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 :
16 : #include <sys/random.h>
17 : #include <vnet/ipsec/ipsec.h>
18 : #include <vnet/ipsec/esp.h>
19 : #include <vnet/udp/udp_local.h>
20 : #include <vnet/fib/fib_table.h>
21 : #include <vnet/fib/fib_entry_track.h>
22 : #include <vnet/ipsec/ipsec_tun.h>
23 : #include <vnet/ipsec/ipsec.api_enum.h>
24 :
25 : /**
26 : * @brief
27 : * SA packet & bytes counters
28 : */
29 : vlib_combined_counter_main_t ipsec_sa_counters = {
30 : .name = "SA",
31 : .stat_segment_name = "/net/ipsec/sa",
32 : };
33 : /* Per-SA error counters */
34 : vlib_simple_counter_main_t ipsec_sa_err_counters[IPSEC_SA_N_ERRORS];
35 :
36 : ipsec_sa_t *ipsec_sa_pool;
37 :
38 : static clib_error_t *
39 13192 : ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
40 : u32 sa_index, int is_add)
41 : {
42 : ipsec_ah_backend_t *ab;
43 : ipsec_esp_backend_t *eb;
44 13192 : switch (sa->protocol)
45 : {
46 818 : case IPSEC_PROTOCOL_AH:
47 818 : ab = pool_elt_at_index (im->ah_backends, im->ah_current_backend);
48 818 : if (ab->add_del_sa_sess_cb)
49 0 : return ab->add_del_sa_sess_cb (sa_index, is_add);
50 818 : break;
51 12374 : case IPSEC_PROTOCOL_ESP:
52 12374 : eb = pool_elt_at_index (im->esp_backends, im->esp_current_backend);
53 12374 : if (eb->add_del_sa_sess_cb)
54 0 : return eb->add_del_sa_sess_cb (sa_index, is_add);
55 12374 : break;
56 : }
57 13192 : return 0;
58 : }
59 :
60 : void
61 13192 : ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len)
62 : {
63 13192 : memset (key, 0, sizeof (*key));
64 :
65 13192 : if (len > sizeof (key->data))
66 0 : key->len = sizeof (key->data);
67 : else
68 13192 : key->len = len;
69 :
70 13192 : memcpy (key->data, data, key->len);
71 13192 : }
72 :
73 : /**
74 : * 'stack' (resolve the recursion for) the SA tunnel destination
75 : */
76 : static void
77 3317 : ipsec_sa_stack (ipsec_sa_t * sa)
78 : {
79 3317 : ipsec_main_t *im = &ipsec_main;
80 3317 : dpo_id_t tmp = DPO_INVALID;
81 :
82 3317 : tunnel_contribute_forwarding (&sa->tunnel, &tmp);
83 :
84 3317 : if (IPSEC_PROTOCOL_AH == sa->protocol)
85 261 : dpo_stack_from_node ((ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ?
86 : im->ah6_encrypt_node_index :
87 : im->ah4_encrypt_node_index), &sa->dpo, &tmp);
88 : else
89 3056 : dpo_stack_from_node ((ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ?
90 : im->esp6_encrypt_node_index :
91 : im->esp4_encrypt_node_index), &sa->dpo, &tmp);
92 3317 : dpo_reset (&tmp);
93 3317 : }
94 :
95 : void
96 6614 : ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled)
97 : {
98 6614 : if (is_enabled)
99 : {
100 732 : sa->crypto_key_index = sa->crypto_async_key_index;
101 732 : sa->crypto_enc_op_id = sa->crypto_async_enc_op_id;
102 732 : sa->crypto_dec_op_id = sa->crypto_async_dec_op_id;
103 732 : sa->integ_key_index = ~0;
104 732 : sa->integ_op_id = ~0;
105 : }
106 : else
107 : {
108 5882 : sa->crypto_key_index = sa->crypto_sync_key_index;
109 5882 : sa->crypto_enc_op_id = sa->crypto_sync_enc_op_id;
110 5882 : sa->crypto_dec_op_id = sa->crypto_sync_dec_op_id;
111 5882 : sa->integ_key_index = sa->integ_sync_key_index;
112 5882 : sa->integ_op_id = sa->integ_sync_op_id;
113 : }
114 6614 : }
115 :
116 : void
117 6596 : ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg)
118 : {
119 6596 : ipsec_main_t *im = &ipsec_main;
120 6596 : sa->crypto_alg = crypto_alg;
121 6596 : sa->crypto_iv_size = im->crypto_algs[crypto_alg].iv_size;
122 6596 : sa->esp_block_align = clib_max (4, im->crypto_algs[crypto_alg].block_align);
123 6596 : sa->crypto_sync_enc_op_id = im->crypto_algs[crypto_alg].enc_op_id;
124 6596 : sa->crypto_sync_dec_op_id = im->crypto_algs[crypto_alg].dec_op_id;
125 6596 : sa->crypto_calg = im->crypto_algs[crypto_alg].alg;
126 6596 : ASSERT (sa->crypto_iv_size <= ESP_MAX_IV_SIZE);
127 6596 : ASSERT (sa->esp_block_align <= ESP_MAX_BLOCK_SIZE);
128 6596 : if (IPSEC_CRYPTO_ALG_IS_GCM (crypto_alg) ||
129 : IPSEC_CRYPTO_ALG_CTR_AEAD_OTHERS (crypto_alg))
130 : {
131 1750 : sa->integ_icv_size = im->crypto_algs[crypto_alg].icv_size;
132 1750 : ipsec_sa_set_IS_CTR (sa);
133 1750 : ipsec_sa_set_IS_AEAD (sa);
134 : }
135 4846 : else if (IPSEC_CRYPTO_ALG_IS_CTR (crypto_alg))
136 : {
137 1296 : ipsec_sa_set_IS_CTR (sa);
138 : }
139 6596 : }
140 :
141 : void
142 4842 : ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg)
143 : {
144 4842 : ipsec_main_t *im = &ipsec_main;
145 4842 : sa->integ_alg = integ_alg;
146 4842 : sa->integ_icv_size = im->integ_algs[integ_alg].icv_size;
147 4842 : sa->integ_sync_op_id = im->integ_algs[integ_alg].op_id;
148 4842 : sa->integ_calg = im->integ_algs[integ_alg].alg;
149 4842 : ASSERT (sa->integ_icv_size <= ESP_MAX_ICV_SIZE);
150 4842 : }
151 :
152 : void
153 6596 : ipsec_sa_set_async_op_ids (ipsec_sa_t * sa)
154 : {
155 : /* *INDENT-OFF* */
156 6596 : if (ipsec_sa_is_set_USE_ESN (sa))
157 : {
158 : #define _(n, s, k) \
159 : if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC) \
160 : sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_ENC; \
161 : if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC) \
162 : sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_DEC;
163 2838 : foreach_crypto_aead_alg
164 : #undef _
165 : }
166 : else
167 : {
168 : #define _(n, s, k) \
169 : if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC) \
170 : sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_ENC; \
171 : if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC) \
172 : sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_DEC;
173 3758 : foreach_crypto_aead_alg
174 : #undef _
175 : }
176 :
177 : #define _(c, h, s, k, d) \
178 : if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##c##_ENC && \
179 : sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC) \
180 : sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC; \
181 : if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##c##_DEC && \
182 : sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC) \
183 : sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC;
184 6596 : foreach_crypto_link_async_alg
185 : #undef _
186 : /* *INDENT-ON* */
187 6596 : }
188 :
189 : int
190 8 : ipsec_sa_update (u32 id, u16 src_port, u16 dst_port, const tunnel_t *tun,
191 : bool is_tun)
192 : {
193 8 : ipsec_main_t *im = &ipsec_main;
194 : ipsec_sa_t *sa;
195 : u32 sa_index;
196 : uword *p;
197 : int rv;
198 :
199 8 : p = hash_get (im->sa_index_by_sa_id, id);
200 8 : if (!p)
201 0 : return VNET_API_ERROR_NO_SUCH_ENTRY;
202 :
203 8 : sa = ipsec_sa_get (p[0]);
204 8 : sa_index = sa - ipsec_sa_pool;
205 :
206 10 : if (is_tun && ipsec_sa_is_set_IS_TUNNEL (sa) &&
207 2 : (ip_address_cmp (&tun->t_src, &sa->tunnel.t_src) != 0 ||
208 0 : ip_address_cmp (&tun->t_dst, &sa->tunnel.t_dst) != 0))
209 : {
210 : /* if the source IP is updated for an inbound SA under a tunnel protect,
211 : we need to update the tun_protect DB with the new src IP */
212 3 : if (ipsec_sa_is_set_IS_INBOUND (sa) &&
213 2 : ip_address_cmp (&tun->t_src, &sa->tunnel.t_src) != 0 &&
214 1 : !ip46_address_is_zero (&tun->t_src.ip))
215 : {
216 1 : if (ip46_address_is_ip4 (&sa->tunnel.t_src.ip))
217 : {
218 : ipsec4_tunnel_kv_t old_key, new_key;
219 : clib_bihash_kv_8_16_t res,
220 1 : *bkey = (clib_bihash_kv_8_16_t *) &old_key;
221 :
222 1 : ipsec4_tunnel_mk_key (&old_key, &sa->tunnel.t_src.ip.ip4,
223 : clib_host_to_net_u32 (sa->spi));
224 1 : ipsec4_tunnel_mk_key (&new_key, &tun->t_src.ip.ip4,
225 : clib_host_to_net_u32 (sa->spi));
226 :
227 1 : if (!clib_bihash_search_8_16 (&im->tun4_protect_by_key, bkey,
228 : &res))
229 : {
230 1 : clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, &res, 0);
231 1 : res.key = new_key.key;
232 1 : clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, &res, 1);
233 : }
234 : }
235 : else
236 : {
237 0 : ipsec6_tunnel_kv_t old_key = {
238 : .key = {
239 : .remote_ip = sa->tunnel.t_src.ip.ip6,
240 0 : .spi = clib_host_to_net_u32 (sa->spi),
241 : },
242 0 : }, new_key = {
243 : .key = {
244 : .remote_ip = tun->t_src.ip.ip6,
245 0 : .spi = clib_host_to_net_u32 (sa->spi),
246 : }};
247 : clib_bihash_kv_24_16_t res,
248 0 : *bkey = (clib_bihash_kv_24_16_t *) &old_key;
249 :
250 0 : if (!clib_bihash_search_24_16 (&im->tun6_protect_by_key, bkey,
251 : &res))
252 : {
253 0 : clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, &res,
254 : 0);
255 0 : clib_memcpy (&res.key, &new_key.key, 3);
256 0 : clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, &res,
257 : 1);
258 : }
259 : }
260 : }
261 2 : tunnel_unresolve (&sa->tunnel);
262 2 : tunnel_copy (tun, &sa->tunnel);
263 2 : if (!ipsec_sa_is_set_IS_INBOUND (sa))
264 : {
265 1 : dpo_reset (&sa->dpo);
266 :
267 1 : sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
268 :
269 1 : rv = tunnel_resolve (&sa->tunnel, FIB_NODE_TYPE_IPSEC_SA, sa_index);
270 :
271 1 : if (rv)
272 : {
273 0 : hash_unset (im->sa_index_by_sa_id, sa->id);
274 0 : pool_put (ipsec_sa_pool, sa);
275 0 : return rv;
276 : }
277 1 : ipsec_sa_stack (sa);
278 : /* generate header templates */
279 1 : if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
280 : {
281 0 : tunnel_build_v6_hdr (&sa->tunnel,
282 0 : (ipsec_sa_is_set_UDP_ENCAP (sa) ?
283 : IP_PROTOCOL_UDP :
284 : IP_PROTOCOL_IPSEC_ESP),
285 : &sa->ip6_hdr);
286 : }
287 : else
288 : {
289 1 : tunnel_build_v4_hdr (&sa->tunnel,
290 1 : (ipsec_sa_is_set_UDP_ENCAP (sa) ?
291 : IP_PROTOCOL_UDP :
292 : IP_PROTOCOL_IPSEC_ESP),
293 : &sa->ip4_hdr);
294 : }
295 : }
296 : }
297 :
298 8 : if (ipsec_sa_is_set_UDP_ENCAP (sa))
299 : {
300 12 : if (dst_port != IPSEC_UDP_PORT_NONE &&
301 6 : dst_port != clib_net_to_host_u16 (sa->udp_hdr.dst_port))
302 : {
303 6 : if (ipsec_sa_is_set_IS_INBOUND (sa))
304 : {
305 3 : ipsec_unregister_udp_port (
306 3 : clib_net_to_host_u16 (sa->udp_hdr.dst_port),
307 3 : !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
308 3 : ipsec_register_udp_port (dst_port,
309 3 : !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
310 : }
311 6 : sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
312 : }
313 12 : if (src_port != IPSEC_UDP_PORT_NONE &&
314 6 : src_port != clib_net_to_host_u16 (sa->udp_hdr.src_port))
315 6 : sa->udp_hdr.src_port = clib_host_to_net_u16 (src_port);
316 : }
317 8 : return (0);
318 : }
319 :
320 : int
321 6596 : ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
322 : ipsec_crypto_alg_t crypto_alg, const ipsec_key_t *ck,
323 : ipsec_integ_alg_t integ_alg, const ipsec_key_t *ik,
324 : ipsec_sa_flags_t flags, u32 salt, u16 src_port,
325 : u16 dst_port, const tunnel_t *tun, u32 *sa_out_index)
326 : {
327 6596 : vlib_main_t *vm = vlib_get_main ();
328 6596 : ipsec_main_t *im = &ipsec_main;
329 : clib_error_t *err;
330 : ipsec_sa_t *sa;
331 : u32 sa_index;
332 : u64 rand[2];
333 : uword *p;
334 : int rv;
335 :
336 6596 : p = hash_get (im->sa_index_by_sa_id, id);
337 6596 : if (p)
338 0 : return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
339 :
340 6596 : if (getrandom (rand, sizeof (rand), 0) != sizeof (rand))
341 0 : return VNET_API_ERROR_INIT_FAILED;
342 :
343 6596 : pool_get_aligned_zero (ipsec_sa_pool, sa, CLIB_CACHE_LINE_BYTES);
344 :
345 6596 : clib_pcg64i_srandom_r (&sa->iv_prng, rand[0], rand[1]);
346 :
347 6596 : fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA);
348 6596 : fib_node_lock (&sa->node);
349 6596 : sa_index = sa - ipsec_sa_pool;
350 :
351 6596 : vlib_validate_combined_counter (&ipsec_sa_counters, sa_index);
352 6596 : vlib_zero_combined_counter (&ipsec_sa_counters, sa_index);
353 112132 : for (int i = 0; i < IPSEC_SA_N_ERRORS; i++)
354 : {
355 105536 : vlib_validate_simple_counter (&ipsec_sa_err_counters[i], sa_index);
356 105536 : vlib_zero_simple_counter (&ipsec_sa_err_counters[i], sa_index);
357 : }
358 :
359 6596 : tunnel_copy (tun, &sa->tunnel);
360 6596 : sa->id = id;
361 6596 : sa->spi = spi;
362 6596 : sa->stat_index = sa_index;
363 6596 : sa->protocol = proto;
364 6596 : sa->flags = flags;
365 6596 : sa->salt = salt;
366 6596 : sa->thread_index = (vlib_num_workers ()) ? ~0 : 0;
367 6596 : if (integ_alg != IPSEC_INTEG_ALG_NONE)
368 : {
369 4842 : ipsec_sa_set_integ_alg (sa, integ_alg);
370 4842 : clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key));
371 : }
372 6596 : ipsec_sa_set_crypto_alg (sa, crypto_alg);
373 6596 : ipsec_sa_set_async_op_ids (sa);
374 :
375 6596 : clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
376 :
377 13192 : sa->crypto_sync_key_index = vnet_crypto_key_add (
378 6596 : vm, im->crypto_algs[crypto_alg].alg, (u8 *) ck->data, ck->len);
379 6596 : if (~0 == sa->crypto_sync_key_index)
380 : {
381 0 : pool_put (ipsec_sa_pool, sa);
382 0 : return VNET_API_ERROR_KEY_LENGTH;
383 : }
384 :
385 6596 : if (integ_alg != IPSEC_INTEG_ALG_NONE)
386 : {
387 9684 : sa->integ_sync_key_index = vnet_crypto_key_add (
388 4842 : vm, im->integ_algs[integ_alg].alg, (u8 *) ik->data, ik->len);
389 4842 : if (~0 == sa->integ_sync_key_index)
390 : {
391 0 : pool_put (ipsec_sa_pool, sa);
392 0 : return VNET_API_ERROR_KEY_LENGTH;
393 : }
394 : }
395 :
396 6596 : if (sa->crypto_async_enc_op_id && !ipsec_sa_is_set_IS_AEAD (sa))
397 4404 : sa->crypto_async_key_index =
398 4404 : vnet_crypto_key_add_linked (vm, sa->crypto_sync_key_index,
399 4404 : sa->integ_sync_key_index); // AES-CBC & HMAC
400 : else
401 2192 : sa->crypto_async_key_index = sa->crypto_sync_key_index;
402 :
403 6596 : if (im->async_mode)
404 : {
405 720 : ipsec_sa_set_async_mode (sa, 1);
406 : }
407 5876 : else if (ipsec_sa_is_set_IS_ASYNC (sa))
408 : {
409 2 : ipsec_sa_set_async_mode (sa, 1 /* is_enabled */);
410 : }
411 : else
412 : {
413 5874 : ipsec_sa_set_async_mode (sa, 0 /* is_enabled */);
414 : }
415 :
416 6596 : err = ipsec_check_support_cb (im, sa);
417 6596 : if (err)
418 : {
419 0 : clib_warning ("%s", err->what);
420 0 : pool_put (ipsec_sa_pool, sa);
421 0 : return VNET_API_ERROR_UNIMPLEMENTED;
422 : }
423 :
424 6596 : err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
425 6596 : if (err)
426 : {
427 0 : pool_put (ipsec_sa_pool, sa);
428 0 : return VNET_API_ERROR_SYSCALL_ERROR_1;
429 : }
430 :
431 6596 : if (ipsec_sa_is_set_IS_TUNNEL (sa) &&
432 3176 : AF_IP6 == ip_addr_version (&tun->t_src))
433 1552 : ipsec_sa_set_IS_TUNNEL_V6 (sa);
434 :
435 6596 : if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
436 : {
437 3169 : sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
438 :
439 3169 : rv = tunnel_resolve (&sa->tunnel, FIB_NODE_TYPE_IPSEC_SA, sa_index);
440 :
441 3169 : if (rv)
442 : {
443 0 : pool_put (ipsec_sa_pool, sa);
444 0 : return rv;
445 : }
446 3169 : ipsec_sa_stack (sa);
447 :
448 : /* generate header templates */
449 3169 : if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
450 : {
451 1552 : tunnel_build_v6_hdr (&sa->tunnel,
452 1552 : (ipsec_sa_is_set_UDP_ENCAP (sa) ?
453 : IP_PROTOCOL_UDP :
454 : IP_PROTOCOL_IPSEC_ESP),
455 1552 : &sa->ip6_hdr);
456 : }
457 : else
458 : {
459 1617 : tunnel_build_v4_hdr (&sa->tunnel,
460 1617 : (ipsec_sa_is_set_UDP_ENCAP (sa) ?
461 : IP_PROTOCOL_UDP :
462 : IP_PROTOCOL_IPSEC_ESP),
463 1617 : &sa->ip4_hdr);
464 : }
465 : }
466 :
467 6596 : if (ipsec_sa_is_set_UDP_ENCAP (sa))
468 : {
469 70 : if (dst_port == IPSEC_UDP_PORT_NONE)
470 6 : sa->udp_hdr.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
471 : else
472 64 : sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
473 :
474 70 : if (src_port == IPSEC_UDP_PORT_NONE)
475 8 : sa->udp_hdr.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
476 : else
477 62 : sa->udp_hdr.src_port = clib_host_to_net_u16 (src_port);
478 :
479 70 : if (ipsec_sa_is_set_IS_INBOUND (sa))
480 24 : ipsec_register_udp_port (clib_host_to_net_u16 (sa->udp_hdr.dst_port),
481 24 : !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
482 : }
483 :
484 6596 : hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
485 :
486 6596 : if (sa_out_index)
487 6542 : *sa_out_index = sa_index;
488 :
489 6596 : return (0);
490 : }
491 :
492 : static void
493 6596 : ipsec_sa_del (ipsec_sa_t * sa)
494 : {
495 6596 : vlib_main_t *vm = vlib_get_main ();
496 6596 : ipsec_main_t *im = &ipsec_main;
497 : u32 sa_index;
498 :
499 6596 : sa_index = sa - ipsec_sa_pool;
500 6596 : hash_unset (im->sa_index_by_sa_id, sa->id);
501 6596 : tunnel_unresolve (&sa->tunnel);
502 :
503 : /* no recovery possible when deleting an SA */
504 6596 : (void) ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
505 :
506 6596 : if (ipsec_sa_is_set_IS_ASYNC (sa))
507 : {
508 2 : if (!ipsec_sa_is_set_IS_AEAD (sa))
509 0 : vnet_crypto_key_del (vm, sa->crypto_async_key_index);
510 : }
511 :
512 6596 : if (ipsec_sa_is_set_UDP_ENCAP (sa) && ipsec_sa_is_set_IS_INBOUND (sa))
513 24 : ipsec_unregister_udp_port (clib_net_to_host_u16 (sa->udp_hdr.dst_port),
514 24 : !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
515 :
516 6596 : if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
517 3169 : dpo_reset (&sa->dpo);
518 6596 : vnet_crypto_key_del (vm, sa->crypto_sync_key_index);
519 6596 : if (sa->integ_alg != IPSEC_INTEG_ALG_NONE)
520 4842 : vnet_crypto_key_del (vm, sa->integ_sync_key_index);
521 6596 : pool_put (ipsec_sa_pool, sa);
522 6596 : }
523 :
524 : int
525 1 : ipsec_sa_bind (u32 id, u32 worker, bool bind)
526 : {
527 1 : ipsec_main_t *im = &ipsec_main;
528 : uword *p;
529 : ipsec_sa_t *sa;
530 :
531 1 : p = hash_get (im->sa_index_by_sa_id, id);
532 1 : if (!p)
533 0 : return VNET_API_ERROR_INVALID_VALUE;
534 :
535 1 : sa = ipsec_sa_get (p[0]);
536 :
537 1 : if (!bind)
538 : {
539 0 : sa->thread_index = ~0;
540 0 : return 0;
541 : }
542 :
543 1 : if (worker >= vlib_num_workers ())
544 0 : return VNET_API_ERROR_INVALID_WORKER;
545 :
546 1 : sa->thread_index = vlib_get_worker_thread_index (worker);
547 1 : return 0;
548 : }
549 :
550 : void
551 23190 : ipsec_sa_unlock (index_t sai)
552 : {
553 : ipsec_sa_t *sa;
554 :
555 23190 : if (INDEX_INVALID == sai)
556 6290 : return;
557 :
558 16900 : sa = ipsec_sa_get (sai);
559 :
560 16900 : fib_node_unlock (&sa->node);
561 : }
562 :
563 : void
564 440 : ipsec_sa_lock (index_t sai)
565 : {
566 : ipsec_sa_t *sa;
567 :
568 440 : if (INDEX_INVALID == sai)
569 0 : return;
570 :
571 440 : sa = ipsec_sa_get (sai);
572 :
573 440 : fib_node_lock (&sa->node);
574 : }
575 :
576 : index_t
577 9864 : ipsec_sa_find_and_lock (u32 id)
578 : {
579 9864 : ipsec_main_t *im = &ipsec_main;
580 : ipsec_sa_t *sa;
581 : uword *p;
582 :
583 9864 : p = hash_get (im->sa_index_by_sa_id, id);
584 :
585 9864 : if (!p)
586 0 : return INDEX_INVALID;
587 :
588 9864 : sa = ipsec_sa_get (p[0]);
589 :
590 9864 : fib_node_lock (&sa->node);
591 :
592 9864 : return (p[0]);
593 : }
594 :
595 : int
596 6617 : ipsec_sa_unlock_id (u32 id)
597 : {
598 6617 : ipsec_main_t *im = &ipsec_main;
599 : uword *p;
600 :
601 6617 : p = hash_get (im->sa_index_by_sa_id, id);
602 :
603 6617 : if (!p)
604 13 : return VNET_API_ERROR_NO_SUCH_ENTRY;
605 :
606 6604 : ipsec_sa_unlock (p[0]);
607 :
608 6604 : return (0);
609 : }
610 :
611 : void
612 20818 : ipsec_sa_clear (index_t sai)
613 : {
614 20818 : vlib_zero_combined_counter (&ipsec_sa_counters, sai);
615 353906 : for (int i = 0; i < IPSEC_SA_N_ERRORS; i++)
616 333088 : vlib_zero_simple_counter (&ipsec_sa_err_counters[i], sai);
617 20818 : }
618 :
619 : void
620 2531 : ipsec_sa_walk (ipsec_sa_walk_cb_t cb, void *ctx)
621 : {
622 : ipsec_sa_t *sa;
623 :
624 : /* *INDENT-OFF* */
625 7449 : pool_foreach (sa, ipsec_sa_pool)
626 : {
627 4918 : if (WALK_CONTINUE != cb (sa, ctx))
628 0 : break;
629 : }
630 : /* *INDENT-ON* */
631 2531 : }
632 :
633 : /**
634 : * Function definition to get a FIB node from its index
635 : */
636 : static fib_node_t *
637 147 : ipsec_sa_fib_node_get (fib_node_index_t index)
638 : {
639 : ipsec_sa_t *sa;
640 :
641 147 : sa = ipsec_sa_get (index);
642 :
643 147 : return (&sa->node);
644 : }
645 :
646 : static ipsec_sa_t *
647 6743 : ipsec_sa_from_fib_node (fib_node_t *node)
648 : {
649 6743 : ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type);
650 : return (
651 6743 : (ipsec_sa_t *) (((char *) node) - STRUCT_OFFSET_OF (ipsec_sa_t, node)));
652 : }
653 :
654 : /**
655 : * Function definition to inform the FIB node that its last lock has gone.
656 : */
657 : static void
658 6596 : ipsec_sa_last_lock_gone (fib_node_t *node)
659 : {
660 : /*
661 : * The ipsec SA is a root of the graph. As such
662 : * it never has children and thus is never locked.
663 : */
664 6596 : ipsec_sa_del (ipsec_sa_from_fib_node (node));
665 6596 : }
666 :
667 : /**
668 : * Function definition to backwalk a FIB node
669 : */
670 : static fib_node_back_walk_rc_t
671 147 : ipsec_sa_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
672 : {
673 147 : ipsec_sa_stack (ipsec_sa_from_fib_node (node));
674 :
675 147 : return (FIB_NODE_BACK_WALK_CONTINUE);
676 : }
677 :
678 : /*
679 : * Virtual function table registered by SAs
680 : * for participation in the FIB object graph.
681 : */
682 : const static fib_node_vft_t ipsec_sa_vft = {
683 : .fnv_get = ipsec_sa_fib_node_get,
684 : .fnv_last_lock = ipsec_sa_last_lock_gone,
685 : .fnv_back_walk = ipsec_sa_back_walk,
686 : };
687 :
688 : /* Init per-SA error counters and node type */
689 : clib_error_t *
690 559 : ipsec_sa_init (vlib_main_t *vm)
691 : {
692 559 : fib_node_register_type (FIB_NODE_TYPE_IPSEC_SA, &ipsec_sa_vft);
693 :
694 : #define _(index, val, err, desc) \
695 : ipsec_sa_err_counters[index].name = \
696 : (char *) format (0, "SA-" #err "%c", 0); \
697 : ipsec_sa_err_counters[index].stat_segment_name = \
698 : (char *) format (0, "/net/ipsec/sa/err/" #err "%c", 0); \
699 : ipsec_sa_err_counters[index].counters = 0;
700 559 : foreach_ipsec_sa_err
701 : #undef _
702 559 : return 0;
703 : }
704 :
705 52639 : VLIB_INIT_FUNCTION (ipsec_sa_init);
706 :
707 : /*
708 : * fd.io coding-style-patch-verification: ON
709 : *
710 : * Local Variables:
711 : * eval: (c-set-style "gnu")
712 : * End:
713 : */
|