[v9,04/10] ipsec: add support for NAT-T

Message ID 20211013121331.300245-5-radu.nicolau@intel.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series new features for ipsec and security libraries |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Radu Nicolau Oct. 13, 2021, 12:13 p.m. UTC
  Add support for the IPsec NAT-Traversal use case for Tunnel mode
packets.

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
Signed-off-by: Abhijit Sinha <abhijit.sinha@intel.com>
Signed-off-by: Daniel Martin Buckley <daniel.m.buckley@intel.com>
Acked-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 doc/guides/prog_guide/ipsec_lib.rst    |  2 ++
 doc/guides/rel_notes/release_21_11.rst |  1 +
 lib/ipsec/esp_outb.c                   |  9 ++++++
 lib/ipsec/rte_ipsec_sa.h               |  9 +++++-
 lib/ipsec/sa.c                         | 39 ++++++++++++++++++++++----
 5 files changed, 54 insertions(+), 6 deletions(-)
  

Comments

Ananyev, Konstantin Oct. 14, 2021, 12:34 p.m. UTC | #1
> 
> Add support for the IPsec NAT-Traversal use case for Tunnel mode
> packets.
> 
> Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
> Signed-off-by: Abhijit Sinha <abhijit.sinha@intel.com>
> Signed-off-by: Daniel Martin Buckley <daniel.m.buckley@intel.com>
> Acked-by: Fan Zhang <roy.fan.zhang@intel.com>
> ---
>  doc/guides/prog_guide/ipsec_lib.rst    |  2 ++
>  doc/guides/rel_notes/release_21_11.rst |  1 +
>  lib/ipsec/esp_outb.c                   |  9 ++++++
>  lib/ipsec/rte_ipsec_sa.h               |  9 +++++-
>  lib/ipsec/sa.c                         | 39 ++++++++++++++++++++++----
>  5 files changed, 54 insertions(+), 6 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst
> index 93e213bf36..af51ff8131 100644
> --- a/doc/guides/prog_guide/ipsec_lib.rst
> +++ b/doc/guides/prog_guide/ipsec_lib.rst
> @@ -313,6 +313,8 @@ Supported features
> 
>  *  ESN and replay window.
> 
> +*  NAT-T / UDP encapsulated ESP.
> +
>  *  algorithms: 3DES-CBC, AES-CBC, AES-CTR, AES-GCM, AES_CCM, CHACHA20_POLY1305,
>     AES_GMAC, HMAC-SHA1, NULL.
> 
> diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst
> index 1748c2db05..e9fb169d44 100644
> --- a/doc/guides/rel_notes/release_21_11.rst
> +++ b/doc/guides/rel_notes/release_21_11.rst
> @@ -157,6 +157,7 @@ New Features
>  * **IPsec library new features.**
> 
>    * Added support for AEAD algorithms AES_CCM, CHACHA20_POLY1305 and AES_GMAC.
> +  * Added support for NAT-T / UDP encapsulated ESP
> 
> 
>  Removed Items
> diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
> index a3f77469c3..0e3314b358 100644
> --- a/lib/ipsec/esp_outb.c
> +++ b/lib/ipsec/esp_outb.c
> @@ -5,6 +5,7 @@
>  #include <rte_ipsec.h>
>  #include <rte_esp.h>
>  #include <rte_ip.h>
> +#include <rte_udp.h>
>  #include <rte_errno.h>
>  #include <rte_cryptodev.h>
> 
> @@ -185,6 +186,14 @@ outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
>  	/* copy tunnel pkt header */
>  	rte_memcpy(ph, sa->hdr, sa->hdr_len);
> 
> +	/* if UDP encap is enabled update the dgram_len */
> +	if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
> +		struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
> +				(ph - sizeof(struct rte_udp_hdr));
> +		udph->dgram_len = rte_cpu_to_be_16(mb->pkt_len - sqh_len -
> +				sa->hdr_l3_off - sa->hdr_len);
> +	}
> +
>  	/* update original and new ip header fields */
>  	update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen,
>  			mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc));
> diff --git a/lib/ipsec/rte_ipsec_sa.h b/lib/ipsec/rte_ipsec_sa.h
> index cf51ad8338..3a22705055 100644
> --- a/lib/ipsec/rte_ipsec_sa.h
> +++ b/lib/ipsec/rte_ipsec_sa.h
> @@ -78,6 +78,7 @@ struct rte_ipsec_sa_prm {
>   * - for TUNNEL outer IP version (IPv4/IPv6)
>   * - are SA SQN operations 'atomic'
>   * - ESN enabled/disabled
> + * - NAT-T UDP encapsulated (TUNNEL mode only)
>   * ...
>   */
> 
> @@ -89,7 +90,8 @@ enum {
>  	RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2,
>  	RTE_SATP_LOG2_ESN,
>  	RTE_SATP_LOG2_ECN,
> -	RTE_SATP_LOG2_DSCP
> +	RTE_SATP_LOG2_DSCP,
> +	RTE_SATP_LOG2_NATT
>  };
> 
>  #define RTE_IPSEC_SATP_IPV_MASK		(1ULL << RTE_SATP_LOG2_IPV)
> @@ -125,6 +127,11 @@ enum {
>  #define RTE_IPSEC_SATP_DSCP_DISABLE	(0ULL << RTE_SATP_LOG2_DSCP)
>  #define RTE_IPSEC_SATP_DSCP_ENABLE	(1ULL << RTE_SATP_LOG2_DSCP)
> 
> +#define RTE_IPSEC_SATP_NATT_MASK	(1ULL << RTE_SATP_LOG2_NATT)
> +#define RTE_IPSEC_SATP_NATT_DISABLE	(0ULL << RTE_SATP_LOG2_NATT)
> +#define RTE_IPSEC_SATP_NATT_ENABLE	(1ULL << RTE_SATP_LOG2_NATT)
> +
> +
>  /**
>   * get type of given SA
>   * @return
> diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
> index 720e0f365b..2830506385 100644
> --- a/lib/ipsec/sa.c
> +++ b/lib/ipsec/sa.c
> @@ -5,6 +5,7 @@
>  #include <rte_ipsec.h>
>  #include <rte_esp.h>
>  #include <rte_ip.h>
> +#include <rte_udp.h>
>  #include <rte_errno.h>
>  #include <rte_cryptodev.h>
> 
> @@ -217,6 +218,10 @@ fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
>  	} else
>  		return -EINVAL;
> 
> +	/* check for UDP encapsulation flag */
> +	if (prm->ipsec_xform.options.udp_encap == 1)
> +		tp |= RTE_IPSEC_SATP_NATT_ENABLE;
> +
>  	/* check for ESN flag */
>  	if (prm->ipsec_xform.options.esn == 0)
>  		tp |= RTE_IPSEC_SATP_ESN_DISABLE;
> @@ -348,20 +353,36 @@ esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
>  /*
>   * Init ESP outbound tunnel specific things.
>   */
> -static void
> +static int
>  esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
>  {
>  	sa->proto = prm->tun.next_proto;
>  	sa->hdr_len = prm->tun.hdr_len;
>  	sa->hdr_l3_off = prm->tun.hdr_l3_off;
> 
> +	if (prm->tun.hdr_len > IPSEC_MAX_HDR_SIZE)
> +		return -EINVAL;

That's not exactly what I asked for.
We already have this check in rte_ipsec_sa_init():

if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
                        prm->tun.hdr_len > sizeof(sa->hdr))

What we need to check is that if NATT enabled, then our new header size wouldn't overflow
our sa->hdr buffer.
So I'd suggest we do instead of that check above, we do something like:
  
 --- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -560,7 +560,7 @@ rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
        uint32_t size)
 {
        int32_t rc, sz;
-       uint32_t nb, wsz;
+       uint32_t hlen, nb, wsz;
        uint64_t type;
        struct crypto_xform cxf;

@@ -584,9 +584,14 @@ rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
        if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
                return -EINVAL;

-       if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL &&
-                       prm->tun.hdr_len > sizeof(sa->hdr))
-               return -EINVAL;
+       if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
+
+               hlen = prm->tun.hdr_len;
+               if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE)
+                       hlen += sizeof(struct rte_udp_hdr);
+               if (hlen > sizeof(sa->hdr))
+                       return -EINVAL;
+       }

        rc = fill_crypto_xform(&cxf, type, prm);
        if (rc != 0)

Then again, we can keep esp_outb_tun_init() as void.
With that in place, feel free to add:
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>


> +	memcpy(sa->hdr, prm->tun.hdr, prm->tun.hdr_len);
> +
> +	/* insert UDP header if UDP encapsulation is inabled */
> +	if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
> +		struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
> +				&sa->hdr[prm->tun.hdr_len];
> +		sa->hdr_len += sizeof(struct rte_udp_hdr);
> +		if (sa->hdr_len > IPSEC_MAX_HDR_SIZE)
> +			return -EINVAL;
> +		udph->src_port = prm->ipsec_xform.udp.sport;
> +		udph->dst_port = prm->ipsec_xform.udp.dport;
> +		udph->dgram_cksum = 0;
> +	}
> +
>  	/* update l2_len and l3_len fields for outbound mbuf */
>  	sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
>  		sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
> 
> -	memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
> -
>  	esp_outb_init(sa, sa->hdr_len);
> +
> +	return 0;
>  }
> 
>  /*
> @@ -372,7 +393,8 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
>  	const struct crypto_xform *cxf)
>  {
>  	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
> -				RTE_IPSEC_SATP_MODE_MASK;
> +				RTE_IPSEC_SATP_MODE_MASK |
> +				RTE_IPSEC_SATP_NATT_MASK;
> 
>  	if (prm->ipsec_xform.options.ecn)
>  		sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
> @@ -475,10 +497,17 @@ esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
>  	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
>  		esp_inb_init(sa);
>  		break;
> +	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4 |
> +			RTE_IPSEC_SATP_NATT_ENABLE):
> +	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6 |
> +			RTE_IPSEC_SATP_NATT_ENABLE):
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
> -		esp_outb_tun_init(sa, prm);
> +		if (esp_outb_tun_init(sa, prm))
> +			return -EINVAL;
>  		break;
> +	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS |
> +			RTE_IPSEC_SATP_NATT_ENABLE):
>  	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
>  		esp_outb_init(sa, 0);
>  		break;
> --
> 2.25.1
  

Patch

diff --git a/doc/guides/prog_guide/ipsec_lib.rst b/doc/guides/prog_guide/ipsec_lib.rst
index 93e213bf36..af51ff8131 100644
--- a/doc/guides/prog_guide/ipsec_lib.rst
+++ b/doc/guides/prog_guide/ipsec_lib.rst
@@ -313,6 +313,8 @@  Supported features
 
 *  ESN and replay window.
 
+*  NAT-T / UDP encapsulated ESP.
+
 *  algorithms: 3DES-CBC, AES-CBC, AES-CTR, AES-GCM, AES_CCM, CHACHA20_POLY1305,
    AES_GMAC, HMAC-SHA1, NULL.
 
diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst
index 1748c2db05..e9fb169d44 100644
--- a/doc/guides/rel_notes/release_21_11.rst
+++ b/doc/guides/rel_notes/release_21_11.rst
@@ -157,6 +157,7 @@  New Features
 * **IPsec library new features.**
 
   * Added support for AEAD algorithms AES_CCM, CHACHA20_POLY1305 and AES_GMAC.
+  * Added support for NAT-T / UDP encapsulated ESP
 
 
 Removed Items
diff --git a/lib/ipsec/esp_outb.c b/lib/ipsec/esp_outb.c
index a3f77469c3..0e3314b358 100644
--- a/lib/ipsec/esp_outb.c
+++ b/lib/ipsec/esp_outb.c
@@ -5,6 +5,7 @@ 
 #include <rte_ipsec.h>
 #include <rte_esp.h>
 #include <rte_ip.h>
+#include <rte_udp.h>
 #include <rte_errno.h>
 #include <rte_cryptodev.h>
 
@@ -185,6 +186,14 @@  outb_tun_pkt_prepare(struct rte_ipsec_sa *sa, rte_be64_t sqc,
 	/* copy tunnel pkt header */
 	rte_memcpy(ph, sa->hdr, sa->hdr_len);
 
+	/* if UDP encap is enabled update the dgram_len */
+	if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
+		struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
+				(ph - sizeof(struct rte_udp_hdr));
+		udph->dgram_len = rte_cpu_to_be_16(mb->pkt_len - sqh_len -
+				sa->hdr_l3_off - sa->hdr_len);
+	}
+
 	/* update original and new ip header fields */
 	update_tun_outb_l3hdr(sa, ph + sa->hdr_l3_off, ph + hlen,
 			mb->pkt_len - sqh_len, sa->hdr_l3_off, sqn_low16(sqc));
diff --git a/lib/ipsec/rte_ipsec_sa.h b/lib/ipsec/rte_ipsec_sa.h
index cf51ad8338..3a22705055 100644
--- a/lib/ipsec/rte_ipsec_sa.h
+++ b/lib/ipsec/rte_ipsec_sa.h
@@ -78,6 +78,7 @@  struct rte_ipsec_sa_prm {
  * - for TUNNEL outer IP version (IPv4/IPv6)
  * - are SA SQN operations 'atomic'
  * - ESN enabled/disabled
+ * - NAT-T UDP encapsulated (TUNNEL mode only)
  * ...
  */
 
@@ -89,7 +90,8 @@  enum {
 	RTE_SATP_LOG2_SQN = RTE_SATP_LOG2_MODE + 2,
 	RTE_SATP_LOG2_ESN,
 	RTE_SATP_LOG2_ECN,
-	RTE_SATP_LOG2_DSCP
+	RTE_SATP_LOG2_DSCP,
+	RTE_SATP_LOG2_NATT
 };
 
 #define RTE_IPSEC_SATP_IPV_MASK		(1ULL << RTE_SATP_LOG2_IPV)
@@ -125,6 +127,11 @@  enum {
 #define RTE_IPSEC_SATP_DSCP_DISABLE	(0ULL << RTE_SATP_LOG2_DSCP)
 #define RTE_IPSEC_SATP_DSCP_ENABLE	(1ULL << RTE_SATP_LOG2_DSCP)
 
+#define RTE_IPSEC_SATP_NATT_MASK	(1ULL << RTE_SATP_LOG2_NATT)
+#define RTE_IPSEC_SATP_NATT_DISABLE	(0ULL << RTE_SATP_LOG2_NATT)
+#define RTE_IPSEC_SATP_NATT_ENABLE	(1ULL << RTE_SATP_LOG2_NATT)
+
+
 /**
  * get type of given SA
  * @return
diff --git a/lib/ipsec/sa.c b/lib/ipsec/sa.c
index 720e0f365b..2830506385 100644
--- a/lib/ipsec/sa.c
+++ b/lib/ipsec/sa.c
@@ -5,6 +5,7 @@ 
 #include <rte_ipsec.h>
 #include <rte_esp.h>
 #include <rte_ip.h>
+#include <rte_udp.h>
 #include <rte_errno.h>
 #include <rte_cryptodev.h>
 
@@ -217,6 +218,10 @@  fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
 	} else
 		return -EINVAL;
 
+	/* check for UDP encapsulation flag */
+	if (prm->ipsec_xform.options.udp_encap == 1)
+		tp |= RTE_IPSEC_SATP_NATT_ENABLE;
+
 	/* check for ESN flag */
 	if (prm->ipsec_xform.options.esn == 0)
 		tp |= RTE_IPSEC_SATP_ESN_DISABLE;
@@ -348,20 +353,36 @@  esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen)
 /*
  * Init ESP outbound tunnel specific things.
  */
-static void
+static int
 esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
 {
 	sa->proto = prm->tun.next_proto;
 	sa->hdr_len = prm->tun.hdr_len;
 	sa->hdr_l3_off = prm->tun.hdr_l3_off;
 
+	if (prm->tun.hdr_len > IPSEC_MAX_HDR_SIZE)
+		return -EINVAL;
+	memcpy(sa->hdr, prm->tun.hdr, prm->tun.hdr_len);
+
+	/* insert UDP header if UDP encapsulation is inabled */
+	if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
+		struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
+				&sa->hdr[prm->tun.hdr_len];
+		sa->hdr_len += sizeof(struct rte_udp_hdr);
+		if (sa->hdr_len > IPSEC_MAX_HDR_SIZE)
+			return -EINVAL;
+		udph->src_port = prm->ipsec_xform.udp.sport;
+		udph->dst_port = prm->ipsec_xform.udp.dport;
+		udph->dgram_cksum = 0;
+	}
+
 	/* update l2_len and l3_len fields for outbound mbuf */
 	sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
 		sa->hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
 
-	memcpy(sa->hdr, prm->tun.hdr, sa->hdr_len);
-
 	esp_outb_init(sa, sa->hdr_len);
+
+	return 0;
 }
 
 /*
@@ -372,7 +393,8 @@  esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
 	const struct crypto_xform *cxf)
 {
 	static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
-				RTE_IPSEC_SATP_MODE_MASK;
+				RTE_IPSEC_SATP_MODE_MASK |
+				RTE_IPSEC_SATP_NATT_MASK;
 
 	if (prm->ipsec_xform.options.ecn)
 		sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
@@ -475,10 +497,17 @@  esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
 	case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
 		esp_inb_init(sa);
 		break;
+	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4 |
+			RTE_IPSEC_SATP_NATT_ENABLE):
+	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6 |
+			RTE_IPSEC_SATP_NATT_ENABLE):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
-		esp_outb_tun_init(sa, prm);
+		if (esp_outb_tun_init(sa, prm))
+			return -EINVAL;
 		break;
+	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS |
+			RTE_IPSEC_SATP_NATT_ENABLE):
 	case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
 		esp_outb_init(sa, 0);
 		break;