DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] examples/ipsec-secgw: enable rte_flow based packet distribution
@ 2020-06-10  9:01 Ankur Dwivedi
  2020-06-10  9:08 ` [dpdk-dev] [PATCH v2] " Ankur Dwivedi
  0 siblings, 1 reply; 6+ messages in thread
From: Ankur Dwivedi @ 2020-06-10  9:01 UTC (permalink / raw)
  To: dev; +Cc: praveen.shetty, konstantin.ananyev, radu.nicolau, akhil.goyal, anoobj

From: Anoob Joseph <anoobj@marvell.com>

RTE_FLOW API allows hardware parsing and steering of packets to specific
queues which helps in distributing ingress traffic across various cores.
Adding 'flow' rules allows user to specify the distribution required.

Signed-off-by: Anoob Joseph <anoobj@marvell.com>
Change-Id: I353e104cab7fae2520f76cf276dbff830a2b931d
---
 doc/guides/sample_app_ug/ipsec_secgw.rst |  78 ++++++++-
 examples/ipsec-secgw/Makefile            |   1 +
 examples/ipsec-secgw/flow.c              | 285 +++++++++++++++++++++++++++++++
 examples/ipsec-secgw/flow.h              |  15 ++
 examples/ipsec-secgw/ipsec-secgw.c       |   3 +
 examples/ipsec-secgw/ipsec-secgw.h       |   7 +
 examples/ipsec-secgw/ipsec.h             |   7 -
 examples/ipsec-secgw/meson.build         |  15 +-
 examples/ipsec-secgw/parser.c            |  46 +++++
 examples/ipsec-secgw/parser.h            |   7 +-
 10 files changed, 450 insertions(+), 14 deletions(-)
 create mode 100644 examples/ipsec-secgw/flow.c
 create mode 100644 examples/ipsec-secgw/flow.h

diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 81c5d43..434f484 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -348,7 +348,7 @@ Configurations
 --------------
 
 The following sections provide the syntax of configurations to initialize
-your SP, SA, Routing and Neighbour tables.
+your SP, SA, Routing, Flow and Neighbour tables.
 Configurations shall be specified in the configuration file to be passed to
 the application. The file is then parsed by the application. The successful
 parsing will result in the appropriate rules being applied to the tables
@@ -369,7 +369,7 @@ General rule syntax
 
 The parse treats one line in the configuration file as one configuration
 item (unless the line concatenation symbol exists). Every configuration
-item shall follow the syntax of either SP, SA, Routing or Neighbour
+item shall follow the syntax of either SP, SA, Routing, Flow or Neighbour
 rules specified below.
 
 The configuration parser supports the following special symbols:
@@ -808,6 +808,80 @@ Example SP rules:
 
     rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0
 
+Flow rule syntax
+^^^^^^^^^^^^^^^^
+
+Flow rule enables the usage of hardware classification capabilities to match specific
+ingress traffic and redirect the packets to the specified queue. This feature is
+optional and relies on hardware ``rte_flow`` support.
+
+The flow rule syntax is shown as follows:
+
+.. code-block:: console
+
+    flow <ip_ver> <src_ip> <dst_ip> <port> <queue>
+
+
+where each options means:
+
+``<ip_ver>``
+
+ * IP protocol version
+
+ * Optional: No
+
+ * Available options:
+
+   * *ipv4*: IP protocol version 4
+   * *ipv6*: IP protocol version 6
+
+``<src_ip>``
+
+ * The source IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *src X.X.X.X/Y* for IPv4
+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<dst_ip>``
+
+ * The destination IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *dst X.X.X.X/Y* for IPv4
+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<port>``
+
+ * The traffic input port id
+
+ * Optional: yes, default input port 0 will be used
+
+ * Syntax: *port X*
+
+``<queue>``
+
+ * The traffic input queue id
+
+ * Optional: yes, default input queue 0 will be used
+
+ * Syntax: *queue X*
+
+Example flow rules:
+
+.. code-block:: console
+
+    flow ipv4 dst 172.16.1.5/32 port 0 queue 0
+
+    flow ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 1 queue 0
+
+
 Neighbour rule syntax
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index c4a272a..dbae152 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -18,6 +18,7 @@ SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
 SRCS-y += ipsec_worker.c
 SRCS-y += event_helper.c
+SRCS-y += flow.c
 
 CFLAGS += -gdwarf-2
 
diff --git a/examples/ipsec-secgw/flow.c b/examples/ipsec-secgw/flow.c
new file mode 100644
index 0000000..69f8405
--- /dev/null
+++ b/examples/ipsec-secgw/flow.c
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_flow.h>
+#include <rte_ip.h>
+
+#include "flow.h"
+#include "ipsec-secgw.h"
+#include "parser.h"
+
+#define FLOW_RULES_MAX 128
+
+struct flow_rule_entry {
+	uint8_t is_ipv4;
+	RTE_STD_C11
+	union {
+		struct {
+			struct rte_flow_item_ipv4 spec;
+			struct rte_flow_item_ipv4 mask;
+		} ipv4;
+		struct {
+			struct rte_flow_item_ipv6 spec;
+			struct rte_flow_item_ipv6 mask;
+		} ipv6;
+	};
+	uint16_t port;
+	uint16_t queue;
+	struct rte_flow *flow;
+} flow_rule_tbl[FLOW_RULES_MAX];
+
+int nb_flow_rule;
+
+static void
+ipv4_hdr_print(struct rte_ipv4_hdr *hdr)
+{
+	char a, b, c, d;
+
+	uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
+	printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
+
+	uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
+	printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d);
+}
+
+static int
+ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in_addr ip;
+	uint32_t depth;
+
+	APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
+		 "unrecognized input \"%s\", expect valid ipv4 addr", token);
+	if (status->status < 0)
+		return -1;
+
+	if (depth > 32)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
+
+	*spec = ip.s_addr;
+	if (depth < 32)
+		*mask = *mask << (32-depth);
+
+	return 0;
+}
+
+static void
+ipv6_hdr_print(struct rte_ipv6_hdr *hdr)
+{
+	uint8_t *addr;
+
+	addr = hdr->src_addr;
+	printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+
+	addr = hdr->dst_addr;
+	printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+}
+
+static int
+ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in6_addr ip;
+	uint32_t depth, i;
+
+	APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
+		"unrecognized input \"%s\", expect valid ipv6 address", token);
+	if (status->status < 0)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
+	memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
+
+	for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
+		mask[i/8] &= ~(1 << (7-i%8));
+
+	return 0;
+}
+
+void
+parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		  struct parse_status *status)
+{
+	struct flow_rule_entry *rule;
+	uint32_t ti;
+
+	if (nb_flow_rule >= FLOW_RULES_MAX) {
+		printf("Too many flow rules\n");
+		return;
+	}
+
+	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) {
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+
+			if (rule->is_ipv4) {
+				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,
+						  tokens[ti], status))
+					return;
+			}
+		}
+		if (strcmp(tokens[ti], "dst") == 0) {
+			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,
+						  tokens[ti], status))
+					return;
+			} else {
+				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
+						  rule->ipv6.mask.hdr.dst_addr,
+						  tokens[ti], status))
+					return;
+			}
+		}
+
+		if (strcmp(tokens[ti], "port") == 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->port = atoi(tokens[ti]);
+
+			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->queue = atoi(tokens[ti]);
+		}
+	}
+
+	nb_flow_rule++;
+}
+
+#define MAX_RTE_FLOW_PATTERN (3)
+#define MAX_RTE_FLOW_ACTIONS (2)
+
+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_attr attr = {};
+	struct rte_flow_error err;
+	int ret;
+
+	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;
+
+	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+
+	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[2].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);
+		return;
+	}
+
+	rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
+	if (rule->flow == NULL)
+		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
+}
+
+void
+flow_init(void)
+{
+	struct flow_rule_entry *rule;
+	int i;
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		flow_init_single(rule);
+	}
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		if (rule->is_ipv4) {
+			printf("Flow #%3d: spec ipv4 ", i);
+			ipv4_hdr_print(&rule->ipv4.spec.hdr);
+			printf("\n");
+			printf("           mask ipv4 ");
+			ipv4_hdr_print(&rule->ipv4.mask.hdr);
+		} else {
+			printf("Flow #%3d: spec ipv6 ", i);
+			ipv6_hdr_print(&rule->ipv6.spec.hdr);
+			printf("\n");
+			printf("           mask ipv6 ");
+			ipv6_hdr_print(&rule->ipv6.mask.hdr);
+		}
+
+		printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
+
+		if (rule->flow == NULL)
+			printf(" [UNSUPPORTED]");
+		printf("\n");
+	}
+}
diff --git a/examples/ipsec-secgw/flow.h b/examples/ipsec-secgw/flow.h
new file mode 100644
index 0000000..1b1b477
--- /dev/null
+++ b/examples/ipsec-secgw/flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#ifndef _FLOW_H_
+#define _FLOW_H_
+
+#include "parser.h"
+
+void parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		       struct parse_status *status);
+
+void flow_init(void);
+
+#endif /* _FLOW_H_ */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index f777ce2..d19688d 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -49,6 +49,7 @@
 #include <rte_ip_frag.h>
 
 #include "event_helper.h"
+#include "flow.h"
 #include "ipsec.h"
 #include "ipsec_worker.h"
 #include "parser.h"
@@ -2914,6 +2915,8 @@ struct lcore_conf {
 		}
 	}
 
+	flow_init();
+
 	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
index 4b53cb5..412d727 100644
--- a/examples/ipsec-secgw/ipsec-secgw.h
+++ b/examples/ipsec-secgw/ipsec-secgw.h
@@ -34,6 +34,13 @@
 	((uint64_t)(a) & 0xff))
 #endif
 
+#define uint32_t_to_char(ip, a, b, c, d) do {\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
+	} while (0)
+
 #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
 
 struct traffic_type {
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 2f69199..7031e28 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -28,13 +28,6 @@
 #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
 				sizeof(struct rte_crypto_sym_op))
 
-#define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (uint8_t)(ip >> 24 & 0xff);\
-		*b = (uint8_t)(ip >> 16 & 0xff);\
-		*c = (uint8_t)(ip >> 8 & 0xff);\
-		*d = (uint8_t)(ip & 0xff);\
-	} while (0)
-
 #define DEFAULT_MAX_CATEGORIES	1
 
 #define INVALID_SPI (0)
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index f9ba2a2..d0373da 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -9,6 +9,17 @@
 deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec', 'eventdev']
 allow_experimental_apis = true
 sources = files(
-	'esp.c', 'event_helper.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'ipsec_worker.c', 'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
+	'esp.c',
+	'event_helper.c',
+	'flow.c',
+	'ipsec.c',
+	'ipsec_process.c',
+	'ipsec-secgw.c',
+	'ipsec_worker.c',
+	'parser.c',
+	'rt.c',
+	'sa.c',
+	'sad.c',
+	'sp4.c',
+	'sp6.c'
 )
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index 65eb7e9..8f66660 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -11,6 +11,7 @@
 #include <cmdline_socket.h>
 #include <cmdline.h>
 
+#include "flow.h"
 #include "ipsec.h"
 #include "parser.h"
 
@@ -484,6 +485,49 @@ struct cfg_rt_add_cfg_item {
 	},
 };
 
+/* flow add parse */
+struct cfg_flow_add_cfg_item {
+	cmdline_fixed_string_t flow_keyword;
+	cmdline_multi_string_t multi_string;
+};
+
+static void
+cfg_flow_add_cfg_item_parsed(void *parsed_result,
+	__rte_unused struct cmdline *cl, void *data)
+{
+	struct cfg_flow_add_cfg_item *params = parsed_result;
+	char *tokens[32];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	struct parse_status *status = (struct parse_status *)data;
+
+	APP_CHECK(parse_tokenize_string(
+		params->multi_string, tokens, &n_tokens) == 0,
+		status, "too many arguments\n");
+	if (status->status < 0)
+		return;
+
+	parse_flow_tokens(tokens, n_tokens, status);
+}
+
+static cmdline_parse_token_string_t cfg_flow_add_flow_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
+		flow_keyword, "flow");
+
+static cmdline_parse_token_string_t cfg_flow_add_multi_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item, multi_string,
+		TOKEN_STRING_MULTI);
+
+cmdline_parse_inst_t cfg_flow_add_rule = {
+	.f = cfg_flow_add_cfg_item_parsed,
+	.data = NULL,
+	.help_str = "",
+	.tokens = {
+		(void *) &cfg_flow_add_flow_str,
+		(void *) &cfg_flow_add_multi_str,
+		NULL,
+	},
+};
+
 /* neigh add parse */
 struct cfg_neigh_add_item {
 	cmdline_fixed_string_t neigh;
@@ -538,6 +582,7 @@ struct cfg_neigh_add_item {
 	(cmdline_parse_inst_t *)&cfg_sp_add_rule,
 	(cmdline_parse_inst_t *)&cfg_sa_add_rule,
 	(cmdline_parse_inst_t *)&cfg_rt_add_rule,
+	(cmdline_parse_inst_t *)&cfg_flow_add_rule,
 	(cmdline_parse_inst_t *)&cfg_neigh_add_rule,
 	NULL,
 };
@@ -564,6 +609,7 @@ struct cfg_neigh_add_item {
 	cfg_sp_add_rule.data = &status;
 	cfg_sa_add_rule.data = &status;
 	cfg_rt_add_rule.data = &status;
+	cfg_flow_add_rule.data = &status;
 	cfg_neigh_add_rule.data = &status;
 
 	do {
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6e764fe..a0ff7e1 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -2,12 +2,13 @@
  * Copyright(c) 2016 Intel Corporation
  */
 
+#ifndef __PARSER_H
+#define __PARSER_H
+
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
-
-#ifndef __PARSER_H
-#define __PARSER_H
+#include <string.h>
 
 struct parse_status {
 	int status;
-- 
1.9.3


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

* [dpdk-dev] [PATCH v2] examples/ipsec-secgw: enable rte_flow based packet distribution
  2020-06-10  9:01 [dpdk-dev] [PATCH] examples/ipsec-secgw: enable rte_flow based packet distribution Ankur Dwivedi
@ 2020-06-10  9:08 ` Ankur Dwivedi
  2020-07-14  9:28   ` Ankur Dwivedi
  2020-07-17 12:31   ` [dpdk-dev] [PATCH v3] " Ankur Dwivedi
  0 siblings, 2 replies; 6+ messages in thread
From: Ankur Dwivedi @ 2020-06-10  9:08 UTC (permalink / raw)
  To: dev
  Cc: praveen.shetty, konstantin.ananyev, radu.nicolau, akhil.goyal,
	anoobj, adwivedi

From: Anoob Joseph <anoobj@marvell.com>

RTE_FLOW API allows hardware parsing and steering of packets to specific
queues which helps in distributing ingress traffic across various cores.
Adding 'flow' rules allows user to specify the distribution required.

Signed-off-by: Anoob Joseph <anoobj@marvell.com>
---
v2:
* Removed Change-Id

 doc/guides/sample_app_ug/ipsec_secgw.rst |  78 ++++++++-
 examples/ipsec-secgw/Makefile            |   1 +
 examples/ipsec-secgw/flow.c              | 285 +++++++++++++++++++++++++++++++
 examples/ipsec-secgw/flow.h              |  15 ++
 examples/ipsec-secgw/ipsec-secgw.c       |   3 +
 examples/ipsec-secgw/ipsec-secgw.h       |   7 +
 examples/ipsec-secgw/ipsec.h             |   7 -
 examples/ipsec-secgw/meson.build         |  15 +-
 examples/ipsec-secgw/parser.c            |  46 +++++
 examples/ipsec-secgw/parser.h            |   7 +-
 10 files changed, 450 insertions(+), 14 deletions(-)
 create mode 100644 examples/ipsec-secgw/flow.c
 create mode 100644 examples/ipsec-secgw/flow.h

diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 81c5d43..434f484 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -348,7 +348,7 @@ Configurations
 --------------
 
 The following sections provide the syntax of configurations to initialize
-your SP, SA, Routing and Neighbour tables.
+your SP, SA, Routing, Flow and Neighbour tables.
 Configurations shall be specified in the configuration file to be passed to
 the application. The file is then parsed by the application. The successful
 parsing will result in the appropriate rules being applied to the tables
@@ -369,7 +369,7 @@ General rule syntax
 
 The parse treats one line in the configuration file as one configuration
 item (unless the line concatenation symbol exists). Every configuration
-item shall follow the syntax of either SP, SA, Routing or Neighbour
+item shall follow the syntax of either SP, SA, Routing, Flow or Neighbour
 rules specified below.
 
 The configuration parser supports the following special symbols:
@@ -808,6 +808,80 @@ Example SP rules:
 
     rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0
 
+Flow rule syntax
+^^^^^^^^^^^^^^^^
+
+Flow rule enables the usage of hardware classification capabilities to match specific
+ingress traffic and redirect the packets to the specified queue. This feature is
+optional and relies on hardware ``rte_flow`` support.
+
+The flow rule syntax is shown as follows:
+
+.. code-block:: console
+
+    flow <ip_ver> <src_ip> <dst_ip> <port> <queue>
+
+
+where each options means:
+
+``<ip_ver>``
+
+ * IP protocol version
+
+ * Optional: No
+
+ * Available options:
+
+   * *ipv4*: IP protocol version 4
+   * *ipv6*: IP protocol version 6
+
+``<src_ip>``
+
+ * The source IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *src X.X.X.X/Y* for IPv4
+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<dst_ip>``
+
+ * The destination IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *dst X.X.X.X/Y* for IPv4
+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<port>``
+
+ * The traffic input port id
+
+ * Optional: yes, default input port 0 will be used
+
+ * Syntax: *port X*
+
+``<queue>``
+
+ * The traffic input queue id
+
+ * Optional: yes, default input queue 0 will be used
+
+ * Syntax: *queue X*
+
+Example flow rules:
+
+.. code-block:: console
+
+    flow ipv4 dst 172.16.1.5/32 port 0 queue 0
+
+    flow ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 1 queue 0
+
+
 Neighbour rule syntax
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index c4a272a..dbae152 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -18,6 +18,7 @@ SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
 SRCS-y += ipsec_worker.c
 SRCS-y += event_helper.c
+SRCS-y += flow.c
 
 CFLAGS += -gdwarf-2
 
diff --git a/examples/ipsec-secgw/flow.c b/examples/ipsec-secgw/flow.c
new file mode 100644
index 0000000..69f8405
--- /dev/null
+++ b/examples/ipsec-secgw/flow.c
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_flow.h>
+#include <rte_ip.h>
+
+#include "flow.h"
+#include "ipsec-secgw.h"
+#include "parser.h"
+
+#define FLOW_RULES_MAX 128
+
+struct flow_rule_entry {
+	uint8_t is_ipv4;
+	RTE_STD_C11
+	union {
+		struct {
+			struct rte_flow_item_ipv4 spec;
+			struct rte_flow_item_ipv4 mask;
+		} ipv4;
+		struct {
+			struct rte_flow_item_ipv6 spec;
+			struct rte_flow_item_ipv6 mask;
+		} ipv6;
+	};
+	uint16_t port;
+	uint16_t queue;
+	struct rte_flow *flow;
+} flow_rule_tbl[FLOW_RULES_MAX];
+
+int nb_flow_rule;
+
+static void
+ipv4_hdr_print(struct rte_ipv4_hdr *hdr)
+{
+	char a, b, c, d;
+
+	uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
+	printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
+
+	uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
+	printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d);
+}
+
+static int
+ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in_addr ip;
+	uint32_t depth;
+
+	APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
+		 "unrecognized input \"%s\", expect valid ipv4 addr", token);
+	if (status->status < 0)
+		return -1;
+
+	if (depth > 32)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
+
+	*spec = ip.s_addr;
+	if (depth < 32)
+		*mask = *mask << (32-depth);
+
+	return 0;
+}
+
+static void
+ipv6_hdr_print(struct rte_ipv6_hdr *hdr)
+{
+	uint8_t *addr;
+
+	addr = hdr->src_addr;
+	printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+
+	addr = hdr->dst_addr;
+	printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+}
+
+static int
+ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in6_addr ip;
+	uint32_t depth, i;
+
+	APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
+		"unrecognized input \"%s\", expect valid ipv6 address", token);
+	if (status->status < 0)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
+	memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
+
+	for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
+		mask[i/8] &= ~(1 << (7-i%8));
+
+	return 0;
+}
+
+void
+parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		  struct parse_status *status)
+{
+	struct flow_rule_entry *rule;
+	uint32_t ti;
+
+	if (nb_flow_rule >= FLOW_RULES_MAX) {
+		printf("Too many flow rules\n");
+		return;
+	}
+
+	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) {
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+
+			if (rule->is_ipv4) {
+				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,
+						  tokens[ti], status))
+					return;
+			}
+		}
+		if (strcmp(tokens[ti], "dst") == 0) {
+			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,
+						  tokens[ti], status))
+					return;
+			} else {
+				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
+						  rule->ipv6.mask.hdr.dst_addr,
+						  tokens[ti], status))
+					return;
+			}
+		}
+
+		if (strcmp(tokens[ti], "port") == 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->port = atoi(tokens[ti]);
+
+			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->queue = atoi(tokens[ti]);
+		}
+	}
+
+	nb_flow_rule++;
+}
+
+#define MAX_RTE_FLOW_PATTERN (3)
+#define MAX_RTE_FLOW_ACTIONS (2)
+
+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_attr attr = {};
+	struct rte_flow_error err;
+	int ret;
+
+	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;
+
+	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+
+	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[2].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);
+		return;
+	}
+
+	rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
+	if (rule->flow == NULL)
+		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
+}
+
+void
+flow_init(void)
+{
+	struct flow_rule_entry *rule;
+	int i;
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		flow_init_single(rule);
+	}
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		if (rule->is_ipv4) {
+			printf("Flow #%3d: spec ipv4 ", i);
+			ipv4_hdr_print(&rule->ipv4.spec.hdr);
+			printf("\n");
+			printf("           mask ipv4 ");
+			ipv4_hdr_print(&rule->ipv4.mask.hdr);
+		} else {
+			printf("Flow #%3d: spec ipv6 ", i);
+			ipv6_hdr_print(&rule->ipv6.spec.hdr);
+			printf("\n");
+			printf("           mask ipv6 ");
+			ipv6_hdr_print(&rule->ipv6.mask.hdr);
+		}
+
+		printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
+
+		if (rule->flow == NULL)
+			printf(" [UNSUPPORTED]");
+		printf("\n");
+	}
+}
diff --git a/examples/ipsec-secgw/flow.h b/examples/ipsec-secgw/flow.h
new file mode 100644
index 0000000..1b1b477
--- /dev/null
+++ b/examples/ipsec-secgw/flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#ifndef _FLOW_H_
+#define _FLOW_H_
+
+#include "parser.h"
+
+void parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		       struct parse_status *status);
+
+void flow_init(void);
+
+#endif /* _FLOW_H_ */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index f777ce2..d19688d 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -49,6 +49,7 @@
 #include <rte_ip_frag.h>
 
 #include "event_helper.h"
+#include "flow.h"
 #include "ipsec.h"
 #include "ipsec_worker.h"
 #include "parser.h"
@@ -2914,6 +2915,8 @@ struct lcore_conf {
 		}
 	}
 
+	flow_init();
+
 	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
index 4b53cb5..412d727 100644
--- a/examples/ipsec-secgw/ipsec-secgw.h
+++ b/examples/ipsec-secgw/ipsec-secgw.h
@@ -34,6 +34,13 @@
 	((uint64_t)(a) & 0xff))
 #endif
 
+#define uint32_t_to_char(ip, a, b, c, d) do {\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
+	} while (0)
+
 #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
 
 struct traffic_type {
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 2f69199..7031e28 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -28,13 +28,6 @@
 #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
 				sizeof(struct rte_crypto_sym_op))
 
-#define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (uint8_t)(ip >> 24 & 0xff);\
-		*b = (uint8_t)(ip >> 16 & 0xff);\
-		*c = (uint8_t)(ip >> 8 & 0xff);\
-		*d = (uint8_t)(ip & 0xff);\
-	} while (0)
-
 #define DEFAULT_MAX_CATEGORIES	1
 
 #define INVALID_SPI (0)
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index f9ba2a2..d0373da 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -9,6 +9,17 @@
 deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec', 'eventdev']
 allow_experimental_apis = true
 sources = files(
-	'esp.c', 'event_helper.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'ipsec_worker.c', 'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
+	'esp.c',
+	'event_helper.c',
+	'flow.c',
+	'ipsec.c',
+	'ipsec_process.c',
+	'ipsec-secgw.c',
+	'ipsec_worker.c',
+	'parser.c',
+	'rt.c',
+	'sa.c',
+	'sad.c',
+	'sp4.c',
+	'sp6.c'
 )
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index 65eb7e9..8f66660 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -11,6 +11,7 @@
 #include <cmdline_socket.h>
 #include <cmdline.h>
 
+#include "flow.h"
 #include "ipsec.h"
 #include "parser.h"
 
@@ -484,6 +485,49 @@ struct cfg_rt_add_cfg_item {
 	},
 };
 
+/* flow add parse */
+struct cfg_flow_add_cfg_item {
+	cmdline_fixed_string_t flow_keyword;
+	cmdline_multi_string_t multi_string;
+};
+
+static void
+cfg_flow_add_cfg_item_parsed(void *parsed_result,
+	__rte_unused struct cmdline *cl, void *data)
+{
+	struct cfg_flow_add_cfg_item *params = parsed_result;
+	char *tokens[32];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	struct parse_status *status = (struct parse_status *)data;
+
+	APP_CHECK(parse_tokenize_string(
+		params->multi_string, tokens, &n_tokens) == 0,
+		status, "too many arguments\n");
+	if (status->status < 0)
+		return;
+
+	parse_flow_tokens(tokens, n_tokens, status);
+}
+
+static cmdline_parse_token_string_t cfg_flow_add_flow_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
+		flow_keyword, "flow");
+
+static cmdline_parse_token_string_t cfg_flow_add_multi_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item, multi_string,
+		TOKEN_STRING_MULTI);
+
+cmdline_parse_inst_t cfg_flow_add_rule = {
+	.f = cfg_flow_add_cfg_item_parsed,
+	.data = NULL,
+	.help_str = "",
+	.tokens = {
+		(void *) &cfg_flow_add_flow_str,
+		(void *) &cfg_flow_add_multi_str,
+		NULL,
+	},
+};
+
 /* neigh add parse */
 struct cfg_neigh_add_item {
 	cmdline_fixed_string_t neigh;
@@ -538,6 +582,7 @@ struct cfg_neigh_add_item {
 	(cmdline_parse_inst_t *)&cfg_sp_add_rule,
 	(cmdline_parse_inst_t *)&cfg_sa_add_rule,
 	(cmdline_parse_inst_t *)&cfg_rt_add_rule,
+	(cmdline_parse_inst_t *)&cfg_flow_add_rule,
 	(cmdline_parse_inst_t *)&cfg_neigh_add_rule,
 	NULL,
 };
@@ -564,6 +609,7 @@ struct cfg_neigh_add_item {
 	cfg_sp_add_rule.data = &status;
 	cfg_sa_add_rule.data = &status;
 	cfg_rt_add_rule.data = &status;
+	cfg_flow_add_rule.data = &status;
 	cfg_neigh_add_rule.data = &status;
 
 	do {
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6e764fe..a0ff7e1 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -2,12 +2,13 @@
  * Copyright(c) 2016 Intel Corporation
  */
 
+#ifndef __PARSER_H
+#define __PARSER_H
+
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
-
-#ifndef __PARSER_H
-#define __PARSER_H
+#include <string.h>
 
 struct parse_status {
 	int status;
-- 
1.9.3


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

* Re: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: enable rte_flow based packet distribution
  2020-06-10  9:08 ` [dpdk-dev] [PATCH v2] " Ankur Dwivedi
@ 2020-07-14  9:28   ` Ankur Dwivedi
  2020-07-16 16:48     ` Akhil Goyal
  2020-07-17 12:31   ` [dpdk-dev] [PATCH v3] " Ankur Dwivedi
  1 sibling, 1 reply; 6+ messages in thread
From: Ankur Dwivedi @ 2020-07-14  9:28 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: praveen.shetty, konstantin.ananyev, radu.nicolau, Anoob Joseph,
	dev, Ankur Dwivedi

Hi Akhil,

Can you please review this patch?

Thanks
Ankur

>-----Original Message-----
>From: Ankur Dwivedi <adwivedi@marvell.com>
>Sent: Wednesday, June 10, 2020 2:39 PM
>To: dev@dpdk.org
>Cc: praveen.shetty@intel.com; konstantin.ananyev@intel.com;
>radu.nicolau@intel.com; akhil.goyal@nxp.com; Anoob Joseph
><anoobj@marvell.com>; Ankur Dwivedi <adwivedi@marvell.com>
>Subject: [PATCH v2] examples/ipsec-secgw: enable rte_flow based packet
>distribution
>
>From: Anoob Joseph <anoobj@marvell.com>
>
>RTE_FLOW API allows hardware parsing and steering of packets to specific
>queues which helps in distributing ingress traffic across various cores.
>Adding 'flow' rules allows user to specify the distribution required.
>
>Signed-off-by: Anoob Joseph <anoobj@marvell.com>
>---
>v2:
>* Removed Change-Id
>
> doc/guides/sample_app_ug/ipsec_secgw.rst |  78 ++++++++-
> examples/ipsec-secgw/Makefile            |   1 +
> examples/ipsec-secgw/flow.c              | 285
>+++++++++++++++++++++++++++++++
> examples/ipsec-secgw/flow.h              |  15 ++
> examples/ipsec-secgw/ipsec-secgw.c       |   3 +
> examples/ipsec-secgw/ipsec-secgw.h       |   7 +
> examples/ipsec-secgw/ipsec.h             |   7 -
> examples/ipsec-secgw/meson.build         |  15 +-
> examples/ipsec-secgw/parser.c            |  46 +++++
> examples/ipsec-secgw/parser.h            |   7 +-
> 10 files changed, 450 insertions(+), 14 deletions(-)  create mode 100644
>examples/ipsec-secgw/flow.c  create mode 100644 examples/ipsec-
>secgw/flow.h
>
>diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst
>b/doc/guides/sample_app_ug/ipsec_secgw.rst
>index 81c5d43..434f484 100644
>--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
>+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
>@@ -348,7 +348,7 @@ Configurations
> --------------
>
> The following sections provide the syntax of configurations to initialize -your
>SP, SA, Routing and Neighbour tables.
>+your SP, SA, Routing, Flow and Neighbour tables.
> Configurations shall be specified in the configuration file to be passed to  the
>application. The file is then parsed by the application. The successful  parsing
>will result in the appropriate rules being applied to the tables @@ -369,7
>+369,7 @@ General rule syntax
>
> The parse treats one line in the configuration file as one configuration  item
>(unless the line concatenation symbol exists). Every configuration -item shall
>follow the syntax of either SP, SA, Routing or Neighbour
>+item shall follow the syntax of either SP, SA, Routing, Flow or
>+Neighbour
> rules specified below.
>
> The configuration parser supports the following special symbols:
>@@ -808,6 +808,80 @@ Example SP rules:
>
>     rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0
>
>+Flow rule syntax
>+^^^^^^^^^^^^^^^^
>+
>+Flow rule enables the usage of hardware classification capabilities to
>+match specific ingress traffic and redirect the packets to the
>+specified queue. This feature is optional and relies on hardware ``rte_flow``
>support.
>+
>+The flow rule syntax is shown as follows:
>+
>+.. code-block:: console
>+
>+    flow <ip_ver> <src_ip> <dst_ip> <port> <queue>
>+
>+
>+where each options means:
>+
>+``<ip_ver>``
>+
>+ * IP protocol version
>+
>+ * Optional: No
>+
>+ * Available options:
>+
>+   * *ipv4*: IP protocol version 4
>+   * *ipv6*: IP protocol version 6
>+
>+``<src_ip>``
>+
>+ * The source IP address and mask
>+
>+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
>+
>+ * Syntax:
>+
>+   * *src X.X.X.X/Y* for IPv4
>+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
>+
>+``<dst_ip>``
>+
>+ * The destination IP address and mask
>+
>+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
>+
>+ * Syntax:
>+
>+   * *dst X.X.X.X/Y* for IPv4
>+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
>+
>+``<port>``
>+
>+ * The traffic input port id
>+
>+ * Optional: yes, default input port 0 will be used
>+
>+ * Syntax: *port X*
>+
>+``<queue>``
>+
>+ * The traffic input queue id
>+
>+ * Optional: yes, default input queue 0 will be used
>+
>+ * Syntax: *queue X*
>+
>+Example flow rules:
>+
>+.. code-block:: console
>+
>+    flow ipv4 dst 172.16.1.5/32 port 0 queue 0
>+
>+    flow ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 1
>+ queue 0
>+
>+
> Neighbour rule syntax
> ^^^^^^^^^^^^^^^^^^^^^
>
>diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
>index c4a272a..dbae152 100644
>--- a/examples/ipsec-secgw/Makefile
>+++ b/examples/ipsec-secgw/Makefile
>@@ -18,6 +18,7 @@ SRCS-y += ipsec_process.c  SRCS-y += ipsec-secgw.c
>SRCS-y += ipsec_worker.c  SRCS-y += event_helper.c
>+SRCS-y += flow.c
>
> CFLAGS += -gdwarf-2
>
>diff --git a/examples/ipsec-secgw/flow.c b/examples/ipsec-secgw/flow.c new
>file mode 100644 index 0000000..69f8405
>--- /dev/null
>+++ b/examples/ipsec-secgw/flow.c
>@@ -0,0 +1,285 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright (C) 2020 Marvell International Ltd.
>+ */
>+
>+#include <stdio.h>
>+
>+#include <rte_common.h>
>+#include <rte_flow.h>
>+#include <rte_ip.h>
>+
>+#include "flow.h"
>+#include "ipsec-secgw.h"
>+#include "parser.h"
>+
>+#define FLOW_RULES_MAX 128
>+
>+struct flow_rule_entry {
>+	uint8_t is_ipv4;
>+	RTE_STD_C11
>+	union {
>+		struct {
>+			struct rte_flow_item_ipv4 spec;
>+			struct rte_flow_item_ipv4 mask;
>+		} ipv4;
>+		struct {
>+			struct rte_flow_item_ipv6 spec;
>+			struct rte_flow_item_ipv6 mask;
>+		} ipv6;
>+	};
>+	uint16_t port;
>+	uint16_t queue;
>+	struct rte_flow *flow;
>+} flow_rule_tbl[FLOW_RULES_MAX];
>+
>+int nb_flow_rule;
>+
>+static void
>+ipv4_hdr_print(struct rte_ipv4_hdr *hdr) {
>+	char a, b, c, d;
>+
>+	uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
>+	printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
>+
>+	uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
>+	printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d); }
>+
>+static int
>+ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
>+	      struct parse_status *status)
>+{
>+	struct in_addr ip;
>+	uint32_t depth;
>+
>+	APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
>+		 "unrecognized input \"%s\", expect valid ipv4 addr", token);
>+	if (status->status < 0)
>+		return -1;
>+
>+	if (depth > 32)
>+		return -1;
>+
>+	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
>+
>+	*spec = ip.s_addr;
>+	if (depth < 32)
>+		*mask = *mask << (32-depth);
>+
>+	return 0;
>+}
>+
>+static void
>+ipv6_hdr_print(struct rte_ipv6_hdr *hdr) {
>+	uint8_t *addr;
>+
>+	addr = hdr->src_addr;
>+	printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
>+	       (uint16_t)((addr[0] << 8) | addr[1]),
>+	       (uint16_t)((addr[2] << 8) | addr[3]),
>+	       (uint16_t)((addr[4] << 8) | addr[5]),
>+	       (uint16_t)((addr[6] << 8) | addr[7]),
>+	       (uint16_t)((addr[8] << 8) | addr[9]),
>+	       (uint16_t)((addr[10] << 8) | addr[11]),
>+	       (uint16_t)((addr[12] << 8) | addr[13]),
>+	       (uint16_t)((addr[14] << 8) | addr[15]));
>+
>+	addr = hdr->dst_addr;
>+	printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
>+	       (uint16_t)((addr[0] << 8) | addr[1]),
>+	       (uint16_t)((addr[2] << 8) | addr[3]),
>+	       (uint16_t)((addr[4] << 8) | addr[5]),
>+	       (uint16_t)((addr[6] << 8) | addr[7]),
>+	       (uint16_t)((addr[8] << 8) | addr[9]),
>+	       (uint16_t)((addr[10] << 8) | addr[11]),
>+	       (uint16_t)((addr[12] << 8) | addr[13]),
>+	       (uint16_t)((addr[14] << 8) | addr[15])); }
>+
>+static int
>+ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
>+	      struct parse_status *status)
>+{
>+	struct in6_addr ip;
>+	uint32_t depth, i;
>+
>+	APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
>+		"unrecognized input \"%s\", expect valid ipv6 address",
>token);
>+	if (status->status < 0)
>+		return -1;
>+
>+	memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
>+	memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
>+
>+	for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
>+		mask[i/8] &= ~(1 << (7-i%8));
>+
>+	return 0;
>+}
>+
>+void
>+parse_flow_tokens(char **tokens, uint32_t n_tokens,
>+		  struct parse_status *status)
>+{
>+	struct flow_rule_entry *rule;
>+	uint32_t ti;
>+
>+	if (nb_flow_rule >= FLOW_RULES_MAX) {
>+		printf("Too many flow rules\n");
>+		return;
>+	}
>+
>+	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) {
>+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
>+			if (status->status < 0)
>+				return;
>+
>+			if (rule->is_ipv4) {
>+				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,
>+						  tokens[ti], status))
>+					return;
>+			}
>+		}
>+		if (strcmp(tokens[ti], "dst") == 0) {
>+			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,
>+						  tokens[ti], status))
>+					return;
>+			} else {
>+				if (ipv6_addr_cpy(rule-
>>ipv6.spec.hdr.dst_addr,
>+						  rule-
>>ipv6.mask.hdr.dst_addr,
>+						  tokens[ti], status))
>+					return;
>+			}
>+		}
>+
>+		if (strcmp(tokens[ti], "port") == 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->port = atoi(tokens[ti]);
>+
>+			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->queue = atoi(tokens[ti]);
>+		}
>+	}
>+
>+	nb_flow_rule++;
>+}
>+
>+#define MAX_RTE_FLOW_PATTERN (3)
>+#define MAX_RTE_FLOW_ACTIONS (2)
>+
>+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_attr attr = {};
>+	struct rte_flow_error err;
>+	int ret;
>+
>+	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;
>+
>+	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
>+
>+	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[2].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);
>+		return;
>+	}
>+
>+	rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
>+	if (rule->flow == NULL)
>+		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n",
>err.message); }
>+
>+void
>+flow_init(void)
>+{
>+	struct flow_rule_entry *rule;
>+	int i;
>+
>+	for (i = 0; i < nb_flow_rule; i++) {
>+		rule = &flow_rule_tbl[i];
>+		flow_init_single(rule);
>+	}
>+
>+	for (i = 0; i < nb_flow_rule; i++) {
>+		rule = &flow_rule_tbl[i];
>+		if (rule->is_ipv4) {
>+			printf("Flow #%3d: spec ipv4 ", i);
>+			ipv4_hdr_print(&rule->ipv4.spec.hdr);
>+			printf("\n");
>+			printf("           mask ipv4 ");
>+			ipv4_hdr_print(&rule->ipv4.mask.hdr);
>+		} else {
>+			printf("Flow #%3d: spec ipv6 ", i);
>+			ipv6_hdr_print(&rule->ipv6.spec.hdr);
>+			printf("\n");
>+			printf("           mask ipv6 ");
>+			ipv6_hdr_print(&rule->ipv6.mask.hdr);
>+		}
>+
>+		printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
>+
>+		if (rule->flow == NULL)
>+			printf(" [UNSUPPORTED]");
>+		printf("\n");
>+	}
>+}
>diff --git a/examples/ipsec-secgw/flow.h b/examples/ipsec-secgw/flow.h new
>file mode 100644 index 0000000..1b1b477
>--- /dev/null
>+++ b/examples/ipsec-secgw/flow.h
>@@ -0,0 +1,15 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright (C) 2020 Marvell International Ltd.
>+ */
>+
>+#ifndef _FLOW_H_
>+#define _FLOW_H_
>+
>+#include "parser.h"
>+
>+void parse_flow_tokens(char **tokens, uint32_t n_tokens,
>+		       struct parse_status *status);
>+
>+void flow_init(void);
>+
>+#endif /* _FLOW_H_ */
>diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
>secgw/ipsec-secgw.c
>index f777ce2..d19688d 100644
>--- a/examples/ipsec-secgw/ipsec-secgw.c
>+++ b/examples/ipsec-secgw/ipsec-secgw.c
>@@ -49,6 +49,7 @@
> #include <rte_ip_frag.h>
>
> #include "event_helper.h"
>+#include "flow.h"
> #include "ipsec.h"
> #include "ipsec_worker.h"
> #include "parser.h"
>@@ -2914,6 +2915,8 @@ struct lcore_conf {
> 		}
> 	}
>
>+	flow_init();
>+
> 	check_all_ports_link_status(enabled_port_mask);
>
> 	/* launch per-lcore init on every lcore */ diff --git a/examples/ipsec-
>secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
>index 4b53cb5..412d727 100644
>--- a/examples/ipsec-secgw/ipsec-secgw.h
>+++ b/examples/ipsec-secgw/ipsec-secgw.h
>@@ -34,6 +34,13 @@
> 	((uint64_t)(a) & 0xff))
> #endif
>
>+#define uint32_t_to_char(ip, a, b, c, d) do {\
>+		*a = (uint8_t)(ip >> 24 & 0xff);\
>+		*b = (uint8_t)(ip >> 16 & 0xff);\
>+		*c = (uint8_t)(ip >> 8 & 0xff);\
>+		*d = (uint8_t)(ip & 0xff);\
>+	} while (0)
>+
> #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
>
> struct traffic_type {
>diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
>index 2f69199..7031e28 100644
>--- a/examples/ipsec-secgw/ipsec.h
>+++ b/examples/ipsec-secgw/ipsec.h
>@@ -28,13 +28,6 @@
> #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
> 				sizeof(struct rte_crypto_sym_op))
>
>-#define uint32_t_to_char(ip, a, b, c, d) do {\
>-		*a = (uint8_t)(ip >> 24 & 0xff);\
>-		*b = (uint8_t)(ip >> 16 & 0xff);\
>-		*c = (uint8_t)(ip >> 8 & 0xff);\
>-		*d = (uint8_t)(ip & 0xff);\
>-	} while (0)
>-
> #define DEFAULT_MAX_CATEGORIES	1
>
> #define INVALID_SPI (0)
>diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-
>secgw/meson.build
>index f9ba2a2..d0373da 100644
>--- a/examples/ipsec-secgw/meson.build
>+++ b/examples/ipsec-secgw/meson.build
>@@ -9,6 +9,17 @@
> deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec', 'eventdev']
>allow_experimental_apis = true  sources = files(
>-	'esp.c', 'event_helper.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
>-	'ipsec_worker.c', 'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
>+	'esp.c',
>+	'event_helper.c',
>+	'flow.c',
>+	'ipsec.c',
>+	'ipsec_process.c',
>+	'ipsec-secgw.c',
>+	'ipsec_worker.c',
>+	'parser.c',
>+	'rt.c',
>+	'sa.c',
>+	'sad.c',
>+	'sp4.c',
>+	'sp6.c'
> )
>diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
>index 65eb7e9..8f66660 100644
>--- a/examples/ipsec-secgw/parser.c
>+++ b/examples/ipsec-secgw/parser.c
>@@ -11,6 +11,7 @@
> #include <cmdline_socket.h>
> #include <cmdline.h>
>
>+#include "flow.h"
> #include "ipsec.h"
> #include "parser.h"
>
>@@ -484,6 +485,49 @@ struct cfg_rt_add_cfg_item {
> 	},
> };
>
>+/* flow add parse */
>+struct cfg_flow_add_cfg_item {
>+	cmdline_fixed_string_t flow_keyword;
>+	cmdline_multi_string_t multi_string;
>+};
>+
>+static void
>+cfg_flow_add_cfg_item_parsed(void *parsed_result,
>+	__rte_unused struct cmdline *cl, void *data) {
>+	struct cfg_flow_add_cfg_item *params = parsed_result;
>+	char *tokens[32];
>+	uint32_t n_tokens = RTE_DIM(tokens);
>+	struct parse_status *status = (struct parse_status *)data;
>+
>+	APP_CHECK(parse_tokenize_string(
>+		params->multi_string, tokens, &n_tokens) == 0,
>+		status, "too many arguments\n");
>+	if (status->status < 0)
>+		return;
>+
>+	parse_flow_tokens(tokens, n_tokens, status); }
>+
>+static cmdline_parse_token_string_t cfg_flow_add_flow_str =
>+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
>+		flow_keyword, "flow");
>+
>+static cmdline_parse_token_string_t cfg_flow_add_multi_str =
>+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
>multi_string,
>+		TOKEN_STRING_MULTI);
>+
>+cmdline_parse_inst_t cfg_flow_add_rule = {
>+	.f = cfg_flow_add_cfg_item_parsed,
>+	.data = NULL,
>+	.help_str = "",
>+	.tokens = {
>+		(void *) &cfg_flow_add_flow_str,
>+		(void *) &cfg_flow_add_multi_str,
>+		NULL,
>+	},
>+};
>+
> /* neigh add parse */
> struct cfg_neigh_add_item {
> 	cmdline_fixed_string_t neigh;
>@@ -538,6 +582,7 @@ struct cfg_neigh_add_item {
> 	(cmdline_parse_inst_t *)&cfg_sp_add_rule,
> 	(cmdline_parse_inst_t *)&cfg_sa_add_rule,
> 	(cmdline_parse_inst_t *)&cfg_rt_add_rule,
>+	(cmdline_parse_inst_t *)&cfg_flow_add_rule,
> 	(cmdline_parse_inst_t *)&cfg_neigh_add_rule,
> 	NULL,
> };
>@@ -564,6 +609,7 @@ struct cfg_neigh_add_item {
> 	cfg_sp_add_rule.data = &status;
> 	cfg_sa_add_rule.data = &status;
> 	cfg_rt_add_rule.data = &status;
>+	cfg_flow_add_rule.data = &status;
> 	cfg_neigh_add_rule.data = &status;
>
> 	do {
>diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
>index 6e764fe..a0ff7e1 100644
>--- a/examples/ipsec-secgw/parser.h
>+++ b/examples/ipsec-secgw/parser.h
>@@ -2,12 +2,13 @@
>  * Copyright(c) 2016 Intel Corporation
>  */
>
>+#ifndef __PARSER_H
>+#define __PARSER_H
>+
> #include <sys/types.h>
> #include <netinet/in.h>
> #include <netinet/ip.h>
>-
>-#ifndef __PARSER_H
>-#define __PARSER_H
>+#include <string.h>
>
> struct parse_status {
> 	int status;
>--
>1.9.3


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

* Re: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: enable rte_flow based packet distribution
  2020-07-14  9:28   ` Ankur Dwivedi
@ 2020-07-16 16:48     ` Akhil Goyal
  0 siblings, 0 replies; 6+ messages in thread
From: Akhil Goyal @ 2020-07-16 16:48 UTC (permalink / raw)
  To: Ankur Dwivedi
  Cc: praveen.shetty, konstantin.ananyev, radu.nicolau, Anoob Joseph, dev

Hi Ankur,
> >
> >From: Anoob Joseph <anoobj@marvell.com>
> >
> >RTE_FLOW API allows hardware parsing and steering of packets to specific
> >queues which helps in distributing ingress traffic across various cores.
> >Adding 'flow' rules allows user to specify the distribution required.
> >
> >Signed-off-by: Anoob Joseph <anoobj@marvell.com>
> >---
Please add the feature in the release notes.

Acked-by: Akhil Goyal <akhil.goyal@nxp.com>


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

* [dpdk-dev] [PATCH v3] examples/ipsec-secgw: enable rte_flow based packet distribution
  2020-06-10  9:08 ` [dpdk-dev] [PATCH v2] " Ankur Dwivedi
  2020-07-14  9:28   ` Ankur Dwivedi
@ 2020-07-17 12:31   ` Ankur Dwivedi
  2020-07-20  9:12     ` Akhil Goyal
  1 sibling, 1 reply; 6+ messages in thread
From: Ankur Dwivedi @ 2020-07-17 12:31 UTC (permalink / raw)
  To: dev; +Cc: akhil.goyal, praveen.shetty, konstantin.ananyev, radu.nicolau, anoobj

From: Anoob Joseph <anoobj@marvell.com>

RTE_FLOW API allows hardware parsing and steering of packets to specific
queues which helps in distributing ingress traffic across various cores.
Adding 'flow' rules allows user to specify the distribution required.

Signed-off-by: Anoob Joseph <anoobj@marvell.com>
Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
---
v3:
* Updated the release note with feature.
* Rebased on recent dpdk-next-crypto.

v2:
* Removed Change-Id

 doc/guides/rel_notes/release_20_08.rst   |   5 +
 doc/guides/sample_app_ug/ipsec_secgw.rst |  78 ++++++++-
 examples/ipsec-secgw/Makefile            |   1 +
 examples/ipsec-secgw/flow.c              | 285 +++++++++++++++++++++++++++++++
 examples/ipsec-secgw/flow.h              |  15 ++
 examples/ipsec-secgw/ipsec-secgw.c       |   3 +
 examples/ipsec-secgw/ipsec-secgw.h       |   7 +
 examples/ipsec-secgw/ipsec.h             |   7 -
 examples/ipsec-secgw/meson.build         |  15 +-
 examples/ipsec-secgw/parser.c            |  46 +++++
 examples/ipsec-secgw/parser.h            |   7 +-
 11 files changed, 455 insertions(+), 14 deletions(-)
 create mode 100644 examples/ipsec-secgw/flow.c
 create mode 100644 examples/ipsec-secgw/flow.h

diff --git a/doc/guides/rel_notes/release_20_08.rst b/doc/guides/rel_notes/release_20_08.rst
index 4883de34..f9c1213 100644
--- a/doc/guides/rel_notes/release_20_08.rst
+++ b/doc/guides/rel_notes/release_20_08.rst
@@ -228,6 +228,11 @@ New Features
   See the :doc:`../sample_app_ug/l2_forward_real_virtual` for more
   details of this parameter usage.
 
+* **Updated ipsec-secgw sample application.**
+
+  Added ``rte_flow`` based rules, which allows hardware parsing and steering
+  of ingress packets to specific NIC queues.
+  See the :doc:`../sample_app_ug/ipsec_secgw` for more details.
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 81c5d43..434f484 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -348,7 +348,7 @@ Configurations
 --------------
 
 The following sections provide the syntax of configurations to initialize
-your SP, SA, Routing and Neighbour tables.
+your SP, SA, Routing, Flow and Neighbour tables.
 Configurations shall be specified in the configuration file to be passed to
 the application. The file is then parsed by the application. The successful
 parsing will result in the appropriate rules being applied to the tables
@@ -369,7 +369,7 @@ General rule syntax
 
 The parse treats one line in the configuration file as one configuration
 item (unless the line concatenation symbol exists). Every configuration
-item shall follow the syntax of either SP, SA, Routing or Neighbour
+item shall follow the syntax of either SP, SA, Routing, Flow or Neighbour
 rules specified below.
 
 The configuration parser supports the following special symbols:
@@ -808,6 +808,80 @@ Example SP rules:
 
     rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0
 
+Flow rule syntax
+^^^^^^^^^^^^^^^^
+
+Flow rule enables the usage of hardware classification capabilities to match specific
+ingress traffic and redirect the packets to the specified queue. This feature is
+optional and relies on hardware ``rte_flow`` support.
+
+The flow rule syntax is shown as follows:
+
+.. code-block:: console
+
+    flow <ip_ver> <src_ip> <dst_ip> <port> <queue>
+
+
+where each options means:
+
+``<ip_ver>``
+
+ * IP protocol version
+
+ * Optional: No
+
+ * Available options:
+
+   * *ipv4*: IP protocol version 4
+   * *ipv6*: IP protocol version 6
+
+``<src_ip>``
+
+ * The source IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *src X.X.X.X/Y* for IPv4
+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<dst_ip>``
+
+ * The destination IP address and mask
+
+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
+
+ * Syntax:
+
+   * *dst X.X.X.X/Y* for IPv4
+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
+
+``<port>``
+
+ * The traffic input port id
+
+ * Optional: yes, default input port 0 will be used
+
+ * Syntax: *port X*
+
+``<queue>``
+
+ * The traffic input queue id
+
+ * Optional: yes, default input queue 0 will be used
+
+ * Syntax: *queue X*
+
+Example flow rules:
+
+.. code-block:: console
+
+    flow ipv4 dst 172.16.1.5/32 port 0 queue 0
+
+    flow ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 1 queue 0
+
+
 Neighbour rule syntax
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index ab15fca..b5ccbca 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -18,6 +18,7 @@ SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
 SRCS-y += ipsec_worker.c
 SRCS-y += event_helper.c
+SRCS-y += flow.c
 
 CFLAGS += -gdwarf-2
 
diff --git a/examples/ipsec-secgw/flow.c b/examples/ipsec-secgw/flow.c
new file mode 100644
index 0000000..69f8405
--- /dev/null
+++ b/examples/ipsec-secgw/flow.c
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_flow.h>
+#include <rte_ip.h>
+
+#include "flow.h"
+#include "ipsec-secgw.h"
+#include "parser.h"
+
+#define FLOW_RULES_MAX 128
+
+struct flow_rule_entry {
+	uint8_t is_ipv4;
+	RTE_STD_C11
+	union {
+		struct {
+			struct rte_flow_item_ipv4 spec;
+			struct rte_flow_item_ipv4 mask;
+		} ipv4;
+		struct {
+			struct rte_flow_item_ipv6 spec;
+			struct rte_flow_item_ipv6 mask;
+		} ipv6;
+	};
+	uint16_t port;
+	uint16_t queue;
+	struct rte_flow *flow;
+} flow_rule_tbl[FLOW_RULES_MAX];
+
+int nb_flow_rule;
+
+static void
+ipv4_hdr_print(struct rte_ipv4_hdr *hdr)
+{
+	char a, b, c, d;
+
+	uint32_t_to_char(rte_bswap32(hdr->src_addr), &a, &b, &c, &d);
+	printf("src: %3hhu.%3hhu.%3hhu.%3hhu \t", a, b, c, d);
+
+	uint32_t_to_char(rte_bswap32(hdr->dst_addr), &a, &b, &c, &d);
+	printf("dst: %3hhu.%3hhu.%3hhu.%3hhu", a, b, c, d);
+}
+
+static int
+ipv4_addr_cpy(rte_be32_t *spec, rte_be32_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in_addr ip;
+	uint32_t depth;
+
+	APP_CHECK(parse_ipv4_addr(token, &ip, &depth) == 0, status,
+		 "unrecognized input \"%s\", expect valid ipv4 addr", token);
+	if (status->status < 0)
+		return -1;
+
+	if (depth > 32)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv4_mask.hdr.src_addr, sizeof(ip));
+
+	*spec = ip.s_addr;
+	if (depth < 32)
+		*mask = *mask << (32-depth);
+
+	return 0;
+}
+
+static void
+ipv6_hdr_print(struct rte_ipv6_hdr *hdr)
+{
+	uint8_t *addr;
+
+	addr = hdr->src_addr;
+	printf("src: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx \t",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+
+	addr = hdr->dst_addr;
+	printf("dst: %4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx:%4hx",
+	       (uint16_t)((addr[0] << 8) | addr[1]),
+	       (uint16_t)((addr[2] << 8) | addr[3]),
+	       (uint16_t)((addr[4] << 8) | addr[5]),
+	       (uint16_t)((addr[6] << 8) | addr[7]),
+	       (uint16_t)((addr[8] << 8) | addr[9]),
+	       (uint16_t)((addr[10] << 8) | addr[11]),
+	       (uint16_t)((addr[12] << 8) | addr[13]),
+	       (uint16_t)((addr[14] << 8) | addr[15]));
+}
+
+static int
+ipv6_addr_cpy(uint8_t *spec, uint8_t *mask, char *token,
+	      struct parse_status *status)
+{
+	struct in6_addr ip;
+	uint32_t depth, i;
+
+	APP_CHECK(parse_ipv6_addr(token, &ip, &depth) == 0, status,
+		"unrecognized input \"%s\", expect valid ipv6 address", token);
+	if (status->status < 0)
+		return -1;
+
+	memcpy(mask, &rte_flow_item_ipv6_mask.hdr.src_addr, sizeof(ip));
+	memcpy(spec, ip.s6_addr, sizeof(struct in6_addr));
+
+	for (i = 0; i < depth && (i%8 <= sizeof(struct in6_addr)); i++)
+		mask[i/8] &= ~(1 << (7-i%8));
+
+	return 0;
+}
+
+void
+parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		  struct parse_status *status)
+{
+	struct flow_rule_entry *rule;
+	uint32_t ti;
+
+	if (nb_flow_rule >= FLOW_RULES_MAX) {
+		printf("Too many flow rules\n");
+		return;
+	}
+
+	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) {
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+
+			if (rule->is_ipv4) {
+				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,
+						  tokens[ti], status))
+					return;
+			}
+		}
+		if (strcmp(tokens[ti], "dst") == 0) {
+			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,
+						  tokens[ti], status))
+					return;
+			} else {
+				if (ipv6_addr_cpy(rule->ipv6.spec.hdr.dst_addr,
+						  rule->ipv6.mask.hdr.dst_addr,
+						  tokens[ti], status))
+					return;
+			}
+		}
+
+		if (strcmp(tokens[ti], "port") == 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->port = atoi(tokens[ti]);
+
+			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->queue = atoi(tokens[ti]);
+		}
+	}
+
+	nb_flow_rule++;
+}
+
+#define MAX_RTE_FLOW_PATTERN (3)
+#define MAX_RTE_FLOW_ACTIONS (2)
+
+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_attr attr = {};
+	struct rte_flow_error err;
+	int ret;
+
+	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;
+
+	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+
+	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[2].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);
+		return;
+	}
+
+	rule->flow = rte_flow_create(rule->port, &attr, pattern, action, &err);
+	if (rule->flow == NULL)
+		RTE_LOG(ERR, IPSEC, "Flow creation return %s\n", err.message);
+}
+
+void
+flow_init(void)
+{
+	struct flow_rule_entry *rule;
+	int i;
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		flow_init_single(rule);
+	}
+
+	for (i = 0; i < nb_flow_rule; i++) {
+		rule = &flow_rule_tbl[i];
+		if (rule->is_ipv4) {
+			printf("Flow #%3d: spec ipv4 ", i);
+			ipv4_hdr_print(&rule->ipv4.spec.hdr);
+			printf("\n");
+			printf("           mask ipv4 ");
+			ipv4_hdr_print(&rule->ipv4.mask.hdr);
+		} else {
+			printf("Flow #%3d: spec ipv6 ", i);
+			ipv6_hdr_print(&rule->ipv6.spec.hdr);
+			printf("\n");
+			printf("           mask ipv6 ");
+			ipv6_hdr_print(&rule->ipv6.mask.hdr);
+		}
+
+		printf("\tPort: %d, Queue: %d", rule->port, rule->queue);
+
+		if (rule->flow == NULL)
+			printf(" [UNSUPPORTED]");
+		printf("\n");
+	}
+}
diff --git a/examples/ipsec-secgw/flow.h b/examples/ipsec-secgw/flow.h
new file mode 100644
index 0000000..1b1b477
--- /dev/null
+++ b/examples/ipsec-secgw/flow.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#ifndef _FLOW_H_
+#define _FLOW_H_
+
+#include "parser.h"
+
+void parse_flow_tokens(char **tokens, uint32_t n_tokens,
+		       struct parse_status *status);
+
+void flow_init(void);
+
+#endif /* _FLOW_H_ */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 6f6abac..8ba15d2 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -50,6 +50,7 @@
 #include <rte_alarm.h>
 
 #include "event_helper.h"
+#include "flow.h"
 #include "ipsec.h"
 #include "ipsec_worker.h"
 #include "parser.h"
@@ -2980,6 +2981,8 @@ struct lcore_conf {
 		}
 	}
 
+	flow_init();
+
 	check_all_ports_link_status(enabled_port_mask);
 
 #if (STATS_INTERVAL > 0)
diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
index 572a930..f2281e7 100644
--- a/examples/ipsec-secgw/ipsec-secgw.h
+++ b/examples/ipsec-secgw/ipsec-secgw.h
@@ -38,6 +38,13 @@
 	((uint64_t)(a) & 0xff))
 #endif
 
+#define uint32_t_to_char(ip, a, b, c, d) do {\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
+	} while (0)
+
 #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
 
 struct traffic_type {
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 2f69199..7031e28 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -28,13 +28,6 @@
 #define IV_OFFSET		(sizeof(struct rte_crypto_op) + \
 				sizeof(struct rte_crypto_sym_op))
 
-#define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (uint8_t)(ip >> 24 & 0xff);\
-		*b = (uint8_t)(ip >> 16 & 0xff);\
-		*c = (uint8_t)(ip >> 8 & 0xff);\
-		*d = (uint8_t)(ip & 0xff);\
-	} while (0)
-
 #define DEFAULT_MAX_CATEGORIES	1
 
 #define INVALID_SPI (0)
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index f9ba2a2..d0373da 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -9,6 +9,17 @@
 deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec', 'eventdev']
 allow_experimental_apis = true
 sources = files(
-	'esp.c', 'event_helper.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'ipsec_worker.c', 'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
+	'esp.c',
+	'event_helper.c',
+	'flow.c',
+	'ipsec.c',
+	'ipsec_process.c',
+	'ipsec-secgw.c',
+	'ipsec_worker.c',
+	'parser.c',
+	'rt.c',
+	'sa.c',
+	'sad.c',
+	'sp4.c',
+	'sp6.c'
 )
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index 65eb7e9..8f66660 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -11,6 +11,7 @@
 #include <cmdline_socket.h>
 #include <cmdline.h>
 
+#include "flow.h"
 #include "ipsec.h"
 #include "parser.h"
 
@@ -484,6 +485,49 @@ struct cfg_rt_add_cfg_item {
 	},
 };
 
+/* flow add parse */
+struct cfg_flow_add_cfg_item {
+	cmdline_fixed_string_t flow_keyword;
+	cmdline_multi_string_t multi_string;
+};
+
+static void
+cfg_flow_add_cfg_item_parsed(void *parsed_result,
+	__rte_unused struct cmdline *cl, void *data)
+{
+	struct cfg_flow_add_cfg_item *params = parsed_result;
+	char *tokens[32];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	struct parse_status *status = (struct parse_status *)data;
+
+	APP_CHECK(parse_tokenize_string(
+		params->multi_string, tokens, &n_tokens) == 0,
+		status, "too many arguments\n");
+	if (status->status < 0)
+		return;
+
+	parse_flow_tokens(tokens, n_tokens, status);
+}
+
+static cmdline_parse_token_string_t cfg_flow_add_flow_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item,
+		flow_keyword, "flow");
+
+static cmdline_parse_token_string_t cfg_flow_add_multi_str =
+	TOKEN_STRING_INITIALIZER(struct cfg_flow_add_cfg_item, multi_string,
+		TOKEN_STRING_MULTI);
+
+cmdline_parse_inst_t cfg_flow_add_rule = {
+	.f = cfg_flow_add_cfg_item_parsed,
+	.data = NULL,
+	.help_str = "",
+	.tokens = {
+		(void *) &cfg_flow_add_flow_str,
+		(void *) &cfg_flow_add_multi_str,
+		NULL,
+	},
+};
+
 /* neigh add parse */
 struct cfg_neigh_add_item {
 	cmdline_fixed_string_t neigh;
@@ -538,6 +582,7 @@ struct cfg_neigh_add_item {
 	(cmdline_parse_inst_t *)&cfg_sp_add_rule,
 	(cmdline_parse_inst_t *)&cfg_sa_add_rule,
 	(cmdline_parse_inst_t *)&cfg_rt_add_rule,
+	(cmdline_parse_inst_t *)&cfg_flow_add_rule,
 	(cmdline_parse_inst_t *)&cfg_neigh_add_rule,
 	NULL,
 };
@@ -564,6 +609,7 @@ struct cfg_neigh_add_item {
 	cfg_sp_add_rule.data = &status;
 	cfg_sa_add_rule.data = &status;
 	cfg_rt_add_rule.data = &status;
+	cfg_flow_add_rule.data = &status;
 	cfg_neigh_add_rule.data = &status;
 
 	do {
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6e764fe..a0ff7e1 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -2,12 +2,13 @@
  * Copyright(c) 2016 Intel Corporation
  */
 
+#ifndef __PARSER_H
+#define __PARSER_H
+
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
-
-#ifndef __PARSER_H
-#define __PARSER_H
+#include <string.h>
 
 struct parse_status {
 	int status;
-- 
1.9.3


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

* Re: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: enable rte_flow based packet distribution
  2020-07-17 12:31   ` [dpdk-dev] [PATCH v3] " Ankur Dwivedi
@ 2020-07-20  9:12     ` Akhil Goyal
  0 siblings, 0 replies; 6+ messages in thread
From: Akhil Goyal @ 2020-07-20  9:12 UTC (permalink / raw)
  To: Ankur Dwivedi, dev
  Cc: praveen.shetty, konstantin.ananyev, radu.nicolau, anoobj

> From: Anoob Joseph <anoobj@marvell.com>
> 
> RTE_FLOW API allows hardware parsing and steering of packets to specific
> queues which helps in distributing ingress traffic across various cores.
> Adding 'flow' rules allows user to specify the distribution required.
> 
> Signed-off-by: Anoob Joseph <anoobj@marvell.com>
> Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
Applied to dpdk-next-crypto

Thanks.


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

end of thread, other threads:[~2020-07-20  9:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-10  9:01 [dpdk-dev] [PATCH] examples/ipsec-secgw: enable rte_flow based packet distribution Ankur Dwivedi
2020-06-10  9:08 ` [dpdk-dev] [PATCH v2] " Ankur Dwivedi
2020-07-14  9:28   ` Ankur Dwivedi
2020-07-16 16:48     ` Akhil Goyal
2020-07-17 12:31   ` [dpdk-dev] [PATCH v3] " Ankur Dwivedi
2020-07-20  9:12     ` Akhil Goyal

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git