ipsec: support NAT-T
authorRadu Nicolau <radu.nicolau@intel.com>
Thu, 14 Oct 2021 16:03:24 +0000 (17:03 +0100)
committerAkhil Goyal <gakhil@marvell.com>
Sun, 17 Oct 2021 12:06:24 +0000 (14:06 +0200)
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>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Acked-by: Akhil Goyal <gakhil@marvell.com>
doc/guides/prog_guide/ipsec_lib.rst
doc/guides/rel_notes/release_21_11.rst
lib/ipsec/esp_outb.c
lib/ipsec/rte_ipsec_sa.h
lib/ipsec/sa.c

index 93e213b..af51ff8 100644 (file)
@@ -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.
 
index 25424e6..7e69818 100644 (file)
@@ -155,6 +155,7 @@ New Features
 
   * Added support for more AEAD algorithms AES_CCM, CHACHA20_POLY1305
     and AES_GMAC.
+  * Added support for NAT-T / UDP encapsulated ESP.
 
 * **Added multi-process support for testpmd.**
 
index a3f7746..0e3314b 100644 (file)
@@ -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));
index cf51ad8..3a22705 100644 (file)
@@ -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
index 720e0f3..fa5a76c 100644 (file)
@@ -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;
@@ -355,12 +360,22 @@ esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
        sa->hdr_len = prm->tun.hdr_len;
        sa->hdr_l3_off = prm->tun.hdr_l3_off;
 
+       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);
+               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);
 }
 
@@ -372,7 +387,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 +491,16 @@ 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);
                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;
@@ -551,9 +573,13 @@ 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) {
+               uint32_t 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)