[v9,04/10] ipsec: add support for NAT-T
Checks
Commit Message
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
>
> 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
@@ -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.
@@ -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
@@ -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));
@@ -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
@@ -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;