dpdk/drivers/common/cnxk/cnxk_security_ar.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(C) 2021 Marvell.
   3 */
   4
   5#ifndef __CNXK_SECURITY_AR_H__
   6#define __CNXK_SECURITY_AR_H__
   7
   8#include <rte_mbuf.h>
   9
  10#include "cnxk_security.h"
  11
  12#define CNXK_ON_AR_WIN_SIZE_MAX 1024
  13
  14/* u64 array size to fit anti replay window bits */
  15#define AR_WIN_ARR_SZ                                                          \
  16        (PLT_ALIGN_CEIL(CNXK_ON_AR_WIN_SIZE_MAX + 1, BITS_PER_LONG_LONG) /     \
  17         BITS_PER_LONG_LONG)
  18
  19#define WORD_SHIFT 6
  20#define WORD_SIZE  (1 << WORD_SHIFT)
  21#define WORD_MASK  (WORD_SIZE - 1)
  22
  23#define IPSEC_ANTI_REPLAY_FAILED (-1)
  24
  25struct cnxk_on_ipsec_ar {
  26        rte_spinlock_t lock;
  27        uint32_t winb;
  28        uint32_t wint;
  29        uint64_t base;                  /**< base of the anti-replay window */
  30        uint64_t window[AR_WIN_ARR_SZ]; /**< anti-replay window */
  31};
  32
  33static inline uint32_t
  34cnxk_on_anti_replay_get_seqh(uint32_t winsz, uint32_t seql, uint32_t esn_hi,
  35                             uint32_t esn_low)
  36{
  37        uint32_t win_low = esn_low - winsz + 1;
  38
  39        if (esn_low > winsz - 1) {
  40                /* Window is in one sequence number subspace */
  41                if (seql > win_low)
  42                        return esn_hi;
  43                else
  44                        return esn_hi + 1;
  45        } else {
  46                /* Window is split across two sequence number subspaces */
  47                if (seql > win_low)
  48                        return esn_hi - 1;
  49                else
  50                        return esn_hi;
  51        }
  52}
  53
  54static inline int
  55cnxk_on_anti_replay_check(uint64_t seq, struct cnxk_on_ipsec_ar *ar,
  56                          uint32_t winsz)
  57{
  58        uint64_t ex_winsz = winsz + WORD_SIZE;
  59        uint64_t *window = &ar->window[0];
  60        uint64_t seqword, shiftwords;
  61        uint64_t base = ar->base;
  62        uint32_t winb = ar->winb;
  63        uint32_t wint = ar->wint;
  64        uint64_t winwords;
  65        uint64_t bit_pos;
  66        uint64_t shift;
  67        uint64_t *wptr;
  68        uint64_t tmp;
  69
  70        winwords = ex_winsz >> WORD_SHIFT;
  71        if (winsz > 64)
  72                goto slow_shift;
  73        /* Check if the seq is the biggest one yet */
  74        if (likely(seq > base)) {
  75                shift = seq - base;
  76                if (shift < winsz) { /* In window */
  77                        /*
  78                         * If more than 64-bit anti-replay window,
  79                         * use slow shift routine
  80                         */
  81                        wptr = window + (shift >> WORD_SHIFT);
  82                        *wptr <<= shift;
  83                        *wptr |= 1ull;
  84                } else {
  85                        /* No special handling of window size > 64 */
  86                        wptr = window + ((winsz - 1) >> WORD_SHIFT);
  87                        /*
  88                         * Zero out the whole window (especially for
  89                         * bigger than 64b window) till the last 64b word
  90                         * as the incoming sequence number minus
  91                         * base sequence is more than the window size.
  92                         */
  93                        while (window != wptr)
  94                                *window++ = 0ull;
  95                        /*
  96                         * Set the last bit (of the window) to 1
  97                         * as that corresponds to the base sequence number.
  98                         * Now any incoming sequence number which is
  99                         * (base - window size - 1) will pass anti-replay check
 100                         */
 101                        *wptr = 1ull;
 102                }
 103                /*
 104                 * Set the base to incoming sequence number as
 105                 * that is the biggest sequence number seen yet
 106                 */
 107                ar->base = seq;
 108                return 0;
 109        }
 110
 111        bit_pos = base - seq;
 112
 113        /* If seq falls behind the window, return failure */
 114        if (bit_pos >= winsz)
 115                return IPSEC_ANTI_REPLAY_FAILED;
 116
 117        /* seq is within anti-replay window */
 118        wptr = window + ((winsz - bit_pos - 1) >> WORD_SHIFT);
 119        bit_pos &= WORD_MASK;
 120
 121        /* Check if this is a replayed packet */
 122        if (*wptr & ((1ull) << bit_pos))
 123                return IPSEC_ANTI_REPLAY_FAILED;
 124
 125        /* mark as seen */
 126        *wptr |= ((1ull) << bit_pos);
 127        return 0;
 128
 129slow_shift:
 130        if (likely(seq > base)) {
 131                uint32_t i;
 132
 133                shift = seq - base;
 134                if (unlikely(shift >= winsz)) {
 135                        /*
 136                         * shift is bigger than the window,
 137                         * so just zero out everything
 138                         */
 139                        for (i = 0; i < winwords; i++)
 140                                window[i] = 0;
 141winupdate:
 142                        /* Find out the word */
 143                        seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
 144
 145                        /* Find out the bit in the word */
 146                        bit_pos = (seq - 1) & WORD_MASK;
 147
 148                        /*
 149                         * Set the bit corresponding to sequence number
 150                         * in window to mark it as received
 151                         */
 152                        window[seqword] |= (1ull << (63 - bit_pos));
 153
 154                        /* wint and winb range from 1 to ex_winsz */
 155                        ar->wint = ((wint + shift - 1) % ex_winsz) + 1;
 156                        ar->winb = ((winb + shift - 1) % ex_winsz) + 1;
 157
 158                        ar->base = seq;
 159                        return 0;
 160                }
 161
 162                /*
 163                 * New sequence number is bigger than the base but
 164                 * it's not bigger than base + window size
 165                 */
 166
 167                shiftwords = ((wint + shift - 1) >> WORD_SHIFT) -
 168                             ((wint - 1) >> WORD_SHIFT);
 169                if (unlikely(shiftwords)) {
 170                        tmp = (wint + WORD_SIZE - 1) / WORD_SIZE;
 171                        for (i = 0; i < shiftwords; i++) {
 172                                tmp %= winwords;
 173                                window[tmp++] = 0;
 174                        }
 175                }
 176
 177                goto winupdate;
 178        }
 179
 180        /* Sequence number is before the window */
 181        if (unlikely((seq + winsz) <= base))
 182                return IPSEC_ANTI_REPLAY_FAILED;
 183
 184        /* Sequence number is within the window */
 185
 186        /* Find out the word */
 187        seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
 188
 189        /* Find out the bit in the word */
 190        bit_pos = (seq - 1) & WORD_MASK;
 191
 192        /* Check if this is a replayed packet */
 193        if (window[seqword] & (1ull << (63 - bit_pos)))
 194                return IPSEC_ANTI_REPLAY_FAILED;
 195
 196        /*
 197         * Set the bit corresponding to sequence number
 198         * in window to mark it as received
 199         */
 200        window[seqword] |= (1ull << (63 - bit_pos));
 201
 202        return 0;
 203}
 204
 205#endif /* __CNXK_SECURITY_AR_H__ */
 206