DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/9] IPSec example enhancements
@ 2016-05-06 16:31 Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
                   ` (9 more replies)
  0 siblings, 10 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Update IPSec sample app with IPv6 and Transport mode support.

The series contains some bug fixes to facilitate patch merge.

Sergio Gonzalez Monroy (9):
  examples/ipsec-secgw: fix esp padding check
  examples/ipsec-secgw: fix stack smashing error
  examples/ipsec-secgw: add build option and cleanup
  examples/ipsec-secgw: rework ipsec execution loop
  examples/ipsec-secgw: fix no sa found case
  examples/ipsec-secgw: consistent config variable names
  examples/ipsec-secgw: ipv6 support
  examples/ipsec-secgw: transport mode support
  doc: update ipsec sample guide

 doc/guides/sample_app_ug/ipsec_secgw.rst | 583 ++++++++++++++++++++-----------
 examples/ipsec-secgw/Makefile            |   8 +-
 examples/ipsec-secgw/esp.c               | 205 +++++++----
 examples/ipsec-secgw/esp.h               |   9 +-
 examples/ipsec-secgw/ipip.h              | 145 ++++++--
 examples/ipsec-secgw/ipsec-secgw.c       | 332 ++++++++++++------
 examples/ipsec-secgw/ipsec.c             |  50 ++-
 examples/ipsec-secgw/ipsec.h             |  63 ++--
 examples/ipsec-secgw/rt.c                | 229 +++++++++---
 examples/ipsec-secgw/sa.c                | 466 +++++++++++++-----------
 examples/ipsec-secgw/sp.c                | 366 -------------------
 examples/ipsec-secgw/sp4.c               | 447 ++++++++++++++++++++++++
 examples/ipsec-secgw/sp6.c               | 448 ++++++++++++++++++++++++
 13 files changed, 2288 insertions(+), 1063 deletions(-)
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

-- 
2.5.5

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

* [dpdk-dev] [PATCH 1/9] examples/ipsec-secgw: fix esp padding check
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Current code fails to correctly check padding sequence for inbound
packets.
Padding sequence starts on 1 but it checks for 0.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 1927380..3e98253 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -139,7 +139,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
-		if (padding[i] != i) {
+		if (padding[i] != i + 1) {
 			IPSEC_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
 			return -EINVAL;
 		}
-- 
2.5.5

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

* [dpdk-dev] [PATCH 2/9] examples/ipsec-secgw: fix stack smashing error
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Building the application with -O3 and -fstack-protection (default in
Ubuntu) results in the following error:

*** stack smashing detected ***: ./build/ipsec-secgw terminated

The error is caused by storing an 8B value in a 4B variable.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signe-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index baf30d4..6371799 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -46,7 +46,7 @@
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 {
-	uint32_t cdev_id_qp = 0;
+	unsigned long cdev_id_qp = 0;
 	int32_t ret;
 	struct cdev_key key = { 0 };
 
-- 
2.5.5

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

* [dpdk-dev] [PATCH 3/9] examples/ipsec-secgw: add build option and cleanup
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Add support for building the application with DEBUG=1.
This option adds the compiler stack protection flag and enables extra
output in the application.

Also remove unnecessary VPATH setup.

Signe-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index f9b59c2..6780ad5 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -46,8 +46,9 @@ ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
 CFLAGS_sa.o += -diag-disable=vec
 endif
 
-
-VPATH += $(SRCDIR)/librte_ipsec
+ifeq ($(DEBUG),1)
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+endif
 
 #
 # all source are stored in SRCS-y
-- 
2.5.5

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

* [dpdk-dev] [PATCH 4/9] examples/ipsec-secgw: rework ipsec execution loop
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (2 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Rework implementation moving from function pointers approach, where each
function implements very specific functionality, to a generic function
approach.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   |   8 +-
 examples/ipsec-secgw/esp.h   |   9 +-
 examples/ipsec-secgw/ipsec.c |  36 ++++--
 examples/ipsec-secgw/ipsec.h |   2 -
 examples/ipsec-secgw/sa.c    | 272 ++++++++++++++++++-------------------------
 5 files changed, 145 insertions(+), 182 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 3e98253..5ecf6a6 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -69,7 +69,7 @@ random_iv_u64(uint64_t *buf, uint16_t n)
 
 /* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	int32_t payload_len;
@@ -117,7 +117,7 @@ esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint8_t *nexthdr, *pad_len;
@@ -155,7 +155,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint16_t pad_payload_len, pad_len;
@@ -234,7 +234,7 @@ esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m __rte_unused,
+esp_outbound_post(struct rte_mbuf *m __rte_unused,
 		struct ipsec_sa *sa __rte_unused,
 		struct rte_crypto_op *cop)
 {
diff --git a/examples/ipsec-secgw/esp.h b/examples/ipsec-secgw/esp.h
index 3101882..fa5cc8a 100644
--- a/examples/ipsec-secgw/esp.h
+++ b/examples/ipsec-secgw/esp.h
@@ -46,21 +46,20 @@ struct esp_hdr {
 	/* Integrity Check Value - ICV */
 };
 
-/* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 #endif /* __RTE_IPSEC_XFORM_ESP_H__ */
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 6371799..797663b 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -42,6 +42,7 @@
 #include <rte_hash.h>
 
 #include "ipsec.h"
+#include "esp.h"
 
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
@@ -99,15 +100,14 @@ enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 	}
 }
 
-static inline uint16_t
-ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
-		struct ipsec_sa *sas[], uint16_t nb_pkts, uint16_t max_pkts)
+static inline void
+ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
+		uint16_t nb_pkts)
 {
-	int ret = 0, i, j, nb_cops;
+	int ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
-	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
-	struct rte_mbuf *pkt;
 
 	for (i = 0; i < nb_pkts; i++) {
 		rte_prefetch0(sas[i]);
@@ -133,7 +133,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		rte_crypto_op_attach_sym_session(&priv->cop,
 				sa->crypto_session);
 
-		ret = sa->pre_crypto(pkts[i], sa, &priv->cop);
+		ret = xform_func(pkts[i], sa, &priv->cop);
 		if (unlikely(ret)) {
 			rte_pktmbuf_free(pkts[i]);
 			continue;
@@ -142,8 +142,18 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		IPSEC_ASSERT(sa->cdev_id_qp < ipsec_ctx->nb_qps);
 		enqueue_cop(&ipsec_ctx->tbl[sa->cdev_id_qp], &priv->cop);
 	}
+}
+
+static inline int
+ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], uint16_t max_pkts)
+{
+	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	struct ipsec_mbuf_metadata *priv;
+	struct rte_crypto_op *cops[max_pkts];
+	struct ipsec_sa *sa;
+	struct rte_mbuf *pkt;
 
-	nb_pkts = 0;
 	for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
 		struct cdev_qp *cqp;
 
@@ -168,7 +178,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 
 			IPSEC_ASSERT(sa != NULL);
 
-			ret = sa->post_crypto(pkt, sa, cops[j]);
+			ret = xform_func(pkt, sa, cops[j]);
 			if (unlikely(ret))
 				rte_pktmbuf_free(pkt);
 			else
@@ -188,7 +198,9 @@ ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_inbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_inbound_post, ctx, pkts, len);
 }
 
 uint16_t
@@ -199,5 +211,7 @@ ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_outbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_outbound_post, ctx, pkts, len);
 }
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index a13fdef..2cf9ea6 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -98,8 +98,6 @@ struct ipsec_sa {
 	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
 	struct rte_crypto_sym_xform *xforms;
-	ipsec_xform_fn pre_crypto;
-	ipsec_xform_fn post_crypto;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index b6260ed..a193bdf 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -47,160 +47,112 @@
 #include "ipsec.h"
 #include "esp.h"
 
-/* SAs EP0 Outbound */
-const struct ipsec_sa sa_ep0_out[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP0 Inbound */
-const struct ipsec_sa sa_ep0_in[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP1 Outbound */
-const struct ipsec_sa sa_ep1_out[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Outbound */
+const struct ipsec_sa sa_out[] = {
+	{
+	.spi = 5,
+	.src = IPv4(172, 16, 1, 5),
+	.dst = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 6,
+	.src = IPv4(172, 16, 1, 6),
+	.dst = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 7,
+	.src = IPv4(172, 16, 1, 7),
+	.dst = IPv4(172, 16, 2, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 8,
+	.src = IPv4(172, 16, 1, 8),
+	.dst = IPv4(172, 16, 2, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 9,
+	.src = IPv4(172, 16, 1, 9),
+	.dst = IPv4(172, 16, 2, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
-/* SAs EP1 Inbound */
-const struct ipsec_sa sa_ep1_in[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Inbound */
+const struct ipsec_sa sa_in[] = {
+	{
+	.spi = 55,
+	.src = IPv4(172, 16, 2, 5),
+	.dst = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 56,
+	.src = IPv4(172, 16, 2, 6),
+	.dst = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 57,
+	.src = IPv4(172, 16, 2, 7),
+	.dst = IPv4(172, 16, 1, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 58,
+	.src = IPv4(172, 16, 2, 8),
+	.dst = IPv4(172, 16, 1, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 59,
+	.src = IPv4(172, 16, 2, 9),
+	.dst = IPv4(172, 16, 1, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -368,15 +320,15 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		sa_out_entries = sa_ep0_out;
-		nb_out_entries = RTE_DIM(sa_ep0_out);
-		sa_in_entries = sa_ep0_in;
-		nb_in_entries = RTE_DIM(sa_ep0_in);
+		sa_out_entries = sa_out;
+		nb_out_entries = RTE_DIM(sa_out);
+		sa_in_entries = sa_in;
+		nb_in_entries = RTE_DIM(sa_in);
 	} else if (ep == 1) {
-		sa_out_entries = sa_ep1_out;
-		nb_out_entries = RTE_DIM(sa_ep1_out);
-		sa_in_entries = sa_ep1_in;
-		nb_in_entries = RTE_DIM(sa_ep1_in);
+		sa_out_entries = sa_in;
+		nb_out_entries = RTE_DIM(sa_in);
+		sa_in_entries = sa_out;
+		nb_in_entries = RTE_DIM(sa_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH 5/9] examples/ipsec-secgw: fix no sa found case
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (3 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

The application only checks that an SA shoudln't be NULL through ASSERT
(only when debugging is enabled) without properly dealing with the case
of not having an SA for the processed packet.

If no SA is found, drop the packet.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 797663b..53af875 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -110,6 +110,11 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 	struct ipsec_sa *sa;
 
 	for (i = 0; i < nb_pkts; i++) {
+		if (unlikely(sas[i] == NULL)) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+
 		rte_prefetch0(sas[i]);
 		rte_prefetch0(pkts[i]);
 
@@ -117,8 +122,6 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		sa = sas[i];
 		priv->sa = sa;
 
-		IPSEC_ASSERT(sa != NULL);
-
 		priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
 
 		rte_prefetch0(&priv->sym_cop);
-- 
2.5.5

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

* [dpdk-dev] [PATCH 6/9] examples/ipsec-secgw: consistent config variable names
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (4 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Modify the default SP config variables names to be consistent with SA.

The resulting naming convention is that variables with suffixes _out/_in
are the default for ep0 and the reverse for ep1.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/sp.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
index 4f16730..6aa377d 100644
--- a/examples/ipsec-secgw/sp.c
+++ b/examples/ipsec-secgw/sp.c
@@ -112,7 +112,7 @@ struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
 
-const struct acl4_rules acl4_rules_in[] = {
+const struct acl4_rules acl4_rules_out[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -175,7 +175,7 @@ const struct acl4_rules acl4_rules_in[] = {
 	}
 };
 
-const struct acl4_rules acl4_rules_out[] = {
+const struct acl4_rules acl4_rules_in[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -343,15 +343,15 @@ sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else if (ep == 1) {
 		rules_out = acl4_rules_out;
 		nb_out_rules = RTE_DIM(acl4_rules_out);
 		rules_in = acl4_rules_in;
 		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH 7/9] examples/ipsec-secgw: ipv6 support
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (5 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Support IPSec IPv6 allowing IPv4/IPv6 traffic in IPv4 or IPv6 tunnel.

We need separate Routing (LPM) and SP (ACL) tables for IPv4 and IPv6,
but a common SA table.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile      |   5 +-
 examples/ipsec-secgw/esp.c         | 128 +++++++-----
 examples/ipsec-secgw/ipip.h        | 145 ++++++++++---
 examples/ipsec-secgw/ipsec-secgw.c | 332 ++++++++++++++++++++----------
 examples/ipsec-secgw/ipsec.c       |   9 +-
 examples/ipsec-secgw/ipsec.h       |  60 ++++--
 examples/ipsec-secgw/rt.c          | 201 +++++++++++++-----
 examples/ipsec-secgw/sa.c          | 239 ++++++++++++++--------
 examples/ipsec-secgw/sp.c          | 366 ---------------------------------
 examples/ipsec-secgw/sp4.c         | 407 +++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sp6.c         | 400 ++++++++++++++++++++++++++++++++++++
 11 files changed, 1582 insertions(+), 710 deletions(-)
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 6780ad5..06b6db1 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -47,7 +47,7 @@ CFLAGS_sa.o += -diag-disable=vec
 endif
 
 ifeq ($(DEBUG),1)
-CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all -O0
 endif
 
 #
@@ -55,7 +55,8 @@ endif
 #
 SRCS-y += ipsec.c
 SRCS-y += esp.c
-SRCS-y += sp.c
+SRCS-y += sp4.c
+SRCS-y += sp6.c
 SRCS-y += sa.c
 SRCS-y += rt.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 5ecf6a6..ee541eb 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <fcntl.h>
 #include <unistd.h>
 
@@ -50,13 +51,11 @@
 #include "esp.h"
 #include "ipip.h"
 
-#define IP_ESP_HDR_SZ (sizeof(struct ip) + sizeof(struct esp_hdr))
-
 static inline void
 random_iv_u64(uint64_t *buf, uint16_t n)
 {
-	unsigned left = n & 0x7;
-	unsigned i;
+	uint32_t left = n & 0x7;
+	uint32_t i;
 
 	IPSEC_ASSERT((n & 0x3) == 0);
 
@@ -67,20 +66,29 @@ random_iv_u64(uint64_t *buf, uint16_t n)
 		*((uint32_t *)&buf[i]) = (uint32_t)lrand48();
 }
 
-/* IPv4 Tunnel */
 int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len;
+	int32_t payload_len, ip_hdr_len;
 	struct rte_crypto_sym_op *sym_cop;
 
 	IPSEC_ASSERT(m != NULL);
 	IPSEC_ASSERT(sa != NULL);
 	IPSEC_ASSERT(cop != NULL);
 
-	payload_len = rte_pktmbuf_pkt_len(m) - IP_ESP_HDR_SZ - sa->iv_len -
-		sa->digest_len;
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
+
+	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
+		sizeof(struct esp_hdr) - sa->iv_len - sa->digest_len;
 
 	if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
 		IPSEC_LOG(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
@@ -91,21 +99,19 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset =  ip_hdr_len + sizeof(struct esp_hdr) +
+		sa->iv_len;
 	sym_cop->cipher.data.length = payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, void*,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
-	if (sa->auth_algo == RTE_CRYPTO_AUTH_AES_GCM)
-		sym_cop->auth.data.length = sizeof(struct esp_hdr);
-	else
-		sym_cop->auth.data.length = sizeof(struct esp_hdr) +
-			sa->iv_len + payload_len;
+	sym_cop->auth.data.offset = ip_hdr_len;
+	sym_cop->auth.data.length = sizeof(struct esp_hdr) +
+		sa->iv_len + payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
@@ -151,17 +157,20 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	return ip4ip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+
+	return 0;
 }
 
 int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len;
-	struct ip *ip;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
+	struct ip *ip4;
+	struct ip6_hdr *ip6;
 	struct esp_hdr *esp;
-	int i;
+	int32_t i;
 	char *padding;
 	struct rte_crypto_sym_op *sym_cop;
 
@@ -174,62 +183,87 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 			sa->block_size);
 	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
 
-	rte_prefetch0(rte_pktmbuf_mtod_offset(m, void *,
-				rte_pktmbuf_pkt_len(m)));
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
 
 	/* Check maximum packet size */
-	if (unlikely(IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len +
-				sa->digest_len > IP_MAXPACKET)) {
-		IPSEC_LOG(DEBUG, IPSEC_ESP, "ipsec packet is too big\n");
+	if (unlikely(ip_hdr_len + sizeof(struct esp_hdr) + sa->iv_len +
+			pad_payload_len + sa->digest_len > IP_MAXPACKET)) {
+		IPSEC_LOG(ERR, IPSEC_ESP, "ipsec packet is too big\n");
 		return -EINVAL;
 	}
 
 	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	if (unlikely(padding == NULL)) {
+		IPSEC_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
+		return -ENOSPC;
+	}
+	rte_prefetch0(padding);
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip4 = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip4 + 1);
+		break;
+	case IP6_TUNNEL:
+		ip6 = ip6ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip6 + 1);
+		break;
+	default:
+		IPSEC_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
+				sa->flags);
+		return -EINVAL;
+	}
 
-	IPSEC_ASSERT(padding != NULL);
-
-	ip = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
-			sa->src, sa->dst);
-
-	esp = (struct esp_hdr *)(ip + 1);
-	esp->spi = sa->spi;
-	esp->seq = htonl(sa->seq++);
+	sa->seq++;
+	esp->spi = rte_cpu_to_be_32(sa->spi);
+	esp->seq = rte_cpu_to_be_32(sa->seq);
 
-	IPSEC_LOG(DEBUG, IPSEC_ESP, "pktlen %u\n", rte_pktmbuf_pkt_len(m));
+	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
+		random_iv_u64((uint64_t *)(esp + 1), sa->iv_len);
 
 	/* Fill pad_len using default sequential scheme */
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
-
 	padding[pad_len - 2] = pad_len - 2;
-	padding[pad_len - 1] = IPPROTO_IPIP;
+
+	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
+		padding[pad_len - 1] = IPPROTO_IPIP;
+	else
+		padding[pad_len - 1] = IPPROTO_IPV6;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset = ip_hdr_len + sizeof(struct esp_hdr) +
+			sa->iv_len;
 	sym_cop->cipher.data.length = pad_payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
+	sym_cop->auth.data.offset = ip_hdr_len;
 	sym_cop->auth.data.length = sizeof(struct esp_hdr) + sa->iv_len +
 		pad_payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.length = sa->digest_len;
 
-	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
-		random_iv_u64((uint64_t *)sym_cop->cipher.iv.data,
-				sym_cop->cipher.iv.length);
-
 	return 0;
 }
 
diff --git a/examples/ipsec-secgw/ipip.h b/examples/ipsec-secgw/ipip.h
index 322076c..9efd060 100644
--- a/examples/ipsec-secgw/ipip.h
+++ b/examples/ipsec-secgw/ipip.h
@@ -37,65 +37,144 @@
 #include <stdint.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_mbuf.h>
 
-#define IPV6_VERSION (6)
-
-static inline  struct ip *
-ip4ip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t src, uint32_t dst)
+static inline void *
+ipip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t is_ipv6,
+		struct ip_addr *src,  struct ip_addr *dst)
 {
-	struct ip *inip, *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint8_t ds_ecn;
 
-	inip = rte_pktmbuf_mtod(m, struct ip*);
+	inip4 = rte_pktmbuf_mtod(m, struct ip *);
 
-	IPSEC_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	IPSEC_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
+	if (inip4->ip_v == IPVERSION) {
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+		ds_ecn = inip4->ip_tos;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+		ds_ecn = ntohl(inip6->ip6_flow) >> 20;
+	}
+
+	if (is_ipv6) {
+		offset += sizeof(struct ip6_hdr);
+		outip6 = (struct ip6_hdr *)rte_pktmbuf_prepend(m, offset);
+
+		IPSEC_ASSERT(outip6 != NULL);
+
+		/* Per RFC4301 5.1.2.1 */
+		outip6->ip6_flow = htonl(IP6_VERSION << 28 | ds_ecn << 20);
+		outip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+
+		outip6->ip6_nxt = IPPROTO_ESP;
+		outip6->ip6_hops = IPDEFTTL;
 
-	outip = (struct ip *)rte_pktmbuf_prepend(m, offset);
+		memcpy(&outip6->ip6_src.s6_addr, src, 16);
+		memcpy(&outip6->ip6_dst.s6_addr, dst, 16);
 
-	IPSEC_ASSERT(outip != NULL);
+		return outip6;
+	}
+
+	offset += sizeof(struct ip);
+	outip4 = (struct ip *)rte_pktmbuf_prepend(m, offset);
+
+	IPSEC_ASSERT(outip4 != NULL);
 
 	/* Per RFC4301 5.1.2.1 */
-	outip->ip_v = IPVERSION;
-	outip->ip_hl = 5;
-	outip->ip_tos = inip->ip_tos;
-	outip->ip_len = htons(rte_pktmbuf_data_len(m));
+	outip4->ip_v = IPVERSION;
+	outip4->ip_hl = 5;
+	outip4->ip_tos = ds_ecn;
+	outip4->ip_len = htons(rte_pktmbuf_data_len(m));
 
-	outip->ip_id = 0;
-	outip->ip_off = 0;
+	outip4->ip_id = 0;
+	outip4->ip_off = 0;
 
-	outip->ip_ttl = IPDEFTTL;
-	outip->ip_p = IPPROTO_ESP;
+	outip4->ip_ttl = IPDEFTTL;
+	outip4->ip_p = IPPROTO_ESP;
 
-	outip->ip_src.s_addr = src;
-	outip->ip_dst.s_addr = dst;
+	outip4->ip_src.s_addr = src->ip4;
+	outip4->ip_dst.s_addr = dst->ip4;
 
-	return outip;
+	return outip4;
+}
+
+static inline struct ip *
+ip4ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 0, src, dst);
+}
+
+static inline struct ip6_hdr *
+ip6ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 1, src, dst);
+}
+
+static inline void
+ip4_ecn_setup(struct ip *ip4)
+{
+	if (ip4->ip_tos & IPTOS_ECN_MASK)
+		ip4->ip_tos |= IPTOS_ECN_CE;
+}
+
+static inline void
+ip6_ecn_setup(struct ip6_hdr *ip6)
+{
+	if ((ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK)
+		ip6->ip6_flow = htonl(ntohl(ip6->ip6_flow) |
+					(IPTOS_ECN_CE << 20));
 }
 
 static inline int
-ip4ip_inbound(struct rte_mbuf *m, uint32_t offset)
+ipip_inbound(struct rte_mbuf *m, uint32_t offset)
 {
-	struct ip *inip;
-	struct ip *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint32_t ip_len, set_ecn;
 
-	outip = rte_pktmbuf_mtod(m, struct ip*);
+	outip4 = rte_pktmbuf_mtod(m, struct ip*);
 
-	IPSEC_ASSERT(outip->ip_v == IPVERSION);
+	IPSEC_ASSERT(outip4->ip_v == IPVERSION || outip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
-	inip = (struct ip *)rte_pktmbuf_adj(m, offset);
-	IPSEC_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	if (outip4->ip_v == IPVERSION) {
+		ip_len = sizeof(struct ip);
+		set_ecn = ((outip4->ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	} else {
+		outip6 = (struct ip6_hdr *)outip4;
+		ip_len = sizeof(struct ip6_hdr);
+		set_ecn = ntohl(outip6->ip6_flow) >> 20;
+		set_ecn = ((set_ecn & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	}
+
+	inip4 = (struct ip *)rte_pktmbuf_adj(m, offset + ip_len);
+	IPSEC_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
 	/* Check packet is still bigger than IP header (inner) */
-	IPSEC_ASSERT(rte_pktmbuf_pkt_len(m) > sizeof(struct ip));
+	IPSEC_ASSERT(rte_pktmbuf_pkt_len(m) > ip_len);
 
 	/* RFC4301 5.1.2.1 Note 6 */
-	if ((inip->ip_tos & htons(IPTOS_ECN_ECT0 | IPTOS_ECN_ECT1)) &&
-			((outip->ip_tos & htons(IPTOS_ECN_CE)) == IPTOS_ECN_CE))
-		inip->ip_tos |= htons(IPTOS_ECN_CE);
+	if (inip4->ip_v == IPVERSION) {
+		if (set_ecn)
+			ip4_ecn_setup(inip4);
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		if (set_ecn)
+			ip6_ecn_setup(inip6);
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+	}
 
 	return 0;
 }
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 00ab2d8..4065b59 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -38,6 +38,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <string.h>
 #include <sys/queue.h>
 #include <stdarg.h>
@@ -65,6 +66,7 @@
 #include <rte_mbuf.h>
 #include <rte_acl.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_hash.h>
 #include <rte_jhash.h>
 #include <rte_cryptodev.h>
@@ -192,7 +194,8 @@ struct lcore_conf {
 	struct buffer tx_mbufs[RTE_MAX_ETHPORTS];
 	struct ipsec_ctx inbound;
 	struct ipsec_ctx outbound;
-	struct rt_ctx *rt_ctx;
+	struct rt_ctx *rt4_ctx;
+	struct rt_ctx *rt6_ctx;
 } __rte_cache_aligned;
 
 static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
@@ -230,27 +233,39 @@ struct traffic_type {
 };
 
 struct ipsec_traffic {
-	struct traffic_type ipsec4;
-	struct traffic_type ipv4;
+	struct traffic_type ipsec;
+	struct traffic_type ip4;
+	struct traffic_type ip6;
 };
 
 static inline void
 prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 {
 	uint8_t *nlp;
+	struct ether_hdr *eth;
 
-	if (RTE_ETH_IS_IPV4_HDR(pkt->packet_type)) {
-		rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
-		nlp = rte_pktmbuf_mtod_offset(pkt, uint8_t *,
-				offsetof(struct ip, ip_p));
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip, ip_p));
 		if (*nlp == IPPROTO_ESP)
-			t->ipsec4.pkts[(t->ipsec4.num)++] = pkt;
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
 		else {
-			t->ipv4.data[t->ipv4.num] = nlp;
-			t->ipv4.pkts[(t->ipv4.num)++] = pkt;
+			t->ip4.data[t->ip4.num] = nlp;
+			t->ip4.pkts[(t->ip4.num)++] = pkt;
+		}
+	} else if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip6_hdr, ip6_nxt));
+		if (*nlp == IPPROTO_ESP)
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
+		else {
+			t->ip6.data[t->ip6.num] = nlp;
+			t->ip6.pkts[(t->ip6.num)++] = pkt;
 		}
 	} else {
 		/* Unknown/Unsupported type, drop the packet */
+		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
 		rte_pktmbuf_free(pkt);
 	}
 }
@@ -261,8 +276,9 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 {
 	int32_t i;
 
-	t->ipsec4.num = 0;
-	t->ipv4.num = 0;
+	t->ipsec.num = 0;
+	t->ip4.num = 0;
+	t->ip6.num = 0;
 
 	for (i = 0; i < (nb_pkts - PREFETCH_OFFSET); i++) {
 		rte_prefetch0(rte_pktmbuf_mtod(pkts[i + PREFETCH_OFFSET],
@@ -277,14 +293,27 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 static inline void
 prepare_tx_pkt(struct rte_mbuf *pkt, uint8_t port)
 {
-	pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
-	pkt->l3_len = sizeof(struct ip);
-	pkt->l2_len = ETHER_HDR_LEN;
+	struct ip *ip;
+	struct ether_hdr *ethhdr;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+
+	ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt, ETHER_HDR_LEN);
 
-	struct ether_hdr *ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt,
-			ETHER_HDR_LEN);
+	if (ip->ip_v == IPVERSION) {
+		pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
+		pkt->l3_len = sizeof(struct ip);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	} else {
+		pkt->ol_flags |= PKT_TX_IPV6;
+		pkt->l3_len = sizeof(struct ip6_hdr);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	}
 
-	ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
 	memcpy(&ethhdr->s_addr, &ethaddr_tbl[port].src,
 			sizeof(struct ether_addr));
 	memcpy(&ethhdr->d_addr, &ethaddr_tbl[port].dst,
@@ -355,94 +384,133 @@ send_single_packet(struct rte_mbuf *m, uint8_t port)
 }
 
 static inline void
-process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
-		struct ipsec_traffic *traffic)
+inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_in, i, j;
-	uint32_t sa_idx, res;
-
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	uint32_t i, j, res, sa_idx;
 
-	/* SP/ACL Inbound check ipsec and ipv4 */
-	for (i = 0; i < nb_pkts_in; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
-		traffic->ipv4.data[idx] = rte_pktmbuf_mtod_offset(m,
-				uint8_t *, offsetof(struct ip, ip_p));
-	}
+	if (ip->num == 0)
+		return;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num - nb_pkts_in; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		if (res & ~BYPASS) {
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		res = ip->res[i];
+		if (res & DISCARD) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
-	}
-	/* Check return SA SPI matches pkt SPI */
-	for ( ; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		sa_idx = traffic->ipv4.res[i] & PROTECT_MASK;
-		if (sa_idx == 0 || !inbound_sa_check(ipsec_ctx->sa_ctx,
-					m, sa_idx)) {
+		if (res & BYPASS) {
+			ip->pkts[j++] = m;
+			continue;
+		}
+		/* Check return SA SPI matches pkt SPI */
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
+		ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
 }
 
 static inline void
-process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_out, i, j;
-	uint32_t sa_idx, res;
+	uint16_t idx, nb_pkts_in, i;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
 
-	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	/* SP/ACL Inbound check ipsec and ip4 */
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+			traffic->ip4.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *, offsetof(struct ip, ip_p));
+		} else if (ip->ip_v == IP6_VERSION) {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+			traffic->ip6.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *,
+					offsetof(struct ip6_hdr, ip6_nxt));
+		} else
+			rte_pktmbuf_free(m);
+	}
+
+	inbound_sp_sa(ipsec_ctx->sp4_ctx, ipsec_ctx->sa_ctx, &traffic->ip4);
+
+	inbound_sp_sa(ipsec_ctx->sp6_ctx, ipsec_ctx->sa_ctx, &traffic->ip6);
+}
+
+static inline void
+outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
+		struct traffic_type *ipsec)
+{
+	struct rte_mbuf *m;
+	uint32_t i, j, sa_idx;
+
+	if (ip->num == 0)
+		return;
 
-	traffic->ipsec4.num = 0;
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		sa_idx = res & PROTECT_MASK;
-		if ((res == 0) || (res & DISCARD))
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if ((ip->res[i] == 0) || (ip->res[i] & DISCARD))
 			rte_pktmbuf_free(m);
 		else if (sa_idx != 0) {
-			traffic->ipsec4.res[traffic->ipsec4.num] = sa_idx;
-			traffic->ipsec4.pkts[traffic->ipsec4.num++] = m;
+			ipsec->res[ipsec->num] = sa_idx;
+			ipsec->pkts[ipsec->num++] = m;
 		} else /* BYPASS */
-			traffic->ipv4.pkts[j++] = m;
+			ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
+}
+
+static inline void
+process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+		struct ipsec_traffic *traffic)
+{
+	struct rte_mbuf *m;
+	uint16_t idx, nb_pkts_out, i;
+
+	/* Drop any IPsec traffic from protected ports */
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.res, traffic->ipsec4.num,
+	traffic->ipsec.num = 0;
+
+	outbound_sp(ipsec_ctx->sp4_ctx, &traffic->ip4, &traffic->ipsec);
+
+	outbound_sp(ipsec_ctx->sp6_ctx, &traffic->ip6, &traffic->ipsec);
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.res, traffic->ipsec.num,
 			MAX_PKT_BURST);
 
 	for (i = 0; i < nb_pkts_out; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
 	}
 }
 
@@ -450,47 +518,72 @@ static inline void
 process_pkts_inbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_in, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_in, i, idx;
 
 	/* Drop any IPv4 traffic from unprotected ports */
-	for (i = 0; i < traffic->ipv4.num; i++)
-		rte_pktmbuf_free(traffic->ipv4.pkts[i]);
+	for (i = 0; i < traffic->ip4.num; i++)
+		rte_pktmbuf_free(traffic->ip4.pkts[i]);
 
-	traffic->ipv4.num = 0;
+	traffic->ip4.num = 0;
 
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	/* Drop any IPv6 traffic from unprotected ports */
+	for (i = 0; i < traffic->ip6.num; i++)
+		rte_pktmbuf_free(traffic->ip6.pkts[i]);
 
-	for (i = 0; i < nb_pkts_in; i++)
-		traffic->ipv4.pkts[i] = traffic->ipsec4.pkts[i];
+	traffic->ip6.num = 0;
 
-	traffic->ipv4.num = nb_pkts_in;
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
+
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
+	}
 }
 
 static inline void
 process_pkts_outbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_out, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_out, i;
+	struct ip *ip;
 
 	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	traffic->ipsec4.num = 0;
+	traffic->ipsec.num = 0;
 
-	for (i = 0; i < traffic->ipv4.num; i++)
-		traffic->ipv4.res[i] = single_sa_idx;
+	for (i = 0; i < traffic->ip4.num; i++)
+		traffic->ip4.res[i] = single_sa_idx;
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipv4.pkts,
-			traffic->ipv4.res, traffic->ipv4.num,
+	for (i = 0; i < traffic->ip6.num; i++)
+		traffic->ip6.res[i] = single_sa_idx;
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ip4.pkts,
+			traffic->ip4.res, traffic->ip4.num,
 			MAX_PKT_BURST);
 
-	traffic->ipv4.num = nb_pkts_out;
+	/* They all sue the same SA (ip4 or ip6 tunnel) */
+	m = traffic->ipsec.pkts[i];
+	ip = rte_pktmbuf_mtod(m, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		traffic->ip4.num = nb_pkts_out;
+	else
+		traffic->ip6.num = nb_pkts_out;
 }
 
 static inline void
-route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+route4_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 {
 	uint32_t hop[MAX_PKT_BURST * 2];
 	uint32_t dst_ip[MAX_PKT_BURST * 2];
@@ -518,6 +611,35 @@ route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 }
 
 static inline void
+route6_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+{
+	int16_t hop[MAX_PKT_BURST * 2];
+	uint8_t dst_ip[MAX_PKT_BURST * 2][16];
+	uint8_t *ip6_dst;
+	uint16_t i, offset;
+
+	if (nb_pkts == 0)
+		return;
+
+	for (i = 0; i < nb_pkts; i++) {
+		offset = offsetof(struct ip6_hdr, ip6_dst);
+		ip6_dst = rte_pktmbuf_mtod_offset(pkts[i], uint8_t *, offset);
+		memcpy(&dst_ip[i][0], ip6_dst, 16);
+	}
+
+	rte_lpm6_lookup_bulk_func((struct rte_lpm6 *)rt_ctx, dst_ip,
+			hop, nb_pkts);
+
+	for (i = 0; i < nb_pkts; i++) {
+		if (hop[i] == -1) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+		send_single_packet(pkts[i], hop[i] & 0xff);
+	}
+}
+
+static inline void
 process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 		uint8_t nb_pkts, uint8_t portid)
 {
@@ -525,7 +647,7 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 
 	prepare_traffic(pkts, &traffic, nb_pkts);
 
-	if (single_sa) {
+	if (unlikely(single_sa)) {
 		if (UNPROTECTED_PORT(portid))
 			process_pkts_inbound_nosp(&qconf->inbound, &traffic);
 		else
@@ -537,7 +659,8 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 			process_pkts_outbound(&qconf->outbound, &traffic);
 	}
 
-	route_pkts(qconf->rt_ctx, traffic.ipv4.pkts, traffic.ipv4.num);
+	route4_pkts(qconf->rt4_ctx, traffic.ip4.pkts, traffic.ip4.num);
+	route6_pkts(qconf->rt6_ctx, traffic.ip6.pkts, traffic.ip6.num);
 }
 
 static inline void
@@ -576,12 +699,15 @@ main_loop(__attribute__((unused)) void *dummy)
 	rxql = qconf->rx_queue_list;
 	socket_id = rte_lcore_to_socket_id(lcore_id);
 
-	qconf->rt_ctx = socket_ctx[socket_id].rt_ipv4;
-	qconf->inbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_in;
-	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_in;
+	qconf->rt4_ctx = socket_ctx[socket_id].rt_ip4;
+	qconf->rt6_ctx = socket_ctx[socket_id].rt_ip6;
+	qconf->inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
+	qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
+	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
 	qconf->inbound.cdev_map = cdev_map_in;
-	qconf->outbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_out;
-	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_out;
+	qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
+	qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
+	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
 	qconf->outbound.cdev_map = cdev_map_out;
 
 	if (qconf->nb_rx_queue == 0) {
@@ -762,7 +888,7 @@ parse_config(const char *q_arg)
 		FLD_LCORE,
 		_NUM_FLD
 	};
-	int long int_fld[_NUM_FLD];
+	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
 	int32_t i;
 	uint32_t size;
@@ -1313,7 +1439,9 @@ main(int32_t argc, char **argv)
 
 		sa_init(&socket_ctx[socket_id], socket_id, ep);
 
-		sp_init(&socket_ctx[socket_id], socket_id, ep);
+		sp4_init(&socket_ctx[socket_id], socket_id, ep);
+
+		sp6_init(&socket_ctx[socket_id], socket_id, ep);
 
 		rt_init(&socket_ctx[socket_id], socket_id, ep);
 
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 53af875..28b7c0f 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -66,7 +66,8 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 	}
 
 	IPSEC_LOG(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
-			"%u qp %u\n", sa->spi, ipsec_ctx->tbl[cdev_id_qp].id,
+			"%u qp %u\n", sa->spi,
+			ipsec_ctx->tbl[cdev_id_qp].id,
 			ipsec_ctx->tbl[cdev_id_qp].qp);
 
 	sa->crypto_session = rte_cryptodev_sym_session_create(
@@ -80,7 +81,7 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 static inline void
 enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 {
-	int ret, i;
+	int32_t ret, i;
 
 	cqp->buf[cqp->len++] = cop;
 
@@ -105,7 +106,7 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
 		uint16_t nb_pkts)
 {
-	int ret = 0, i;
+	int32_t ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
 	struct ipsec_sa *sa;
 
@@ -151,7 +152,7 @@ static inline int
 ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], uint16_t max_pkts)
 {
-	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
 	struct ipsec_mbuf_metadata *priv;
 	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 2cf9ea6..d4701fd 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 #include <stdint.h>
 
 #include <rte_byteorder.h>
-#include <rte_ip.h>
 #include <rte_crypto.h>
 
 #define RTE_LOGTYPE_IPSEC       RTE_LOGTYPE_USER1
@@ -62,15 +61,15 @@ if (!(exp)) {                                                        \
 #define MAX_DIGEST_SIZE 32 /* Bytes -- 256 bits */
 
 #define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (unsigned char)(ip >> 24 & 0xff);\
-		*b = (unsigned char)(ip >> 16 & 0xff);\
-		*c = (unsigned char)(ip >> 8 & 0xff);\
-		*d = (unsigned char)(ip & 0xff);\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
 	} while (0)
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (64) /* must be power of 2, max 2 power 30 */
+#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)
 
@@ -81,6 +80,8 @@ if (!(exp)) {                                                        \
 
 #define IPSEC_XFORM_MAX 2
 
+#define IP6_VERSION (6)
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_cryptodev_session;
@@ -88,23 +89,35 @@ struct rte_mbuf;
 
 struct ipsec_sa;
 
-typedef int (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
+typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
+struct ip_addr {
+	union {
+		uint32_t ip4;
+		union {
+			uint64_t ip6[2];
+			uint8_t ip6_b[16];
+		};
+	};
+};
+
 struct ipsec_sa {
 	uint32_t spi;
 	uint32_t cdev_id_qp;
-	uint32_t src;
-	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
-	struct rte_crypto_sym_xform *xforms;
+	uint32_t seq;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
 	uint16_t iv_len;
 	uint16_t block_size;
 	uint16_t flags;
-	uint32_t seq;
+#define IP4_TUNNEL (1 << 0)
+#define IP6_TUNNEL (1 << 1)
+	struct ip_addr src;
+	struct ip_addr dst;
+	struct rte_crypto_sym_xform *xforms;
 } __rte_cache_aligned;
 
 struct ipsec_mbuf_metadata {
@@ -123,7 +136,8 @@ struct cdev_qp {
 
 struct ipsec_ctx {
 	struct rte_hash *cdev_map;
-	struct sp_ctx *sp_ctx;
+	struct sp_ctx *sp4_ctx;
+	struct sp_ctx *sp6_ctx;
 	struct sa_ctx *sa_ctx;
 	uint16_t nb_qps;
 	uint16_t last_qp;
@@ -137,11 +151,14 @@ struct cdev_key {
 };
 
 struct socket_ctx {
-	struct sa_ctx *sa_ipv4_in;
-	struct sa_ctx *sa_ipv4_out;
-	struct sp_ctx *sp_ipv4_in;
-	struct sp_ctx *sp_ipv4_out;
-	struct rt_ctx *rt_ipv4;
+	struct sa_ctx *sa_in;
+	struct sa_ctx *sa_out;
+	struct sp_ctx *sp_ip4_in;
+	struct sp_ctx *sp_ip4_out;
+	struct sp_ctx *sp_ip6_in;
+	struct sp_ctx *sp_ip6_out;
+	struct rt_ctx *rt_ip4;
+	struct rt_ctx *rt_ip6;
 	struct rte_mempool *mbuf_pool;
 };
 
@@ -177,12 +194,15 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts);
 
 void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index a6d0866..d46df49 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -36,110 +36,205 @@
  */
 #include <sys/types.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 
-#define RT_IPV4_MAX_RULES         64
+#define RT_IPV4_MAX_RULES	1024
+#define RT_IPV6_MAX_RULES	1024
 
-struct ipv4_route {
+struct ip4_route {
 	uint32_t ip;
-	uint8_t  depth;
-	uint8_t  if_out;
+	uint8_t depth;
+	uint8_t if_out;
 };
 
-/* In the default routing table we have:
- * ep0 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep0[] = {
+struct ip6_route {
+	uint8_t ip[16];
+	uint8_t depth;
+	uint8_t if_out;
+};
+
+static struct ip4_route rt_ip4_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
-	{ IPv4(172, 16, 2, 6), 32, 0 },
-	{ IPv4(172, 16, 2, 7), 32, 1 },
-	{ IPv4(172, 16, 2, 8), 32, 1 },
+	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 240, 0), 24, 0 },
+	{ IPv4(192, 168, 241, 0), 24, 1 },
 
+	/* Inbound */
+	/* Tunnels */
 	{ IPv4(192, 168, 115, 0), 24, 2 },
-	{ IPv4(192, 168, 116, 0), 24, 2 },
-	{ IPv4(192, 168, 117, 0), 24, 3 },
-	{ IPv4(192, 168, 118, 0), 24, 3 },
-
+	{ IPv4(192, 168, 116, 0), 24, 3 },
+	{ IPv4(192, 168, 65, 0), 24, 2 },
+	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
-
-	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 211, 0), 24, 3 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 2 },
+	{ IPv4(192, 168, 246, 0), 24, 3 },
 };
 
-/* In the default routing table we have:
- * ep1 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep1[] = {
-	{ IPv4(172, 16, 1, 5), 32, 2 },
-	{ IPv4(172, 16, 1, 6), 32, 2 },
-	{ IPv4(172, 16, 1, 7), 32, 3 },
-	{ IPv4(172, 16, 1, 8), 32, 3 },
-
-	{ IPv4(192, 168, 105, 0), 24, 0 },
-	{ IPv4(192, 168, 106, 0), 24, 0 },
-	{ IPv4(192, 168, 107, 0), 24, 1 },
-	{ IPv4(192, 168, 108, 0), 24, 1 },
-
-	{ IPv4(192, 168, 200, 0), 24, 0 },
+static struct ip6_route rt_ip6_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Inbound */
+	/* Tunnels */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+};
 
+static struct ip4_route rt_ip4_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ IPv4(172, 16, 1, 5), 32, 0 },
+	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 0 },
+	{ IPv4(192, 168, 246, 0), 24, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ IPv4(192, 168, 105, 0), 24, 2 },
+	{ IPv4(192, 168, 106, 0), 24, 3 },
+	{ IPv4(192, 168, 55, 0), 24, 2 },
+	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* NULL */
+	{ IPv4(192, 168, 200, 0), 24, 2 },
+	{ IPv4(192, 168, 201, 0), 24, 3 },
+	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 241, 0), 24, 3 },
+};
+
+static struct ip6_route rt_ip6_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	char name[PATH_MAX];
-	unsigned i;
-	int ret;
+	uint32_t i;
+	int32_t ret;
 	struct rte_lpm *lpm;
-	struct ipv4_route *rt;
+	struct rte_lpm6 *lpm6;
+	struct ip4_route *rt;
+	struct ip6_route *rt6;
 	char a, b, c, d;
-	unsigned nb_routes;
+	uint32_t nb_routes, nb_routes6;
 	struct rte_lpm_config conf = { 0 };
+	struct rte_lpm6_config conf6 = { 0 };
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->rt_ipv4 != NULL)
-		rte_exit(EXIT_FAILURE, "Routing Table for socket %u already "
-			"initialized\n", socket_id);
+	if (ctx->rt_ip4 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv4 Routing Table for socket %u "
+			"already initialized\n", socket_id);
 
-	printf("Creating Routing Table (RT) context with %u max routes\n",
+	if (ctx->rt_ip6 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u "
+			"already initialized\n", socket_id);
+
+	printf("Creating IPv4 Routing Table (RT) context with %u max routes\n",
 			RT_IPV4_MAX_RULES);
 
 	if (ep == 0) {
-		rt = rt_ipv4_ep0;
-		nb_routes = RTE_DIM(rt_ipv4_ep0);
+		rt = rt_ip4_ep0;
+		nb_routes = RTE_DIM(rt_ip4_ep0);
+		rt6 = rt_ip6_ep0;
+		nb_routes6 = RTE_DIM(rt_ip6_ep0);
 	} else if (ep == 1) {
-		rt = rt_ipv4_ep1;
-		nb_routes = RTE_DIM(rt_ipv4_ep1);
+		rt = rt_ip4_ep1;
+		nb_routes = RTE_DIM(rt_ip4_ep1);
+		rt6 = rt_ip6_ep1;
+		nb_routes6 = RTE_DIM(rt_ip6_ep1);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. Only 0 or 1 "
 			"supported.\n", ep);
 
 	/* create the LPM table */
-	snprintf(name, sizeof(name), "%s_%u", "rt_ipv4", socket_id);
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip4", socket_id);
 	conf.max_rules = RT_IPV4_MAX_RULES;
 	conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
 	lpm = rte_lpm_create(name, socket_id, &conf);
 	if (lpm == NULL)
-		rte_exit(EXIT_FAILURE, "Unable to create LPM table "
-			"on socket %d\n", socket_id);
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
 
 	/* populate the LPM table */
 	for (i = 0; i < nb_routes; i++) {
 		ret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out);
 		if (ret < 0)
-			rte_exit(EXIT_FAILURE, "Unable to add entry num %u to "
-				"LPM table on socket %d\n", i, socket_id);
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
 
 		uint32_t_to_char(rt[i].ip, &a, &b, &c, &d);
 		printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n",
 				a, b, c, d, rt[i].depth, rt[i].if_out);
 	}
 
-	ctx->rt_ipv4 = (struct rt_ctx *)lpm;
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id);
+	conf6.max_rules = RT_IPV6_MAX_RULES;
+	conf6.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
+	lpm6 = rte_lpm6_create(name, socket_id, &conf6);
+	if (lpm6 == NULL)
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
+
+	/* populate the LPM table */
+	for (i = 0; i < nb_routes6; i++) {
+		ret = rte_lpm6_add(lpm6, rt6[i].ip, rt6[i].depth,
+				rt6[i].if_out);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
+
+		printf("LPM6: Adding route "
+			" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n",
+			(uint16_t)((rt6[i].ip[0] << 8) | rt6[i].ip[1]),
+			(uint16_t)((rt6[i].ip[2] << 8) | rt6[i].ip[3]),
+			(uint16_t)((rt6[i].ip[4] << 8) | rt6[i].ip[5]),
+			(uint16_t)((rt6[i].ip[6] << 8) | rt6[i].ip[7]),
+			(uint16_t)((rt6[i].ip[8] << 8) | rt6[i].ip[9]),
+			(uint16_t)((rt6[i].ip[10] << 8) | rt6[i].ip[11]),
+			(uint16_t)((rt6[i].ip[12] << 8) | rt6[i].ip[13]),
+			(uint16_t)((rt6[i].ip[14] << 8) | rt6[i].ip[15]),
+			rt6[i].depth, rt6[i].if_out);
+	}
+
+	ctx->rt_ip4 = (struct rt_ctx *)lpm;
+	ctx->rt_ip6 = (struct rt_ctx *)lpm6;
 }
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a193bdf..8b54beb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -37,12 +37,14 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_memzone.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_byteorder.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -51,108 +53,148 @@
 const struct ipsec_sa sa_out[] = {
 	{
 	.spi = 5,
-	.src = IPv4(172, 16, 1, 5),
-	.dst = IPv4(172, 16, 2, 5),
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
 	.spi = 6,
-	.src = IPv4(172, 16, 1, 6),
-	.dst = IPv4(172, 16, 2, 6),
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 7,
-	.src = IPv4(172, 16, 1, 7),
-	.dst = IPv4(172, 16, 2, 7),
+	.spi = 15,
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 16,
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 25,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 8,
-	.src = IPv4(172, 16, 1, 8),
-	.dst = IPv4(172, 16, 2, 8),
+	.spi = 26,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 9,
-	.src = IPv4(172, 16, 1, 9),
-	.dst = IPv4(172, 16, 2, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 /* SAs Inbound */
 const struct ipsec_sa sa_in[] = {
 	{
-	.spi = 55,
-	.src = IPv4(172, 16, 2, 5),
-	.dst = IPv4(172, 16, 1, 5),
+	.spi = 105,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 56,
-	.src = IPv4(172, 16, 2, 6),
-	.dst = IPv4(172, 16, 1, 6),
+	.spi = 106,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 115,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 57,
-	.src = IPv4(172, 16, 2, 7),
-	.dst = IPv4(172, 16, 1, 7),
+	.spi = 116,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 125,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 58,
-	.src = IPv4(172, 16, 2, 8),
-	.dst = IPv4(172, 16, 1, 8),
+	.spi = 126,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 59,
-	.src = IPv4(172, 16, 2, 9),
-	.dst = IPv4(172, 16, 1, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -217,11 +259,11 @@ struct sa_ctx {
 };
 
 static struct sa_ctx *
-sa_ipv4_create(const char *name, int socket_id)
+sa_create(const char *name, int32_t socket_id)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
-	unsigned mz_size;
+	uint32_t mz_size;
 	const struct rte_memzone *mz;
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
@@ -246,10 +288,10 @@ sa_ipv4_create(const char *name, int socket_id)
 
 static int
 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries, unsigned inbound)
+		uint32_t nb_entries, uint32_t inbound)
 {
 	struct ipsec_sa *sa;
-	unsigned i, idx;
+	uint32_t i, idx;
 
 	for (i = 0; i < nb_entries; i++) {
 		idx = SPI2IDX(entries[i].spi);
@@ -260,8 +302,14 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
-		sa->src = rte_cpu_to_be_32(sa->src);
-		sa->dst = rte_cpu_to_be_32(sa->dst);
+		sa->seq = 0;
+
+		switch (sa->flags) {
+		case IP4_TUNNEL:
+			sa->src.ip4 = rte_cpu_to_be_32(sa->src.ip4);
+			sa->dst.ip4 = rte_cpu_to_be_32(sa->dst.ip4);
+		}
+
 		if (inbound) {
 			if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
 				sa_ctx->xf[idx].a = null_auth_xf;
@@ -289,33 +337,33 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 
 static inline int
 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 0);
 }
 
 static inline int
 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 1);
 }
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	const struct ipsec_sa *sa_out_entries, *sa_in_entries;
-	unsigned nb_out_entries, nb_in_entries;
+	uint32_t nb_out_entries, nb_in_entries;
 	const char *name;
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->sa_ipv4_in != NULL)
+	if (ctx->sa_in != NULL)
 		rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (ctx->sa_ipv4_out != NULL)
+	if (ctx->sa_out != NULL)
 		rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
@@ -333,21 +381,21 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
 
-	name = "sa_ipv4_in";
-	ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_in == NULL)
+	name = "sa_in";
+	ctx->sa_in = sa_create(name, socket_id);
+	if (ctx->sa_in == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	name = "sa_ipv4_out";
-	ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_out == NULL)
+	name = "sa_out";
+	ctx->sa_out = sa_create(name, socket_id);
+	if (ctx->sa_out == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
+	sa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);
 
-	sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
+	sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
 }
 
 int
@@ -360,38 +408,63 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
 }
 
+static inline void
+single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
+		struct ipsec_sa **sa_ret)
+{
+	struct esp_hdr *esp;
+	struct ip *ip;
+	uint32_t *src4_addr;
+	uint8_t *src6_addr;
+	struct ipsec_sa *sa;
+
+	*sa_ret = NULL;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		esp = (struct esp_hdr *)(ip + 1);
+	else
+		esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
+
+	if (esp->spi == INVALID_SPI)
+		return;
+
+	sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
+	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
+		return;
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
+		if ((ip->ip_v == IPVERSION) &&
+				(sa->src.ip4 == *src4_addr) &&
+				(sa->dst.ip4 == *(src4_addr + 1)))
+			*sa_ret = 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.ip6, src6_addr, 16) &&
+				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
+			*sa_ret = sa;
+	}
+}
+
 void
 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
-	uint32_t *src, spi;
-
-	for (i = 0; i < nb_pkts; i++) {
-		spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
-				sizeof(struct ip))->spi;
+	uint32_t i;
 
-		if (spi == INVALID_SPI)
-			continue;
-
-		sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
-		if (spi != sa[i]->spi) {
-			sa[i] = NULL;
-			continue;
-		}
-
-		src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
-				offsetof(struct ip, ip_src));
-		if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
-			sa[i] = NULL;
-	}
+	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[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
+	uint32_t i;
 
 	for (i = 0; i < nb_pkts; i++)
 		sa[i] = &sa_ctx->sa[sa_idx[i]];
diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
deleted file mode 100644
index 6aa377d..0000000
--- a/examples/ipsec-secgw/sp.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Security Policies
- */
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-
-#include <rte_acl.h>
-
-#include "ipsec.h"
-
-#define MAX_ACL_RULE_NUM	1000
-
-/*
- * Rule and trace formats definitions.
- */
-enum {
-	PROTO_FIELD_IPV4,
-	SRC_FIELD_IPV4,
-	DST_FIELD_IPV4,
-	SRCP_FIELD_IPV4,
-	DSTP_FIELD_IPV4,
-	NUM_FIELDS_IPV4
-};
-
-/*
- * That effectively defines order of IPV4 classifications:
- *  - PROTO
- *  - SRC IP ADDRESS
- *  - DST IP ADDRESS
- *  - PORTS (SRC and DST)
- */
-enum {
-	RTE_ACL_IPV4_PROTO,
-	RTE_ACL_IPV4_SRC,
-	RTE_ACL_IPV4_DST,
-	RTE_ACL_IPV4_PORTS,
-	RTE_ACL_IPV4_NUM
-};
-
-struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
-	{
-	.type = RTE_ACL_FIELD_TYPE_BITMASK,
-	.size = sizeof(uint8_t),
-	.field_index = PROTO_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PROTO,
-	.offset = 0,
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = SRC_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_SRC,
-	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = DST_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_DST,
-	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = SRCP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = DSTP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
-		sizeof(uint16_t)
-	},
-};
-
-RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
-
-const struct acl4_rules acl4_rules_out[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 107, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 108, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 250, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-const struct acl4_rules acl4_rules_in[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 117, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 118, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-static void
-print_one_ipv4_rule(const struct acl4_rules *rule, int extra)
-{
-	unsigned char a, b, c, d;
-
-	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[SRC_FIELD_IPV4].mask_range.u32);
-	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[DST_FIELD_IPV4].mask_range.u32);
-	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
-		rule->field[SRCP_FIELD_IPV4].value.u16,
-		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
-		rule->field[DSTP_FIELD_IPV4].value.u16,
-		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
-		rule->field[PROTO_FIELD_IPV4].value.u8,
-		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
-	if (extra)
-		printf("0x%x-0x%x-0x%x ",
-			rule->data.category_mask,
-			rule->data.priority,
-			rule->data.userdata);
-}
-
-static inline void
-dump_ipv4_rules(const struct acl4_rules *rule, int num, int extra)
-{
-	int i;
-
-	for (i = 0; i < num; i++, rule++) {
-		printf("\t%d:", i + 1);
-		print_one_ipv4_rule(rule, extra);
-		printf("\n");
-	}
-}
-
-static struct rte_acl_ctx *
-acl4_init(const char *name, int socketid, const struct acl4_rules *rules,
-		unsigned rules_nb)
-{
-	char s[PATH_MAX];
-	struct rte_acl_param acl_param;
-	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);
-
-	memset(&acl_param, 0, sizeof(acl_param));
-
-	/* Create ACL contexts */
-	snprintf(s, sizeof(s), "%s_%d", name, socketid);
-
-	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
-	dump_ipv4_rules(rules, rules_nb, 1);
-
-	acl_param.name = s;
-	acl_param.socket_id = socketid;
-	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ipv4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
-
-	ctx = rte_acl_create(&acl_param);
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
-
-	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
-				rules_nb) < 0)
-		rte_exit(EXIT_FAILURE, "add rules failed\n");
-
-	/* Perform builds */
-	memset(&acl_build_param, 0, sizeof(acl_build_param));
-
-	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
-	acl_build_param.num_fields = RTE_DIM(ipv4_defs);
-	memcpy(&acl_build_param.defs, ipv4_defs, sizeof(ipv4_defs));
-
-	if (rte_acl_build(ctx, &acl_build_param) != 0)
-		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
-
-	rte_acl_dump(ctx);
-
-	return ctx;
-}
-
-void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
-{
-	const char *name;
-	const struct acl4_rules *rules_out, *rules_in;
-	unsigned nb_out_rules, nb_in_rules;
-
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "NULL context.\n");
-
-	if (ctx->sp_ipv4_in != NULL)
-		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ctx->sp_ipv4_out != NULL)
-		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ep == 0) {
-		rules_out = acl4_rules_out;
-		nb_out_rules = RTE_DIM(acl4_rules_out);
-		rules_in = acl4_rules_in;
-		nb_in_rules = RTE_DIM(acl4_rules_in);
-	} else if (ep == 1) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else
-		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
-				"Only 0 or 1 supported.\n", ep);
-
-	name = "sp_ipv4_in";
-	ctx->sp_ipv4_in = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_in, nb_in_rules);
-
-	name = "sp_ipv4_out";
-	ctx->sp_ipv4_out = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_out, nb_out_rules);
-}
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
new file mode 100644
index 0000000..61720c8
--- /dev/null
+++ b/examples/ipsec-secgw/sp4.c
@@ -0,0 +1,407 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+/*
+ * Rule and trace formats definitions.
+ */
+enum {
+	PROTO_FIELD_IPV4,
+	SRC_FIELD_IPV4,
+	DST_FIELD_IPV4,
+	SRCP_FIELD_IPV4,
+	DSTP_FIELD_IPV4,
+	NUM_FIELDS_IPV4
+};
+
+/*
+ * That effectively defines order of IPV4 classifications:
+ *  - PROTO
+ *  - SRC IP ADDRESS
+ *  - DST IP ADDRESS
+ *  - PORTS (SRC and DST)
+ */
+enum {
+	RTE_ACL_IPV4_PROTO,
+	RTE_ACL_IPV4_SRC,
+	RTE_ACL_IPV4_DST,
+	RTE_ACL_IPV4_PORTS,
+	RTE_ACL_IPV4_NUM
+};
+
+struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = PROTO_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = SRC_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_SRC,
+	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = DST_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_DST,
+	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = SRCP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = DSTP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
+		sizeof(uint16_t)
+	},
+};
+
+RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
+
+const struct acl4_rules acl4_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 201, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 55, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 56, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 241, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl4_rules acl4_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(105), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(106), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(116), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 211, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 65, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 66, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 245, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 246, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static void
+print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[SRC_FIELD_IPV4].mask_range.u32);
+	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[DST_FIELD_IPV4].mask_range.u32);
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[SRCP_FIELD_IPV4].value.u16,
+		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
+		rule->field[DSTP_FIELD_IPV4].value.u16,
+		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
+		rule->field[PROTO_FIELD_IPV4].value.u8,
+		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip4_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip4_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip4_defs);
+	memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl4_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip4_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ctx->sp_ip4_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl4_rules_out;
+		nb_out_rules = RTE_DIM(acl4_rules_out);
+		rules_in = acl4_rules_in;
+		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip4_in";
+	ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip4_out";
+	ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
new file mode 100644
index 0000000..c6fb851
--- /dev/null
+++ b/examples/ipsec-secgw/sp6.c
@@ -0,0 +1,400 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+enum {
+	IP6_PROTO,
+	IP6_SRC0,
+	IP6_SRC1,
+	IP6_SRC2,
+	IP6_SRC3,
+	IP6_DST0,
+	IP6_DST1,
+	IP6_DST2,
+	IP6_DST3,
+	IP6_SRCP,
+	IP6_DSTP,
+	IP6_NUM
+};
+
+#define IP6_ADDR_SIZE 16
+
+struct rte_acl_field_def ip6_defs[IP6_NUM] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = IP6_PROTO,
+	.input_index = IP6_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC0,
+	.input_index = IP6_SRC0,
+	.offset = 2
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC1,
+	.input_index = IP6_SRC1,
+	.offset = 6
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC2,
+	.input_index = IP6_SRC2,
+	.offset = 10
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC3,
+	.input_index = IP6_SRC3,
+	.offset = 14
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST0,
+	.input_index = IP6_DST0,
+	.offset = 18
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST1,
+	.input_index = IP6_DST1,
+	.offset = 22
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST2,
+	.input_index = IP6_DST2,
+	.offset = 26
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST3,
+	.input_index = IP6_DST3,
+	.offset = 30
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_SRCP,
+	.input_index = IP6_SRCP,
+	.offset = 34
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_DSTP,
+	.input_index = IP6_SRCP,
+	.offset = 36
+	}
+};
+
+RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
+
+const struct acl6_rules acl6_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl6_rules acl6_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static inline void
+print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_SRC0].mask_range.u32
+			+ rule->field[IP6_SRC1].mask_range.u32
+			+ rule->field[IP6_SRC2].mask_range.u32
+			+ rule->field[IP6_SRC3].mask_range.u32);
+
+	uint32_t_to_char(rule->field[IP6_DST0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_DST0].mask_range.u32
+			+ rule->field[IP6_DST1].mask_range.u32
+			+ rule->field[IP6_DST2].mask_range.u32
+			+ rule->field[IP6_DST3].mask_range.u32);
+
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[IP6_SRCP].value.u16,
+		rule->field[IP6_SRCP].mask_range.u16,
+		rule->field[IP6_DSTP].value.u16,
+		rule->field[IP6_DSTP].mask_range.u16,
+		rule->field[IP6_PROTO].value.u8,
+		rule->field[IP6_PROTO].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip6_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip6_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip6_defs);
+	memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl6_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip6_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ctx->sp_ip6_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl6_rules_out;
+		nb_out_rules = RTE_DIM(acl6_rules_out);
+		rules_in = acl6_rules_in;
+		nb_in_rules = RTE_DIM(acl6_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl6_rules_in;
+		nb_out_rules = RTE_DIM(acl6_rules_in);
+		rules_in = acl6_rules_out;
+		nb_in_rules = RTE_DIM(acl6_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip6_in";
+	ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip6_out";
+	ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
-- 
2.5.5

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

* [dpdk-dev] [PATCH 8/9] examples/ipsec-secgw: transport mode support
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (6 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

IPSec transport mode support.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   | 121 ++++++++++++++++++++++++++++++-------------
 examples/ipsec-secgw/ipsec.h |   1 +
 examples/ipsec-secgw/rt.c    |  32 ++++++++++++
 examples/ipsec-secgw/sa.c    |  39 ++++++++++++++
 examples/ipsec-secgw/sp4.c   |  40 ++++++++++++++
 examples/ipsec-secgw/sp6.c   |  48 +++++++++++++++++
 6 files changed, 244 insertions(+), 37 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index ee541eb..7efac39 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -42,7 +42,6 @@
 #include <unistd.h>
 
 #include <rte_common.h>
-#include <rte_memcpy.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_random.h>
@@ -70,21 +69,24 @@ int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len, ip_hdr_len;
+	struct ip *ip4;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t payload_len, ip_hdr_len;
 
 	IPSEC_ASSERT(m != NULL);
 	IPSEC_ASSERT(sa != NULL);
 	IPSEC_ASSERT(cop != NULL);
 
-	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
-		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION))
+		ip_hdr_len = ip4->ip_hl * 4;
+	else if (ip4->ip_v == IP6_VERSION)
+		/* XXX No option headers supported */
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
+	else {
+		IPSEC_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
 	}
 
 	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
@@ -126,6 +128,8 @@ int
 esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
+	struct ip *ip4, *ip;
+	struct ip6_hdr *ip6;
 	uint8_t *nexthdr, *pad_len;
 	uint8_t *padding;
 	uint16_t i;
@@ -135,7 +139,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	IPSEC_ASSERT(cop != NULL);
 
 	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
-		IPSEC_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
+		IPSEC_LOG(ERR, IPSEC_ESP, "failed crypto op\n");
 		return -1;
 	}
 
@@ -146,7 +150,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
 		if (padding[i] != i + 1) {
-			IPSEC_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
+			IPSEC_LOG(ERR, IPSEC_ESP, "invalid padding\n");
 			return -EINVAL;
 		}
 	}
@@ -157,7 +161,23 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	if (unlikely(sa->flags == TRANSPORT)) {
+		ip = rte_pktmbuf_mtod(m, struct ip *);
+		ip4 = (struct ip *)rte_pktmbuf_adj(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		if (likely(ip->ip_v == IPVERSION)) {
+			memmove(ip4, ip, ip->ip_hl * 4);
+			ip4->ip_p = *nexthdr;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)ip4;
+			/* XXX No option headers supported */
+			memmove(ip6, ip, sizeof(struct ip6_hdr));
+			ip6->ip6_nxt = *nexthdr;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
+	} else
+		ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
 
 	return 0;
 }
@@ -166,32 +186,53 @@ int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 	struct ip *ip4;
 	struct ip6_hdr *ip6;
-	struct esp_hdr *esp;
-	int32_t i;
-	char *padding;
+	struct esp_hdr *esp = NULL;
+	uint8_t *padding, *new_ip, nlp;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t i;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 
 	IPSEC_ASSERT(m != NULL);
 	IPSEC_ASSERT(sa != NULL);
 	IPSEC_ASSERT(cop != NULL);
 
-	/* Payload length */
-	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) + 2,
-			sa->block_size);
-	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
-
 	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
+
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION)) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			ip_hdr_len = ip4->ip_hl * 4;
+			nlp = ip4->ip_p;
+		} else
+			nlp = IPPROTO_IPIP;
+	} else if (ip4->ip_v == IP6_VERSION) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			/* XXX No option headers supported */
+			ip_hdr_len = sizeof(struct ip6_hdr);
+			ip6 = (struct ip6_hdr *)ip4;
+			nlp = ip6->ip6_nxt;
+		} else
+			nlp = IPPROTO_IPV6;
+	} else {
+		IPSEC_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
+	}
+
+	/* Padded payload length */
+	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) -
+			ip_hdr_len + 2, sa->block_size);
+	pad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);
+
+	IPSEC_ASSERT(sa->flags == IP4_TUNNEL || sa->flags == IP6_TUNNEL ||
+			sa->flags == TRANSPORT);
+
+	if (likely(sa->flags == IP4_TUNNEL))
 		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	else if (sa->flags == IP6_TUNNEL)
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
-	}
 
 	/* Check maximum packet size */
 	if (unlikely(ip_hdr_len + sizeof(struct esp_hdr) + sa->iv_len +
@@ -200,7 +241,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	padding = (uint8_t *)rte_pktmbuf_append(m, pad_len + sa->digest_len);
 	if (unlikely(padding == NULL)) {
 		IPSEC_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
 		return -ENOSPC;
@@ -218,10 +259,20 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 				&sa->src, &sa->dst);
 		esp = (struct esp_hdr *)(ip6 + 1);
 		break;
-	default:
-		IPSEC_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
-				sa->flags);
-		return -EINVAL;
+	case TRANSPORT:
+		new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		memmove(new_ip, ip4, ip_hdr_len);
+		esp = (struct esp_hdr *)(new_ip + ip_hdr_len);
+		if (likely(ip4->ip_v == IPVERSION)) {
+			ip4 = (struct ip *)new_ip;
+			ip4->ip_p = IPPROTO_ESP;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)new_ip;
+			ip6->ip6_nxt = IPPROTO_ESP;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
 	}
 
 	sa->seq++;
@@ -235,11 +286,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
 	padding[pad_len - 2] = pad_len - 2;
-
-	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
-		padding[pad_len - 1] = IPPROTO_IPIP;
-	else
-		padding[pad_len - 1] = IPPROTO_IPV6;
+	padding[pad_len - 1] = nlp;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index d4701fd..e28f9de 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -115,6 +115,7 @@ struct ipsec_sa {
 	uint16_t flags;
 #define IP4_TUNNEL (1 << 0)
 #define IP6_TUNNEL (1 << 1)
+#define TRANSPORT  (1 << 2)
 	struct ip_addr src;
 	struct ip_addr dst;
 	struct rte_crypto_sym_xform *xforms;
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index d46df49..fa5f042 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -62,6 +62,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
 	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 0 },
+	{ IPv4(192, 168, 176, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 0 },
 	{ IPv4(192, 168, 241, 0), 24, 1 },
@@ -72,6 +75,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	{ IPv4(192, 168, 116, 0), 24, 3 },
 	{ IPv4(192, 168, 65, 0), 24, 2 },
 	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 2 },
+	{ IPv4(192, 168, 186, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
 	{ IPv4(192, 168, 211, 0), 24, 3 },
@@ -87,6 +93,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
 	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 	/* Inbound */
 	/* Tunnels */
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
@@ -97,6 +108,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 static struct ip4_route rt_ip4_ep1[] = {
@@ -104,6 +120,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 1, 5), 32, 0 },
 	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 0 },
+	{ IPv4(192, 168, 186, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 245, 0), 24, 0 },
 	{ IPv4(192, 168, 246, 0), 24, 1 },
@@ -114,6 +133,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	{ IPv4(192, 168, 106, 0), 24, 3 },
 	{ IPv4(192, 168, 55, 0), 24, 2 },
 	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 2 },
+	{ IPv4(192, 168, 176, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 200, 0), 24, 2 },
 	{ IPv4(192, 168, 201, 0), 24, 3 },
@@ -129,6 +151,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
 	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 
 	/* Inbound */
 	/* Tunnels */
@@ -140,6 +167,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8b54beb..ab18b81 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -74,6 +74,24 @@ const struct ipsec_sa sa_out[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 10,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 11,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 15,
 	.src.ip4 = IPv4(172, 16, 1, 5),
 	.dst.ip4 = IPv4(172, 16, 2, 5),
@@ -148,6 +166,24 @@ const struct ipsec_sa sa_in[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 110,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 111,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 115,
 	.src.ip4 = IPv4(172, 16, 2, 5),
 	.dst.ip4 = IPv4(172, 16, 1, 5),
@@ -447,6 +483,9 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 				!memcmp(&sa->src.ip6, src6_addr, 16) &&
 				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
 			*sa_ret = sa;
+		break;
+	case TRANSPORT:
+		*sa_ret = sa;
 	}
 }
 
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 61720c8..9c4b256 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -135,6 +135,26 @@ const struct acl4_rules acl4_rules_out[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 175, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 176, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
@@ -218,6 +238,26 @@ const struct acl4_rules acl4_rules_in[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 185, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 186, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index c6fb851..1dda11a 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -170,6 +170,30 @@ const struct acl6_rules acl6_rules_out[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
@@ -221,6 +245,30 @@ const struct acl6_rules acl6_rules_in[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
-- 
2.5.5

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

* [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (7 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
@ 2016-05-06 16:31 ` Sergio Gonzalez Monroy
  2016-05-10  9:21   ` Mcnamara, John
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-06 16:31 UTC (permalink / raw)
  To: dev

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 doc/guides/sample_app_ug/ipsec_secgw.rst | 583 ++++++++++++++++++++-----------
 1 file changed, 381 insertions(+), 202 deletions(-)

diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index c11c7e7..5dbee2e 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -76,10 +76,10 @@ Path for IPsec Outbound traffic:
 
 Constraints
 -----------
-*  IPv4 traffic
-*  ESP tunnel mode
-*  EAS-CBC, HMAC-SHA1 and NULL
-*  Each SA must be handle by a unique lcore (1 RX queue per port)
+*  No IPv6 options headers
+*  No AH mode
+*  Currently only EAS-CBC, HMAC-SHA1 and NULL
+*  Each SA must be handle by a unique lcore (*1 RX queue per port*)
 *  No chained mbufs
 
 Compiling the Application
@@ -108,6 +108,14 @@ To compile the application:
 
        make
 
+#. [Optional] Build the application for debugging:
+   This option adds some extra flags, disables compiler optimizations and
+   is verbose.
+
+   .. code-block:: console
+
+       make DEBUG=1
+
 Running the Application
 -----------------------
 
@@ -141,8 +149,9 @@ where,
 *   --ep1: configure the app as Endpoint 1.
 
 Either one of --ep0 or --ep1 *must* be specified.
-The main purpose of these options is two easily configure two systems
-back-to-back that would forward traffic through an IPsec tunnel.
+The main purpose of these options is to easily configure two systems
+back-to-back that would forward traffic through an IPsec tunnel (see
+:ref:`figure_ipsec_endpoints`).
 
 The mapping of lcores to port/queues is similar to other l3fwd applications.
 
@@ -196,7 +205,8 @@ Refer to the *DPDK Getting Started Guide* for general information on running
 applications and the Environment Abstraction Layer (EAL) options.
 
 The application would do a best effort to "map" crypto devices to cores, with
-hardware devices having priority.
+hardware devices having priority. Basically, hardware devices if present would
+be assign to a core before software ones.
 This means that if the application is using a single core and both hardware
 and software crypto devices are detected, hardware devices will be used.
 
@@ -221,6 +231,20 @@ The following sections provide some details on the default values used to
 initialize the SP, SA and Routing tables.
 Currently all the configuration is hard coded into the application.
 
+The following image illustrate a few of the concepts regarding IPSec, such
+as protected/unprotected and inbound/outbound traffic, from the point of
+view of two back-to-back endpoints:
+
+.. _figure_ipsec_endpoints:
+
+.. figure:: img/ipsec_endpoints.svg
+
+   IPSec Inbound/Outbound traffic
+
+Note that the above image only displays uniderectional traffic per port
+for illustration purposes.
+The application supports bidirectional traffic on all ports,
+
 Security Policy Initialization
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -228,107 +252,122 @@ As mention in the overview, the Security Policies are ACL rules.
 The application defines two ACLs, one each of Inbound and Outbound, and
 it replicates them per socket in use.
 
-Following are the default rules:
+Following are the default rules which show only the relevant information,
+assuming ANY value is valid for the fields not mentioned (src ip, proto,
+src/dst ports).
 
 Endpoint 0 Outbound Security Policies:
 
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
++-----------------------------------+------------+
+| **Dst**                           | **SA idx** |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.105.0/24                  | 5          |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.106.0/24                  | 6          |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.175.0/24                  | 10         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.176.0/24                  | 11         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.200.0/24                  | 15         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.201.0/24                  | 16         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.55.0/24                   | 25         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.56.0/24                   | 26         |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.240.0/24                  | BYPASS     |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.241.0/24                  | BYPASS     |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:0:0:5555:5555:0:0/96          | 5          |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:0:0:6666:6666:0:0/96          | 6          |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:1111:1111:0:0:0:0/96          | 10         |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:1111:1111:1111:1111:0:0/96    | 11         |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:0:0:aaaa:aaaa:0:0/96          | 25         |
+|                                   |            |
++-----------------------------------+------------+
+| 0:0:0:0:bbbb:bbbb:0:0/96          | 26         |
+|                                   |            |
++-----------------------------------+------------+
 
 Endpoint 0 Inbound Security Policies:
 
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Outbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Inbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
++-----------------------------------+------------+
+| **Dst**                           | **SA idx** |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.115.0/24                  | 105        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.116.0/24                  | 106        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.185.0/24                  | 110        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.186.0/24                  | 111        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.210.0/24                  | 115        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.211.0/24                  | 116        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.65.0/24                   | 125        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.66.0/24                   | 126        |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.245.0/24                  | BYPASS     |
+|                                   |            |
++-----------------------------------+------------+
+| 192.168.246.0/24                  | BYPASS     |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:0:0:5555:5555:0:0/96       | 105        |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:0:0:6666:6666:0:0/96       | 106        |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:1111:1111:0:0:0:0/96       | 110        |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:1111:1111:1111:1111:0:0/96 | 111        |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:0:0:aaaa:aaaa:0:0/96       | 125        |
+|                                   |            |
++-----------------------------------+------------+
+| ffff:0:0:0:bbbb:bbbb:0:0/96       | 126        |
+|                                   |            |
++-----------------------------------+------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
 
 
 Security Association Initialization
@@ -350,91 +389,81 @@ Following are the default values:
 
 Endpoint 0 Outbound Security Associations:
 
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
++---------+----------+------------+-----------+----------------+----------------+
+| **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 5       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 6       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 10      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 11      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 15      | Tunnel   | NULL       | NULL      | 172.16.1.5     | 172.16.2.5     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 16      | Tunnel   | NULL       | NULL      | 172.16.1.6     | 172.16.2.6     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 25      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:5555      | 2222:5555      |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 26      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:1111:     | 2222:2222:     |
+|         |          |            |           | 1111:6666      | 2222:6666      |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
 
 Endpoint 0 Inbound Security Associations:
 
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Outbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Inbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
++---------+----------+------------+-----------+----------------+----------------+
+| **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 105     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 106     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 110     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 111     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 115     | Tunnel   | NULL       | NULL      | 172.16.2.5     | 172.16.1.5     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 116     | Tunnel   | NULL       | NULL      | 172.16.2.6     | 172.16.1.6     |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 125     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:5555      | 1111:5555      |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+| 126     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:2222:     | 1111:1111:     |
+|         |          |            |           | 2222:6666      | 1111:6666      |
+|         |          |            |           |                |                |
++---------+----------+------------+-----------+----------------+----------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
+
 
 Routing Initialization
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -452,34 +481,109 @@ Endpoint 0 Routing Table:
 | 172.16.2.5/32    | 0        |
 |                  |          |
 +------------------+----------+
-| 172.16.2.6/32    | 0        |
+| 172.16.2.6/32    | 1        |
+|                  |          |
++------------------+----------+
+| 192.168.175.0/24 | 0        |
+|                  |          |
++------------------+----------+
+| 192.168.176.0/24 | 1        |
 |                  |          |
 +------------------+----------+
-| 172.16.2.7/32    | 1        |
+| 192.168.240.0/24 | 0        |
 |                  |          |
 +------------------+----------+
-| 172.16.2.8/32    | 1        |
+| 192.168.241.0/24 | 1        |
 |                  |          |
 +------------------+----------+
 | 192.168.115.0/24 | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.116.0/24 | 2        |
+| 192.168.116.0/24 | 3        |
+|                  |          |
++------------------+----------+
+| 192.168.65.0/24  | 2        |
+|                  |          |
++------------------+----------+
+| 192.168.66.0/24  | 3        |
 |                  |          |
 +------------------+----------+
-| 192.168.117.0/24 | 3        |
+| 192.168.185.0/24 | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.118.0/24 | 3        |
+| 192.168.186.0/24 | 3        |
 |                  |          |
 +------------------+----------+
 | 192.168.210.0/24 | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.240.0/24 | 2        |
+| 192.168.211.0/24 | 3        |
+|                  |          |
++------------------+----------+
+| 192.168.245.0/24 | 2        |
+|                  |          |
++------------------+----------+
+| 192.168.246.0/24 | 3        |
+|                  |          |
++------------------+----------+
+| 2222:2222:       | 0        |
+| 2222:2222:       |          |
+| 2222:2222:       |          |
+| 2222:5555/116    |          |
+|                  |          |
++------------------+----------+
+| 2222:2222:       | 1        |
+| 2222:2222:       |          |
+| 2222:2222:       |          |
+| 2222:6666/116    |          |
 |                  |          |
 +------------------+----------+
-| 192.168.250.0/24 | 0        |
+| 0000:0000:       | 0        |
+| 1111:1111:       |          |
+| 0000:0000:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 1        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 2        |
+| 0000:0000:       |          |
+| aaaa:aaaa:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 3        |
+| 0000:0000:       |          |
+| bbbb:bbbb:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 2        |
+| 0000:0000:       |          |
+| 5555:5555:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 3        |
+| 0000:0000:       |          |
+| 6666:6666:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 2        |
+| 1111:1111:       |          |
+| 0000:0000:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 3        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 0000:0000/116    |          |
 |                  |          |
 +------------------+----------+
 
@@ -489,36 +593,111 @@ Endpoint 1 Routing Table:
 | **Dst addr**     | **Port** |
 |                  |          |
 +------------------+----------+
-| 172.16.1.5/32    | 2        |
+| 172.16.1.5/32    | 0        |
+|                  |          |
++------------------+----------+
+| 172.16.1.6/32    | 1        |
+|                  |          |
++------------------+----------+
+| 192.168.185.0/24 | 0        |
 |                  |          |
 +------------------+----------+
-| 172.16.1.6/32    | 2        |
+| 192.168.186.0/24 | 1        |
 |                  |          |
 +------------------+----------+
-| 172.16.1.7/32    | 3        |
+| 192.168.245.0/24 | 0        |
 |                  |          |
 +------------------+----------+
-| 172.16.1.8/32    | 3        |
+| 192.168.246.0/24 | 1        |
 |                  |          |
 +------------------+----------+
-| 192.168.105.0/24 | 0        |
+| 192.168.105.0/24 | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.106.0/24 | 0        |
+| 192.168.106.0/24 | 3        |
 |                  |          |
 +------------------+----------+
-| 192.168.107.0/24 | 1        |
+| 192.168.55.0/24  | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.108.0/24 | 1        |
+| 192.168.56.0/24  | 3        |
 |                  |          |
 +------------------+----------+
-| 192.168.200.0/24 | 0        |
+| 192.168.175.0/24 | 2        |
+|                  |          |
++------------------+----------+
+| 192.168.176.0/24 | 3        |
+|                  |          |
++------------------+----------+
+| 192.168.200.0/24 | 2        |
+|                  |          |
++------------------+----------+
+| 192.168.201.0/24 | 3        |
 |                  |          |
 +------------------+----------+
 | 192.168.240.0/24 | 2        |
 |                  |          |
 +------------------+----------+
-| 192.168.250.0/24 | 0        |
+| 192.168.241.0/24 | 3        |
+|                  |          |
++------------------+----------+
+| 1111:1111:       | 0        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 1111:5555/116    |          |
+|                  |          |
++------------------+----------+
+| 1111:1111:       | 1        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 1111:6666/116    |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 0        |
+| 1111:1111:       |          |
+| 0000:0000:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| ffff:0000:       | 1        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 2        |
+| 0000:0000:       |          |
+| aaaa:aaaa:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 3        |
+| 0000:0000:       |          |
+| bbbb:bbbb:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 2        |
+| 0000:0000:       |          |
+| 5555:5555:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 3        |
+| 0000:0000:       |          |
+| 6666:6666:       |          |
+| 0000:0/116       |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 2        |
+| 1111:1111:       |          |
+| 0000:0000:       |          |
+| 0000:0000/116    |          |
+|                  |          |
++------------------+----------+
+| 0000:0000:       | 3        |
+| 1111:1111:       |          |
+| 1111:1111:       |          |
+| 0000:0000/116    |          |
 |                  |          |
 +------------------+----------+
-- 
2.5.5

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

* Re: [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-05-10  9:21   ` Mcnamara, John
  0 siblings, 0 replies; 41+ messages in thread
From: Mcnamara, John @ 2016-05-10  9:21 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev

Hi,

Thanks for the updated docs and clear examples. Some minor comments below.


> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Friday, May 6, 2016 5:32 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
> ---
>  doc/guides/sample_app_ug/ipsec_secgw.rst | 583 ++++++++++++++++++++------
> -----
>  1 file changed, 381 insertions(+), 202 deletions(-)



> +#. [Optional] Build the application for debugging:
> +   This option adds some extra flags, disables compiler optimizations and
> +   is verbose.
> +
> +   .. code-block:: console
> +
> +       make DEBUG=1
> +

For simple console code-blocks like this you can just use ::. It defaults
to "console".

> +
> +.. _figure_ipsec_endpoints:
> +
> +.. figure:: img/ipsec_endpoints.svg
> +
> +   IPSec Inbound/Outbound traffic


The patch is missing the file:
    doc/guides/sample_app_ug/img/ipsec_endpoints.svg


> ++-----------------------------------+------------+
> +| **Dst**                           | **SA idx** |
> +|                                   |            |
> ++-----------------------------------+------------+
> +| 192.168.105.0/24                  | 5          |
> +|                                   |            |



You should add the table directive before these tables so that a
caption can be applied:

   .. _table_ipsec_endpoint_outbound_sp:
   
   .. table:: Endpoint 0 Outbound Security Policies
   
      +-----------------------------------+------------+
      | **Dst**                           | **SA idx** |
      |                                   |            |
      +-----------------------------------+------------+
      | 192.168.105.0/24                  | 5          |
      |                                   |            |


John

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

* [dpdk-dev] [PATCH v2 0/9] IPSec enhancements
  2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
                   ` (8 preceding siblings ...)
  2016-05-06 16:31 ` [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-05-18 12:42 ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
                     ` (9 more replies)
  9 siblings, 10 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Update IPSec sample app with IPv6 and Transport mode support.

The series contains some bug fixes to facilitate patch merge.

v2:
 - rebase code
 - doc improvements
 - add missing image file

Sergio Gonzalez Monroy (9):
  examples/ipsec-secgw: fix esp padding check
  examples/ipsec-secgw: fix stack smashing error
  examples/ipsec-secgw: add build option and cleanup
  examples/ipsec-secgw: rework ipsec execution loop
  examples/ipsec-secgw: fix no sa found case
  examples/ipsec-secgw: consistent config variable names
  examples/ipsec-secgw: ipv6 support
  examples/ipsec-secgw: transport mode support
  doc: update ipsec sample guide

 doc/guides/sample_app_ug/img/ipsec_endpoints.svg | 850 +++++++++++++++++++++
 doc/guides/sample_app_ug/ipsec_secgw.rst         | 910 ++++++++++++++---------
 examples/ipsec-secgw/Makefile                    |   8 +-
 examples/ipsec-secgw/esp.c                       | 210 ++++--
 examples/ipsec-secgw/esp.h                       |   9 +-
 examples/ipsec-secgw/ipip.h                      | 145 +++-
 examples/ipsec-secgw/ipsec-secgw.c               | 332 ++++++---
 examples/ipsec-secgw/ipsec.c                     |  50 +-
 examples/ipsec-secgw/ipsec.h                     |  63 +-
 examples/ipsec-secgw/rt.c                        | 229 ++++--
 examples/ipsec-secgw/sa.c                        | 466 +++++++-----
 examples/ipsec-secgw/sp.c                        | 366 ---------
 examples/ipsec-secgw/sp4.c                       | 447 +++++++++++
 examples/ipsec-secgw/sp6.c                       | 448 +++++++++++
 14 files changed, 3312 insertions(+), 1221 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/img/ipsec_endpoints.svg
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 1/9] examples/ipsec-secgw: fix esp padding check
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Current code fails to correctly check padding sequence for inbound
packets.
Padding sequence starts on 1 but it checks for 0.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 0f6b33e..7dce78c 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -139,7 +139,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
-		if (padding[i] != i) {
+		if (padding[i] != i + 1) {
 			RTE_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
 			return -EINVAL;
 		}
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 2/9] examples/ipsec-secgw: fix stack smashing error
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Building the application with -O3 and -fstack-protection (default in
Ubuntu) results in the following error:

*** stack smashing detected ***: ./build/ipsec-secgw terminated

The error is caused by storing an 8B value in a 4B variable.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 4566d38..3ffa77a 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -46,7 +46,7 @@
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 {
-	uint32_t cdev_id_qp = 0;
+	unsigned long cdev_id_qp = 0;
 	int32_t ret;
 	struct cdev_key key = { 0 };
 
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 3/9] examples/ipsec-secgw: add build option and cleanup
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Add support for building the application with DEBUG=1.
This option adds the compiler stack protection flag and enables extra
output in the application.

Also remove unnecessary VPATH setup.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index f9b59c2..6780ad5 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -46,8 +46,9 @@ ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
 CFLAGS_sa.o += -diag-disable=vec
 endif
 
-
-VPATH += $(SRCDIR)/librte_ipsec
+ifeq ($(DEBUG),1)
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+endif
 
 #
 # all source are stored in SRCS-y
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (2 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-06-07 12:50     ` De Lara Guarch, Pablo
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
                     ` (5 subsequent siblings)
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Rework implementation moving from function pointers approach, where each
function implements very specific functionality, to a generic function
approach.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   |   8 +-
 examples/ipsec-secgw/esp.h   |   9 +-
 examples/ipsec-secgw/ipsec.c |  36 ++++--
 examples/ipsec-secgw/ipsec.h |   2 -
 examples/ipsec-secgw/sa.c    | 272 ++++++++++++++++++-------------------------
 5 files changed, 145 insertions(+), 182 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 7dce78c..b423080 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -69,7 +69,7 @@ random_iv_u64(uint64_t *buf, uint16_t n)
 
 /* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	int32_t payload_len;
@@ -117,7 +117,7 @@ esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint8_t *nexthdr, *pad_len;
@@ -155,7 +155,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint16_t pad_payload_len, pad_len;
@@ -234,7 +234,7 @@ esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m __rte_unused,
+esp_outbound_post(struct rte_mbuf *m __rte_unused,
 		struct ipsec_sa *sa __rte_unused,
 		struct rte_crypto_op *cop)
 {
diff --git a/examples/ipsec-secgw/esp.h b/examples/ipsec-secgw/esp.h
index 3101882..fa5cc8a 100644
--- a/examples/ipsec-secgw/esp.h
+++ b/examples/ipsec-secgw/esp.h
@@ -46,21 +46,20 @@ struct esp_hdr {
 	/* Integrity Check Value - ICV */
 };
 
-/* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 #endif /* __RTE_IPSEC_XFORM_ESP_H__ */
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 3ffa77a..90a9a86 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -42,6 +42,7 @@
 #include <rte_hash.h>
 
 #include "ipsec.h"
+#include "esp.h"
 
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
@@ -99,15 +100,14 @@ enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 	}
 }
 
-static inline uint16_t
-ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
-		struct ipsec_sa *sas[], uint16_t nb_pkts, uint16_t max_pkts)
+static inline void
+ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
+		uint16_t nb_pkts)
 {
-	int ret = 0, i, j, nb_cops;
+	int ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
-	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
-	struct rte_mbuf *pkt;
 
 	for (i = 0; i < nb_pkts; i++) {
 		rte_prefetch0(sas[i]);
@@ -133,7 +133,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		rte_crypto_op_attach_sym_session(&priv->cop,
 				sa->crypto_session);
 
-		ret = sa->pre_crypto(pkts[i], sa, &priv->cop);
+		ret = xform_func(pkts[i], sa, &priv->cop);
 		if (unlikely(ret)) {
 			rte_pktmbuf_free(pkts[i]);
 			continue;
@@ -142,8 +142,18 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		RTE_ASSERT(sa->cdev_id_qp < ipsec_ctx->nb_qps);
 		enqueue_cop(&ipsec_ctx->tbl[sa->cdev_id_qp], &priv->cop);
 	}
+}
+
+static inline int
+ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], uint16_t max_pkts)
+{
+	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	struct ipsec_mbuf_metadata *priv;
+	struct rte_crypto_op *cops[max_pkts];
+	struct ipsec_sa *sa;
+	struct rte_mbuf *pkt;
 
-	nb_pkts = 0;
 	for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
 		struct cdev_qp *cqp;
 
@@ -168,7 +178,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 
 			RTE_ASSERT(sa != NULL);
 
-			ret = sa->post_crypto(pkt, sa, cops[j]);
+			ret = xform_func(pkt, sa, cops[j]);
 			if (unlikely(ret))
 				rte_pktmbuf_free(pkt);
 			else
@@ -188,7 +198,9 @@ ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_inbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_inbound_post, ctx, pkts, len);
 }
 
 uint16_t
@@ -199,5 +211,7 @@ ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_outbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_outbound_post, ctx, pkts, len);
 }
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index e60fae6..74ef6fc 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -86,8 +86,6 @@ struct ipsec_sa {
 	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
 	struct rte_crypto_sym_xform *xforms;
-	ipsec_xform_fn pre_crypto;
-	ipsec_xform_fn post_crypto;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index b6260ed..a193bdf 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -47,160 +47,112 @@
 #include "ipsec.h"
 #include "esp.h"
 
-/* SAs EP0 Outbound */
-const struct ipsec_sa sa_ep0_out[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP0 Inbound */
-const struct ipsec_sa sa_ep0_in[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP1 Outbound */
-const struct ipsec_sa sa_ep1_out[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Outbound */
+const struct ipsec_sa sa_out[] = {
+	{
+	.spi = 5,
+	.src = IPv4(172, 16, 1, 5),
+	.dst = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 6,
+	.src = IPv4(172, 16, 1, 6),
+	.dst = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 7,
+	.src = IPv4(172, 16, 1, 7),
+	.dst = IPv4(172, 16, 2, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 8,
+	.src = IPv4(172, 16, 1, 8),
+	.dst = IPv4(172, 16, 2, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 9,
+	.src = IPv4(172, 16, 1, 9),
+	.dst = IPv4(172, 16, 2, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
-/* SAs EP1 Inbound */
-const struct ipsec_sa sa_ep1_in[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Inbound */
+const struct ipsec_sa sa_in[] = {
+	{
+	.spi = 55,
+	.src = IPv4(172, 16, 2, 5),
+	.dst = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 56,
+	.src = IPv4(172, 16, 2, 6),
+	.dst = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 57,
+	.src = IPv4(172, 16, 2, 7),
+	.dst = IPv4(172, 16, 1, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 58,
+	.src = IPv4(172, 16, 2, 8),
+	.dst = IPv4(172, 16, 1, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 59,
+	.src = IPv4(172, 16, 2, 9),
+	.dst = IPv4(172, 16, 1, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -368,15 +320,15 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		sa_out_entries = sa_ep0_out;
-		nb_out_entries = RTE_DIM(sa_ep0_out);
-		sa_in_entries = sa_ep0_in;
-		nb_in_entries = RTE_DIM(sa_ep0_in);
+		sa_out_entries = sa_out;
+		nb_out_entries = RTE_DIM(sa_out);
+		sa_in_entries = sa_in;
+		nb_in_entries = RTE_DIM(sa_in);
 	} else if (ep == 1) {
-		sa_out_entries = sa_ep1_out;
-		nb_out_entries = RTE_DIM(sa_ep1_out);
-		sa_in_entries = sa_ep1_in;
-		nb_in_entries = RTE_DIM(sa_ep1_in);
+		sa_out_entries = sa_in;
+		nb_out_entries = RTE_DIM(sa_in);
+		sa_in_entries = sa_out;
+		nb_in_entries = RTE_DIM(sa_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (3 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-06-07 13:17     ` De Lara Guarch, Pablo
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
                     ` (4 subsequent siblings)
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

The application only checks that an SA shoudln't be NULL through ASSERT
(only when debugging is enabled) without properly dealing with the case
of not having an SA for the processed packet.

If no SA is found, drop the packet.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 90a9a86..ccc840f 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -110,6 +110,11 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 	struct ipsec_sa *sa;
 
 	for (i = 0; i < nb_pkts; i++) {
+		if (unlikely(sas[i] == NULL)) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+
 		rte_prefetch0(sas[i]);
 		rte_prefetch0(pkts[i]);
 
@@ -117,8 +122,6 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		sa = sas[i];
 		priv->sa = sa;
 
-		RTE_ASSERT(sa != NULL);
-
 		priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
 
 		rte_prefetch0(&priv->sym_cop);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 6/9] examples/ipsec-secgw: consistent config variable names
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (4 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Modify the default SP config variables names to be consistent with SA.

The resulting naming convention is that variables with suffixes _out/_in
are the default for ep0 and the reverse for ep1.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/sp.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
index 4f16730..6aa377d 100644
--- a/examples/ipsec-secgw/sp.c
+++ b/examples/ipsec-secgw/sp.c
@@ -112,7 +112,7 @@ struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
 
-const struct acl4_rules acl4_rules_in[] = {
+const struct acl4_rules acl4_rules_out[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -175,7 +175,7 @@ const struct acl4_rules acl4_rules_in[] = {
 	}
 };
 
-const struct acl4_rules acl4_rules_out[] = {
+const struct acl4_rules acl4_rules_in[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -343,15 +343,15 @@ sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else if (ep == 1) {
 		rules_out = acl4_rules_out;
 		nb_out_rules = RTE_DIM(acl4_rules_out);
 		rules_in = acl4_rules_in;
 		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (5 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-06-07 16:10     ` De Lara Guarch, Pablo
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
                     ` (2 subsequent siblings)
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Support IPSec IPv6 allowing IPv4/IPv6 traffic in IPv4 or IPv6 tunnel.

We need separate Routing (LPM) and SP (ACL) tables for IPv4 and IPv6,
but a common SA table.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile      |   5 +-
 examples/ipsec-secgw/esp.c         | 128 +++++++-----
 examples/ipsec-secgw/ipip.h        | 145 ++++++++++---
 examples/ipsec-secgw/ipsec-secgw.c | 332 ++++++++++++++++++++----------
 examples/ipsec-secgw/ipsec.c       |   9 +-
 examples/ipsec-secgw/ipsec.h       |  60 ++++--
 examples/ipsec-secgw/rt.c          | 201 +++++++++++++-----
 examples/ipsec-secgw/sa.c          | 239 ++++++++++++++--------
 examples/ipsec-secgw/sp.c          | 366 ---------------------------------
 examples/ipsec-secgw/sp4.c         | 407 +++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sp6.c         | 400 ++++++++++++++++++++++++++++++++++++
 11 files changed, 1582 insertions(+), 710 deletions(-)
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 6780ad5..06b6db1 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -47,7 +47,7 @@ CFLAGS_sa.o += -diag-disable=vec
 endif
 
 ifeq ($(DEBUG),1)
-CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all -O0
 endif
 
 #
@@ -55,7 +55,8 @@ endif
 #
 SRCS-y += ipsec.c
 SRCS-y += esp.c
-SRCS-y += sp.c
+SRCS-y += sp4.c
+SRCS-y += sp6.c
 SRCS-y += sa.c
 SRCS-y += rt.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index b423080..e1fde36 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <fcntl.h>
 #include <unistd.h>
 
@@ -50,13 +51,11 @@
 #include "esp.h"
 #include "ipip.h"
 
-#define IP_ESP_HDR_SZ (sizeof(struct ip) + sizeof(struct esp_hdr))
-
 static inline void
 random_iv_u64(uint64_t *buf, uint16_t n)
 {
-	unsigned left = n & 0x7;
-	unsigned i;
+	uint32_t left = n & 0x7;
+	uint32_t i;
 
 	RTE_ASSERT((n & 0x3) == 0);
 
@@ -67,20 +66,29 @@ random_iv_u64(uint64_t *buf, uint16_t n)
 		*((uint32_t *)&buf[i]) = (uint32_t)lrand48();
 }
 
-/* IPv4 Tunnel */
 int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len;
+	int32_t payload_len, ip_hdr_len;
 	struct rte_crypto_sym_op *sym_cop;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	payload_len = rte_pktmbuf_pkt_len(m) - IP_ESP_HDR_SZ - sa->iv_len -
-		sa->digest_len;
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
+
+	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
+		sizeof(struct esp_hdr) - sa->iv_len - sa->digest_len;
 
 	if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
 		RTE_LOG(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
@@ -91,21 +99,19 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset =  ip_hdr_len + sizeof(struct esp_hdr) +
+		sa->iv_len;
 	sym_cop->cipher.data.length = payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, void*,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
-	if (sa->auth_algo == RTE_CRYPTO_AUTH_AES_GCM)
-		sym_cop->auth.data.length = sizeof(struct esp_hdr);
-	else
-		sym_cop->auth.data.length = sizeof(struct esp_hdr) +
-			sa->iv_len + payload_len;
+	sym_cop->auth.data.offset = ip_hdr_len;
+	sym_cop->auth.data.length = sizeof(struct esp_hdr) +
+		sa->iv_len + payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
@@ -151,17 +157,20 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	return ip4ip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+
+	return 0;
 }
 
 int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len;
-	struct ip *ip;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
+	struct ip *ip4;
+	struct ip6_hdr *ip6;
 	struct esp_hdr *esp;
-	int i;
+	int32_t i;
 	char *padding;
 	struct rte_crypto_sym_op *sym_cop;
 
@@ -174,62 +183,87 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 			sa->block_size);
 	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
 
-	rte_prefetch0(rte_pktmbuf_mtod_offset(m, void *,
-				rte_pktmbuf_pkt_len(m)));
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
 
 	/* Check maximum packet size */
-	if (unlikely(IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len +
-				sa->digest_len > IP_MAXPACKET)) {
-		RTE_LOG(DEBUG, IPSEC_ESP, "ipsec packet is too big\n");
+	if (unlikely(ip_hdr_len + sizeof(struct esp_hdr) + sa->iv_len +
+			pad_payload_len + sa->digest_len > IP_MAXPACKET)) {
+		RTE_LOG(ERR, IPSEC_ESP, "ipsec packet is too big\n");
 		return -EINVAL;
 	}
 
 	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	if (unlikely(padding == NULL)) {
+		RTE_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
+		return -ENOSPC;
+	}
+	rte_prefetch0(padding);
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip4 = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip4 + 1);
+		break;
+	case IP6_TUNNEL:
+		ip6 = ip6ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip6 + 1);
+		break;
+	default:
+		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
+				sa->flags);
+		return -EINVAL;
+	}
 
-	RTE_ASSERT(padding != NULL);
-
-	ip = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
-			sa->src, sa->dst);
-
-	esp = (struct esp_hdr *)(ip + 1);
-	esp->spi = sa->spi;
-	esp->seq = htonl(sa->seq++);
+	sa->seq++;
+	esp->spi = rte_cpu_to_be_32(sa->spi);
+	esp->seq = rte_cpu_to_be_32(sa->seq);
 
-	RTE_LOG(DEBUG, IPSEC_ESP, "pktlen %u\n", rte_pktmbuf_pkt_len(m));
+	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
+		random_iv_u64((uint64_t *)(esp + 1), sa->iv_len);
 
 	/* Fill pad_len using default sequential scheme */
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
-
 	padding[pad_len - 2] = pad_len - 2;
-	padding[pad_len - 1] = IPPROTO_IPIP;
+
+	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
+		padding[pad_len - 1] = IPPROTO_IPIP;
+	else
+		padding[pad_len - 1] = IPPROTO_IPV6;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset = ip_hdr_len + sizeof(struct esp_hdr) +
+			sa->iv_len;
 	sym_cop->cipher.data.length = pad_payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
+	sym_cop->auth.data.offset = ip_hdr_len;
 	sym_cop->auth.data.length = sizeof(struct esp_hdr) + sa->iv_len +
 		pad_payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.length = sa->digest_len;
 
-	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
-		random_iv_u64((uint64_t *)sym_cop->cipher.iv.data,
-				sym_cop->cipher.iv.length);
-
 	return 0;
 }
 
diff --git a/examples/ipsec-secgw/ipip.h b/examples/ipsec-secgw/ipip.h
index 1307a12..886e7a8 100644
--- a/examples/ipsec-secgw/ipip.h
+++ b/examples/ipsec-secgw/ipip.h
@@ -37,65 +37,144 @@
 #include <stdint.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_mbuf.h>
 
-#define IPV6_VERSION (6)
-
-static inline  struct ip *
-ip4ip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t src, uint32_t dst)
+static inline void *
+ipip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t is_ipv6,
+		struct ip_addr *src,  struct ip_addr *dst)
 {
-	struct ip *inip, *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint8_t ds_ecn;
 
-	inip = rte_pktmbuf_mtod(m, struct ip*);
+	inip4 = rte_pktmbuf_mtod(m, struct ip *);
 
-	RTE_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
+	if (inip4->ip_v == IPVERSION) {
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+		ds_ecn = inip4->ip_tos;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+		ds_ecn = ntohl(inip6->ip6_flow) >> 20;
+	}
+
+	if (is_ipv6) {
+		offset += sizeof(struct ip6_hdr);
+		outip6 = (struct ip6_hdr *)rte_pktmbuf_prepend(m, offset);
+
+		RTE_ASSERT(outip6 != NULL);
+
+		/* Per RFC4301 5.1.2.1 */
+		outip6->ip6_flow = htonl(IP6_VERSION << 28 | ds_ecn << 20);
+		outip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+
+		outip6->ip6_nxt = IPPROTO_ESP;
+		outip6->ip6_hops = IPDEFTTL;
 
-	outip = (struct ip *)rte_pktmbuf_prepend(m, offset);
+		memcpy(&outip6->ip6_src.s6_addr, src, 16);
+		memcpy(&outip6->ip6_dst.s6_addr, dst, 16);
 
-	RTE_ASSERT(outip != NULL);
+		return outip6;
+	}
+
+	offset += sizeof(struct ip);
+	outip4 = (struct ip *)rte_pktmbuf_prepend(m, offset);
+
+	RTE_ASSERT(outip4 != NULL);
 
 	/* Per RFC4301 5.1.2.1 */
-	outip->ip_v = IPVERSION;
-	outip->ip_hl = 5;
-	outip->ip_tos = inip->ip_tos;
-	outip->ip_len = htons(rte_pktmbuf_data_len(m));
+	outip4->ip_v = IPVERSION;
+	outip4->ip_hl = 5;
+	outip4->ip_tos = ds_ecn;
+	outip4->ip_len = htons(rte_pktmbuf_data_len(m));
 
-	outip->ip_id = 0;
-	outip->ip_off = 0;
+	outip4->ip_id = 0;
+	outip4->ip_off = 0;
 
-	outip->ip_ttl = IPDEFTTL;
-	outip->ip_p = IPPROTO_ESP;
+	outip4->ip_ttl = IPDEFTTL;
+	outip4->ip_p = IPPROTO_ESP;
 
-	outip->ip_src.s_addr = src;
-	outip->ip_dst.s_addr = dst;
+	outip4->ip_src.s_addr = src->ip4;
+	outip4->ip_dst.s_addr = dst->ip4;
 
-	return outip;
+	return outip4;
+}
+
+static inline struct ip *
+ip4ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 0, src, dst);
+}
+
+static inline struct ip6_hdr *
+ip6ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 1, src, dst);
+}
+
+static inline void
+ip4_ecn_setup(struct ip *ip4)
+{
+	if (ip4->ip_tos & IPTOS_ECN_MASK)
+		ip4->ip_tos |= IPTOS_ECN_CE;
+}
+
+static inline void
+ip6_ecn_setup(struct ip6_hdr *ip6)
+{
+	if ((ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK)
+		ip6->ip6_flow = htonl(ntohl(ip6->ip6_flow) |
+					(IPTOS_ECN_CE << 20));
 }
 
 static inline int
-ip4ip_inbound(struct rte_mbuf *m, uint32_t offset)
+ipip_inbound(struct rte_mbuf *m, uint32_t offset)
 {
-	struct ip *inip;
-	struct ip *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint32_t ip_len, set_ecn;
 
-	outip = rte_pktmbuf_mtod(m, struct ip*);
+	outip4 = rte_pktmbuf_mtod(m, struct ip*);
 
-	RTE_ASSERT(outip->ip_v == IPVERSION);
+	RTE_ASSERT(outip4->ip_v == IPVERSION || outip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
-	inip = (struct ip *)rte_pktmbuf_adj(m, offset);
-	RTE_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	if (outip4->ip_v == IPVERSION) {
+		ip_len = sizeof(struct ip);
+		set_ecn = ((outip4->ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	} else {
+		outip6 = (struct ip6_hdr *)outip4;
+		ip_len = sizeof(struct ip6_hdr);
+		set_ecn = ntohl(outip6->ip6_flow) >> 20;
+		set_ecn = ((set_ecn & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	}
+
+	inip4 = (struct ip *)rte_pktmbuf_adj(m, offset + ip_len);
+	RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
 	/* Check packet is still bigger than IP header (inner) */
-	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > sizeof(struct ip));
+	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > ip_len);
 
 	/* RFC4301 5.1.2.1 Note 6 */
-	if ((inip->ip_tos & htons(IPTOS_ECN_ECT0 | IPTOS_ECN_ECT1)) &&
-			((outip->ip_tos & htons(IPTOS_ECN_CE)) == IPTOS_ECN_CE))
-		inip->ip_tos |= htons(IPTOS_ECN_CE);
+	if (inip4->ip_v == IPVERSION) {
+		if (set_ecn)
+			ip4_ecn_setup(inip4);
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		if (set_ecn)
+			ip6_ecn_setup(inip6);
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+	}
 
 	return 0;
 }
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 00ab2d8..4065b59 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -38,6 +38,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <string.h>
 #include <sys/queue.h>
 #include <stdarg.h>
@@ -65,6 +66,7 @@
 #include <rte_mbuf.h>
 #include <rte_acl.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_hash.h>
 #include <rte_jhash.h>
 #include <rte_cryptodev.h>
@@ -192,7 +194,8 @@ struct lcore_conf {
 	struct buffer tx_mbufs[RTE_MAX_ETHPORTS];
 	struct ipsec_ctx inbound;
 	struct ipsec_ctx outbound;
-	struct rt_ctx *rt_ctx;
+	struct rt_ctx *rt4_ctx;
+	struct rt_ctx *rt6_ctx;
 } __rte_cache_aligned;
 
 static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
@@ -230,27 +233,39 @@ struct traffic_type {
 };
 
 struct ipsec_traffic {
-	struct traffic_type ipsec4;
-	struct traffic_type ipv4;
+	struct traffic_type ipsec;
+	struct traffic_type ip4;
+	struct traffic_type ip6;
 };
 
 static inline void
 prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 {
 	uint8_t *nlp;
+	struct ether_hdr *eth;
 
-	if (RTE_ETH_IS_IPV4_HDR(pkt->packet_type)) {
-		rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
-		nlp = rte_pktmbuf_mtod_offset(pkt, uint8_t *,
-				offsetof(struct ip, ip_p));
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip, ip_p));
 		if (*nlp == IPPROTO_ESP)
-			t->ipsec4.pkts[(t->ipsec4.num)++] = pkt;
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
 		else {
-			t->ipv4.data[t->ipv4.num] = nlp;
-			t->ipv4.pkts[(t->ipv4.num)++] = pkt;
+			t->ip4.data[t->ip4.num] = nlp;
+			t->ip4.pkts[(t->ip4.num)++] = pkt;
+		}
+	} else if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip6_hdr, ip6_nxt));
+		if (*nlp == IPPROTO_ESP)
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
+		else {
+			t->ip6.data[t->ip6.num] = nlp;
+			t->ip6.pkts[(t->ip6.num)++] = pkt;
 		}
 	} else {
 		/* Unknown/Unsupported type, drop the packet */
+		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
 		rte_pktmbuf_free(pkt);
 	}
 }
@@ -261,8 +276,9 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 {
 	int32_t i;
 
-	t->ipsec4.num = 0;
-	t->ipv4.num = 0;
+	t->ipsec.num = 0;
+	t->ip4.num = 0;
+	t->ip6.num = 0;
 
 	for (i = 0; i < (nb_pkts - PREFETCH_OFFSET); i++) {
 		rte_prefetch0(rte_pktmbuf_mtod(pkts[i + PREFETCH_OFFSET],
@@ -277,14 +293,27 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 static inline void
 prepare_tx_pkt(struct rte_mbuf *pkt, uint8_t port)
 {
-	pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
-	pkt->l3_len = sizeof(struct ip);
-	pkt->l2_len = ETHER_HDR_LEN;
+	struct ip *ip;
+	struct ether_hdr *ethhdr;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+
+	ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt, ETHER_HDR_LEN);
 
-	struct ether_hdr *ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt,
-			ETHER_HDR_LEN);
+	if (ip->ip_v == IPVERSION) {
+		pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
+		pkt->l3_len = sizeof(struct ip);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	} else {
+		pkt->ol_flags |= PKT_TX_IPV6;
+		pkt->l3_len = sizeof(struct ip6_hdr);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	}
 
-	ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
 	memcpy(&ethhdr->s_addr, &ethaddr_tbl[port].src,
 			sizeof(struct ether_addr));
 	memcpy(&ethhdr->d_addr, &ethaddr_tbl[port].dst,
@@ -355,94 +384,133 @@ send_single_packet(struct rte_mbuf *m, uint8_t port)
 }
 
 static inline void
-process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
-		struct ipsec_traffic *traffic)
+inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_in, i, j;
-	uint32_t sa_idx, res;
-
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	uint32_t i, j, res, sa_idx;
 
-	/* SP/ACL Inbound check ipsec and ipv4 */
-	for (i = 0; i < nb_pkts_in; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
-		traffic->ipv4.data[idx] = rte_pktmbuf_mtod_offset(m,
-				uint8_t *, offsetof(struct ip, ip_p));
-	}
+	if (ip->num == 0)
+		return;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num - nb_pkts_in; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		if (res & ~BYPASS) {
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		res = ip->res[i];
+		if (res & DISCARD) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
-	}
-	/* Check return SA SPI matches pkt SPI */
-	for ( ; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		sa_idx = traffic->ipv4.res[i] & PROTECT_MASK;
-		if (sa_idx == 0 || !inbound_sa_check(ipsec_ctx->sa_ctx,
-					m, sa_idx)) {
+		if (res & BYPASS) {
+			ip->pkts[j++] = m;
+			continue;
+		}
+		/* Check return SA SPI matches pkt SPI */
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
+		ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
 }
 
 static inline void
-process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_out, i, j;
-	uint32_t sa_idx, res;
+	uint16_t idx, nb_pkts_in, i;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
 
-	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	/* SP/ACL Inbound check ipsec and ip4 */
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+			traffic->ip4.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *, offsetof(struct ip, ip_p));
+		} else if (ip->ip_v == IP6_VERSION) {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+			traffic->ip6.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *,
+					offsetof(struct ip6_hdr, ip6_nxt));
+		} else
+			rte_pktmbuf_free(m);
+	}
+
+	inbound_sp_sa(ipsec_ctx->sp4_ctx, ipsec_ctx->sa_ctx, &traffic->ip4);
+
+	inbound_sp_sa(ipsec_ctx->sp6_ctx, ipsec_ctx->sa_ctx, &traffic->ip6);
+}
+
+static inline void
+outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
+		struct traffic_type *ipsec)
+{
+	struct rte_mbuf *m;
+	uint32_t i, j, sa_idx;
+
+	if (ip->num == 0)
+		return;
 
-	traffic->ipsec4.num = 0;
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		sa_idx = res & PROTECT_MASK;
-		if ((res == 0) || (res & DISCARD))
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if ((ip->res[i] == 0) || (ip->res[i] & DISCARD))
 			rte_pktmbuf_free(m);
 		else if (sa_idx != 0) {
-			traffic->ipsec4.res[traffic->ipsec4.num] = sa_idx;
-			traffic->ipsec4.pkts[traffic->ipsec4.num++] = m;
+			ipsec->res[ipsec->num] = sa_idx;
+			ipsec->pkts[ipsec->num++] = m;
 		} else /* BYPASS */
-			traffic->ipv4.pkts[j++] = m;
+			ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
+}
+
+static inline void
+process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+		struct ipsec_traffic *traffic)
+{
+	struct rte_mbuf *m;
+	uint16_t idx, nb_pkts_out, i;
+
+	/* Drop any IPsec traffic from protected ports */
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.res, traffic->ipsec4.num,
+	traffic->ipsec.num = 0;
+
+	outbound_sp(ipsec_ctx->sp4_ctx, &traffic->ip4, &traffic->ipsec);
+
+	outbound_sp(ipsec_ctx->sp6_ctx, &traffic->ip6, &traffic->ipsec);
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.res, traffic->ipsec.num,
 			MAX_PKT_BURST);
 
 	for (i = 0; i < nb_pkts_out; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
 	}
 }
 
@@ -450,47 +518,72 @@ static inline void
 process_pkts_inbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_in, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_in, i, idx;
 
 	/* Drop any IPv4 traffic from unprotected ports */
-	for (i = 0; i < traffic->ipv4.num; i++)
-		rte_pktmbuf_free(traffic->ipv4.pkts[i]);
+	for (i = 0; i < traffic->ip4.num; i++)
+		rte_pktmbuf_free(traffic->ip4.pkts[i]);
 
-	traffic->ipv4.num = 0;
+	traffic->ip4.num = 0;
 
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	/* Drop any IPv6 traffic from unprotected ports */
+	for (i = 0; i < traffic->ip6.num; i++)
+		rte_pktmbuf_free(traffic->ip6.pkts[i]);
 
-	for (i = 0; i < nb_pkts_in; i++)
-		traffic->ipv4.pkts[i] = traffic->ipsec4.pkts[i];
+	traffic->ip6.num = 0;
 
-	traffic->ipv4.num = nb_pkts_in;
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
+
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
+	}
 }
 
 static inline void
 process_pkts_outbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_out, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_out, i;
+	struct ip *ip;
 
 	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	traffic->ipsec4.num = 0;
+	traffic->ipsec.num = 0;
 
-	for (i = 0; i < traffic->ipv4.num; i++)
-		traffic->ipv4.res[i] = single_sa_idx;
+	for (i = 0; i < traffic->ip4.num; i++)
+		traffic->ip4.res[i] = single_sa_idx;
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipv4.pkts,
-			traffic->ipv4.res, traffic->ipv4.num,
+	for (i = 0; i < traffic->ip6.num; i++)
+		traffic->ip6.res[i] = single_sa_idx;
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ip4.pkts,
+			traffic->ip4.res, traffic->ip4.num,
 			MAX_PKT_BURST);
 
-	traffic->ipv4.num = nb_pkts_out;
+	/* They all sue the same SA (ip4 or ip6 tunnel) */
+	m = traffic->ipsec.pkts[i];
+	ip = rte_pktmbuf_mtod(m, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		traffic->ip4.num = nb_pkts_out;
+	else
+		traffic->ip6.num = nb_pkts_out;
 }
 
 static inline void
-route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+route4_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 {
 	uint32_t hop[MAX_PKT_BURST * 2];
 	uint32_t dst_ip[MAX_PKT_BURST * 2];
@@ -518,6 +611,35 @@ route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 }
 
 static inline void
+route6_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+{
+	int16_t hop[MAX_PKT_BURST * 2];
+	uint8_t dst_ip[MAX_PKT_BURST * 2][16];
+	uint8_t *ip6_dst;
+	uint16_t i, offset;
+
+	if (nb_pkts == 0)
+		return;
+
+	for (i = 0; i < nb_pkts; i++) {
+		offset = offsetof(struct ip6_hdr, ip6_dst);
+		ip6_dst = rte_pktmbuf_mtod_offset(pkts[i], uint8_t *, offset);
+		memcpy(&dst_ip[i][0], ip6_dst, 16);
+	}
+
+	rte_lpm6_lookup_bulk_func((struct rte_lpm6 *)rt_ctx, dst_ip,
+			hop, nb_pkts);
+
+	for (i = 0; i < nb_pkts; i++) {
+		if (hop[i] == -1) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+		send_single_packet(pkts[i], hop[i] & 0xff);
+	}
+}
+
+static inline void
 process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 		uint8_t nb_pkts, uint8_t portid)
 {
@@ -525,7 +647,7 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 
 	prepare_traffic(pkts, &traffic, nb_pkts);
 
-	if (single_sa) {
+	if (unlikely(single_sa)) {
 		if (UNPROTECTED_PORT(portid))
 			process_pkts_inbound_nosp(&qconf->inbound, &traffic);
 		else
@@ -537,7 +659,8 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 			process_pkts_outbound(&qconf->outbound, &traffic);
 	}
 
-	route_pkts(qconf->rt_ctx, traffic.ipv4.pkts, traffic.ipv4.num);
+	route4_pkts(qconf->rt4_ctx, traffic.ip4.pkts, traffic.ip4.num);
+	route6_pkts(qconf->rt6_ctx, traffic.ip6.pkts, traffic.ip6.num);
 }
 
 static inline void
@@ -576,12 +699,15 @@ main_loop(__attribute__((unused)) void *dummy)
 	rxql = qconf->rx_queue_list;
 	socket_id = rte_lcore_to_socket_id(lcore_id);
 
-	qconf->rt_ctx = socket_ctx[socket_id].rt_ipv4;
-	qconf->inbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_in;
-	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_in;
+	qconf->rt4_ctx = socket_ctx[socket_id].rt_ip4;
+	qconf->rt6_ctx = socket_ctx[socket_id].rt_ip6;
+	qconf->inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
+	qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
+	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
 	qconf->inbound.cdev_map = cdev_map_in;
-	qconf->outbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_out;
-	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_out;
+	qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
+	qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
+	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
 	qconf->outbound.cdev_map = cdev_map_out;
 
 	if (qconf->nb_rx_queue == 0) {
@@ -762,7 +888,7 @@ parse_config(const char *q_arg)
 		FLD_LCORE,
 		_NUM_FLD
 	};
-	int long int_fld[_NUM_FLD];
+	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
 	int32_t i;
 	uint32_t size;
@@ -1313,7 +1439,9 @@ main(int32_t argc, char **argv)
 
 		sa_init(&socket_ctx[socket_id], socket_id, ep);
 
-		sp_init(&socket_ctx[socket_id], socket_id, ep);
+		sp4_init(&socket_ctx[socket_id], socket_id, ep);
+
+		sp6_init(&socket_ctx[socket_id], socket_id, ep);
 
 		rt_init(&socket_ctx[socket_id], socket_id, ep);
 
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index ccc840f..1e87d0d 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -66,7 +66,8 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 	}
 
 	RTE_LOG(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
-			"%u qp %u\n", sa->spi, ipsec_ctx->tbl[cdev_id_qp].id,
+			"%u qp %u\n", sa->spi,
+			ipsec_ctx->tbl[cdev_id_qp].id,
 			ipsec_ctx->tbl[cdev_id_qp].qp);
 
 	sa->crypto_session = rte_cryptodev_sym_session_create(
@@ -80,7 +81,7 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 static inline void
 enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 {
-	int ret, i;
+	int32_t ret, i;
 
 	cqp->buf[cqp->len++] = cop;
 
@@ -105,7 +106,7 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
 		uint16_t nb_pkts)
 {
-	int ret = 0, i;
+	int32_t ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
 	struct ipsec_sa *sa;
 
@@ -151,7 +152,7 @@ static inline int
 ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], uint16_t max_pkts)
 {
-	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
 	struct ipsec_mbuf_metadata *priv;
 	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 74ef6fc..83d7b1c 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 #include <stdint.h>
 
 #include <rte_byteorder.h>
-#include <rte_ip.h>
 #include <rte_crypto.h>
 
 #define RTE_LOGTYPE_IPSEC       RTE_LOGTYPE_USER1
@@ -50,15 +49,15 @@
 #define MAX_DIGEST_SIZE 32 /* Bytes -- 256 bits */
 
 #define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (unsigned char)(ip >> 24 & 0xff);\
-		*b = (unsigned char)(ip >> 16 & 0xff);\
-		*c = (unsigned char)(ip >> 8 & 0xff);\
-		*d = (unsigned char)(ip & 0xff);\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
 	} while (0)
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (64) /* must be power of 2, max 2 power 30 */
+#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)
 
@@ -69,6 +68,8 @@
 
 #define IPSEC_XFORM_MAX 2
 
+#define IP6_VERSION (6)
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_cryptodev_session;
@@ -76,23 +77,35 @@ struct rte_mbuf;
 
 struct ipsec_sa;
 
-typedef int (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
+typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
+struct ip_addr {
+	union {
+		uint32_t ip4;
+		union {
+			uint64_t ip6[2];
+			uint8_t ip6_b[16];
+		};
+	};
+};
+
 struct ipsec_sa {
 	uint32_t spi;
 	uint32_t cdev_id_qp;
-	uint32_t src;
-	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
-	struct rte_crypto_sym_xform *xforms;
+	uint32_t seq;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
 	uint16_t iv_len;
 	uint16_t block_size;
 	uint16_t flags;
-	uint32_t seq;
+#define IP4_TUNNEL (1 << 0)
+#define IP6_TUNNEL (1 << 1)
+	struct ip_addr src;
+	struct ip_addr dst;
+	struct rte_crypto_sym_xform *xforms;
 } __rte_cache_aligned;
 
 struct ipsec_mbuf_metadata {
@@ -111,7 +124,8 @@ struct cdev_qp {
 
 struct ipsec_ctx {
 	struct rte_hash *cdev_map;
-	struct sp_ctx *sp_ctx;
+	struct sp_ctx *sp4_ctx;
+	struct sp_ctx *sp6_ctx;
 	struct sa_ctx *sa_ctx;
 	uint16_t nb_qps;
 	uint16_t last_qp;
@@ -125,11 +139,14 @@ struct cdev_key {
 };
 
 struct socket_ctx {
-	struct sa_ctx *sa_ipv4_in;
-	struct sa_ctx *sa_ipv4_out;
-	struct sp_ctx *sp_ipv4_in;
-	struct sp_ctx *sp_ipv4_out;
-	struct rt_ctx *rt_ipv4;
+	struct sa_ctx *sa_in;
+	struct sa_ctx *sa_out;
+	struct sp_ctx *sp_ip4_in;
+	struct sp_ctx *sp_ip4_out;
+	struct sp_ctx *sp_ip6_in;
+	struct sp_ctx *sp_ip6_out;
+	struct rt_ctx *rt_ip4;
+	struct rt_ctx *rt_ip6;
 	struct rte_mempool *mbuf_pool;
 };
 
@@ -165,12 +182,15 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts);
 
 void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index a6d0866..d46df49 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -36,110 +36,205 @@
  */
 #include <sys/types.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 
-#define RT_IPV4_MAX_RULES         64
+#define RT_IPV4_MAX_RULES	1024
+#define RT_IPV6_MAX_RULES	1024
 
-struct ipv4_route {
+struct ip4_route {
 	uint32_t ip;
-	uint8_t  depth;
-	uint8_t  if_out;
+	uint8_t depth;
+	uint8_t if_out;
 };
 
-/* In the default routing table we have:
- * ep0 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep0[] = {
+struct ip6_route {
+	uint8_t ip[16];
+	uint8_t depth;
+	uint8_t if_out;
+};
+
+static struct ip4_route rt_ip4_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
-	{ IPv4(172, 16, 2, 6), 32, 0 },
-	{ IPv4(172, 16, 2, 7), 32, 1 },
-	{ IPv4(172, 16, 2, 8), 32, 1 },
+	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 240, 0), 24, 0 },
+	{ IPv4(192, 168, 241, 0), 24, 1 },
 
+	/* Inbound */
+	/* Tunnels */
 	{ IPv4(192, 168, 115, 0), 24, 2 },
-	{ IPv4(192, 168, 116, 0), 24, 2 },
-	{ IPv4(192, 168, 117, 0), 24, 3 },
-	{ IPv4(192, 168, 118, 0), 24, 3 },
-
+	{ IPv4(192, 168, 116, 0), 24, 3 },
+	{ IPv4(192, 168, 65, 0), 24, 2 },
+	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
-
-	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 211, 0), 24, 3 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 2 },
+	{ IPv4(192, 168, 246, 0), 24, 3 },
 };
 
-/* In the default routing table we have:
- * ep1 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep1[] = {
-	{ IPv4(172, 16, 1, 5), 32, 2 },
-	{ IPv4(172, 16, 1, 6), 32, 2 },
-	{ IPv4(172, 16, 1, 7), 32, 3 },
-	{ IPv4(172, 16, 1, 8), 32, 3 },
-
-	{ IPv4(192, 168, 105, 0), 24, 0 },
-	{ IPv4(192, 168, 106, 0), 24, 0 },
-	{ IPv4(192, 168, 107, 0), 24, 1 },
-	{ IPv4(192, 168, 108, 0), 24, 1 },
-
-	{ IPv4(192, 168, 200, 0), 24, 0 },
+static struct ip6_route rt_ip6_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Inbound */
+	/* Tunnels */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+};
 
+static struct ip4_route rt_ip4_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ IPv4(172, 16, 1, 5), 32, 0 },
+	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 0 },
+	{ IPv4(192, 168, 246, 0), 24, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ IPv4(192, 168, 105, 0), 24, 2 },
+	{ IPv4(192, 168, 106, 0), 24, 3 },
+	{ IPv4(192, 168, 55, 0), 24, 2 },
+	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* NULL */
+	{ IPv4(192, 168, 200, 0), 24, 2 },
+	{ IPv4(192, 168, 201, 0), 24, 3 },
+	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 241, 0), 24, 3 },
+};
+
+static struct ip6_route rt_ip6_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	char name[PATH_MAX];
-	unsigned i;
-	int ret;
+	uint32_t i;
+	int32_t ret;
 	struct rte_lpm *lpm;
-	struct ipv4_route *rt;
+	struct rte_lpm6 *lpm6;
+	struct ip4_route *rt;
+	struct ip6_route *rt6;
 	char a, b, c, d;
-	unsigned nb_routes;
+	uint32_t nb_routes, nb_routes6;
 	struct rte_lpm_config conf = { 0 };
+	struct rte_lpm6_config conf6 = { 0 };
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->rt_ipv4 != NULL)
-		rte_exit(EXIT_FAILURE, "Routing Table for socket %u already "
-			"initialized\n", socket_id);
+	if (ctx->rt_ip4 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv4 Routing Table for socket %u "
+			"already initialized\n", socket_id);
 
-	printf("Creating Routing Table (RT) context with %u max routes\n",
+	if (ctx->rt_ip6 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u "
+			"already initialized\n", socket_id);
+
+	printf("Creating IPv4 Routing Table (RT) context with %u max routes\n",
 			RT_IPV4_MAX_RULES);
 
 	if (ep == 0) {
-		rt = rt_ipv4_ep0;
-		nb_routes = RTE_DIM(rt_ipv4_ep0);
+		rt = rt_ip4_ep0;
+		nb_routes = RTE_DIM(rt_ip4_ep0);
+		rt6 = rt_ip6_ep0;
+		nb_routes6 = RTE_DIM(rt_ip6_ep0);
 	} else if (ep == 1) {
-		rt = rt_ipv4_ep1;
-		nb_routes = RTE_DIM(rt_ipv4_ep1);
+		rt = rt_ip4_ep1;
+		nb_routes = RTE_DIM(rt_ip4_ep1);
+		rt6 = rt_ip6_ep1;
+		nb_routes6 = RTE_DIM(rt_ip6_ep1);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. Only 0 or 1 "
 			"supported.\n", ep);
 
 	/* create the LPM table */
-	snprintf(name, sizeof(name), "%s_%u", "rt_ipv4", socket_id);
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip4", socket_id);
 	conf.max_rules = RT_IPV4_MAX_RULES;
 	conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
 	lpm = rte_lpm_create(name, socket_id, &conf);
 	if (lpm == NULL)
-		rte_exit(EXIT_FAILURE, "Unable to create LPM table "
-			"on socket %d\n", socket_id);
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
 
 	/* populate the LPM table */
 	for (i = 0; i < nb_routes; i++) {
 		ret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out);
 		if (ret < 0)
-			rte_exit(EXIT_FAILURE, "Unable to add entry num %u to "
-				"LPM table on socket %d\n", i, socket_id);
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
 
 		uint32_t_to_char(rt[i].ip, &a, &b, &c, &d);
 		printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n",
 				a, b, c, d, rt[i].depth, rt[i].if_out);
 	}
 
-	ctx->rt_ipv4 = (struct rt_ctx *)lpm;
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id);
+	conf6.max_rules = RT_IPV6_MAX_RULES;
+	conf6.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
+	lpm6 = rte_lpm6_create(name, socket_id, &conf6);
+	if (lpm6 == NULL)
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
+
+	/* populate the LPM table */
+	for (i = 0; i < nb_routes6; i++) {
+		ret = rte_lpm6_add(lpm6, rt6[i].ip, rt6[i].depth,
+				rt6[i].if_out);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
+
+		printf("LPM6: Adding route "
+			" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n",
+			(uint16_t)((rt6[i].ip[0] << 8) | rt6[i].ip[1]),
+			(uint16_t)((rt6[i].ip[2] << 8) | rt6[i].ip[3]),
+			(uint16_t)((rt6[i].ip[4] << 8) | rt6[i].ip[5]),
+			(uint16_t)((rt6[i].ip[6] << 8) | rt6[i].ip[7]),
+			(uint16_t)((rt6[i].ip[8] << 8) | rt6[i].ip[9]),
+			(uint16_t)((rt6[i].ip[10] << 8) | rt6[i].ip[11]),
+			(uint16_t)((rt6[i].ip[12] << 8) | rt6[i].ip[13]),
+			(uint16_t)((rt6[i].ip[14] << 8) | rt6[i].ip[15]),
+			rt6[i].depth, rt6[i].if_out);
+	}
+
+	ctx->rt_ip4 = (struct rt_ctx *)lpm;
+	ctx->rt_ip6 = (struct rt_ctx *)lpm6;
 }
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a193bdf..8b54beb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -37,12 +37,14 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_memzone.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_byteorder.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -51,108 +53,148 @@
 const struct ipsec_sa sa_out[] = {
 	{
 	.spi = 5,
-	.src = IPv4(172, 16, 1, 5),
-	.dst = IPv4(172, 16, 2, 5),
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
 	.spi = 6,
-	.src = IPv4(172, 16, 1, 6),
-	.dst = IPv4(172, 16, 2, 6),
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 7,
-	.src = IPv4(172, 16, 1, 7),
-	.dst = IPv4(172, 16, 2, 7),
+	.spi = 15,
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 16,
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 25,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 8,
-	.src = IPv4(172, 16, 1, 8),
-	.dst = IPv4(172, 16, 2, 8),
+	.spi = 26,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 9,
-	.src = IPv4(172, 16, 1, 9),
-	.dst = IPv4(172, 16, 2, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 /* SAs Inbound */
 const struct ipsec_sa sa_in[] = {
 	{
-	.spi = 55,
-	.src = IPv4(172, 16, 2, 5),
-	.dst = IPv4(172, 16, 1, 5),
+	.spi = 105,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 56,
-	.src = IPv4(172, 16, 2, 6),
-	.dst = IPv4(172, 16, 1, 6),
+	.spi = 106,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 115,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 57,
-	.src = IPv4(172, 16, 2, 7),
-	.dst = IPv4(172, 16, 1, 7),
+	.spi = 116,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 125,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 58,
-	.src = IPv4(172, 16, 2, 8),
-	.dst = IPv4(172, 16, 1, 8),
+	.spi = 126,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 59,
-	.src = IPv4(172, 16, 2, 9),
-	.dst = IPv4(172, 16, 1, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -217,11 +259,11 @@ struct sa_ctx {
 };
 
 static struct sa_ctx *
-sa_ipv4_create(const char *name, int socket_id)
+sa_create(const char *name, int32_t socket_id)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
-	unsigned mz_size;
+	uint32_t mz_size;
 	const struct rte_memzone *mz;
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
@@ -246,10 +288,10 @@ sa_ipv4_create(const char *name, int socket_id)
 
 static int
 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries, unsigned inbound)
+		uint32_t nb_entries, uint32_t inbound)
 {
 	struct ipsec_sa *sa;
-	unsigned i, idx;
+	uint32_t i, idx;
 
 	for (i = 0; i < nb_entries; i++) {
 		idx = SPI2IDX(entries[i].spi);
@@ -260,8 +302,14 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
-		sa->src = rte_cpu_to_be_32(sa->src);
-		sa->dst = rte_cpu_to_be_32(sa->dst);
+		sa->seq = 0;
+
+		switch (sa->flags) {
+		case IP4_TUNNEL:
+			sa->src.ip4 = rte_cpu_to_be_32(sa->src.ip4);
+			sa->dst.ip4 = rte_cpu_to_be_32(sa->dst.ip4);
+		}
+
 		if (inbound) {
 			if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
 				sa_ctx->xf[idx].a = null_auth_xf;
@@ -289,33 +337,33 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 
 static inline int
 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 0);
 }
 
 static inline int
 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 1);
 }
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	const struct ipsec_sa *sa_out_entries, *sa_in_entries;
-	unsigned nb_out_entries, nb_in_entries;
+	uint32_t nb_out_entries, nb_in_entries;
 	const char *name;
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->sa_ipv4_in != NULL)
+	if (ctx->sa_in != NULL)
 		rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (ctx->sa_ipv4_out != NULL)
+	if (ctx->sa_out != NULL)
 		rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
@@ -333,21 +381,21 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
 
-	name = "sa_ipv4_in";
-	ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_in == NULL)
+	name = "sa_in";
+	ctx->sa_in = sa_create(name, socket_id);
+	if (ctx->sa_in == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	name = "sa_ipv4_out";
-	ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_out == NULL)
+	name = "sa_out";
+	ctx->sa_out = sa_create(name, socket_id);
+	if (ctx->sa_out == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
+	sa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);
 
-	sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
+	sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
 }
 
 int
@@ -360,38 +408,63 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
 }
 
+static inline void
+single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
+		struct ipsec_sa **sa_ret)
+{
+	struct esp_hdr *esp;
+	struct ip *ip;
+	uint32_t *src4_addr;
+	uint8_t *src6_addr;
+	struct ipsec_sa *sa;
+
+	*sa_ret = NULL;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		esp = (struct esp_hdr *)(ip + 1);
+	else
+		esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
+
+	if (esp->spi == INVALID_SPI)
+		return;
+
+	sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
+	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
+		return;
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
+		if ((ip->ip_v == IPVERSION) &&
+				(sa->src.ip4 == *src4_addr) &&
+				(sa->dst.ip4 == *(src4_addr + 1)))
+			*sa_ret = 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.ip6, src6_addr, 16) &&
+				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
+			*sa_ret = sa;
+	}
+}
+
 void
 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
-	uint32_t *src, spi;
-
-	for (i = 0; i < nb_pkts; i++) {
-		spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
-				sizeof(struct ip))->spi;
+	uint32_t i;
 
-		if (spi == INVALID_SPI)
-			continue;
-
-		sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
-		if (spi != sa[i]->spi) {
-			sa[i] = NULL;
-			continue;
-		}
-
-		src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
-				offsetof(struct ip, ip_src));
-		if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
-			sa[i] = NULL;
-	}
+	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[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
+	uint32_t i;
 
 	for (i = 0; i < nb_pkts; i++)
 		sa[i] = &sa_ctx->sa[sa_idx[i]];
diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
deleted file mode 100644
index 6aa377d..0000000
--- a/examples/ipsec-secgw/sp.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Security Policies
- */
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-
-#include <rte_acl.h>
-
-#include "ipsec.h"
-
-#define MAX_ACL_RULE_NUM	1000
-
-/*
- * Rule and trace formats definitions.
- */
-enum {
-	PROTO_FIELD_IPV4,
-	SRC_FIELD_IPV4,
-	DST_FIELD_IPV4,
-	SRCP_FIELD_IPV4,
-	DSTP_FIELD_IPV4,
-	NUM_FIELDS_IPV4
-};
-
-/*
- * That effectively defines order of IPV4 classifications:
- *  - PROTO
- *  - SRC IP ADDRESS
- *  - DST IP ADDRESS
- *  - PORTS (SRC and DST)
- */
-enum {
-	RTE_ACL_IPV4_PROTO,
-	RTE_ACL_IPV4_SRC,
-	RTE_ACL_IPV4_DST,
-	RTE_ACL_IPV4_PORTS,
-	RTE_ACL_IPV4_NUM
-};
-
-struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
-	{
-	.type = RTE_ACL_FIELD_TYPE_BITMASK,
-	.size = sizeof(uint8_t),
-	.field_index = PROTO_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PROTO,
-	.offset = 0,
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = SRC_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_SRC,
-	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = DST_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_DST,
-	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = SRCP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = DSTP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
-		sizeof(uint16_t)
-	},
-};
-
-RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
-
-const struct acl4_rules acl4_rules_out[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 107, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 108, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 250, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-const struct acl4_rules acl4_rules_in[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 117, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 118, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-static void
-print_one_ipv4_rule(const struct acl4_rules *rule, int extra)
-{
-	unsigned char a, b, c, d;
-
-	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[SRC_FIELD_IPV4].mask_range.u32);
-	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[DST_FIELD_IPV4].mask_range.u32);
-	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
-		rule->field[SRCP_FIELD_IPV4].value.u16,
-		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
-		rule->field[DSTP_FIELD_IPV4].value.u16,
-		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
-		rule->field[PROTO_FIELD_IPV4].value.u8,
-		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
-	if (extra)
-		printf("0x%x-0x%x-0x%x ",
-			rule->data.category_mask,
-			rule->data.priority,
-			rule->data.userdata);
-}
-
-static inline void
-dump_ipv4_rules(const struct acl4_rules *rule, int num, int extra)
-{
-	int i;
-
-	for (i = 0; i < num; i++, rule++) {
-		printf("\t%d:", i + 1);
-		print_one_ipv4_rule(rule, extra);
-		printf("\n");
-	}
-}
-
-static struct rte_acl_ctx *
-acl4_init(const char *name, int socketid, const struct acl4_rules *rules,
-		unsigned rules_nb)
-{
-	char s[PATH_MAX];
-	struct rte_acl_param acl_param;
-	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);
-
-	memset(&acl_param, 0, sizeof(acl_param));
-
-	/* Create ACL contexts */
-	snprintf(s, sizeof(s), "%s_%d", name, socketid);
-
-	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
-	dump_ipv4_rules(rules, rules_nb, 1);
-
-	acl_param.name = s;
-	acl_param.socket_id = socketid;
-	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ipv4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
-
-	ctx = rte_acl_create(&acl_param);
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
-
-	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
-				rules_nb) < 0)
-		rte_exit(EXIT_FAILURE, "add rules failed\n");
-
-	/* Perform builds */
-	memset(&acl_build_param, 0, sizeof(acl_build_param));
-
-	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
-	acl_build_param.num_fields = RTE_DIM(ipv4_defs);
-	memcpy(&acl_build_param.defs, ipv4_defs, sizeof(ipv4_defs));
-
-	if (rte_acl_build(ctx, &acl_build_param) != 0)
-		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
-
-	rte_acl_dump(ctx);
-
-	return ctx;
-}
-
-void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
-{
-	const char *name;
-	const struct acl4_rules *rules_out, *rules_in;
-	unsigned nb_out_rules, nb_in_rules;
-
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "NULL context.\n");
-
-	if (ctx->sp_ipv4_in != NULL)
-		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ctx->sp_ipv4_out != NULL)
-		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ep == 0) {
-		rules_out = acl4_rules_out;
-		nb_out_rules = RTE_DIM(acl4_rules_out);
-		rules_in = acl4_rules_in;
-		nb_in_rules = RTE_DIM(acl4_rules_in);
-	} else if (ep == 1) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else
-		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
-				"Only 0 or 1 supported.\n", ep);
-
-	name = "sp_ipv4_in";
-	ctx->sp_ipv4_in = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_in, nb_in_rules);
-
-	name = "sp_ipv4_out";
-	ctx->sp_ipv4_out = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_out, nb_out_rules);
-}
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
new file mode 100644
index 0000000..61720c8
--- /dev/null
+++ b/examples/ipsec-secgw/sp4.c
@@ -0,0 +1,407 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+/*
+ * Rule and trace formats definitions.
+ */
+enum {
+	PROTO_FIELD_IPV4,
+	SRC_FIELD_IPV4,
+	DST_FIELD_IPV4,
+	SRCP_FIELD_IPV4,
+	DSTP_FIELD_IPV4,
+	NUM_FIELDS_IPV4
+};
+
+/*
+ * That effectively defines order of IPV4 classifications:
+ *  - PROTO
+ *  - SRC IP ADDRESS
+ *  - DST IP ADDRESS
+ *  - PORTS (SRC and DST)
+ */
+enum {
+	RTE_ACL_IPV4_PROTO,
+	RTE_ACL_IPV4_SRC,
+	RTE_ACL_IPV4_DST,
+	RTE_ACL_IPV4_PORTS,
+	RTE_ACL_IPV4_NUM
+};
+
+struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = PROTO_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = SRC_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_SRC,
+	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = DST_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_DST,
+	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = SRCP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = DSTP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
+		sizeof(uint16_t)
+	},
+};
+
+RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
+
+const struct acl4_rules acl4_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 201, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 55, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 56, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 241, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl4_rules acl4_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(105), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(106), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(116), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 211, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 65, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 66, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 245, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 246, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static void
+print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[SRC_FIELD_IPV4].mask_range.u32);
+	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[DST_FIELD_IPV4].mask_range.u32);
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[SRCP_FIELD_IPV4].value.u16,
+		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
+		rule->field[DSTP_FIELD_IPV4].value.u16,
+		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
+		rule->field[PROTO_FIELD_IPV4].value.u8,
+		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip4_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip4_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip4_defs);
+	memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl4_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip4_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ctx->sp_ip4_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl4_rules_out;
+		nb_out_rules = RTE_DIM(acl4_rules_out);
+		rules_in = acl4_rules_in;
+		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip4_in";
+	ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip4_out";
+	ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
new file mode 100644
index 0000000..c6fb851
--- /dev/null
+++ b/examples/ipsec-secgw/sp6.c
@@ -0,0 +1,400 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+enum {
+	IP6_PROTO,
+	IP6_SRC0,
+	IP6_SRC1,
+	IP6_SRC2,
+	IP6_SRC3,
+	IP6_DST0,
+	IP6_DST1,
+	IP6_DST2,
+	IP6_DST3,
+	IP6_SRCP,
+	IP6_DSTP,
+	IP6_NUM
+};
+
+#define IP6_ADDR_SIZE 16
+
+struct rte_acl_field_def ip6_defs[IP6_NUM] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = IP6_PROTO,
+	.input_index = IP6_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC0,
+	.input_index = IP6_SRC0,
+	.offset = 2
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC1,
+	.input_index = IP6_SRC1,
+	.offset = 6
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC2,
+	.input_index = IP6_SRC2,
+	.offset = 10
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC3,
+	.input_index = IP6_SRC3,
+	.offset = 14
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST0,
+	.input_index = IP6_DST0,
+	.offset = 18
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST1,
+	.input_index = IP6_DST1,
+	.offset = 22
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST2,
+	.input_index = IP6_DST2,
+	.offset = 26
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST3,
+	.input_index = IP6_DST3,
+	.offset = 30
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_SRCP,
+	.input_index = IP6_SRCP,
+	.offset = 34
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_DSTP,
+	.input_index = IP6_SRCP,
+	.offset = 36
+	}
+};
+
+RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
+
+const struct acl6_rules acl6_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl6_rules acl6_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static inline void
+print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_SRC0].mask_range.u32
+			+ rule->field[IP6_SRC1].mask_range.u32
+			+ rule->field[IP6_SRC2].mask_range.u32
+			+ rule->field[IP6_SRC3].mask_range.u32);
+
+	uint32_t_to_char(rule->field[IP6_DST0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_DST0].mask_range.u32
+			+ rule->field[IP6_DST1].mask_range.u32
+			+ rule->field[IP6_DST2].mask_range.u32
+			+ rule->field[IP6_DST3].mask_range.u32);
+
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[IP6_SRCP].value.u16,
+		rule->field[IP6_SRCP].mask_range.u16,
+		rule->field[IP6_DSTP].value.u16,
+		rule->field[IP6_DSTP].mask_range.u16,
+		rule->field[IP6_PROTO].value.u8,
+		rule->field[IP6_PROTO].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip6_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip6_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip6_defs);
+	memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl6_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip6_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ctx->sp_ip6_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl6_rules_out;
+		nb_out_rules = RTE_DIM(acl6_rules_out);
+		rules_in = acl6_rules_in;
+		nb_in_rules = RTE_DIM(acl6_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl6_rules_in;
+		nb_out_rules = RTE_DIM(acl6_rules_in);
+		rules_in = acl6_rules_out;
+		nb_in_rules = RTE_DIM(acl6_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip6_in";
+	ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip6_out";
+	ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 8/9] examples/ipsec-secgw: transport mode support
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (6 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

IPSec transport mode support.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   | 124 ++++++++++++++++++++++++++++++-------------
 examples/ipsec-secgw/ipsec.h |   1 +
 examples/ipsec-secgw/rt.c    |  32 +++++++++++
 examples/ipsec-secgw/sa.c    |  39 ++++++++++++++
 examples/ipsec-secgw/sp4.c   |  40 ++++++++++++++
 examples/ipsec-secgw/sp6.c   |  48 +++++++++++++++++
 6 files changed, 248 insertions(+), 36 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index e1fde36..05caa77 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -42,7 +42,6 @@
 #include <unistd.h>
 
 #include <rte_common.h>
-#include <rte_memcpy.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_random.h>
@@ -70,21 +69,24 @@ int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len, ip_hdr_len;
+	struct ip *ip4;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t payload_len, ip_hdr_len;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
-		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION))
+		ip_hdr_len = ip4->ip_hl * 4;
+	else if (ip4->ip_v == IP6_VERSION)
+		/* XXX No option headers supported */
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
+	else {
+		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
 	}
 
 	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
@@ -126,6 +128,8 @@ int
 esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
+	struct ip *ip4, *ip;
+	struct ip6_hdr *ip6;
 	uint8_t *nexthdr, *pad_len;
 	uint8_t *padding;
 	uint16_t i;
@@ -135,7 +139,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	RTE_ASSERT(cop != NULL);
 
 	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
-		RTE_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
+		RTE_LOG(ERR, IPSEC_ESP, "failed crypto op\n");
 		return -1;
 	}
 
@@ -146,7 +150,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
 		if (padding[i] != i + 1) {
-			RTE_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
+			RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
 			return -EINVAL;
 		}
 	}
@@ -157,7 +161,23 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	if (unlikely(sa->flags == TRANSPORT)) {
+		ip = rte_pktmbuf_mtod(m, struct ip *);
+		ip4 = (struct ip *)rte_pktmbuf_adj(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		if (likely(ip->ip_v == IPVERSION)) {
+			memmove(ip4, ip, ip->ip_hl * 4);
+			ip4->ip_p = *nexthdr;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)ip4;
+			/* XXX No option headers supported */
+			memmove(ip6, ip, sizeof(struct ip6_hdr));
+			ip6->ip6_nxt = *nexthdr;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
+	} else
+		ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
 
 	return 0;
 }
@@ -166,31 +186,57 @@ int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 	struct ip *ip4;
 	struct ip6_hdr *ip6;
-	struct esp_hdr *esp;
-	int32_t i;
-	char *padding;
+	struct esp_hdr *esp = NULL;
+	uint8_t *padding, *new_ip, nlp;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t i;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	/* Payload length */
-	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) + 2,
-			sa->block_size);
-	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
-
 	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
+
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION)) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			ip_hdr_len = ip4->ip_hl * 4;
+			nlp = ip4->ip_p;
+		} else
+			nlp = IPPROTO_IPIP;
+	} else if (ip4->ip_v == IP6_VERSION) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			/* XXX No option headers supported */
+			ip_hdr_len = sizeof(struct ip6_hdr);
+			ip6 = (struct ip6_hdr *)ip4;
+			nlp = ip6->ip6_nxt;
+		} else
+			nlp = IPPROTO_IPV6;
+	} else {
+		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
+	}
+
+	/* Padded payload length */
+	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) -
+			ip_hdr_len + 2, sa->block_size);
+	pad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);
+
+	RTE_ASSERT(sa->flags == IP4_TUNNEL || sa->flags == IP6_TUNNEL ||
+			sa->flags == TRANSPORT);
+
+	if (likely(sa->flags == IP4_TUNNEL))
 		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	else if (sa->flags == IP6_TUNNEL)
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
+	else if (sa->flags != TRANSPORT) {
+		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
+				sa->flags);
+		return -EINVAL;
 	}
 
 	/* Check maximum packet size */
@@ -200,7 +246,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	padding = (uint8_t *)rte_pktmbuf_append(m, pad_len + sa->digest_len);
 	if (unlikely(padding == NULL)) {
 		RTE_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
 		return -ENOSPC;
@@ -218,10 +264,20 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 				&sa->src, &sa->dst);
 		esp = (struct esp_hdr *)(ip6 + 1);
 		break;
-	default:
-		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
-				sa->flags);
-		return -EINVAL;
+	case TRANSPORT:
+		new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		memmove(new_ip, ip4, ip_hdr_len);
+		esp = (struct esp_hdr *)(new_ip + ip_hdr_len);
+		if (likely(ip4->ip_v == IPVERSION)) {
+			ip4 = (struct ip *)new_ip;
+			ip4->ip_p = IPPROTO_ESP;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)new_ip;
+			ip6->ip6_nxt = IPPROTO_ESP;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
 	}
 
 	sa->seq++;
@@ -235,11 +291,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
 	padding[pad_len - 2] = pad_len - 2;
-
-	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
-		padding[pad_len - 1] = IPPROTO_IPIP;
-	else
-		padding[pad_len - 1] = IPPROTO_IPV6;
+	padding[pad_len - 1] = nlp;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 83d7b1c..0d2ee25 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -103,6 +103,7 @@ struct ipsec_sa {
 	uint16_t flags;
 #define IP4_TUNNEL (1 << 0)
 #define IP6_TUNNEL (1 << 1)
+#define TRANSPORT  (1 << 2)
 	struct ip_addr src;
 	struct ip_addr dst;
 	struct rte_crypto_sym_xform *xforms;
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index d46df49..fa5f042 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -62,6 +62,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
 	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 0 },
+	{ IPv4(192, 168, 176, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 0 },
 	{ IPv4(192, 168, 241, 0), 24, 1 },
@@ -72,6 +75,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	{ IPv4(192, 168, 116, 0), 24, 3 },
 	{ IPv4(192, 168, 65, 0), 24, 2 },
 	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 2 },
+	{ IPv4(192, 168, 186, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
 	{ IPv4(192, 168, 211, 0), 24, 3 },
@@ -87,6 +93,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
 	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 	/* Inbound */
 	/* Tunnels */
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
@@ -97,6 +108,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 static struct ip4_route rt_ip4_ep1[] = {
@@ -104,6 +120,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 1, 5), 32, 0 },
 	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 0 },
+	{ IPv4(192, 168, 186, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 245, 0), 24, 0 },
 	{ IPv4(192, 168, 246, 0), 24, 1 },
@@ -114,6 +133,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	{ IPv4(192, 168, 106, 0), 24, 3 },
 	{ IPv4(192, 168, 55, 0), 24, 2 },
 	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 2 },
+	{ IPv4(192, 168, 176, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 200, 0), 24, 2 },
 	{ IPv4(192, 168, 201, 0), 24, 3 },
@@ -129,6 +151,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
 	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 
 	/* Inbound */
 	/* Tunnels */
@@ -140,6 +167,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8b54beb..ab18b81 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -74,6 +74,24 @@ const struct ipsec_sa sa_out[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 10,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 11,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 15,
 	.src.ip4 = IPv4(172, 16, 1, 5),
 	.dst.ip4 = IPv4(172, 16, 2, 5),
@@ -148,6 +166,24 @@ const struct ipsec_sa sa_in[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 110,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 111,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 115,
 	.src.ip4 = IPv4(172, 16, 2, 5),
 	.dst.ip4 = IPv4(172, 16, 1, 5),
@@ -447,6 +483,9 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 				!memcmp(&sa->src.ip6, src6_addr, 16) &&
 				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
 			*sa_ret = sa;
+		break;
+	case TRANSPORT:
+		*sa_ret = sa;
 	}
 }
 
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 61720c8..9c4b256 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -135,6 +135,26 @@ const struct acl4_rules acl4_rules_out[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 175, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 176, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
@@ -218,6 +238,26 @@ const struct acl4_rules acl4_rules_in[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 185, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 186, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index c6fb851..1dda11a 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -170,6 +170,30 @@ const struct acl6_rules acl6_rules_out[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
@@ -221,6 +245,30 @@ const struct acl6_rules acl6_rules_in[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
-- 
2.5.5

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

* [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (7 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
@ 2016-05-18 12:42   ` Sergio Gonzalez Monroy
  2016-05-18 13:43     ` Mcnamara, John
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-05-18 12:42 UTC (permalink / raw)
  To: dev; +Cc: john.mcnamara

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 doc/guides/sample_app_ug/img/ipsec_endpoints.svg | 850 +++++++++++++++++++++
 doc/guides/sample_app_ug/ipsec_secgw.rst         | 910 ++++++++++++++---------
 2 files changed, 1400 insertions(+), 360 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/img/ipsec_endpoints.svg

diff --git a/doc/guides/sample_app_ug/img/ipsec_endpoints.svg b/doc/guides/sample_app_ug/img/ipsec_endpoints.svg
new file mode 100644
index 0000000..e4aba4c
--- /dev/null
+++ b/doc/guides/sample_app_ug/img/ipsec_endpoints.svg
@@ -0,0 +1,850 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="155.68507mm"
+   height="76.061203mm"
+   viewBox="0 0 551.64003 269.50821"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="endpoints.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker18451"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path18453"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker18273"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path18275" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10612"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Send">
+      <path
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#cfce37;fill-opacity:1;fill-rule:evenodd;stroke:#cfce37;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path10614"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10270"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path10272"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Sstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker9102"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path9104"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#035002;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.2,0,0,0.2,1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Sstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Sstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5945"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#d4ce00;fill-opacity:1;fill-rule:evenodd;stroke:#d4ce00;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.2,0,0,0.2,1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       id="linearGradient11398"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11400" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11402" />
+    </linearGradient>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9540"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9542"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       id="linearGradient9336"
+       osb:paint="solid">
+      <stop
+         style="stop-color:#dc181a;stop-opacity:1;"
+         offset="0"
+         id="stop9338" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7350"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7352"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4871"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7092"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path7094"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5822"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5824"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path5371"
+         style="fill:#035002;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5013"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="scale(0.8,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Tail"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Tail"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <g
+         id="g4907"
+         transform="scale(-1.2,-1.2)"
+         style="fill:#528ac6;fill-opacity:1;stroke:#000000;stroke-opacity:1">
+        <path
+           id="path4909"
+           d="M -3.8048674,-3.9585227 0.54352094,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4911"
+           d="M -1.2866832,-3.9585227 3.0617053,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4913"
+           d="M 1.3053582,-3.9585227 5.6537466,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4915"
+           d="M -3.8048674,4.1775838 0.54352094,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4917"
+           d="M -1.2866832,4.1775838 3.0617053,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4919"
+           d="M 1.3053582,4.1775838 5.6537466,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+      </g>
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Send"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4904"
+         style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4886"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4874"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4-3"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7-7"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7-1"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-1"
+         style="fill:#d4ce00;fill-opacity:1;fill-rule:evenodd;stroke:#d4ce00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-9"
+         style="fill:#38782d;fill-opacity:1;fill-rule:evenodd;stroke:#38782d;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-3-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-1-0"
+         style="fill:#38782d;fill-opacity:1;fill-rule:evenodd;stroke:#38782d;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker18451-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path18453-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart-7"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4871-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7350-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7352-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="258.01346"
+     inkscape:cy="122.99559"
+     inkscape:document-units="cm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     inkscape:window-x="1592"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     fit-margin-top="3"
+     fit-margin-right="1"
+     fit-margin-bottom="1"
+     fit-margin-left="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(194.35761,4.2637303)">
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5"
+       width="131.15564"
+       height="102.30846"
+       x="-179.57692"
+       y="140.22072"
+       ry="7.155364" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-1"
+       width="131.15564"
+       height="102.30846"
+       x="213.55591"
+       y="140.22072"
+       ry="6.5590839" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-2"
+       width="131.15564"
+       height="46.258114"
+       x="-179.57692"
+       y="6.3661909"
+       ry="5.3665228" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-2-7"
+       width="131.15564"
+       height="46.258114"
+       x="213.55591"
+       y="6.3661909"
+       ry="6.5590839" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-182.36929"
+       y="188.59424"
+       id="text4210"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4212"
+         x="-182.36929"
+         y="188.59424">ep0</tspan><tspan
+         sodipodi:role="line"
+         x="-182.36929"
+         y="208.69011"
+         id="tspan4214" /><tspan
+         sodipodi:role="line"
+         x="-182.36929"
+         y="228.786"
+         id="tspan4216" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="324.621"
+       y="188.49612"
+       id="text4218"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4220"
+         x="324.621"
+         y="188.49612">ep1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-159.97678"
+       y="32.860863"
+       id="text4222"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4224"
+         x="-159.97678"
+         y="32.860863">traffic gen</tspan><tspan
+         sodipodi:role="line"
+         x="-159.97678"
+         y="52.956738"
+         id="tspan4226" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="249.77068"
+       y="32.860863"
+       id="text4222-1"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4224-1"
+         x="249.77068"
+         y="32.860863">traffic gen</tspan><tspan
+         sodipodi:role="line"
+         x="249.77068"
+         y="52.956738"
+         id="tspan4226-6" /></text>
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="m -48.997848,184.52811 c 260.957198,-0.5963 260.957198,-0.5963 260.957198,-0.5963"
+       id="path5305"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker10270)"
+       d="M -47.641399,212.81116 C 213.3158,212.21487 213.3158,212.21487 213.3158,212.21487"
+       id="path5305-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7350)"
+       d="m 262.8239,53.615939 c 0,85.864371 0,85.864371 0,85.864371"
+       id="path5922-0-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
+       d="m -146.8568,54.80849 c 0,85.86437 0,85.86437 0,85.86437"
+       id="path5922-0-1"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="246.78571"
+       y="500.57648"
+       id="text7750"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7752"
+         x="246.78571"
+         y="500.57648" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-158.9595"
+       y="151.84753"
+       id="text7754"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7756"
+         x="-158.9595"
+         y="151.84753">2</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-110.66317"
+       y="151.84753"
+       id="text7758"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7760"
+         x="-110.66317"
+         y="151.84753">3</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="267.07309"
+       y="151.84753"
+       id="text7762"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7764"
+         x="267.07309"
+         y="151.84753">2</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="318.81448"
+       y="151.84753"
+       id="text7766"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7768"
+         x="318.81448"
+         y="151.84753">3</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="225.86406"
+       y="183.73483"
+       id="text7770"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7772"
+         x="225.86406"
+         y="183.73483">0</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="226.18214"
+       y="211.56969"
+       id="text7774"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7776"
+         x="226.18214"
+         y="211.56969">1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:11.25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="311.78571"
+       y="505.93362"
+       id="text7778"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7780"
+         x="311.78571"
+         y="505.93362" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-65.239075"
+       y="183.73483"
+       id="text7782"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7784"
+         x="-65.239075"
+         y="183.73483">0</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-64.921005"
+       y="211.56969"
+       id="text7786"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7788"
+         x="-64.921005"
+         y="211.56969">1</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#dc181a;stroke-width:1.60606241;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:3.21212486, 9.63637456;stroke-dashoffset:0;stroke-opacity:1"
+       d="M -190.00162,248.33118 C -74.638406,174.62535 10.240093,56.871479 81.499676,57.515772 176.72224,59.019701 245.16177,197.27679 352.92565,246.54234"
+       id="path7850"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#dc181a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="84.985992"
+       y="98.449951"
+       id="text7876"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7878"
+         x="84.985992"
+         y="98.449951">UNPROTECTED</tspan><tspan
+         sodipodi:role="line"
+         x="84.985992"
+         y="118.54583"
+         id="tspan7886">cipher-text</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#dc181a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="84.899643"
+       y="20.937273"
+       id="text7880"
+       sodipodi:linespacing="125%"
+       inkscape:transform-center-x="48.100163"
+       inkscape:transform-center-y="3.577681"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7882"
+         x="84.899643"
+         y="20.937273">PROTECTED</tspan><tspan
+         sodipodi:role="line"
+         x="84.899643"
+         y="41.03315"
+         id="tspan7884">clear-text</tspan></text>
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:3.42781782;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5369)"
+       d="m -101.57521,164.71986 c -0.0232,13.22578 17.528492,19.5572 32.486212,20.12768"
+       id="path9370"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:3.08351111;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5369-3)"
+       d="m 231.46374,184.56991 c 19.27508,-1.72507 24.47287,-7.77038 31.06883,-19.63365"
+       id="path9370-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.8206749px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="60.45417"
+       y="251.78688"
+       id="text14635"
+       sodipodi:linespacing="125%"
+       transform="scale(0.9630889,1.0383257)"><tspan
+         sodipodi:role="line"
+         id="tspan14637"
+         x="60.45417"
+         y="251.78688">outbound</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="62.073208"
+       y="232.23116"
+       id="text14635-4"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan14637-2"
+         x="62.073208"
+         y="232.23116">inbound</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:3.8278625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Sstart)"
+       d="m -144.07995,171.20523 c 15.90052,30.60035 40.80354,39.04445 75.670299,43.29761"
+       id="path9370-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:3.73783302;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker9102)"
+       d="m 236.99654,212.30897 c 40.08586,-4.29157 62.39356,-19.33069 76.11102,-48.84339"
+       id="path9370-8-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:4.01917505;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 32.274837,235.80819 c 18.037567,-0.2236 20.456397,-0.29813 20.456397,-0.29813"
+       id="path10604"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#035002;stroke-width:4.01917505;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 32.274837,256.82674 c 18.037567,-0.22362 20.456397,-0.29814 20.456397,-0.29814"
+       id="path10604-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart-7)"
+       d="m -100.78618,138.21108 c 0,-85.864363 0,-85.864363 0,-85.864363"
+       id="path5922-0-1-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7350-9)"
+       d="m 312.42811,137.49681 c 0,-85.864382 0,-85.864382 0,-85.864382"
+       id="path5922-0-6-9"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index c11c7e7..66dd326 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -38,165 +38,171 @@ Overview
 --------
 
 The application demonstrates the implementation of a Security Gateway
-(not IPsec compliant, see Constraints bellow) using DPDK based on RFC4301,
+(not IPsec compliant, see the Constraints section below) using DPDK based on RFC4301,
 RFC4303, RFC3602 and RFC2404.
 
 Internet Key Exchange (IKE) is not implemented, so only manual setting of
 Security Policies and Security Associations is supported.
 
 The Security Policies (SP) are implemented as ACL rules, the Security
-Associations (SA) are stored in a table and the Routing is implemented
+Associations (SA) are stored in a table and the routing is implemented
 using LPM.
 
-The application classify the ports between Protected and Unprotected.
-Thus, traffic received in an Unprotected or Protected port is consider
+The application classifies the ports as *Protected* and *Unprotected*.
+Thus, traffic received on an Unprotected or Protected port is consider
 Inbound or Outbound respectively.
 
-Path for IPsec Inbound traffic:
+The Path for IPsec Inbound traffic is:
 
-*  Read packets from the port
+*  Read packets from the port.
 *  Classify packets between IPv4 and ESP.
-*  Inbound SA lookup for ESP packets based on their SPI
-*  Verification/Decryption
-*  Removal of ESP and outer IP header
-*  Inbound SP check using ACL of decrypted packets and any other IPv4 packet
-   we read.
-*  Routing
-*  Write packet to port
-
-Path for IPsec Outbound traffic:
-
-*  Read packets from the port
-*  Outbound SP check using ACL of all IPv4 traffic
-*  Outbound SA lookup for packets that need IPsec protection
-*  Add ESP and outer IP header
-*  Encryption/Digest
-*  Routing
-*  Write packet to port
+*  Perform Inbound SA lookup for ESP packets based on their SPI.
+*  Perform Verification/Decryption.
+*  Remove ESP and outer IP header
+*  Inbound SP check using ACL of decrypted packets and any other IPv4 packets.
+*  Routing.
+*  Write packet to port.
+
+The Path for the IPsec Outbound traffic is:
+
+*  Read packets from the port.
+*  Perform Outbound SP check using ACL of all IPv4 traffic.
+*  Perform Outbound SA lookup for packets that need IPsec protection.
+*  Add ESP and outer IP header.
+*  Perform Encryption/Digest.
+*  Routing.
+*  Write packet to port.
+
 
 Constraints
 -----------
-*  IPv4 traffic
-*  ESP tunnel mode
-*  EAS-CBC, HMAC-SHA1 and NULL
-*  Each SA must be handle by a unique lcore (1 RX queue per port)
-*  No chained mbufs
+
+*  No IPv6 options headers.
+*  No AH mode.
+*  Currently only EAS-CBC, HMAC-SHA1 and NULL.
+*  Each SA must be handle by a unique lcore (*1 RX queue per port*).
+*  No chained mbufs.
+
 
 Compiling the Application
 -------------------------
 
 To compile the application:
 
-#. Go to the sample application directory:
-
-   .. code-block:: console
+#. Go to the sample application directory::
 
       export RTE_SDK=/path/to/rte_sdk
       cd ${RTE_SDK}/examples/ipsec-secgw
 
-#. Set the target (a default target is used if not specified). For example:
+#. Set the target (a default target is used if not specified). For example::
 
-   .. code-block:: console
 
       export RTE_TARGET=x86_64-native-linuxapp-gcc
 
    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
 
-#. Build the application:
-
-   .. code-block:: console
+#. Build the application::
 
        make
 
+#. [Optional] Build the application for debugging:
+   This option adds some extra flags, disables compiler optimizations and
+   is verbose::
+
+       make DEBUG=1
+
+
 Running the Application
 -----------------------
 
-The application has a number of command line options:
+The application has a number of command line options::
 
-.. code-block:: console
 
-   ./build/ipsec-secgw [EAL options] -- -p PORTMASK -P -u PORTMASK --config
-   (port,queue,lcore)[,(port,queue,lcore] --single-sa SAIDX --ep0|--ep1
+   ./build/ipsec-secgw [EAL options] --
+                        -p PORTMASK -P -u PORTMASK
+                        --config (port,queue,lcore)[,(port,queue,lcore]
+                        --single-sa SAIDX
+			--ep0|--ep1
 
-where,
+Where:
 
-*   -p PORTMASK: Hexadecimal bitmask of ports to configure
+*   ``-p PORTMASK``: Hexadecimal bitmask of ports to configure.
 
-*   -P: optional, sets all ports to promiscuous mode so that packets are
+*   ``-P``: *optional*. Sets all ports to promiscuous mode so that packets are
     accepted regardless of the packet's Ethernet MAC destination address.
     Without this option, only packets with the Ethernet MAC destination address
     set to the Ethernet address of the port are accepted (default is enabled).
 
-*   -u PORTMASK: hexadecimal bitmask of unprotected ports
+*   ``-u PORTMASK``: hexadecimal bitmask of unprotected ports
 
-*   --config (port,queue,lcore)[,(port,queue,lcore)]: determines which queues
-    from which ports are mapped to which cores
+*   ``--config (port,queue,lcore)[,(port,queue,lcore)]``: determines which queues
+    from which ports are mapped to which cores.
 
-*   --single-sa SAIDX: use a single SA for outbound traffic, bypassing the SP
+*   ``--single-sa SAIDX``: use a single SA for outbound traffic, bypassing the SP
     on both Inbound and Outbound. This option is meant for debugging/performance
     purposes.
 
-*   --ep0: configure the app as Endpoint 0.
+*   ``--ep0``: configure the app as Endpoint 0.
 
-*   --ep1: configure the app as Endpoint 1.
+*   ``--ep1``: configure the app as Endpoint 1.
 
-Either one of --ep0 or --ep1 *must* be specified.
-The main purpose of these options is two easily configure two systems
-back-to-back that would forward traffic through an IPsec tunnel.
+Either one of ``--ep0`` or ``--ep1`` **must** be specified.
+The main purpose of these options is to easily configure two systems
+back-to-back that would forward traffic through an IPsec tunnel (see
+:ref:`figure_ipsec_endpoints`).
 
 The mapping of lcores to port/queues is similar to other l3fwd applications.
 
-For example, given the following command line:
+For example, given the following command line::
 
-.. code-block:: console
-
-    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
-           --vdev "cryptodev_null_pmd" -- -p 0xf -P -u 0x3
-           --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" --ep0
+    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048       \
+           --vdev "cryptodev_null_pmd" -- -p 0xf -P -u 0x3      \
+           --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" --ep0 \
 
 where each options means:
 
-*   The -l option enables cores 20 and 21
+*   The ``-l`` option enables cores 20 and 21.
 
-*   The -n option sets memory 4 channels
+*   The ``-n`` option sets memory 4 channels.
 
-*   The --socket-mem to use 2GB on socket 1
+*   The ``--socket-mem`` to use 2GB on socket 1.
 
-*   The --vdev "cryptodev_null_pmd" option creates virtual NULL cryptodev PMD
+*   The ``--vdev "cryptodev_null_pmd"`` option creates virtual NULL cryptodev PMD.
 
-*   The -p option enables ports (detected) 0, 1, 2 and 3
+*   The ``-p`` option enables ports (detected) 0, 1, 2 and 3.
 
-*   The -P option enables promiscuous mode
+*   The ``-P`` option enables promiscuous mode.
 
-*   The -u option sets ports 1 and 2 as unprotected, leaving 2 and 3 as protected
+*   The ``-u`` option sets ports 1 and 2 as unprotected, leaving 2 and 3 as protected.
 
-*   The --config option enables one queue per port with the following mapping:
+*   The ``--config`` option enables one queue per port with the following mapping:
 
-+----------+-----------+-----------+---------------------------------------+
-| **Port** | **Queue** | **lcore** | **Description**                       |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 0        | 0         | 20        | Map queue 0 from port 0 to lcore 20.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 1        | 0         | 20        | Map queue 0 from port 1 to lcore 20.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 2        | 0         | 21        | Map queue 0 from port 2 to lcore 21.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 3        | 0         | 21        | Map queue 0 from port 3 to lcore 21.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
+    +----------+-----------+-----------+---------------------------------------+
+    | **Port** | **Queue** | **lcore** | **Description**                       |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 0        | 0         | 20        | Map queue 0 from port 0 to lcore 20.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 1        | 0         | 20        | Map queue 0 from port 1 to lcore 20.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 2        | 0         | 21        | Map queue 0 from port 2 to lcore 21.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 3        | 0         | 21        | Map queue 0 from port 3 to lcore 21.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
 
-*   The --ep0 options configures the app with a given set of SP, SA and Routing
+*   The ``--ep0`` options configures the app with a given set of SP, SA and Routing
     entries as explained below in more detail.
 
 Refer to the *DPDK Getting Started Guide* for general information on running
 applications and the Environment Abstraction Layer (EAL) options.
 
 The application would do a best effort to "map" crypto devices to cores, with
-hardware devices having priority.
+hardware devices having priority. Basically, hardware devices if present would
+be assigned to a core before software ones.
 This means that if the application is using a single core and both hardware
 and software crypto devices are detected, hardware devices will be used.
 
@@ -208,18 +214,35 @@ For example, something like the following command line:
 
 .. code-block:: console
 
-    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
-            -w 81:00.0 -w 81:00.1 -w 81:00.2 -w 81:00.3
-            --vdev "cryptodev_aesni_mb_pmd" --vdev "cryptodev_null_pmd" --
-            -p 0xf -P -u 0x3 --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)"
+    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048 \
+            -w 81:00.0 -w 81:00.1 -w 81:00.2 -w 81:00.3 \
+            --vdev "cryptodev_aesni_mb_pmd" --vdev "cryptodev_null_pmd" \
+	    -- \
+            -p 0xf -P -u 0x3 --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" \
             --ep0
 
+
 Configurations
 --------------
 
 The following sections provide some details on the default values used to
 initialize the SP, SA and Routing tables.
-Currently all the configuration is hard coded into the application.
+Currently all configuration information is hard coded into the application.
+
+The following image illustrate a few of the concepts regarding IPSec, such
+as protected/unprotected and inbound/outbound traffic, from the point of
+view of two back-to-back endpoints:
+
+.. _figure_ipsec_endpoints:
+
+.. figure:: img/ipsec_endpoints.svg
+
+   IPSec Inbound/Outbound traffic
+
+Note that the above image only displays unidirectional traffic per port
+for illustration purposes.
+The application supports bidirectional traffic on all ports,
+
 
 Security Policy Initialization
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -228,107 +251,126 @@ As mention in the overview, the Security Policies are ACL rules.
 The application defines two ACLs, one each of Inbound and Outbound, and
 it replicates them per socket in use.
 
-Following are the default rules:
-
-Endpoint 0 Outbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 0 Inbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Outbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Inbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
+Following are the default rules which show only the relevant information,
+assuming ANY value is valid for the fields not mentioned (src ip, proto,
+src/dst ports).
+
+.. _table_ipsec_endpoint_outbound_sp:
+
+.. table:: Endpoint 0 Outbound Security Policies
+
+   +-----------------------------------+------------+
+   | **Dst**                           | **SA idx** |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.105.0/24                  | 5          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.106.0/24                  | 6          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.175.0/24                  | 10         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.176.0/24                  | 11         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.200.0/24                  | 15         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.201.0/24                  | 16         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.55.0/24                   | 25         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.56.0/24                   | 26         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.240.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.241.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:5555:5555:0:0/96          | 5          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:6666:6666:0:0/96          | 6          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:1111:1111:0:0:0:0/96          | 10         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:1111:1111:1111:1111:0:0/96    | 11         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:aaaa:aaaa:0:0/96          | 25         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:bbbb:bbbb:0:0/96          | 26         |
+   |                                   |            |
+   +-----------------------------------+------------+
+
+.. _table_ipsec_endpoint_inbound_sp:
+
+.. table:: Endpoint 0 Inbound Security Policies
+
+   +-----------------------------------+------------+
+   | **Dst**                           | **SA idx** |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.115.0/24                  | 105        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.116.0/24                  | 106        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.185.0/24                  | 110        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.186.0/24                  | 111        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.210.0/24                  | 115        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.211.0/24                  | 116        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.65.0/24                   | 125        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.66.0/24                   | 126        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.245.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.246.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:5555:5555:0:0/96       | 105        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:6666:6666:0:0/96       | 106        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:1111:1111:0:0:0:0/96       | 110        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:1111:1111:1111:1111:0:0/96 | 111        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:aaaa:aaaa:0:0/96       | 125        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:bbbb:bbbb:0:0/96       | 126        |
+   |                                   |            |
+   +-----------------------------------+------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
 
 
 Security Association Initialization
@@ -336,7 +378,7 @@ Security Association Initialization
 
 The SAs are kept in a array table.
 
-For Inbound, the SPI is used as index module the table size.
+For Inbound, the SPI is used as index modulo the table size.
 This means that on a table for 100 SA, SPI 5 and 105 would use the same index
 and that is not currently supported.
 
@@ -346,179 +388,327 @@ not the SPI in the Security Policy.
 All SAs configured with AES-CBC and HMAC-SHA1 share the same values for cipher
 block size and key, and authentication digest size and key.
 
-Following are the default values:
-
-Endpoint 0 Outbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 0 Inbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Outbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Inbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
+The following are the default values:
+
+.. _table_ipsec_endpoint_outbound_sa:
+
+.. table:: Endpoint 0 Outbound Security Associations
+
+   +---------+----------+------------+-----------+----------------+----------------+
+   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 5       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 6       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 10      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 11      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 15      | Tunnel   | NULL       | NULL      | 172.16.1.5     | 172.16.2.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 16      | Tunnel   | NULL       | NULL      | 172.16.1.6     | 172.16.2.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 25      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:5555      | 2222:5555      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 26      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:6666      | 2222:6666      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+
+.. _table_ipsec_endpoint_inbound_sa:
+
+.. table:: Endpoint 0 Inbound Security Associations
+
+   +---------+----------+------------+-----------+----------------+----------------+
+   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 105     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 106     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 110     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 111     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 115     | Tunnel   | NULL       | NULL      | 172.16.2.5     | 172.16.1.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 116     | Tunnel   | NULL       | NULL      | 172.16.2.6     | 172.16.1.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 125     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:5555      | 1111:5555      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 126     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:6666      | 1111:6666      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
+
 
 Routing Initialization
 ~~~~~~~~~~~~~~~~~~~~~~
 
-The Routing is implemented using LPM table.
+The Routing is implemented using an LPM table.
 
 Following default values:
 
-Endpoint 0 Routing Table:
-
-+------------------+----------+
-| **Dst addr**     | **Port** |
-|                  |          |
-+------------------+----------+
-| 172.16.2.5/32    | 0        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.6/32    | 0        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.7/32    | 1        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.8/32    | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.115.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.116.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.117.0/24 | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.118.0/24 | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.210.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.240.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.250.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-
-Endpoint 1 Routing Table:
-
-+------------------+----------+
-| **Dst addr**     | **Port** |
-|                  |          |
-+------------------+----------+
-| 172.16.1.5/32    | 2        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.6/32    | 2        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.7/32    | 3        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.8/32    | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.105.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.106.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.107.0/24 | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.108.0/24 | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.200.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.240.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.250.0/24 | 0        |
-|                  |          |
-+------------------+----------+
+.. _table_ipsec_endpoint_outbound_routing:
+
+.. table:: Endpoint 0 Routing Table
+
+   +------------------+----------+
+   | **Dst addr**     | **Port** |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.2.5/32    | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.2.6/32    | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.175.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.176.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.240.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.241.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.115.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.116.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.65.0/24  | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.66.0/24  | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.185.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.186.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.210.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.211.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.245.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.246.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 2222:2222:       | 0        |
+   | 2222:2222:       |          |
+   | 2222:2222:       |          |
+   | 2222:5555/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 2222:2222:       | 1        |
+   | 2222:2222:       |          |
+   | 2222:2222:       |          |
+   | 2222:6666/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 0        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 0000:0000:       |          |
+   | aaaa:aaaa:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 0000:0000:       |          |
+   | bbbb:bbbb:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 0000:0000:       |          |
+   | 5555:5555:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 0000:0000:       |          |
+   | 6666:6666:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+
+.. _table_ipsec_endpoint_inbound_routing:
+
+.. table:: Endpoint 1 Routing Table
+
+   +------------------+----------+
+   | **Dst addr**     | **Port** |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.1.5/32    | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.1.6/32    | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.185.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.186.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.245.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.246.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.105.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.106.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.55.0/24  | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.56.0/24  | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.175.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.176.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.200.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.201.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.240.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.241.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 1111:1111:       | 0        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 1111:5555/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 1111:1111:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 1111:6666/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 0        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 0000:0000:       |          |
+   | aaaa:aaaa:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 0000:0000:       |          |
+   | bbbb:bbbb:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 0000:0000:       |          |
+   | 5555:5555:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 0000:0000:       |          |
+   | 6666:6666:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
-- 
2.5.5

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

* Re: [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-05-18 13:43     ` Mcnamara, John
  0 siblings, 0 replies; 41+ messages in thread
From: Mcnamara, John @ 2016-05-18 13:43 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev

 -----Original Message-----
> From: Gonzalez Monroy, Sergio
> Sent: Wednesday, May 18, 2016 1:42 PM
> To: dev@dpdk.org
> Cc: Mcnamara, John <john.mcnamara@intel.com>
> Subject: [PATCH v2 9/9] doc: update ipsec sample guide
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>

Reviewed-by: John McNamara <john.mcnamara@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>

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

* Re: [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
@ 2016-06-07 12:50     ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-06-07 12:50 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev; +Cc: Mcnamara, John



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Wednesday, May 18, 2016 1:42 PM
> To: dev@dpdk.org
> Cc: Mcnamara, John
> Subject: [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec
> execution loop
> 
> Rework implementation moving from function pointers approach, where
> each
> function implements very specific functionality, to a generic function
> approach.
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
> ---
>  examples/ipsec-secgw/esp.c   |   8 +-
>  examples/ipsec-secgw/esp.h   |   9 +-
>  examples/ipsec-secgw/ipsec.c |  36 ++++--
>  examples/ipsec-secgw/ipsec.h |   2 -
>  examples/ipsec-secgw/sa.c    | 272 ++++++++++++++++++-------------------------
>  5 files changed, 145 insertions(+), 182 deletions(-)
> 
> diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
> index 7dce78c..b423080 100644
> --- a/examples/ipsec-secgw/esp.c
> +++ b/examples/ipsec-secgw/esp.c
> @@ -69,7 +69,7 @@ random_iv_u64(uint64_t *buf, uint16_t n)
> 
>  /* IPv4 Tunnel */

You removed this comment in the header file, so probably you should do the same here?

>  int
> -esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
> +esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
>  		struct rte_crypto_op *cop)
>  {
>  	int32_t payload_len;
> @@ -117,7 +117,7 @@ esp4_tunnel_inbound_pre_crypto(struct rte_mbuf
> *m, struct ipsec_sa *sa,
>  }

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

* Re: [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
@ 2016-06-07 13:17     ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-06-07 13:17 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev; +Cc: Mcnamara, John



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Wednesday, May 18, 2016 1:42 PM
> To: dev@dpdk.org
> Cc: Mcnamara, John
> Subject: [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found
> case
> 
> The application only checks that an SA shoudln't be NULL through ASSERT

Typo here: "a SA should not be"

> (only when debugging is enabled) without properly dealing with the case
> of not having an SA for the processed packet.
> 
> If no SA is found, drop the packet.
> 
> Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>

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

* Re: [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
@ 2016-06-07 16:10     ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-06-07 16:10 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev; +Cc: Mcnamara, John



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Wednesday, May 18, 2016 1:42 PM
> To: dev@dpdk.org
> Cc: Mcnamara, John
> Subject: [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support
> 
> Support IPSec IPv6 allowing IPv4/IPv6 traffic in IPv4 or IPv6 tunnel.
> 
> We need separate Routing (LPM) and SP (ACL) tables for IPv4 and IPv6,
> but a common SA table.
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>

...

> +static inline void
> +ip4_ecn_setup(struct ip *ip4)
> +{
> +	if (ip4->ip_tos & IPTOS_ECN_MASK)
> +		ip4->ip_tos |= IPTOS_ECN_CE;
> +}
> +
> +static inline void
> +ip6_ecn_setup(struct ip6_hdr *ip6)
> +{
> +	if ((ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK)
> +		ip6->ip6_flow = htonl(ntohl(ip6->ip6_flow) |
> +					(IPTOS_ECN_CE << 20));
>  }
> 
>  static inline int
> -ip4ip_inbound(struct rte_mbuf *m, uint32_t offset)
> +ipip_inbound(struct rte_mbuf *m, uint32_t offset)

This function should return void, since it is returning 0 always.

>  {
> -	struct ip *inip;
> -	struct ip *outip;
> +	struct ip *inip4, *outip4;
> +	struct ip6_hdr *inip6, *outip6;
> +	uint32_t ip_len, set_ecn;
> 
> -	outip = rte_pktmbuf_mtod(m, struct ip*);
> +	outip4 = rte_pktmbuf_mtod(m, struct ip*);
> 
> -	RTE_ASSERT(outip->ip_v == IPVERSION);
> +	RTE_ASSERT(outip4->ip_v == IPVERSION || outip4->ip_v ==
> IP6_VERSION);
> 
> -	offset += sizeof(struct ip);
> -	inip = (struct ip *)rte_pktmbuf_adj(m, offset);
> -	RTE_ASSERT(inip->ip_v == IPVERSION || inip->ip_v ==
> IPV6_VERSION);
> +	if (outip4->ip_v == IPVERSION) {
> +		ip_len = sizeof(struct ip);
> +		set_ecn = ((outip4->ip_tos & IPTOS_ECN_CE) ==
> IPTOS_ECN_CE);
> +	} else {
> +		outip6 = (struct ip6_hdr *)outip4;
> +		ip_len = sizeof(struct ip6_hdr);
> +		set_ecn = ntohl(outip6->ip6_flow) >> 20;
> +		set_ecn = ((set_ecn & IPTOS_ECN_CE) == IPTOS_ECN_CE);
> +	}
> +
> +	inip4 = (struct ip *)rte_pktmbuf_adj(m, offset + ip_len);
> +	RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v ==
> IP6_VERSION);
> 
>  	/* Check packet is still bigger than IP header (inner) */
> -	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > sizeof(struct ip));
> +	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > ip_len);
> 
>  	/* RFC4301 5.1.2.1 Note 6 */
> -	if ((inip->ip_tos & htons(IPTOS_ECN_ECT0 | IPTOS_ECN_ECT1)) &&
> -			((outip->ip_tos & htons(IPTOS_ECN_CE)) ==
> IPTOS_ECN_CE))
> -		inip->ip_tos |= htons(IPTOS_ECN_CE);
> +	if (inip4->ip_v == IPVERSION) {
> +		if (set_ecn)
> +			ip4_ecn_setup(inip4);
> +		/* XXX This should be done by the forwarding engine instead
> */
> +		inip4->ip_ttl -= 1;
> +	} else {
> +		inip6 = (struct ip6_hdr *)inip4;
> +		if (set_ecn)
> +			ip6_ecn_setup(inip6);
> +		/* XXX This should be done by the forwarding engine instead
> */
> +		inip6->ip6_hops -= 1;
> +	}
> 
>  	return 0;
>  }

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

* [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements
  2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
                     ` (8 preceding siblings ...)
  2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-06-09  8:42   ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
                       ` (9 more replies)
  9 siblings, 10 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Update IPSec sample app with IPv6 and Transport mode support.

The series contains some bug fixes to facilitate patch merge.

v3:
 - change ipip_inbound function to reurn void
 - update some commit message and comments

v2:
 - rebase code
 - doc improvements
 - add missing image file

Sergio Gonzalez Monroy (9):
  examples/ipsec-secgw: fix esp padding check
  examples/ipsec-secgw: fix stack smashing error
  examples/ipsec-secgw: add build option and cleanup
  examples/ipsec-secgw: rework ipsec execution loop
  examples/ipsec-secgw: fix no sa found case
  examples/ipsec-secgw: consistent config variable names
  examples/ipsec-secgw: ipv6 support
  examples/ipsec-secgw: transport mode support
  doc: update ipsec sample guide

 doc/guides/sample_app_ug/img/ipsec_endpoints.svg | 850 +++++++++++++++++++++
 doc/guides/sample_app_ug/ipsec_secgw.rst         | 910 ++++++++++++++---------
 examples/ipsec-secgw/Makefile                    |   8 +-
 examples/ipsec-secgw/esp.c                       | 210 ++++--
 examples/ipsec-secgw/esp.h                       |   9 +-
 examples/ipsec-secgw/ipip.h                      | 149 +++-
 examples/ipsec-secgw/ipsec-secgw.c               | 332 ++++++---
 examples/ipsec-secgw/ipsec.c                     |  50 +-
 examples/ipsec-secgw/ipsec.h                     |  63 +-
 examples/ipsec-secgw/rt.c                        | 229 ++++--
 examples/ipsec-secgw/sa.c                        | 466 +++++++-----
 examples/ipsec-secgw/sp.c                        | 366 ---------
 examples/ipsec-secgw/sp4.c                       | 447 +++++++++++
 examples/ipsec-secgw/sp6.c                       | 448 +++++++++++
 14 files changed, 3313 insertions(+), 1224 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/img/ipsec_endpoints.svg
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 1/9] examples/ipsec-secgw: fix esp padding check
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
                       ` (8 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Current code fails to correctly check padding sequence for inbound
packets.
Padding sequence starts on 1 but it checks for 0.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 0f6b33e..7dce78c 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -139,7 +139,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
-		if (padding[i] != i) {
+		if (padding[i] != i + 1) {
 			RTE_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
 			return -EINVAL;
 		}
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 2/9] examples/ipsec-secgw: fix stack smashing error
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Building the application with -O3 and -fstack-protection (default in
Ubuntu) results in the following error:

*** stack smashing detected ***: ./build/ipsec-secgw terminated

The error is caused by storing an 8B value in a 4B variable.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 4566d38..3ffa77a 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -46,7 +46,7 @@
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 {
-	uint32_t cdev_id_qp = 0;
+	unsigned long cdev_id_qp = 0;
 	int32_t ret;
 	struct cdev_key key = { 0 };
 
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 3/9] examples/ipsec-secgw: add build option and cleanup
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Add support for building the application with DEBUG=1.
This option adds the compiler stack protection flag and enables extra
output in the application.

Also remove unnecessary VPATH setup.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index f9b59c2..6780ad5 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -46,8 +46,9 @@ ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
 CFLAGS_sa.o += -diag-disable=vec
 endif
 
-
-VPATH += $(SRCDIR)/librte_ipsec
+ifeq ($(DEBUG),1)
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+endif
 
 #
 # all source are stored in SRCS-y
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 4/9] examples/ipsec-secgw: rework ipsec execution loop
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (2 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
                       ` (5 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Rework implementation moving from function pointers approach, where each
function implements very specific functionality, to a generic function
approach.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   |   9 +-
 examples/ipsec-secgw/esp.h   |   9 +-
 examples/ipsec-secgw/ipsec.c |  36 ++++--
 examples/ipsec-secgw/ipsec.h |   2 -
 examples/ipsec-secgw/sa.c    | 272 ++++++++++++++++++-------------------------
 5 files changed, 145 insertions(+), 183 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 7dce78c..2ca97ad 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -67,9 +67,8 @@ random_iv_u64(uint64_t *buf, uint16_t n)
 		*((uint32_t *)&buf[i]) = (uint32_t)lrand48();
 }
 
-/* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	int32_t payload_len;
@@ -117,7 +116,7 @@ esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint8_t *nexthdr, *pad_len;
@@ -155,7 +154,7 @@ esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
 	uint16_t pad_payload_len, pad_len;
@@ -234,7 +233,7 @@ esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
 }
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m __rte_unused,
+esp_outbound_post(struct rte_mbuf *m __rte_unused,
 		struct ipsec_sa *sa __rte_unused,
 		struct rte_crypto_op *cop)
 {
diff --git a/examples/ipsec-secgw/esp.h b/examples/ipsec-secgw/esp.h
index 3101882..fa5cc8a 100644
--- a/examples/ipsec-secgw/esp.h
+++ b/examples/ipsec-secgw/esp.h
@@ -46,21 +46,20 @@ struct esp_hdr {
 	/* Integrity Check Value - ICV */
 };
 
-/* IPv4 Tunnel */
 int
-esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 int
-esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
+esp_outbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
 #endif /* __RTE_IPSEC_XFORM_ESP_H__ */
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 3ffa77a..90a9a86 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -42,6 +42,7 @@
 #include <rte_hash.h>
 
 #include "ipsec.h"
+#include "esp.h"
 
 static inline int
 create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
@@ -99,15 +100,14 @@ enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 	}
 }
 
-static inline uint16_t
-ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
-		struct ipsec_sa *sas[], uint16_t nb_pkts, uint16_t max_pkts)
+static inline void
+ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
+		uint16_t nb_pkts)
 {
-	int ret = 0, i, j, nb_cops;
+	int ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
-	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
-	struct rte_mbuf *pkt;
 
 	for (i = 0; i < nb_pkts; i++) {
 		rte_prefetch0(sas[i]);
@@ -133,7 +133,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		rte_crypto_op_attach_sym_session(&priv->cop,
 				sa->crypto_session);
 
-		ret = sa->pre_crypto(pkts[i], sa, &priv->cop);
+		ret = xform_func(pkts[i], sa, &priv->cop);
 		if (unlikely(ret)) {
 			rte_pktmbuf_free(pkts[i]);
 			continue;
@@ -142,8 +142,18 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 		RTE_ASSERT(sa->cdev_id_qp < ipsec_ctx->nb_qps);
 		enqueue_cop(&ipsec_ctx->tbl[sa->cdev_id_qp], &priv->cop);
 	}
+}
+
+static inline int
+ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
+		struct rte_mbuf *pkts[], uint16_t max_pkts)
+{
+	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	struct ipsec_mbuf_metadata *priv;
+	struct rte_crypto_op *cops[max_pkts];
+	struct ipsec_sa *sa;
+	struct rte_mbuf *pkt;
 
-	nb_pkts = 0;
 	for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
 		struct cdev_qp *cqp;
 
@@ -168,7 +178,7 @@ ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
 
 			RTE_ASSERT(sa != NULL);
 
-			ret = sa->post_crypto(pkt, sa, cops[j]);
+			ret = xform_func(pkt, sa, cops[j]);
 			if (unlikely(ret))
 				rte_pktmbuf_free(pkt);
 			else
@@ -188,7 +198,9 @@ ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_inbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_inbound_post, ctx, pkts, len);
 }
 
 uint16_t
@@ -199,5 +211,7 @@ ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
 
 	outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
 
-	return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
+	ipsec_enqueue(esp_outbound, ctx, pkts, sas, nb_pkts);
+
+	return ipsec_dequeue(esp_outbound_post, ctx, pkts, len);
 }
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index e60fae6..74ef6fc 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -86,8 +86,6 @@ struct ipsec_sa {
 	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
 	struct rte_crypto_sym_xform *xforms;
-	ipsec_xform_fn pre_crypto;
-	ipsec_xform_fn post_crypto;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index b6260ed..a193bdf 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -47,160 +47,112 @@
 #include "ipsec.h"
 #include "esp.h"
 
-/* SAs EP0 Outbound */
-const struct ipsec_sa sa_ep0_out[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP0 Inbound */
-const struct ipsec_sa sa_ep0_in[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
-};
-
-/* SAs EP1 Outbound */
-const struct ipsec_sa sa_ep1_out[] = {
-	{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
-		NULL, NULL,
-		esp4_tunnel_outbound_pre_crypto,
-		esp4_tunnel_outbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Outbound */
+const struct ipsec_sa sa_out[] = {
+	{
+	.spi = 5,
+	.src = IPv4(172, 16, 1, 5),
+	.dst = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 6,
+	.src = IPv4(172, 16, 1, 6),
+	.dst = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 7,
+	.src = IPv4(172, 16, 1, 7),
+	.dst = IPv4(172, 16, 2, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 8,
+	.src = IPv4(172, 16, 1, 8),
+	.dst = IPv4(172, 16, 2, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 9,
+	.src = IPv4(172, 16, 1, 9),
+	.dst = IPv4(172, 16, 2, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
-/* SAs EP1 Inbound */
-const struct ipsec_sa sa_ep1_in[] = {
-	{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
-		12, 16, 16,
-		0, 0 },
-	{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
-		NULL, NULL,
-		esp4_tunnel_inbound_pre_crypto,
-		esp4_tunnel_inbound_post_crypto,
-		RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
-		0, 0, 4,
-		0, 0 },
+/* SAs Inbound */
+const struct ipsec_sa sa_in[] = {
+	{
+	.spi = 55,
+	.src = IPv4(172, 16, 2, 5),
+	.dst = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 56,
+	.src = IPv4(172, 16, 2, 6),
+	.dst = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 57,
+	.src = IPv4(172, 16, 2, 7),
+	.dst = IPv4(172, 16, 1, 7),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 58,
+	.src = IPv4(172, 16, 2, 8),
+	.dst = IPv4(172, 16, 1, 8),
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	},
+	{
+	.spi = 59,
+	.src = IPv4(172, 16, 2, 9),
+	.dst = IPv4(172, 16, 1, 9),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -368,15 +320,15 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		sa_out_entries = sa_ep0_out;
-		nb_out_entries = RTE_DIM(sa_ep0_out);
-		sa_in_entries = sa_ep0_in;
-		nb_in_entries = RTE_DIM(sa_ep0_in);
+		sa_out_entries = sa_out;
+		nb_out_entries = RTE_DIM(sa_out);
+		sa_in_entries = sa_in;
+		nb_in_entries = RTE_DIM(sa_in);
 	} else if (ep == 1) {
-		sa_out_entries = sa_ep1_out;
-		nb_out_entries = RTE_DIM(sa_ep1_out);
-		sa_in_entries = sa_ep1_in;
-		nb_in_entries = RTE_DIM(sa_ep1_in);
+		sa_out_entries = sa_in;
+		nb_out_entries = RTE_DIM(sa_in);
+		sa_in_entries = sa_out;
+		nb_in_entries = RTE_DIM(sa_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 5/9] examples/ipsec-secgw: fix no sa found case
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (3 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

The application only ASSERTS that an SA is not NULL (only when debugging
is enabled) without properly dealing with the case of not having an SA
for the processed packet.

Behavior should be such as if no SA is found, drop the packet.

Fixes: d299106e8e31 ("examples/ipsec-secgw: add IPsec sample application")

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/ipsec.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 90a9a86..ccc840f 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -110,6 +110,11 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 	struct ipsec_sa *sa;
 
 	for (i = 0; i < nb_pkts; i++) {
+		if (unlikely(sas[i] == NULL)) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+
 		rte_prefetch0(sas[i]);
 		rte_prefetch0(pkts[i]);
 
@@ -117,8 +122,6 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		sa = sas[i];
 		priv->sa = sa;
 
-		RTE_ASSERT(sa != NULL);
-
 		priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
 
 		rte_prefetch0(&priv->sym_cop);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 6/9] examples/ipsec-secgw: consistent config variable names
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (4 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Modify the default SP config variables names to be consistent with SA.

The resulting naming convention is that variables with suffixes _out/_in
are the default for ep0 and the reverse for ep1.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/sp.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
index 4f16730..6aa377d 100644
--- a/examples/ipsec-secgw/sp.c
+++ b/examples/ipsec-secgw/sp.c
@@ -112,7 +112,7 @@ struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
 
 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
 
-const struct acl4_rules acl4_rules_in[] = {
+const struct acl4_rules acl4_rules_out[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -175,7 +175,7 @@ const struct acl4_rules acl4_rules_in[] = {
 	}
 };
 
-const struct acl4_rules acl4_rules_out[] = {
+const struct acl4_rules acl4_rules_in[] = {
 	{
 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
@@ -343,15 +343,15 @@ sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 				"initialized\n", socket_id);
 
 	if (ep == 0) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else if (ep == 1) {
 		rules_out = acl4_rules_out;
 		nb_out_rules = RTE_DIM(acl4_rules_out);
 		rules_in = acl4_rules_in;
 		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 7/9] examples/ipsec-secgw: ipv6 support
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (5 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Support IPSec IPv6 allowing IPv4/IPv6 traffic in IPv4 or IPv6 tunnel.

We need separate Routing (LPM) and SP (ACL) tables for IPv4 and IPv6,
but a common SA table.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/Makefile      |   5 +-
 examples/ipsec-secgw/esp.c         | 127 +++++++-----
 examples/ipsec-secgw/ipip.h        | 149 ++++++++++----
 examples/ipsec-secgw/ipsec-secgw.c | 332 ++++++++++++++++++++----------
 examples/ipsec-secgw/ipsec.c       |   9 +-
 examples/ipsec-secgw/ipsec.h       |  60 ++++--
 examples/ipsec-secgw/rt.c          | 201 +++++++++++++-----
 examples/ipsec-secgw/sa.c          | 239 ++++++++++++++--------
 examples/ipsec-secgw/sp.c          | 366 ---------------------------------
 examples/ipsec-secgw/sp4.c         | 407 +++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/sp6.c         | 400 ++++++++++++++++++++++++++++++++++++
 11 files changed, 1583 insertions(+), 712 deletions(-)
 delete mode 100644 examples/ipsec-secgw/sp.c
 create mode 100644 examples/ipsec-secgw/sp4.c
 create mode 100644 examples/ipsec-secgw/sp6.c

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 6780ad5..06b6db1 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -47,7 +47,7 @@ CFLAGS_sa.o += -diag-disable=vec
 endif
 
 ifeq ($(DEBUG),1)
-CFLAGS += -DIPSEC_DEBUG -fstack-protector-all
+CFLAGS += -DIPSEC_DEBUG -fstack-protector-all -O0
 endif
 
 #
@@ -55,7 +55,8 @@ endif
 #
 SRCS-y += ipsec.c
 SRCS-y += esp.c
-SRCS-y += sp.c
+SRCS-y += sp4.c
+SRCS-y += sp6.c
 SRCS-y += sa.c
 SRCS-y += rt.c
 SRCS-y += ipsec-secgw.c
diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index 2ca97ad..e1fde36 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <fcntl.h>
 #include <unistd.h>
 
@@ -50,13 +51,11 @@
 #include "esp.h"
 #include "ipip.h"
 
-#define IP_ESP_HDR_SZ (sizeof(struct ip) + sizeof(struct esp_hdr))
-
 static inline void
 random_iv_u64(uint64_t *buf, uint16_t n)
 {
-	unsigned left = n & 0x7;
-	unsigned i;
+	uint32_t left = n & 0x7;
+	uint32_t i;
 
 	RTE_ASSERT((n & 0x3) == 0);
 
@@ -71,15 +70,25 @@ int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len;
+	int32_t payload_len, ip_hdr_len;
 	struct rte_crypto_sym_op *sym_cop;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	payload_len = rte_pktmbuf_pkt_len(m) - IP_ESP_HDR_SZ - sa->iv_len -
-		sa->digest_len;
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
+
+	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
+		sizeof(struct esp_hdr) - sa->iv_len - sa->digest_len;
 
 	if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
 		RTE_LOG(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
@@ -90,21 +99,19 @@ esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset =  ip_hdr_len + sizeof(struct esp_hdr) +
+		sa->iv_len;
 	sym_cop->cipher.data.length = payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, void*,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
-	if (sa->auth_algo == RTE_CRYPTO_AUTH_AES_GCM)
-		sym_cop->auth.data.length = sizeof(struct esp_hdr);
-	else
-		sym_cop->auth.data.length = sizeof(struct esp_hdr) +
-			sa->iv_len + payload_len;
+	sym_cop->auth.data.offset = ip_hdr_len;
+	sym_cop->auth.data.length = sizeof(struct esp_hdr) +
+		sa->iv_len + payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
 			rte_pktmbuf_pkt_len(m) - sa->digest_len);
@@ -150,17 +157,20 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	return ip4ip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+
+	return 0;
 }
 
 int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len;
-	struct ip *ip;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
+	struct ip *ip4;
+	struct ip6_hdr *ip6;
 	struct esp_hdr *esp;
-	int i;
+	int32_t i;
 	char *padding;
 	struct rte_crypto_sym_op *sym_cop;
 
@@ -173,62 +183,87 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 			sa->block_size);
 	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
 
-	rte_prefetch0(rte_pktmbuf_mtod_offset(m, void *,
-				rte_pktmbuf_pkt_len(m)));
+	ip_hdr_len = 0;
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip_hdr_len = sizeof(struct ip);
+		break;
+	case IP6_TUNNEL:
+		ip_hdr_len = sizeof(struct ip6_hdr);
+		break;
+	}
 
 	/* Check maximum packet size */
-	if (unlikely(IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len +
-				sa->digest_len > IP_MAXPACKET)) {
-		RTE_LOG(DEBUG, IPSEC_ESP, "ipsec packet is too big\n");
+	if (unlikely(ip_hdr_len + sizeof(struct esp_hdr) + sa->iv_len +
+			pad_payload_len + sa->digest_len > IP_MAXPACKET)) {
+		RTE_LOG(ERR, IPSEC_ESP, "ipsec packet is too big\n");
 		return -EINVAL;
 	}
 
 	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	if (unlikely(padding == NULL)) {
+		RTE_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
+		return -ENOSPC;
+	}
+	rte_prefetch0(padding);
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		ip4 = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip4 + 1);
+		break;
+	case IP6_TUNNEL:
+		ip6 = ip6ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
+				&sa->src, &sa->dst);
+		esp = (struct esp_hdr *)(ip6 + 1);
+		break;
+	default:
+		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
+				sa->flags);
+		return -EINVAL;
+	}
 
-	RTE_ASSERT(padding != NULL);
-
-	ip = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
-			sa->src, sa->dst);
-
-	esp = (struct esp_hdr *)(ip + 1);
-	esp->spi = sa->spi;
-	esp->seq = htonl(sa->seq++);
+	sa->seq++;
+	esp->spi = rte_cpu_to_be_32(sa->spi);
+	esp->seq = rte_cpu_to_be_32(sa->seq);
 
-	RTE_LOG(DEBUG, IPSEC_ESP, "pktlen %u\n", rte_pktmbuf_pkt_len(m));
+	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
+		random_iv_u64((uint64_t *)(esp + 1), sa->iv_len);
 
 	/* Fill pad_len using default sequential scheme */
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
-
 	padding[pad_len - 2] = pad_len - 2;
-	padding[pad_len - 1] = IPPROTO_IPIP;
+
+	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
+		padding[pad_len - 1] = IPPROTO_IPIP;
+	else
+		padding[pad_len - 1] = IPPROTO_IPV6;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
 	sym_cop->m_src = m;
-	sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
+	sym_cop->cipher.data.offset = ip_hdr_len + sizeof(struct esp_hdr) +
+			sa->iv_len;
 	sym_cop->cipher.data.length = pad_payload_len;
 
 	sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ);
+			 ip_hdr_len + sizeof(struct esp_hdr));
 	sym_cop->cipher.iv.length = sa->iv_len;
 
-	sym_cop->auth.data.offset = sizeof(struct ip);
+	sym_cop->auth.data.offset = ip_hdr_len;
 	sym_cop->auth.data.length = sizeof(struct esp_hdr) + sa->iv_len +
 		pad_payload_len;
 
 	sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
-			IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
+			rte_pktmbuf_pkt_len(m) - sa->digest_len);
 	sym_cop->auth.digest.length = sa->digest_len;
 
-	if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
-		random_iv_u64((uint64_t *)sym_cop->cipher.iv.data,
-				sym_cop->cipher.iv.length);
-
 	return 0;
 }
 
diff --git a/examples/ipsec-secgw/ipip.h b/examples/ipsec-secgw/ipip.h
index 1307a12..ce25a2e 100644
--- a/examples/ipsec-secgw/ipip.h
+++ b/examples/ipsec-secgw/ipip.h
@@ -37,67 +37,144 @@
 #include <stdint.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_mbuf.h>
 
-#define IPV6_VERSION (6)
-
-static inline  struct ip *
-ip4ip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t src, uint32_t dst)
+static inline void *
+ipip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t is_ipv6,
+		struct ip_addr *src,  struct ip_addr *dst)
 {
-	struct ip *inip, *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint8_t ds_ecn;
 
-	inip = rte_pktmbuf_mtod(m, struct ip*);
+	inip4 = rte_pktmbuf_mtod(m, struct ip *);
 
-	RTE_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
+	if (inip4->ip_v == IPVERSION) {
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+		ds_ecn = inip4->ip_tos;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+		ds_ecn = ntohl(inip6->ip6_flow) >> 20;
+	}
+
+	if (is_ipv6) {
+		offset += sizeof(struct ip6_hdr);
+		outip6 = (struct ip6_hdr *)rte_pktmbuf_prepend(m, offset);
+
+		RTE_ASSERT(outip6 != NULL);
+
+		/* Per RFC4301 5.1.2.1 */
+		outip6->ip6_flow = htonl(IP6_VERSION << 28 | ds_ecn << 20);
+		outip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+
+		outip6->ip6_nxt = IPPROTO_ESP;
+		outip6->ip6_hops = IPDEFTTL;
 
-	outip = (struct ip *)rte_pktmbuf_prepend(m, offset);
+		memcpy(&outip6->ip6_src.s6_addr, src, 16);
+		memcpy(&outip6->ip6_dst.s6_addr, dst, 16);
 
-	RTE_ASSERT(outip != NULL);
+		return outip6;
+	}
+
+	offset += sizeof(struct ip);
+	outip4 = (struct ip *)rte_pktmbuf_prepend(m, offset);
+
+	RTE_ASSERT(outip4 != NULL);
 
 	/* Per RFC4301 5.1.2.1 */
-	outip->ip_v = IPVERSION;
-	outip->ip_hl = 5;
-	outip->ip_tos = inip->ip_tos;
-	outip->ip_len = htons(rte_pktmbuf_data_len(m));
+	outip4->ip_v = IPVERSION;
+	outip4->ip_hl = 5;
+	outip4->ip_tos = ds_ecn;
+	outip4->ip_len = htons(rte_pktmbuf_data_len(m));
+
+	outip4->ip_id = 0;
+	outip4->ip_off = 0;
+
+	outip4->ip_ttl = IPDEFTTL;
+	outip4->ip_p = IPPROTO_ESP;
+
+	outip4->ip_src.s_addr = src->ip4;
+	outip4->ip_dst.s_addr = dst->ip4;
 
-	outip->ip_id = 0;
-	outip->ip_off = 0;
+	return outip4;
+}
+
+static inline struct ip *
+ip4ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 0, src, dst);
+}
 
-	outip->ip_ttl = IPDEFTTL;
-	outip->ip_p = IPPROTO_ESP;
+static inline struct ip6_hdr *
+ip6ip_outbound(struct rte_mbuf *m, uint32_t offset,
+		struct ip_addr *src,  struct ip_addr *dst)
+{
+	return ipip_outbound(m, offset, 1, src, dst);
+}
 
-	outip->ip_src.s_addr = src;
-	outip->ip_dst.s_addr = dst;
+static inline void
+ip4_ecn_setup(struct ip *ip4)
+{
+	if (ip4->ip_tos & IPTOS_ECN_MASK)
+		ip4->ip_tos |= IPTOS_ECN_CE;
+}
 
-	return outip;
+static inline void
+ip6_ecn_setup(struct ip6_hdr *ip6)
+{
+	if ((ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK)
+		ip6->ip6_flow = htonl(ntohl(ip6->ip6_flow) |
+					(IPTOS_ECN_CE << 20));
 }
 
-static inline int
-ip4ip_inbound(struct rte_mbuf *m, uint32_t offset)
+static inline void
+ipip_inbound(struct rte_mbuf *m, uint32_t offset)
 {
-	struct ip *inip;
-	struct ip *outip;
+	struct ip *inip4, *outip4;
+	struct ip6_hdr *inip6, *outip6;
+	uint32_t ip_len, set_ecn;
 
-	outip = rte_pktmbuf_mtod(m, struct ip*);
+	outip4 = rte_pktmbuf_mtod(m, struct ip*);
 
-	RTE_ASSERT(outip->ip_v == IPVERSION);
+	RTE_ASSERT(outip4->ip_v == IPVERSION || outip4->ip_v == IP6_VERSION);
 
-	offset += sizeof(struct ip);
-	inip = (struct ip *)rte_pktmbuf_adj(m, offset);
-	RTE_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
+	if (outip4->ip_v == IPVERSION) {
+		ip_len = sizeof(struct ip);
+		set_ecn = ((outip4->ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	} else {
+		outip6 = (struct ip6_hdr *)outip4;
+		ip_len = sizeof(struct ip6_hdr);
+		set_ecn = ntohl(outip6->ip6_flow) >> 20;
+		set_ecn = ((set_ecn & IPTOS_ECN_CE) == IPTOS_ECN_CE);
+	}
+
+	inip4 = (struct ip *)rte_pktmbuf_adj(m, offset + ip_len);
+	RTE_ASSERT(inip4->ip_v == IPVERSION || inip4->ip_v == IP6_VERSION);
 
 	/* Check packet is still bigger than IP header (inner) */
-	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > sizeof(struct ip));
+	RTE_ASSERT(rte_pktmbuf_pkt_len(m) > ip_len);
 
 	/* RFC4301 5.1.2.1 Note 6 */
-	if ((inip->ip_tos & htons(IPTOS_ECN_ECT0 | IPTOS_ECN_ECT1)) &&
-			((outip->ip_tos & htons(IPTOS_ECN_CE)) == IPTOS_ECN_CE))
-		inip->ip_tos |= htons(IPTOS_ECN_CE);
-
-	return 0;
+	if (inip4->ip_v == IPVERSION) {
+		if (set_ecn)
+			ip4_ecn_setup(inip4);
+		/* XXX This should be done by the forwarding engine instead */
+		inip4->ip_ttl -= 1;
+	} else {
+		inip6 = (struct ip6_hdr *)inip4;
+		if (set_ecn)
+			ip6_ecn_setup(inip6);
+		/* XXX This should be done by the forwarding engine instead */
+		inip6->ip6_hops -= 1;
+	}
 }
 
 #endif /* __IPIP_H__ */
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 00ab2d8..4065b59 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -38,6 +38,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <string.h>
 #include <sys/queue.h>
 #include <stdarg.h>
@@ -65,6 +66,7 @@
 #include <rte_mbuf.h>
 #include <rte_acl.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_hash.h>
 #include <rte_jhash.h>
 #include <rte_cryptodev.h>
@@ -192,7 +194,8 @@ struct lcore_conf {
 	struct buffer tx_mbufs[RTE_MAX_ETHPORTS];
 	struct ipsec_ctx inbound;
 	struct ipsec_ctx outbound;
-	struct rt_ctx *rt_ctx;
+	struct rt_ctx *rt4_ctx;
+	struct rt_ctx *rt6_ctx;
 } __rte_cache_aligned;
 
 static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
@@ -230,27 +233,39 @@ struct traffic_type {
 };
 
 struct ipsec_traffic {
-	struct traffic_type ipsec4;
-	struct traffic_type ipv4;
+	struct traffic_type ipsec;
+	struct traffic_type ip4;
+	struct traffic_type ip6;
 };
 
 static inline void
 prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 {
 	uint8_t *nlp;
+	struct ether_hdr *eth;
 
-	if (RTE_ETH_IS_IPV4_HDR(pkt->packet_type)) {
-		rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
-		nlp = rte_pktmbuf_mtod_offset(pkt, uint8_t *,
-				offsetof(struct ip, ip_p));
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip, ip_p));
 		if (*nlp == IPPROTO_ESP)
-			t->ipsec4.pkts[(t->ipsec4.num)++] = pkt;
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
 		else {
-			t->ipv4.data[t->ipv4.num] = nlp;
-			t->ipv4.pkts[(t->ipv4.num)++] = pkt;
+			t->ip4.data[t->ip4.num] = nlp;
+			t->ip4.pkts[(t->ip4.num)++] = pkt;
+		}
+	} else if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		nlp = (uint8_t *)rte_pktmbuf_adj(pkt, ETHER_HDR_LEN);
+		nlp = RTE_PTR_ADD(nlp, offsetof(struct ip6_hdr, ip6_nxt));
+		if (*nlp == IPPROTO_ESP)
+			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
+		else {
+			t->ip6.data[t->ip6.num] = nlp;
+			t->ip6.pkts[(t->ip6.num)++] = pkt;
 		}
 	} else {
 		/* Unknown/Unsupported type, drop the packet */
+		RTE_LOG(ERR, IPSEC, "Unsupported packet type\n");
 		rte_pktmbuf_free(pkt);
 	}
 }
@@ -261,8 +276,9 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 {
 	int32_t i;
 
-	t->ipsec4.num = 0;
-	t->ipv4.num = 0;
+	t->ipsec.num = 0;
+	t->ip4.num = 0;
+	t->ip6.num = 0;
 
 	for (i = 0; i < (nb_pkts - PREFETCH_OFFSET); i++) {
 		rte_prefetch0(rte_pktmbuf_mtod(pkts[i + PREFETCH_OFFSET],
@@ -277,14 +293,27 @@ prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
 static inline void
 prepare_tx_pkt(struct rte_mbuf *pkt, uint8_t port)
 {
-	pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
-	pkt->l3_len = sizeof(struct ip);
-	pkt->l2_len = ETHER_HDR_LEN;
+	struct ip *ip;
+	struct ether_hdr *ethhdr;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+
+	ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt, ETHER_HDR_LEN);
 
-	struct ether_hdr *ethhdr = (struct ether_hdr *)rte_pktmbuf_prepend(pkt,
-			ETHER_HDR_LEN);
+	if (ip->ip_v == IPVERSION) {
+		pkt->ol_flags |= PKT_TX_IP_CKSUM | PKT_TX_IPV4;
+		pkt->l3_len = sizeof(struct ip);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	} else {
+		pkt->ol_flags |= PKT_TX_IPV6;
+		pkt->l3_len = sizeof(struct ip6_hdr);
+		pkt->l2_len = ETHER_HDR_LEN;
+
+		ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	}
 
-	ethhdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
 	memcpy(&ethhdr->s_addr, &ethaddr_tbl[port].src,
 			sizeof(struct ether_addr));
 	memcpy(&ethhdr->d_addr, &ethaddr_tbl[port].dst,
@@ -355,94 +384,133 @@ send_single_packet(struct rte_mbuf *m, uint8_t port)
 }
 
 static inline void
-process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
-		struct ipsec_traffic *traffic)
+inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_in, i, j;
-	uint32_t sa_idx, res;
-
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	uint32_t i, j, res, sa_idx;
 
-	/* SP/ACL Inbound check ipsec and ipv4 */
-	for (i = 0; i < nb_pkts_in; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
-		traffic->ipv4.data[idx] = rte_pktmbuf_mtod_offset(m,
-				uint8_t *, offsetof(struct ip, ip_p));
-	}
+	if (ip->num == 0)
+		return;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num - nb_pkts_in; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		if (res & ~BYPASS) {
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		res = ip->res[i];
+		if (res & DISCARD) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
-	}
-	/* Check return SA SPI matches pkt SPI */
-	for ( ; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		sa_idx = traffic->ipv4.res[i] & PROTECT_MASK;
-		if (sa_idx == 0 || !inbound_sa_check(ipsec_ctx->sa_ctx,
-					m, sa_idx)) {
+		if (res & BYPASS) {
+			ip->pkts[j++] = m;
+			continue;
+		}
+		/* Check return SA SPI matches pkt SPI */
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if (sa_idx == 0 || !inbound_sa_check(sa, m, sa_idx)) {
 			rte_pktmbuf_free(m);
 			continue;
 		}
-		traffic->ipv4.pkts[j++] = m;
+		ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
 }
 
 static inline void
-process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
 	struct rte_mbuf *m;
-	uint16_t idx, nb_pkts_out, i, j;
-	uint32_t sa_idx, res;
+	uint16_t idx, nb_pkts_in, i;
 
-	rte_acl_classify((struct rte_acl_ctx *)ipsec_ctx->sp_ctx,
-			traffic->ipv4.data, traffic->ipv4.res,
-			traffic->ipv4.num, DEFAULT_MAX_CATEGORIES);
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
 
-	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	/* SP/ACL Inbound check ipsec and ip4 */
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+			traffic->ip4.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *, offsetof(struct ip, ip_p));
+		} else if (ip->ip_v == IP6_VERSION) {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+			traffic->ip6.data[idx] = rte_pktmbuf_mtod_offset(m,
+					uint8_t *,
+					offsetof(struct ip6_hdr, ip6_nxt));
+		} else
+			rte_pktmbuf_free(m);
+	}
+
+	inbound_sp_sa(ipsec_ctx->sp4_ctx, ipsec_ctx->sa_ctx, &traffic->ip4);
+
+	inbound_sp_sa(ipsec_ctx->sp6_ctx, ipsec_ctx->sa_ctx, &traffic->ip6);
+}
+
+static inline void
+outbound_sp(struct sp_ctx *sp, struct traffic_type *ip,
+		struct traffic_type *ipsec)
+{
+	struct rte_mbuf *m;
+	uint32_t i, j, sa_idx;
+
+	if (ip->num == 0)
+		return;
 
-	traffic->ipsec4.num = 0;
+	rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
+			ip->num, DEFAULT_MAX_CATEGORIES);
 
 	j = 0;
-	for (i = 0; i < traffic->ipv4.num; i++) {
-		m = traffic->ipv4.pkts[i];
-		res = traffic->ipv4.res[i];
-		sa_idx = res & PROTECT_MASK;
-		if ((res == 0) || (res & DISCARD))
+	for (i = 0; i < ip->num; i++) {
+		m = ip->pkts[i];
+		sa_idx = ip->res[i] & PROTECT_MASK;
+		if ((ip->res[i] == 0) || (ip->res[i] & DISCARD))
 			rte_pktmbuf_free(m);
 		else if (sa_idx != 0) {
-			traffic->ipsec4.res[traffic->ipsec4.num] = sa_idx;
-			traffic->ipsec4.pkts[traffic->ipsec4.num++] = m;
+			ipsec->res[ipsec->num] = sa_idx;
+			ipsec->pkts[ipsec->num++] = m;
 		} else /* BYPASS */
-			traffic->ipv4.pkts[j++] = m;
+			ip->pkts[j++] = m;
 	}
-	traffic->ipv4.num = j;
+	ip->num = j;
+}
+
+static inline void
+process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
+		struct ipsec_traffic *traffic)
+{
+	struct rte_mbuf *m;
+	uint16_t idx, nb_pkts_out, i;
+
+	/* Drop any IPsec traffic from protected ports */
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.res, traffic->ipsec4.num,
+	traffic->ipsec.num = 0;
+
+	outbound_sp(ipsec_ctx->sp4_ctx, &traffic->ip4, &traffic->ipsec);
+
+	outbound_sp(ipsec_ctx->sp6_ctx, &traffic->ip6, &traffic->ipsec);
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.res, traffic->ipsec.num,
 			MAX_PKT_BURST);
 
 	for (i = 0; i < nb_pkts_out; i++) {
-		idx = traffic->ipv4.num++;
-		m = traffic->ipsec4.pkts[i];
-		traffic->ipv4.pkts[idx] = m;
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
 	}
 }
 
@@ -450,47 +518,72 @@ static inline void
 process_pkts_inbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_in, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_in, i, idx;
 
 	/* Drop any IPv4 traffic from unprotected ports */
-	for (i = 0; i < traffic->ipv4.num; i++)
-		rte_pktmbuf_free(traffic->ipv4.pkts[i]);
+	for (i = 0; i < traffic->ip4.num; i++)
+		rte_pktmbuf_free(traffic->ip4.pkts[i]);
 
-	traffic->ipv4.num = 0;
+	traffic->ip4.num = 0;
 
-	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec4.pkts,
-			traffic->ipsec4.num, MAX_PKT_BURST);
+	/* Drop any IPv6 traffic from unprotected ports */
+	for (i = 0; i < traffic->ip6.num; i++)
+		rte_pktmbuf_free(traffic->ip6.pkts[i]);
 
-	for (i = 0; i < nb_pkts_in; i++)
-		traffic->ipv4.pkts[i] = traffic->ipsec4.pkts[i];
+	traffic->ip6.num = 0;
 
-	traffic->ipv4.num = nb_pkts_in;
+	nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
+			traffic->ipsec.num, MAX_PKT_BURST);
+
+	for (i = 0; i < nb_pkts_in; i++) {
+		m = traffic->ipsec.pkts[i];
+		struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
+		if (ip->ip_v == IPVERSION) {
+			idx = traffic->ip4.num++;
+			traffic->ip4.pkts[idx] = m;
+		} else {
+			idx = traffic->ip6.num++;
+			traffic->ip6.pkts[idx] = m;
+		}
+	}
 }
 
 static inline void
 process_pkts_outbound_nosp(struct ipsec_ctx *ipsec_ctx,
 		struct ipsec_traffic *traffic)
 {
-	uint16_t nb_pkts_out, i;
+	struct rte_mbuf *m;
+	uint32_t nb_pkts_out, i;
+	struct ip *ip;
 
 	/* Drop any IPsec traffic from protected ports */
-	for (i = 0; i < traffic->ipsec4.num; i++)
-		rte_pktmbuf_free(traffic->ipsec4.pkts[i]);
+	for (i = 0; i < traffic->ipsec.num; i++)
+		rte_pktmbuf_free(traffic->ipsec.pkts[i]);
 
-	traffic->ipsec4.num = 0;
+	traffic->ipsec.num = 0;
 
-	for (i = 0; i < traffic->ipv4.num; i++)
-		traffic->ipv4.res[i] = single_sa_idx;
+	for (i = 0; i < traffic->ip4.num; i++)
+		traffic->ip4.res[i] = single_sa_idx;
 
-	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipv4.pkts,
-			traffic->ipv4.res, traffic->ipv4.num,
+	for (i = 0; i < traffic->ip6.num; i++)
+		traffic->ip6.res[i] = single_sa_idx;
+
+	nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ip4.pkts,
+			traffic->ip4.res, traffic->ip4.num,
 			MAX_PKT_BURST);
 
-	traffic->ipv4.num = nb_pkts_out;
+	/* They all sue the same SA (ip4 or ip6 tunnel) */
+	m = traffic->ipsec.pkts[i];
+	ip = rte_pktmbuf_mtod(m, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		traffic->ip4.num = nb_pkts_out;
+	else
+		traffic->ip6.num = nb_pkts_out;
 }
 
 static inline void
-route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+route4_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 {
 	uint32_t hop[MAX_PKT_BURST * 2];
 	uint32_t dst_ip[MAX_PKT_BURST * 2];
@@ -518,6 +611,35 @@ route_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
 }
 
 static inline void
+route6_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
+{
+	int16_t hop[MAX_PKT_BURST * 2];
+	uint8_t dst_ip[MAX_PKT_BURST * 2][16];
+	uint8_t *ip6_dst;
+	uint16_t i, offset;
+
+	if (nb_pkts == 0)
+		return;
+
+	for (i = 0; i < nb_pkts; i++) {
+		offset = offsetof(struct ip6_hdr, ip6_dst);
+		ip6_dst = rte_pktmbuf_mtod_offset(pkts[i], uint8_t *, offset);
+		memcpy(&dst_ip[i][0], ip6_dst, 16);
+	}
+
+	rte_lpm6_lookup_bulk_func((struct rte_lpm6 *)rt_ctx, dst_ip,
+			hop, nb_pkts);
+
+	for (i = 0; i < nb_pkts; i++) {
+		if (hop[i] == -1) {
+			rte_pktmbuf_free(pkts[i]);
+			continue;
+		}
+		send_single_packet(pkts[i], hop[i] & 0xff);
+	}
+}
+
+static inline void
 process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 		uint8_t nb_pkts, uint8_t portid)
 {
@@ -525,7 +647,7 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 
 	prepare_traffic(pkts, &traffic, nb_pkts);
 
-	if (single_sa) {
+	if (unlikely(single_sa)) {
 		if (UNPROTECTED_PORT(portid))
 			process_pkts_inbound_nosp(&qconf->inbound, &traffic);
 		else
@@ -537,7 +659,8 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 			process_pkts_outbound(&qconf->outbound, &traffic);
 	}
 
-	route_pkts(qconf->rt_ctx, traffic.ipv4.pkts, traffic.ipv4.num);
+	route4_pkts(qconf->rt4_ctx, traffic.ip4.pkts, traffic.ip4.num);
+	route6_pkts(qconf->rt6_ctx, traffic.ip6.pkts, traffic.ip6.num);
 }
 
 static inline void
@@ -576,12 +699,15 @@ main_loop(__attribute__((unused)) void *dummy)
 	rxql = qconf->rx_queue_list;
 	socket_id = rte_lcore_to_socket_id(lcore_id);
 
-	qconf->rt_ctx = socket_ctx[socket_id].rt_ipv4;
-	qconf->inbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_in;
-	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_in;
+	qconf->rt4_ctx = socket_ctx[socket_id].rt_ip4;
+	qconf->rt6_ctx = socket_ctx[socket_id].rt_ip6;
+	qconf->inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
+	qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
+	qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
 	qconf->inbound.cdev_map = cdev_map_in;
-	qconf->outbound.sp_ctx = socket_ctx[socket_id].sp_ipv4_out;
-	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_ipv4_out;
+	qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
+	qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
+	qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
 	qconf->outbound.cdev_map = cdev_map_out;
 
 	if (qconf->nb_rx_queue == 0) {
@@ -762,7 +888,7 @@ parse_config(const char *q_arg)
 		FLD_LCORE,
 		_NUM_FLD
 	};
-	int long int_fld[_NUM_FLD];
+	unsigned long int_fld[_NUM_FLD];
 	char *str_fld[_NUM_FLD];
 	int32_t i;
 	uint32_t size;
@@ -1313,7 +1439,9 @@ main(int32_t argc, char **argv)
 
 		sa_init(&socket_ctx[socket_id], socket_id, ep);
 
-		sp_init(&socket_ctx[socket_id], socket_id, ep);
+		sp4_init(&socket_ctx[socket_id], socket_id, ep);
+
+		sp6_init(&socket_ctx[socket_id], socket_id, ep);
 
 		rt_init(&socket_ctx[socket_id], socket_id, ep);
 
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index ccc840f..1e87d0d 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -66,7 +66,8 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 	}
 
 	RTE_LOG(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
-			"%u qp %u\n", sa->spi, ipsec_ctx->tbl[cdev_id_qp].id,
+			"%u qp %u\n", sa->spi,
+			ipsec_ctx->tbl[cdev_id_qp].id,
 			ipsec_ctx->tbl[cdev_id_qp].qp);
 
 	sa->crypto_session = rte_cryptodev_sym_session_create(
@@ -80,7 +81,7 @@ create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
 static inline void
 enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
 {
-	int ret, i;
+	int32_t ret, i;
 
 	cqp->buf[cqp->len++] = cop;
 
@@ -105,7 +106,7 @@ ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], struct ipsec_sa *sas[],
 		uint16_t nb_pkts)
 {
-	int ret = 0, i;
+	int32_t ret = 0, i;
 	struct ipsec_mbuf_metadata *priv;
 	struct ipsec_sa *sa;
 
@@ -151,7 +152,7 @@ static inline int
 ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
 		struct rte_mbuf *pkts[], uint16_t max_pkts)
 {
-	int nb_pkts = 0, ret = 0, i, j, nb_cops;
+	int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
 	struct ipsec_mbuf_metadata *priv;
 	struct rte_crypto_op *cops[max_pkts];
 	struct ipsec_sa *sa;
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 74ef6fc..83d7b1c 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -37,7 +37,6 @@
 #include <stdint.h>
 
 #include <rte_byteorder.h>
-#include <rte_ip.h>
 #include <rte_crypto.h>
 
 #define RTE_LOGTYPE_IPSEC       RTE_LOGTYPE_USER1
@@ -50,15 +49,15 @@
 #define MAX_DIGEST_SIZE 32 /* Bytes -- 256 bits */
 
 #define uint32_t_to_char(ip, a, b, c, d) do {\
-		*a = (unsigned char)(ip >> 24 & 0xff);\
-		*b = (unsigned char)(ip >> 16 & 0xff);\
-		*c = (unsigned char)(ip >> 8 & 0xff);\
-		*d = (unsigned char)(ip & 0xff);\
+		*a = (uint8_t)(ip >> 24 & 0xff);\
+		*b = (uint8_t)(ip >> 16 & 0xff);\
+		*c = (uint8_t)(ip >> 8 & 0xff);\
+		*d = (uint8_t)(ip & 0xff);\
 	} while (0)
 
 #define DEFAULT_MAX_CATEGORIES	1
 
-#define IPSEC_SA_MAX_ENTRIES (64) /* must be power of 2, max 2 power 30 */
+#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)
 
@@ -69,6 +68,8 @@
 
 #define IPSEC_XFORM_MAX 2
 
+#define IP6_VERSION (6)
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_cryptodev_session;
@@ -76,23 +77,35 @@ struct rte_mbuf;
 
 struct ipsec_sa;
 
-typedef int (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
+typedef int32_t (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop);
 
+struct ip_addr {
+	union {
+		uint32_t ip4;
+		union {
+			uint64_t ip6[2];
+			uint8_t ip6_b[16];
+		};
+	};
+};
+
 struct ipsec_sa {
 	uint32_t spi;
 	uint32_t cdev_id_qp;
-	uint32_t src;
-	uint32_t dst;
 	struct rte_cryptodev_sym_session *crypto_session;
-	struct rte_crypto_sym_xform *xforms;
+	uint32_t seq;
 	enum rte_crypto_cipher_algorithm cipher_algo;
 	enum rte_crypto_auth_algorithm auth_algo;
 	uint16_t digest_len;
 	uint16_t iv_len;
 	uint16_t block_size;
 	uint16_t flags;
-	uint32_t seq;
+#define IP4_TUNNEL (1 << 0)
+#define IP6_TUNNEL (1 << 1)
+	struct ip_addr src;
+	struct ip_addr dst;
+	struct rte_crypto_sym_xform *xforms;
 } __rte_cache_aligned;
 
 struct ipsec_mbuf_metadata {
@@ -111,7 +124,8 @@ struct cdev_qp {
 
 struct ipsec_ctx {
 	struct rte_hash *cdev_map;
-	struct sp_ctx *sp_ctx;
+	struct sp_ctx *sp4_ctx;
+	struct sp_ctx *sp6_ctx;
 	struct sa_ctx *sa_ctx;
 	uint16_t nb_qps;
 	uint16_t last_qp;
@@ -125,11 +139,14 @@ struct cdev_key {
 };
 
 struct socket_ctx {
-	struct sa_ctx *sa_ipv4_in;
-	struct sa_ctx *sa_ipv4_out;
-	struct sp_ctx *sp_ipv4_in;
-	struct sp_ctx *sp_ipv4_out;
-	struct rt_ctx *rt_ipv4;
+	struct sa_ctx *sa_in;
+	struct sa_ctx *sa_out;
+	struct sp_ctx *sp_ip4_in;
+	struct sp_ctx *sp_ip4_out;
+	struct sp_ctx *sp_ip6_in;
+	struct sp_ctx *sp_ip6_out;
+	struct rt_ctx *rt_ip4;
+	struct rt_ctx *rt_ip6;
 	struct rte_mempool *mbuf_pool;
 };
 
@@ -165,12 +182,15 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts);
 
 void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index a6d0866..d46df49 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -36,110 +36,205 @@
  */
 #include <sys/types.h>
 #include <rte_lpm.h>
+#include <rte_lpm6.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 
-#define RT_IPV4_MAX_RULES         64
+#define RT_IPV4_MAX_RULES	1024
+#define RT_IPV6_MAX_RULES	1024
 
-struct ipv4_route {
+struct ip4_route {
 	uint32_t ip;
-	uint8_t  depth;
-	uint8_t  if_out;
+	uint8_t depth;
+	uint8_t if_out;
 };
 
-/* In the default routing table we have:
- * ep0 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep0[] = {
+struct ip6_route {
+	uint8_t ip[16];
+	uint8_t depth;
+	uint8_t if_out;
+};
+
+static struct ip4_route rt_ip4_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
-	{ IPv4(172, 16, 2, 6), 32, 0 },
-	{ IPv4(172, 16, 2, 7), 32, 1 },
-	{ IPv4(172, 16, 2, 8), 32, 1 },
+	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 240, 0), 24, 0 },
+	{ IPv4(192, 168, 241, 0), 24, 1 },
 
+	/* Inbound */
+	/* Tunnels */
 	{ IPv4(192, 168, 115, 0), 24, 2 },
-	{ IPv4(192, 168, 116, 0), 24, 2 },
-	{ IPv4(192, 168, 117, 0), 24, 3 },
-	{ IPv4(192, 168, 118, 0), 24, 3 },
-
+	{ IPv4(192, 168, 116, 0), 24, 3 },
+	{ IPv4(192, 168, 65, 0), 24, 2 },
+	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
-
-	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 211, 0), 24, 3 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 2 },
+	{ IPv4(192, 168, 246, 0), 24, 3 },
 };
 
-/* In the default routing table we have:
- * ep1 protected ports 0 and 1, and unprotected ports 2 and 3.
- */
-static struct ipv4_route rt_ipv4_ep1[] = {
-	{ IPv4(172, 16, 1, 5), 32, 2 },
-	{ IPv4(172, 16, 1, 6), 32, 2 },
-	{ IPv4(172, 16, 1, 7), 32, 3 },
-	{ IPv4(172, 16, 1, 8), 32, 3 },
-
-	{ IPv4(192, 168, 105, 0), 24, 0 },
-	{ IPv4(192, 168, 106, 0), 24, 0 },
-	{ IPv4(192, 168, 107, 0), 24, 1 },
-	{ IPv4(192, 168, 108, 0), 24, 1 },
-
-	{ IPv4(192, 168, 200, 0), 24, 0 },
+static struct ip6_route rt_ip6_ep0[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
+	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Inbound */
+	/* Tunnels */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+};
 
+static struct ip4_route rt_ip4_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ IPv4(172, 16, 1, 5), 32, 0 },
+	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Bypass */
+	{ IPv4(192, 168, 245, 0), 24, 0 },
+	{ IPv4(192, 168, 246, 0), 24, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ IPv4(192, 168, 105, 0), 24, 2 },
+	{ IPv4(192, 168, 106, 0), 24, 3 },
+	{ IPv4(192, 168, 55, 0), 24, 2 },
+	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* NULL */
+	{ IPv4(192, 168, 200, 0), 24, 2 },
+	{ IPv4(192, 168, 201, 0), 24, 3 },
+	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 2 },
-	{ IPv4(192, 168, 250, 0), 24, 0 }
+	{ IPv4(192, 168, 241, 0), 24, 3 },
+};
+
+static struct ip6_route rt_ip6_ep1[] = {
+	/* Outbound */
+	/* Tunnels */
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
+	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+
+	/* Inbound */
+	/* Tunnels */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
+		  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
-rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	char name[PATH_MAX];
-	unsigned i;
-	int ret;
+	uint32_t i;
+	int32_t ret;
 	struct rte_lpm *lpm;
-	struct ipv4_route *rt;
+	struct rte_lpm6 *lpm6;
+	struct ip4_route *rt;
+	struct ip6_route *rt6;
 	char a, b, c, d;
-	unsigned nb_routes;
+	uint32_t nb_routes, nb_routes6;
 	struct rte_lpm_config conf = { 0 };
+	struct rte_lpm6_config conf6 = { 0 };
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->rt_ipv4 != NULL)
-		rte_exit(EXIT_FAILURE, "Routing Table for socket %u already "
-			"initialized\n", socket_id);
+	if (ctx->rt_ip4 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv4 Routing Table for socket %u "
+			"already initialized\n", socket_id);
 
-	printf("Creating Routing Table (RT) context with %u max routes\n",
+	if (ctx->rt_ip6 != NULL)
+		rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u "
+			"already initialized\n", socket_id);
+
+	printf("Creating IPv4 Routing Table (RT) context with %u max routes\n",
 			RT_IPV4_MAX_RULES);
 
 	if (ep == 0) {
-		rt = rt_ipv4_ep0;
-		nb_routes = RTE_DIM(rt_ipv4_ep0);
+		rt = rt_ip4_ep0;
+		nb_routes = RTE_DIM(rt_ip4_ep0);
+		rt6 = rt_ip6_ep0;
+		nb_routes6 = RTE_DIM(rt_ip6_ep0);
 	} else if (ep == 1) {
-		rt = rt_ipv4_ep1;
-		nb_routes = RTE_DIM(rt_ipv4_ep1);
+		rt = rt_ip4_ep1;
+		nb_routes = RTE_DIM(rt_ip4_ep1);
+		rt6 = rt_ip6_ep1;
+		nb_routes6 = RTE_DIM(rt_ip6_ep1);
 	} else
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. Only 0 or 1 "
 			"supported.\n", ep);
 
 	/* create the LPM table */
-	snprintf(name, sizeof(name), "%s_%u", "rt_ipv4", socket_id);
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip4", socket_id);
 	conf.max_rules = RT_IPV4_MAX_RULES;
 	conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
 	lpm = rte_lpm_create(name, socket_id, &conf);
 	if (lpm == NULL)
-		rte_exit(EXIT_FAILURE, "Unable to create LPM table "
-			"on socket %d\n", socket_id);
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
 
 	/* populate the LPM table */
 	for (i = 0; i < nb_routes; i++) {
 		ret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out);
 		if (ret < 0)
-			rte_exit(EXIT_FAILURE, "Unable to add entry num %u to "
-				"LPM table on socket %d\n", i, socket_id);
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
 
 		uint32_t_to_char(rt[i].ip, &a, &b, &c, &d);
 		printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n",
 				a, b, c, d, rt[i].depth, rt[i].if_out);
 	}
 
-	ctx->rt_ipv4 = (struct rt_ctx *)lpm;
+	snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id);
+	conf6.max_rules = RT_IPV6_MAX_RULES;
+	conf6.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
+	lpm6 = rte_lpm6_create(name, socket_id, &conf6);
+	if (lpm6 == NULL)
+		rte_exit(EXIT_FAILURE, "Unable to create %s LPM table "
+			"on socket %d\n", name, socket_id);
+
+	/* populate the LPM table */
+	for (i = 0; i < nb_routes6; i++) {
+		ret = rte_lpm6_add(lpm6, rt6[i].ip, rt6[i].depth,
+				rt6[i].if_out);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
+				"LPM table on socket %d\n", i, name, socket_id);
+
+		printf("LPM6: Adding route "
+			" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n",
+			(uint16_t)((rt6[i].ip[0] << 8) | rt6[i].ip[1]),
+			(uint16_t)((rt6[i].ip[2] << 8) | rt6[i].ip[3]),
+			(uint16_t)((rt6[i].ip[4] << 8) | rt6[i].ip[5]),
+			(uint16_t)((rt6[i].ip[6] << 8) | rt6[i].ip[7]),
+			(uint16_t)((rt6[i].ip[8] << 8) | rt6[i].ip[9]),
+			(uint16_t)((rt6[i].ip[10] << 8) | rt6[i].ip[11]),
+			(uint16_t)((rt6[i].ip[12] << 8) | rt6[i].ip[13]),
+			(uint16_t)((rt6[i].ip[14] << 8) | rt6[i].ip[15]),
+			rt6[i].depth, rt6[i].if_out);
+	}
+
+	ctx->rt_ip4 = (struct rt_ctx *)lpm;
+	ctx->rt_ip6 = (struct rt_ctx *)lpm6;
 }
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a193bdf..8b54beb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -37,12 +37,14 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <rte_memzone.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_byteorder.h>
 #include <rte_errno.h>
+#include <rte_ip.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -51,108 +53,148 @@
 const struct ipsec_sa sa_out[] = {
 	{
 	.spi = 5,
-	.src = IPv4(172, 16, 1, 5),
-	.dst = IPv4(172, 16, 2, 5),
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
 	.spi = 6,
-	.src = IPv4(172, 16, 1, 6),
-	.dst = IPv4(172, 16, 2, 6),
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 7,
-	.src = IPv4(172, 16, 1, 7),
-	.dst = IPv4(172, 16, 2, 7),
+	.spi = 15,
+	.src.ip4 = IPv4(172, 16, 1, 5),
+	.dst.ip4 = IPv4(172, 16, 2, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 16,
+	.src.ip4 = IPv4(172, 16, 1, 6),
+	.dst.ip4 = IPv4(172, 16, 2, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 25,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 8,
-	.src = IPv4(172, 16, 1, 8),
-	.dst = IPv4(172, 16, 2, 8),
+	.spi = 26,
+	.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
+	.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 9,
-	.src = IPv4(172, 16, 1, 9),
-	.dst = IPv4(172, 16, 2, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 /* SAs Inbound */
 const struct ipsec_sa sa_in[] = {
 	{
-	.spi = 55,
-	.src = IPv4(172, 16, 2, 5),
-	.dst = IPv4(172, 16, 1, 5),
+	.spi = 105,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 56,
-	.src = IPv4(172, 16, 2, 6),
-	.dst = IPv4(172, 16, 1, 6),
+	.spi = 106,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 115,
+	.src.ip4 = IPv4(172, 16, 2, 5),
+	.dst.ip4 = IPv4(172, 16, 1, 5),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
 	},
 	{
-	.spi = 57,
-	.src = IPv4(172, 16, 2, 7),
-	.dst = IPv4(172, 16, 1, 7),
+	.spi = 116,
+	.src.ip4 = IPv4(172, 16, 2, 6),
+	.dst.ip4 = IPv4(172, 16, 1, 6),
+	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
+	.auth_algo = RTE_CRYPTO_AUTH_NULL,
+	.digest_len = 0,
+	.iv_len = 0,
+	.block_size = 4,
+	.flags = IP4_TUNNEL
+	},
+	{
+	.spi = 125,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
 	{
-	.spi = 58,
-	.src = IPv4(172, 16, 2, 8),
-	.dst = IPv4(172, 16, 1, 8),
+	.spi = 126,
+	.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+		0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
+	.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
 	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
 	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
 	.digest_len = 12,
 	.iv_len = 16,
 	.block_size = 16,
+	.flags = IP6_TUNNEL
 	},
-	{
-	.spi = 59,
-	.src = IPv4(172, 16, 2, 9),
-	.dst = IPv4(172, 16, 1, 9),
-	.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
-	.auth_algo = RTE_CRYPTO_AUTH_NULL,
-	.digest_len = 0,
-	.iv_len = 0,
-	.block_size = 4,
-	}
 };
 
 static uint8_t cipher_key[256] = "sixteenbytes key";
@@ -217,11 +259,11 @@ struct sa_ctx {
 };
 
 static struct sa_ctx *
-sa_ipv4_create(const char *name, int socket_id)
+sa_create(const char *name, int32_t socket_id)
 {
 	char s[PATH_MAX];
 	struct sa_ctx *sa_ctx;
-	unsigned mz_size;
+	uint32_t mz_size;
 	const struct rte_memzone *mz;
 
 	snprintf(s, sizeof(s), "%s_%u", name, socket_id);
@@ -246,10 +288,10 @@ sa_ipv4_create(const char *name, int socket_id)
 
 static int
 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries, unsigned inbound)
+		uint32_t nb_entries, uint32_t inbound)
 {
 	struct ipsec_sa *sa;
-	unsigned i, idx;
+	uint32_t i, idx;
 
 	for (i = 0; i < nb_entries; i++) {
 		idx = SPI2IDX(entries[i].spi);
@@ -260,8 +302,14 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			return -EINVAL;
 		}
 		*sa = entries[i];
-		sa->src = rte_cpu_to_be_32(sa->src);
-		sa->dst = rte_cpu_to_be_32(sa->dst);
+		sa->seq = 0;
+
+		switch (sa->flags) {
+		case IP4_TUNNEL:
+			sa->src.ip4 = rte_cpu_to_be_32(sa->src.ip4);
+			sa->dst.ip4 = rte_cpu_to_be_32(sa->dst.ip4);
+		}
+
 		if (inbound) {
 			if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
 				sa_ctx->xf[idx].a = null_auth_xf;
@@ -289,33 +337,33 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 
 static inline int
 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 0);
 }
 
 static inline int
 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
-		unsigned nb_entries)
+		uint32_t nb_entries)
 {
 	return sa_add_rules(sa_ctx, entries, nb_entries, 1);
 }
 
 void
-sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
+sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
 {
 	const struct ipsec_sa *sa_out_entries, *sa_in_entries;
-	unsigned nb_out_entries, nb_in_entries;
+	uint32_t nb_out_entries, nb_in_entries;
 	const char *name;
 
 	if (ctx == NULL)
 		rte_exit(EXIT_FAILURE, "NULL context.\n");
 
-	if (ctx->sa_ipv4_in != NULL)
+	if (ctx->sa_in != NULL)
 		rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
-	if (ctx->sa_ipv4_out != NULL)
+	if (ctx->sa_out != NULL)
 		rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
 				"initialized\n", socket_id);
 
@@ -333,21 +381,21 @@ sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
 				"Only 0 or 1 supported.\n", ep);
 
-	name = "sa_ipv4_in";
-	ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_in == NULL)
+	name = "sa_in";
+	ctx->sa_in = sa_create(name, socket_id);
+	if (ctx->sa_in == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	name = "sa_ipv4_out";
-	ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
-	if (ctx->sa_ipv4_out == NULL)
+	name = "sa_out";
+	ctx->sa_out = sa_create(name, socket_id);
+	if (ctx->sa_out == NULL)
 		rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
 				"in socket %d\n", rte_errno, name, socket_id);
 
-	sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
+	sa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);
 
-	sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
+	sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
 }
 
 int
@@ -360,38 +408,63 @@ inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
 	return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
 }
 
+static inline void
+single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
+		struct ipsec_sa **sa_ret)
+{
+	struct esp_hdr *esp;
+	struct ip *ip;
+	uint32_t *src4_addr;
+	uint8_t *src6_addr;
+	struct ipsec_sa *sa;
+
+	*sa_ret = NULL;
+
+	ip = rte_pktmbuf_mtod(pkt, struct ip *);
+	if (ip->ip_v == IPVERSION)
+		esp = (struct esp_hdr *)(ip + 1);
+	else
+		esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
+
+	if (esp->spi == INVALID_SPI)
+		return;
+
+	sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
+	if (rte_be_to_cpu_32(esp->spi) != sa->spi)
+		return;
+
+	switch (sa->flags) {
+	case IP4_TUNNEL:
+		src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
+		if ((ip->ip_v == IPVERSION) &&
+				(sa->src.ip4 == *src4_addr) &&
+				(sa->dst.ip4 == *(src4_addr + 1)))
+			*sa_ret = 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.ip6, src6_addr, 16) &&
+				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
+			*sa_ret = sa;
+	}
+}
+
 void
 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
-	uint32_t *src, spi;
-
-	for (i = 0; i < nb_pkts; i++) {
-		spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
-				sizeof(struct ip))->spi;
+	uint32_t i;
 
-		if (spi == INVALID_SPI)
-			continue;
-
-		sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
-		if (spi != sa[i]->spi) {
-			sa[i] = NULL;
-			continue;
-		}
-
-		src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
-				offsetof(struct ip, ip_src));
-		if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
-			sa[i] = NULL;
-	}
+	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[],
 		struct ipsec_sa *sa[], uint16_t nb_pkts)
 {
-	unsigned i;
+	uint32_t i;
 
 	for (i = 0; i < nb_pkts; i++)
 		sa[i] = &sa_ctx->sa[sa_idx[i]];
diff --git a/examples/ipsec-secgw/sp.c b/examples/ipsec-secgw/sp.c
deleted file mode 100644
index 6aa377d..0000000
--- a/examples/ipsec-secgw/sp.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2016 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Security Policies
- */
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-
-#include <rte_acl.h>
-
-#include "ipsec.h"
-
-#define MAX_ACL_RULE_NUM	1000
-
-/*
- * Rule and trace formats definitions.
- */
-enum {
-	PROTO_FIELD_IPV4,
-	SRC_FIELD_IPV4,
-	DST_FIELD_IPV4,
-	SRCP_FIELD_IPV4,
-	DSTP_FIELD_IPV4,
-	NUM_FIELDS_IPV4
-};
-
-/*
- * That effectively defines order of IPV4 classifications:
- *  - PROTO
- *  - SRC IP ADDRESS
- *  - DST IP ADDRESS
- *  - PORTS (SRC and DST)
- */
-enum {
-	RTE_ACL_IPV4_PROTO,
-	RTE_ACL_IPV4_SRC,
-	RTE_ACL_IPV4_DST,
-	RTE_ACL_IPV4_PORTS,
-	RTE_ACL_IPV4_NUM
-};
-
-struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
-	{
-	.type = RTE_ACL_FIELD_TYPE_BITMASK,
-	.size = sizeof(uint8_t),
-	.field_index = PROTO_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PROTO,
-	.offset = 0,
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = SRC_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_SRC,
-	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_MASK,
-	.size = sizeof(uint32_t),
-	.field_index = DST_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_DST,
-	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = SRCP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
-	},
-	{
-	.type = RTE_ACL_FIELD_TYPE_RANGE,
-	.size = sizeof(uint16_t),
-	.field_index = DSTP_FIELD_IPV4,
-	.input_index = RTE_ACL_IPV4_PORTS,
-	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
-		sizeof(uint16_t)
-	},
-};
-
-RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
-
-const struct acl4_rules acl4_rules_out[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 107, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 108, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 250, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-const struct acl4_rules acl4_rules_in[] = {
-	{
-	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 117, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 118, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	},
-	{
-	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
-	/* destination IPv4 */
-	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
-				.mask_range.u32 = 24,},
-	/* source port */
-	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
-	/* destination port */
-	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
-	}
-};
-
-static void
-print_one_ipv4_rule(const struct acl4_rules *rule, int extra)
-{
-	unsigned char a, b, c, d;
-
-	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[SRC_FIELD_IPV4].mask_range.u32);
-	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
-			&a, &b, &c, &d);
-	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
-			rule->field[DST_FIELD_IPV4].mask_range.u32);
-	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
-		rule->field[SRCP_FIELD_IPV4].value.u16,
-		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
-		rule->field[DSTP_FIELD_IPV4].value.u16,
-		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
-		rule->field[PROTO_FIELD_IPV4].value.u8,
-		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
-	if (extra)
-		printf("0x%x-0x%x-0x%x ",
-			rule->data.category_mask,
-			rule->data.priority,
-			rule->data.userdata);
-}
-
-static inline void
-dump_ipv4_rules(const struct acl4_rules *rule, int num, int extra)
-{
-	int i;
-
-	for (i = 0; i < num; i++, rule++) {
-		printf("\t%d:", i + 1);
-		print_one_ipv4_rule(rule, extra);
-		printf("\n");
-	}
-}
-
-static struct rte_acl_ctx *
-acl4_init(const char *name, int socketid, const struct acl4_rules *rules,
-		unsigned rules_nb)
-{
-	char s[PATH_MAX];
-	struct rte_acl_param acl_param;
-	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);
-
-	memset(&acl_param, 0, sizeof(acl_param));
-
-	/* Create ACL contexts */
-	snprintf(s, sizeof(s), "%s_%d", name, socketid);
-
-	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
-	dump_ipv4_rules(rules, rules_nb, 1);
-
-	acl_param.name = s;
-	acl_param.socket_id = socketid;
-	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ipv4_defs));
-	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
-
-	ctx = rte_acl_create(&acl_param);
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
-
-	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
-				rules_nb) < 0)
-		rte_exit(EXIT_FAILURE, "add rules failed\n");
-
-	/* Perform builds */
-	memset(&acl_build_param, 0, sizeof(acl_build_param));
-
-	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
-	acl_build_param.num_fields = RTE_DIM(ipv4_defs);
-	memcpy(&acl_build_param.defs, ipv4_defs, sizeof(ipv4_defs));
-
-	if (rte_acl_build(ctx, &acl_build_param) != 0)
-		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
-
-	rte_acl_dump(ctx);
-
-	return ctx;
-}
-
-void
-sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
-{
-	const char *name;
-	const struct acl4_rules *rules_out, *rules_in;
-	unsigned nb_out_rules, nb_in_rules;
-
-	if (ctx == NULL)
-		rte_exit(EXIT_FAILURE, "NULL context.\n");
-
-	if (ctx->sp_ipv4_in != NULL)
-		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ctx->sp_ipv4_out != NULL)
-		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
-				"initialized\n", socket_id);
-
-	if (ep == 0) {
-		rules_out = acl4_rules_out;
-		nb_out_rules = RTE_DIM(acl4_rules_out);
-		rules_in = acl4_rules_in;
-		nb_in_rules = RTE_DIM(acl4_rules_in);
-	} else if (ep == 1) {
-		rules_out = acl4_rules_in;
-		nb_out_rules = RTE_DIM(acl4_rules_in);
-		rules_in = acl4_rules_out;
-		nb_in_rules = RTE_DIM(acl4_rules_out);
-	} else
-		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
-				"Only 0 or 1 supported.\n", ep);
-
-	name = "sp_ipv4_in";
-	ctx->sp_ipv4_in = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_in, nb_in_rules);
-
-	name = "sp_ipv4_out";
-	ctx->sp_ipv4_out = (struct sp_ctx *)acl4_init(name, socket_id,
-			rules_out, nb_out_rules);
-}
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
new file mode 100644
index 0000000..61720c8
--- /dev/null
+++ b/examples/ipsec-secgw/sp4.c
@@ -0,0 +1,407 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+/*
+ * Rule and trace formats definitions.
+ */
+enum {
+	PROTO_FIELD_IPV4,
+	SRC_FIELD_IPV4,
+	DST_FIELD_IPV4,
+	SRCP_FIELD_IPV4,
+	DSTP_FIELD_IPV4,
+	NUM_FIELDS_IPV4
+};
+
+/*
+ * That effectively defines order of IPV4 classifications:
+ *  - PROTO
+ *  - SRC IP ADDRESS
+ *  - DST IP ADDRESS
+ *  - PORTS (SRC and DST)
+ */
+enum {
+	RTE_ACL_IPV4_PROTO,
+	RTE_ACL_IPV4_SRC,
+	RTE_ACL_IPV4_DST,
+	RTE_ACL_IPV4_PORTS,
+	RTE_ACL_IPV4_NUM
+};
+
+struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = PROTO_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = SRC_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_SRC,
+	.offset = offsetof(struct ip, ip_src) -	offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = sizeof(uint32_t),
+	.field_index = DST_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_DST,
+	.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = SRCP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = DSTP_FIELD_IPV4,
+	.input_index = RTE_ACL_IPV4_PORTS,
+	.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
+		sizeof(uint16_t)
+	},
+};
+
+RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
+
+const struct acl4_rules acl4_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 201, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 55, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 56, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 241, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl4_rules acl4_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(105), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(106), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(116), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 211, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 65, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 66, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 245, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 246, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static void
+print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[SRC_FIELD_IPV4].mask_range.u32);
+	uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
+			&a, &b, &c, &d);
+	printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
+			rule->field[DST_FIELD_IPV4].mask_range.u32);
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[SRCP_FIELD_IPV4].value.u16,
+		rule->field[SRCP_FIELD_IPV4].mask_range.u16,
+		rule->field[DSTP_FIELD_IPV4].value.u16,
+		rule->field[DSTP_FIELD_IPV4].mask_range.u16,
+		rule->field[PROTO_FIELD_IPV4].value.u8,
+		rule->field[PROTO_FIELD_IPV4].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip4_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip4_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip4_defs);
+	memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl4_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip4_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ctx->sp_ip4_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
+				"initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl4_rules_out;
+		nb_out_rules = RTE_DIM(acl4_rules_out);
+		rules_in = acl4_rules_in;
+		nb_in_rules = RTE_DIM(acl4_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl4_rules_in;
+		nb_out_rules = RTE_DIM(acl4_rules_in);
+		rules_in = acl4_rules_out;
+		nb_in_rules = RTE_DIM(acl4_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip4_in";
+	ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip4_out";
+	ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
new file mode 100644
index 0000000..c6fb851
--- /dev/null
+++ b/examples/ipsec-secgw/sp6.c
@@ -0,0 +1,400 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Security Policies
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <rte_acl.h>
+#include <rte_ip.h>
+
+#include "ipsec.h"
+
+#define MAX_ACL_RULE_NUM	1000
+
+enum {
+	IP6_PROTO,
+	IP6_SRC0,
+	IP6_SRC1,
+	IP6_SRC2,
+	IP6_SRC3,
+	IP6_DST0,
+	IP6_DST1,
+	IP6_DST2,
+	IP6_DST3,
+	IP6_SRCP,
+	IP6_DSTP,
+	IP6_NUM
+};
+
+#define IP6_ADDR_SIZE 16
+
+struct rte_acl_field_def ip6_defs[IP6_NUM] = {
+	{
+	.type = RTE_ACL_FIELD_TYPE_BITMASK,
+	.size = sizeof(uint8_t),
+	.field_index = IP6_PROTO,
+	.input_index = IP6_PROTO,
+	.offset = 0,
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC0,
+	.input_index = IP6_SRC0,
+	.offset = 2
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC1,
+	.input_index = IP6_SRC1,
+	.offset = 6
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC2,
+	.input_index = IP6_SRC2,
+	.offset = 10
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_SRC3,
+	.input_index = IP6_SRC3,
+	.offset = 14
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST0,
+	.input_index = IP6_DST0,
+	.offset = 18
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST1,
+	.input_index = IP6_DST1,
+	.offset = 22
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST2,
+	.input_index = IP6_DST2,
+	.offset = 26
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_MASK,
+	.size = 4,
+	.field_index = IP6_DST3,
+	.input_index = IP6_DST3,
+	.offset = 30
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_SRCP,
+	.input_index = IP6_SRCP,
+	.offset = 34
+	},
+	{
+	.type = RTE_ACL_FIELD_TYPE_RANGE,
+	.size = sizeof(uint16_t),
+	.field_index = IP6_DSTP,
+	.input_index = IP6_SRCP,
+	.offset = 36
+	}
+};
+
+RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
+
+const struct acl6_rules acl6_rules_out[] = {
+	{
+	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+const struct acl6_rules acl6_rules_in[] = {
+	{
+	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	}
+};
+
+static inline void
+print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
+{
+	uint8_t a, b, c, d;
+
+	uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_SRC0].mask_range.u32
+			+ rule->field[IP6_SRC1].mask_range.u32
+			+ rule->field[IP6_SRC2].mask_range.u32
+			+ rule->field[IP6_SRC3].mask_range.u32);
+
+	uint32_t_to_char(rule->field[IP6_DST0].value.u32,
+		&a, &b, &c, &d);
+	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST1].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST2].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
+	uint32_t_to_char(rule->field[IP6_DST3].value.u32,
+		&a, &b, &c, &d);
+	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
+			rule->field[IP6_DST0].mask_range.u32
+			+ rule->field[IP6_DST1].mask_range.u32
+			+ rule->field[IP6_DST2].mask_range.u32
+			+ rule->field[IP6_DST3].mask_range.u32);
+
+	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
+		rule->field[IP6_SRCP].value.u16,
+		rule->field[IP6_SRCP].mask_range.u16,
+		rule->field[IP6_DSTP].value.u16,
+		rule->field[IP6_DSTP].mask_range.u16,
+		rule->field[IP6_PROTO].value.u8,
+		rule->field[IP6_PROTO].mask_range.u8);
+	if (extra)
+		printf("0x%x-0x%x-0x%x ",
+			rule->data.category_mask,
+			rule->data.priority,
+			rule->data.userdata);
+}
+
+static inline void
+dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
+{
+	int32_t i;
+
+	for (i = 0; i < num; i++, rule++) {
+		printf("\t%d:", i + 1);
+		print_one_ip6_rule(rule, extra);
+		printf("\n");
+	}
+}
+
+static struct rte_acl_ctx *
+acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
+		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;
+
+	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
+
+	memset(&acl_param, 0, sizeof(acl_param));
+
+	/* Create ACL contexts */
+	snprintf(s, sizeof(s), "%s_%d", name, socketid);
+
+	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
+	dump_ip6_rules(rules, rules_nb, 1);
+
+	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;
+
+	ctx = rte_acl_create(&acl_param);
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
+
+	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
+				rules_nb) < 0)
+		rte_exit(EXIT_FAILURE, "add rules failed\n");
+
+	/* Perform builds */
+	memset(&acl_build_param, 0, sizeof(acl_build_param));
+
+	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
+	acl_build_param.num_fields = RTE_DIM(ip6_defs);
+	memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
+
+	if (rte_acl_build(ctx, &acl_build_param) != 0)
+		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
+
+	rte_acl_dump(ctx);
+
+	return ctx;
+}
+
+void
+sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
+{
+	const char *name;
+	const struct acl6_rules *rules_out, *rules_in;
+	uint32_t nb_out_rules, nb_in_rules;
+
+	if (ctx == NULL)
+		rte_exit(EXIT_FAILURE, "NULL context.\n");
+
+	if (ctx->sp_ip6_in != NULL)
+		rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ctx->sp_ip6_out != NULL)
+		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
+				"already initialized\n", socket_id);
+
+	if (ep == 0) {
+		rules_out = acl6_rules_out;
+		nb_out_rules = RTE_DIM(acl6_rules_out);
+		rules_in = acl6_rules_in;
+		nb_in_rules = RTE_DIM(acl6_rules_in);
+	} else if (ep == 1) {
+		rules_out = acl6_rules_in;
+		nb_out_rules = RTE_DIM(acl6_rules_in);
+		rules_in = acl6_rules_out;
+		nb_in_rules = RTE_DIM(acl6_rules_out);
+	} else
+		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
+				"Only 0 or 1 supported.\n", ep);
+
+	name = "sp_ip6_in";
+	ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_in, nb_in_rules);
+
+	name = "sp_ip6_out";
+	ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,
+			rules_out, nb_out_rules);
+}
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 8/9] examples/ipsec-secgw: transport mode support
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (6 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
  2016-06-09 11:58     ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements De Lara Guarch, Pablo
  9 siblings, 0 replies; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

IPSec transport mode support.

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 examples/ipsec-secgw/esp.c   | 124 ++++++++++++++++++++++++++++++-------------
 examples/ipsec-secgw/ipsec.h |   1 +
 examples/ipsec-secgw/rt.c    |  32 +++++++++++
 examples/ipsec-secgw/sa.c    |  39 ++++++++++++++
 examples/ipsec-secgw/sp4.c   |  40 ++++++++++++++
 examples/ipsec-secgw/sp6.c   |  48 +++++++++++++++++
 6 files changed, 248 insertions(+), 36 deletions(-)

diff --git a/examples/ipsec-secgw/esp.c b/examples/ipsec-secgw/esp.c
index e1fde36..05caa77 100644
--- a/examples/ipsec-secgw/esp.c
+++ b/examples/ipsec-secgw/esp.c
@@ -42,7 +42,6 @@
 #include <unistd.h>
 
 #include <rte_common.h>
-#include <rte_memcpy.h>
 #include <rte_crypto.h>
 #include <rte_cryptodev.h>
 #include <rte_random.h>
@@ -70,21 +69,24 @@ int
 esp_inbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	int32_t payload_len, ip_hdr_len;
+	struct ip *ip4;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t payload_len, ip_hdr_len;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
-		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION))
+		ip_hdr_len = ip4->ip_hl * 4;
+	else if (ip4->ip_v == IP6_VERSION)
+		/* XXX No option headers supported */
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
+	else {
+		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
 	}
 
 	payload_len = rte_pktmbuf_pkt_len(m) - ip_hdr_len -
@@ -126,6 +128,8 @@ int
 esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
+	struct ip *ip4, *ip;
+	struct ip6_hdr *ip6;
 	uint8_t *nexthdr, *pad_len;
 	uint8_t *padding;
 	uint16_t i;
@@ -135,7 +139,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	RTE_ASSERT(cop != NULL);
 
 	if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
-		RTE_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
+		RTE_LOG(ERR, IPSEC_ESP, "failed crypto op\n");
 		return -1;
 	}
 
@@ -146,7 +150,7 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 	padding = pad_len - *pad_len;
 	for (i = 0; i < *pad_len; i++) {
 		if (padding[i] != i + 1) {
-			RTE_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
+			RTE_LOG(ERR, IPSEC_ESP, "invalid padding\n");
 			return -EINVAL;
 		}
 	}
@@ -157,7 +161,23 @@ esp_inbound_post(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
+	if (unlikely(sa->flags == TRANSPORT)) {
+		ip = rte_pktmbuf_mtod(m, struct ip *);
+		ip4 = (struct ip *)rte_pktmbuf_adj(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		if (likely(ip->ip_v == IPVERSION)) {
+			memmove(ip4, ip, ip->ip_hl * 4);
+			ip4->ip_p = *nexthdr;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)ip4;
+			/* XXX No option headers supported */
+			memmove(ip6, ip, sizeof(struct ip6_hdr));
+			ip6->ip6_nxt = *nexthdr;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
+	} else
+		ipip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
 
 	return 0;
 }
@@ -166,31 +186,57 @@ int
 esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		struct rte_crypto_op *cop)
 {
-	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 	struct ip *ip4;
 	struct ip6_hdr *ip6;
-	struct esp_hdr *esp;
-	int32_t i;
-	char *padding;
+	struct esp_hdr *esp = NULL;
+	uint8_t *padding, *new_ip, nlp;
 	struct rte_crypto_sym_op *sym_cop;
+	int32_t i;
+	uint16_t pad_payload_len, pad_len, ip_hdr_len;
 
 	RTE_ASSERT(m != NULL);
 	RTE_ASSERT(sa != NULL);
 	RTE_ASSERT(cop != NULL);
 
-	/* Payload length */
-	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) + 2,
-			sa->block_size);
-	pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
-
 	ip_hdr_len = 0;
-	switch (sa->flags) {
-	case IP4_TUNNEL:
+
+	ip4 = rte_pktmbuf_mtod(m, struct ip *);
+	if (likely(ip4->ip_v == IPVERSION)) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			ip_hdr_len = ip4->ip_hl * 4;
+			nlp = ip4->ip_p;
+		} else
+			nlp = IPPROTO_IPIP;
+	} else if (ip4->ip_v == IP6_VERSION) {
+		if (unlikely(sa->flags == TRANSPORT)) {
+			/* XXX No option headers supported */
+			ip_hdr_len = sizeof(struct ip6_hdr);
+			ip6 = (struct ip6_hdr *)ip4;
+			nlp = ip6->ip6_nxt;
+		} else
+			nlp = IPPROTO_IPV6;
+	} else {
+		RTE_LOG(ERR, IPSEC_ESP, "invalid IP packet type %d\n",
+				ip4->ip_v);
+		return -EINVAL;
+	}
+
+	/* Padded payload length */
+	pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) -
+			ip_hdr_len + 2, sa->block_size);
+	pad_len = pad_payload_len + ip_hdr_len - rte_pktmbuf_pkt_len(m);
+
+	RTE_ASSERT(sa->flags == IP4_TUNNEL || sa->flags == IP6_TUNNEL ||
+			sa->flags == TRANSPORT);
+
+	if (likely(sa->flags == IP4_TUNNEL))
 		ip_hdr_len = sizeof(struct ip);
-		break;
-	case IP6_TUNNEL:
+	else if (sa->flags == IP6_TUNNEL)
 		ip_hdr_len = sizeof(struct ip6_hdr);
-		break;
+	else if (sa->flags != TRANSPORT) {
+		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
+				sa->flags);
+		return -EINVAL;
 	}
 
 	/* Check maximum packet size */
@@ -200,7 +246,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 		return -EINVAL;
 	}
 
-	padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
+	padding = (uint8_t *)rte_pktmbuf_append(m, pad_len + sa->digest_len);
 	if (unlikely(padding == NULL)) {
 		RTE_LOG(ERR, IPSEC_ESP, "not enough mbuf trailing space\n");
 		return -ENOSPC;
@@ -218,10 +264,20 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 				&sa->src, &sa->dst);
 		esp = (struct esp_hdr *)(ip6 + 1);
 		break;
-	default:
-		RTE_LOG(ERR, IPSEC_ESP, "Unsupported SA flags: 0x%x\n",
-				sa->flags);
-		return -EINVAL;
+	case TRANSPORT:
+		new_ip = (uint8_t *)rte_pktmbuf_prepend(m,
+				sizeof(struct esp_hdr) + sa->iv_len);
+		memmove(new_ip, ip4, ip_hdr_len);
+		esp = (struct esp_hdr *)(new_ip + ip_hdr_len);
+		if (likely(ip4->ip_v == IPVERSION)) {
+			ip4 = (struct ip *)new_ip;
+			ip4->ip_p = IPPROTO_ESP;
+			ip4->ip_len = htons(rte_pktmbuf_data_len(m));
+		} else {
+			ip6 = (struct ip6_hdr *)new_ip;
+			ip6->ip6_nxt = IPPROTO_ESP;
+			ip6->ip6_plen = htons(rte_pktmbuf_data_len(m));
+		}
 	}
 
 	sa->seq++;
@@ -235,11 +291,7 @@ esp_outbound(struct rte_mbuf *m, struct ipsec_sa *sa,
 	for (i = 0; i < pad_len - 2; i++)
 		padding[i] = i + 1;
 	padding[pad_len - 2] = pad_len - 2;
-
-	if (RTE_ETH_IS_IPV4_HDR(m->packet_type))
-		padding[pad_len - 1] = IPPROTO_IPIP;
-	else
-		padding[pad_len - 1] = IPPROTO_IPV6;
+	padding[pad_len - 1] = nlp;
 
 	sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
 
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 83d7b1c..0d2ee25 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -103,6 +103,7 @@ struct ipsec_sa {
 	uint16_t flags;
 #define IP4_TUNNEL (1 << 0)
 #define IP6_TUNNEL (1 << 1)
+#define TRANSPORT  (1 << 2)
 	struct ip_addr src;
 	struct ip_addr dst;
 	struct rte_crypto_sym_xform *xforms;
diff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c
index d46df49..fa5f042 100644
--- a/examples/ipsec-secgw/rt.c
+++ b/examples/ipsec-secgw/rt.c
@@ -62,6 +62,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 2, 5), 32, 0 },
 	{ IPv4(172, 16, 2, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 0 },
+	{ IPv4(192, 168, 176, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 240, 0), 24, 0 },
 	{ IPv4(192, 168, 241, 0), 24, 1 },
@@ -72,6 +75,9 @@ static struct ip4_route rt_ip4_ep0[] = {
 	{ IPv4(192, 168, 116, 0), 24, 3 },
 	{ IPv4(192, 168, 65, 0), 24, 2 },
 	{ IPv4(192, 168, 66, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 2 },
+	{ IPv4(192, 168, 186, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 210, 0), 24, 2 },
 	{ IPv4(192, 168, 211, 0), 24, 3 },
@@ -87,6 +93,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
 	{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 		  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 	/* Inbound */
 	/* Tunnels */
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
@@ -97,6 +108,11 @@ static struct ip6_route rt_ip6_ep0[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 static struct ip4_route rt_ip4_ep1[] = {
@@ -104,6 +120,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	/* Tunnels */
 	{ IPv4(172, 16, 1, 5), 32, 0 },
 	{ IPv4(172, 16, 1, 6), 32, 1 },
+	/* Transport */
+	{ IPv4(192, 168, 185, 0), 24, 0 },
+	{ IPv4(192, 168, 186, 0), 24, 1 },
 	/* Bypass */
 	{ IPv4(192, 168, 245, 0), 24, 0 },
 	{ IPv4(192, 168, 246, 0), 24, 1 },
@@ -114,6 +133,9 @@ static struct ip4_route rt_ip4_ep1[] = {
 	{ IPv4(192, 168, 106, 0), 24, 3 },
 	{ IPv4(192, 168, 55, 0), 24, 2 },
 	{ IPv4(192, 168, 56, 0), 24, 3 },
+	/* Transport */
+	{ IPv4(192, 168, 175, 0), 24, 2 },
+	{ IPv4(192, 168, 176, 0), 24, 3 },
 	/* NULL */
 	{ IPv4(192, 168, 200, 0), 24, 2 },
 	{ IPv4(192, 168, 201, 0), 24, 3 },
@@ -129,6 +151,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
 	{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
 		  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
+	/* Transport */
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
+	{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
 
 	/* Inbound */
 	/* Tunnels */
@@ -140,6 +167,11 @@ static struct ip6_route rt_ip6_ep1[] = {
 		  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
 	{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
 		  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
+	/* Transport */
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
+	{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
+		  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
 };
 
 void
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 8b54beb..ab18b81 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -74,6 +74,24 @@ const struct ipsec_sa sa_out[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 10,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 11,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 15,
 	.src.ip4 = IPv4(172, 16, 1, 5),
 	.dst.ip4 = IPv4(172, 16, 2, 5),
@@ -148,6 +166,24 @@ const struct ipsec_sa sa_in[] = {
 	.flags = IP4_TUNNEL
 	},
 	{
+	.spi = 110,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
+	.spi = 111,
+	.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
+	.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
+	.digest_len = 12,
+	.iv_len = 16,
+	.block_size = 16,
+	.flags = TRANSPORT
+	},
+	{
 	.spi = 115,
 	.src.ip4 = IPv4(172, 16, 2, 5),
 	.dst.ip4 = IPv4(172, 16, 1, 5),
@@ -447,6 +483,9 @@ single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
 				!memcmp(&sa->src.ip6, src6_addr, 16) &&
 				!memcmp(&sa->dst.ip6, src6_addr + 16, 16))
 			*sa_ret = sa;
+		break;
+	case TRANSPORT:
+		*sa_ret = sa;
 	}
 }
 
diff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c
index 61720c8..9c4b256 100644
--- a/examples/ipsec-secgw/sp4.c
+++ b/examples/ipsec-secgw/sp4.c
@@ -135,6 +135,26 @@ const struct acl4_rules acl4_rules_out[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 175, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 176, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
@@ -218,6 +238,26 @@ const struct acl4_rules acl4_rules_in[] = {
 	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 185, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv4 */
+	.field[2] = {.value.u32 = IPv4(192, 168, 186, 0),
+				.mask_range.u32 = 24,},
+	/* source port */
+	.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
 	/* destination IPv4 */
 	.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
diff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c
index c6fb851..1dda11a 100644
--- a/examples/ipsec-secgw/sp6.c
+++ b/examples/ipsec-secgw/sp6.c
@@ -170,6 +170,30 @@ const struct acl6_rules acl6_rules_out[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
@@ -221,6 +245,30 @@ const struct acl6_rules acl6_rules_in[] = {
 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
 	},
 	{
+	.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
+	.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
+	/* destination IPv6 */
+	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
+	.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
+	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
+	/* source port */
+	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
+	/* destination port */
+	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
+	},
+	{
 	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
 	/* destination IPv6 */
 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
-- 
2.5.5

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

* [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (7 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
@ 2016-06-09  8:42     ` Sergio Gonzalez Monroy
  2016-06-09 11:11       ` Mcnamara, John
  2016-06-09 11:58     ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements De Lara Guarch, Pablo
  9 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-06-09  8:42 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, john.mcnamara

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
---
 doc/guides/sample_app_ug/img/ipsec_endpoints.svg | 850 +++++++++++++++++++++
 doc/guides/sample_app_ug/ipsec_secgw.rst         | 910 ++++++++++++++---------
 2 files changed, 1400 insertions(+), 360 deletions(-)
 create mode 100644 doc/guides/sample_app_ug/img/ipsec_endpoints.svg

diff --git a/doc/guides/sample_app_ug/img/ipsec_endpoints.svg b/doc/guides/sample_app_ug/img/ipsec_endpoints.svg
new file mode 100644
index 0000000..e4aba4c
--- /dev/null
+++ b/doc/guides/sample_app_ug/img/ipsec_endpoints.svg
@@ -0,0 +1,850 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="155.68507mm"
+   height="76.061203mm"
+   viewBox="0 0 551.64003 269.50821"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="endpoints.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker18451"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path18453"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker18273"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path18275" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10612"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Send">
+      <path
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#cfce37;fill-opacity:1;fill-rule:evenodd;stroke:#cfce37;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path10614"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10270"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path10272"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Sstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker9102"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path9104"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#035002;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.2,0,0,0.2,1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Sstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Sstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5945"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#d4ce00;fill-opacity:1;fill-rule:evenodd;stroke:#d4ce00;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.2,0,0,0.2,1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       id="linearGradient11398"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop11400" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop11402" />
+    </linearGradient>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9540"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9542"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       id="linearGradient9336"
+       osb:paint="solid">
+      <stop
+         style="stop-color:#dc181a;stop-opacity:1;"
+         offset="0"
+         id="stop9338" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7350"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7352"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4871"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7092"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path7094"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5822"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5824"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path5371"
+         style="fill:#035002;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutL"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5013"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="scale(0.8,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Tail"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Tail"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <g
+         id="g4907"
+         transform="scale(-1.2,-1.2)"
+         style="fill:#528ac6;fill-opacity:1;stroke:#000000;stroke-opacity:1">
+        <path
+           id="path4909"
+           d="M -3.8048674,-3.9585227 0.54352094,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4911"
+           d="M -1.2866832,-3.9585227 3.0617053,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4913"
+           d="M 1.3053582,-3.9585227 5.6537466,0"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4915"
+           d="M -3.8048674,4.1775838 0.54352094,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4917"
+           d="M -1.2866832,4.1775838 3.0617053,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+        <path
+           id="path4919"
+           d="M 1.3053582,4.1775838 5.6537466,0.21974226"
+           style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-opacity:1"
+           inkscape:connector-curvature="0" />
+      </g>
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Send"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4904"
+         style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4886"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#528ac6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4874"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4-3"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7-7"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5734-4-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path5736-7-1"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-1"
+         style="fill:#d4ce00;fill-opacity:1;fill-rule:evenodd;stroke:#d4ce00;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-9"
+         style="fill:#38782d;fill-opacity:1;fill-rule:evenodd;stroke:#38782d;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5369-3-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5371-1-0"
+         style="fill:#38782d;fill-opacity:1;fill-rule:evenodd;stroke:#38782d;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker18451-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path18453-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart-7"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4871-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7350-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7352-0"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="258.01346"
+     inkscape:cy="122.99559"
+     inkscape:document-units="cm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     inkscape:window-x="1592"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     fit-margin-top="3"
+     fit-margin-right="1"
+     fit-margin-bottom="1"
+     fit-margin-left="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(194.35761,4.2637303)">
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5"
+       width="131.15564"
+       height="102.30846"
+       x="-179.57692"
+       y="140.22072"
+       ry="7.155364" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-1"
+       width="131.15564"
+       height="102.30846"
+       x="213.55591"
+       y="140.22072"
+       ry="6.5590839" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-2"
+       width="131.15564"
+       height="46.258114"
+       x="-179.57692"
+       y="6.3661909"
+       ry="5.3665228" />
+    <rect
+       style="opacity:1;fill:#528ac6;fill-opacity:1;stroke:none;stroke-opacity:1"
+       id="rect4140-5-2-7"
+       width="131.15564"
+       height="46.258114"
+       x="213.55591"
+       y="6.3661909"
+       ry="6.5590839" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-182.36929"
+       y="188.59424"
+       id="text4210"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4212"
+         x="-182.36929"
+         y="188.59424">ep0</tspan><tspan
+         sodipodi:role="line"
+         x="-182.36929"
+         y="208.69011"
+         id="tspan4214" /><tspan
+         sodipodi:role="line"
+         x="-182.36929"
+         y="228.786"
+         id="tspan4216" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="324.621"
+       y="188.49612"
+       id="text4218"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4220"
+         x="324.621"
+         y="188.49612">ep1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-159.97678"
+       y="32.860863"
+       id="text4222"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4224"
+         x="-159.97678"
+         y="32.860863">traffic gen</tspan><tspan
+         sodipodi:role="line"
+         x="-159.97678"
+         y="52.956738"
+         id="tspan4226" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="249.77068"
+       y="32.860863"
+       id="text4222-1"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan4224-1"
+         x="249.77068"
+         y="32.860863">traffic gen</tspan><tspan
+         sodipodi:role="line"
+         x="249.77068"
+         y="52.956738"
+         id="tspan4226-6" /></text>
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="m -48.997848,184.52811 c 260.957198,-0.5963 260.957198,-0.5963 260.957198,-0.5963"
+       id="path5305"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker10270)"
+       d="M -47.641399,212.81116 C 213.3158,212.21487 213.3158,212.21487 213.3158,212.21487"
+       id="path5305-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7350)"
+       d="m 262.8239,53.615939 c 0,85.864371 0,85.864371 0,85.864371"
+       id="path5922-0-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
+       d="m -146.8568,54.80849 c 0,85.86437 0,85.86437 0,85.86437"
+       id="path5922-0-1"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="246.78571"
+       y="500.57648"
+       id="text7750"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7752"
+         x="246.78571"
+         y="500.57648" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-158.9595"
+       y="151.84753"
+       id="text7754"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7756"
+         x="-158.9595"
+         y="151.84753">2</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-110.66317"
+       y="151.84753"
+       id="text7758"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7760"
+         x="-110.66317"
+         y="151.84753">3</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="267.07309"
+       y="151.84753"
+       id="text7762"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7764"
+         x="267.07309"
+         y="151.84753">2</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="318.81448"
+       y="151.84753"
+       id="text7766"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7768"
+         x="318.81448"
+         y="151.84753">3</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="225.86406"
+       y="183.73483"
+       id="text7770"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7772"
+         x="225.86406"
+         y="183.73483">0</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="226.18214"
+       y="211.56969"
+       id="text7774"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7776"
+         x="226.18214"
+         y="211.56969">1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:11.25px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="311.78571"
+       y="505.93362"
+       id="text7778"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan7780"
+         x="311.78571"
+         y="505.93362" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-65.239075"
+       y="183.73483"
+       id="text7782"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7784"
+         x="-65.239075"
+         y="183.73483">0</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:18.08628845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-64.921005"
+       y="211.56969"
+       id="text7786"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7788"
+         x="-64.921005"
+         y="211.56969">1</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#dc181a;stroke-width:1.60606241;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:3.21212486, 9.63637456;stroke-dashoffset:0;stroke-opacity:1"
+       d="M -190.00162,248.33118 C -74.638406,174.62535 10.240093,56.871479 81.499676,57.515772 176.72224,59.019701 245.16177,197.27679 352.92565,246.54234"
+       id="path7850"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#dc181a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="84.985992"
+       y="98.449951"
+       id="text7876"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7878"
+         x="84.985992"
+         y="98.449951">UNPROTECTED</tspan><tspan
+         sodipodi:role="line"
+         x="84.985992"
+         y="118.54583"
+         id="tspan7886">cipher-text</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#dc181a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="84.899643"
+       y="20.937273"
+       id="text7880"
+       sodipodi:linespacing="125%"
+       inkscape:transform-center-x="48.100163"
+       inkscape:transform-center-y="3.577681"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan7882"
+         x="84.899643"
+         y="20.937273">PROTECTED</tspan><tspan
+         sodipodi:role="line"
+         x="84.899643"
+         y="41.03315"
+         id="tspan7884">clear-text</tspan></text>
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:3.42781782;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5369)"
+       d="m -101.57521,164.71986 c -0.0232,13.22578 17.528492,19.5572 32.486212,20.12768"
+       id="path9370"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:3.08351111;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5369-3)"
+       d="m 231.46374,184.56991 c 19.27508,-1.72507 24.47287,-7.77038 31.06883,-19.63365"
+       id="path9370-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.8206749px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="60.45417"
+       y="251.78688"
+       id="text14635"
+       sodipodi:linespacing="125%"
+       transform="scale(0.9630889,1.0383257)"><tspan
+         sodipodi:role="line"
+         id="tspan14637"
+         x="60.45417"
+         y="251.78688">outbound</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16.07670021px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="62.073208"
+       y="232.23116"
+       id="text14635-4"
+       sodipodi:linespacing="125%"
+       transform="scale(0.96291595,1.0385122)"><tspan
+         sodipodi:role="line"
+         id="tspan14637-2"
+         x="62.073208"
+         y="232.23116">inbound</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:3.8278625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Sstart)"
+       d="m -144.07995,171.20523 c 15.90052,30.60035 40.80354,39.04445 75.670299,43.29761"
+       id="path9370-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#035002;stroke-width:3.73783302;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker9102)"
+       d="m 236.99654,212.30897 c 40.08586,-4.29157 62.39356,-19.33069 76.11102,-48.84339"
+       id="path9370-8-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#d4ce00;stroke-width:4.01917505;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 32.274837,235.80819 c 18.037567,-0.2236 20.456397,-0.29813 20.456397,-0.29813"
+       id="path10604"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#035002;stroke-width:4.01917505;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 32.274837,256.82674 c 18.037567,-0.22362 20.456397,-0.29814 20.456397,-0.29814"
+       id="path10604-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart-7)"
+       d="m -100.78618,138.21108 c 0,-85.864363 0,-85.864363 0,-85.864363"
+       id="path5922-0-1-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.60767007px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7350-9)"
+       d="m 312.42811,137.49681 c 0,-85.864382 0,-85.864382 0,-85.864382"
+       id="path5922-0-6-9"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index c11c7e7..66dd326 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -38,165 +38,171 @@ Overview
 --------
 
 The application demonstrates the implementation of a Security Gateway
-(not IPsec compliant, see Constraints bellow) using DPDK based on RFC4301,
+(not IPsec compliant, see the Constraints section below) using DPDK based on RFC4301,
 RFC4303, RFC3602 and RFC2404.
 
 Internet Key Exchange (IKE) is not implemented, so only manual setting of
 Security Policies and Security Associations is supported.
 
 The Security Policies (SP) are implemented as ACL rules, the Security
-Associations (SA) are stored in a table and the Routing is implemented
+Associations (SA) are stored in a table and the routing is implemented
 using LPM.
 
-The application classify the ports between Protected and Unprotected.
-Thus, traffic received in an Unprotected or Protected port is consider
+The application classifies the ports as *Protected* and *Unprotected*.
+Thus, traffic received on an Unprotected or Protected port is consider
 Inbound or Outbound respectively.
 
-Path for IPsec Inbound traffic:
+The Path for IPsec Inbound traffic is:
 
-*  Read packets from the port
+*  Read packets from the port.
 *  Classify packets between IPv4 and ESP.
-*  Inbound SA lookup for ESP packets based on their SPI
-*  Verification/Decryption
-*  Removal of ESP and outer IP header
-*  Inbound SP check using ACL of decrypted packets and any other IPv4 packet
-   we read.
-*  Routing
-*  Write packet to port
-
-Path for IPsec Outbound traffic:
-
-*  Read packets from the port
-*  Outbound SP check using ACL of all IPv4 traffic
-*  Outbound SA lookup for packets that need IPsec protection
-*  Add ESP and outer IP header
-*  Encryption/Digest
-*  Routing
-*  Write packet to port
+*  Perform Inbound SA lookup for ESP packets based on their SPI.
+*  Perform Verification/Decryption.
+*  Remove ESP and outer IP header
+*  Inbound SP check using ACL of decrypted packets and any other IPv4 packets.
+*  Routing.
+*  Write packet to port.
+
+The Path for the IPsec Outbound traffic is:
+
+*  Read packets from the port.
+*  Perform Outbound SP check using ACL of all IPv4 traffic.
+*  Perform Outbound SA lookup for packets that need IPsec protection.
+*  Add ESP and outer IP header.
+*  Perform Encryption/Digest.
+*  Routing.
+*  Write packet to port.
+
 
 Constraints
 -----------
-*  IPv4 traffic
-*  ESP tunnel mode
-*  EAS-CBC, HMAC-SHA1 and NULL
-*  Each SA must be handle by a unique lcore (1 RX queue per port)
-*  No chained mbufs
+
+*  No IPv6 options headers.
+*  No AH mode.
+*  Currently only EAS-CBC, HMAC-SHA1 and NULL.
+*  Each SA must be handle by a unique lcore (*1 RX queue per port*).
+*  No chained mbufs.
+
 
 Compiling the Application
 -------------------------
 
 To compile the application:
 
-#. Go to the sample application directory:
-
-   .. code-block:: console
+#. Go to the sample application directory::
 
       export RTE_SDK=/path/to/rte_sdk
       cd ${RTE_SDK}/examples/ipsec-secgw
 
-#. Set the target (a default target is used if not specified). For example:
+#. Set the target (a default target is used if not specified). For example::
 
-   .. code-block:: console
 
       export RTE_TARGET=x86_64-native-linuxapp-gcc
 
    See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
 
-#. Build the application:
-
-   .. code-block:: console
+#. Build the application::
 
        make
 
+#. [Optional] Build the application for debugging:
+   This option adds some extra flags, disables compiler optimizations and
+   is verbose::
+
+       make DEBUG=1
+
+
 Running the Application
 -----------------------
 
-The application has a number of command line options:
+The application has a number of command line options::
 
-.. code-block:: console
 
-   ./build/ipsec-secgw [EAL options] -- -p PORTMASK -P -u PORTMASK --config
-   (port,queue,lcore)[,(port,queue,lcore] --single-sa SAIDX --ep0|--ep1
+   ./build/ipsec-secgw [EAL options] --
+                        -p PORTMASK -P -u PORTMASK
+                        --config (port,queue,lcore)[,(port,queue,lcore]
+                        --single-sa SAIDX
+			--ep0|--ep1
 
-where,
+Where:
 
-*   -p PORTMASK: Hexadecimal bitmask of ports to configure
+*   ``-p PORTMASK``: Hexadecimal bitmask of ports to configure.
 
-*   -P: optional, sets all ports to promiscuous mode so that packets are
+*   ``-P``: *optional*. Sets all ports to promiscuous mode so that packets are
     accepted regardless of the packet's Ethernet MAC destination address.
     Without this option, only packets with the Ethernet MAC destination address
     set to the Ethernet address of the port are accepted (default is enabled).
 
-*   -u PORTMASK: hexadecimal bitmask of unprotected ports
+*   ``-u PORTMASK``: hexadecimal bitmask of unprotected ports
 
-*   --config (port,queue,lcore)[,(port,queue,lcore)]: determines which queues
-    from which ports are mapped to which cores
+*   ``--config (port,queue,lcore)[,(port,queue,lcore)]``: determines which queues
+    from which ports are mapped to which cores.
 
-*   --single-sa SAIDX: use a single SA for outbound traffic, bypassing the SP
+*   ``--single-sa SAIDX``: use a single SA for outbound traffic, bypassing the SP
     on both Inbound and Outbound. This option is meant for debugging/performance
     purposes.
 
-*   --ep0: configure the app as Endpoint 0.
+*   ``--ep0``: configure the app as Endpoint 0.
 
-*   --ep1: configure the app as Endpoint 1.
+*   ``--ep1``: configure the app as Endpoint 1.
 
-Either one of --ep0 or --ep1 *must* be specified.
-The main purpose of these options is two easily configure two systems
-back-to-back that would forward traffic through an IPsec tunnel.
+Either one of ``--ep0`` or ``--ep1`` **must** be specified.
+The main purpose of these options is to easily configure two systems
+back-to-back that would forward traffic through an IPsec tunnel (see
+:ref:`figure_ipsec_endpoints`).
 
 The mapping of lcores to port/queues is similar to other l3fwd applications.
 
-For example, given the following command line:
+For example, given the following command line::
 
-.. code-block:: console
-
-    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
-           --vdev "cryptodev_null_pmd" -- -p 0xf -P -u 0x3
-           --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" --ep0
+    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048       \
+           --vdev "cryptodev_null_pmd" -- -p 0xf -P -u 0x3      \
+           --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" --ep0 \
 
 where each options means:
 
-*   The -l option enables cores 20 and 21
+*   The ``-l`` option enables cores 20 and 21.
 
-*   The -n option sets memory 4 channels
+*   The ``-n`` option sets memory 4 channels.
 
-*   The --socket-mem to use 2GB on socket 1
+*   The ``--socket-mem`` to use 2GB on socket 1.
 
-*   The --vdev "cryptodev_null_pmd" option creates virtual NULL cryptodev PMD
+*   The ``--vdev "cryptodev_null_pmd"`` option creates virtual NULL cryptodev PMD.
 
-*   The -p option enables ports (detected) 0, 1, 2 and 3
+*   The ``-p`` option enables ports (detected) 0, 1, 2 and 3.
 
-*   The -P option enables promiscuous mode
+*   The ``-P`` option enables promiscuous mode.
 
-*   The -u option sets ports 1 and 2 as unprotected, leaving 2 and 3 as protected
+*   The ``-u`` option sets ports 1 and 2 as unprotected, leaving 2 and 3 as protected.
 
-*   The --config option enables one queue per port with the following mapping:
+*   The ``--config`` option enables one queue per port with the following mapping:
 
-+----------+-----------+-----------+---------------------------------------+
-| **Port** | **Queue** | **lcore** | **Description**                       |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 0        | 0         | 20        | Map queue 0 from port 0 to lcore 20.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 1        | 0         | 20        | Map queue 0 from port 1 to lcore 20.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 2        | 0         | 21        | Map queue 0 from port 2 to lcore 21.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
-| 3        | 0         | 21        | Map queue 0 from port 3 to lcore 21.  |
-|          |           |           |                                       |
-+----------+-----------+-----------+---------------------------------------+
+    +----------+-----------+-----------+---------------------------------------+
+    | **Port** | **Queue** | **lcore** | **Description**                       |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 0        | 0         | 20        | Map queue 0 from port 0 to lcore 20.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 1        | 0         | 20        | Map queue 0 from port 1 to lcore 20.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 2        | 0         | 21        | Map queue 0 from port 2 to lcore 21.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
+    | 3        | 0         | 21        | Map queue 0 from port 3 to lcore 21.  |
+    |          |           |           |                                       |
+    +----------+-----------+-----------+---------------------------------------+
 
-*   The --ep0 options configures the app with a given set of SP, SA and Routing
+*   The ``--ep0`` options configures the app with a given set of SP, SA and Routing
     entries as explained below in more detail.
 
 Refer to the *DPDK Getting Started Guide* for general information on running
 applications and the Environment Abstraction Layer (EAL) options.
 
 The application would do a best effort to "map" crypto devices to cores, with
-hardware devices having priority.
+hardware devices having priority. Basically, hardware devices if present would
+be assigned to a core before software ones.
 This means that if the application is using a single core and both hardware
 and software crypto devices are detected, hardware devices will be used.
 
@@ -208,18 +214,35 @@ For example, something like the following command line:
 
 .. code-block:: console
 
-    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
-            -w 81:00.0 -w 81:00.1 -w 81:00.2 -w 81:00.3
-            --vdev "cryptodev_aesni_mb_pmd" --vdev "cryptodev_null_pmd" --
-            -p 0xf -P -u 0x3 --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)"
+    ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048 \
+            -w 81:00.0 -w 81:00.1 -w 81:00.2 -w 81:00.3 \
+            --vdev "cryptodev_aesni_mb_pmd" --vdev "cryptodev_null_pmd" \
+	    -- \
+            -p 0xf -P -u 0x3 --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" \
             --ep0
 
+
 Configurations
 --------------
 
 The following sections provide some details on the default values used to
 initialize the SP, SA and Routing tables.
-Currently all the configuration is hard coded into the application.
+Currently all configuration information is hard coded into the application.
+
+The following image illustrate a few of the concepts regarding IPSec, such
+as protected/unprotected and inbound/outbound traffic, from the point of
+view of two back-to-back endpoints:
+
+.. _figure_ipsec_endpoints:
+
+.. figure:: img/ipsec_endpoints.svg
+
+   IPSec Inbound/Outbound traffic
+
+Note that the above image only displays unidirectional traffic per port
+for illustration purposes.
+The application supports bidirectional traffic on all ports,
+
 
 Security Policy Initialization
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -228,107 +251,126 @@ As mention in the overview, the Security Policies are ACL rules.
 The application defines two ACLs, one each of Inbound and Outbound, and
 it replicates them per socket in use.
 
-Following are the default rules:
-
-Endpoint 0 Outbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 0 Inbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Outbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.115.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.116.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.117.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.118.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.210.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.240.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-
-Endpoint 1 Inbound Security Policies:
-
-+---------+------------------+-----------+------------+
-| **Src** | **Dst**          | **proto** | **SA idx** |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.105.0/24 | Any       | 5          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.106.0/24 | Any       | 6          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.107.0/24 | Any       | 7          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.108.0/24 | Any       | 8          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.200.0/24 | Any       | 9          |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
-| Any     | 192.168.250.0/24 | Any       | BYPASS     |
-|         |                  |           |            |
-+---------+------------------+-----------+------------+
+Following are the default rules which show only the relevant information,
+assuming ANY value is valid for the fields not mentioned (src ip, proto,
+src/dst ports).
+
+.. _table_ipsec_endpoint_outbound_sp:
+
+.. table:: Endpoint 0 Outbound Security Policies
+
+   +-----------------------------------+------------+
+   | **Dst**                           | **SA idx** |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.105.0/24                  | 5          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.106.0/24                  | 6          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.175.0/24                  | 10         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.176.0/24                  | 11         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.200.0/24                  | 15         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.201.0/24                  | 16         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.55.0/24                   | 25         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.56.0/24                   | 26         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.240.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.241.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:5555:5555:0:0/96          | 5          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:6666:6666:0:0/96          | 6          |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:1111:1111:0:0:0:0/96          | 10         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:1111:1111:1111:1111:0:0/96    | 11         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:aaaa:aaaa:0:0/96          | 25         |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 0:0:0:0:bbbb:bbbb:0:0/96          | 26         |
+   |                                   |            |
+   +-----------------------------------+------------+
+
+.. _table_ipsec_endpoint_inbound_sp:
+
+.. table:: Endpoint 0 Inbound Security Policies
+
+   +-----------------------------------+------------+
+   | **Dst**                           | **SA idx** |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.115.0/24                  | 105        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.116.0/24                  | 106        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.185.0/24                  | 110        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.186.0/24                  | 111        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.210.0/24                  | 115        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.211.0/24                  | 116        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.65.0/24                   | 125        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.66.0/24                   | 126        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.245.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | 192.168.246.0/24                  | BYPASS     |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:5555:5555:0:0/96       | 105        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:6666:6666:0:0/96       | 106        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:1111:1111:0:0:0:0/96       | 110        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:1111:1111:1111:1111:0:0/96 | 111        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:aaaa:aaaa:0:0/96       | 125        |
+   |                                   |            |
+   +-----------------------------------+------------+
+   | ffff:0:0:0:bbbb:bbbb:0:0/96       | 126        |
+   |                                   |            |
+   +-----------------------------------+------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
 
 
 Security Association Initialization
@@ -336,7 +378,7 @@ Security Association Initialization
 
 The SAs are kept in a array table.
 
-For Inbound, the SPI is used as index module the table size.
+For Inbound, the SPI is used as index modulo the table size.
 This means that on a table for 100 SA, SPI 5 and 105 would use the same index
 and that is not currently supported.
 
@@ -346,179 +388,327 @@ not the SPI in the Security Policy.
 All SAs configured with AES-CBC and HMAC-SHA1 share the same values for cipher
 block size and key, and authentication digest size and key.
 
-Following are the default values:
-
-Endpoint 0 Outbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 0 Inbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Outbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.2.7     | 172.16.1.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.2.8     | 172.16.1.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.2.5     | 172.16.1.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-
-Endpoint 1 Inbound Security Associations:
-
-+---------+------------+-----------+----------------+------------------+
-| **SPI** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst**   |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 5       | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 6       | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 7       | AES-CBC    | HMAC-SHA1 | 172.16.1.7     | 172.16.2.7       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 8       | AES-CBC    | HMAC-SHA1 | 172.16.1.8     | 172.16.2.8       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
-| 9       | NULL       | NULL      | 172.16.1.5     | 172.16.2.5       |
-|         |            |           |                |                  |
-+---------+------------+-----------+----------------+------------------+
+The following are the default values:
+
+.. _table_ipsec_endpoint_outbound_sa:
+
+.. table:: Endpoint 0 Outbound Security Associations
+
+   +---------+----------+------------+-----------+----------------+----------------+
+   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 5       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 6       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 10      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 11      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 15      | Tunnel   | NULL       | NULL      | 172.16.1.5     | 172.16.2.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 16      | Tunnel   | NULL       | NULL      | 172.16.1.6     | 172.16.2.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 25      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:5555      | 2222:5555      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 26      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:1111:     | 2222:2222:     |
+   |         |          |            |           | 1111:6666      | 2222:6666      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+
+.. _table_ipsec_endpoint_inbound_sa:
+
+.. table:: Endpoint 0 Inbound Security Associations
+
+   +---------+----------+------------+-----------+----------------+----------------+
+   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 105     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 106     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 110     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 111     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 115     | Tunnel   | NULL       | NULL      | 172.16.2.5     | 172.16.1.5     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 116     | Tunnel   | NULL       | NULL      | 172.16.2.6     | 172.16.1.6     |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 125     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:5555      | 1111:5555      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+   | 126     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:2222:     | 1111:1111:     |
+   |         |          |            |           | 2222:6666      | 1111:6666      |
+   |         |          |            |           |                |                |
+   +---------+----------+------------+-----------+----------------+----------------+
+
+For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
+entries are set as Outbound and vice versa.
+
 
 Routing Initialization
 ~~~~~~~~~~~~~~~~~~~~~~
 
-The Routing is implemented using LPM table.
+The Routing is implemented using an LPM table.
 
 Following default values:
 
-Endpoint 0 Routing Table:
-
-+------------------+----------+
-| **Dst addr**     | **Port** |
-|                  |          |
-+------------------+----------+
-| 172.16.2.5/32    | 0        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.6/32    | 0        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.7/32    | 1        |
-|                  |          |
-+------------------+----------+
-| 172.16.2.8/32    | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.115.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.116.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.117.0/24 | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.118.0/24 | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.210.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.240.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.250.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-
-Endpoint 1 Routing Table:
-
-+------------------+----------+
-| **Dst addr**     | **Port** |
-|                  |          |
-+------------------+----------+
-| 172.16.1.5/32    | 2        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.6/32    | 2        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.7/32    | 3        |
-|                  |          |
-+------------------+----------+
-| 172.16.1.8/32    | 3        |
-|                  |          |
-+------------------+----------+
-| 192.168.105.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.106.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.107.0/24 | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.108.0/24 | 1        |
-|                  |          |
-+------------------+----------+
-| 192.168.200.0/24 | 0        |
-|                  |          |
-+------------------+----------+
-| 192.168.240.0/24 | 2        |
-|                  |          |
-+------------------+----------+
-| 192.168.250.0/24 | 0        |
-|                  |          |
-+------------------+----------+
+.. _table_ipsec_endpoint_outbound_routing:
+
+.. table:: Endpoint 0 Routing Table
+
+   +------------------+----------+
+   | **Dst addr**     | **Port** |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.2.5/32    | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.2.6/32    | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.175.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.176.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.240.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.241.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.115.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.116.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.65.0/24  | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.66.0/24  | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.185.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.186.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.210.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.211.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.245.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.246.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 2222:2222:       | 0        |
+   | 2222:2222:       |          |
+   | 2222:2222:       |          |
+   | 2222:5555/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 2222:2222:       | 1        |
+   | 2222:2222:       |          |
+   | 2222:2222:       |          |
+   | 2222:6666/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 0        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 0000:0000:       |          |
+   | aaaa:aaaa:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 0000:0000:       |          |
+   | bbbb:bbbb:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 0000:0000:       |          |
+   | 5555:5555:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 0000:0000:       |          |
+   | 6666:6666:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 2        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 3        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+
+.. _table_ipsec_endpoint_inbound_routing:
+
+.. table:: Endpoint 1 Routing Table
+
+   +------------------+----------+
+   | **Dst addr**     | **Port** |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.1.5/32    | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 172.16.1.6/32    | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.185.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.186.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.245.0/24 | 0        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.246.0/24 | 1        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.105.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.106.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.55.0/24  | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.56.0/24  | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.175.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.176.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.200.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.201.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.240.0/24 | 2        |
+   |                  |          |
+   +------------------+----------+
+   | 192.168.241.0/24 | 3        |
+   |                  |          |
+   +------------------+----------+
+   | 1111:1111:       | 0        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 1111:5555/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 1111:1111:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 1111:6666/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 0        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | ffff:0000:       | 1        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 0000:0000:       |          |
+   | aaaa:aaaa:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 0000:0000:       |          |
+   | bbbb:bbbb:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 0000:0000:       |          |
+   | 5555:5555:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 0000:0000:       |          |
+   | 6666:6666:       |          |
+   | 0000:0/116       |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 2        |
+   | 1111:1111:       |          |
+   | 0000:0000:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
+   | 0000:0000:       | 3        |
+   | 1111:1111:       |          |
+   | 1111:1111:       |          |
+   | 0000:0000/116    |          |
+   |                  |          |
+   +------------------+----------+
-- 
2.5.5

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

* Re: [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-06-09 11:11       ` Mcnamara, John
  0 siblings, 0 replies; 41+ messages in thread
From: Mcnamara, John @ 2016-06-09 11:11 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev; +Cc: De Lara Guarch, Pablo

> -----Original Message-----
> From: Gonzalez Monroy, Sergio
> Sent: Thursday, June 9, 2016 9:43 AM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>; Mcnamara, John
> <john.mcnamara@intel.com>
> Subject: [PATCH v3 9/9] doc: update ipsec sample guide
> 
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
>
> ...
>
>  Configurations
>  --------------
> 
>  The following sections provide some details on the default values used to
>  initialize the SP, SA and Routing tables.
> -Currently all the configuration is hard coded into the application.
> +Currently all configuration information is hard coded into the
> application.
> +
> +The following image illustrate a few of the concepts regarding IPSec,
> such
> +as protected/unprotected and inbound/outbound traffic, from the point of
> +view of two back-to-back endpoints:
> +
> +.. _figure_ipsec_endpoints:
> +
> +.. figure:: img/ipsec_endpoints.svg
> +
> +   IPSec Inbound/Outbound traffic

Hi,

This file throws an error with make doc-guides-pdf.

The image needs to be specified as "img/ipsec_endpoints.*" (now .svg) to 
allow it to be converted from svg to pdf.

With this fix the build works.

John

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

* Re: [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements
  2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
                       ` (8 preceding siblings ...)
  2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
@ 2016-06-09 11:58     ` De Lara Guarch, Pablo
  2016-06-21 10:14       ` Thomas Monjalon
  9 siblings, 1 reply; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-06-09 11:58 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev; +Cc: Mcnamara, John



> -----Original Message-----
> From: Gonzalez Monroy, Sergio
> Sent: Thursday, June 09, 2016 9:43 AM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo; Mcnamara, John
> Subject: [PATCH v3 0/9] IPSec Enhancements
> 
> Update IPSec sample app with IPv6 and Transport mode support.
> 
> The series contains some bug fixes to facilitate patch merge.
> 
> v3:
>  - change ipip_inbound function to reurn void
>  - update some commit message and comments
> 
> v2:
>  - rebase code
>  - doc improvements
>  - add missing image file
> 
> Sergio Gonzalez Monroy (9):
>   examples/ipsec-secgw: fix esp padding check
>   examples/ipsec-secgw: fix stack smashing error
>   examples/ipsec-secgw: add build option and cleanup
>   examples/ipsec-secgw: rework ipsec execution loop
>   examples/ipsec-secgw: fix no sa found case
>   examples/ipsec-secgw: consistent config variable names
>   examples/ipsec-secgw: ipv6 support
>   examples/ipsec-secgw: transport mode support
>   doc: update ipsec sample guide
> 
>  doc/guides/sample_app_ug/img/ipsec_endpoints.svg | 850
> +++++++++++++++++++++
>  doc/guides/sample_app_ug/ipsec_secgw.rst         | 910 ++++++++++++++------
> ---
>  examples/ipsec-secgw/Makefile                    |   8 +-
>  examples/ipsec-secgw/esp.c                       | 210 ++++--
>  examples/ipsec-secgw/esp.h                       |   9 +-
>  examples/ipsec-secgw/ipip.h                      | 149 +++-
>  examples/ipsec-secgw/ipsec-secgw.c               | 332 ++++++---
>  examples/ipsec-secgw/ipsec.c                     |  50 +-
>  examples/ipsec-secgw/ipsec.h                     |  63 +-
>  examples/ipsec-secgw/rt.c                        | 229 ++++--
>  examples/ipsec-secgw/sa.c                        | 466 +++++++-----
>  examples/ipsec-secgw/sp.c                        | 366 ---------
>  examples/ipsec-secgw/sp4.c                       | 447 +++++++++++
>  examples/ipsec-secgw/sp6.c                       | 448 +++++++++++
>  14 files changed, 3313 insertions(+), 1224 deletions(-)
>  create mode 100644 doc/guides/sample_app_ug/img/ipsec_endpoints.svg
>  delete mode 100644 examples/ipsec-secgw/sp.c
>  create mode 100644 examples/ipsec-secgw/sp4.c
>  create mode 100644 examples/ipsec-secgw/sp6.c
> 
> --
> 2.5.5

Series-acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

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

* Re: [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements
  2016-06-09 11:58     ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements De Lara Guarch, Pablo
@ 2016-06-21 10:14       ` Thomas Monjalon
  0 siblings, 0 replies; 41+ messages in thread
From: Thomas Monjalon @ 2016-06-21 10:14 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio; +Cc: dev, De Lara Guarch, Pablo, Mcnamara, John

> > Sergio Gonzalez Monroy (9):
> >   examples/ipsec-secgw: fix esp padding check
> >   examples/ipsec-secgw: fix stack smashing error
> >   examples/ipsec-secgw: add build option and cleanup
> >   examples/ipsec-secgw: rework ipsec execution loop
> >   examples/ipsec-secgw: fix no sa found case
> >   examples/ipsec-secgw: consistent config variable names
> >   examples/ipsec-secgw: ipv6 support
> >   examples/ipsec-secgw: transport mode support
> >   doc: update ipsec sample guide
> 
> Series-acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

Applied (with the fix suggested by John for the PDF doc), thanks.

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

* Re: [dpdk-dev] [PATCH v3 0/9] IPsec Enhancements
  2016-09-30  0:27   ` De Lara Guarch, Pablo
@ 2016-10-05  0:43     ` De Lara Guarch, Pablo
  0 siblings, 0 replies; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-10-05  0:43 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, Gonzalez Monroy, Sergio, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of De Lara Guarch,
> Pablo
> Sent: Thursday, September 29, 2016 5:28 PM
> To: Gonzalez Monroy, Sergio; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v3 0/9] IPsec Enhancements
> 
> 
> 
> > -----Original Message-----
> > From: Gonzalez Monroy, Sergio
> > Sent: Thursday, September 29, 2016 8:44 AM
> > To: dev@dpdk.org
> > Cc: De Lara Guarch, Pablo
> > Subject: [PATCH v3 0/9] IPsec Enhancements
> >
> > This patch set mainly adds support for AES-GCM and AES-CTR.
> >
> > It also updates the IV generation method for AES-CBC mode using
> > the forward function instead of randomly generating the IV.
> >
> > v3:
> >  - update sample app guide
> >  - remove unused function
> >  - improve commit messages
> >
> > v2:
> >  - Update releas notes.
> >  - Initialize salt values, GCM/CTR key length now is 20B,
> >    16B key and 4 LSB salt.
> >  - Do not check SP/ACL if we have no rules.
> >  - Add macro for cryptodev queue size
> >
> > Dependencies:
> > examples/ipsec-secgw: add configuration file support
> > http://dpdk.org/dev/patchwork/patch/16004/
> >
> > examples/ipsec-secgw: add sample configuration files
> > http://dpdk.org/dev/patchwork/patch/16003/
> >
> > Sergio Gonzalez Monroy (9):
> >   examples/ipsec-secgw: change CBC IV generation
> >   examples/ipsec-secgw: reset crypto operation status
> >   examples/ipsec-secgw: add AES-GCM support
> >   examples/ipsec-secgw: enable AES-CTR mode
> >   examples/ipsec-secgw: check sp only when setup
> >   examples/ipsec-secgw: add cryptodev queue size macro
> >   examples/ipsec-secgw: initialize sa salt
> >   examples/ipsec-secgw: update release notes
> >   examples/ipsec-secgw: update ipsec-secgw guide
> >
> >  doc/guides/rel_notes/release_16_11.rst   |   9 ++
> >  doc/guides/sample_app_ug/ipsec_secgw.rst |  15 ++--
> >  examples/ipsec-secgw/esp.c               | 144 ++++++++++++++++++++++---------
> >  examples/ipsec-secgw/ipsec-secgw.c       |   7 +-
> >  examples/ipsec-secgw/ipsec.c             |   1 +
> >  examples/ipsec-secgw/ipsec.h             |  35 +++++++-
> >  examples/ipsec-secgw/sa.c                |  54 ++++++++++--
> >  7 files changed, 207 insertions(+), 58 deletions(-)
> >
> > --
> > 2.5.5
> 
> Series-acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

Applied to dpdk-next-crypto.
Thanks,

Pablo

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

* Re: [dpdk-dev] [PATCH v3 0/9] IPsec Enhancements
  2016-09-29 15:44 ` [dpdk-dev] [PATCH v3 0/9] " Sergio Gonzalez Monroy
@ 2016-09-30  0:27   ` De Lara Guarch, Pablo
  2016-10-05  0:43     ` De Lara Guarch, Pablo
  0 siblings, 1 reply; 41+ messages in thread
From: De Lara Guarch, Pablo @ 2016-09-30  0:27 UTC (permalink / raw)
  To: Gonzalez Monroy, Sergio, dev



> -----Original Message-----
> From: Gonzalez Monroy, Sergio
> Sent: Thursday, September 29, 2016 8:44 AM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo
> Subject: [PATCH v3 0/9] IPsec Enhancements
> 
> This patch set mainly adds support for AES-GCM and AES-CTR.
> 
> It also updates the IV generation method for AES-CBC mode using
> the forward function instead of randomly generating the IV.
> 
> v3:
>  - update sample app guide
>  - remove unused function
>  - improve commit messages
> 
> v2:
>  - Update releas notes.
>  - Initialize salt values, GCM/CTR key length now is 20B,
>    16B key and 4 LSB salt.
>  - Do not check SP/ACL if we have no rules.
>  - Add macro for cryptodev queue size
> 
> Dependencies:
> examples/ipsec-secgw: add configuration file support
> http://dpdk.org/dev/patchwork/patch/16004/
> 
> examples/ipsec-secgw: add sample configuration files
> http://dpdk.org/dev/patchwork/patch/16003/
> 
> Sergio Gonzalez Monroy (9):
>   examples/ipsec-secgw: change CBC IV generation
>   examples/ipsec-secgw: reset crypto operation status
>   examples/ipsec-secgw: add AES-GCM support
>   examples/ipsec-secgw: enable AES-CTR mode
>   examples/ipsec-secgw: check sp only when setup
>   examples/ipsec-secgw: add cryptodev queue size macro
>   examples/ipsec-secgw: initialize sa salt
>   examples/ipsec-secgw: update release notes
>   examples/ipsec-secgw: update ipsec-secgw guide
> 
>  doc/guides/rel_notes/release_16_11.rst   |   9 ++
>  doc/guides/sample_app_ug/ipsec_secgw.rst |  15 ++--
>  examples/ipsec-secgw/esp.c               | 144 ++++++++++++++++++++++---------
>  examples/ipsec-secgw/ipsec-secgw.c       |   7 +-
>  examples/ipsec-secgw/ipsec.c             |   1 +
>  examples/ipsec-secgw/ipsec.h             |  35 +++++++-
>  examples/ipsec-secgw/sa.c                |  54 ++++++++++--
>  7 files changed, 207 insertions(+), 58 deletions(-)
> 
> --
> 2.5.5

Series-acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

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

* [dpdk-dev] [PATCH v3 0/9] IPsec Enhancements
  2016-09-23  7:45 [dpdk-dev] [PATCH v2 0/8] IPsec Enhancements Sergio Gonzalez Monroy
@ 2016-09-29 15:44 ` Sergio Gonzalez Monroy
  2016-09-30  0:27   ` De Lara Guarch, Pablo
  0 siblings, 1 reply; 41+ messages in thread
From: Sergio Gonzalez Monroy @ 2016-09-29 15:44 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch

This patch set mainly adds support for AES-GCM and AES-CTR.

It also updates the IV generation method for AES-CBC mode using
the forward function instead of randomly generating the IV.

v3:
 - update sample app guide
 - remove unused function
 - improve commit messages

v2:
 - Update releas notes.
 - Initialize salt values, GCM/CTR key length now is 20B,
   16B key and 4 LSB salt.
 - Do not check SP/ACL if we have no rules.
 - Add macro for cryptodev queue size

Dependencies:
examples/ipsec-secgw: add configuration file support
http://dpdk.org/dev/patchwork/patch/16004/

examples/ipsec-secgw: add sample configuration files
http://dpdk.org/dev/patchwork/patch/16003/

Sergio Gonzalez Monroy (9):
  examples/ipsec-secgw: change CBC IV generation
  examples/ipsec-secgw: reset crypto operation status
  examples/ipsec-secgw: add AES-GCM support
  examples/ipsec-secgw: enable AES-CTR mode
  examples/ipsec-secgw: check sp only when setup
  examples/ipsec-secgw: add cryptodev queue size macro
  examples/ipsec-secgw: initialize sa salt
  examples/ipsec-secgw: update release notes
  examples/ipsec-secgw: update ipsec-secgw guide

 doc/guides/rel_notes/release_16_11.rst   |   9 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst |  15 ++--
 examples/ipsec-secgw/esp.c               | 144 ++++++++++++++++++++++---------
 examples/ipsec-secgw/ipsec-secgw.c       |   7 +-
 examples/ipsec-secgw/ipsec.c             |   1 +
 examples/ipsec-secgw/ipsec.h             |  35 +++++++-
 examples/ipsec-secgw/sa.c                |  54 ++++++++++--
 7 files changed, 207 insertions(+), 58 deletions(-)

-- 
2.5.5

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

end of thread, other threads:[~2016-10-05  0:43 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-06 16:31 [dpdk-dev] [PATCH 0/9] IPSec example enhancements Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
2016-05-06 16:31 ` [dpdk-dev] [PATCH 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
2016-05-10  9:21   ` Mcnamara, John
2016-05-18 12:42 ` [dpdk-dev] [PATCH v2 0/9] IPSec enhancements Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
2016-06-07 12:50     ` De Lara Guarch, Pablo
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
2016-06-07 13:17     ` De Lara Guarch, Pablo
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
2016-06-07 16:10     ` De Lara Guarch, Pablo
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
2016-05-18 12:42   ` [dpdk-dev] [PATCH v2 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
2016-05-18 13:43     ` Mcnamara, John
2016-06-09  8:42   ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 1/9] examples/ipsec-secgw: fix esp padding check Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 2/9] examples/ipsec-secgw: fix stack smashing error Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 3/9] examples/ipsec-secgw: add build option and cleanup Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 4/9] examples/ipsec-secgw: rework ipsec execution loop Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 5/9] examples/ipsec-secgw: fix no sa found case Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 6/9] examples/ipsec-secgw: consistent config variable names Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 7/9] examples/ipsec-secgw: ipv6 support Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 8/9] examples/ipsec-secgw: transport mode support Sergio Gonzalez Monroy
2016-06-09  8:42     ` [dpdk-dev] [PATCH v3 9/9] doc: update ipsec sample guide Sergio Gonzalez Monroy
2016-06-09 11:11       ` Mcnamara, John
2016-06-09 11:58     ` [dpdk-dev] [PATCH v3 0/9] IPSec Enhancements De Lara Guarch, Pablo
2016-06-21 10:14       ` Thomas Monjalon
2016-09-23  7:45 [dpdk-dev] [PATCH v2 0/8] IPsec Enhancements Sergio Gonzalez Monroy
2016-09-29 15:44 ` [dpdk-dev] [PATCH v3 0/9] " Sergio Gonzalez Monroy
2016-09-30  0:27   ` De Lara Guarch, Pablo
2016-10-05  0:43     ` De Lara Guarch, Pablo

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