DPDK-dev Archive on lore.kernel.org
 help / color / Atom feed
* [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw
@ 2019-12-11 16:45 Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 1/4] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
                   ` (9 more replies)
  0 siblings, 10 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-11 16:45 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

This series integrates SA database (SAD) capabilities from ipsec library.
The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
Also patch series removes hardcoded limitation for maximum number of SA's.

Vladimir Medvedkin (4):
  ipsec: move ipsec sad name length into .h
  examples/ipsec-secgw: implement inbound SAD
  examples/ipsec-secgw: integrate inbound SAD
  examples/ipsec-secgw: get rid of maximum sa limitation

 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |  13 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 236 +++++++++++++++++++------------------
 examples/ipsec-secgw/sad.c         |  90 ++++++++++++++
 examples/ipsec-secgw/sad.h         |  74 ++++++++++++
 examples/ipsec-secgw/sp4.c         |  24 ++--
 examples/ipsec-secgw/sp6.c         |  24 ++--
 lib/librte_ipsec/ipsec_sad.c       |  20 ++--
 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
 11 files changed, 344 insertions(+), 146 deletions(-)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

-- 
2.7.4


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

* [dpdk-dev] [PATCH 1/4] ipsec: move ipsec sad name length into .h
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
@ 2019-12-11 16:45 ` Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 2/4] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-11 16:45 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Move IPSEC_SAD_NAMESIZE into public header
and rename it to RTE_IPSEC_SAD_NAMESIZE

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 lib/librte_ipsec/ipsec_sad.c     | 20 ++++++++++----------
 lib/librte_ipsec/rte_ipsec_sad.h |  2 ++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c
index db2c44c..2c994ed 100644
--- a/lib/librte_ipsec/ipsec_sad.c
+++ b/lib/librte_ipsec/ipsec_sad.c
@@ -20,7 +20,6 @@
  * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
  */
 
-#define IPSEC_SAD_NAMESIZE	64
 #define SAD_PREFIX		"SAD_"
 /* "SAD_<name>" */
 #define SAD_FORMAT		SAD_PREFIX "%s"
@@ -34,7 +33,7 @@ struct hash_cnt {
 };
 
 struct rte_ipsec_sad {
-	char name[IPSEC_SAD_NAMESIZE];
+	char name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_hash	*hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
 	/* Array to track number of more specific rules
 	 * (spi_dip or spi_dip_sip). Used only in add/delete
@@ -231,7 +230,7 @@ struct rte_ipsec_sad *
 rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 {
 	char hash_name[RTE_HASH_NAMESIZE];
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	struct rte_ipsec_sad *sad, *tmp_sad = NULL;
@@ -249,8 +248,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 		return NULL;
 	}
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -326,7 +325,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 	/* guarantee there's no existing */
 	TAILQ_FOREACH(te, sad_list, next) {
 		tmp_sad = (struct rte_ipsec_sad *)te->data;
-		if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, tmp_sad->name,
+				RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	if (te != NULL) {
@@ -354,14 +354,14 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 struct rte_ipsec_sad *
 rte_ipsec_sad_find_existing(const char *name)
 {
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_ipsec_sad *sad = NULL;
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	int ret;
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -372,7 +372,7 @@ rte_ipsec_sad_find_existing(const char *name)
 	rte_mcfg_tailq_read_lock();
 	TAILQ_FOREACH(te, sad_list, next) {
 		sad = (struct rte_ipsec_sad *) te->data;
-		if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, sad->name, RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	rte_mcfg_tailq_read_unlock();
diff --git a/lib/librte_ipsec/rte_ipsec_sad.h b/lib/librte_ipsec/rte_ipsec_sad.h
index 8386f73..dcc8224 100644
--- a/lib/librte_ipsec/rte_ipsec_sad.h
+++ b/lib/librte_ipsec/rte_ipsec_sad.h
@@ -47,6 +47,8 @@ union rte_ipsec_sad_key {
 	struct rte_ipsec_sadv6_key	v6;
 };
 
+/** Max number of characters in SAD name. */
+#define RTE_IPSEC_SAD_NAMESIZE		64
 /** Flag to create SAD with ipv6 dip and sip addresses */
 #define RTE_IPSEC_SAD_FLAG_IPV6			0x1
 /** Flag to support reader writer concurrency */
-- 
2.7.4


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

* [dpdk-dev] [PATCH 2/4] examples/ipsec-secgw: implement inbound SAD
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 1/4] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
@ 2019-12-11 16:45 ` Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 3/4] examples/ipsec-secgw: integrate " Vladimir Medvedkin
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-11 16:45 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Add initial support for librte_ipsec SAD library

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h | 11 ++++++
 examples/ipsec-secgw/sad.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sad.h   | 74 ++++++++++++++++++++++++++++++++++++
 3 files changed, 175 insertions(+)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 8e07521..132286c 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -53,6 +53,17 @@ struct ipsec_xform;
 struct rte_mbuf;
 
 struct ipsec_sa;
+/*
+ * Keeps number of configured SA's of each type:
+ * transport
+ * v4 tunnel
+ * v6 tunnel
+ */
+struct ipsec_sa_cnt {
+	uint32_t	nb_trn;
+	uint32_t	nb_v4_tun;
+	uint32_t	nb_v6_tun;
+};
 
 typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
diff --git a/examples/ipsec-secgw/sad.c b/examples/ipsec-secgw/sad.c
new file mode 100644
index 0000000..bcac462
--- /dev/null
+++ b/examples/ipsec-secgw/sad.c
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <rte_errno.h>
+
+#include "ipsec.h"
+#include "sad.h"
+
+int
+ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
+{
+	int ret;
+	union rte_ipsec_sad_key key = { {0} };
+
+	/* spi field is common for ipv4 and ipv6 key types */
+	key.v4.spi = rte_cpu_to_be_32(sa->spi);
+	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
+	case IP4_TUNNEL:
+		key.v4.dip = rte_cpu_to_be_32(sa->dst.ip.ip4);
+		key.v4.sip = rte_cpu_to_be_32(sa->src.ip.ip4);
+		ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case IP6_TUNNEL:
+		memcpy(key.v6.dip, sa->dst.ip.ip6.ip6,
+				sizeof(key.v6.dip));
+		memcpy(key.v6.sip, sa->src.ip.ip6.ip6,
+				sizeof(key.v6.sip));
+		ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case TRANSPORT:
+		if (sp4_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+
+		if (sp6_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt)
+{
+	int ret;
+	struct rte_ipsec_sad_conf sad_conf;
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v4", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+
+	sad_conf.socket_id = socket_id;
+	sad_conf.flags = 0;
+	/* Make SAD have extra 25% of required number of entries */
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = sa_cnt->nb_trn * 5 / 4;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v4_tun * 5 / 4;
+
+	sad->sad_v4 = rte_ipsec_sad_create(sad_name, &sad_conf);
+	if (sad->sad_v4 == NULL)
+		return -rte_errno;
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v6", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+	sad_conf.flags = RTE_IPSEC_SAD_FLAG_IPV6;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v6_tun * 5 / 4;
+
+	sad->sad_v6 = rte_ipsec_sad_create(name, &sad_conf);
+	if (sad->sad_v6 == NULL)
+		return -rte_errno;
+
+	return 0;
+}
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
new file mode 100644
index 0000000..e754d57
--- /dev/null
+++ b/examples/ipsec-secgw/sad.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef __SAD_H__
+#define __SAD_H__
+
+#include <rte_ipsec_sad.h>
+
+struct ipsec_sad {
+	struct rte_ipsec_sad *sad_v4;
+	struct rte_ipsec_sad *sad_v6;
+};
+
+int ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt);
+
+int ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa);
+
+static inline void
+sad_lookup(const struct ipsec_sad *sad, struct rte_mbuf *pkts[],
+	void *sa[], uint16_t nb_pkts)
+{
+	uint32_t i;
+	uint32_t nb_v4 = 0, nb_v6 = 0;
+	struct rte_esp_hdr *esp;
+	struct rte_ipv4_hdr *ipv4;
+	struct rte_ipv6_hdr *ipv6;
+	struct rte_ipsec_sadv4_key	v4[nb_pkts];
+	struct rte_ipsec_sadv6_key	v6[nb_pkts];
+	int v4_idxes[nb_pkts];
+	int v6_idxes[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v4[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v6[nb_pkts];
+	void *v4_res[nb_pkts];
+	void *v6_res[nb_pkts];
+
+	for (i = 0; i < nb_pkts; i++) {
+		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
+		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
+				pkts[i]->l3_len);
+		if ((ipv4->version_ihl >> 4) == IPVERSION) {
+			v4[nb_v4].spi = esp->spi;
+			v4[nb_v4].dip = ipv4->dst_addr;
+			v4[nb_v4].sip = ipv4->src_addr;
+			keys_v4[nb_v4] = (const union rte_ipsec_sad_key *)
+						&v4[nb_v4];
+			v4_idxes[nb_v4++] = i;
+		} else {
+			ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
+			v6[nb_v6].spi = esp->spi;
+			memcpy(v6[nb_v6].dip, ipv6->dst_addr,
+					sizeof(ipv6->dst_addr));
+			memcpy(v6[nb_v6].sip, ipv6->src_addr,
+					sizeof(ipv6->src_addr));
+			keys_v6[nb_v6] = (const union rte_ipsec_sad_key *)
+						&v6[nb_v6];
+			v6_idxes[nb_v6++] = i;
+		}
+	}
+
+	if (nb_v4 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v4, keys_v4, v4_res, nb_v4);
+	if (nb_v6 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v6, keys_v6, v6_res, nb_v6);
+
+	for (i = 0; i < nb_v4; i++)
+		sa[v4_idxes[i]] = v4_res[i];
+
+	for (i = 0; i < nb_v6; i++)
+		sa[v6_idxes[i]] = v6_res[i];
+}
+
+#endif /* __SAD_H__ */
-- 
2.7.4


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

* [dpdk-dev] [PATCH 3/4] examples/ipsec-secgw: integrate inbound SAD
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 1/4] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 2/4] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
@ 2019-12-11 16:45 ` " Vladimir Medvedkin
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 4/4] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-11 16:45 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Integrate ipsec SAD support into secgw app:

1. Use SAD library for inbound SA lookup
2. Changes in struct sa_ctx:
  - sa array allocates dynamically depending on number of configured sa
  - All SA's are kept one by one without using SPI2IDX
3. SP's userdata now contain index of SA in sa_ctx instead of SPI
4. Get rid of SPI2IDX macro

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |   2 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 160 +++++++++++++++++--------------------
 examples/ipsec-secgw/sp4.c         |  24 +++---
 examples/ipsec-secgw/sp6.c         |  24 +++---
 7 files changed, 110 insertions(+), 107 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 851123b..8734b15 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -12,6 +12,7 @@ SRCS-y += esp.c
 SRCS-y += sp4.c
 SRCS-y += sp6.c
 SRCS-y += sa.c
+SRCS-y += sad.c
 SRCS-y += rt.c
 SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3b5aaf6..3e5f82e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -601,7 +601,7 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
 			continue;
 		}
 
-		sa_idx = SPI2IDX(res);
+		sa_idx = res - 1;
 		if (!inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
@@ -688,7 +688,7 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
 	j = 0;
 	for (i = 0; i < ip->num; i++) {
 		m = ip->pkts[i];
-		sa_idx = SPI2IDX(ip->res[i]);
+		sa_idx = ip->res[i] - 1;
 		if (ip->res[i] == DISCARD)
 			rte_pktmbuf_free(m);
 		else if (ip->res[i] == BYPASS)
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 132286c..f731bf8 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -363,7 +363,7 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
  * or -ENOENT otherwise.
  */
 int
-sa_spi_present(uint32_t spi, int inbound);
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound);
 
 void
 sa_init(struct socket_ctx *ctx, int32_t socket_id);
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index 9ece345..6bd5b78 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec']
 allow_experimental_apis = true
 sources = files(
 	'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c'
+	'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
 )
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 7f046e3..8cc7b17 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -24,6 +24,7 @@
 #include "ipsec.h"
 #include "esp.h"
 #include "parser.h"
+#include "sad.h"
 
 #define IPDEFTTL 64
 
@@ -134,9 +135,11 @@ const struct supported_aead_algo aead_algos[] = {
 
 static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_out;
+static struct ipsec_sa_cnt sa_out_cnt;
 
 static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_in;
+static struct ipsec_sa_cnt sa_in_cnt;
 
 static const struct supported_cipher_algo *
 find_match_cipher_algo(const char *cipher_keyword)
@@ -229,6 +232,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
 	uint32_t *ri /*rule index*/;
+	struct ipsec_sa_cnt *sa_cnt;
 	uint32_t cipher_algo_p = 0;
 	uint32_t auth_algo_p = 0;
 	uint32_t aead_algo_p = 0;
@@ -241,6 +245,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
+		sa_cnt = &sa_in_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -251,6 +256,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
+		sa_cnt = &sa_out_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -280,13 +286,16 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
+			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
+				sa_cnt->nb_v4_tun++;
 				rule->flags = IP4_TUNNEL;
-			else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
+			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
+				sa_cnt->nb_v6_tun++;
 				rule->flags = IP6_TUNNEL;
-			else if (strcmp(tokens[ti], "transport") == 0)
+			} else if (strcmp(tokens[ti], "transport") == 0) {
+				sa_cnt->nb_trn++;
 				rule->flags = TRANSPORT;
-			else {
+			} else {
 				APP_CHECK(0, status, "unrecognized "
 					"input \"%s\"", tokens[ti]);
 				return;
@@ -772,19 +781,21 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	printf("\n");
 }
 
+struct ipsec_xf {
+	struct rte_crypto_sym_xform a;
+	struct rte_crypto_sym_xform b;
+};
+
 struct sa_ctx {
 	void *satbl; /* pointer to array of rte_ipsec_sa objects*/
-	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
-	union {
-		struct {
-			struct rte_crypto_sym_xform a;
-			struct rte_crypto_sym_xform b;
-		};
-	} xf[IPSEC_SA_MAX_ENTRIES];
+	struct ipsec_sad sad;
+	struct ipsec_xf *xf;
+	uint32_t nb_sa;
+	struct ipsec_sa sa[];
 };
 
 static struct sa_ctx *
-sa_create(const char *name, int32_t socket_id)
+sa_create(const char *name, int32_t socket_id, uint32_t nb_sa)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
@@ -793,20 +804,31 @@ sa_create(const char *name, int32_t socket_id)
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
 
-	/* Create SA array table */
+	/* Create SA context */
 	printf("Creating SA context with %u maximum entries on socket %d\n",
-			IPSEC_SA_MAX_ENTRIES, socket_id);
+			nb_sa, socket_id);
 
-	mz_size = sizeof(struct sa_ctx);
+	mz_size = sizeof(struct ipsec_xf) * nb_sa;
 	mz = rte_memzone_reserve(s, mz_size, socket_id,
 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
 	if (mz == NULL) {
-		printf("Failed to allocate SA DB memory\n");
+		printf("Failed to allocate SA XFORM memory\n");
 		rte_errno = ENOMEM;
 		return NULL;
 	}
 
-	sa_ctx = (struct sa_ctx *)mz->addr;
+	sa_ctx = rte_malloc(NULL, sizeof(struct sa_ctx) +
+		sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE);
+
+	if (sa_ctx == NULL) {
+		printf("Failed to allocate SA CTX memory\n");
+		rte_errno = ENOMEM;
+		rte_memzone_free(mz);
+		return NULL;
+	}
+
+	sa_ctx->xf = (struct ipsec_xf *)mz->addr;
+	sa_ctx->nb_sa = nb_sa;
 
 	return sa_ctx;
 }
@@ -949,7 +971,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
 	for (i = 0; i < nb_entries; i++) {
-		idx = SPI2IDX(entries[i].spi);
+		idx = i;
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
@@ -957,6 +979,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
+
+		if (inbound) {
+			rc = ipsec_sad_add(&sa_ctx->sad, sa);
+			if (rc != 0)
+				return rc;
+		}
+
 		sa->seq = 0;
 		ips = ipsec_get_primary_session(sa);
 
@@ -1237,8 +1266,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
  * one per session.
  */
 static int
-ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
-	uint32_t nb_ent, int32_t socket)
+ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 {
 	int32_t rc, sz;
 	uint32_t i, idx;
@@ -1248,7 +1276,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	struct rte_ipsec_sa_prm prm;
 
 	/* determine SA size */
-	idx = SPI2IDX(ent[0].spi);
+	idx = 0;
 	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
 	sz = rte_ipsec_sa_size(&prm);
 	if (sz < 0) {
@@ -1271,7 +1299,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	rc = 0;
 	for (i = 0; i != nb_ent && rc == 0; i++) {
 
-		idx = SPI2IDX(ent[i].spi);
+		idx = i;
 
 		sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i);
 		lsa = ctx->sa + idx;
@@ -1286,18 +1314,16 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
  * Walk through all SA rules to find an SA with given SPI
  */
 int
-sa_spi_present(uint32_t spi, int inbound)
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
 	uint32_t i, num;
 	const struct ipsec_sa *sar;
 
-	if (inbound != 0) {
-		sar = sa_in;
+	sar = sa_ctx->sa;
+	if (inbound != 0)
 		num = nb_sa_in;
-	} else {
-		sar = sa_out;
+	else
 		num = nb_sa_out;
-	}
 
 	for (i = 0; i != num; i++) {
 		if (sar[i].spi == spi)
@@ -1326,16 +1352,21 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_in > 0) {
 		name = "sa_in";
-		ctx->sa_in = sa_create(name, socket_id);
+		ctx->sa_in = sa_create(name, socket_id, nb_sa_in);
 		if (ctx->sa_in == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
+		rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id,
+				&sa_in_cnt);
+		if (rc != 0)
+			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
+
 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_in, sa_in, nb_sa_in,
+			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1346,7 +1377,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_out > 0) {
 		name = "sa_out";
-		ctx->sa_out = sa_create(name, socket_id);
+		ctx->sa_out = sa_create(name, socket_id, nb_sa_out);
 		if (ctx->sa_out == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
@@ -1355,7 +1386,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_out, sa_out, nb_sa_out,
+			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1381,28 +1412,13 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return 0;
 }
 
-static inline void
-single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
-		void **sa_ret)
+void
+inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
+		void *sa[], uint16_t nb_pkts)
 {
-	struct rte_esp_hdr *esp;
-	struct ip *ip;
-	uint32_t *src4_addr;
-	uint8_t *src6_addr;
-	struct ipsec_sa *sa;
-	void *result_sa;
+	uint32_t i;
 
-	*sa_ret = NULL;
-
-	ip = rte_pktmbuf_mtod(pkt, struct ip *);
-	esp = rte_pktmbuf_mtod_offset(pkt, struct rte_esp_hdr *, pkt->l3_len);
-
-	if (esp->spi == INVALID_SPI)
-		return;
-
-	result_sa = sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
-	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
-		return;
+	sad_lookup(&sa_ctx->sad, pkts, sa, nb_pkts);
 
 	/*
 	 * Mark need for inline offload fallback on the LSB of SA pointer.
@@ -1413,40 +1429,14 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 	 * pointer to prevent from unintentional use. Use ipsec_mask_saptr
 	 * to get valid struct pointer.
 	 */
-	if (MBUF_NO_SEC_OFFLOAD(pkt) && sa->fallback_sessions > 0) {
-		uintptr_t intsa = (uintptr_t)sa;
-		intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
-		result_sa = (void *)intsa;
+	for (i = 0; i < nb_pkts; i++) {
+		if (MBUF_NO_SEC_OFFLOAD(pkts[i]) && (sa[i] != NULL) &&
+			((struct ipsec_sa *)sa[i])->fallback_sessions > 0) {
+			uintptr_t intsa = (uintptr_t)sa[i];
+			intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
+			sa[i] = (void *)intsa;
+		}
 	}
-
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
-		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
-		if ((ip->ip_v == IPVERSION) &&
-				(sa->src.ip.ip4 == *src4_addr) &&
-				(sa->dst.ip.ip4 == *(src4_addr + 1)))
-			*sa_ret = result_sa;
-		break;
-	case IP6_TUNNEL:
-		src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
-		if ((ip->ip_v == IP6_VERSION) &&
-				!memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
-				!memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
-			*sa_ret = result_sa;
-		break;
-	case TRANSPORT:
-		*sa_ret = result_sa;
-	}
-}
-
-void
-inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
-		void *sa[], uint16_t nb_pkts)
-{
-	uint32_t i;
-
-	for (i = 0; i < nb_pkts; i++)
-		single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
 }
 
 void
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 3871c6c..1dcec52 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -493,10 +493,11 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl4_rules *acr;
+	int32_t spi_idx;
+	struct acl4_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -508,11 +509,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -535,11 +541,11 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index d8be6b1..b489e15 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -625,10 +625,11 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl6_rules *acr;
+	int32_t spi_idx;
+	struct acl6_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -640,11 +641,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -667,11 +673,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
 				"already initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH 4/4] examples/ipsec-secgw: get rid of maximum sa limitation
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (2 preceding siblings ...)
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 3/4] examples/ipsec-secgw: integrate " Vladimir Medvedkin
@ 2019-12-11 16:45 ` Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-11 16:45 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Parse config file and save SA's into linked list
instead of flat array with predefined size.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/sa.c | 78 +++++++++++++++++++++++++++++------------------
 1 file changed, 48 insertions(+), 30 deletions(-)

diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8cc7b17..32919fe 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,7 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <sys/queue.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -133,11 +134,17 @@ const struct supported_aead_algo aead_algos[] = {
 	}
 };
 
-static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
+struct ipsec_sa_mgmt {
+	STAILQ_ENTRY(ipsec_sa_mgmt) next;
+	struct ipsec_sa         sa;
+};
+STAILQ_HEAD(sa_head, ipsec_sa_mgmt);
+
+static struct sa_head sa_out_head = STAILQ_HEAD_INITIALIZER(sa_out_head);
 static uint32_t nb_sa_out;
 static struct ipsec_sa_cnt sa_out_cnt;
 
-static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
+static struct sa_head sa_in_head = STAILQ_HEAD_INITIALIZER(sa_in_head);
 static uint32_t nb_sa_in;
 static struct ipsec_sa_cnt sa_in_cnt;
 
@@ -228,6 +235,8 @@ void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
+	struct sa_head *head;
 	struct ipsec_sa *rule = NULL;
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
@@ -243,27 +252,21 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
 
+	sa_mgmt = calloc(1, sizeof(struct ipsec_sa_mgmt));
+	if (sa_mgmt == NULL)
+		return;
+
+	rule = &sa_mgmt->sa;
+
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
 		sa_cnt = &sa_in_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule = &sa_in[*ri];
+		head = &sa_in_head;
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
 		sa_cnt = &sa_out_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule = &sa_out[*ri];
+		head = &sa_out_head;
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	}
 
@@ -687,6 +690,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->portid = -1;
 	}
 
+	STAILQ_INSERT_TAIL(head, sa_mgmt, next);
 	*ri = *ri + 1;
 }
 
@@ -956,12 +960,13 @@ sa_add_address_inline_crypto(struct ipsec_sa *sa)
 }
 
 static int
-sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, uint32_t inbound,
 		struct socket_ctx *skt_ctx)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
 	struct ipsec_sa *sa;
-	uint32_t i, idx;
+	uint32_t idx;
 	uint16_t iv_length, aad_length;
 	int inline_status;
 	int32_t rc;
@@ -970,15 +975,18 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	/* for ESN upper 32 bits of SQN also need to be part of AAD */
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
-	for (i = 0; i < nb_entries; i++) {
-		idx = i;
+	sa_mgmt = STAILQ_FIRST(entries);
+	for (idx = 0; idx < nb_entries; idx++) {
+		if (sa_mgmt == NULL)
+			rte_exit(EXIT_FAILURE, "SA mgmt queue is broken\n");
+
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
 					idx, sa->spi);
 			return -EINVAL;
 		}
-		*sa = entries[i];
+		*sa = sa_mgmt->sa;
 
 		if (inbound) {
 			rc = ipsec_sad_add(&sa_ctx->sad, sa);
@@ -1114,20 +1122,29 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 
 			print_one_sa_rule(sa, inbound);
 		}
+		sa_mgmt = STAILQ_NEXT(sa_mgmt, next);
 	}
 
+	for (sa_mgmt = STAILQ_FIRST(entries); sa_mgmt != NULL;
+			sa_mgmt = STAILQ_FIRST(entries)) {
+		STAILQ_REMOVE_HEAD(entries, next);
+		free(sa_mgmt);
+	}
+
+	STAILQ_INIT(entries);
+
 	return 0;
 }
 
 static inline int
-sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_out_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 0, skt_ctx);
 }
 
 static inline int
-sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_in_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 1, skt_ctx);
@@ -1363,7 +1380,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		if (rc != 0)
 			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
 
-		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
+		sa_in_add_rules(ctx->sa_in, &sa_in_head, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
 			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
@@ -1383,7 +1400,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
-		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
+		sa_out_add_rules(ctx->sa_out, &sa_out_head, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
 			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
@@ -1451,21 +1468,22 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 
 /*
  * Select HW offloads to be used.
+ * Called before sa_init, so working with mgmt queue
  */
 int
 sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 		uint64_t *tx_offloads)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
 	struct ipsec_sa *rule;
-	uint32_t idx_sa;
 	enum rte_security_session_action_type rule_type;
 
 	*rx_offloads = 0;
 	*tx_offloads = 0;
 
 	/* Check for inbound rules that use offloads and use this port */
-	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
-		rule = &sa_in[idx_sa];
+	STAILQ_FOREACH(sa_mgmt, &sa_in_head, next) {
+		rule = &sa_mgmt->sa;
 		rule_type = ipsec_get_action_type(rule);
 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
 				rule_type ==
@@ -1475,8 +1493,8 @@ sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 	}
 
 	/* Check for outbound rules that use offloads and use this port */
-	for (idx_sa = 0; idx_sa < nb_sa_out; idx_sa++) {
-		rule = &sa_out[idx_sa];
+	STAILQ_FOREACH(sa_mgmt, &sa_out_head, next) {
+		rule = &sa_mgmt->sa;
 		rule_type = ipsec_get_action_type(rule);
 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
 				rule_type ==
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (3 preceding siblings ...)
  2019-12-11 16:45 ` [dpdk-dev] [PATCH 4/4] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
@ 2019-12-18 16:00 ` Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
                     ` (5 more replies)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
                   ` (4 subsequent siblings)
  9 siblings, 6 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

This series integrates SA database (SAD) capabilities from ipsec library.
The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
Also patch series removes hardcoded limitation for maximum number of SA's
and SP's.

v2:
 - get rid of maximum sp limitation

Vladimir Medvedkin (5):
  ipsec: move ipsec sad name length into .h
  examples/ipsec-secgw: implement inbound SAD
  examples/ipsec-secgw: integrate inbound SAD
  examples/ipsec-secgw: get rid of maximum sa limitation
  examples/ipsec-secgw: get rid of maximum sp limitation

 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |  13 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 236 +++++++++++++++++++------------------
 examples/ipsec-secgw/sad.c         |  90 ++++++++++++++
 examples/ipsec-secgw/sad.h         |  74 ++++++++++++
 examples/ipsec-secgw/sp4.c         | 141 ++++++++++++----------
 examples/ipsec-secgw/sp6.c         | 138 ++++++++++++----------
 lib/librte_ipsec/ipsec_sad.c       |  20 ++--
 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
 11 files changed, 474 insertions(+), 247 deletions(-)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 1/5] ipsec: move ipsec sad name length into .h
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (4 preceding siblings ...)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
@ 2019-12-18 16:00 ` Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Move IPSEC_SAD_NAMESIZE into public header
and rename it to RTE_IPSEC_SAD_NAMESIZE

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 lib/librte_ipsec/ipsec_sad.c     | 20 ++++++++++----------
 lib/librte_ipsec/rte_ipsec_sad.h |  2 ++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c
index db2c44c..2c994ed 100644
--- a/lib/librte_ipsec/ipsec_sad.c
+++ b/lib/librte_ipsec/ipsec_sad.c
@@ -20,7 +20,6 @@
  * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
  */
 
-#define IPSEC_SAD_NAMESIZE	64
 #define SAD_PREFIX		"SAD_"
 /* "SAD_<name>" */
 #define SAD_FORMAT		SAD_PREFIX "%s"
@@ -34,7 +33,7 @@ struct hash_cnt {
 };
 
 struct rte_ipsec_sad {
-	char name[IPSEC_SAD_NAMESIZE];
+	char name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_hash	*hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
 	/* Array to track number of more specific rules
 	 * (spi_dip or spi_dip_sip). Used only in add/delete
@@ -231,7 +230,7 @@ struct rte_ipsec_sad *
 rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 {
 	char hash_name[RTE_HASH_NAMESIZE];
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	struct rte_ipsec_sad *sad, *tmp_sad = NULL;
@@ -249,8 +248,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 		return NULL;
 	}
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -326,7 +325,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 	/* guarantee there's no existing */
 	TAILQ_FOREACH(te, sad_list, next) {
 		tmp_sad = (struct rte_ipsec_sad *)te->data;
-		if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, tmp_sad->name,
+				RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	if (te != NULL) {
@@ -354,14 +354,14 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 struct rte_ipsec_sad *
 rte_ipsec_sad_find_existing(const char *name)
 {
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_ipsec_sad *sad = NULL;
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	int ret;
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -372,7 +372,7 @@ rte_ipsec_sad_find_existing(const char *name)
 	rte_mcfg_tailq_read_lock();
 	TAILQ_FOREACH(te, sad_list, next) {
 		sad = (struct rte_ipsec_sad *) te->data;
-		if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, sad->name, RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	rte_mcfg_tailq_read_unlock();
diff --git a/lib/librte_ipsec/rte_ipsec_sad.h b/lib/librte_ipsec/rte_ipsec_sad.h
index 8386f73..dcc8224 100644
--- a/lib/librte_ipsec/rte_ipsec_sad.h
+++ b/lib/librte_ipsec/rte_ipsec_sad.h
@@ -47,6 +47,8 @@ union rte_ipsec_sad_key {
 	struct rte_ipsec_sadv6_key	v6;
 };
 
+/** Max number of characters in SAD name. */
+#define RTE_IPSEC_SAD_NAMESIZE		64
 /** Flag to create SAD with ipv6 dip and sip addresses */
 #define RTE_IPSEC_SAD_FLAG_IPV6			0x1
 /** Flag to support reader writer concurrency */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 2/5] examples/ipsec-secgw: implement inbound SAD
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (5 preceding siblings ...)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
@ 2019-12-18 16:00 ` Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Add initial support for librte_ipsec SAD library

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h | 11 ++++++
 examples/ipsec-secgw/sad.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sad.h   | 74 ++++++++++++++++++++++++++++++++++++
 3 files changed, 175 insertions(+)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 8e07521..132286c 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -53,6 +53,17 @@ struct ipsec_xform;
 struct rte_mbuf;
 
 struct ipsec_sa;
+/*
+ * Keeps number of configured SA's of each type:
+ * transport
+ * v4 tunnel
+ * v6 tunnel
+ */
+struct ipsec_sa_cnt {
+	uint32_t	nb_trn;
+	uint32_t	nb_v4_tun;
+	uint32_t	nb_v6_tun;
+};
 
 typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
diff --git a/examples/ipsec-secgw/sad.c b/examples/ipsec-secgw/sad.c
new file mode 100644
index 0000000..bcac462
--- /dev/null
+++ b/examples/ipsec-secgw/sad.c
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <rte_errno.h>
+
+#include "ipsec.h"
+#include "sad.h"
+
+int
+ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
+{
+	int ret;
+	union rte_ipsec_sad_key key = { {0} };
+
+	/* spi field is common for ipv4 and ipv6 key types */
+	key.v4.spi = rte_cpu_to_be_32(sa->spi);
+	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
+	case IP4_TUNNEL:
+		key.v4.dip = rte_cpu_to_be_32(sa->dst.ip.ip4);
+		key.v4.sip = rte_cpu_to_be_32(sa->src.ip.ip4);
+		ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case IP6_TUNNEL:
+		memcpy(key.v6.dip, sa->dst.ip.ip6.ip6,
+				sizeof(key.v6.dip));
+		memcpy(key.v6.sip, sa->src.ip.ip6.ip6,
+				sizeof(key.v6.sip));
+		ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case TRANSPORT:
+		if (sp4_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+
+		if (sp6_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt)
+{
+	int ret;
+	struct rte_ipsec_sad_conf sad_conf;
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v4", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+
+	sad_conf.socket_id = socket_id;
+	sad_conf.flags = 0;
+	/* Make SAD have extra 25% of required number of entries */
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = sa_cnt->nb_trn * 5 / 4;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v4_tun * 5 / 4;
+
+	sad->sad_v4 = rte_ipsec_sad_create(sad_name, &sad_conf);
+	if (sad->sad_v4 == NULL)
+		return -rte_errno;
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v6", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+	sad_conf.flags = RTE_IPSEC_SAD_FLAG_IPV6;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v6_tun * 5 / 4;
+
+	sad->sad_v6 = rte_ipsec_sad_create(name, &sad_conf);
+	if (sad->sad_v6 == NULL)
+		return -rte_errno;
+
+	return 0;
+}
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
new file mode 100644
index 0000000..e754d57
--- /dev/null
+++ b/examples/ipsec-secgw/sad.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef __SAD_H__
+#define __SAD_H__
+
+#include <rte_ipsec_sad.h>
+
+struct ipsec_sad {
+	struct rte_ipsec_sad *sad_v4;
+	struct rte_ipsec_sad *sad_v6;
+};
+
+int ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt);
+
+int ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa);
+
+static inline void
+sad_lookup(const struct ipsec_sad *sad, struct rte_mbuf *pkts[],
+	void *sa[], uint16_t nb_pkts)
+{
+	uint32_t i;
+	uint32_t nb_v4 = 0, nb_v6 = 0;
+	struct rte_esp_hdr *esp;
+	struct rte_ipv4_hdr *ipv4;
+	struct rte_ipv6_hdr *ipv6;
+	struct rte_ipsec_sadv4_key	v4[nb_pkts];
+	struct rte_ipsec_sadv6_key	v6[nb_pkts];
+	int v4_idxes[nb_pkts];
+	int v6_idxes[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v4[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v6[nb_pkts];
+	void *v4_res[nb_pkts];
+	void *v6_res[nb_pkts];
+
+	for (i = 0; i < nb_pkts; i++) {
+		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
+		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
+				pkts[i]->l3_len);
+		if ((ipv4->version_ihl >> 4) == IPVERSION) {
+			v4[nb_v4].spi = esp->spi;
+			v4[nb_v4].dip = ipv4->dst_addr;
+			v4[nb_v4].sip = ipv4->src_addr;
+			keys_v4[nb_v4] = (const union rte_ipsec_sad_key *)
+						&v4[nb_v4];
+			v4_idxes[nb_v4++] = i;
+		} else {
+			ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
+			v6[nb_v6].spi = esp->spi;
+			memcpy(v6[nb_v6].dip, ipv6->dst_addr,
+					sizeof(ipv6->dst_addr));
+			memcpy(v6[nb_v6].sip, ipv6->src_addr,
+					sizeof(ipv6->src_addr));
+			keys_v6[nb_v6] = (const union rte_ipsec_sad_key *)
+						&v6[nb_v6];
+			v6_idxes[nb_v6++] = i;
+		}
+	}
+
+	if (nb_v4 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v4, keys_v4, v4_res, nb_v4);
+	if (nb_v6 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v6, keys_v6, v6_res, nb_v6);
+
+	for (i = 0; i < nb_v4; i++)
+		sa[v4_idxes[i]] = v4_res[i];
+
+	for (i = 0; i < nb_v6; i++)
+		sa[v6_idxes[i]] = v6_res[i];
+}
+
+#endif /* __SAD_H__ */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 3/5] examples/ipsec-secgw: integrate inbound SAD
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (6 preceding siblings ...)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
@ 2019-12-18 16:00 ` " Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Integrate ipsec SAD support into secgw app:

1. Use SAD library for inbound SA lookup
2. Changes in struct sa_ctx:
  - sa array allocates dynamically depending on number of configured sa
  - All SA's are kept one by one without using SPI2IDX
3. SP's userdata now contain index of SA in sa_ctx instead of SPI
4. Get rid of SPI2IDX macro

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |   2 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 160 +++++++++++++++++--------------------
 examples/ipsec-secgw/sp4.c         |  24 +++---
 examples/ipsec-secgw/sp6.c         |  24 +++---
 7 files changed, 110 insertions(+), 107 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 851123b..8734b15 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -12,6 +12,7 @@ SRCS-y += esp.c
 SRCS-y += sp4.c
 SRCS-y += sp6.c
 SRCS-y += sa.c
+SRCS-y += sad.c
 SRCS-y += rt.c
 SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3b5aaf6..3e5f82e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -601,7 +601,7 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
 			continue;
 		}
 
-		sa_idx = SPI2IDX(res);
+		sa_idx = res - 1;
 		if (!inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
@@ -688,7 +688,7 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
 	j = 0;
 	for (i = 0; i < ip->num; i++) {
 		m = ip->pkts[i];
-		sa_idx = SPI2IDX(ip->res[i]);
+		sa_idx = ip->res[i] - 1;
 		if (ip->res[i] == DISCARD)
 			rte_pktmbuf_free(m);
 		else if (ip->res[i] == BYPASS)
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 132286c..f731bf8 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -363,7 +363,7 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
  * or -ENOENT otherwise.
  */
 int
-sa_spi_present(uint32_t spi, int inbound);
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound);
 
 void
 sa_init(struct socket_ctx *ctx, int32_t socket_id);
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index 9ece345..6bd5b78 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec']
 allow_experimental_apis = true
 sources = files(
 	'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c'
+	'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
 )
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 7f046e3..8cc7b17 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -24,6 +24,7 @@
 #include "ipsec.h"
 #include "esp.h"
 #include "parser.h"
+#include "sad.h"
 
 #define IPDEFTTL 64
 
@@ -134,9 +135,11 @@ const struct supported_aead_algo aead_algos[] = {
 
 static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_out;
+static struct ipsec_sa_cnt sa_out_cnt;
 
 static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_in;
+static struct ipsec_sa_cnt sa_in_cnt;
 
 static const struct supported_cipher_algo *
 find_match_cipher_algo(const char *cipher_keyword)
@@ -229,6 +232,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
 	uint32_t *ri /*rule index*/;
+	struct ipsec_sa_cnt *sa_cnt;
 	uint32_t cipher_algo_p = 0;
 	uint32_t auth_algo_p = 0;
 	uint32_t aead_algo_p = 0;
@@ -241,6 +245,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
+		sa_cnt = &sa_in_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -251,6 +256,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
+		sa_cnt = &sa_out_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -280,13 +286,16 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
+			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
+				sa_cnt->nb_v4_tun++;
 				rule->flags = IP4_TUNNEL;
-			else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
+			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
+				sa_cnt->nb_v6_tun++;
 				rule->flags = IP6_TUNNEL;
-			else if (strcmp(tokens[ti], "transport") == 0)
+			} else if (strcmp(tokens[ti], "transport") == 0) {
+				sa_cnt->nb_trn++;
 				rule->flags = TRANSPORT;
-			else {
+			} else {
 				APP_CHECK(0, status, "unrecognized "
 					"input \"%s\"", tokens[ti]);
 				return;
@@ -772,19 +781,21 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	printf("\n");
 }
 
+struct ipsec_xf {
+	struct rte_crypto_sym_xform a;
+	struct rte_crypto_sym_xform b;
+};
+
 struct sa_ctx {
 	void *satbl; /* pointer to array of rte_ipsec_sa objects*/
-	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
-	union {
-		struct {
-			struct rte_crypto_sym_xform a;
-			struct rte_crypto_sym_xform b;
-		};
-	} xf[IPSEC_SA_MAX_ENTRIES];
+	struct ipsec_sad sad;
+	struct ipsec_xf *xf;
+	uint32_t nb_sa;
+	struct ipsec_sa sa[];
 };
 
 static struct sa_ctx *
-sa_create(const char *name, int32_t socket_id)
+sa_create(const char *name, int32_t socket_id, uint32_t nb_sa)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
@@ -793,20 +804,31 @@ sa_create(const char *name, int32_t socket_id)
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
 
-	/* Create SA array table */
+	/* Create SA context */
 	printf("Creating SA context with %u maximum entries on socket %d\n",
-			IPSEC_SA_MAX_ENTRIES, socket_id);
+			nb_sa, socket_id);
 
-	mz_size = sizeof(struct sa_ctx);
+	mz_size = sizeof(struct ipsec_xf) * nb_sa;
 	mz = rte_memzone_reserve(s, mz_size, socket_id,
 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
 	if (mz == NULL) {
-		printf("Failed to allocate SA DB memory\n");
+		printf("Failed to allocate SA XFORM memory\n");
 		rte_errno = ENOMEM;
 		return NULL;
 	}
 
-	sa_ctx = (struct sa_ctx *)mz->addr;
+	sa_ctx = rte_malloc(NULL, sizeof(struct sa_ctx) +
+		sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE);
+
+	if (sa_ctx == NULL) {
+		printf("Failed to allocate SA CTX memory\n");
+		rte_errno = ENOMEM;
+		rte_memzone_free(mz);
+		return NULL;
+	}
+
+	sa_ctx->xf = (struct ipsec_xf *)mz->addr;
+	sa_ctx->nb_sa = nb_sa;
 
 	return sa_ctx;
 }
@@ -949,7 +971,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
 	for (i = 0; i < nb_entries; i++) {
-		idx = SPI2IDX(entries[i].spi);
+		idx = i;
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
@@ -957,6 +979,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
+
+		if (inbound) {
+			rc = ipsec_sad_add(&sa_ctx->sad, sa);
+			if (rc != 0)
+				return rc;
+		}
+
 		sa->seq = 0;
 		ips = ipsec_get_primary_session(sa);
 
@@ -1237,8 +1266,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
  * one per session.
  */
 static int
-ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
-	uint32_t nb_ent, int32_t socket)
+ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 {
 	int32_t rc, sz;
 	uint32_t i, idx;
@@ -1248,7 +1276,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	struct rte_ipsec_sa_prm prm;
 
 	/* determine SA size */
-	idx = SPI2IDX(ent[0].spi);
+	idx = 0;
 	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
 	sz = rte_ipsec_sa_size(&prm);
 	if (sz < 0) {
@@ -1271,7 +1299,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	rc = 0;
 	for (i = 0; i != nb_ent && rc == 0; i++) {
 
-		idx = SPI2IDX(ent[i].spi);
+		idx = i;
 
 		sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i);
 		lsa = ctx->sa + idx;
@@ -1286,18 +1314,16 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
  * Walk through all SA rules to find an SA with given SPI
  */
 int
-sa_spi_present(uint32_t spi, int inbound)
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
 	uint32_t i, num;
 	const struct ipsec_sa *sar;
 
-	if (inbound != 0) {
-		sar = sa_in;
+	sar = sa_ctx->sa;
+	if (inbound != 0)
 		num = nb_sa_in;
-	} else {
-		sar = sa_out;
+	else
 		num = nb_sa_out;
-	}
 
 	for (i = 0; i != num; i++) {
 		if (sar[i].spi == spi)
@@ -1326,16 +1352,21 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_in > 0) {
 		name = "sa_in";
-		ctx->sa_in = sa_create(name, socket_id);
+		ctx->sa_in = sa_create(name, socket_id, nb_sa_in);
 		if (ctx->sa_in == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
+		rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id,
+				&sa_in_cnt);
+		if (rc != 0)
+			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
+
 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_in, sa_in, nb_sa_in,
+			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1346,7 +1377,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_out > 0) {
 		name = "sa_out";
-		ctx->sa_out = sa_create(name, socket_id);
+		ctx->sa_out = sa_create(name, socket_id, nb_sa_out);
 		if (ctx->sa_out == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
@@ -1355,7 +1386,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_out, sa_out, nb_sa_out,
+			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1381,28 +1412,13 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return 0;
 }
 
-static inline void
-single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
-		void **sa_ret)
+void
+inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
+		void *sa[], uint16_t nb_pkts)
 {
-	struct rte_esp_hdr *esp;
-	struct ip *ip;
-	uint32_t *src4_addr;
-	uint8_t *src6_addr;
-	struct ipsec_sa *sa;
-	void *result_sa;
+	uint32_t i;
 
-	*sa_ret = NULL;
-
-	ip = rte_pktmbuf_mtod(pkt, struct ip *);
-	esp = rte_pktmbuf_mtod_offset(pkt, struct rte_esp_hdr *, pkt->l3_len);
-
-	if (esp->spi == INVALID_SPI)
-		return;
-
-	result_sa = sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
-	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
-		return;
+	sad_lookup(&sa_ctx->sad, pkts, sa, nb_pkts);
 
 	/*
 	 * Mark need for inline offload fallback on the LSB of SA pointer.
@@ -1413,40 +1429,14 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 	 * pointer to prevent from unintentional use. Use ipsec_mask_saptr
 	 * to get valid struct pointer.
 	 */
-	if (MBUF_NO_SEC_OFFLOAD(pkt) && sa->fallback_sessions > 0) {
-		uintptr_t intsa = (uintptr_t)sa;
-		intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
-		result_sa = (void *)intsa;
+	for (i = 0; i < nb_pkts; i++) {
+		if (MBUF_NO_SEC_OFFLOAD(pkts[i]) && (sa[i] != NULL) &&
+			((struct ipsec_sa *)sa[i])->fallback_sessions > 0) {
+			uintptr_t intsa = (uintptr_t)sa[i];
+			intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
+			sa[i] = (void *)intsa;
+		}
 	}
-
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
-		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
-		if ((ip->ip_v == IPVERSION) &&
-				(sa->src.ip.ip4 == *src4_addr) &&
-				(sa->dst.ip.ip4 == *(src4_addr + 1)))
-			*sa_ret = result_sa;
-		break;
-	case IP6_TUNNEL:
-		src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
-		if ((ip->ip_v == IP6_VERSION) &&
-				!memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
-				!memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
-			*sa_ret = result_sa;
-		break;
-	case TRANSPORT:
-		*sa_ret = result_sa;
-	}
-}
-
-void
-inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
-		void *sa[], uint16_t nb_pkts)
-{
-	uint32_t i;
-
-	for (i = 0; i < nb_pkts; i++)
-		single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
 }
 
 void
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 3871c6c..1dcec52 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -493,10 +493,11 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl4_rules *acr;
+	int32_t spi_idx;
+	struct acl4_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -508,11 +509,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -535,11 +541,11 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index d8be6b1..b489e15 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -625,10 +625,11 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl6_rules *acr;
+	int32_t spi_idx;
+	struct acl6_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -640,11 +641,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -667,11 +673,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
 				"already initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 4/5] examples/ipsec-secgw: get rid of maximum sa limitation
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (7 preceding siblings ...)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
@ 2019-12-18 16:00 ` Vladimir Medvedkin
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Parse config file and save SA's into linked list
instead of flat array with predefined size.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/sa.c | 78 +++++++++++++++++++++++++++++------------------
 1 file changed, 48 insertions(+), 30 deletions(-)

diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8cc7b17..32919fe 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,7 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <sys/queue.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -133,11 +134,17 @@ const struct supported_aead_algo aead_algos[] = {
 	}
 };
 
-static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
+struct ipsec_sa_mgmt {
+	STAILQ_ENTRY(ipsec_sa_mgmt) next;
+	struct ipsec_sa         sa;
+};
+STAILQ_HEAD(sa_head, ipsec_sa_mgmt);
+
+static struct sa_head sa_out_head = STAILQ_HEAD_INITIALIZER(sa_out_head);
 static uint32_t nb_sa_out;
 static struct ipsec_sa_cnt sa_out_cnt;
 
-static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
+static struct sa_head sa_in_head = STAILQ_HEAD_INITIALIZER(sa_in_head);
 static uint32_t nb_sa_in;
 static struct ipsec_sa_cnt sa_in_cnt;
 
@@ -228,6 +235,8 @@ void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
+	struct sa_head *head;
 	struct ipsec_sa *rule = NULL;
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
@@ -243,27 +252,21 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
 
+	sa_mgmt = calloc(1, sizeof(struct ipsec_sa_mgmt));
+	if (sa_mgmt == NULL)
+		return;
+
+	rule = &sa_mgmt->sa;
+
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
 		sa_cnt = &sa_in_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule = &sa_in[*ri];
+		head = &sa_in_head;
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
 		sa_cnt = &sa_out_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule = &sa_out[*ri];
+		head = &sa_out_head;
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	}
 
@@ -687,6 +690,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->portid = -1;
 	}
 
+	STAILQ_INSERT_TAIL(head, sa_mgmt, next);
 	*ri = *ri + 1;
 }
 
@@ -956,12 +960,13 @@ sa_add_address_inline_crypto(struct ipsec_sa *sa)
 }
 
 static int
-sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, uint32_t inbound,
 		struct socket_ctx *skt_ctx)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
 	struct ipsec_sa *sa;
-	uint32_t i, idx;
+	uint32_t idx;
 	uint16_t iv_length, aad_length;
 	int inline_status;
 	int32_t rc;
@@ -970,15 +975,18 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	/* for ESN upper 32 bits of SQN also need to be part of AAD */
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
-	for (i = 0; i < nb_entries; i++) {
-		idx = i;
+	sa_mgmt = STAILQ_FIRST(entries);
+	for (idx = 0; idx < nb_entries; idx++) {
+		if (sa_mgmt == NULL)
+			rte_exit(EXIT_FAILURE, "SA mgmt queue is broken\n");
+
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
 					idx, sa->spi);
 			return -EINVAL;
 		}
-		*sa = entries[i];
+		*sa = sa_mgmt->sa;
 
 		if (inbound) {
 			rc = ipsec_sad_add(&sa_ctx->sad, sa);
@@ -1114,20 +1122,29 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 
 			print_one_sa_rule(sa, inbound);
 		}
+		sa_mgmt = STAILQ_NEXT(sa_mgmt, next);
 	}
 
+	for (sa_mgmt = STAILQ_FIRST(entries); sa_mgmt != NULL;
+			sa_mgmt = STAILQ_FIRST(entries)) {
+		STAILQ_REMOVE_HEAD(entries, next);
+		free(sa_mgmt);
+	}
+
+	STAILQ_INIT(entries);
+
 	return 0;
 }
 
 static inline int
-sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_out_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 0, skt_ctx);
 }
 
 static inline int
-sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
+sa_in_add_rules(struct sa_ctx *sa_ctx, struct sa_head *entries,
 		uint32_t nb_entries, struct socket_ctx *skt_ctx)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 1, skt_ctx);
@@ -1363,7 +1380,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		if (rc != 0)
 			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
 
-		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
+		sa_in_add_rules(ctx->sa_in, &sa_in_head, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
 			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
@@ -1383,7 +1400,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
-		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
+		sa_out_add_rules(ctx->sa_out, &sa_out_head, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
 			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
@@ -1451,21 +1468,22 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 
 /*
  * Select HW offloads to be used.
+ * Called before sa_init, so working with mgmt queue
  */
 int
 sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 		uint64_t *tx_offloads)
 {
+	struct ipsec_sa_mgmt *sa_mgmt;
 	struct ipsec_sa *rule;
-	uint32_t idx_sa;
 	enum rte_security_session_action_type rule_type;
 
 	*rx_offloads = 0;
 	*tx_offloads = 0;
 
 	/* Check for inbound rules that use offloads and use this port */
-	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
-		rule = &sa_in[idx_sa];
+	STAILQ_FOREACH(sa_mgmt, &sa_in_head, next) {
+		rule = &sa_mgmt->sa;
 		rule_type = ipsec_get_action_type(rule);
 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
 				rule_type ==
@@ -1475,8 +1493,8 @@ sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 	}
 
 	/* Check for outbound rules that use offloads and use this port */
-	for (idx_sa = 0; idx_sa < nb_sa_out; idx_sa++) {
-		rule = &sa_out[idx_sa];
+	STAILQ_FOREACH(sa_mgmt, &sa_out_head, next) {
+		rule = &sa_mgmt->sa;
 		rule_type = ipsec_get_action_type(rule);
 		if ((rule_type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO ||
 				rule_type ==
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 5/5] examples/ipsec-secgw: get rid of maximum sp limitation
  2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                   ` (8 preceding siblings ...)
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
@ 2019-12-18 16:00 ` Vladimir Medvedkin
  9 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2019-12-18 16:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Parse config file and save SP rules into linked list
instead of flat array with predefined size.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/sp4.c | 121 ++++++++++++++++++++++++++-------------------
 examples/ipsec-secgw/sp6.c | 118 +++++++++++++++++++++++--------------------
 2 files changed, 134 insertions(+), 105 deletions(-)

diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 1dcec52..f0938c5 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -8,6 +8,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <sys/queue.h>
 
 #include <rte_acl.h>
 #include <rte_ip.h>
@@ -15,8 +16,6 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
-
 #define IPV4_DST_FROM_SP(acr) \
 		(rte_cpu_to_be_32((acr).field[DST_FIELD_IPV4].value.u32))
 
@@ -97,16 +96,24 @@ static struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
 
-static struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM];
+struct ipsec_sp_mgmt {
+	STAILQ_ENTRY(ipsec_sp_mgmt)	next;
+	struct acl4_rules		sp;
+};
+STAILQ_HEAD(sp_head, ipsec_sp_mgmt);
+
+static struct sp_head sp_out_head = STAILQ_HEAD_INITIALIZER(sp_out_head);
 static uint32_t nb_acl4_rules_out;
 
-static struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM];
+static struct sp_head sp_in_head = STAILQ_HEAD_INITIALIZER(sp_in_head);
 static uint32_t nb_acl4_rules_in;
 
 void
 parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
 {
+	struct ipsec_sp_mgmt *sp_mgmt;
+	struct sp_head *head;
 	struct acl4_rules *rule_ipv4 = NULL;
 
 	uint32_t *ri = NULL; /* rule index */
@@ -124,25 +131,18 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t sport_p = 0;
 	uint32_t dport_p = 0;
 
+	sp_mgmt = calloc(1, sizeof(struct ipsec_sp_mgmt));
+	if (sp_mgmt == NULL)
+		return;
+
+	rule_ipv4 = &sp_mgmt->sp;
+
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl4_rules_in;
-
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule_ipv4 = &acl4_rules_in[*ri];
-
+		head = &sp_in_head;
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl4_rules_out;
-
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule_ipv4 = &acl4_rules_out[*ri];
+		head = &sp_out_head;
 	} else {
 		APP_CHECK(0, status, "unrecognized input \"%s\", expect"
 			" \"in\" or \"out\"\n", tokens[ti]);
@@ -400,6 +400,7 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	if (status->status < 0)
 		return;
 
+	STAILQ_INSERT_TAIL(head, sp_mgmt, next);
 	*ri = *ri + 1;
 }
 
@@ -443,18 +444,34 @@ dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra)
 }
 
 static struct rte_acl_ctx *
-acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
+acl4_init(const char *name, int32_t socketid, struct sp_head *rules_list,
 		uint32_t rules_nb)
 {
 	char s[PATH_MAX];
 	struct rte_acl_param acl_param;
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
+	struct acl4_rules *rules; /* Temporary array containing rules */
+	struct ipsec_sp_mgmt *sp_mgmt;
+	uint32_t i;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
+	/* Create flat array of rules which is needed for acl context */
+	rules = calloc(rules_nb, sizeof(struct acl4_rules));
+	if (rules == NULL)
+		rte_exit(EXIT_FAILURE, "Can't allocate rules array\n");
+
+	sp_mgmt = STAILQ_FIRST(rules_list);
+	for (i = 0; i < rules_nb; i++) {
+		if (sp_mgmt == NULL)
+			rte_exit(EXIT_FAILURE, "SP list is broken\n");
+		rules[i] = sp_mgmt->sp;
+		sp_mgmt = STAILQ_NEXT(sp_mgmt, next);
+	}
+
 	/* Create ACL contexts */
 	snprintf(s, sizeof(s), "%s_%d", name, socketid);
 
@@ -464,7 +481,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -486,6 +503,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 
 	rte_acl_dump(ctx);
 
+	free(rules);
 	return ctx;
 }
 
@@ -495,20 +513,19 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 static int
 check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
-	uint32_t i, num, spi;
+	uint32_t spi;
 	int32_t spi_idx;
-	struct acl4_rules *acr;
+	struct ipsec_sp_mgmt	*sp_mgmt;
+	struct sp_head		*head;
 
-	if (inbound != 0) {
-		acr = acl4_rules_in;
-		num = nb_acl4_rules_in;
-	} else {
-		acr = acl4_rules_out;
-		num = nb_acl4_rules_out;
-	}
+	if (inbound != 0)
+		head = &sp_in_head;
+	else
+		head = &sp_out_head;
 
-	for (i = 0; i != num; i++) {
-		spi = acr[i].data.userdata;
+
+	STAILQ_FOREACH(sp_mgmt, head, next) {
+		spi = sp_mgmt->sp.data.userdata;
 		if (spi != DISCARD && spi != BYPASS) {
 			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
 			if (spi_idx < 0) {
@@ -518,7 +535,7 @@ check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 				return -ENOENT;
 			}
 			/* Update userdata with spi index */
-			acr[i].data.userdata = spi_idx + 1;
+			sp_mgmt->sp.data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -548,11 +565,10 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv4 SP DB has unmatched in SAD SPIs\n");
-
 	if (nb_acl4_rules_in > 0) {
 		name = "sp_ip4_in";
 		ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name,
-			socket_id, acl4_rules_in, nb_acl4_rules_in);
+			socket_id, &sp_in_head, nb_acl4_rules_in);
 	} else
 		RTE_LOG(WARNING, IPSEC, "No IPv4 SP Inbound rule "
 			"specified\n");
@@ -560,7 +576,7 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 	if (nb_acl4_rules_out > 0) {
 		name = "sp_ip4_out";
 		ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name,
-			socket_id, acl4_rules_out, nb_acl4_rules_out);
+			socket_id, &sp_out_head, nb_acl4_rules_out);
 	} else
 		RTE_LOG(WARNING, IPSEC, "No IPv4 SP Outbound rule "
 			"specified\n");
@@ -573,27 +589,28 @@ int
 sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
-	const struct acl4_rules *acr;
+	uint32_t i = 0;
+	struct ipsec_sp_mgmt	*sp_mgmt;
+	struct sp_head		*head;
 
-	if (inbound != 0) {
-		acr = acl4_rules_in;
-		num = nb_acl4_rules_in;
-	} else {
-		acr = acl4_rules_out;
-		num = nb_acl4_rules_out;
-	}
+	if (inbound != 0)
+		head = &sp_in_head;
+	else
+		head = &sp_out_head;
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
+	STAILQ_FOREACH(sp_mgmt, head, next) {
+		if (sp_mgmt->sp.data.userdata == spi) {
 			if (NULL != ip_addr && NULL != mask) {
-				ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(acr[i]);
-				ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(acr[i]);
-				mask[0] = IPV4_SRC_MASK_FROM_SP(acr[i]);
-				mask[1] = IPV4_DST_MASK_FROM_SP(acr[i]);
+				ip_addr[0].ip.ip4 =
+					IPV4_SRC_FROM_SP(sp_mgmt->sp);
+				ip_addr[1].ip.ip4 =
+					IPV4_DST_FROM_SP(sp_mgmt->sp);
+				mask[0] = IPV4_SRC_MASK_FROM_SP(sp_mgmt->sp);
+				mask[1] = IPV4_DST_MASK_FROM_SP(sp_mgmt->sp);
 			}
 			return i;
 		}
+		i++;
 	}
 
 	return -ENOENT;
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index b489e15..b931c50 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -8,6 +8,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip6.h>
+#include <sys/queue.h>
 
 #include <rte_acl.h>
 #include <rte_ip.h>
@@ -15,8 +16,6 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
-
 #define IPV6_FROM_SP(acr, fidx_low, fidx_high) \
 		(((uint64_t)(acr).field[(fidx_high)].value.u32 << 32) | \
 		(acr).field[(fidx_low)].value.u32)
@@ -146,16 +145,24 @@ static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
 
 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
 
-static struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
+struct ipsec_sp_mgmt {
+	STAILQ_ENTRY(ipsec_sp_mgmt)	next;
+	struct acl6_rules		sp;
+};
+STAILQ_HEAD(sp_head, ipsec_sp_mgmt);
+
+static struct sp_head sp_out_head = STAILQ_HEAD_INITIALIZER(sp_out_head);
 static uint32_t nb_acl6_rules_out;
 
-static struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
+static struct sp_head sp_in_head = STAILQ_HEAD_INITIALIZER(sp_in_head);
 static uint32_t nb_acl6_rules_in;
 
 void
 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
 {
+	struct ipsec_sp_mgmt *sp_mgmt;
+	struct sp_head *head;
 	struct acl6_rules *rule_ipv6 = NULL;
 
 	uint32_t *ri = NULL; /* rule index */
@@ -173,26 +180,18 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t sport_p = 0;
 	uint32_t dport_p = 0;
 
+	sp_mgmt = calloc(1, sizeof(struct ipsec_sp_mgmt));
+	if (sp_mgmt == NULL)
+		return;
+
+	rule_ipv6 = &sp_mgmt->sp;
+
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl6_rules_in;
-
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule_ipv6 = &acl6_rules_in[*ri];
-
+		head = &sp_in_head;
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl6_rules_out;
-
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
-			return;
-
-		rule_ipv6 = &acl6_rules_out[*ri];
-
+		head = &sp_out_head;
 	} else {
 		APP_CHECK(0, status, "unrecognized input \"%s\", expect"
 			" \"in\" or \"out\"\n", tokens[ti]);
@@ -201,7 +200,6 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 
 	rule_ipv6->data.category_mask = 1;
 
-
 	for (ti = 2; ti < n_tokens; ti++) {
 		if (strcmp(tokens[ti], "esp") == 0) {
 			/* currently do nothing */
@@ -506,6 +504,7 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	if (status->status < 0)
 		return;
 
+	STAILQ_INSERT_TAIL(head, sp_mgmt, next);
 	*ri = *ri + 1;
 }
 
@@ -575,18 +574,34 @@ dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
 }
 
 static struct rte_acl_ctx *
-acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
+acl6_init(const char *name, int32_t socketid, struct sp_head *rules_list,
 		uint32_t rules_nb)
 {
 	char s[PATH_MAX];
 	struct rte_acl_param acl_param;
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
+	struct acl6_rules *rules; /* Temporary array containing rules */
+	struct ipsec_sp_mgmt *sp_mgmt;
+	uint32_t i;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
+	/* Create flat array of rules which is needed for acl context */
+	rules = calloc(rules_nb, sizeof(struct acl6_rules));
+	if (rules == NULL)
+		rte_exit(EXIT_FAILURE, "Can't allocate rules array\n");
+
+	sp_mgmt = STAILQ_FIRST(rules_list);
+	for (i = 0; i < rules_nb; i++) {
+		if (sp_mgmt == NULL)
+			rte_exit(EXIT_FAILURE, "SP list is broken\n");
+		rules[i] = sp_mgmt->sp;
+		sp_mgmt = STAILQ_NEXT(sp_mgmt, next);
+	}
+
 	/* Create ACL contexts */
 	snprintf(s, sizeof(s), "%s_%d", name, socketid);
 
@@ -596,7 +611,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -618,6 +633,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 
 	rte_acl_dump(ctx);
 
+	free(rules);
 	return ctx;
 }
 
@@ -627,20 +643,18 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 static int
 check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
-	uint32_t i, num, spi;
+	uint32_t spi;
 	int32_t spi_idx;
-	struct acl6_rules *acr;
+	struct ipsec_sp_mgmt    *sp_mgmt;
+	struct sp_head  *head;
 
-	if (inbound != 0) {
-		acr = acl6_rules_in;
-		num = nb_acl6_rules_in;
-	} else {
-		acr = acl6_rules_out;
-		num = nb_acl6_rules_out;
-	}
+	if (inbound != 0)
+		head = &sp_in_head;
+	else
+		head = &sp_out_head;
 
-	for (i = 0; i != num; i++) {
-		spi = acr[i].data.userdata;
+	STAILQ_FOREACH(sp_mgmt, head, next) {
+		spi = sp_mgmt->sp.data.userdata;
 		if (spi != DISCARD && spi != BYPASS) {
 			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
 			if (spi_idx < 0) {
@@ -650,7 +664,7 @@ check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 				return -ENOENT;
 			}
 			/* Update userdata with spi index */
-			acr[i].data.userdata = spi_idx + 1;
+			sp_mgmt->sp.data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -684,7 +698,7 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 	if (nb_acl6_rules_in > 0) {
 		name = "sp_ip6_in";
 		ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
-			socket_id, acl6_rules_in, nb_acl6_rules_in);
+			socket_id, &sp_in_head, nb_acl6_rules_in);
 	} else
 		RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
 			"specified\n");
@@ -692,7 +706,7 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 	if (nb_acl6_rules_out > 0) {
 		name = "sp_ip6_out";
 		ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
-			socket_id, acl6_rules_out, nb_acl6_rules_out);
+			socket_id, &sp_out_head, nb_acl6_rules_out);
 	} else
 		RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "
 			"specified\n");
@@ -705,24 +719,22 @@ int
 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
-	const struct acl6_rules *acr;
+	uint32_t i = 0;
+	struct ipsec_sp_mgmt	*sp_mgmt;
+	struct sp_head		*head;
 
-	if (inbound != 0) {
-		acr = acl6_rules_in;
-		num = nb_acl6_rules_in;
-	} else {
-		acr = acl6_rules_out;
-		num = nb_acl6_rules_out;
-	}
+	if (inbound != 0)
+		head = &sp_in_head;
+	else
+		head = &sp_out_head;
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
+	STAILQ_FOREACH(sp_mgmt, head, next) {
+		if (sp_mgmt->sp.data.userdata == spi) {
 			if (NULL != ip_addr && NULL != mask) {
-				IPV6_SRC_FROM_SP(ip_addr[0], acr[i]);
-				IPV6_DST_FROM_SP(ip_addr[1], acr[i]);
-				IPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);
-				IPV6_DST_MASK_FROM_SP(mask[1], acr[i]);
+				IPV6_SRC_FROM_SP(ip_addr[0], sp_mgmt->sp);
+				IPV6_DST_FROM_SP(ip_addr[1], sp_mgmt->sp);
+				IPV6_SRC_MASK_FROM_SP(mask[0], sp_mgmt->sp);
+				IPV6_DST_MASK_FROM_SP(mask[1], sp_mgmt->sp);
 			}
 			return i;
 		}
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
@ 2020-01-13 12:55   ` " Vladimir Medvedkin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 " Vladimir Medvedkin
                       ` (5 more replies)
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
                     ` (4 subsequent siblings)
  5 siblings, 6 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

This series integrates SA database (SAD) capabilities from ipsec library.
The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
Also patch series removes hardcoded limitation for maximum number of SA's
and SP's.

v3:
 - parse SA and SP into sorted array instead of linked list

v2:
 - get rid of maximum sp limitation

Vladimir Medvedkin (5):
  ipsec: move ipsec sad name length into .h
  examples/ipsec-secgw: implement inbound SAD
  examples/ipsec-secgw: integrate inbound SAD
  examples/ipsec-secgw: get rid of maximum sa limitation
  examples/ipsec-secgw: get rid of maximum sp limitation

 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |  15 ++-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/parser.c      |   4 +
 examples/ipsec-secgw/parser.h      |   9 ++
 examples/ipsec-secgw/sa.c          | 234 +++++++++++++++++++++----------------
 examples/ipsec-secgw/sad.c         |  94 +++++++++++++++
 examples/ipsec-secgw/sad.h         |  74 ++++++++++++
 examples/ipsec-secgw/sp4.c         | 114 +++++++++++++-----
 examples/ipsec-secgw/sp6.c         | 112 +++++++++++++-----
 lib/librte_ipsec/ipsec_sad.c       |  20 ++--
 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
 13 files changed, 507 insertions(+), 178 deletions(-)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 1/5] ipsec: move ipsec sad name length into .h
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
@ 2020-01-13 12:55   ` Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Move IPSEC_SAD_NAMESIZE into public header
and rename it to RTE_IPSEC_SAD_NAMESIZE

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 lib/librte_ipsec/ipsec_sad.c     | 20 ++++++++++----------
 lib/librte_ipsec/rte_ipsec_sad.h |  2 ++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c
index db2c44c..2c994ed 100644
--- a/lib/librte_ipsec/ipsec_sad.c
+++ b/lib/librte_ipsec/ipsec_sad.c
@@ -20,7 +20,6 @@
  * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
  */
 
-#define IPSEC_SAD_NAMESIZE	64
 #define SAD_PREFIX		"SAD_"
 /* "SAD_<name>" */
 #define SAD_FORMAT		SAD_PREFIX "%s"
@@ -34,7 +33,7 @@ struct hash_cnt {
 };
 
 struct rte_ipsec_sad {
-	char name[IPSEC_SAD_NAMESIZE];
+	char name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_hash	*hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
 	/* Array to track number of more specific rules
 	 * (spi_dip or spi_dip_sip). Used only in add/delete
@@ -231,7 +230,7 @@ struct rte_ipsec_sad *
 rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 {
 	char hash_name[RTE_HASH_NAMESIZE];
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	struct rte_ipsec_sad *sad, *tmp_sad = NULL;
@@ -249,8 +248,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 		return NULL;
 	}
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -326,7 +325,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 	/* guarantee there's no existing */
 	TAILQ_FOREACH(te, sad_list, next) {
 		tmp_sad = (struct rte_ipsec_sad *)te->data;
-		if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, tmp_sad->name,
+				RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	if (te != NULL) {
@@ -354,14 +354,14 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 struct rte_ipsec_sad *
 rte_ipsec_sad_find_existing(const char *name)
 {
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_ipsec_sad *sad = NULL;
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	int ret;
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -372,7 +372,7 @@ rte_ipsec_sad_find_existing(const char *name)
 	rte_mcfg_tailq_read_lock();
 	TAILQ_FOREACH(te, sad_list, next) {
 		sad = (struct rte_ipsec_sad *) te->data;
-		if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, sad->name, RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	rte_mcfg_tailq_read_unlock();
diff --git a/lib/librte_ipsec/rte_ipsec_sad.h b/lib/librte_ipsec/rte_ipsec_sad.h
index 8386f73..dcc8224 100644
--- a/lib/librte_ipsec/rte_ipsec_sad.h
+++ b/lib/librte_ipsec/rte_ipsec_sad.h
@@ -47,6 +47,8 @@ union rte_ipsec_sad_key {
 	struct rte_ipsec_sadv6_key	v6;
 };
 
+/** Max number of characters in SAD name. */
+#define RTE_IPSEC_SAD_NAMESIZE		64
 /** Flag to create SAD with ipv6 dip and sip addresses */
 #define RTE_IPSEC_SAD_FLAG_IPV6			0x1
 /** Flag to support reader writer concurrency */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 2/5] examples/ipsec-secgw: implement inbound SAD
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
@ 2020-01-13 12:55   ` Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Add initial support for librte_ipsec SAD library

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h | 11 ++++++
 examples/ipsec-secgw/sad.c   | 94 ++++++++++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sad.h   | 74 ++++++++++++++++++++++++++++++++++
 3 files changed, 179 insertions(+)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 8e07521..132286c 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -53,6 +53,17 @@ struct ipsec_xform;
 struct rte_mbuf;
 
 struct ipsec_sa;
+/*
+ * Keeps number of configured SA's of each type:
+ * transport
+ * v4 tunnel
+ * v6 tunnel
+ */
+struct ipsec_sa_cnt {
+	uint32_t	nb_trn;
+	uint32_t	nb_v4_tun;
+	uint32_t	nb_v6_tun;
+};
 
 typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
diff --git a/examples/ipsec-secgw/sad.c b/examples/ipsec-secgw/sad.c
new file mode 100644
index 0000000..1445c48
--- /dev/null
+++ b/examples/ipsec-secgw/sad.c
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <rte_errno.h>
+
+#include "ipsec.h"
+#include "sad.h"
+
+int
+ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
+{
+	int ret;
+	union rte_ipsec_sad_key key = { {0} };
+
+	/* spi field is common for ipv4 and ipv6 key types */
+	key.v4.spi = rte_cpu_to_be_32(sa->spi);
+	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
+	case IP4_TUNNEL:
+		key.v4.dip = rte_cpu_to_be_32(sa->dst.ip.ip4);
+		key.v4.sip = rte_cpu_to_be_32(sa->src.ip.ip4);
+		ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case IP6_TUNNEL:
+		memcpy(key.v6.dip, sa->dst.ip.ip6.ip6,
+				sizeof(key.v6.dip));
+		memcpy(key.v6.sip, sa->src.ip.ip6.ip6,
+				sizeof(key.v6.sip));
+		ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_DIP_SIP, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case TRANSPORT:
+		if (sp4_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+
+		if (sp6_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt)
+{
+	int ret;
+	struct rte_ipsec_sad_conf sad_conf;
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v4", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+
+	sad_conf.socket_id = socket_id;
+	sad_conf.flags = 0;
+	/* Make SAD have extra 25% of required number of entries */
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = sa_cnt->nb_trn * 5 / 4;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v4_tun * 5 / 4;
+
+	if ((sa_cnt->nb_trn != 0) || (sa_cnt->nb_v4_tun != 0)) {
+		sad->sad_v4 = rte_ipsec_sad_create(sad_name, &sad_conf);
+		if (sad->sad_v4 == NULL)
+			return -rte_errno;
+	}
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v6", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+	sad_conf.flags = RTE_IPSEC_SAD_FLAG_IPV6;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = sa_cnt->nb_v6_tun * 5 / 4;
+
+	if ((sa_cnt->nb_trn != 0) || (sa_cnt->nb_v6_tun != 0)) {
+		sad->sad_v6 = rte_ipsec_sad_create(name, &sad_conf);
+		if (sad->sad_v6 == NULL)
+			return -rte_errno;
+	}
+
+	return 0;
+}
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
new file mode 100644
index 0000000..e754d57
--- /dev/null
+++ b/examples/ipsec-secgw/sad.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef __SAD_H__
+#define __SAD_H__
+
+#include <rte_ipsec_sad.h>
+
+struct ipsec_sad {
+	struct rte_ipsec_sad *sad_v4;
+	struct rte_ipsec_sad *sad_v6;
+};
+
+int ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt);
+
+int ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa);
+
+static inline void
+sad_lookup(const struct ipsec_sad *sad, struct rte_mbuf *pkts[],
+	void *sa[], uint16_t nb_pkts)
+{
+	uint32_t i;
+	uint32_t nb_v4 = 0, nb_v6 = 0;
+	struct rte_esp_hdr *esp;
+	struct rte_ipv4_hdr *ipv4;
+	struct rte_ipv6_hdr *ipv6;
+	struct rte_ipsec_sadv4_key	v4[nb_pkts];
+	struct rte_ipsec_sadv6_key	v6[nb_pkts];
+	int v4_idxes[nb_pkts];
+	int v6_idxes[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v4[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v6[nb_pkts];
+	void *v4_res[nb_pkts];
+	void *v6_res[nb_pkts];
+
+	for (i = 0; i < nb_pkts; i++) {
+		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
+		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
+				pkts[i]->l3_len);
+		if ((ipv4->version_ihl >> 4) == IPVERSION) {
+			v4[nb_v4].spi = esp->spi;
+			v4[nb_v4].dip = ipv4->dst_addr;
+			v4[nb_v4].sip = ipv4->src_addr;
+			keys_v4[nb_v4] = (const union rte_ipsec_sad_key *)
+						&v4[nb_v4];
+			v4_idxes[nb_v4++] = i;
+		} else {
+			ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
+			v6[nb_v6].spi = esp->spi;
+			memcpy(v6[nb_v6].dip, ipv6->dst_addr,
+					sizeof(ipv6->dst_addr));
+			memcpy(v6[nb_v6].sip, ipv6->src_addr,
+					sizeof(ipv6->src_addr));
+			keys_v6[nb_v6] = (const union rte_ipsec_sad_key *)
+						&v6[nb_v6];
+			v6_idxes[nb_v6++] = i;
+		}
+	}
+
+	if (nb_v4 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v4, keys_v4, v4_res, nb_v4);
+	if (nb_v6 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v6, keys_v6, v6_res, nb_v6);
+
+	for (i = 0; i < nb_v4; i++)
+		sa[v4_idxes[i]] = v4_res[i];
+
+	for (i = 0; i < nb_v6; i++)
+		sa[v6_idxes[i]] = v6_res[i];
+}
+
+#endif /* __SAD_H__ */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 3/5] examples/ipsec-secgw: integrate inbound SAD
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                     ` (2 preceding siblings ...)
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
@ 2020-01-13 12:55   ` " Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  5 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Integrate ipsec SAD support into secgw app:

1. Use SAD library for inbound SA lookup
2. Changes in struct sa_ctx:
  - sa array allocates dynamically depending on number of configured sa
  - All SA's are kept one by one without using SPI2IDX
3. SP's userdata now contain index of SA in sa_ctx instead of SPI
4. Get rid of SPI2IDX macro

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |   3 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 160 +++++++++++++++++--------------------
 examples/ipsec-secgw/sp4.c         |  24 +++---
 examples/ipsec-secgw/sp6.c         |  24 +++---
 7 files changed, 110 insertions(+), 108 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 851123b..8734b15 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -12,6 +12,7 @@ SRCS-y += esp.c
 SRCS-y += sp4.c
 SRCS-y += sp6.c
 SRCS-y += sa.c
+SRCS-y += sad.c
 SRCS-y += rt.c
 SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3b5aaf6..3e5f82e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -601,7 +601,7 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
 			continue;
 		}
 
-		sa_idx = SPI2IDX(res);
+		sa_idx = res - 1;
 		if (!inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
@@ -688,7 +688,7 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
 	j = 0;
 	for (i = 0; i < ip->num; i++) {
 		m = ip->pkts[i];
-		sa_idx = SPI2IDX(ip->res[i]);
+		sa_idx = ip->res[i] - 1;
 		if (ip->res[i] == DISCARD)
 			rte_pktmbuf_free(m);
 		else if (ip->res[i] == BYPASS)
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 132286c..8ca6c2a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -38,7 +38,6 @@
 #define DEFAULT_MAX_CATEGORIES	1
 
 #define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */
-#define SPI2IDX(spi) (spi & (IPSEC_SA_MAX_ENTRIES - 1))
 #define INVALID_SPI (0)
 
 #define DISCARD	INVALID_SPI
@@ -363,7 +362,7 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
  * or -ENOENT otherwise.
  */
 int
-sa_spi_present(uint32_t spi, int inbound);
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound);
 
 void
 sa_init(struct socket_ctx *ctx, int32_t socket_id);
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index 9ece345..6bd5b78 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec']
 allow_experimental_apis = true
 sources = files(
 	'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c'
+	'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
 )
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 7f046e3..8cc7b17 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -24,6 +24,7 @@
 #include "ipsec.h"
 #include "esp.h"
 #include "parser.h"
+#include "sad.h"
 
 #define IPDEFTTL 64
 
@@ -134,9 +135,11 @@ const struct supported_aead_algo aead_algos[] = {
 
 static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_out;
+static struct ipsec_sa_cnt sa_out_cnt;
 
 static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_in;
+static struct ipsec_sa_cnt sa_in_cnt;
 
 static const struct supported_cipher_algo *
 find_match_cipher_algo(const char *cipher_keyword)
@@ -229,6 +232,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
 	uint32_t *ri /*rule index*/;
+	struct ipsec_sa_cnt *sa_cnt;
 	uint32_t cipher_algo_p = 0;
 	uint32_t auth_algo_p = 0;
 	uint32_t aead_algo_p = 0;
@@ -241,6 +245,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
+		sa_cnt = &sa_in_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -251,6 +256,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
+		sa_cnt = &sa_out_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -280,13 +286,16 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
+			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
+				sa_cnt->nb_v4_tun++;
 				rule->flags = IP4_TUNNEL;
-			else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
+			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
+				sa_cnt->nb_v6_tun++;
 				rule->flags = IP6_TUNNEL;
-			else if (strcmp(tokens[ti], "transport") == 0)
+			} else if (strcmp(tokens[ti], "transport") == 0) {
+				sa_cnt->nb_trn++;
 				rule->flags = TRANSPORT;
-			else {
+			} else {
 				APP_CHECK(0, status, "unrecognized "
 					"input \"%s\"", tokens[ti]);
 				return;
@@ -772,19 +781,21 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	printf("\n");
 }
 
+struct ipsec_xf {
+	struct rte_crypto_sym_xform a;
+	struct rte_crypto_sym_xform b;
+};
+
 struct sa_ctx {
 	void *satbl; /* pointer to array of rte_ipsec_sa objects*/
-	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
-	union {
-		struct {
-			struct rte_crypto_sym_xform a;
-			struct rte_crypto_sym_xform b;
-		};
-	} xf[IPSEC_SA_MAX_ENTRIES];
+	struct ipsec_sad sad;
+	struct ipsec_xf *xf;
+	uint32_t nb_sa;
+	struct ipsec_sa sa[];
 };
 
 static struct sa_ctx *
-sa_create(const char *name, int32_t socket_id)
+sa_create(const char *name, int32_t socket_id, uint32_t nb_sa)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
@@ -793,20 +804,31 @@ sa_create(const char *name, int32_t socket_id)
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
 
-	/* Create SA array table */
+	/* Create SA context */
 	printf("Creating SA context with %u maximum entries on socket %d\n",
-			IPSEC_SA_MAX_ENTRIES, socket_id);
+			nb_sa, socket_id);
 
-	mz_size = sizeof(struct sa_ctx);
+	mz_size = sizeof(struct ipsec_xf) * nb_sa;
 	mz = rte_memzone_reserve(s, mz_size, socket_id,
 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
 	if (mz == NULL) {
-		printf("Failed to allocate SA DB memory\n");
+		printf("Failed to allocate SA XFORM memory\n");
 		rte_errno = ENOMEM;
 		return NULL;
 	}
 
-	sa_ctx = (struct sa_ctx *)mz->addr;
+	sa_ctx = rte_malloc(NULL, sizeof(struct sa_ctx) +
+		sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE);
+
+	if (sa_ctx == NULL) {
+		printf("Failed to allocate SA CTX memory\n");
+		rte_errno = ENOMEM;
+		rte_memzone_free(mz);
+		return NULL;
+	}
+
+	sa_ctx->xf = (struct ipsec_xf *)mz->addr;
+	sa_ctx->nb_sa = nb_sa;
 
 	return sa_ctx;
 }
@@ -949,7 +971,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
 	for (i = 0; i < nb_entries; i++) {
-		idx = SPI2IDX(entries[i].spi);
+		idx = i;
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
@@ -957,6 +979,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
+
+		if (inbound) {
+			rc = ipsec_sad_add(&sa_ctx->sad, sa);
+			if (rc != 0)
+				return rc;
+		}
+
 		sa->seq = 0;
 		ips = ipsec_get_primary_session(sa);
 
@@ -1237,8 +1266,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
  * one per session.
  */
 static int
-ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
-	uint32_t nb_ent, int32_t socket)
+ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 {
 	int32_t rc, sz;
 	uint32_t i, idx;
@@ -1248,7 +1276,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	struct rte_ipsec_sa_prm prm;
 
 	/* determine SA size */
-	idx = SPI2IDX(ent[0].spi);
+	idx = 0;
 	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
 	sz = rte_ipsec_sa_size(&prm);
 	if (sz < 0) {
@@ -1271,7 +1299,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	rc = 0;
 	for (i = 0; i != nb_ent && rc == 0; i++) {
 
-		idx = SPI2IDX(ent[i].spi);
+		idx = i;
 
 		sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i);
 		lsa = ctx->sa + idx;
@@ -1286,18 +1314,16 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
  * Walk through all SA rules to find an SA with given SPI
  */
 int
-sa_spi_present(uint32_t spi, int inbound)
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
 	uint32_t i, num;
 	const struct ipsec_sa *sar;
 
-	if (inbound != 0) {
-		sar = sa_in;
+	sar = sa_ctx->sa;
+	if (inbound != 0)
 		num = nb_sa_in;
-	} else {
-		sar = sa_out;
+	else
 		num = nb_sa_out;
-	}
 
 	for (i = 0; i != num; i++) {
 		if (sar[i].spi == spi)
@@ -1326,16 +1352,21 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_in > 0) {
 		name = "sa_in";
-		ctx->sa_in = sa_create(name, socket_id);
+		ctx->sa_in = sa_create(name, socket_id, nb_sa_in);
 		if (ctx->sa_in == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
+		rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id,
+				&sa_in_cnt);
+		if (rc != 0)
+			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
+
 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_in, sa_in, nb_sa_in,
+			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1346,7 +1377,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_out > 0) {
 		name = "sa_out";
-		ctx->sa_out = sa_create(name, socket_id);
+		ctx->sa_out = sa_create(name, socket_id, nb_sa_out);
 		if (ctx->sa_out == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
@@ -1355,7 +1386,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_out, sa_out, nb_sa_out,
+			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1381,28 +1412,13 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return 0;
 }
 
-static inline void
-single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
-		void **sa_ret)
+void
+inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
+		void *sa[], uint16_t nb_pkts)
 {
-	struct rte_esp_hdr *esp;
-	struct ip *ip;
-	uint32_t *src4_addr;
-	uint8_t *src6_addr;
-	struct ipsec_sa *sa;
-	void *result_sa;
+	uint32_t i;
 
-	*sa_ret = NULL;
-
-	ip = rte_pktmbuf_mtod(pkt, struct ip *);
-	esp = rte_pktmbuf_mtod_offset(pkt, struct rte_esp_hdr *, pkt->l3_len);
-
-	if (esp->spi == INVALID_SPI)
-		return;
-
-	result_sa = sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
-	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
-		return;
+	sad_lookup(&sa_ctx->sad, pkts, sa, nb_pkts);
 
 	/*
 	 * Mark need for inline offload fallback on the LSB of SA pointer.
@@ -1413,40 +1429,14 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 	 * pointer to prevent from unintentional use. Use ipsec_mask_saptr
 	 * to get valid struct pointer.
 	 */
-	if (MBUF_NO_SEC_OFFLOAD(pkt) && sa->fallback_sessions > 0) {
-		uintptr_t intsa = (uintptr_t)sa;
-		intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
-		result_sa = (void *)intsa;
+	for (i = 0; i < nb_pkts; i++) {
+		if (MBUF_NO_SEC_OFFLOAD(pkts[i]) && (sa[i] != NULL) &&
+			((struct ipsec_sa *)sa[i])->fallback_sessions > 0) {
+			uintptr_t intsa = (uintptr_t)sa[i];
+			intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
+			sa[i] = (void *)intsa;
+		}
 	}
-
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
-		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
-		if ((ip->ip_v == IPVERSION) &&
-				(sa->src.ip.ip4 == *src4_addr) &&
-				(sa->dst.ip.ip4 == *(src4_addr + 1)))
-			*sa_ret = result_sa;
-		break;
-	case IP6_TUNNEL:
-		src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
-		if ((ip->ip_v == IP6_VERSION) &&
-				!memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
-				!memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
-			*sa_ret = result_sa;
-		break;
-	case TRANSPORT:
-		*sa_ret = result_sa;
-	}
-}
-
-void
-inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
-		void *sa[], uint16_t nb_pkts)
-{
-	uint32_t i;
-
-	for (i = 0; i < nb_pkts; i++)
-		single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
 }
 
 void
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 3871c6c..1dcec52 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -493,10 +493,11 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl4_rules *acr;
+	int32_t spi_idx;
+	struct acl4_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -508,11 +509,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -535,11 +541,11 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index d8be6b1..b489e15 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -625,10 +625,11 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl6_rules *acr;
+	int32_t spi_idx;
+	struct acl6_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -640,11 +641,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -667,11 +673,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
 				"already initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 4/5] examples/ipsec-secgw: get rid of maximum sa limitation
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                     ` (3 preceding siblings ...)
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
@ 2020-01-13 12:55   ` Vladimir Medvedkin
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  5 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Get rid of maximum SA limitation.
Keep parsed SA's into the sorted by SPI value array.
Use binary search in the sorted SA array to find appropriate SA
for a given SPI.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h  |  1 -
 examples/ipsec-secgw/parser.c |  2 ++
 examples/ipsec-secgw/parser.h |  3 ++
 examples/ipsec-secgw/sa.c     | 74 +++++++++++++++++++++++++++++++++----------
 4 files changed, 62 insertions(+), 18 deletions(-)

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 8ca6c2a..0475a54 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */
 #define INVALID_SPI (0)
 
 #define DISCARD	INVALID_SPI
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index fc8c238..67df170 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -642,6 +642,8 @@ parse_cfg_file(const char *cfg_filename)
 	cmdline_stdin_exit(cl);
 	fclose(f);
 
+	sa_sort_arr();
+
 	return 0;
 
 error_exit:
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6b8a100..1f8bd3e 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -75,6 +75,9 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
 void
+sa_sort_arr(void);
+
+void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8cc7b17..7346337 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -133,11 +133,15 @@ const struct supported_aead_algo aead_algos[] = {
 	}
 };
 
-static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
+#define SA_INIT_NB	128
+
+static struct ipsec_sa *sa_out;
+static uint32_t sa_out_sz;
 static uint32_t nb_sa_out;
 static struct ipsec_sa_cnt sa_out_cnt;
 
-static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
+static struct ipsec_sa *sa_in;
+static uint32_t sa_in_sz;
 static uint32_t nb_sa_in;
 static struct ipsec_sa_cnt sa_in_cnt;
 
@@ -224,6 +228,31 @@ parse_key_string(const char *key_str, uint8_t *key)
 	return nb_bytes;
 }
 
+static int
+extend_sa_arr(struct ipsec_sa **sa_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sa_tbl == NULL) {
+		*sa_tbl = calloc(SA_INIT_NB, sizeof(struct ipsec_sa));
+		if (*sa_tbl == NULL)
+			return -1;
+		*cur_sz = SA_INIT_NB;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sa_tbl = realloc(*sa_tbl,
+			*cur_sz * sizeof(struct ipsec_sa) * 2);
+		if (*sa_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sa_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct ipsec_sa));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
+
 void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
@@ -246,23 +275,15 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
 		sa_cnt = &sa_in_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_in, nb_sa_in, &sa_in_sz) < 0)
 			return;
-
 		rule = &sa_in[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
 		sa_cnt = &sa_out_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_out, nb_sa_out, &sa_out_sz) < 0)
 			return;
-
 		rule = &sa_out[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	}
@@ -1310,13 +1331,24 @@ ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 	return rc;
 }
 
+static int
+sa_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct ipsec_sa *)p)->spi;
+	uint32_t spi2 = ((const struct ipsec_sa *)q)->spi;
+
+	return (int)(spi1 - spi2);
+}
+
 /*
  * Walk through all SA rules to find an SA with given SPI
  */
 int
 sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct ipsec_sa *sa;
+	struct ipsec_sa tmpl;
 	const struct ipsec_sa *sar;
 
 	sar = sa_ctx->sa;
@@ -1325,10 +1357,11 @@ sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 	else
 		num = nb_sa_out;
 
-	for (i = 0; i != num; i++) {
-		if (sar[i].spi == spi)
-			return i;
-	}
+	tmpl.spi = spi;
+
+	sa = bsearch(&tmpl, sar, num, sizeof(struct ipsec_sa), sa_cmp);
+	if (sa != NULL)
+		return RTE_PTR_DIFF(sa, sar) / sizeof(struct ipsec_sa);
 
 	return -ENOENT;
 }
@@ -1486,3 +1519,10 @@ sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 	}
 	return 0;
 }
+
+void
+sa_sort_arr(void)
+{
+	qsort(sa_in, nb_sa_in, sizeof(struct ipsec_sa), sa_cmp);
+	qsort(sa_out, nb_sa_out, sizeof(struct ipsec_sa), sa_cmp);
+}
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 5/5] examples/ipsec-secgw: get rid of maximum sp limitation
  2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
                     ` (4 preceding siblings ...)
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
@ 2020-01-13 12:55   ` Vladimir Medvedkin
  5 siblings, 0 replies; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-13 12:55 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Get rid of maximum SP limitation.
Keep parsed SP's into the sorted by SPI value array.
Use binary search in the sorted SP array to find appropriate SP
for a given SPI.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/parser.c |  2 +
 examples/ipsec-secgw/parser.h |  6 +++
 examples/ipsec-secgw/sp4.c    | 90 +++++++++++++++++++++++++++++++++----------
 examples/ipsec-secgw/sp6.c    | 88 ++++++++++++++++++++++++++++++++----------
 4 files changed, 144 insertions(+), 42 deletions(-)

diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index 67df170..65eb7e9 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -643,6 +643,8 @@ parse_cfg_file(const char *cfg_filename)
 	fclose(f);
 
 	sa_sort_arr();
+	sp4_sort_arr();
+	sp6_sort_arr();
 
 	return 0;
 
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 1f8bd3e..6e764fe 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -67,10 +67,16 @@ int
 parse_range(const char *token, uint16_t *low, uint16_t *high);
 
 void
+sp4_sort_arr(void);
+
+void
 parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
 void
+sp6_sort_arr(void);
+
+void
 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 1dcec52..beddd7b 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -15,7 +15,7 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
+#define INIT_ACL_RULE_NUM	128
 
 #define IPV4_DST_FROM_SP(acr) \
 		(rte_cpu_to_be_32((acr).field[DST_FIELD_IPV4].value.u32))
@@ -97,11 +97,39 @@ static struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
 
-static struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM];
+static struct acl4_rules *acl4_rules_out;
 static uint32_t nb_acl4_rules_out;
+static uint32_t sp_out_sz;
 
-static struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM];
+static struct acl4_rules *acl4_rules_in;
 static uint32_t nb_acl4_rules_in;
+static uint32_t sp_in_sz;
+
+static int
+extend_sp_arr(struct acl4_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sp_tbl == NULL) {
+		*sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl4_rules));
+		if (*sp_tbl == NULL)
+			return -1;
+		*cur_sz = INIT_ACL_RULE_NUM;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sp_tbl = realloc(*sp_tbl,
+			*cur_sz * sizeof(struct acl4_rules) * 2);
+		if (*sp_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sp_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct acl4_rules));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
+
 
 void
 parse_sp4_tokens(char **tokens, uint32_t n_tokens,
@@ -127,9 +155,8 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl4_rules_in;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl4_rules_in, nb_acl4_rules_in,
+				&sp_in_sz) < 0)
 			return;
 
 		rule_ipv4 = &acl4_rules_in[*ri];
@@ -137,9 +164,8 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl4_rules_out;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl4_rules_out, nb_acl4_rules_out,
+				&sp_out_sz) < 0)
 			return;
 
 		rule_ipv4 = &acl4_rules_out[*ri];
@@ -451,7 +477,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
@@ -464,7 +490,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -566,6 +592,16 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 			"specified\n");
 }
 
+static int
+sp_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct acl4_rules *)p)->data.userdata;
+	uint32_t spi2 = ((const struct acl4_rules *)q)->data.userdata;
+
+	return (int)(spi1 - spi2);
+}
+
+
 /*
  * Search though SP rules for given SPI.
  */
@@ -573,8 +609,10 @@ int
 sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct acl4_rules *rule;
 	const struct acl4_rules *acr;
+	struct acl4_rules tmpl;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -584,17 +622,27 @@ sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 		num = nb_acl4_rules_out;
 	}
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
-			if (NULL != ip_addr && NULL != mask) {
-				ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(acr[i]);
-				ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(acr[i]);
-				mask[0] = IPV4_SRC_MASK_FROM_SP(acr[i]);
-				mask[1] = IPV4_DST_MASK_FROM_SP(acr[i]);
-			}
-			return i;
+	tmpl.data.userdata = spi;
+
+	rule = bsearch(&tmpl, acr, num, sizeof(struct acl4_rules), sp_cmp);
+	if (rule != NULL) {
+		if (NULL != ip_addr && NULL != mask) {
+			ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(*rule);
+			ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(*rule);
+			mask[0] = IPV4_SRC_MASK_FROM_SP(*rule);
+			mask[1] = IPV4_DST_MASK_FROM_SP(*rule);
 		}
+		return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl4_rules);
 	}
 
 	return -ENOENT;
 }
+
+void
+sp4_sort_arr(void)
+{
+	qsort(acl4_rules_in, nb_acl4_rules_in, sizeof(struct acl4_rules),
+		sp_cmp);
+	qsort(acl4_rules_out, nb_acl4_rules_out, sizeof(struct acl4_rules),
+		sp_cmp);
+}
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index b489e15..328e085 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -15,7 +15,7 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
+#define INIT_ACL_RULE_NUM	128
 
 #define IPV6_FROM_SP(acr, fidx_low, fidx_high) \
 		(((uint64_t)(acr).field[(fidx_high)].value.u32 << 32) | \
@@ -146,11 +146,38 @@ static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
 
 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
 
-static struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
+static struct acl6_rules *acl6_rules_out;
 static uint32_t nb_acl6_rules_out;
+static uint32_t sp_out_sz;
 
-static struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
+static struct acl6_rules *acl6_rules_in;
 static uint32_t nb_acl6_rules_in;
+static uint32_t sp_in_sz;
+
+static int
+extend_sp_arr(struct acl6_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sp_tbl == NULL) {
+		*sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl6_rules));
+		if (*sp_tbl == NULL)
+			return -1;
+		*cur_sz = INIT_ACL_RULE_NUM;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sp_tbl = realloc(*sp_tbl,
+			*cur_sz * sizeof(struct acl6_rules) * 2);
+		if (*sp_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sp_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct acl6_rules));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
 
 void
 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
@@ -176,9 +203,8 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl6_rules_in;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl6_rules_in, nb_acl6_rules_in,
+				&sp_in_sz) < 0)
 			return;
 
 		rule_ipv6 = &acl6_rules_in[*ri];
@@ -186,9 +212,8 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl6_rules_out;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl6_rules_out, nb_acl6_rules_out,
+				&sp_out_sz) < 0)
 			return;
 
 		rule_ipv6 = &acl6_rules_out[*ri];
@@ -583,7 +608,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
@@ -596,7 +621,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -698,6 +723,15 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 			"specified\n");
 }
 
+static int
+sp_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct acl6_rules *)p)->data.userdata;
+	uint32_t spi2 = ((const struct acl6_rules *)q)->data.userdata;
+
+	return (int)(spi1 - spi2);
+}
+
 /*
  * Search though SP rules for given SPI.
  */
@@ -705,8 +739,10 @@ int
 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct acl6_rules *rule;
 	const struct acl6_rules *acr;
+	struct acl6_rules tmpl;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -716,17 +752,27 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 		num = nb_acl6_rules_out;
 	}
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
-			if (NULL != ip_addr && NULL != mask) {
-				IPV6_SRC_FROM_SP(ip_addr[0], acr[i]);
-				IPV6_DST_FROM_SP(ip_addr[1], acr[i]);
-				IPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);
-				IPV6_DST_MASK_FROM_SP(mask[1], acr[i]);
-			}
-			return i;
+	tmpl.data.userdata = spi;
+
+	rule = bsearch(&tmpl, acr, num, sizeof(struct acl6_rules), sp_cmp);
+	if (rule != NULL) {
+		if (NULL != ip_addr && NULL != mask) {
+			IPV6_SRC_FROM_SP(ip_addr[0], *rule);
+			IPV6_DST_FROM_SP(ip_addr[1], *rule);
+			IPV6_SRC_MASK_FROM_SP(mask[0], *rule);
+			IPV6_DST_MASK_FROM_SP(mask[1], *rule);
 		}
+		return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl6_rules);
 	}
 
 	return -ENOENT;
 }
+
+void
+sp6_sort_arr(void)
+{
+	qsort(acl6_rules_in, nb_acl6_rules_in, sizeof(struct acl6_rules),
+		sp_cmp);
+	qsort(acl6_rules_out, nb_acl6_rules_out, sizeof(struct acl6_rules),
+		sp_cmp);
+}
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
@ 2020-01-14 14:27     ` " Vladimir Medvedkin
  2020-01-15 15:45       ` Akhil Goyal
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
                       ` (4 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

This series integrates SA database (SAD) capabilities from ipsec library.
The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
Also patch series removes hardcoded limitation for maximum number of SA's
and SP's.

v4:
 - put tunnel SA's into SAD with SPI_ONLY type for performance reason

v3:
 - parse SA and SP into sorted array instead of linked list

v2:
 - get rid of maximum sp limitation

Vladimir Medvedkin (5):
  ipsec: move ipsec sad name length into .h
  examples/ipsec-secgw: implement inbound SAD
  examples/ipsec-secgw: integrate inbound SAD
  examples/ipsec-secgw: get rid of maximum sa limitation
  examples/ipsec-secgw: get rid of maximum sp limitation

 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |  11 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/parser.c      |   4 +
 examples/ipsec-secgw/parser.h      |   9 ++
 examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------
 examples/ipsec-secgw/sad.c         |  90 +++++++++++++
 examples/ipsec-secgw/sad.h         |  74 +++++++++++
 examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
 examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
 lib/librte_ipsec/ipsec_sad.c       |  20 +--
 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
 13 files changed, 528 insertions(+), 171 deletions(-)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 " Vladimir Medvedkin
@ 2020-01-14 14:27     ` Vladimir Medvedkin
  2020-01-14 15:51       ` Ananyev, Konstantin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Move IPSEC_SAD_NAMESIZE into public header
and rename it to RTE_IPSEC_SAD_NAMESIZE

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 lib/librte_ipsec/ipsec_sad.c     | 20 ++++++++++----------
 lib/librte_ipsec/rte_ipsec_sad.h |  2 ++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lib/librte_ipsec/ipsec_sad.c b/lib/librte_ipsec/ipsec_sad.c
index db2c44c..2c994ed 100644
--- a/lib/librte_ipsec/ipsec_sad.c
+++ b/lib/librte_ipsec/ipsec_sad.c
@@ -20,7 +20,6 @@
  * indicate presence of entries with the same SPI in DIP and DIP+SIP tables.
  */
 
-#define IPSEC_SAD_NAMESIZE	64
 #define SAD_PREFIX		"SAD_"
 /* "SAD_<name>" */
 #define SAD_FORMAT		SAD_PREFIX "%s"
@@ -34,7 +33,7 @@ struct hash_cnt {
 };
 
 struct rte_ipsec_sad {
-	char name[IPSEC_SAD_NAMESIZE];
+	char name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_hash	*hash[RTE_IPSEC_SAD_KEY_TYPE_MASK];
 	/* Array to track number of more specific rules
 	 * (spi_dip or spi_dip_sip). Used only in add/delete
@@ -231,7 +230,7 @@ struct rte_ipsec_sad *
 rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 {
 	char hash_name[RTE_HASH_NAMESIZE];
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	struct rte_ipsec_sad *sad, *tmp_sad = NULL;
@@ -249,8 +248,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 		return NULL;
 	}
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -326,7 +325,8 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 	/* guarantee there's no existing */
 	TAILQ_FOREACH(te, sad_list, next) {
 		tmp_sad = (struct rte_ipsec_sad *)te->data;
-		if (strncmp(sad_name, tmp_sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, tmp_sad->name,
+				RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	if (te != NULL) {
@@ -354,14 +354,14 @@ rte_ipsec_sad_create(const char *name, const struct rte_ipsec_sad_conf *conf)
 struct rte_ipsec_sad *
 rte_ipsec_sad_find_existing(const char *name)
 {
-	char sad_name[IPSEC_SAD_NAMESIZE];
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
 	struct rte_ipsec_sad *sad = NULL;
 	struct rte_tailq_entry *te;
 	struct rte_ipsec_sad_list *sad_list;
 	int ret;
 
-	ret = snprintf(sad_name, IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
-	if (ret < 0 || ret >= IPSEC_SAD_NAMESIZE) {
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, SAD_FORMAT, name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE) {
 		rte_errno = ENAMETOOLONG;
 		return NULL;
 	}
@@ -372,7 +372,7 @@ rte_ipsec_sad_find_existing(const char *name)
 	rte_mcfg_tailq_read_lock();
 	TAILQ_FOREACH(te, sad_list, next) {
 		sad = (struct rte_ipsec_sad *) te->data;
-		if (strncmp(sad_name, sad->name, IPSEC_SAD_NAMESIZE) == 0)
+		if (strncmp(sad_name, sad->name, RTE_IPSEC_SAD_NAMESIZE) == 0)
 			break;
 	}
 	rte_mcfg_tailq_read_unlock();
diff --git a/lib/librte_ipsec/rte_ipsec_sad.h b/lib/librte_ipsec/rte_ipsec_sad.h
index 8386f73..dcc8224 100644
--- a/lib/librte_ipsec/rte_ipsec_sad.h
+++ b/lib/librte_ipsec/rte_ipsec_sad.h
@@ -47,6 +47,8 @@ union rte_ipsec_sad_key {
 	struct rte_ipsec_sadv6_key	v6;
 };
 
+/** Max number of characters in SAD name. */
+#define RTE_IPSEC_SAD_NAMESIZE		64
 /** Flag to create SAD with ipv6 dip and sip addresses */
 #define RTE_IPSEC_SAD_FLAG_IPV6			0x1
 /** Flag to support reader writer concurrency */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 " Vladimir Medvedkin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
@ 2020-01-14 14:27     ` Vladimir Medvedkin
  2020-01-14 15:53       ` Ananyev, Konstantin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
                       ` (2 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Add initial support for librte_ipsec SAD library

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h |  7 ++++
 examples/ipsec-secgw/sad.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sad.h   | 74 ++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 8e07521..9ddb5d9 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -53,6 +53,13 @@ struct ipsec_xform;
 struct rte_mbuf;
 
 struct ipsec_sa;
+/*
+ * Keeps number of configured SA's for each address family:
+ */
+struct ipsec_sa_cnt {
+	uint32_t	nb_v4;
+	uint32_t	nb_v6;
+};
 
 typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
diff --git a/examples/ipsec-secgw/sad.c b/examples/ipsec-secgw/sad.c
new file mode 100644
index 0000000..a193172
--- /dev/null
+++ b/examples/ipsec-secgw/sad.c
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <rte_errno.h>
+
+#include "ipsec.h"
+#include "sad.h"
+
+int
+ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa)
+{
+	int ret;
+	union rte_ipsec_sad_key key = { {0} };
+
+	/* spi field is common for ipv4 and ipv6 key types */
+	key.v4.spi = rte_cpu_to_be_32(sa->spi);
+	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
+	case IP4_TUNNEL:
+		ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+			RTE_IPSEC_SAD_SPI_ONLY, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case IP6_TUNNEL:
+		ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+			RTE_IPSEC_SAD_SPI_ONLY, sa);
+		if (ret != 0)
+			return ret;
+		break;
+	case TRANSPORT:
+		if (sp4_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v4, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+		if (sp6_spi_present(sa->spi, 1, NULL, NULL) >= 0) {
+			ret = rte_ipsec_sad_add(sad->sad_v6, &key,
+				RTE_IPSEC_SAD_SPI_ONLY, sa);
+			if (ret != 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt)
+{
+	int ret;
+	struct rte_ipsec_sad_conf sad_conf;
+	char sad_name[RTE_IPSEC_SAD_NAMESIZE];
+
+	if ((name == NULL) || (sad == NULL) || (sa_cnt == NULL))
+		return -EINVAL;
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v4", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+
+	sad_conf.socket_id = socket_id;
+	sad_conf.flags = 0;
+	/* Make SAD have extra 25% of required number of entries */
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = sa_cnt->nb_v4 * 5 / 4;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP] = 0;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_DIP_SIP] = 0;
+
+	if (sa_cnt->nb_v4 != 0) {
+		sad->sad_v4 = rte_ipsec_sad_create(sad_name, &sad_conf);
+		if (sad->sad_v4 == NULL)
+			return -rte_errno;
+	}
+
+	ret = snprintf(sad_name, RTE_IPSEC_SAD_NAMESIZE, "%s_v6", name);
+	if (ret < 0 || ret >= RTE_IPSEC_SAD_NAMESIZE)
+		return -ENAMETOOLONG;
+	sad_conf.flags = RTE_IPSEC_SAD_FLAG_IPV6;
+	sad_conf.max_sa[RTE_IPSEC_SAD_SPI_ONLY] = sa_cnt->nb_v6 * 5 / 4;
+
+	if (sa_cnt->nb_v6 != 0) {
+		sad->sad_v6 = rte_ipsec_sad_create(name, &sad_conf);
+		if (sad->sad_v6 == NULL)
+			return -rte_errno;
+	}
+
+	return 0;
+}
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
new file mode 100644
index 0000000..e754d57
--- /dev/null
+++ b/examples/ipsec-secgw/sad.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef __SAD_H__
+#define __SAD_H__
+
+#include <rte_ipsec_sad.h>
+
+struct ipsec_sad {
+	struct rte_ipsec_sad *sad_v4;
+	struct rte_ipsec_sad *sad_v6;
+};
+
+int ipsec_sad_create(const char *name, struct ipsec_sad *sad,
+	int socket_id, struct ipsec_sa_cnt *sa_cnt);
+
+int ipsec_sad_add(struct ipsec_sad *sad, struct ipsec_sa *sa);
+
+static inline void
+sad_lookup(const struct ipsec_sad *sad, struct rte_mbuf *pkts[],
+	void *sa[], uint16_t nb_pkts)
+{
+	uint32_t i;
+	uint32_t nb_v4 = 0, nb_v6 = 0;
+	struct rte_esp_hdr *esp;
+	struct rte_ipv4_hdr *ipv4;
+	struct rte_ipv6_hdr *ipv6;
+	struct rte_ipsec_sadv4_key	v4[nb_pkts];
+	struct rte_ipsec_sadv6_key	v6[nb_pkts];
+	int v4_idxes[nb_pkts];
+	int v6_idxes[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v4[nb_pkts];
+	const union rte_ipsec_sad_key	*keys_v6[nb_pkts];
+	void *v4_res[nb_pkts];
+	void *v6_res[nb_pkts];
+
+	for (i = 0; i < nb_pkts; i++) {
+		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
+		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
+				pkts[i]->l3_len);
+		if ((ipv4->version_ihl >> 4) == IPVERSION) {
+			v4[nb_v4].spi = esp->spi;
+			v4[nb_v4].dip = ipv4->dst_addr;
+			v4[nb_v4].sip = ipv4->src_addr;
+			keys_v4[nb_v4] = (const union rte_ipsec_sad_key *)
+						&v4[nb_v4];
+			v4_idxes[nb_v4++] = i;
+		} else {
+			ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
+			v6[nb_v6].spi = esp->spi;
+			memcpy(v6[nb_v6].dip, ipv6->dst_addr,
+					sizeof(ipv6->dst_addr));
+			memcpy(v6[nb_v6].sip, ipv6->src_addr,
+					sizeof(ipv6->src_addr));
+			keys_v6[nb_v6] = (const union rte_ipsec_sad_key *)
+						&v6[nb_v6];
+			v6_idxes[nb_v6++] = i;
+		}
+	}
+
+	if (nb_v4 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v4, keys_v4, v4_res, nb_v4);
+	if (nb_v6 != 0)
+		rte_ipsec_sad_lookup(sad->sad_v6, keys_v6, v6_res, nb_v6);
+
+	for (i = 0; i < nb_v4; i++)
+		sa[v4_idxes[i]] = v4_res[i];
+
+	for (i = 0; i < nb_v6; i++)
+		sa[v6_idxes[i]] = v6_res[i];
+}
+
+#endif /* __SAD_H__ */
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate inbound SAD
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
                       ` (2 preceding siblings ...)
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
@ 2020-01-14 14:27     ` " Vladimir Medvedkin
  2020-01-14 15:54       ` Ananyev, Konstantin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Integrate ipsec SAD support into secgw app:

1. Use SAD library for inbound SA lookup
2. Changes in struct sa_ctx:
  - sa array allocates dynamically depending on number of configured sa
  - All SA's are kept one by one without using SPI2IDX
3. SP's userdata now contain index of SA in sa_ctx instead of SPI
4. Get rid of SPI2IDX macro

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |   3 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/sa.c          | 182 +++++++++++++++++++++----------------
 examples/ipsec-secgw/sp4.c         |  24 +++--
 examples/ipsec-secgw/sp6.c         |  24 +++--
 7 files changed, 139 insertions(+), 101 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 851123b..8734b15 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -12,6 +12,7 @@ SRCS-y += esp.c
 SRCS-y += sp4.c
 SRCS-y += sp6.c
 SRCS-y += sa.c
+SRCS-y += sad.c
 SRCS-y += rt.c
 SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 3b5aaf6..3e5f82e 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -601,7 +601,7 @@ inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
 			continue;
 		}
 
-		sa_idx = SPI2IDX(res);
+		sa_idx = res - 1;
 		if (!inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
@@ -688,7 +688,7 @@ outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
 	j = 0;
 	for (i = 0; i < ip->num; i++) {
 		m = ip->pkts[i];
-		sa_idx = SPI2IDX(ip->res[i]);
+		sa_idx = ip->res[i] - 1;
 		if (ip->res[i] == DISCARD)
 			rte_pktmbuf_free(m);
 		else if (ip->res[i] == BYPASS)
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 9ddb5d9..5988d59 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -38,7 +38,6 @@
 #define DEFAULT_MAX_CATEGORIES	1
 
 #define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */
-#define SPI2IDX(spi) (spi & (IPSEC_SA_MAX_ENTRIES - 1))
 #define INVALID_SPI (0)
 
 #define DISCARD	INVALID_SPI
@@ -359,7 +358,7 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
  * or -ENOENT otherwise.
  */
 int
-sa_spi_present(uint32_t spi, int inbound);
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound);
 
 void
 sa_init(struct socket_ctx *ctx, int32_t socket_id);
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index 9ece345..6bd5b78 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec']
 allow_experimental_apis = true
 sources = files(
 	'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c'
+	'parser.c', 'rt.c', 'sa.c', 'sad.c', 'sp4.c', 'sp6.c'
 )
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 7f046e3..d10a6ec 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -24,6 +24,7 @@
 #include "ipsec.h"
 #include "esp.h"
 #include "parser.h"
+#include "sad.h"
 
 #define IPDEFTTL 64
 
@@ -134,9 +135,11 @@ const struct supported_aead_algo aead_algos[] = {
 
 static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_out;
+static struct ipsec_sa_cnt sa_out_cnt;
 
 static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
 static uint32_t nb_sa_in;
+static struct ipsec_sa_cnt sa_in_cnt;
 
 static const struct supported_cipher_algo *
 find_match_cipher_algo(const char *cipher_keyword)
@@ -229,6 +232,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct rte_ipsec_session *ips;
 	uint32_t ti; /*token index*/
 	uint32_t *ri /*rule index*/;
+	struct ipsec_sa_cnt *sa_cnt;
 	uint32_t cipher_algo_p = 0;
 	uint32_t auth_algo_p = 0;
 	uint32_t aead_algo_p = 0;
@@ -241,6 +245,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
+		sa_cnt = &sa_in_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -251,6 +256,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
+		sa_cnt = &sa_out_cnt;
 
 		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
 			"too many sa rules, abort insertion\n");
@@ -280,13 +286,17 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			if (status->status < 0)
 				return;
 
-			if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
+			if (strcmp(tokens[ti], "ipv4-tunnel") == 0) {
+				sa_cnt->nb_v4++;
 				rule->flags = IP4_TUNNEL;
-			else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
+			} else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) {
+				sa_cnt->nb_v6++;
 				rule->flags = IP6_TUNNEL;
-			else if (strcmp(tokens[ti], "transport") == 0)
+			} else if (strcmp(tokens[ti], "transport") == 0) {
+				sa_cnt->nb_v4++;
+				sa_cnt->nb_v6++;
 				rule->flags = TRANSPORT;
-			else {
+			} else {
 				APP_CHECK(0, status, "unrecognized "
 					"input \"%s\"", tokens[ti]);
 				return;
@@ -772,19 +782,21 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 	printf("\n");
 }
 
+struct ipsec_xf {
+	struct rte_crypto_sym_xform a;
+	struct rte_crypto_sym_xform b;
+};
+
 struct sa_ctx {
 	void *satbl; /* pointer to array of rte_ipsec_sa objects*/
-	struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
-	union {
-		struct {
-			struct rte_crypto_sym_xform a;
-			struct rte_crypto_sym_xform b;
-		};
-	} xf[IPSEC_SA_MAX_ENTRIES];
+	struct ipsec_sad sad;
+	struct ipsec_xf *xf;
+	uint32_t nb_sa;
+	struct ipsec_sa sa[];
 };
 
 static struct sa_ctx *
-sa_create(const char *name, int32_t socket_id)
+sa_create(const char *name, int32_t socket_id, uint32_t nb_sa)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
@@ -793,20 +805,31 @@ sa_create(const char *name, int32_t socket_id)
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
 
-	/* Create SA array table */
+	/* Create SA context */
 	printf("Creating SA context with %u maximum entries on socket %d\n",
-			IPSEC_SA_MAX_ENTRIES, socket_id);
+			nb_sa, socket_id);
 
-	mz_size = sizeof(struct sa_ctx);
+	mz_size = sizeof(struct ipsec_xf) * nb_sa;
 	mz = rte_memzone_reserve(s, mz_size, socket_id,
 			RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
 	if (mz == NULL) {
-		printf("Failed to allocate SA DB memory\n");
+		printf("Failed to allocate SA XFORM memory\n");
 		rte_errno = ENOMEM;
 		return NULL;
 	}
 
-	sa_ctx = (struct sa_ctx *)mz->addr;
+	sa_ctx = rte_malloc(NULL, sizeof(struct sa_ctx) +
+		sizeof(struct ipsec_sa) * nb_sa, RTE_CACHE_LINE_SIZE);
+
+	if (sa_ctx == NULL) {
+		printf("Failed to allocate SA CTX memory\n");
+		rte_errno = ENOMEM;
+		rte_memzone_free(mz);
+		return NULL;
+	}
+
+	sa_ctx->xf = (struct ipsec_xf *)mz->addr;
+	sa_ctx->nb_sa = nb_sa;
 
 	return sa_ctx;
 }
@@ -949,7 +972,7 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 	aad_length = (app_sa_prm.enable_esn != 0) ? sizeof(uint32_t) : 0;
 
 	for (i = 0; i < nb_entries; i++) {
-		idx = SPI2IDX(entries[i].spi);
+		idx = i;
 		sa = &sa_ctx->sa[idx];
 		if (sa->spi != 0) {
 			printf("Index %u already in use by SPI %u\n",
@@ -957,6 +980,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
+
+		if (inbound) {
+			rc = ipsec_sad_add(&sa_ctx->sad, sa);
+			if (rc != 0)
+				return rc;
+		}
+
 		sa->seq = 0;
 		ips = ipsec_get_primary_session(sa);
 
@@ -1237,8 +1267,7 @@ ipsec_sa_init(struct ipsec_sa *lsa, struct rte_ipsec_sa *sa, uint32_t sa_size)
  * one per session.
  */
 static int
-ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
-	uint32_t nb_ent, int32_t socket)
+ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 {
 	int32_t rc, sz;
 	uint32_t i, idx;
@@ -1248,7 +1277,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	struct rte_ipsec_sa_prm prm;
 
 	/* determine SA size */
-	idx = SPI2IDX(ent[0].spi);
+	idx = 0;
 	fill_ipsec_sa_prm(&prm, ctx->sa + idx, NULL, NULL);
 	sz = rte_ipsec_sa_size(&prm);
 	if (sz < 0) {
@@ -1271,7 +1300,7 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
 	rc = 0;
 	for (i = 0; i != nb_ent && rc == 0; i++) {
 
-		idx = SPI2IDX(ent[i].spi);
+		idx = i;
 
 		sa = (struct rte_ipsec_sa *)((uintptr_t)ctx->satbl + sz * i);
 		lsa = ctx->sa + idx;
@@ -1286,18 +1315,16 @@ ipsec_satbl_init(struct sa_ctx *ctx, const struct ipsec_sa *ent,
  * Walk through all SA rules to find an SA with given SPI
  */
 int
-sa_spi_present(uint32_t spi, int inbound)
+sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
 	uint32_t i, num;
 	const struct ipsec_sa *sar;
 
-	if (inbound != 0) {
-		sar = sa_in;
+	sar = sa_ctx->sa;
+	if (inbound != 0)
 		num = nb_sa_in;
-	} else {
-		sar = sa_out;
+	else
 		num = nb_sa_out;
-	}
 
 	for (i = 0; i != num; i++) {
 		if (sar[i].spi == spi)
@@ -1326,16 +1353,21 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_in > 0) {
 		name = "sa_in";
-		ctx->sa_in = sa_create(name, socket_id);
+		ctx->sa_in = sa_create(name, socket_id, nb_sa_in);
 		if (ctx->sa_in == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
 				name, socket_id);
 
+		rc = ipsec_sad_create(name, &ctx->sa_in->sad, socket_id,
+				&sa_in_cnt);
+		if (rc != 0)
+			rte_exit(EXIT_FAILURE, "failed to init SAD\n");
+
 		sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_in, sa_in, nb_sa_in,
+			rc = ipsec_satbl_init(ctx->sa_in, nb_sa_in,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1346,7 +1378,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 
 	if (nb_sa_out > 0) {
 		name = "sa_out";
-		ctx->sa_out = sa_create(name, socket_id);
+		ctx->sa_out = sa_create(name, socket_id, nb_sa_out);
 		if (ctx->sa_out == NULL)
 			rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
 				"context %s in socket %d\n", rte_errno,
@@ -1355,7 +1387,7 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id)
 		sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out, ctx);
 
 		if (app_sa_prm.enable != 0) {
-			rc = ipsec_satbl_init(ctx->sa_out, sa_out, nb_sa_out,
+			rc = ipsec_satbl_init(ctx->sa_out, nb_sa_out,
 				socket_id);
 			if (rc != 0)
 				rte_exit(EXIT_FAILURE,
@@ -1381,28 +1413,18 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return 0;
 }
 
-static inline void
-single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
-		void **sa_ret)
+void
+inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
+		void *sa_arr[], uint16_t nb_pkts)
 {
-	struct rte_esp_hdr *esp;
+	uint32_t i;
 	struct ip *ip;
 	uint32_t *src4_addr;
 	uint8_t *src6_addr;
-	struct ipsec_sa *sa;
 	void *result_sa;
+	struct ipsec_sa *sa;
 
-	*sa_ret = NULL;
-
-	ip = rte_pktmbuf_mtod(pkt, struct ip *);
-	esp = rte_pktmbuf_mtod_offset(pkt, struct rte_esp_hdr *, pkt->l3_len);
-
-	if (esp->spi == INVALID_SPI)
-		return;
-
-	result_sa = sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
-	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
-		return;
+	sad_lookup(&sa_ctx->sad, pkts, sa_arr, nb_pkts);
 
 	/*
 	 * Mark need for inline offload fallback on the LSB of SA pointer.
@@ -1413,43 +1435,47 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 	 * pointer to prevent from unintentional use. Use ipsec_mask_saptr
 	 * to get valid struct pointer.
 	 */
-	if (MBUF_NO_SEC_OFFLOAD(pkt) && sa->fallback_sessions > 0) {
-		uintptr_t intsa = (uintptr_t)sa;
-		intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
-		result_sa = (void *)intsa;
-	}
+	for (i = 0; i < nb_pkts; i++) {
+		if (sa_arr[i] == NULL)
+			continue;
 
-	switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
-	case IP4_TUNNEL:
-		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
-		if ((ip->ip_v == IPVERSION) &&
-				(sa->src.ip.ip4 == *src4_addr) &&
-				(sa->dst.ip.ip4 == *(src4_addr + 1)))
-			*sa_ret = result_sa;
-		break;
-	case IP6_TUNNEL:
-		src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
-		if ((ip->ip_v == IP6_VERSION) &&
+		result_sa = sa = sa_arr[i];
+		if (MBUF_NO_SEC_OFFLOAD(pkts[i]) &&
+			sa->fallback_sessions > 0) {
+			uintptr_t intsa = (uintptr_t)sa;
+			intsa |= IPSEC_SA_OFFLOAD_FALLBACK_FLAG;
+			result_sa = (void *)intsa;
+		}
+
+		ip = rte_pktmbuf_mtod(pkts[i], struct ip *);
+		switch (WITHOUT_TRANSPORT_VERSION(sa->flags)) {
+		case IP4_TUNNEL:
+			src4_addr = RTE_PTR_ADD(ip,
+				offsetof(struct ip, ip_src));
+			if ((ip->ip_v == IPVERSION) &&
+					(sa->src.ip.ip4 == *src4_addr) &&
+					(sa->dst.ip.ip4 == *(src4_addr + 1)))
+				sa_arr[i] = result_sa;
+			else
+				sa_arr[i] = NULL;
+			break;
+		case IP6_TUNNEL:
+			src6_addr = RTE_PTR_ADD(ip,
+				offsetof(struct ip6_hdr, ip6_src));
+			if ((ip->ip_v == IP6_VERSION) &&
 				!memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) &&
 				!memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16))
-			*sa_ret = result_sa;
-		break;
-	case TRANSPORT:
-		*sa_ret = result_sa;
+				sa_arr[i] = result_sa;
+			else
+				sa_arr[i] = NULL;
+			break;
+		case TRANSPORT:
+			sa_arr[i] = result_sa;
+		}
 	}
 }
 
 void
-inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
-		void *sa[], uint16_t nb_pkts)
-{
-	uint32_t i;
-
-	for (i = 0; i < nb_pkts; i++)
-		single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
-}
-
-void
 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 		void *sa[], uint16_t nb_pkts)
 {
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 3871c6c..1dcec52 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -493,10 +493,11 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl4_rules *acr;
+	int32_t spi_idx;
+	struct acl4_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -508,11 +509,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -535,11 +541,11 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv4 SP DB has unmatched in SAD SPIs\n");
 
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index d8be6b1..b489e15 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -625,10 +625,11 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
  * check that for each rule it's SPI has a correspondent entry in SAD
  */
 static int
-check_spi_value(int inbound)
+check_spi_value(struct sa_ctx *sa_ctx, int inbound)
 {
 	uint32_t i, num, spi;
-	const struct acl6_rules *acr;
+	int32_t spi_idx;
+	struct acl6_rules *acr;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -640,11 +641,16 @@ check_spi_value(int inbound)
 
 	for (i = 0; i != num; i++) {
 		spi = acr[i].data.userdata;
-		if (spi != DISCARD && spi != BYPASS &&
-				sa_spi_present(spi, inbound) < 0) {
-			RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
-				spi);
-			return -ENOENT;
+		if (spi != DISCARD && spi != BYPASS) {
+			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
+			if (spi_idx < 0) {
+				RTE_LOG(ERR, IPSEC,
+					"SPI %u is not present in SAD\n",
+					spi);
+				return -ENOENT;
+			}
+			/* Update userdata with spi index */
+			acr[i].data.userdata = spi_idx + 1;
 		}
 	}
 
@@ -667,11 +673,11 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
 				"already initialized\n", socket_id);
 
-	if (check_spi_value(1) < 0)
+	if (check_spi_value(ctx->sa_in, 1) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-	if (check_spi_value(0) < 0)
+	if (check_spi_value(ctx->sa_out, 0) < 0)
 		rte_exit(EXIT_FAILURE,
 			"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
                       ` (3 preceding siblings ...)
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
@ 2020-01-14 14:27     ` Vladimir Medvedkin
  2020-01-14 15:56       ` Ananyev, Konstantin
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Get rid of maximum SA limitation.
Keep parsed SA's into the sorted by SPI value array.
Use binary search in the sorted SA array to find appropriate SA
for a given SPI.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/ipsec.h  |  1 -
 examples/ipsec-secgw/parser.c |  2 ++
 examples/ipsec-secgw/parser.h |  3 ++
 examples/ipsec-secgw/sa.c     | 74 +++++++++++++++++++++++++++++++++----------
 4 files changed, 62 insertions(+), 18 deletions(-)

diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 5988d59..3c77232 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (128) /* must be power of 2, max 2 power 30 */
 #define INVALID_SPI (0)
 
 #define DISCARD	INVALID_SPI
diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index fc8c238..67df170 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -642,6 +642,8 @@ parse_cfg_file(const char *cfg_filename)
 	cmdline_stdin_exit(cl);
 	fclose(f);
 
+	sa_sort_arr();
+
 	return 0;
 
 error_exit:
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 6b8a100..1f8bd3e 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -75,6 +75,9 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
 void
+sa_sort_arr(void);
+
+void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index d10a6ec..b3b83e3 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -133,11 +133,15 @@ const struct supported_aead_algo aead_algos[] = {
 	}
 };
 
-static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
+#define SA_INIT_NB	128
+
+static struct ipsec_sa *sa_out;
+static uint32_t sa_out_sz;
 static uint32_t nb_sa_out;
 static struct ipsec_sa_cnt sa_out_cnt;
 
-static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
+static struct ipsec_sa *sa_in;
+static uint32_t sa_in_sz;
 static uint32_t nb_sa_in;
 static struct ipsec_sa_cnt sa_in_cnt;
 
@@ -224,6 +228,31 @@ parse_key_string(const char *key_str, uint8_t *key)
 	return nb_bytes;
 }
 
+static int
+extend_sa_arr(struct ipsec_sa **sa_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sa_tbl == NULL) {
+		*sa_tbl = calloc(SA_INIT_NB, sizeof(struct ipsec_sa));
+		if (*sa_tbl == NULL)
+			return -1;
+		*cur_sz = SA_INIT_NB;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sa_tbl = realloc(*sa_tbl,
+			*cur_sz * sizeof(struct ipsec_sa) * 2);
+		if (*sa_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sa_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct ipsec_sa));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
+
 void
 parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status)
@@ -246,23 +275,15 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
 		sa_cnt = &sa_in_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_in, nb_sa_in, &sa_in_sz) < 0)
 			return;
-
 		rule = &sa_in[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
 	} else {
 		ri = &nb_sa_out;
 		sa_cnt = &sa_out_cnt;
-
-		APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
-			"too many sa rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sa_arr(&sa_out, nb_sa_out, &sa_out_sz) < 0)
 			return;
-
 		rule = &sa_out[*ri];
 		rule->direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
 	}
@@ -1311,13 +1332,24 @@ ipsec_satbl_init(struct sa_ctx *ctx, uint32_t nb_ent, int32_t socket)
 	return rc;
 }
 
+static int
+sa_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct ipsec_sa *)p)->spi;
+	uint32_t spi2 = ((const struct ipsec_sa *)q)->spi;
+
+	return (int)(spi1 - spi2);
+}
+
 /*
  * Walk through all SA rules to find an SA with given SPI
  */
 int
 sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct ipsec_sa *sa;
+	struct ipsec_sa tmpl;
 	const struct ipsec_sa *sar;
 
 	sar = sa_ctx->sa;
@@ -1326,10 +1358,11 @@ sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound)
 	else
 		num = nb_sa_out;
 
-	for (i = 0; i != num; i++) {
-		if (sar[i].spi == spi)
-			return i;
-	}
+	tmpl.spi = spi;
+
+	sa = bsearch(&tmpl, sar, num, sizeof(struct ipsec_sa), sa_cmp);
+	if (sa != NULL)
+		return RTE_PTR_DIFF(sa, sar) / sizeof(struct ipsec_sa);
 
 	return -ENOENT;
 }
@@ -1522,3 +1555,10 @@ sa_check_offloads(uint16_t port_id, uint64_t *rx_offloads,
 	}
 	return 0;
 }
+
+void
+sa_sort_arr(void)
+{
+	qsort(sa_in, nb_sa_in, sizeof(struct ipsec_sa), sa_cmp);
+	qsort(sa_out, nb_sa_out, sizeof(struct ipsec_sa), sa_cmp);
+}
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation
  2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
                       ` (4 preceding siblings ...)
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
@ 2020-01-14 14:27     ` Vladimir Medvedkin
  2020-01-14 15:57       ` Ananyev, Konstantin
  5 siblings, 1 reply; 35+ messages in thread
From: Vladimir Medvedkin @ 2020-01-14 14:27 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, akhil.goyal

Get rid of maximum SP limitation.
Keep parsed SP's into the sorted by SPI value array.
Use binary search in the sorted SP array to find appropriate SP
for a given SPI.

Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
---
 examples/ipsec-secgw/parser.c |  2 +
 examples/ipsec-secgw/parser.h |  6 +++
 examples/ipsec-secgw/sp4.c    | 90 +++++++++++++++++++++++++++++++++----------
 examples/ipsec-secgw/sp6.c    | 88 ++++++++++++++++++++++++++++++++----------
 4 files changed, 144 insertions(+), 42 deletions(-)

diff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c
index 67df170..65eb7e9 100644
--- a/examples/ipsec-secgw/parser.c
+++ b/examples/ipsec-secgw/parser.c
@@ -643,6 +643,8 @@ parse_cfg_file(const char *cfg_filename)
 	fclose(f);
 
 	sa_sort_arr();
+	sp4_sort_arr();
+	sp6_sort_arr();
 
 	return 0;
 
diff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h
index 1f8bd3e..6e764fe 100644
--- a/examples/ipsec-secgw/parser.h
+++ b/examples/ipsec-secgw/parser.h
@@ -67,10 +67,16 @@ int
 parse_range(const char *token, uint16_t *low, uint16_t *high);
 
 void
+sp4_sort_arr(void);
+
+void
 parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
 void
+sp6_sort_arr(void);
+
+void
 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	struct parse_status *status);
 
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 1dcec52..beddd7b 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -15,7 +15,7 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
+#define INIT_ACL_RULE_NUM	128
 
 #define IPV4_DST_FROM_SP(acr) \
 		(rte_cpu_to_be_32((acr).field[DST_FIELD_IPV4].value.u32))
@@ -97,11 +97,39 @@ static struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
 
-static struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM];
+static struct acl4_rules *acl4_rules_out;
 static uint32_t nb_acl4_rules_out;
+static uint32_t sp_out_sz;
 
-static struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM];
+static struct acl4_rules *acl4_rules_in;
 static uint32_t nb_acl4_rules_in;
+static uint32_t sp_in_sz;
+
+static int
+extend_sp_arr(struct acl4_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sp_tbl == NULL) {
+		*sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl4_rules));
+		if (*sp_tbl == NULL)
+			return -1;
+		*cur_sz = INIT_ACL_RULE_NUM;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sp_tbl = realloc(*sp_tbl,
+			*cur_sz * sizeof(struct acl4_rules) * 2);
+		if (*sp_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sp_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct acl4_rules));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
+
 
 void
 parse_sp4_tokens(char **tokens, uint32_t n_tokens,
@@ -127,9 +155,8 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl4_rules_in;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl4_rules_in, nb_acl4_rules_in,
+				&sp_in_sz) < 0)
 			return;
 
 		rule_ipv4 = &acl4_rules_in[*ri];
@@ -137,9 +164,8 @@ parse_sp4_tokens(char **tokens, uint32_t n_tokens,
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl4_rules_out;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
-			"too many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl4_rules_out, nb_acl4_rules_out,
+				&sp_out_sz) < 0)
 			return;
 
 		rule_ipv4 = &acl4_rules_out[*ri];
@@ -451,7 +477,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
@@ -464,7 +490,7 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -566,6 +592,16 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id)
 			"specified\n");
 }
 
+static int
+sp_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct acl4_rules *)p)->data.userdata;
+	uint32_t spi2 = ((const struct acl4_rules *)q)->data.userdata;
+
+	return (int)(spi1 - spi2);
+}
+
+
 /*
  * Search though SP rules for given SPI.
  */
@@ -573,8 +609,10 @@ int
 sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct acl4_rules *rule;
 	const struct acl4_rules *acr;
+	struct acl4_rules tmpl;
 
 	if (inbound != 0) {
 		acr = acl4_rules_in;
@@ -584,17 +622,27 @@ sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 		num = nb_acl4_rules_out;
 	}
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
-			if (NULL != ip_addr && NULL != mask) {
-				ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(acr[i]);
-				ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(acr[i]);
-				mask[0] = IPV4_SRC_MASK_FROM_SP(acr[i]);
-				mask[1] = IPV4_DST_MASK_FROM_SP(acr[i]);
-			}
-			return i;
+	tmpl.data.userdata = spi;
+
+	rule = bsearch(&tmpl, acr, num, sizeof(struct acl4_rules), sp_cmp);
+	if (rule != NULL) {
+		if (NULL != ip_addr && NULL != mask) {
+			ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(*rule);
+			ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(*rule);
+			mask[0] = IPV4_SRC_MASK_FROM_SP(*rule);
+			mask[1] = IPV4_DST_MASK_FROM_SP(*rule);
 		}
+		return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl4_rules);
 	}
 
 	return -ENOENT;
 }
+
+void
+sp4_sort_arr(void)
+{
+	qsort(acl4_rules_in, nb_acl4_rules_in, sizeof(struct acl4_rules),
+		sp_cmp);
+	qsort(acl4_rules_out, nb_acl4_rules_out, sizeof(struct acl4_rules),
+		sp_cmp);
+}
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index b489e15..328e085 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -15,7 +15,7 @@
 #include "ipsec.h"
 #include "parser.h"
 
-#define MAX_ACL_RULE_NUM	1024
+#define INIT_ACL_RULE_NUM	128
 
 #define IPV6_FROM_SP(acr, fidx_low, fidx_high) \
 		(((uint64_t)(acr).field[(fidx_high)].value.u32 << 32) | \
@@ -146,11 +146,38 @@ static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
 
 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
 
-static struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
+static struct acl6_rules *acl6_rules_out;
 static uint32_t nb_acl6_rules_out;
+static uint32_t sp_out_sz;
 
-static struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
+static struct acl6_rules *acl6_rules_in;
 static uint32_t nb_acl6_rules_in;
+static uint32_t sp_in_sz;
+
+static int
+extend_sp_arr(struct acl6_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
+{
+	if (*sp_tbl == NULL) {
+		*sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl6_rules));
+		if (*sp_tbl == NULL)
+			return -1;
+		*cur_sz = INIT_ACL_RULE_NUM;
+		return 0;
+	}
+
+	if (cur_cnt >= *cur_sz) {
+		*sp_tbl = realloc(*sp_tbl,
+			*cur_sz * sizeof(struct acl6_rules) * 2);
+		if (*sp_tbl == NULL)
+			return -1;
+		/* clean reallocated extra space */
+		memset(&(*sp_tbl)[*cur_sz], 0,
+			*cur_sz * sizeof(struct acl6_rules));
+		*cur_sz *= 2;
+	}
+
+	return 0;
+}
 
 void
 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
@@ -176,9 +203,8 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	if (strcmp(tokens[1], "in") == 0) {
 		ri = &nb_acl6_rules_in;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl6_rules_in, nb_acl6_rules_in,
+				&sp_in_sz) < 0)
 			return;
 
 		rule_ipv6 = &acl6_rules_in[*ri];
@@ -186,9 +212,8 @@ parse_sp6_tokens(char **tokens, uint32_t n_tokens,
 	} else if (strcmp(tokens[1], "out") == 0) {
 		ri = &nb_acl6_rules_out;
 
-		APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
-			"many sp rules, abort insertion\n");
-		if (status->status < 0)
+		if (extend_sp_arr(&acl6_rules_out, nb_acl6_rules_out,
+				&sp_out_sz) < 0)
 			return;
 
 		rule_ipv6 = &acl6_rules_out[*ri];
@@ -583,7 +608,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 	struct rte_acl_config acl_build_param;
 	struct rte_acl_ctx *ctx;
 
-	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+	printf("Creating SP context with %u rules\n", rules_nb);
 
 	memset(&acl_param, 0, sizeof(acl_param));
 
@@ -596,7 +621,7 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
 	acl_param.name = s;
 	acl_param.socket_id = socketid;
 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
+	acl_param.max_rule_num = rules_nb;
 
 	ctx = rte_acl_create(&acl_param);
 	if (ctx == NULL)
@@ -698,6 +723,15 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id)
 			"specified\n");
 }
 
+static int
+sp_cmp(const void *p, const void *q)
+{
+	uint32_t spi1 = ((const struct acl6_rules *)p)->data.userdata;
+	uint32_t spi2 = ((const struct acl6_rules *)q)->data.userdata;
+
+	return (int)(spi1 - spi2);
+}
+
 /*
  * Search though SP rules for given SPI.
  */
@@ -705,8 +739,10 @@ int
 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 			uint32_t mask[2])
 {
-	uint32_t i, num;
+	uint32_t num;
+	struct acl6_rules *rule;
 	const struct acl6_rules *acr;
+	struct acl6_rules tmpl;
 
 	if (inbound != 0) {
 		acr = acl6_rules_in;
@@ -716,17 +752,27 @@ sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
 		num = nb_acl6_rules_out;
 	}
 
-	for (i = 0; i != num; i++) {
-		if (acr[i].data.userdata == spi) {
-			if (NULL != ip_addr && NULL != mask) {
-				IPV6_SRC_FROM_SP(ip_addr[0], acr[i]);
-				IPV6_DST_FROM_SP(ip_addr[1], acr[i]);
-				IPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);
-				IPV6_DST_MASK_FROM_SP(mask[1], acr[i]);
-			}
-			return i;
+	tmpl.data.userdata = spi;
+
+	rule = bsearch(&tmpl, acr, num, sizeof(struct acl6_rules), sp_cmp);
+	if (rule != NULL) {
+		if (NULL != ip_addr && NULL != mask) {
+			IPV6_SRC_FROM_SP(ip_addr[0], *rule);
+			IPV6_DST_FROM_SP(ip_addr[1], *rule);
+			IPV6_SRC_MASK_FROM_SP(mask[0], *rule);
+			IPV6_DST_MASK_FROM_SP(mask[1], *rule);
 		}
+		return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl6_rules);
 	}
 
 	return -ENOENT;
 }
+
+void
+sp6_sort_arr(void)
+{
+	qsort(acl6_rules_in, nb_acl6_rules_in, sizeof(struct acl6_rules),
+		sp_cmp);
+	qsort(acl6_rules_out, nb_acl6_rules_out, sizeof(struct acl6_rules),
+		sp_cmp);
+}
-- 
2.7.4


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

* Re: [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
@ 2020-01-14 15:51       ` Ananyev, Konstantin
  0 siblings, 0 replies; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-14 15:51 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev; +Cc: akhil.goyal



> -----Original Message-----
> From: Medvedkin, Vladimir <vladimir.medvedkin@intel.com>
> Sent: Tuesday, January 14, 2020 2:27 PM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; akhil.goyal@nxp.com
> Subject: [PATCH v4 1/5] ipsec: move ipsec sad name length into .h
> 
> Move IPSEC_SAD_NAMESIZE into public header
> and rename it to RTE_IPSEC_SAD_NAMESIZE
> 
> Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> ---

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

> --
> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
@ 2020-01-14 15:53       ` Ananyev, Konstantin
  0 siblings, 0 replies; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-14 15:53 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev; +Cc: akhil.goyal



> 
> Add initial support for librte_ipsec SAD library
> 
> Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> ---

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate inbound SAD
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
@ 2020-01-14 15:54       ` Ananyev, Konstantin
  0 siblings, 0 replies; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-14 15:54 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev; +Cc: akhil.goyal



> -----Original Message-----
> From: Medvedkin, Vladimir <vladimir.medvedkin@intel.com>
> Sent: Tuesday, January 14, 2020 2:27 PM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; akhil.goyal@nxp.com
> Subject: [PATCH v4 3/5] examples/ipsec-secgw: integrate inbound SAD
> 
> Integrate ipsec SAD support into secgw app:
> 
> 1. Use SAD library for inbound SA lookup
> 2. Changes in struct sa_ctx:
>   - sa array allocates dynamically depending on number of configured sa
>   - All SA's are kept one by one without using SPI2IDX
> 3. SP's userdata now contain index of SA in sa_ctx instead of SPI
> 4. Get rid of SPI2IDX macro
> 
> Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> ---
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
@ 2020-01-14 15:56       ` Ananyev, Konstantin
  0 siblings, 0 replies; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-14 15:56 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev; +Cc: akhil.goyal



> -----Original Message-----
> From: Medvedkin, Vladimir <vladimir.medvedkin@intel.com>
> Sent: Tuesday, January 14, 2020 2:27 PM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; akhil.goyal@nxp.com
> Subject: [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation
> 
> Get rid of maximum SA limitation.
> Keep parsed SA's into the sorted by SPI value array.
> Use binary search in the sorted SA array to find appropriate SA
> for a given SPI.
> 
> Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> ---

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
@ 2020-01-14 15:57       ` Ananyev, Konstantin
  0 siblings, 0 replies; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-14 15:57 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev; +Cc: akhil.goyal


> Get rid of maximum SP limitation.
> Keep parsed SP's into the sorted by SPI value array.
> Use binary search in the sorted SP array to find appropriate SP
> for a given SPI.
> 
> Signed-off-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> ---

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 " Vladimir Medvedkin
@ 2020-01-15 15:45       ` Akhil Goyal
  2020-01-17 12:26         ` Akhil Goyal
  2020-01-17 17:05         ` Medvedkin, Vladimir
  0 siblings, 2 replies; 35+ messages in thread
From: Akhil Goyal @ 2020-01-15 15:45 UTC (permalink / raw)
  To: Vladimir Medvedkin, dev; +Cc: konstantin.ananyev

Hi Vladimir,

There is more than 10% drop with this patchset on NXP hardware with both legacy mode and the ipsec lib mode. This would need some debugging.
Didn't you see any drop on intel?

Regards,
Akhil

> -----Original Message-----
> From: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
> Sent: Tuesday, January 14, 2020 7:57 PM
> To: dev@dpdk.org
> Cc: konstantin.ananyev@intel.com; Akhil Goyal <akhil.goyal@nxp.com>
> Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
> 
> This series integrates SA database (SAD) capabilities from ipsec library.
> The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
> Also patch series removes hardcoded limitation for maximum number of SA's
> and SP's.
> 
> v4:
>  - put tunnel SA's into SAD with SPI_ONLY type for performance reason
> 
> v3:
>  - parse SA and SP into sorted array instead of linked list
> 
> v2:
>  - get rid of maximum sp limitation
> 
> Vladimir Medvedkin (5):
>   ipsec: move ipsec sad name length into .h
>   examples/ipsec-secgw: implement inbound SAD
>   examples/ipsec-secgw: integrate inbound SAD
>   examples/ipsec-secgw: get rid of maximum sa limitation
>   examples/ipsec-secgw: get rid of maximum sp limitation
> 
>  examples/ipsec-secgw/Makefile      |   1 +
>  examples/ipsec-secgw/ipsec-secgw.c |   4 +-
>  examples/ipsec-secgw/ipsec.h       |  11 +-
>  examples/ipsec-secgw/meson.build   |   2 +-
>  examples/ipsec-secgw/parser.c      |   4 +
>  examples/ipsec-secgw/parser.h      |   9 ++
>  examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------
>  examples/ipsec-secgw/sad.c         |  90 +++++++++++++
>  examples/ipsec-secgw/sad.h         |  74 +++++++++++
>  examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
>  examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
>  lib/librte_ipsec/ipsec_sad.c       |  20 +--
>  lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
>  13 files changed, 528 insertions(+), 171 deletions(-)
>  create mode 100644 examples/ipsec-secgw/sad.c
>  create mode 100644 examples/ipsec-secgw/sad.h
> 
> --
> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-15 15:45       ` Akhil Goyal
@ 2020-01-17 12:26         ` Akhil Goyal
  2020-01-17 17:05         ` Medvedkin, Vladimir
  1 sibling, 0 replies; 35+ messages in thread
From: Akhil Goyal @ 2020-01-17 12:26 UTC (permalink / raw)
  To: Vladimir Medvedkin, dev; +Cc: konstantin.ananyev

Hi Vladimir,

The lookup logic for SAD has been brought more closer to real use case, but it looks very high on CPU and should be optimized. We cannot have 10-15% drop because of this change in SA lookup for small packet(82B) sizes where CPU is bottleneck. For large packet sizes it will not impact.

> 
> Hi Vladimir,
> 
> There is more than 10% drop with this patchset on NXP hardware with both
> legacy mode and the ipsec lib mode. This would need some debugging.
> Didn't you see any drop on intel?
> 
> Regards,
> Akhil
> 
> >
> > This series integrates SA database (SAD) capabilities from ipsec library.
> > The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
> > Also patch series removes hardcoded limitation for maximum number of SA's
> > and SP's.
> >
> > v4:
> >  - put tunnel SA's into SAD with SPI_ONLY type for performance reason
> >
> > v3:
> >  - parse SA and SP into sorted array instead of linked list
> >
> > v2:
> >  - get rid of maximum sp limitation
> >
> > Vladimir Medvedkin (5):
> >   ipsec: move ipsec sad name length into .h
> >   examples/ipsec-secgw: implement inbound SAD
> >   examples/ipsec-secgw: integrate inbound SAD
> >   examples/ipsec-secgw: get rid of maximum sa limitation
> >   examples/ipsec-secgw: get rid of maximum sp limitation
> >
> >  examples/ipsec-secgw/Makefile      |   1 +
> >  examples/ipsec-secgw/ipsec-secgw.c |   4 +-
> >  examples/ipsec-secgw/ipsec.h       |  11 +-
> >  examples/ipsec-secgw/meson.build   |   2 +-
> >  examples/ipsec-secgw/parser.c      |   4 +
> >  examples/ipsec-secgw/parser.h      |   9 ++
> >  examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++-------------
> -
> >  examples/ipsec-secgw/sad.c         |  90 +++++++++++++
> >  examples/ipsec-secgw/sad.h         |  74 +++++++++++
> >  examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
> >  examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
> >  lib/librte_ipsec/ipsec_sad.c       |  20 +--
> >  lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
> >  13 files changed, 528 insertions(+), 171 deletions(-)
> >  create mode 100644 examples/ipsec-secgw/sad.c
> >  create mode 100644 examples/ipsec-secgw/sad.h
> >
> > --
> > 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-15 15:45       ` Akhil Goyal
  2020-01-17 12:26         ` Akhil Goyal
@ 2020-01-17 17:05         ` Medvedkin, Vladimir
  2020-01-20  6:44           ` Akhil Goyal
  1 sibling, 1 reply; 35+ messages in thread
From: Medvedkin, Vladimir @ 2020-01-17 17:05 UTC (permalink / raw)
  To: Akhil Goyal, dev; +Cc: konstantin.ananyev

Hi Akhil,

Indeed with our tests we also seeing ~15% perf drop for small packets 
(~90B) and ~3-4% drop for 1KB packets. While I am looking on a ways to 
minimize the drop, I think it would be hard, if possible at all to 
eliminate it completely.
Reason for that: current SAD implementation is completely synthetic 
(using plain array structure indexed by SPI value). That provides a very 
low overhead, but doesn't provide expected functionality and can't be 
used in proper implementation.
To measure plain IPsec performance without SAD user can still use 
'--signle-sa' option.

On 15/01/2020 15:45, Akhil Goyal wrote:
> Hi Vladimir,
>
> There is more than 10% drop with this patchset on NXP hardware with both legacy mode and the ipsec lib mode. This would need some debugging.
> Didn't you see any drop on intel?
>
> Regards,
> Akhil
>
>> -----Original Message-----
>> From: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
>> Sent: Tuesday, January 14, 2020 7:57 PM
>> To: dev@dpdk.org
>> Cc: konstantin.ananyev@intel.com; Akhil Goyal <akhil.goyal@nxp.com>
>> Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
>>
>> This series integrates SA database (SAD) capabilities from ipsec library.
>> The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
>> Also patch series removes hardcoded limitation for maximum number of SA's
>> and SP's.
>>
>> v4:
>>   - put tunnel SA's into SAD with SPI_ONLY type for performance reason
>>
>> v3:
>>   - parse SA and SP into sorted array instead of linked list
>>
>> v2:
>>   - get rid of maximum sp limitation
>>
>> Vladimir Medvedkin (5):
>>    ipsec: move ipsec sad name length into .h
>>    examples/ipsec-secgw: implement inbound SAD
>>    examples/ipsec-secgw: integrate inbound SAD
>>    examples/ipsec-secgw: get rid of maximum sa limitation
>>    examples/ipsec-secgw: get rid of maximum sp limitation
>>
>>   examples/ipsec-secgw/Makefile      |   1 +
>>   examples/ipsec-secgw/ipsec-secgw.c |   4 +-
>>   examples/ipsec-secgw/ipsec.h       |  11 +-
>>   examples/ipsec-secgw/meson.build   |   2 +-
>>   examples/ipsec-secgw/parser.c      |   4 +
>>   examples/ipsec-secgw/parser.h      |   9 ++
>>   examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------
>>   examples/ipsec-secgw/sad.c         |  90 +++++++++++++
>>   examples/ipsec-secgw/sad.h         |  74 +++++++++++
>>   examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
>>   examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
>>   lib/librte_ipsec/ipsec_sad.c       |  20 +--
>>   lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
>>   13 files changed, 528 insertions(+), 171 deletions(-)
>>   create mode 100644 examples/ipsec-secgw/sad.c
>>   create mode 100644 examples/ipsec-secgw/sad.h
>>
>> --
>> 2.7.4

-- 
Regards,
Vladimir


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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-17 17:05         ` Medvedkin, Vladimir
@ 2020-01-20  6:44           ` Akhil Goyal
  2020-01-20 12:44             ` Anoob Joseph
       [not found]             ` <SN6PR11MB25581C7C8F969AA18EE8C1949A320@SN6PR11MB2558.namprd11.prod.outlook.com>
  0 siblings, 2 replies; 35+ messages in thread
From: Akhil Goyal @ 2020-01-20  6:44 UTC (permalink / raw)
  To: Medvedkin, Vladimir, dev
  Cc: konstantin.ananyev, Anoob Joseph, Thomas Monjalon, Ravi Kumar,
	Ruifeng Wang

Hi Vladimir,
The SA lookup logic and management is purely requirement based for the application. The application may only cater to <128 SAs which can be handled based on the current logic. –single-sa option cannot handle this.
Sample applications in DPDK are there to showcase the best a hardware can deliver. IMO, we cannot allow this logic on NXP hardwares. We give performance numbers based on IPSec app to customers and we cannot allow 15% degradation.
Other vendors(Marvell, ARM, AMD) please comment?
Regards,
Akhil
From: Medvedkin, Vladimir <vladimir.medvedkin@intel.com>
Sent: Friday, January 17, 2020 10:35 PM
To: Akhil Goyal <akhil.goyal@nxp.com>; dev@dpdk.org
Cc: konstantin.ananyev@intel.com
Subject: Re: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw

Hi Akhil,
Indeed with our tests we also seeing ~15% perf drop for small packets (~90B) and ~3-4% drop for 1KB packets. While I am looking on a ways to minimize the drop, I think it would be hard, if possible at all to eliminate it completely.
Reason for that: current SAD implementation is completely synthetic (using plain array structure indexed by SPI value). That provides a very low overhead, but doesn't provide expected functionality and can't be used in proper implementation.
To measure plain IPsec performance without SAD user can still use '--signle-sa' option.
On 15/01/2020 15:45, Akhil Goyal wrote:

Hi Vladimir,



There is more than 10% drop with this patchset on NXP hardware with both legacy mode and the ipsec lib mode. This would need some debugging.

Didn't you see any drop on intel?



Regards,

Akhil



-----Original Message-----

From: Vladimir Medvedkin <vladimir.medvedkin@intel.com><mailto:vladimir.medvedkin@intel.com>

Sent: Tuesday, January 14, 2020 7:57 PM

To: dev@dpdk.org<mailto:dev@dpdk.org>

Cc: konstantin.ananyev@intel.com<mailto:konstantin.ananyev@intel.com>; Akhil Goyal <akhil.goyal@nxp.com><mailto:akhil.goyal@nxp.com>

Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw



This series integrates SA database (SAD) capabilities from ipsec library.

The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.

Also patch series removes hardcoded limitation for maximum number of SA's

and SP's.



v4:

 - put tunnel SA's into SAD with SPI_ONLY type for performance reason



v3:

 - parse SA and SP into sorted array instead of linked list



v2:

 - get rid of maximum sp limitation



Vladimir Medvedkin (5):

  ipsec: move ipsec sad name length into .h

  examples/ipsec-secgw: implement inbound SAD

  examples/ipsec-secgw: integrate inbound SAD

  examples/ipsec-secgw: get rid of maximum sa limitation

  examples/ipsec-secgw: get rid of maximum sp limitation



 examples/ipsec-secgw/Makefile      |   1 +

 examples/ipsec-secgw/ipsec-secgw.c |   4 +-

 examples/ipsec-secgw/ipsec.h       |  11 +-

 examples/ipsec-secgw/meson.build   |   2 +-

 examples/ipsec-secgw/parser.c      |   4 +

 examples/ipsec-secgw/parser.h      |   9 ++

 examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------

 examples/ipsec-secgw/sad.c         |  90 +++++++++++++

 examples/ipsec-secgw/sad.h         |  74 +++++++++++

 examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----

 examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----

 lib/librte_ipsec/ipsec_sad.c       |  20 +--

 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +

 13 files changed, 528 insertions(+), 171 deletions(-)

 create mode 100644 examples/ipsec-secgw/sad.c

 create mode 100644 examples/ipsec-secgw/sad.h



--

2.7.4



--

Regards,

Vladimir
-->

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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-20  6:44           ` Akhil Goyal
@ 2020-01-20 12:44             ` Anoob Joseph
       [not found]             ` <SN6PR11MB25581C7C8F969AA18EE8C1949A320@SN6PR11MB2558.namprd11.prod.outlook.com>
  1 sibling, 0 replies; 35+ messages in thread
From: Anoob Joseph @ 2020-01-20 12:44 UTC (permalink / raw)
  To: Akhil Goyal, Medvedkin, Vladimir, dev
  Cc: konstantin.ananyev, Thomas Monjalon, Ravi Kumar, Ruifeng Wang,
	Jerin Jacob Kollanukkaran, Narayana Prasad Raju Athreya,
	Lukas Bartosik

Hi Vladimir, Akhil,

Marvell is also observing 10-15% drop with the SAD change. I agree with Akhil's opinion and we are not in favor of making this change.

Thanks,
Anoob

From: Akhil Goyal <akhil.goyal@nxp.com> 
Sent: Monday, January 20, 2020 12:14 PM
To: Medvedkin, Vladimir <vladimir.medvedkin@intel.com>; dev@dpdk.org
Cc: konstantin.ananyev@intel.com; Anoob Joseph <anoobj@marvell.com>; Thomas Monjalon <thomas@monjalon.net>; Ravi Kumar <ravi1.kumar@amd.com>; Ruifeng Wang <ruifeng.wang@arm.com>
Subject: [EXT] RE: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw

External Email 
________________________________________
Hi Vladimir,
The SA lookup logic and management is purely requirement based for the application. The application may only cater to <128 SAs which can be handled based on the current logic. –single-sa option cannot handle this.
Sample applications in DPDK are there to showcase the best a hardware can deliver. IMO, we cannot allow this logic on NXP hardwares. We give performance numbers based on IPSec app to customers and we cannot allow 15% degradation.
Other vendors(Marvell, ARM, AMD) please comment?
Regards,
Akhil
From: Medvedkin, Vladimir <mailto:vladimir.medvedkin@intel.com> 
Sent: Friday, January 17, 2020 10:35 PM
To: Akhil Goyal <mailto:akhil.goyal@nxp.com>; mailto:dev@dpdk.org
Cc: mailto:konstantin.ananyev@intel.com
Subject: Re: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw

Hi Akhil,
Indeed with our tests we also seeing ~15% perf drop for small packets (~90B) and ~3-4% drop for 1KB packets. While I am looking on a ways to minimize the drop, I think it would be hard, if possible at all to eliminate it completely.
Reason for that: current SAD implementation is completely synthetic (using plain array structure indexed by SPI value). That provides a very low overhead, but doesn't provide expected functionality and can't be used in proper implementation.
To measure plain IPsec performance without SAD user can still use '--signle-sa' option.
On 15/01/2020 15:45, Akhil Goyal wrote:
Hi Vladimir,

There is more than 10% drop with this patchset on NXP hardware with both legacy mode and the ipsec lib mode. This would need some debugging.
Didn't you see any drop on intel?

Regards,
Akhil

-----Original Message-----
From: Vladimir Medvedkin mailto:vladimir.medvedkin@intel.com
Sent: Tuesday, January 14, 2020 7:57 PM
To: mailto:dev@dpdk.org
Cc: mailto:konstantin.ananyev@intel.com; Akhil Goyal mailto:akhil.goyal@nxp.com
Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw

This series integrates SA database (SAD) capabilities from ipsec library.
The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
Also patch series removes hardcoded limitation for maximum number of SA's
and SP's.

v4:
 - put tunnel SA's into SAD with SPI_ONLY type for performance reason

v3:
 - parse SA and SP into sorted array instead of linked list

v2:
 - get rid of maximum sp limitation

Vladimir Medvedkin (5):
  ipsec: move ipsec sad name length into .h
  examples/ipsec-secgw: implement inbound SAD
  examples/ipsec-secgw: integrate inbound SAD
  examples/ipsec-secgw: get rid of maximum sa limitation
  examples/ipsec-secgw: get rid of maximum sp limitation

 examples/ipsec-secgw/Makefile      |   1 +
 examples/ipsec-secgw/ipsec-secgw.c |   4 +-
 examples/ipsec-secgw/ipsec.h       |  11 +-
 examples/ipsec-secgw/meson.build   |   2 +-
 examples/ipsec-secgw/parser.c      |   4 +
 examples/ipsec-secgw/parser.h      |   9 ++
 examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------
 examples/ipsec-secgw/sad.c         |  90 +++++++++++++
 examples/ipsec-secgw/sad.h         |  74 +++++++++++
 examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
 examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
 lib/librte_ipsec/ipsec_sad.c       |  20 +--
 lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
 13 files changed, 528 insertions(+), 171 deletions(-)
 create mode 100644 examples/ipsec-secgw/sad.c
 create mode 100644 examples/ipsec-secgw/sad.h

--
2.7.4

-- 
Regards,
Vladimir
-->

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

* [dpdk-dev] FW: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
       [not found]               ` <SN6PR11MB25588E3DD326CFC90DD1E3989A320@SN6PR11MB2558.namprd11.prod.outlook.com>
@ 2020-01-20 14:45                 ` " Ananyev, Konstantin
  2020-01-21 14:47                   ` [dpdk-dev] " Akhil Goyal
  0 siblings, 1 reply; 35+ messages in thread
From: Ananyev, Konstantin @ 2020-01-20 14:45 UTC (permalink / raw)
  To: Akhil Goyal, dev
  Cc: Medvedkin, Vladimir, Anoob Joseph, Thomas Monjalon, Ravi Kumar,
	Ruifeng Wang

Hi Akhil,
 
> Hi Vladimir,
> The SA lookup logic and management is purely requirement based for the application. 
>The application may only cater to <128 SAs which can
> be handled based on the current logic.

Not always, current implementation can handle < 128 SA, 
whose SPI%128 never match (let say it cant't handle SPI=1 and SPI=129).
Yes, what we have right now has nearly zero overhead,
and might be ok for some really simple show-cases.
But for majority of production IPsec implementations, 
I believe that definitely wouldn't be enough.  

> –single-sa option cannot handle this.
> Sample applications in DPDK are there to showcase the best a hardware can deliver. 

My thought was - that's the reason we have single-sa option -
demonstrate best possible HW perf without minimal SW intervention.
For something more serious than that, we use generic SAD implementation.

> IMO, we cannot allow this logic on NXP hardwares. We
> give performance numbers based on IPSec app to customers and we cannot allow 15% degradation.

As Vladimir said, we are looking how to improve current SAD numbers
and minimize the drop.
But with same equals - plain array will always be faster than hash table,
so not sure we will be able to match existing performance.
So two questions:
1. What exact case you use for perf testing
    (total number of SAs, packets per burst belong to the same/different SAs)?
    Might be there is a way to speedup it.
    Again if 10-15% is not an affordable drop, which one is: zero or ...?
2. I think there are 2 different directions for ipsec-secgw:
   From one-side there is a desire to use it as a show-case for best-possible HW IPsec performance
  (which is understandable).
   From other side - attempt to make it as close as real-world generic ipsec processing app as possible
   (support for ESN, replay window, fragmented packets, generic proper SAD, etc).
   Obviously these goals contradict and it makes really hard for the same app to fulfill both.
   Any thoughts how to deal with that?
   One obvious would be to split the app, anything else?
    
Konstantin

> Other vendors(Marvell, ARM, AMD) please comment?
> Regards,
> Akhil
> From: Medvedkin, Vladimir <mailto:vladimir.medvedkin@intel.com>
> Sent: Friday, January 17, 2020 10:35 PM
> To: Akhil Goyal <mailto:akhil.goyal@nxp.com>; mailto:dev@dpdk.org
> Cc: mailto:konstantin.ananyev@intel.com
> Subject: Re: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
> 
> Hi Akhil,
> Indeed with our tests we also seeing ~15% perf drop for small packets (~90B) and ~3-4% drop for 1KB packets. While I am looking on a ways
> to minimize the drop, I think it would be hard, if possible at all to eliminate it completely.
> Reason for that: current SAD implementation is completely synthetic (using plain array structure indexed by SPI value). That provides a very
> low overhead, but doesn't provide expected functionality and can't be used in proper implementation.
> To measure plain IPsec performance without SAD user can still use '--signle-sa' option.
> On 15/01/2020 15:45, Akhil Goyal wrote:
> Hi Vladimir,
> 
> There is more than 10% drop with this patchset on NXP hardware with both legacy mode and the ipsec lib mode. This would need some
> debugging.
> Didn't you see any drop on intel?
> 
> Regards,
> Akhil
> 
> -----Original Message-----
> From: Vladimir Medvedkin mailto:vladimir.medvedkin@intel.com
> Sent: Tuesday, January 14, 2020 7:57 PM
> To: mailto:dev@dpdk.org
> Cc: mailto:konstantin.ananyev@intel.com; Akhil Goyal mailto:akhil.goyal@nxp.com
> Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
> 
> This series integrates SA database (SAD) capabilities from ipsec library.
> The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
> Also patch series removes hardcoded limitation for maximum number of SA's
> and SP's.
> 
> v4:
>  - put tunnel SA's into SAD with SPI_ONLY type for performance reason
> 
> v3:
>  - parse SA and SP into sorted array instead of linked list
> 
> v2:
>  - get rid of maximum sp limitation
> 
> Vladimir Medvedkin (5):
>   ipsec: move ipsec sad name length into .h
>   examples/ipsec-secgw: implement inbound SAD
>   examples/ipsec-secgw: integrate inbound SAD
>   examples/ipsec-secgw: get rid of maximum sa limitation
>   examples/ipsec-secgw: get rid of maximum sp limitation
> 
>  examples/ipsec-secgw/Makefile      |   1 +
>  examples/ipsec-secgw/ipsec-secgw.c |   4 +-
>  examples/ipsec-secgw/ipsec.h       |  11 +-
>  examples/ipsec-secgw/meson.build   |   2 +-
>  examples/ipsec-secgw/parser.c      |   4 +
>  examples/ipsec-secgw/parser.h      |   9 ++
>  examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++--------------
>  examples/ipsec-secgw/sad.c         |  90 +++++++++++++
>  examples/ipsec-secgw/sad.h         |  74 +++++++++++
>  examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
>  examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
>  lib/librte_ipsec/ipsec_sad.c       |  20 +--
>  lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
>  13 files changed, 528 insertions(+), 171 deletions(-)
>  create mode 100644 examples/ipsec-secgw/sad.c
>  create mode 100644 examples/ipsec-secgw/sad.h
> 
> --
> 2.7.4
> 
> --
> Regards,
> Vladimir
> -->

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

* Re: [dpdk-dev] [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
  2020-01-20 14:45                 ` [dpdk-dev] FW: " Ananyev, Konstantin
@ 2020-01-21 14:47                   ` " Akhil Goyal
  0 siblings, 0 replies; 35+ messages in thread
From: Akhil Goyal @ 2020-01-21 14:47 UTC (permalink / raw)
  To: Ananyev, Konstantin, dev
  Cc: Medvedkin, Vladimir, Anoob Joseph, Thomas Monjalon, Ravi Kumar,
	Ruifeng Wang

Hi Konstantin,
> 
> Hi Akhil,
> 
> > Hi Vladimir,
> > The SA lookup logic and management is purely requirement based for the
> application.
> >The application may only cater to <128 SAs which can
> > be handled based on the current logic.
> 
> Not always, current implementation can handle < 128 SA,
> whose SPI%128 never match (let say it cant't handle SPI=1 and SPI=129).
> Yes, what we have right now has nearly zero overhead,
> and might be ok for some really simple show-cases.
> But for majority of production IPsec implementations,
> I believe that definitely wouldn't be enough.
> 
> > –single-sa option cannot handle this.
> > Sample applications in DPDK are there to showcase the best a hardware can
> deliver.
> 
> My thought was - that's the reason we have single-sa option -
> demonstrate best possible HW perf without minimal SW intervention.
> For something more serious than that, we use generic SAD implementation.
> 
> > IMO, we cannot allow this logic on NXP hardwares. We
> > give performance numbers based on IPSec app to customers and we cannot
> allow 15% degradation.
> 
> As Vladimir said, we are looking how to improve current SAD numbers
> and minimize the drop.
> But with same equals - plain array will always be faster than hash table,
> so not sure we will be able to match existing performance.
> So two questions:
> 1. What exact case you use for perf testing
>     (total number of SAs, packets per burst belong to the same/different SAs)?
>     Might be there is a way to speedup it.
>     Again if 10-15% is not an affordable drop, which one is: zero or ...?

We should add features judiciously, we cannot drop the performance of a benchmarking
Application in lieu of adding functionality. We should only add features which are not
Impacting the performance significantly.
Every vendor may have different cases. We cannot tune for everybody.
However, I see drop in 64 outbound 64 inbound SAs all with different SPI and IPs.
Packets per burst = 32 all with different SAs.

> 2. I think there are 2 different directions for ipsec-secgw:
>    From one-side there is a desire to use it as a show-case for best-possible HW
> IPsec performance
>   (which is understandable).
>    From other side - attempt to make it as close as real-world generic ipsec
> processing app as possible
>    (support for ESN, replay window, fragmented packets, generic proper SAD,
> etc).
>    Obviously these goals contradict and it makes really hard for the same app to
> fulfill both.
>    Any thoughts how to deal with that?
>    One obvious would be to split the app, anything else?

We can have a fallback mechanism back to original functionality for whatever feature
which has some perf drop.
Splitting an app can be thought of but that would be similar to a full fledged IPSec stack
like VPP-IPSec.

> 
> Konstantin
> 
> > Other vendors(Marvell, ARM, AMD) please comment?
> > Regards,
> > Akhil
> > From: Medvedkin, Vladimir <mailto:vladimir.medvedkin@intel.com>
> > Sent: Friday, January 17, 2020 10:35 PM
> > To: Akhil Goyal <mailto:akhil.goyal@nxp.com>; mailto:dev@dpdk.org
> > Cc: mailto:konstantin.ananyev@intel.com
> > Subject: Re: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
> >
> > Hi Akhil,
> > Indeed with our tests we also seeing ~15% perf drop for small packets (~90B)
> and ~3-4% drop for 1KB packets. While I am looking on a ways
> > to minimize the drop, I think it would be hard, if possible at all to eliminate it
> completely.
> > Reason for that: current SAD implementation is completely synthetic (using
> plain array structure indexed by SPI value). That provides a very
> > low overhead, but doesn't provide expected functionality and can't be used in
> proper implementation.
> > To measure plain IPsec performance without SAD user can still use '--signle-sa'
> option.
> > On 15/01/2020 15:45, Akhil Goyal wrote:
> > Hi Vladimir,
> >
> > There is more than 10% drop with this patchset on NXP hardware with both
> legacy mode and the ipsec lib mode. This would need some
> > debugging.
> > Didn't you see any drop on intel?
> >
> > Regards,
> > Akhil
> >
> > -----Original Message-----
> > From: Vladimir Medvedkin mailto:vladimir.medvedkin@intel.com
> > Sent: Tuesday, January 14, 2020 7:57 PM
> > To: mailto:dev@dpdk.org
> > Cc: mailto:konstantin.ananyev@intel.com; Akhil Goyal
> mailto:akhil.goyal@nxp.com
> > Subject: [PATCH v4 0/5] integrate librte_ipsec SAD into ipsec-secgw
> >
> > This series integrates SA database (SAD) capabilities from ipsec library.
> > The goal is to make ipsec-secgw RFC compliant regarding inbound SAD.
> > Also patch series removes hardcoded limitation for maximum number of SA's
> > and SP's.
> >
> > v4:
> >  - put tunnel SA's into SAD with SPI_ONLY type for performance reason
> >
> > v3:
> >  - parse SA and SP into sorted array instead of linked list
> >
> > v2:
> >  - get rid of maximum sp limitation
> >
> > Vladimir Medvedkin (5):
> >   ipsec: move ipsec sad name length into .h
> >   examples/ipsec-secgw: implement inbound SAD
> >   examples/ipsec-secgw: integrate inbound SAD
> >   examples/ipsec-secgw: get rid of maximum sa limitation
> >   examples/ipsec-secgw: get rid of maximum sp limitation
> >
> >  examples/ipsec-secgw/Makefile      |   1 +
> >  examples/ipsec-secgw/ipsec-secgw.c |   4 +-
> >  examples/ipsec-secgw/ipsec.h       |  11 +-
> >  examples/ipsec-secgw/meson.build   |   2 +-
> >  examples/ipsec-secgw/parser.c      |   4 +
> >  examples/ipsec-secgw/parser.h      |   9 ++
> >  examples/ipsec-secgw/sa.c          | 256 +++++++++++++++++++++++-------------
> -
> >  examples/ipsec-secgw/sad.c         |  90 +++++++++++++
> >  examples/ipsec-secgw/sad.h         |  74 +++++++++++
> >  examples/ipsec-secgw/sp4.c         | 114 ++++++++++++-----
> >  examples/ipsec-secgw/sp6.c         | 112 +++++++++++-----
> >  lib/librte_ipsec/ipsec_sad.c       |  20 +--
> >  lib/librte_ipsec/rte_ipsec_sad.h   |   2 +
> >  13 files changed, 528 insertions(+), 171 deletions(-)
> >  create mode 100644 examples/ipsec-secgw/sad.c
> >  create mode 100644 examples/ipsec-secgw/sad.h
> >
> > --
> > 2.7.4
> >
> > --
> > Regards,
> > Vladimir
> > -->

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

end of thread, back to index

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-11 16:45 [dpdk-dev] [PATCH 0/4] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
2019-12-11 16:45 ` [dpdk-dev] [PATCH 1/4] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
2019-12-11 16:45 ` [dpdk-dev] [PATCH 2/4] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
2019-12-11 16:45 ` [dpdk-dev] [PATCH 3/4] examples/ipsec-secgw: integrate " Vladimir Medvedkin
2019-12-11 16:45 ` [dpdk-dev] [PATCH 4/4] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 0/5] integrate librte_ipsec SAD into ipsec-secgw Vladimir Medvedkin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 " Vladimir Medvedkin
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 " Vladimir Medvedkin
2020-01-15 15:45       ` Akhil Goyal
2020-01-17 12:26         ` Akhil Goyal
2020-01-17 17:05         ` Medvedkin, Vladimir
2020-01-20  6:44           ` Akhil Goyal
2020-01-20 12:44             ` Anoob Joseph
     [not found]             ` <SN6PR11MB25581C7C8F969AA18EE8C1949A320@SN6PR11MB2558.namprd11.prod.outlook.com>
     [not found]               ` <SN6PR11MB25588E3DD326CFC90DD1E3989A320@SN6PR11MB2558.namprd11.prod.outlook.com>
2020-01-20 14:45                 ` [dpdk-dev] FW: " Ananyev, Konstantin
2020-01-21 14:47                   ` [dpdk-dev] " Akhil Goyal
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
2020-01-14 15:51       ` Ananyev, Konstantin
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
2020-01-14 15:53       ` Ananyev, Konstantin
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
2020-01-14 15:54       ` Ananyev, Konstantin
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
2020-01-14 15:56       ` Ananyev, Konstantin
2020-01-14 14:27     ` [dpdk-dev] [PATCH v4 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
2020-01-14 15:57       ` Ananyev, Konstantin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
2020-01-13 12:55   ` [dpdk-dev] [PATCH v3 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 1/5] ipsec: move ipsec sad name length into .h Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 2/5] examples/ipsec-secgw: implement inbound SAD Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 3/5] examples/ipsec-secgw: integrate " Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 4/5] examples/ipsec-secgw: get rid of maximum sa limitation Vladimir Medvedkin
2019-12-18 16:00 ` [dpdk-dev] [PATCH v2 5/5] examples/ipsec-secgw: get rid of maximum sp limitation Vladimir Medvedkin

DPDK-dev Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/dpdk-dev/0 dpdk-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 dpdk-dev dpdk-dev/ https://lore.kernel.org/dpdk-dev \
		dev@dpdk.org
	public-inbox-index dpdk-dev

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.dpdk.dev


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