1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
8 #define WINDOW_BUCKET_BITS 6 /* uint64_t */
9 #define WINDOW_BUCKET_SIZE (1 << WINDOW_BUCKET_BITS)
10 #define WINDOW_BIT_LOC_MASK (WINDOW_BUCKET_SIZE - 1)
12 /* minimum number of bucket, power of 2*/
13 #define WINDOW_BUCKET_MIN 2
14 #define WINDOW_BUCKET_MAX (INT16_MAX + 1)
16 #define IS_ESN(sa) ((sa)->sqn_mask == UINT64_MAX)
19 * gets SQN.hi32 bits, SQN supposed to be in network byte order.
21 static inline rte_be32_t
22 sqn_hi32(rte_be64_t sqn)
24 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
32 * gets SQN.low32 bits, SQN supposed to be in network byte order.
34 static inline rte_be32_t
35 sqn_low32(rte_be64_t sqn)
37 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
45 * gets SQN.low16 bits, SQN supposed to be in network byte order.
47 static inline rte_be16_t
48 sqn_low16(rte_be64_t sqn)
50 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
58 * for given size, calculate required number of buckets.
61 replay_num_bucket(uint32_t wsz)
65 nb = rte_align32pow2(RTE_ALIGN_MUL_CEIL(wsz, WINDOW_BUCKET_SIZE) /
67 nb = RTE_MAX(nb, (uint32_t)WINDOW_BUCKET_MIN);
73 * According to RFC4303 A2.1, determine the high-order bit of sequence number.
74 * use 32bit arithmetic inside, return uint64_t.
76 static inline uint64_t
77 reconstruct_esn(uint64_t t, uint32_t sqn, uint32_t w)
85 /* case A: window is within one sequence number subspace */
88 /* case B: window spans two sequence number subspaces */
92 /* return constructed sequence with proper high-order bits */
93 return (uint64_t)th << 32 | sqn;
97 * Perform the replay checking.
99 * struct rte_ipsec_sa contains the window and window related parameters,
100 * such as the window size, bitmask, and the last acknowledged sequence number.
103 * Blocks are 64 bits unsigned integers
105 static inline int32_t
106 esn_inb_check_sqn(const struct replay_sqn *rsn, const struct rte_ipsec_sa *sa,
109 uint32_t bit, bucket;
111 /* replay not enabled */
112 if (sa->replay.win_sz == 0)
115 /* seq is larger than lastseq */
119 /* seq is outside window */
120 if (sqn == 0 || sqn + sa->replay.win_sz < rsn->sqn)
123 /* seq is inside the window */
124 bit = sqn & WINDOW_BIT_LOC_MASK;
125 bucket = (sqn >> WINDOW_BUCKET_BITS) & sa->replay.bucket_index_mask;
127 /* already seen packet */
128 if (rsn->window[bucket] & ((uint64_t)1 << bit))
135 * For outbound SA perform the sequence number update.
137 static inline uint64_t
138 esn_outb_update_sqn(struct rte_ipsec_sa *sa, uint32_t *num)
143 sqn = sa->sqn.outb + n;
147 if (sqn > sa->sqn_mask) {
148 s = sqn - sa->sqn_mask;
149 *num = (s < n) ? n - s : 0;
156 * For inbound SA perform the sequence number and replay window update.
158 static inline int32_t
159 esn_inb_update_sqn(struct replay_sqn *rsn, const struct rte_ipsec_sa *sa,
162 uint32_t bit, bucket, last_bucket, new_bucket, diff, i;
164 /* replay not enabled */
165 if (sa->replay.win_sz == 0)
170 sqn = reconstruct_esn(rsn->sqn, sqn, sa->replay.win_sz);
172 /* seq is outside window*/
173 if (sqn == 0 || sqn + sa->replay.win_sz < rsn->sqn)
177 bucket = (sqn >> WINDOW_BUCKET_BITS);
179 /* check if the seq is within the range */
180 if (sqn > rsn->sqn) {
181 last_bucket = rsn->sqn >> WINDOW_BUCKET_BITS;
182 diff = bucket - last_bucket;
183 /* seq is way after the range of WINDOW_SIZE */
184 if (diff > sa->replay.nb_bucket)
185 diff = sa->replay.nb_bucket;
187 for (i = 0; i != diff; i++) {
188 new_bucket = (i + last_bucket + 1) &
189 sa->replay.bucket_index_mask;
190 rsn->window[new_bucket] = 0;
195 bucket &= sa->replay.bucket_index_mask;
196 bit = (uint64_t)1 << (sqn & WINDOW_BIT_LOC_MASK);
198 /* already seen packet */
199 if (rsn->window[bucket] & bit)
202 rsn->window[bucket] |= bit;
207 * To achieve ability to do multiple readers single writer for
208 * SA replay window information and sequence number (RSN)
209 * basic RCU schema is used:
210 * SA have 2 copies of RSN (one for readers, another for writers).
211 * Each RSN contains a rwlock that has to be grabbed (for read/write)
212 * to avoid races between readers and writer.
213 * Writer is responsible to make a copy or reader RSN, update it
214 * and mark newly updated RSN as readers one.
215 * That approach is intended to minimize contention and cache sharing
216 * between writer and readers.
220 * Based on number of buckets calculated required size for the
221 * structure that holds replay window and sequence number (RSN) information.
224 rsn_size(uint32_t nb_bucket)
227 struct replay_sqn *rsn;
229 sz = sizeof(*rsn) + nb_bucket * sizeof(rsn->window[0]);
230 sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
234 #endif /* _IPSEC_SQN_H_ */