Line data Source code
1 : /*
2 : * ipsec_tun.h : IPSEC tunnel protection
3 : *
4 : * Copyright (c) 2015 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/ipsec/ipsec_tun.h>
19 : #include <vnet/ipsec/ipsec_itf.h>
20 : #include <vnet/ipsec/esp.h>
21 : #include <vnet/udp/udp_local.h>
22 : #include <vnet/adj/adj_delegate.h>
23 : #include <vnet/adj/adj_midchain.h>
24 : #include <vnet/teib/teib.h>
25 : #include <vnet/mpls/mpls.h>
26 :
27 : /* instantiate the bihash functions */
28 : #include <vppinfra/bihash_8_16.h>
29 : #include <vppinfra/bihash_template.c>
30 : #include <vppinfra/bihash_24_16.h>
31 : #include <vppinfra/bihash_template.c>
32 :
33 : #define IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
34 : #define IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE 512 << 20
35 :
36 : /**
37 : * The logger
38 : */
39 : vlib_log_class_t ipsec_tun_protect_logger;
40 :
41 : /**
42 : * Pool of tunnel protection objects
43 : */
44 : ipsec_tun_protect_t *ipsec_tun_protect_pool;
45 :
46 : /**
47 : * Adj delegate registered type
48 : */
49 : static adj_delegate_type_t ipsec_tun_adj_delegate_type;
50 :
51 : /**
52 : * Adj index to TX SA mapping
53 : */
54 : index_t *ipsec_tun_protect_sa_by_adj_index;
55 :
56 : const ip_address_t IP_ADDR_ALL_0 = IP_ADDRESS_V4_ALL_0S;
57 :
58 : /**
59 : * The DB of all added per-nh tunnel protectiond
60 : */
61 : typedef struct ipsec_tun_protect_itf_db_t_
62 : {
63 : /** A hash table key'd on IP (4 or 6) address */
64 : uword *id_hash;
65 : /** If the interface is P2P then there is only one protect
66 : * object associated with the auto-adj for each NH proto */
67 : index_t id_itp;
68 : } ipsec_tun_protect_itf_db_t;
69 :
70 : typedef struct ipsec_tun_protect_db_t_
71 : {
72 : /** Per-interface vector */
73 : ipsec_tun_protect_itf_db_t *id_itf;
74 : } ipsec_tun_protect_db_t;
75 :
76 : static ipsec_tun_protect_db_t itp_db;
77 :
78 : const static ipsec_tun_protect_itf_db_t IPSEC_TUN_PROTECT_DEFAULT_DB_ENTRY = {
79 : .id_itp = INDEX_INVALID,
80 : };
81 :
82 : #define ITP_DBG(_itp, _fmt, _args...) \
83 : { \
84 : vlib_log_debug(ipsec_tun_protect_logger, \
85 : "[%U]: " _fmt, \
86 : format_ipsec_tun_protect, \
87 : _itp, ##_args); \
88 : }
89 :
90 : #define ITP_DBG2(_fmt, _args...) \
91 : { \
92 : vlib_log_debug(ipsec_tun_protect_logger, \
93 : _fmt, ##_args); \
94 : }
95 :
96 : static u32 ipsec_tun_node_regs[N_AF];
97 :
98 : void
99 374 : ipsec_tun_register_nodes (ip_address_family_t af)
100 : {
101 374 : if (0 == ipsec_tun_node_regs[af]++)
102 : {
103 168 : if (AF_IP4 == af)
104 103 : ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
105 : ipsec4_tun_input_node.index);
106 : else
107 65 : ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
108 : ipsec6_tun_input_node.index);
109 168 : ipsec_register_udp_port (UDP_DST_PORT_ipsec, (AF_IP4 == af));
110 : }
111 374 : }
112 :
113 : void
114 355 : ipsec_tun_unregister_nodes (ip_address_family_t af)
115 : {
116 355 : ASSERT (0 != ipsec_tun_node_regs[af]);
117 355 : if (0 == --ipsec_tun_node_regs[af])
118 : {
119 157 : if (AF_IP4 == af)
120 97 : ip4_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
121 : else
122 60 : ip6_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
123 157 : ipsec_unregister_udp_port (UDP_DST_PORT_ipsec, (AF_IP4 == af));
124 : }
125 355 : }
126 :
127 : static inline const ipsec_tun_protect_t *
128 1 : ipsec_tun_protect_from_const_base (const adj_delegate_t * ad)
129 : {
130 1 : if (ad == NULL)
131 0 : return (NULL);
132 1 : return (pool_elt_at_index (ipsec_tun_protect_pool, ad->ad_index));
133 : }
134 :
135 : static u32
136 876 : ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
137 : const ipsec_tun_protect_t *itp)
138 : {
139 : ipsec_main_t *im;
140 : u32 next;
141 :
142 876 : im = &ipsec_main;
143 876 : next = 0;
144 :
145 876 : if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
146 : {
147 801 : if (ip46_address_is_ip4 (&itp->itp_tun.src))
148 597 : linkt = VNET_LINK_IP4;
149 : else
150 204 : linkt = VNET_LINK_IP6;
151 : }
152 :
153 876 : switch (linkt)
154 : {
155 636 : case VNET_LINK_IP4:
156 636 : next = im->esp4_encrypt_tun_node_index;
157 636 : break;
158 226 : case VNET_LINK_IP6:
159 226 : next = im->esp6_encrypt_tun_node_index;
160 226 : break;
161 14 : case VNET_LINK_MPLS:
162 14 : next = im->esp_mpls_encrypt_tun_node_index;
163 14 : break;
164 0 : case VNET_LINK_ARP:
165 : case VNET_LINK_NSH:
166 : case VNET_LINK_ETHERNET:
167 0 : ASSERT (0);
168 0 : break;
169 : }
170 :
171 876 : return (next);
172 : }
173 :
174 : static void
175 169 : ipsec_tun_setup_tx_nodes (u32 sw_if_index, const ipsec_tun_protect_t *itp)
176 : {
177 169 : vnet_feature_modify_end_node (
178 169 : ip4_main.lookup_main.output_feature_arc_index, sw_if_index,
179 : ipsec_tun_protect_get_adj_next (VNET_LINK_IP4, itp));
180 169 : vnet_feature_modify_end_node (
181 169 : ip6_main.lookup_main.output_feature_arc_index, sw_if_index,
182 : ipsec_tun_protect_get_adj_next (VNET_LINK_IP6, itp));
183 169 : vnet_feature_modify_end_node (
184 169 : mpls_main.output_feature_arc_index, sw_if_index,
185 : ipsec_tun_protect_get_adj_next (VNET_LINK_MPLS, itp));
186 169 : }
187 :
188 : static void
189 670 : ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp)
190 : {
191 766 : vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
192 : INDEX_INVALID);
193 :
194 670 : if (NULL == itp)
195 : {
196 301 : ipsec_tun_protect_sa_by_adj_index[ai] = INDEX_INVALID;
197 301 : adj_nbr_midchain_reset_next_node (ai);
198 : }
199 : else
200 : {
201 369 : ipsec_tun_protect_sa_by_adj_index[ai] = itp->itp_out_sa;
202 369 : adj_nbr_midchain_update_next_node (
203 369 : ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp));
204 : }
205 670 : }
206 :
207 : static index_t
208 1165 : ipsec_tun_protect_find (u32 sw_if_index, const ip_address_t * nh)
209 : {
210 : ipsec_tun_protect_itf_db_t *idi;
211 : uword *p;
212 :
213 1165 : if (vec_len (itp_db.id_itf) <= sw_if_index)
214 588 : return INDEX_INVALID;
215 :
216 577 : if (vnet_sw_interface_is_p2p (vnet_get_main (), sw_if_index))
217 319 : return (itp_db.id_itf[sw_if_index].id_itp);
218 :
219 258 : idi = &itp_db.id_itf[sw_if_index];
220 258 : p = hash_get_mem (idi->id_hash, nh);
221 :
222 258 : if (NULL == p)
223 : {
224 100 : return INDEX_INVALID;
225 : }
226 158 : return (p[0]);
227 : }
228 :
229 : static void
230 263 : ipsec_tun_protect_rx_db_add (ipsec_main_t * im,
231 : const ipsec_tun_protect_t * itp)
232 : {
233 : const ipsec_sa_t *sa;
234 : u32 sai;
235 :
236 263 : if (ip46_address_is_zero (&itp->itp_crypto.dst))
237 16 : return;
238 :
239 : /* *INDENT-OFF* */
240 504 : FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
241 : ({
242 : sa = ipsec_sa_get (sai);
243 :
244 : ipsec_tun_lkup_result_t res = {
245 : .tun_index = itp - ipsec_tun_protect_pool,
246 : .sa_index = sai,
247 : .flags = itp->itp_flags,
248 : .sw_if_index = itp->itp_sw_if_index,
249 : };
250 :
251 : /*
252 : * The key is formed from the tunnel's destination
253 : * as the packet lookup is done from the packet's source
254 : */
255 : if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
256 : {
257 : ipsec4_tunnel_kv_t key = {
258 : .value = res,
259 : };
260 : clib_bihash_kv_8_16_t *bkey = (clib_bihash_kv_8_16_t*)&key;
261 :
262 : ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
263 : clib_host_to_net_u32 (sa->spi));
264 :
265 : if (!clib_bihash_is_initialised_8_16 (&im->tun4_protect_by_key))
266 : clib_bihash_init_8_16 (&im->tun4_protect_by_key,
267 : "IPSec IPv4 tunnels",
268 : IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
269 : IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
270 :
271 : clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 1);
272 : ipsec_tun_register_nodes (AF_IP4);
273 : }
274 : else
275 : {
276 : ipsec6_tunnel_kv_t key = {
277 : .key = {
278 : .remote_ip = itp->itp_crypto.dst.ip6,
279 : .spi = clib_host_to_net_u32 (sa->spi),
280 : },
281 : .value = res,
282 : };
283 : clib_bihash_kv_24_16_t *bkey = (clib_bihash_kv_24_16_t*)&key;
284 :
285 : if (!clib_bihash_is_initialised_24_16 (&im->tun6_protect_by_key))
286 : clib_bihash_init_24_16 (&im->tun6_protect_by_key,
287 : "IPSec IPv6 tunnels",
288 : IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
289 : IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
290 : clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 1);
291 : ipsec_tun_register_nodes (AF_IP6);
292 : }
293 : }))
294 : /* *INDENT-ON* */
295 : }
296 :
297 : static adj_walk_rc_t
298 301 : ipsec_tun_protect_adj_add (adj_index_t ai, void *arg)
299 : {
300 301 : ipsec_tun_protect_t *itp = arg;
301 301 : adj_delegate_add (adj_get (ai), ipsec_tun_adj_delegate_type,
302 301 : itp - ipsec_tun_protect_pool);
303 301 : ipsec_tun_protect_add_adj (ai, itp);
304 :
305 301 : if (itp->itp_flags & IPSEC_PROTECT_ITF)
306 39 : ipsec_itf_adj_stack (ai, itp->itp_out_sa);
307 :
308 301 : return (ADJ_WALK_RC_CONTINUE);
309 : }
310 :
311 : static void
312 215 : ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp)
313 : {
314 : /*
315 : * add the delegate to the adj
316 : */
317 : ipsec_tun_protect_itf_db_t *idi;
318 : fib_protocol_t nh_proto;
319 : ip46_address_t nh;
320 :
321 502 : vec_validate_init_empty (itp_db.id_itf,
322 : itp->itp_sw_if_index,
323 : IPSEC_TUN_PROTECT_DEFAULT_DB_ENTRY);
324 :
325 215 : idi = &itp_db.id_itf[itp->itp_sw_if_index];
326 :
327 215 : if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
328 : {
329 154 : if (INDEX_INVALID == idi->id_itp)
330 : {
331 154 : ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
332 : }
333 154 : idi->id_itp = itp - ipsec_tun_protect_pool;
334 :
335 462 : FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
336 308 : adj_nbr_walk (itp->itp_sw_if_index,
337 : nh_proto, ipsec_tun_protect_adj_add, itp);
338 : }
339 : else
340 : {
341 61 : if (NULL == idi->id_hash)
342 : {
343 15 : idi->id_hash =
344 15 : hash_create_mem (0, sizeof (ip_address_t), sizeof (uword));
345 : /*
346 : * enable the encrypt feature for egress if this is the first addition
347 : * on this interface
348 : */
349 15 : ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
350 : }
351 :
352 122 : hash_set_mem (idi->id_hash, itp->itp_key, itp - ipsec_tun_protect_pool);
353 :
354 : /*
355 : * walk all the adjs with the same nh on this interface
356 : * to associate them with this protection
357 : */
358 61 : nh_proto = ip_address_to_46 (itp->itp_key, &nh);
359 :
360 61 : adj_nbr_walk_nh (itp->itp_sw_if_index,
361 : nh_proto, &nh, ipsec_tun_protect_adj_add, itp);
362 :
363 61 : ipsec_tun_register_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
364 : AF_IP6 : AF_IP4);
365 : }
366 215 : }
367 :
368 : static void
369 295 : ipsec_tun_protect_rx_db_remove (ipsec_main_t * im,
370 : const ipsec_tun_protect_t * itp)
371 : {
372 : const ipsec_sa_t *sa;
373 :
374 : /* *INDENT-OFF* */
375 600 : FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
376 : ({
377 : if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
378 : {
379 : ipsec4_tunnel_kv_t key;
380 : clib_bihash_kv_8_16_t res, *bkey = (clib_bihash_kv_8_16_t*)&key;
381 :
382 : ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
383 : clib_host_to_net_u32 (sa->spi));
384 :
385 : if (!clib_bihash_search_8_16 (&im->tun4_protect_by_key, bkey, &res))
386 : {
387 : clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 0);
388 : ipsec_tun_unregister_nodes(AF_IP4);
389 : }
390 : }
391 : else
392 : {
393 : ipsec6_tunnel_kv_t key = {
394 : .key = {
395 : .remote_ip = itp->itp_crypto.dst.ip6,
396 : .spi = clib_host_to_net_u32 (sa->spi),
397 : },
398 : };
399 : clib_bihash_kv_24_16_t res, *bkey = (clib_bihash_kv_24_16_t*)&key;
400 :
401 : if (!clib_bihash_search_24_16 (&im->tun6_protect_by_key, bkey, &res))
402 : {
403 : clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 0);
404 : ipsec_tun_unregister_nodes(AF_IP6);
405 : }
406 : }
407 : }));
408 : /* *INDENT-ON* */
409 295 : }
410 :
411 : static adj_walk_rc_t
412 259 : ipsec_tun_protect_adj_remove (adj_index_t ai, void *arg)
413 : {
414 259 : ipsec_tun_protect_t *itp = arg;
415 :
416 259 : adj_delegate_remove (ai, ipsec_tun_adj_delegate_type);
417 259 : ipsec_tun_protect_add_adj (ai, NULL);
418 :
419 259 : if (itp->itp_flags & IPSEC_PROTECT_ITF)
420 23 : ipsec_itf_adj_unstack (ai);
421 :
422 259 : return (ADJ_WALK_RC_CONTINUE);
423 : }
424 :
425 : static void
426 215 : ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
427 : {
428 : ipsec_tun_protect_itf_db_t *idi;
429 : fib_protocol_t nh_proto;
430 : ip46_address_t nh;
431 :
432 215 : nh_proto = ip_address_to_46 (itp->itp_key, &nh);
433 215 : idi = &itp_db.id_itf[itp->itp_sw_if_index];
434 :
435 215 : if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
436 : {
437 154 : ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
438 154 : idi->id_itp = INDEX_INVALID;
439 :
440 462 : FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
441 308 : adj_nbr_walk (itp->itp_sw_if_index,
442 : nh_proto, ipsec_tun_protect_adj_remove, itp);
443 : }
444 : else
445 : {
446 61 : adj_nbr_walk_nh (itp->itp_sw_if_index,
447 : nh_proto, &nh, ipsec_tun_protect_adj_remove, itp);
448 :
449 122 : hash_unset_mem (idi->id_hash, itp->itp_key);
450 :
451 61 : if (0 == hash_elts (idi->id_hash))
452 : {
453 15 : ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
454 15 : hash_free (idi->id_hash);
455 15 : idi->id_hash = NULL;
456 : }
457 61 : ipsec_tun_unregister_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
458 : AF_IP6 : AF_IP4);
459 : }
460 215 : }
461 :
462 : static void
463 279 : ipsec_tun_protect_set_crypto_addr (ipsec_tun_protect_t * itp)
464 : {
465 : ipsec_sa_t *sa;
466 :
467 : /* *INDENT-OFF* */
468 568 : FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
469 : ({
470 : if (ipsec_sa_is_set_IS_TUNNEL (sa))
471 : {
472 : itp->itp_crypto.src = ip_addr_46 (&sa->tunnel.t_dst);
473 : itp->itp_crypto.dst = ip_addr_46 (&sa->tunnel.t_src);
474 : if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
475 : {
476 : ipsec_sa_set_IS_PROTECT (sa);
477 : itp->itp_flags |= IPSEC_PROTECT_ENCAPED;
478 : }
479 : }
480 : else
481 : {
482 : itp->itp_crypto.src = itp->itp_tun.src;
483 : itp->itp_crypto.dst = itp->itp_tun.dst;
484 : itp->itp_flags &= ~IPSEC_PROTECT_ENCAPED;
485 : }
486 : }));
487 : /* *INDENT-ON* */
488 279 : }
489 :
490 : static void
491 215 : ipsec_tun_protect_config (ipsec_main_t * im,
492 : ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in)
493 : {
494 : index_t sai;
495 : u32 ii;
496 :
497 215 : itp->itp_n_sa_in = vec_len (sas_in);
498 440 : for (ii = 0; ii < itp->itp_n_sa_in; ii++)
499 225 : itp->itp_in_sas[ii] = sas_in[ii];
500 215 : itp->itp_out_sa = sa_out;
501 :
502 215 : ipsec_sa_lock (itp->itp_out_sa);
503 :
504 215 : if (itp->itp_flags & IPSEC_PROTECT_ITF)
505 28 : ipsec_sa_set_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
506 :
507 : /* *INDENT-OFF* */
508 440 : FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
509 : ({
510 : ipsec_sa_lock(sai);
511 : }));
512 215 : ipsec_tun_protect_set_crypto_addr(itp);
513 : /* *INDENT-ON* */
514 :
515 : /*
516 : * add to the DB against each SA
517 : */
518 215 : ipsec_tun_protect_rx_db_add (im, itp);
519 215 : ipsec_tun_protect_tx_db_add (itp);
520 :
521 215 : ITP_DBG (itp, "configured");
522 215 : }
523 :
524 : static void
525 215 : ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp)
526 : {
527 : ipsec_sa_t *sa;
528 : index_t sai;
529 :
530 : /* *INDENT-OFF* */
531 440 : FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
532 : ({
533 : ipsec_sa_unset_IS_PROTECT (sa);
534 : }));
535 :
536 215 : ipsec_tun_protect_rx_db_remove (im, itp);
537 215 : ipsec_tun_protect_tx_db_remove (itp);
538 :
539 215 : ipsec_sa_unset_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
540 215 : ipsec_sa_unlock(itp->itp_out_sa);
541 :
542 440 : FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
543 : ({
544 : ipsec_sa_unlock(sai);
545 : }));
546 : /* *INDENT-ON* */
547 215 : ITP_DBG (itp, "unconfigured");
548 215 : }
549 :
550 : static void
551 96 : ipsec_tun_protect_update_from_teib (ipsec_tun_protect_t * itp,
552 : const teib_entry_t * ne)
553 : {
554 96 : if (NULL != ne)
555 : {
556 : const fib_prefix_t *pfx;
557 :
558 48 : pfx = teib_entry_get_nh (ne);
559 :
560 48 : ip46_address_copy (&itp->itp_tun.dst, &pfx->fp_addr);
561 : }
562 : else
563 48 : ip46_address_reset (&itp->itp_tun.dst);
564 96 : }
565 :
566 : int
567 215 : ipsec_tun_protect_update (u32 sw_if_index,
568 : const ip_address_t * nh, u32 sa_out, u32 * sas_in)
569 : {
570 : ipsec_tun_protect_t *itp;
571 : u32 itpi, ii, *saip;
572 : ipsec_main_t *im;
573 : int rv;
574 :
575 215 : if (NULL == nh)
576 29 : nh = &IP_ADDR_ALL_0;
577 :
578 215 : ITP_DBG2 ("update: %U/%U",
579 : format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
580 : format_ip_address, nh);
581 :
582 215 : if (vec_len (sas_in) > ITP_MAX_N_SA_IN)
583 : {
584 0 : rv = VNET_API_ERROR_LIMIT_EXCEEDED;
585 0 : goto out;
586 : }
587 :
588 215 : rv = 0;
589 215 : im = &ipsec_main;
590 215 : itpi = ipsec_tun_protect_find (sw_if_index, nh);
591 :
592 440 : vec_foreach_index (ii, sas_in)
593 : {
594 225 : sas_in[ii] = ipsec_sa_find_and_lock (sas_in[ii]);
595 225 : if (~0 == sas_in[ii])
596 : {
597 0 : rv = VNET_API_ERROR_INVALID_VALUE;
598 0 : goto out;
599 : }
600 : }
601 :
602 215 : sa_out = ipsec_sa_find_and_lock (sa_out);
603 :
604 215 : if (~0 == sa_out)
605 : {
606 0 : rv = VNET_API_ERROR_INVALID_VALUE;
607 0 : goto out;
608 : }
609 :
610 215 : if (INDEX_INVALID == itpi)
611 : {
612 : vnet_device_class_t *dev_class;
613 : vnet_hw_interface_t *hi;
614 : vnet_main_t *vnm;
615 : u8 is_l2;
616 :
617 183 : vnm = vnet_get_main ();
618 183 : hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
619 183 : dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
620 :
621 183 : if (NULL == dev_class->ip_tun_desc)
622 : {
623 0 : rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
624 0 : goto out;
625 : }
626 :
627 183 : pool_get_zero (ipsec_tun_protect_pool, itp);
628 :
629 183 : itp->itp_sw_if_index = sw_if_index;
630 183 : itp->itp_ai = ADJ_INDEX_INVALID;
631 :
632 183 : itp->itp_n_sa_in = vec_len (sas_in);
633 374 : for (ii = 0; ii < itp->itp_n_sa_in; ii++)
634 191 : itp->itp_in_sas[ii] = sas_in[ii];
635 183 : itp->itp_out_sa = sa_out;
636 :
637 183 : itp->itp_key = clib_mem_alloc (sizeof (*itp->itp_key));
638 183 : ip_address_copy (itp->itp_key, nh);
639 :
640 183 : rv = dev_class->ip_tun_desc (sw_if_index,
641 183 : &itp->itp_tun.src,
642 183 : &itp->itp_tun.dst, &is_l2);
643 :
644 183 : if (rv)
645 0 : goto out;
646 :
647 183 : if (ip46_address_is_zero (&itp->itp_tun.src))
648 : {
649 : /*
650 : * must be one of those pesky ipsec interfaces that has no encap.
651 : * the encap then MUST come from the tunnel mode SA.
652 : */
653 : ipsec_sa_t *sa;
654 :
655 26 : sa = ipsec_sa_get (itp->itp_out_sa);
656 :
657 26 : if (!ipsec_sa_is_set_IS_TUNNEL (sa))
658 : {
659 0 : rv = VNET_API_ERROR_INVALID_DST_ADDRESS;
660 0 : goto out;
661 : }
662 :
663 26 : itp->itp_flags |= IPSEC_PROTECT_ITF;
664 : }
665 157 : else if (ip46_address_is_zero (&itp->itp_tun.dst))
666 : {
667 : /* tunnel has no destination address, presumably because it's p2mp
668 : in which case we use the nh that this is protection for */
669 32 : ipsec_tun_protect_update_from_teib
670 32 : (itp, teib_entry_find (sw_if_index, nh));
671 : }
672 :
673 183 : if (is_l2)
674 12 : itp->itp_flags |= IPSEC_PROTECT_L2;
675 :
676 : /*
677 : * add to the tunnel DB for ingress
678 : * - if the SA is in trasnport mode, then the packates will arrive
679 : * with the IP src,dst of the protected tunnel, in which case we can
680 : * simply strip the IP header and hand the payload to the protocol
681 : * appropriate input handler
682 : * - if the SA is in tunnel mode then there are two IP headers present
683 : * one for the crytpo tunnel endpoints (described in the SA) and one
684 : * for the tunnel endpoints. The outer IP headers in the srriving
685 : * packets will have the crypto endpoints. So the DB needs to contain
686 : * the crpto endpoint. Once the crypto header is stripped, revealing,
687 : * the tunnel-IP we have 2 choices:
688 : * 1) do a tunnel lookup based on the revealed header
689 : * 2) skip the tunnel lookup and assume that the packet matches the
690 : * one that is protected here.
691 : * If we did 1) then we would allow our peer to use the SA for tunnel
692 : * X to inject traffic onto tunnel Y, this is not good. If we do 2)
693 : * then we don't verify that the peer is indeed using SA for tunnel
694 : * X and addressing tunnel X. So we take a compromise, once the SA
695 : * matches to tunnel X we veriy that the inner IP matches the value
696 : * of the tunnel we are protecting, else it's dropped.
697 : */
698 183 : ipsec_tun_protect_config (im, itp, sa_out, sas_in);
699 : }
700 : else
701 : {
702 : /* updating SAs only */
703 32 : itp = pool_elt_at_index (ipsec_tun_protect_pool, itpi);
704 :
705 32 : ipsec_tun_protect_unconfig (im, itp);
706 32 : ipsec_tun_protect_config (im, itp, sa_out, sas_in);
707 : }
708 :
709 215 : ipsec_sa_unlock (sa_out);
710 440 : vec_foreach (saip, sas_in) ipsec_sa_unlock (*saip);
711 215 : vec_free (sas_in);
712 :
713 215 : out:
714 215 : return (rv);
715 : }
716 :
717 : int
718 183 : ipsec_tun_protect_del (u32 sw_if_index, const ip_address_t * nh)
719 : {
720 : ipsec_tun_protect_t *itp;
721 : ipsec_main_t *im;
722 : index_t itpi;
723 :
724 183 : ITP_DBG2 ("delete: %U/%U",
725 : format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
726 : format_ip_address, nh);
727 :
728 183 : im = &ipsec_main;
729 183 : if (NULL == nh)
730 27 : nh = &IP_ADDR_ALL_0;
731 :
732 183 : itpi = ipsec_tun_protect_find (sw_if_index, nh);
733 :
734 183 : if (INDEX_INVALID == itpi)
735 0 : return (VNET_API_ERROR_NO_SUCH_ENTRY);
736 :
737 183 : itp = ipsec_tun_protect_get (itpi);
738 183 : ipsec_tun_protect_unconfig (im, itp);
739 :
740 183 : if (ADJ_INDEX_INVALID != itp->itp_ai)
741 0 : adj_unlock (itp->itp_ai);
742 :
743 183 : clib_mem_free (itp->itp_key);
744 183 : pool_put (ipsec_tun_protect_pool, itp);
745 :
746 183 : return (0);
747 : }
748 :
749 : void
750 3625 : ipsec_tun_protect_walk (ipsec_tun_protect_walk_cb_t fn, void *ctx)
751 : {
752 : index_t itpi;
753 :
754 : /* *INDENT-OFF* */
755 5732 : pool_foreach_index (itpi, ipsec_tun_protect_pool)
756 : {
757 2107 : fn (itpi, ctx);
758 : }
759 : /* *INDENT-ON* */
760 3625 : }
761 :
762 : void
763 312 : ipsec_tun_protect_walk_itf (u32 sw_if_index,
764 : ipsec_tun_protect_walk_cb_t fn, void *ctx)
765 : {
766 : ipsec_tun_protect_itf_db_t *idi;
767 : ip_address_t *key;
768 : index_t itpi;
769 :
770 312 : if (vec_len (itp_db.id_itf) <= sw_if_index)
771 6 : return;
772 :
773 306 : idi = &itp_db.id_itf[sw_if_index];
774 :
775 : /* *INDENT-OFF* */
776 7806 : hash_foreach(key, itpi, idi->id_hash,
777 : ({
778 : fn (itpi, ctx);
779 : }));
780 : /* *INDENT-ON* */
781 306 : if (INDEX_INVALID != idi->id_itp)
782 78 : fn (idi->id_itp, ctx);
783 : }
784 :
785 : static void
786 132306 : ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable,
787 : void *data)
788 : {
789 : ipsec_tun_protect_t *itp;
790 : index_t itpi;
791 :
792 132306 : if (arc_index != feature_main.device_input_feature_arc_index)
793 132172 : return;
794 :
795 : /* Only p2p tunnels supported */
796 134 : itpi = ipsec_tun_protect_find (sw_if_index, &IP_ADDR_ALL_0);
797 134 : if (itpi == INDEX_INVALID)
798 118 : return;
799 :
800 16 : itp = ipsec_tun_protect_get (itpi);
801 :
802 16 : if (is_enable)
803 : {
804 8 : u32 decrypt_tun = ip46_address_is_ip4 (&itp->itp_crypto.dst) ?
805 8 : ipsec_main.esp4_decrypt_tun_node_index :
806 : ipsec_main.esp6_decrypt_tun_node_index;
807 :
808 8 : if (!(itp->itp_flags & IPSEC_PROTECT_FEAT))
809 : {
810 4 : itp->itp_flags |= IPSEC_PROTECT_FEAT;
811 4 : vnet_feature_modify_end_node (
812 4 : feature_main.device_input_feature_arc_index, sw_if_index,
813 : decrypt_tun);
814 : }
815 : }
816 : else
817 : {
818 8 : if (itp->itp_flags & IPSEC_PROTECT_FEAT)
819 : {
820 4 : itp->itp_flags &= ~IPSEC_PROTECT_FEAT;
821 :
822 4 : u32 eth_in =
823 4 : vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input")
824 : ->index;
825 :
826 4 : vnet_feature_modify_end_node (
827 4 : feature_main.device_input_feature_arc_index, sw_if_index, eth_in);
828 : }
829 : }
830 :
831 : /* Propagate flag change into lookup entries */
832 16 : ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
833 16 : ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
834 : }
835 :
836 : static void
837 42 : ipsec_tun_protect_adj_delegate_adj_deleted (adj_delegate_t * ad)
838 : {
839 : /* remove our delegate */
840 42 : ipsec_tun_protect_add_adj (ad->ad_adj_index, NULL);
841 42 : adj_delegate_remove (ad->ad_adj_index, ipsec_tun_adj_delegate_type);
842 42 : }
843 :
844 : static void
845 68 : ipsec_tun_protect_adj_delegate_adj_modified (adj_delegate_t * ad)
846 : {
847 68 : ipsec_tun_protect_add_adj (ad->ad_adj_index,
848 68 : ipsec_tun_protect_get (ad->ad_index));
849 68 : }
850 :
851 : static void
852 47098 : ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai)
853 : {
854 : /* add our delegate if there is protection for this neighbour */
855 47098 : ip_address_t ip = IP_ADDRESS_V4_ALL_0S;
856 : ip_adjacency_t *adj;
857 : index_t itpi;
858 :
859 47098 : if (!adj_is_midchain (ai))
860 46635 : return;
861 :
862 1877 : vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
863 : INDEX_INVALID);
864 :
865 463 : adj = adj_get (ai);
866 :
867 463 : ip_address_from_46 (&adj->sub_type.midchain.next_hop,
868 463 : adj->ia_nh_proto, &ip);
869 :
870 463 : itpi = ipsec_tun_protect_find (adj->rewrite_header.sw_if_index, &ip);
871 :
872 463 : if (INDEX_INVALID != itpi)
873 45 : ipsec_tun_protect_adj_add (ai, ipsec_tun_protect_get (itpi));
874 : }
875 :
876 : static u8 *
877 1 : ipsec_tun_protect_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
878 : {
879 : const ipsec_tun_protect_t *itp;
880 :
881 1 : itp = ipsec_tun_protect_from_const_base (aed);
882 1 : s = format (s, "ipsec-tun-protect:\n%U", format_ipsec_tun_protect, itp);
883 :
884 1 : return (s);
885 : }
886 :
887 : static void
888 85 : ipsec_tun_teib_entry_added (const teib_entry_t * ne)
889 : {
890 : ipsec_tun_protect_t *itp;
891 : index_t itpi;
892 :
893 85 : itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
894 : teib_entry_get_peer (ne));
895 :
896 85 : if (INDEX_INVALID == itpi)
897 53 : return;
898 :
899 32 : itp = ipsec_tun_protect_get (itpi);
900 32 : ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
901 32 : ipsec_tun_protect_update_from_teib (itp, ne);
902 32 : ipsec_tun_protect_set_crypto_addr (itp);
903 32 : ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
904 :
905 32 : ITP_DBG (itp, "teib-added");
906 : }
907 :
908 : static void
909 85 : ipsec_tun_teib_entry_deleted (const teib_entry_t * ne)
910 : {
911 : ipsec_tun_protect_t *itp;
912 : index_t itpi;
913 :
914 85 : itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
915 : teib_entry_get_peer (ne));
916 :
917 85 : if (INDEX_INVALID == itpi)
918 53 : return;
919 :
920 32 : itp = ipsec_tun_protect_get (itpi);
921 32 : ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
922 32 : ipsec_tun_protect_update_from_teib (itp, NULL);
923 32 : ipsec_tun_protect_set_crypto_addr (itp);
924 :
925 32 : ITP_DBG (itp, "teib-removed");
926 : }
927 :
928 : /**
929 : * VFT registered with the adjacency delegate
930 : */
931 : const static adj_delegate_vft_t ipsec_tun_adj_delegate_vft = {
932 : .adv_adj_deleted = ipsec_tun_protect_adj_delegate_adj_deleted,
933 : .adv_adj_created = ipsec_tun_protect_adj_delegate_adj_created,
934 : .adv_adj_modified = ipsec_tun_protect_adj_delegate_adj_modified,
935 : .adv_format = ipsec_tun_protect_adj_delegate_format,
936 : };
937 :
938 : const static teib_vft_t ipsec_tun_teib_vft = {
939 : .nv_added = ipsec_tun_teib_entry_added,
940 : .nv_deleted = ipsec_tun_teib_entry_deleted,
941 : };
942 :
943 : void
944 0 : ipsec_tun_table_init (ip_address_family_t af, uword table_size, u32 n_buckets)
945 : {
946 : ipsec_main_t *im;
947 :
948 0 : im = &ipsec_main;
949 :
950 0 : if (AF_IP4 == af)
951 0 : clib_bihash_init_8_16 (&im->tun4_protect_by_key,
952 : "IPSec IPv4 tunnels", n_buckets, table_size);
953 : else
954 0 : clib_bihash_init_24_16 (&im->tun6_protect_by_key,
955 : "IPSec IPv6 tunnels", n_buckets, table_size);
956 0 : }
957 :
958 : static clib_error_t *
959 575 : ipsec_tunnel_protect_init (vlib_main_t *vm)
960 : {
961 : ipsec_main_t *im;
962 :
963 575 : im = &ipsec_main;
964 575 : clib_bihash_init_24_16 (&im->tun6_protect_by_key,
965 : "IPSec IPv6 tunnels",
966 : IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
967 : IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
968 575 : clib_bihash_init_8_16 (&im->tun4_protect_by_key,
969 : "IPSec IPv4 tunnels",
970 : IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
971 : IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
972 :
973 575 : ipsec_tun_adj_delegate_type =
974 575 : adj_delegate_register_new_type (&ipsec_tun_adj_delegate_vft);
975 :
976 575 : ipsec_tun_protect_logger = vlib_log_register_class ("ipsec", "tun");
977 :
978 575 : teib_register (&ipsec_tun_teib_vft);
979 :
980 575 : vnet_feature_register (ipsec_tun_feature_update, NULL);
981 :
982 575 : return 0;
983 : }
984 :
985 54143 : VLIB_INIT_FUNCTION (ipsec_tunnel_protect_init);
986 :
987 : /*
988 : * fd.io coding-style-patch-verification: ON
989 : *
990 : * Local Variables:
991 : * eval: (c-set-style "gnu")
992 : * End:
993 : */
|