examples/ipsec-secgw: support more flow patterns and actions

Message ID 20220419082537.270116-1-psatheesh@marvell.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series examples/ipsec-secgw: support more flow patterns and actions |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK
ci/github-robot: build success github build: passed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-aarch64-unit-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-abi-testing success Testing PASS
ci/intel-Testing success Testing PASS

Commit Message

Satheesh Paul Antonysamy April 19, 2022, 8:25 a.m. UTC
  From: Satheesh Paul <psatheesh@marvell.com>

Added support to create flows with count, mark and security
actions and mark pattern. The flow configuration can be done
with these pattern and actions in the below format in the
configuration file.

flow [mark <val>] [eth] [ipv4 | ipv6] <src>|<dst> \
     <ipv4_addr_string|ipv6_addr_string> port <val> queue <val> \
     [count] [security] [set_mark <val>]

mark <val>:
     Set RTE_FLOW_ITEM_TYPE_MARK pattern item with value <val>
eth:
     Set RTE_FLOW_ITEM_TYPE_ETH pattern item. This matches all
     ethernet packets.
ipv4 | ipv6 <src>|<dst>:
     Set RTE_FLOW_ITEM_TYPE_IPV4|RTE_FLOW_ITEM_TYPE_IPV6 pattern
     with given ipv4 or ipv6 address as source or destination.
port <val>:
     Create flow rule on port <val>.
queue <val>:
     Set RTE_FLOW_ACTION_TYPE_QUEUE action with queue <val>.
count:
     Set RTE_FLOW_ACTION_TYPE_COUNT action.
security:
     Set RTE_FLOW_ITEM_TYPE_ESP pattern and
     RTE_FLOW_ACTION_TYPE_SECURITY action.
set_mark <val>:
     Set RTE_FLOW_ACTION_TYPE_MARK action with <val> as mark.

Examples:
     flow mark 123 ipv4 dst 192.168.0.0/16 port 0 queue 0 count
     flow eth ipv4 dst 192.168.0.0/16 port 0 queue 0 count
     flow ipv4 dst 192.168.0.0/16 port 0 queue 0 count
     flow ipv4 dst 192.168.0.0/16 port 0 queue 0
     flow port 0 security set_mark 123
     flow ipv4 dst 1.1.0.0/16 port 0 count set_mark 123 security

Signed-off-by: Satheesh Paul <psatheesh@marvell.com>
---
 examples/ipsec-secgw/flow.c        | 280 +++++++++++++++++++++++------
 examples/ipsec-secgw/flow.h        |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   3 +-
 3 files changed, 233 insertions(+), 51 deletions(-)
  

Patch

diff --git a/examples/ipsec-secgw/flow.c b/examples/ipsec-secgw/flow.c
index 1a1ec7861c..23962f35e7 100644
--- a/examples/ipsec-secgw/flow.c
+++ b/examples/ipsec-secgw/flow.c
@@ -15,7 +15,9 @@ 
 #define FLOW_RULES_MAX 128
 
 struct flow_rule_entry {
+	uint8_t is_eth;
 	uint8_t is_ipv4;
+	uint8_t is_ipv6;
 	RTE_STD_C11
 	union {
 		struct {
@@ -27,8 +29,15 @@  struct flow_rule_entry {
 			struct rte_flow_item_ipv6 mask;
 		} ipv6;
 	};
+	struct rte_flow_item_mark mark_val;
 	uint16_t port;
 	uint16_t queue;
+	bool is_queue_set;
+	bool enable_count;
+	bool enable_mark;
+	bool set_security_action;
+	bool set_mark_action;
+	uint32_t mark_action_val;
 	struct rte_flow *flow;
 } flow_rule_tbl[FLOW_RULES_MAX];
 
@@ -64,8 +73,9 @@  ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
 	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
 
 	*spec = ip.s_addr;
+
 	if (depth < 32)
-		*mask = *mask << (32-depth);
+		*mask = htonl(*mask << (32 - depth));
 
 	return 0;
 }
@@ -124,7 +134,7 @@  parse_flow_tokens(char **tokens, uint32_t n_tokens,
 		  struct parse_status *status)
 {
 	struct flow_rule_entry *rule;
-	uint32_t ti;
+	uint32_t ti = 0;
 
 	if (nb_flow_rule >= FLOW_RULES_MAX) {
 		printf("Too many flow rules\n");
@@ -134,49 +144,73 @@  parse_flow_tokens(char **tokens, uint32_t n_tokens,
 	rule = &flow_rule_tbl[nb_flow_rule];
 	memset(rule, 0, sizeof(*rule));
 
-	if (strcmp(tokens[0], "ipv4") == 0) {
-		rule->is_ipv4 = 1;
-	} else if (strcmp(tokens[0], "ipv6") == 0) {
-		rule->is_ipv4 = 0;
-	} else {
-		APP_CHECK(0, status, "unrecognized input \"%s\"", tokens[0]);
-		return;
-	}
-
-	for (ti = 1; ti < n_tokens; ti++) {
-		if (strcmp(tokens[ti], "src") == 0) {
+	for (ti = 0; ti < n_tokens; ti++) {
+		if (strcmp(tokens[ti], "mark") == 0) {
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
 			if (status->status < 0)
 				return;
 
-			if (rule->is_ipv4) {
+			rule->mark_val.id = atoi(tokens[ti]);
+			rule->enable_mark = true;
+			continue;
+		}
+		if (strcmp(tokens[ti], "eth") == 0) {
+			rule->is_eth = true;
+			continue;
+		}
+
+		if (strcmp(tokens[ti], "ipv4") == 0) {
+			rule->is_ipv4 = true;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (strcmp(tokens[ti], "src") == 0) {
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
 				if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.src_addr,
 						  &rule->ipv4.mask.hdr.src_addr,
 						  tokens[ti], status))
 					return;
-			} else {
-				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr,
-						  rule->ipv6.mask.hdr.src_addr,
+			}
+			if (strcmp(tokens[ti], "dst") == 0) {
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.src_addr,
+						  &rule->ipv4.mask.hdr.src_addr,
 						  tokens[ti], status))
 					return;
 			}
+			continue;
 		}
-		if (strcmp(tokens[ti], "dst") == 0) {
+		if (strcmp(tokens[ti], "ipv6") == 0) {
+			rule->is_ipv6 = true;
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-
-			if (rule->is_ipv4) {
-				if (ipv4_addr_cpy(&rule->ipv4.spec.hdr.dst_addr,
-						  &rule->ipv4.mask.hdr.dst_addr,
+			if (strcmp(tokens[ti], "src") == 0) {
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr,
+						  rule->ipv6.mask.hdr.src_addr,
 						  tokens[ti], status))
 					return;
-			} else {
-				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
-						  rule->ipv6.mask.hdr.dst_addr,
+			}
+			if (strcmp(tokens[ti], "dst") == 0) {
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.src_addr,
+						  rule->ipv6.mask.hdr.src_addr,
 						  tokens[ti], status))
 					return;
 			}
+			continue;
 		}
 
 		if (strcmp(tokens[ti], "port") == 0) {
@@ -188,6 +222,7 @@  parse_flow_tokens(char **tokens, uint32_t n_tokens,
 				return;
 
 			rule->port = atoi(tokens[ti]);
+			continue;
 		}
 
 		if (strcmp(tokens[ti], "queue") == 0) {
@@ -199,50 +234,129 @@  parse_flow_tokens(char **tokens, uint32_t n_tokens,
 				return;
 
 			rule->queue = atoi(tokens[ti]);
+			rule->is_queue_set = true;
+			continue;
+		}
+
+		if (strcmp(tokens[ti], "count") == 0) {
+			rule->enable_count = true;
+			continue;
+		}
+
+		if (strcmp(tokens[ti], "security") == 0) {
+			rule->set_security_action = true;
+			continue;
 		}
+
+		if (strcmp(tokens[ti], "set_mark") == 0) {
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
+			if (status->status < 0)
+				return;
+
+			rule->set_mark_action = true;
+			rule->mark_action_val = atoi(tokens[ti]);
+			continue;
+		}
+
+		sprintf(status->parse_msg, "Unrecognized input:%s\n", tokens[ti]);
+		status->status = -1;
+		return;
 	}
+	printf("\n");
 
 	nb_flow_rule++;
 }
 
-#define MAX_RTE_FLOW_PATTERN (3)
-#define MAX_RTE_FLOW_ACTIONS (2)
+#define MAX_RTE_FLOW_PATTERN (4)
+#define MAX_RTE_FLOW_ACTIONS (5)
 
 static void
 flow_init_single(struct flow_rule_entry *rule)
 {
-	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN] = {};
 	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS] = {};
+	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN] = {};
+	struct rte_flow_action_queue queue_action;
+	struct rte_flow_action_mark mark_action;
+	int ret, pattern_idx = 0, act_idx = 0;
+	struct rte_flow_item_mark mark_mask;
 	struct rte_flow_attr attr = {};
-	struct rte_flow_error err;
-	int ret;
+	struct rte_flow_error err = {};
 
 	attr.egress = 0;
 	attr.ingress = 1;
 
-	action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
-	action[0].conf = &(struct rte_flow_action_queue) {
-				.index = rule->queue,
-	};
-	action[1].type = RTE_FLOW_ACTION_TYPE_END;
+	if (rule->is_queue_set) {
+		queue_action.index = rule->queue;
+		action[act_idx].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+		action[act_idx].conf = &queue_action;
+		act_idx++;
+	}
+
+	if (rule->enable_count) {
+		action[act_idx].type = RTE_FLOW_ACTION_TYPE_COUNT;
+		act_idx++;
+	}
+
+	if (rule->set_security_action) {
+		action[act_idx].type = RTE_FLOW_ACTION_TYPE_SECURITY;
+		action[act_idx].conf = NULL;
+		act_idx++;
+	}
+
+	if (rule->set_mark_action) {
+		mark_action.id = rule->mark_action_val;
+		action[act_idx].type = RTE_FLOW_ACTION_TYPE_MARK;
+		action[act_idx].conf = &mark_action;
+		act_idx++;
+	}
 
-	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	action[act_idx].type = RTE_FLOW_ACTION_TYPE_END;
+	action[act_idx].conf = NULL;
+
+	if (rule->enable_mark) {
+		mark_mask.id = UINT32_MAX;
+		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_MARK;
+		pattern[pattern_idx].spec = &rule->mark_val;
+		pattern[pattern_idx].mask = &mark_mask;
+		pattern_idx++;
+	}
+
+	if (rule->is_eth) {
+		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ETH;
+		pattern_idx++;
+	}
 
 	if (rule->is_ipv4) {
-		pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
-		pattern[1].spec = &rule->ipv4.spec;
-		pattern[1].mask = &rule->ipv4.mask;
-	} else {
-		pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
-		pattern[1].spec = &rule->ipv6.spec;
-		pattern[1].mask = &rule->ipv6.mask;
+		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		pattern[pattern_idx].spec = &rule->ipv4.spec;
+		pattern[pattern_idx].mask = &rule->ipv4.mask;
+		pattern_idx++;
+	}
+
+	if (rule->is_ipv6) {
+		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		pattern[pattern_idx].spec = &rule->ipv6.spec;
+		pattern[pattern_idx].mask = &rule->ipv6.mask;
+		pattern_idx++;
+	}
+
+	if (rule->set_security_action) {
+		pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_ESP;
+		pattern[pattern_idx].spec = NULL;
+		pattern[pattern_idx].mask = NULL;
+		pattern[pattern_idx].last = NULL;
+		pattern_idx++;
 	}
 
-	pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+	pattern[pattern_idx].type = RTE_FLOW_ITEM_TYPE_END;
 
 	ret = rte_flow_validate(rule->port, &attr, pattern, action, &err);
 	if (ret < 0) {
 		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
+		rule->flow = 0;
 		return;
 	}
 
@@ -251,6 +365,56 @@  flow_init_single(struct flow_rule_entry *rule)
 		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
 }
 
+void
+flow_print_counters(void)
+{
+	struct rte_flow_query_count count_query;
+	struct rte_flow_action action;
+	struct flow_rule_entry *rule;
+	struct rte_flow_error error;
+	int i = 0, ret = 0;
+
+	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		if (!rule->flow || !rule->enable_count)
+			continue;
+
+		/* Poisoning to make sure PMDs update it in case of error. */
+		memset(&error, 0x55, sizeof(error));
+		memset(&count_query, 0, sizeof(count_query));
+		ret = rte_flow_query(rule->port, rule->flow, &action,
+				     &count_query, &error);
+		if (ret)
+			RTE_LOG(ERR, IPSEC,
+				"Failed to get flow counter "
+				" for port %u, err msg: %s\n",
+				rule->port, error.message);
+
+		printf("Flow #%3d:", i);
+		if (rule->is_ipv4) {
+			printf(" spec ipv4 ");
+			ipv4_hdr_print(&rule->ipv4.spec.hdr);
+		}
+		if (rule->is_ipv6) {
+			printf(" spec ipv6 ");
+			ipv6_hdr_print(&rule->ipv6.spec.hdr);
+		}
+
+		if (rule->set_security_action)
+			printf(" Security action set,");
+
+		if (rule->enable_mark)
+			printf(" Mark Enabled");
+
+		printf(" Port: %d,", rule->port);
+		if (rule->is_queue_set)
+			printf(" Queue: %d", rule->queue);
+		printf(" Hits: %"PRIu64"\n", count_query.hits);
+	}
+}
+
 void
 flow_init(void)
 {
@@ -264,21 +428,37 @@  flow_init(void)
 
 	for (i = 0; i < nb_flow_rule; i++) {
 		rule = &flow_rule_tbl[i];
+		printf("Flow #%3d: ", i);
 		if (rule->is_ipv4) {
-			printf("Flow #%3d: spec ipv4 ", i);
+			printf("spec ipv4 ");
 			ipv4_hdr_print(&rule->ipv4.spec.hdr);
 			printf("\n");
-			printf("           mask ipv4 ");
+			printf(" mask ipv4 ");
 			ipv4_hdr_print(&rule->ipv4.mask.hdr);
-		} else {
-			printf("Flow #%3d: spec ipv6 ", i);
+		}
+		if (rule->is_ipv6) {
+			printf("spec ipv6 ");
 			ipv6_hdr_print(&rule->ipv6.spec.hdr);
 			printf("\n");
-			printf("           mask ipv6 ");
+			printf(" mask ipv6 ");
 			ipv6_hdr_print(&rule->ipv6.mask.hdr);
 		}
 
-		printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
+		if (rule->enable_mark)
+			printf(", Mark enabled");
+
+		printf("\tPort: %d,", rule->port);
+		if (rule->is_queue_set)
+			printf(" Queue: %d,", rule->queue);
+
+		if (rule->set_security_action)
+			printf(" Security action set,");
+
+		if (rule->set_mark_action)
+			printf(" Mark: %d,", rule->mark_action_val);
+
+		if (rule->enable_count)
+			printf(" Counter enabled,");
 
 		if (rule->flow == NULL)
 			printf(" [UNSUPPORTED]");
diff --git a/examples/ipsec-secgw/flow.h b/examples/ipsec-secgw/flow.h
index 1b1b4774e4..9492d06346 100644
--- a/examples/ipsec-secgw/flow.h
+++ b/examples/ipsec-secgw/flow.h
@@ -11,5 +11,6 @@  void parse_flow_tokens(char **tokens, uint32_t n_tokens,
 		       struct parse_status *status);
 
 void flow_init(void);
+void flow_print_counters(void);
 
 #endif /* _FLOW_H_ */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 42b5081840..244453e06e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -3271,7 +3271,6 @@  ipsec_secgw_telemetry_init(void)
 		"Optional Parameters: int <logical core id>");
 }
 
-
 int32_t
 main(int32_t argc, char **argv)
 {
@@ -3512,6 +3511,8 @@  main(int32_t argc, char **argv)
 		printf(" Done\n");
 	}
 
+	flow_print_counters();
+
 	RTE_ETH_FOREACH_DEV(portid) {
 		if ((enabled_port_mask & (1 << portid)) == 0)
 			continue;