[v2,2/2] net/octeontx2: add replay check for inline inbound packets
diff mbox series

Message ID 20200918110943.14553-3-adwivedi@marvell.com
State Accepted
Delegated to: akhil goyal
Headers show
Series
  • add anti replay support in OCTEON TX2 security
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/travis-robot success Travis build: passed
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-testing success Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/checkpatch success coding style OK

Commit Message

Ankur Dwivedi Sept. 18, 2020, 11:09 a.m. UTC
The function handling anti replay is added. If replay window
is enabled the rx packets will be validated against the window. The
rx offload fails in case of error.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
---
 .../crypto/octeontx2/otx2_ipsec_anti_replay.h | 208 ++++++++++++++++++
 drivers/net/octeontx2/otx2_rx.h               |   7 +
 2 files changed, 215 insertions(+)
 create mode 100644 drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h

Patch
diff mbox series

diff --git a/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h b/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h
new file mode 100644
index 000000000..858ce5b15
--- /dev/null
+++ b/drivers/crypto/octeontx2/otx2_ipsec_anti_replay.h
@@ -0,0 +1,208 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+#ifndef __OTX2_IPSEC_ANTI_REPLAY_H__
+#define __OTX2_IPSEC_ANTI_REPLAY_H__
+
+#include <rte_mbuf.h>
+
+#include "otx2_ipsec_fp.h"
+
+#define WORD_SHIFT	6
+#define WORD_SIZE	(1 << WORD_SHIFT)
+#define WORD_MASK	(WORD_SIZE - 1)
+
+#define IPSEC_ANTI_REPLAY_FAILED	(-1)
+
+static inline int
+anti_replay_check(uint64_t seq, struct otx2_ipsec_fp_in_sa *sa)
+{
+	struct otx2_ipsec_replay *replay = sa->replay;
+	uint64_t *window = &replay->window[0];
+	uint64_t winsz = sa->replay_win_sz;
+	uint64_t ex_winsz = winsz + WORD_SIZE;
+	uint64_t winwords = ex_winsz >> WORD_SHIFT;
+	uint64_t base = replay->base;
+	uint32_t winb = replay->winb;
+	uint32_t wint = replay->wint;
+	uint64_t seqword, shiftwords;
+	uint64_t bit_pos;
+	uint64_t shift;
+	uint64_t *wptr;
+	uint64_t tmp;
+
+	if (winsz > 64)
+		goto slow_shift;
+	/* Check if the seq is the biggest one yet */
+	if (likely(seq > base)) {
+		shift = seq - base;
+		if (shift < winsz) {  /* In window */
+			/*
+			 * If more than 64-bit anti-replay window,
+			 * use slow shift routine
+			 */
+			wptr = window + (shift >> WORD_SHIFT);
+			*wptr <<= shift;
+			*wptr |= 1ull;
+		} else {
+			/* No special handling of window size > 64 */
+			wptr = window + ((winsz - 1) >> WORD_SHIFT);
+			/*
+			 * Zero out the whole window (especially for
+			 * bigger than 64b window) till the last 64b word
+			 * as the incoming sequence number minus
+			 * base sequence is more than the window size.
+			 */
+			while (window != wptr)
+				*window++ = 0ull;
+			/*
+			 * Set the last bit (of the window) to 1
+			 * as that corresponds to the base sequence number.
+			 * Now any incoming sequence number which is
+			 * (base - window size - 1) will pass anti-replay check
+			 */
+			*wptr = 1ull;
+		}
+		/*
+		 * Set the base to incoming sequence number as
+		 * that is the biggest sequence number seen yet
+		 */
+		replay->base = seq;
+		return 0;
+	}
+
+	bit_pos = base - seq;
+
+	/* If seq falls behind the window, return failure */
+	if (bit_pos >= winsz)
+		return IPSEC_ANTI_REPLAY_FAILED;
+
+	/* seq is within anti-replay window */
+	wptr = window + ((winsz - bit_pos - 1) >> WORD_SHIFT);
+	bit_pos &= WORD_MASK;
+
+	/* Check if this is a replayed packet */
+	if (*wptr & ((1ull) << bit_pos))
+		return IPSEC_ANTI_REPLAY_FAILED;
+
+	/* mark as seen */
+	*wptr |= ((1ull) << bit_pos);
+	return 0;
+
+slow_shift:
+	if (likely(seq > base)) {
+		uint32_t i;
+
+		shift = seq - base;
+		if (unlikely(shift >= winsz)) {
+			/*
+			 * shift is bigger than the window,
+			 * so just zero out everything
+			 */
+			for (i = 0; i < winwords; i++)
+				window[i] = 0;
+winupdate:
+			/* Find out the word */
+			seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
+
+			/* Find out the bit in the word */
+			bit_pos = (seq - 1) & WORD_MASK;
+
+			/*
+			 * Set the bit corresponding to sequence number
+			 * in window to mark it as received
+			 */
+			window[seqword] |= (1ull << (63 - bit_pos));
+
+			/* wint and winb range from 1 to ex_winsz */
+			replay->wint = ((wint + shift - 1) % ex_winsz) + 1;
+			replay->winb = ((winb + shift - 1) % ex_winsz) + 1;
+
+			replay->base = seq;
+			return 0;
+		}
+
+		/*
+		 * New sequence number is bigger than the base but
+		 * it's not bigger than base + window size
+		 */
+
+		shiftwords = ((wint + shift - 1) >> WORD_SHIFT) -
+			     ((wint - 1) >> WORD_SHIFT);
+		if (unlikely(shiftwords)) {
+			tmp = (wint + WORD_SIZE - 1) / WORD_SIZE;
+			for (i = 0; i < shiftwords; i++) {
+				tmp %= winwords;
+				window[tmp++] = 0;
+			}
+		}
+
+		goto winupdate;
+	}
+
+	/* Sequence number is before the window */
+	if (unlikely((seq + winsz) <= base))
+		return IPSEC_ANTI_REPLAY_FAILED;
+
+	/* Sequence number is within the window */
+
+	/* Find out the word */
+	seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
+
+	/* Find out the bit in the word */
+	bit_pos = (seq - 1) & WORD_MASK;
+
+	/* Check if this is a replayed packet */
+	if (window[seqword] & (1ull << (63 - bit_pos)))
+		return IPSEC_ANTI_REPLAY_FAILED;
+
+	/*
+	 * Set the bit corresponding to sequence number
+	 * in window to mark it as received
+	 */
+	window[seqword] |= (1ull << (63 - bit_pos));
+
+	return 0;
+}
+
+static int
+cpt_ipsec_antireplay_check(struct otx2_ipsec_fp_in_sa *sa, char *data)
+{
+	uint64_t seq_in_sa;
+	uint32_t seqh = 0;
+	uint32_t seql;
+	uint64_t seq;
+	uint8_t esn;
+	int ret;
+
+	esn = sa->ctl.esn_en;
+	seql = rte_be_to_cpu_32(*((uint32_t *)(data +
+			OTX2_IPSEC_SEQNO_LO_INDEX)));
+
+	if (!esn)
+		seq = (uint64_t)seql;
+	else {
+		seqh = rte_be_to_cpu_32(*((uint32_t *)(data +
+				OTX2_IPSEC_SEQNO_HI_INDEX)));
+		seq = ((uint64_t)seqh << 32) | seql;
+	}
+
+	if (unlikely(seq == 0))
+		return IPSEC_ANTI_REPLAY_FAILED;
+
+	rte_spinlock_lock(&sa->replay->lock);
+	ret = anti_replay_check(seq, sa);
+	if (esn && (ret == 0)) {
+		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(&sa->replay->lock);
+
+	return ret;
+}
+#endif /* __OTX2_IPSEC_ANTI_REPLAY_H__ */
diff --git a/drivers/net/octeontx2/otx2_rx.h b/drivers/net/octeontx2/otx2_rx.h
index d8648b692..f29a0542f 100644
--- a/drivers/net/octeontx2/otx2_rx.h
+++ b/drivers/net/octeontx2/otx2_rx.h
@@ -9,6 +9,7 @@ 
 
 #include "otx2_common.h"
 #include "otx2_ethdev_sec.h"
+#include "otx2_ipsec_anti_replay.h"
 #include "otx2_ipsec_fp.h"
 
 /* Default mark value used when none is provided. */
@@ -243,6 +244,12 @@  nix_rx_sec_mbuf_update(const struct nix_cqe_hdr_s *cq, struct rte_mbuf *m,
 	m->udata64 = (uint64_t)sa->userdata;
 
 	data = rte_pktmbuf_mtod(m, char *);
+
+	if (sa->replay_win_sz) {
+		if (cpt_ipsec_antireplay_check(sa, data) < 0)
+			return PKT_RX_SEC_OFFLOAD | PKT_RX_SEC_OFFLOAD_FAILED;
+	}
+
 	memcpy(data + INLINE_INB_RPTR_HDR, data, RTE_ETHER_HDR_LEN);
 
 	m->data_off += INLINE_INB_RPTR_HDR;