Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : #ifndef __IPSEC_SPD_SA_H__
16 : #define __IPSEC_SPD_SA_H__
17 :
18 : #include <vlib/vlib.h>
19 : #include <vppinfra/pcg.h>
20 : #include <vnet/crypto/crypto.h>
21 : #include <vnet/ip/ip.h>
22 : #include <vnet/fib/fib_node.h>
23 : #include <vnet/tunnel/tunnel.h>
24 :
25 : #define ESP_MAX_ICV_SIZE (32)
26 : #define ESP_MAX_IV_SIZE (16)
27 : #define ESP_MAX_BLOCK_SIZE (16)
28 :
29 : #define foreach_ipsec_crypto_alg \
30 : _ (0, NONE, "none") \
31 : _ (1, AES_CBC_128, "aes-cbc-128") \
32 : _ (2, AES_CBC_192, "aes-cbc-192") \
33 : _ (3, AES_CBC_256, "aes-cbc-256") \
34 : _ (4, AES_CTR_128, "aes-ctr-128") \
35 : _ (5, AES_CTR_192, "aes-ctr-192") \
36 : _ (6, AES_CTR_256, "aes-ctr-256") \
37 : _ (7, AES_GCM_128, "aes-gcm-128") \
38 : _ (8, AES_GCM_192, "aes-gcm-192") \
39 : _ (9, AES_GCM_256, "aes-gcm-256") \
40 : _ (10, DES_CBC, "des-cbc") \
41 : _ (11, 3DES_CBC, "3des-cbc") \
42 : _ (12, CHACHA20_POLY1305, "chacha20-poly1305") \
43 : _ (13, AES_NULL_GMAC_128, "aes-null-gmac-128") \
44 : _ (14, AES_NULL_GMAC_192, "aes-null-gmac-192") \
45 : _ (15, AES_NULL_GMAC_256, "aes-null-gmac-256")
46 :
47 : typedef enum
48 : {
49 : #define _(v, f, s) IPSEC_CRYPTO_ALG_##f = v,
50 : foreach_ipsec_crypto_alg
51 : #undef _
52 : IPSEC_CRYPTO_N_ALG,
53 : } __clib_packed ipsec_crypto_alg_t;
54 :
55 : #define IPSEC_CRYPTO_ALG_IS_NULL_GMAC(_alg) \
56 : ((_alg == IPSEC_CRYPTO_ALG_AES_NULL_GMAC_128) || \
57 : (_alg == IPSEC_CRYPTO_ALG_AES_NULL_GMAC_192) || \
58 : (_alg == IPSEC_CRYPTO_ALG_AES_NULL_GMAC_256))
59 :
60 : #define IPSEC_CRYPTO_ALG_IS_GCM(_alg) \
61 : (((_alg == IPSEC_CRYPTO_ALG_AES_GCM_128) || \
62 : (_alg == IPSEC_CRYPTO_ALG_AES_GCM_192) || \
63 : (_alg == IPSEC_CRYPTO_ALG_AES_GCM_256)))
64 :
65 : #define IPSEC_CRYPTO_ALG_IS_CTR(_alg) \
66 : (((_alg == IPSEC_CRYPTO_ALG_AES_CTR_128) || \
67 : (_alg == IPSEC_CRYPTO_ALG_AES_CTR_192) || \
68 : (_alg == IPSEC_CRYPTO_ALG_AES_CTR_256)))
69 :
70 : #define IPSEC_CRYPTO_ALG_CTR_AEAD_OTHERS(_alg) \
71 : (_alg == IPSEC_CRYPTO_ALG_CHACHA20_POLY1305)
72 :
73 : #define foreach_ipsec_integ_alg \
74 : _ (0, NONE, "none") \
75 : _ (1, MD5_96, "md5-96") /* RFC2403 */ \
76 : _ (2, SHA1_96, "sha1-96") /* RFC2404 */ \
77 : _ (3, SHA_256_96, "sha-256-96") /* draft-ietf-ipsec-ciph-sha-256-00 */ \
78 : _ (4, SHA_256_128, "sha-256-128") /* RFC4868 */ \
79 : _ (5, SHA_384_192, "sha-384-192") /* RFC4868 */ \
80 : _ (6, SHA_512_256, "sha-512-256") /* RFC4868 */
81 :
82 : typedef enum
83 : {
84 : #define _(v, f, s) IPSEC_INTEG_ALG_##f = v,
85 : foreach_ipsec_integ_alg
86 : #undef _
87 : IPSEC_INTEG_N_ALG,
88 : } __clib_packed ipsec_integ_alg_t;
89 :
90 : typedef enum
91 : {
92 : IPSEC_PROTOCOL_AH = 0,
93 : IPSEC_PROTOCOL_ESP = 1
94 : } __clib_packed ipsec_protocol_t;
95 :
96 : #define IPSEC_KEY_MAX_LEN 128
97 : typedef struct ipsec_key_t_
98 : {
99 : u8 len;
100 : u8 data[IPSEC_KEY_MAX_LEN];
101 : } ipsec_key_t;
102 :
103 : /*
104 : * Enable extended sequence numbers
105 : * Enable Anti-replay
106 : * IPsec tunnel mode if non-zero, else transport mode
107 : * IPsec tunnel mode is IPv6 if non-zero,
108 : * else IPv4 tunnel only valid if is_tunnel is non-zero
109 : * enable UDP encapsulation for NAT traversal
110 : */
111 : #define foreach_ipsec_sa_flags \
112 : _ (0, NONE, "none") \
113 : _ (1, USE_ESN, "esn") \
114 : _ (2, USE_ANTI_REPLAY, "anti-replay") \
115 : _ (4, IS_TUNNEL, "tunnel") \
116 : _ (8, IS_TUNNEL_V6, "tunnel-v6") \
117 : _ (16, UDP_ENCAP, "udp-encap") \
118 : _ (32, IS_PROTECT, "Protect") \
119 : _ (64, IS_INBOUND, "inbound") \
120 : _ (128, IS_AEAD, "aead") \
121 : _ (256, IS_CTR, "ctr") \
122 : _ (512, IS_ASYNC, "async") \
123 : _ (1024, NO_ALGO_NO_DROP, "no-algo-no-drop") \
124 : _ (2048, IS_NULL_GMAC, "null-gmac")
125 :
126 : typedef enum ipsec_sad_flags_t_
127 : {
128 : #define _(v, f, s) IPSEC_SA_FLAG_##f = v,
129 : foreach_ipsec_sa_flags
130 : #undef _
131 : } __clib_packed ipsec_sa_flags_t;
132 :
133 : STATIC_ASSERT (sizeof (ipsec_sa_flags_t) == 2, "IPSEC SA flags != 2 byte");
134 :
135 : #define foreach_ipsec_sa_err \
136 : _ (0, LOST, lost, "packets lost") \
137 : _ (1, HANDOFF, handoff, "hand-off") \
138 : _ (2, INTEG_ERROR, integ_error, "Integrity check failed") \
139 : _ (3, DECRYPTION_FAILED, decryption_failed, "Decryption failed") \
140 : _ (4, CRYPTO_ENGINE_ERROR, crypto_engine_error, \
141 : "crypto engine error (dropped)") \
142 : _ (5, REPLAY, replay, "SA replayed packet") \
143 : _ (6, RUNT, runt, "undersized packet") \
144 : _ (7, NO_BUFFERS, no_buffers, "no buffers (dropped)") \
145 : _ (8, OVERSIZED_HEADER, oversized_header, \
146 : "buffer with oversized header (dropped)") \
147 : _ (9, NO_TAIL_SPACE, no_tail_space, \
148 : "no enough buffer tail space (dropped)") \
149 : _ (10, TUN_NO_PROTO, tun_no_proto, "no tunnel protocol") \
150 : _ (11, UNSUP_PAYLOAD, unsup_payload, "unsupported payload") \
151 : _ (12, SEQ_CYCLED, seq_cycled, "sequence number cycled (dropped)") \
152 : _ (13, CRYPTO_QUEUE_FULL, crypto_queue_full, "crypto queue full (dropped)") \
153 : _ (14, NO_ENCRYPTION, no_encryption, "no Encrypting SA (dropped)") \
154 : _ (15, DROP_FRAGMENTS, drop_fragments, "IP fragments drop")
155 :
156 : typedef enum
157 : {
158 : #define _(v, f, s, d) IPSEC_SA_ERROR_##f = v,
159 : foreach_ipsec_sa_err
160 : #undef _
161 : IPSEC_SA_N_ERRORS,
162 : } __clib_packed ipsec_sa_err_t;
163 :
164 : typedef struct
165 : {
166 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
167 :
168 : clib_pcg64i_random_t iv_prng;
169 :
170 : u64 replay_window;
171 : dpo_id_t dpo;
172 :
173 : vnet_crypto_key_index_t crypto_key_index;
174 : vnet_crypto_key_index_t integ_key_index;
175 :
176 : u32 spi;
177 : u32 seq;
178 : u32 seq_hi;
179 :
180 : u16 crypto_enc_op_id;
181 : u16 crypto_dec_op_id;
182 : u16 integ_op_id;
183 : ipsec_sa_flags_t flags;
184 : u16 thread_index;
185 :
186 : u16 integ_icv_size : 6;
187 : u16 crypto_iv_size : 5;
188 : u16 esp_block_align : 5;
189 :
190 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
191 :
192 : union
193 : {
194 : ip4_header_t ip4_hdr;
195 : ip6_header_t ip6_hdr;
196 : };
197 : udp_header_t udp_hdr;
198 :
199 : /* Salt used in CTR modes (incl. GCM) - stored in network byte order */
200 : u32 salt;
201 :
202 : ipsec_protocol_t protocol;
203 : tunnel_encap_decap_flags_t tunnel_flags;
204 : u8 __pad[2];
205 :
206 : /* data accessed by dataplane code should be above this comment */
207 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);
208 :
209 : /* Elements with u64 size multiples */
210 : tunnel_t tunnel;
211 : fib_node_t node;
212 :
213 : /* elements with u32 size */
214 : u32 id;
215 : u32 stat_index;
216 : vnet_crypto_alg_t integ_calg;
217 : vnet_crypto_alg_t crypto_calg;
218 : u32 crypto_sync_key_index;
219 : u32 integ_sync_key_index;
220 : u32 crypto_async_key_index;
221 :
222 : /* elements with u16 size */
223 : u16 crypto_sync_enc_op_id;
224 : u16 crypto_sync_dec_op_id;
225 : u16 integ_sync_op_id;
226 : u16 crypto_async_enc_op_id;
227 : u16 crypto_async_dec_op_id;
228 :
229 : /* else u8 packed */
230 : ipsec_crypto_alg_t crypto_alg;
231 : ipsec_integ_alg_t integ_alg;
232 :
233 : ipsec_key_t integ_key;
234 : ipsec_key_t crypto_key;
235 : } ipsec_sa_t;
236 :
237 : STATIC_ASSERT (VNET_CRYPTO_N_OP_IDS < (1 << 16), "crypto ops overflow");
238 : STATIC_ASSERT (ESP_MAX_ICV_SIZE < (1 << 6), "integer icv overflow");
239 : STATIC_ASSERT (ESP_MAX_IV_SIZE < (1 << 5), "esp iv overflow");
240 : STATIC_ASSERT (ESP_MAX_BLOCK_SIZE < (1 << 5), "esp alignment overflow");
241 : STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline1, CLIB_CACHE_LINE_BYTES);
242 : STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline2, 2 * CLIB_CACHE_LINE_BYTES);
243 :
244 : /**
245 : * Pool of IPSec SAs
246 : */
247 : extern ipsec_sa_t *ipsec_sa_pool;
248 :
249 : /*
250 : * Ensure that the IPsec data does not overlap with the IP data in
251 : * the buffer meta data
252 : */
253 : STATIC_ASSERT (STRUCT_OFFSET_OF (vnet_buffer_opaque_t, ipsec.sad_index) ==
254 : STRUCT_OFFSET_OF (vnet_buffer_opaque_t, ip.save_protocol),
255 : "IPSec data is overlapping with IP data");
256 :
257 : #define _(a,v,s) \
258 : always_inline int \
259 : ipsec_sa_is_set_##v (const ipsec_sa_t *sa) { \
260 : return (sa->flags & IPSEC_SA_FLAG_##v); \
261 : }
262 4425966 : foreach_ipsec_sa_flags
263 : #undef _
264 : #define _(a,v,s) \
265 : always_inline int \
266 : ipsec_sa_set_##v (ipsec_sa_t *sa) { \
267 : return (sa->flags |= IPSEC_SA_FLAG_##v); \
268 : }
269 7798 : foreach_ipsec_sa_flags
270 : #undef _
271 : #define _(a,v,s) \
272 : always_inline int \
273 : ipsec_sa_unset_##v (ipsec_sa_t *sa) { \
274 : return (sa->flags &= ~IPSEC_SA_FLAG_##v); \
275 : }
276 440 : foreach_ipsec_sa_flags
277 : #undef _
278 : /**
279 : * @brief
280 : * SA packet & bytes counters
281 : */
282 : extern vlib_combined_counter_main_t ipsec_sa_counters;
283 : extern vlib_simple_counter_main_t ipsec_sa_err_counters[IPSEC_SA_N_ERRORS];
284 :
285 : extern void ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len);
286 :
287 : extern int ipsec_sa_update (u32 id, u16 src_port, u16 dst_port,
288 : const tunnel_t *tun, bool is_tun);
289 : extern int
290 : ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
291 : ipsec_crypto_alg_t crypto_alg, const ipsec_key_t *ck,
292 : ipsec_integ_alg_t integ_alg, const ipsec_key_t *ik,
293 : ipsec_sa_flags_t flags, u32 salt, u16 src_port,
294 : u16 dst_port, const tunnel_t *tun, u32 *sa_out_index);
295 : extern int ipsec_sa_bind (u32 id, u32 worker, bool bind);
296 : extern index_t ipsec_sa_find_and_lock (u32 id);
297 : extern int ipsec_sa_unlock_id (u32 id);
298 : extern void ipsec_sa_unlock (index_t sai);
299 : extern void ipsec_sa_lock (index_t sai);
300 : extern void ipsec_sa_clear (index_t sai);
301 : extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa,
302 : ipsec_crypto_alg_t crypto_alg);
303 : extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa,
304 : ipsec_integ_alg_t integ_alg);
305 : extern void ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled);
306 :
307 : typedef walk_rc_t (*ipsec_sa_walk_cb_t) (ipsec_sa_t * sa, void *ctx);
308 : extern void ipsec_sa_walk (ipsec_sa_walk_cb_t cd, void *ctx);
309 :
310 : extern u8 *format_ipsec_replay_window (u8 *s, va_list *args);
311 : extern u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
312 : extern u8 *format_ipsec_integ_alg (u8 * s, va_list * args);
313 : extern u8 *format_ipsec_sa (u8 * s, va_list * args);
314 : extern u8 *format_ipsec_key (u8 * s, va_list * args);
315 : extern uword unformat_ipsec_crypto_alg (unformat_input_t * input,
316 : va_list * args);
317 : extern uword unformat_ipsec_integ_alg (unformat_input_t * input,
318 : va_list * args);
319 : extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args);
320 :
321 : #define IPSEC_UDP_PORT_NONE ((u16)~0)
322 :
323 : /*
324 : * Anti Replay definitions
325 : */
326 :
327 : #define IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE (64)
328 : #define IPSEC_SA_ANTI_REPLAY_WINDOW_MAX_INDEX (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE-1)
329 :
330 : /*
331 : * sequence number less than the lower bound are outside of the window
332 : * From RFC4303 Appendix A:
333 : * Bl = Tl - W + 1
334 : */
335 : #define IPSEC_SA_ANTI_REPLAY_WINDOW_LOWER_BOUND(_tl) (_tl - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE + 1)
336 :
337 : always_inline int
338 2050 : ipsec_sa_anti_replay_check (const ipsec_sa_t *sa, u32 seq)
339 : {
340 2050 : if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa) &&
341 2050 : sa->replay_window & (1ULL << (sa->seq - seq)))
342 1804 : return 1;
343 : else
344 246 : return 0;
345 : }
346 :
347 : /*
348 : * Anti replay check.
349 : * inputs need to be in host byte order.
350 : *
351 : * The function runs in two contexts. pre and post decrypt.
352 : * Pre-decrypt it:
353 : * 1 - determines if a packet is a replay - a simple check in the window
354 : * 2 - returns the hi-seq number that should be used to decrypt.
355 : * post-decrypt:
356 : * Checks whether the packet is a replay or falls out of window
357 : *
358 : * This funcion should be called even without anti-replay enabled to ensure
359 : * the high sequence number is set.
360 : */
361 : always_inline int
362 497317 : ipsec_sa_anti_replay_and_sn_advance (const ipsec_sa_t *sa, u32 seq,
363 : u32 hi_seq_used, bool post_decrypt,
364 : u32 *hi_seq_req)
365 : {
366 497317 : ASSERT ((post_decrypt == false) == (hi_seq_req != 0));
367 :
368 497317 : if (!ipsec_sa_is_set_USE_ESN (sa))
369 : {
370 272421 : if (hi_seq_req)
371 : /* no ESN, therefore the hi-seq is always 0 */
372 138152 : *hi_seq_req = 0;
373 :
374 272421 : if (!ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
375 147924 : return 0;
376 :
377 124497 : if (PREDICT_TRUE (seq > sa->seq))
378 121517 : return 0;
379 :
380 2980 : u32 diff = sa->seq - seq;
381 :
382 2980 : if (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE > diff)
383 2109 : return ((sa->replay_window & (1ULL << diff)) ? 1 : 0);
384 : else
385 871 : return 1;
386 :
387 : return 0;
388 : }
389 :
390 224896 : if (!ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
391 : {
392 : /* there's no AR configured for this SA, but in order
393 : * to know whether a packet has wrapped the hi ESN we need
394 : * to know whether it is out of window. if we use the default
395 : * lower bound then we are effectively forcing AR because
396 : * out of window packets will get the increased hi seq number
397 : * and will thus fail to decrypt. IOW we need a window to know
398 : * if the SN has wrapped, but we don't want a window to check for
399 : * anti replay. to resolve the contradiction we use a huge window.
400 : * if the packet is not within 2^30 of the current SN, we'll consider
401 : * it a wrap.
402 : */
403 107984 : if (hi_seq_req)
404 : {
405 54033 : if (seq >= sa->seq)
406 : /* The packet's sequence number is larger that the SA's.
407 : * that can't be a warp - unless we lost more than
408 : * 2^32 packets ... how could we know? */
409 53705 : *hi_seq_req = sa->seq_hi;
410 : else
411 : {
412 : /* The packet's SN is less than the SAs, so either the SN has
413 : * wrapped or the SN is just old. */
414 328 : if (sa->seq - seq > (1 << 30))
415 : /* It's really really really old => it wrapped */
416 164 : *hi_seq_req = sa->seq_hi + 1;
417 : else
418 164 : *hi_seq_req = sa->seq_hi;
419 : }
420 : }
421 : /*
422 : * else
423 : * this is post-decrpyt and since it decrypted we accept it
424 : */
425 107984 : return 0;
426 : }
427 116912 : if (PREDICT_TRUE (sa->seq >= (IPSEC_SA_ANTI_REPLAY_WINDOW_MAX_INDEX)))
428 : {
429 : /*
430 : * the last sequence number VPP recieved is more than one
431 : * window size greater than zero.
432 : * Case A from RFC4303 Appendix A.
433 : */
434 77064 : if (seq < IPSEC_SA_ANTI_REPLAY_WINDOW_LOWER_BOUND (sa->seq))
435 : {
436 : /*
437 : * the received sequence number is lower than the lower bound
438 : * of the window, this could mean either a replay packet or that
439 : * the high sequence number has wrapped. if it decrypts corrently
440 : * then it's the latter.
441 : */
442 1230 : if (post_decrypt)
443 : {
444 205 : if (hi_seq_used == sa->seq_hi)
445 : /* the high sequence number used to succesfully decrypt this
446 : * packet is the same as the last-sequnence number of the SA.
447 : * that means this packet did not cause a wrap.
448 : * this packet is thus out of window and should be dropped */
449 41 : return 1;
450 : else
451 : /* The packet decrypted with a different high sequence number
452 : * to the SA, that means it is the wrap packet and should be
453 : * accepted */
454 164 : return 0;
455 : }
456 : else
457 : {
458 : /* pre-decrypt it might be the might that casues a wrap, we
459 : * need to decrpyt to find out */
460 1025 : if (hi_seq_req)
461 1025 : *hi_seq_req = sa->seq_hi + 1;
462 1025 : return 0;
463 : }
464 : }
465 : else
466 : {
467 : /*
468 : * the recieved sequence number greater than the low
469 : * end of the window.
470 : */
471 75834 : if (hi_seq_req)
472 37215 : *hi_seq_req = sa->seq_hi;
473 75834 : if (seq <= sa->seq)
474 : /*
475 : * The recieved seq number is within bounds of the window
476 : * check if it's a duplicate
477 : */
478 328 : return (ipsec_sa_anti_replay_check (sa, seq));
479 : else
480 : /*
481 : * The received sequence number is greater than the window
482 : * upper bound. this packet will move the window along, assuming
483 : * it decrypts correctly.
484 : */
485 75506 : return 0;
486 : }
487 : }
488 : else
489 : {
490 : /*
491 : * the last sequence number VPP recieved is within one window
492 : * size of zero, i.e. 0 < TL < WINDOW_SIZE, the lower bound is thus a
493 : * large sequence number.
494 : * Note that the check below uses unsiged integer arthimetic, so the
495 : * RHS will be a larger number.
496 : * Case B from RFC4303 Appendix A.
497 : */
498 39848 : if (seq < IPSEC_SA_ANTI_REPLAY_WINDOW_LOWER_BOUND (sa->seq))
499 : {
500 : /*
501 : * the sequence number is less than the lower bound.
502 : */
503 39766 : if (seq <= sa->seq)
504 : {
505 : /*
506 : * the packet is within the window upper bound.
507 : * check for duplicates.
508 : */
509 1640 : if (hi_seq_req)
510 1353 : *hi_seq_req = sa->seq_hi;
511 1640 : return (ipsec_sa_anti_replay_check (sa, seq));
512 : }
513 : else
514 : {
515 : /*
516 : * the packet is less the window lower bound or greater than
517 : * the higher bound, depending on how you look at it...
518 : * We're assuming, given that the last sequence number received,
519 : * TL < WINDOW_SIZE, that a largeer seq num is more likely to be
520 : * a packet that moves the window forward, than a packet that has
521 : * wrapped the high sequence again. If it were the latter then
522 : * we've lost close to 2^32 packets.
523 : */
524 38126 : if (hi_seq_req)
525 20703 : *hi_seq_req = sa->seq_hi;
526 38126 : return 0;
527 : }
528 : }
529 : else
530 : {
531 : /*
532 : * the packet seq number is between the lower bound (a large nubmer)
533 : * and MAX_SEQ_NUM. This is in the window since the window upper bound
534 : * tl > 0.
535 : * However, since TL is the other side of 0 to the received
536 : * packet, the SA has moved on to a higher sequence number.
537 : */
538 82 : if (hi_seq_req)
539 41 : *hi_seq_req = sa->seq_hi - 1;
540 82 : return (ipsec_sa_anti_replay_check (sa, seq));
541 : }
542 : }
543 :
544 : /* unhandled case */
545 : ASSERT (0);
546 : return 0;
547 : }
548 :
549 : always_inline u32
550 243213 : ipsec_sa_anti_replay_window_shift (ipsec_sa_t *sa, u32 inc)
551 : {
552 243213 : u32 n_lost = 0;
553 :
554 243213 : if (inc < IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
555 : {
556 242203 : if (sa->seq > IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE)
557 : {
558 : /*
559 : * count how many holes there are in the portion
560 : * of the window that we will right shift of the end
561 : * as a result of this increments
562 : */
563 163054 : u64 mask = (((u64) 1 << inc) - 1) << (BITS (u64) - inc);
564 163054 : u64 old = sa->replay_window & mask;
565 : /* the number of packets we saw in this section of the window */
566 163054 : u64 seen = count_set_bits (old);
567 :
568 : /*
569 : * the number we missed is the size of the window section
570 : * minus the number we saw.
571 : */
572 163054 : n_lost = inc - seen;
573 : }
574 242203 : sa->replay_window = ((sa->replay_window) << inc) | 1;
575 : }
576 : else
577 : {
578 : /* holes in the replay window are lost packets */
579 1010 : n_lost = BITS (u64) - count_set_bits (sa->replay_window);
580 :
581 : /* any sequence numbers that now fall outside the window
582 : * are forever lost */
583 1010 : n_lost += inc - IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE;
584 :
585 1010 : sa->replay_window = 1;
586 : }
587 :
588 243213 : return (n_lost);
589 : }
590 :
591 : /*
592 : * Anti replay window advance
593 : * inputs need to be in host byte order.
594 : * This function both advances the anti-replay window and the sequence number
595 : * We always need to move on the SN but the window updates are only needed
596 : * if AR is on.
597 : * However, updating the window is trivial, so we do it anyway to save
598 : * the branch cost.
599 : */
600 : always_inline u64
601 244118 : ipsec_sa_anti_replay_advance (ipsec_sa_t *sa, u32 thread_index, u32 seq,
602 : u32 hi_seq)
603 : {
604 244118 : u64 n_lost = 0;
605 : u32 pos;
606 :
607 244118 : if (ipsec_sa_is_set_USE_ESN (sa))
608 : {
609 110198 : int wrap = hi_seq - sa->seq_hi;
610 :
611 110198 : if (wrap == 0 && seq > sa->seq)
612 : {
613 109624 : pos = seq - sa->seq;
614 109624 : n_lost = ipsec_sa_anti_replay_window_shift (sa, pos);
615 109624 : sa->seq = seq;
616 : }
617 574 : else if (wrap > 0)
618 : {
619 246 : pos = ~seq + sa->seq + 1;
620 246 : n_lost = ipsec_sa_anti_replay_window_shift (sa, pos);
621 246 : sa->seq = seq;
622 246 : sa->seq_hi = hi_seq;
623 : }
624 328 : else if (wrap < 0)
625 : {
626 41 : pos = ~seq + sa->seq + 1;
627 41 : sa->replay_window |= (1ULL << pos);
628 : }
629 : else
630 : {
631 287 : pos = sa->seq - seq;
632 287 : sa->replay_window |= (1ULL << pos);
633 : }
634 : }
635 : else
636 : {
637 133920 : if (seq > sa->seq)
638 : {
639 133343 : pos = seq - sa->seq;
640 133343 : n_lost = ipsec_sa_anti_replay_window_shift (sa, pos);
641 133343 : sa->seq = seq;
642 : }
643 : else
644 : {
645 577 : pos = sa->seq - seq;
646 577 : sa->replay_window |= (1ULL << pos);
647 : }
648 : }
649 :
650 244118 : return n_lost;
651 : }
652 :
653 :
654 : /*
655 : * Makes choice for thread_id should be assigned.
656 : * if input ~0, gets random worker_id based on unix_time_now_nsec
657 : */
658 : always_inline u16
659 19 : ipsec_sa_assign_thread (u16 thread_id)
660 : {
661 : return ((thread_id) ? thread_id
662 19 : : (unix_time_now_nsec () % vlib_num_workers ()) + 1);
663 : }
664 :
665 : always_inline ipsec_sa_t *
666 1084535 : ipsec_sa_get (u32 sa_index)
667 : {
668 1084535 : return (pool_elt_at_index (ipsec_sa_pool, sa_index));
669 : }
670 :
671 : #endif /* __IPSEC_SPD_SA_H__ */
672 :
673 : /*
674 : * fd.io coding-style-patch-verification: ON
675 : *
676 : * Local Variables:
677 : * eval: (c-set-style "gnu")
678 : * End:
679 : */
|