From 1ec23c7523b4c42b15f9e4880a5a38fd215ea1be Mon Sep 17 00:00:00 2001 From: Srujana Challa Date: Fri, 1 Oct 2021 19:10:08 +0530 Subject: [PATCH] common/cnxk: support anti-replay check in SW for cn9k Adds anti replay SW implementation for cn9k platform. Signed-off-by: Srujana Challa Acked-by: Jerin Jacob --- drivers/common/cnxk/cnxk_security_ar.h | 184 +++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 drivers/common/cnxk/cnxk_security_ar.h diff --git a/drivers/common/cnxk/cnxk_security_ar.h b/drivers/common/cnxk/cnxk_security_ar.h new file mode 100644 index 0000000000..6bc517c875 --- /dev/null +++ b/drivers/common/cnxk/cnxk_security_ar.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2021 Marvell. + */ + +#ifndef __CNXK_SECURITY_AR_H__ +#define __CNXK_SECURITY_AR_H__ + +#include + +#include "cnxk_security.h" + +#define CNXK_ON_AR_WIN_SIZE_MAX 1024 + +/* u64 array size to fit anti replay window bits */ +#define AR_WIN_ARR_SZ \ + (PLT_ALIGN_CEIL(CNXK_ON_AR_WIN_SIZE_MAX, BITS_PER_LONG_LONG) / \ + BITS_PER_LONG_LONG) + +#define WORD_SHIFT 6 +#define WORD_SIZE (1 << WORD_SHIFT) +#define WORD_MASK (WORD_SIZE - 1) + +#define IPSEC_ANTI_REPLAY_FAILED (-1) + +struct cnxk_on_ipsec_ar { + rte_spinlock_t lock; + uint32_t winb; + uint32_t wint; + uint64_t base; /**< base of the anti-replay window */ + uint64_t window[AR_WIN_ARR_SZ]; /**< anti-replay window */ +}; + +static inline int +cnxk_on_anti_replay_check(uint64_t seq, struct cnxk_on_ipsec_ar *ar, + uint32_t winsz) +{ + uint64_t ex_winsz = winsz + WORD_SIZE; + uint64_t *window = &ar->window[0]; + uint64_t seqword, shiftwords; + uint64_t base = ar->base; + uint32_t winb = ar->winb; + uint32_t wint = ar->wint; + uint64_t winwords; + uint64_t bit_pos; + uint64_t shift; + uint64_t *wptr; + uint64_t tmp; + + winwords = ex_winsz >> WORD_SHIFT; + 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 + */ + ar->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 */ + ar->wint = ((wint + shift - 1) % ex_winsz) + 1; + ar->winb = ((winb + shift - 1) % ex_winsz) + 1; + + ar->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; +} + +#endif /* __CNXK_SECURITY_AR_H__ */ -- 2.20.1