net/cnxk: support IPsec anti replay in cn9k
authorSrujana Challa <schalla@marvell.com>
Fri, 1 Oct 2021 13:40:16 +0000 (19:10 +0530)
committerJerin Jacob <jerinj@marvell.com>
Sat, 2 Oct 2021 13:45:23 +0000 (15:45 +0200)
Adds anti replay support for cn9k platform using
SW anti replay check.

Signed-off-by: Srujana Challa <schalla@marvell.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
drivers/net/cnxk/cn9k_ethdev.h
drivers/net/cnxk/cn9k_ethdev_sec.c
drivers/net/cnxk/cn9k_rx.h

index f8818b8..2b452fe 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <cnxk_ethdev.h>
 #include <cnxk_security.h>
+#include <cnxk_security_ar.h>
 
 struct cn9k_eth_txq {
        uint64_t cmd[8];
@@ -40,6 +41,8 @@ struct cn9k_eth_rxq {
 /* Private data in sw rsvd area of struct roc_onf_ipsec_inb_sa */
 struct cn9k_inb_priv_data {
        void *userdata;
+       uint32_t replay_win_sz;
+       struct cnxk_on_ipsec_ar ar;
        struct cnxk_eth_sec_sess *eth_sec;
 };
 
index 3ec7497..deb1daf 100644 (file)
@@ -73,6 +73,27 @@ static const struct rte_security_capability cn9k_eth_sec_capabilities[] = {
        }
 };
 
+static inline int
+ar_window_init(struct cn9k_inb_priv_data *inb_priv)
+{
+       if (inb_priv->replay_win_sz > CNXK_ON_AR_WIN_SIZE_MAX) {
+               plt_err("Replay window size:%u is not supported",
+                       inb_priv->replay_win_sz);
+               return -ENOTSUP;
+       }
+
+       rte_spinlock_init(&inb_priv->ar.lock);
+       /*
+        * Set window bottom to 1, base and top to size of
+        * window
+        */
+       inb_priv->ar.winb = 1;
+       inb_priv->ar.wint = inb_priv->replay_win_sz;
+       inb_priv->ar.base = inb_priv->replay_win_sz;
+
+       return 0;
+}
+
 static int
 cn9k_eth_sec_session_create(void *device,
                            struct rte_security_session_conf *conf,
@@ -158,6 +179,14 @@ cn9k_eth_sec_session_create(void *device,
                /* Save userdata in inb private area */
                inb_priv->userdata = conf->userdata;
 
+               inb_priv->replay_win_sz = ipsec->replay_win_sz;
+               if (inb_priv->replay_win_sz) {
+                       rc = ar_window_init(inb_priv);
+                       if (rc)
+                               goto mempool_put;
+               }
+
+               /* Prepare session priv */
                sess_priv.inb_sa = 1;
                sess_priv.sa_idx = ipsec->spi;
 
index bdedeab..7ab415a 100644 (file)
@@ -31,6 +31,9 @@
 #define CQE_CAST(x)         ((struct nix_cqe_hdr_s *)(x))
 #define CQE_SZ(x)           ((x) * CNXK_NIX_CQ_ENTRY_SZ)
 
+#define IPSEC_SQ_LO_IDX 4
+#define IPSEC_SQ_HI_IDX 8
+
 union mbuf_initializer {
        struct {
                uint16_t data_off;
@@ -166,6 +169,48 @@ nix_cqe_xtract_mseg(const union nix_rx_parse_u *rx, struct rte_mbuf *mbuf,
        mbuf->next = NULL;
 }
 
+static inline int
+ipsec_antireplay_check(struct roc_onf_ipsec_inb_sa *sa,
+                      struct cn9k_inb_priv_data *priv, uintptr_t data,
+                      uint32_t win_sz)
+{
+       struct cnxk_on_ipsec_ar *ar = &priv->ar;
+       uint64_t seq_in_sa;
+       uint32_t seqh = 0;
+       uint32_t seql;
+       uint64_t seq;
+       uint8_t esn;
+       int rc;
+
+       esn = sa->ctl.esn_en;
+       seql = rte_be_to_cpu_32(*((uint32_t *)(data + IPSEC_SQ_LO_IDX)));
+
+       if (!esn) {
+               seq = (uint64_t)seql;
+       } else {
+               seqh = rte_be_to_cpu_32(*((uint32_t *)(data +
+                                       IPSEC_SQ_HI_IDX)));
+               seq = ((uint64_t)seqh << 32) | seql;
+       }
+
+       if (unlikely(seq == 0))
+               return -1;
+
+       rte_spinlock_lock(&ar->lock);
+       rc = cnxk_on_anti_replay_check(seq, ar, win_sz);
+       if (esn && !rc) {
+               seq_in_sa = ((uint64_t)rte_be_to_cpu_32(sa->esn_hi) << 32) |
+                           rte_be_to_cpu_32(sa->esn_low);
+               if (seq > seq_in_sa) {
+                       sa->esn_low = rte_cpu_to_be_32(seql);
+                       sa->esn_hi = rte_cpu_to_be_32(seqh);
+               }
+       }
+       rte_spinlock_unlock(&ar->lock);
+
+       return rc;
+}
+
 static __rte_always_inline uint64_t
 nix_rx_sec_mbuf_update(const struct nix_cqe_hdr_s *cq, struct rte_mbuf *m,
                       uintptr_t sa_base, uint64_t *rearm_val, uint16_t *len)
@@ -178,8 +223,8 @@ nix_rx_sec_mbuf_update(const struct nix_cqe_hdr_s *cq, struct rte_mbuf *m,
        uint8_t lcptr = rx->lcptr;
        struct rte_ipv4_hdr *ipv4;
        uint16_t data_off, res;
+       uint32_t spi, win_sz;
        uint32_t spi_mask;
-       uint32_t spi;
        uintptr_t data;
        __uint128_t dw;
        uint8_t sa_w;
@@ -209,6 +254,13 @@ nix_rx_sec_mbuf_update(const struct nix_cqe_hdr_s *cq, struct rte_mbuf *m,
        dw = *(__uint128_t *)sa_priv;
        *rte_security_dynfield(m) = (uint64_t)dw;
 
+       /* Check if anti-replay is enabled */
+       win_sz = (uint32_t)(dw >> 64);
+       if (win_sz) {
+               if (ipsec_antireplay_check(sa, sa_priv, data, win_sz) < 0)
+                       return PKT_RX_SEC_OFFLOAD | PKT_RX_SEC_OFFLOAD_FAILED;
+       }
+
        /* Get total length from IPv4 header. We can assume only IPv4 */
        ipv4 = (struct rte_ipv4_hdr *)(data + ROC_ONF_IPSEC_INB_SPI_SEQ_SZ +
                                       ROC_ONF_IPSEC_INB_MAX_L2_SZ);