From d698fa5469acab59e935e13ffe453b77be9c69ac Mon Sep 17 00:00:00 2001 From: Ankur Dwivedi Date: Fri, 18 Sep 2020 16:39:43 +0530 Subject: [PATCH] net/octeontx2: add replay check for inline inbound packets 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 Acked-by: Akhil Goyal --- .../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 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 0000000000..858ce5b15f --- /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 + +#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 d8648b692a..f29a0542f9 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; -- 2.20.1