diff mbox series

[v3,22/28] net/cnxk: support IPsec anti replay in cn9k

Message ID 20211001134022.22700-23-ndabilpuram@marvell.com (mailing list archive)
State Accepted, archived
Delegated to: Jerin Jacob
Headers show
Series net/cnxk: support for inline ipsec | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Nithin Dabilpuram Oct. 1, 2021, 1:40 p.m. UTC
From: Srujana Challa <schalla@marvell.com>

Adds anti replay support for cn9k platform using
SW anti replay check.

Signed-off-by: Srujana Challa <schalla@marvell.com>
---
 drivers/net/cnxk/cn9k_ethdev.h     |  3 +++
 drivers/net/cnxk/cn9k_ethdev_sec.c | 29 ++++++++++++++++++++
 drivers/net/cnxk/cn9k_rx.h         | 54 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 85 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/cnxk/cn9k_ethdev.h b/drivers/net/cnxk/cn9k_ethdev.h
index f8818b8..2b452fe 100644
--- a/drivers/net/cnxk/cn9k_ethdev.h
+++ b/drivers/net/cnxk/cn9k_ethdev.h
@@ -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;
 };
 
diff --git a/drivers/net/cnxk/cn9k_ethdev_sec.c b/drivers/net/cnxk/cn9k_ethdev_sec.c
index 3ec7497..deb1daf 100644
--- a/drivers/net/cnxk/cn9k_ethdev_sec.c
+++ b/drivers/net/cnxk/cn9k_ethdev_sec.c
@@ -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;
 
diff --git a/drivers/net/cnxk/cn9k_rx.h b/drivers/net/cnxk/cn9k_rx.h
index bdedeab..7ab415a 100644
--- a/drivers/net/cnxk/cn9k_rx.h
+++ b/drivers/net/cnxk/cn9k_rx.h
@@ -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);