2 * ipsec_if.c : IPSec interface support
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/fib/fib.h>
22 #include <vnet/udp/udp.h>
23 #include <vnet/adj/adj_midchain.h>
25 #include <vnet/ipsec/ipsec.h>
26 #include <vnet/ipsec/esp.h>
28 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
31 format_ipsec_name (u8 * s, va_list * args)
33 u32 dev_instance = va_arg (*args, u32);
34 ipsec_main_t *im = &ipsec_main;
35 ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance;
37 return format (s, "ipsec%d", t->show_instance);
40 /* Statistics (not really errors) */
41 #define foreach_ipsec_if_tx_error \
42 _(TX, "good packets transmitted")
45 ipsec_if_tunnel_stack (adj_index_t ai)
47 ipsec_main_t *ipm = &ipsec_main;
48 ipsec_tunnel_if_t *it;
53 sw_if_index = adj->rewrite_header.sw_if_index;
55 if ((vec_len (ipm->ipsec_if_by_sw_if_index) <= sw_if_index) ||
56 (~0 == ipm->ipsec_if_by_sw_if_index[sw_if_index]))
59 it = pool_elt_at_index (ipm->tunnel_interfaces,
60 ipm->ipsec_if_by_sw_if_index[sw_if_index]);
62 if (!vnet_hw_interface_is_link_up (vnet_get_main (), it->hw_if_index))
64 adj_midchain_delegate_unstack (ai);
70 sa = ipsec_sa_get (it->output_sa_index);
73 .fp_addr = sa->tunnel_dst_addr,
74 .fp_len = (sa->is_tunnel_ip6 ? 128 : 32),
75 .fp_proto = (sa->is_tunnel_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4),
78 adj_midchain_delegate_stack (ai, sa->tx_fib_index, &pfx);
83 * @brief Call back when restacking all adjacencies on a GRE interface
86 ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx)
88 ipsec_if_tunnel_stack (ai);
90 return (ADJ_WALK_RC_CONTINUE);
94 ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it)
99 * walk all the adjacencies on th GRE interface and restack them
101 FOR_EACH_FIB_IP_PROTOCOL (proto)
103 adj_nbr_walk (it->sw_if_index, proto, ipsec_if_adj_walk_cb, NULL);
107 static clib_error_t *
108 ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
110 ipsec_main_t *im = &ipsec_main;
111 clib_error_t *err = 0;
112 ipsec_tunnel_if_t *t;
113 vnet_hw_interface_t *hi;
116 hi = vnet_get_hw_interface (vnm, hw_if_index);
117 t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
120 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
122 sa = pool_elt_at_index (im->sad, t->input_sa_index);
124 err = ipsec_check_support_cb (im, sa);
128 err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1);
132 sa = pool_elt_at_index (im->sad, t->output_sa_index);
134 err = ipsec_check_support_cb (im, sa);
138 err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1);
142 vnet_hw_interface_set_flags (vnm, hw_if_index,
143 VNET_HW_INTERFACE_FLAG_LINK_UP);
147 vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
148 sa = pool_elt_at_index (im->sad, t->input_sa_index);
149 err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0);
152 sa = pool_elt_at_index (im->sad, t->output_sa_index);
153 err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0);
158 ipsec_if_tunnel_restack (t);
164 ipsec_if_build_rewrite (vnet_main_t * vnm,
166 vnet_link_t link_type, const void *dst_address)
172 ipsec_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
174 adj_nbr_midchain_update_rewrite
175 (ai, NULL, NULL, ADJ_FLAG_MIDCHAIN_IP_STACK,
176 ipsec_if_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai), NULL));
178 ipsec_if_tunnel_stack (ai);
182 VNET_DEVICE_CLASS (ipsec_device_class) =
185 .format_device_name = format_ipsec_name,
186 .admin_up_down_function = ipsec_admin_up_down_function,
191 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
194 .build_rewrite = default_build_rewrite,
195 .update_adjacency = ipsec_if_update_adj,
196 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
201 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
203 vnet_main_t *vnm = vnet_get_main ();
204 ASSERT (vlib_get_thread_index () == 0);
206 return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
210 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
212 vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
213 (u8 *) args, sizeof (*args));
218 ipsec_tun_mk_input_sa_id (u32 ti)
220 return (0x80000000 | ti);
224 ipsec_tun_mk_output_sa_id (u32 ti)
226 return (0xc0000000 | ti);
230 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
231 ipsec_add_del_tunnel_args_t * args,
234 ipsec_tunnel_if_t *t;
235 ipsec_main_t *im = &ipsec_main;
236 vnet_hw_interface_t *hi = NULL;
237 u32 hw_if_index = ~0;
240 ipsec_key_t crypto_key, integ_key;
241 ipsec_sa_flags_t flags;
243 int is_ip6 = args->is_ip6;
244 ipsec4_tunnel_key_t key4;
245 ipsec6_tunnel_key_t key6;
249 key4.remote_ip = args->remote_ip.ip4.as_u32;
250 key4.spi = clib_host_to_net_u32 (args->remote_spi);
251 p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64);
255 key6.remote_ip = args->remote_ip.ip6;
256 key6.spi = clib_host_to_net_u32 (args->remote_spi);
257 p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key6);
262 /* check if same src/dst pair exists */
264 return VNET_API_ERROR_INVALID_VALUE;
266 pool_get_aligned_zero (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
268 dev_instance = t - im->tunnel_interfaces;
270 t->show_instance = args->show_instance;
272 t->show_instance = dev_instance;
274 if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance))
276 pool_put (im->tunnel_interfaces, t);
277 return VNET_API_ERROR_INSTANCE_IN_USE;
280 hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance,
283 flags = IPSEC_SA_FLAG_IS_TUNNEL;
285 flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
287 flags |= IPSEC_SA_FLAG_UDP_ENCAP;
289 flags |= IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM;
290 if (args->anti_replay)
291 flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
293 ipsec_mk_key (&crypto_key,
294 args->remote_crypto_key, args->remote_crypto_key_len);
295 ipsec_mk_key (&integ_key,
296 args->remote_integ_key, args->remote_integ_key_len);
298 rv = ipsec_sa_add (ipsec_tun_mk_input_sa_id (dev_instance),
308 &args->local_ip, &t->input_sa_index);
311 return VNET_API_ERROR_INVALID_SRC_ADDRESS;
313 ipsec_mk_key (&crypto_key,
314 args->local_crypto_key, args->local_crypto_key_len);
315 ipsec_mk_key (&integ_key,
316 args->local_integ_key, args->local_integ_key_len);
318 rv = ipsec_sa_add (ipsec_tun_mk_output_sa_id (dev_instance),
328 &args->remote_ip, &t->output_sa_index);
331 return VNET_API_ERROR_INVALID_DST_ADDRESS;
335 hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6,
336 t - im->tunnel_interfaces);
338 hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64,
339 t - im->tunnel_interfaces);
341 hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
342 t - im->tunnel_interfaces,
343 ipsec_hw_class.index,
344 t - im->tunnel_interfaces);
346 hi = vnet_get_hw_interface (vnm, hw_if_index);
348 t->hw_if_index = hw_if_index;
349 t->sw_if_index = hi->sw_if_index;
351 /* Add the new tunnel to the DB of tunnels per sw_if_index ... */
352 vec_validate_init_empty (im->ipsec_if_by_sw_if_index, t->sw_if_index,
354 im->ipsec_if_by_sw_if_index[t->sw_if_index] = dev_instance;
356 vnet_feature_enable_disable ("ip4-output",
360 sizeof (t->output_sa_index));
361 vnet_feature_enable_disable ("ip6-output",
365 sizeof (t->output_sa_index));
367 /*1st interface, register protocol */
368 if (pool_elts (im->tunnel_interfaces) == 1)
370 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
371 ipsec4_if_input_node.index);
372 ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
373 ipsec6_if_input_node.index);
381 /* check if exists */
383 return VNET_API_ERROR_INVALID_VALUE;
386 t = pool_elt_at_index (im->tunnel_interfaces, ti);
387 hi = vnet_get_hw_interface (vnm, t->hw_if_index);
388 vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
390 vnet_feature_enable_disable ("ip4-output",
394 sizeof (t->output_sa_index));
395 vnet_feature_enable_disable ("ip6-output",
399 sizeof (t->output_sa_index));
400 vnet_delete_hw_interface (vnm, t->hw_if_index);
403 hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6);
405 hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64);
407 hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
408 im->ipsec_if_by_sw_if_index[t->sw_if_index] = ~0;
410 pool_put (im->tunnel_interfaces, t);
412 /* delete input and output SA */
413 ipsec_sa_del (ipsec_tun_mk_input_sa_id (ti));
414 ipsec_sa_del (ipsec_tun_mk_output_sa_id (ti));
418 *sw_if_index = hi->sw_if_index;
424 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
425 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
427 ipsec_tunnel_if_t *t = 0;
428 ipsec_main_t *im = &ipsec_main;
431 ipsec4_tunnel_key_t key;
434 p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
436 return VNET_API_ERROR_INVALID_VALUE;
439 p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
441 return VNET_API_ERROR_INVALID_VALUE;
443 sa = pool_elt_at_index (im->sad, p[0]);
445 if (ipsec_sa_is_set_IS_TUNNEL (sa))
447 key.remote_ip = sa->tunnel_dst_addr.ip4.as_u32;
448 key.spi = clib_host_to_net_u32 (sa->spi);
452 key.remote_ip = args->remote_ip.as_u32;
453 key.spi = clib_host_to_net_u32 (sa->spi);
456 p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
460 /* check if same src/dst pair exists */
462 return VNET_API_ERROR_INVALID_VALUE;
464 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
465 clib_memset (t, 0, sizeof (*t));
467 t->input_sa_index = isa;
468 t->output_sa_index = osa;
470 hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
471 t - im->tunnel_interfaces);
473 /*1st interface, register protocol */
474 if (pool_elts (im->tunnel_interfaces) == 1)
476 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
477 ipsec4_if_input_node.index);
480 ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
481 ipsec6_if_input_node.index);
487 /* check if exists */
489 return VNET_API_ERROR_INVALID_VALUE;
491 t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
492 hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
493 pool_put (im->tunnel_interfaces, t);
499 ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
500 ipsec_if_set_key_type_t type, u8 alg, u8 * key)
502 ipsec_main_t *im = &ipsec_main;
503 vnet_hw_interface_t *hi;
504 ipsec_tunnel_if_t *t;
507 hi = vnet_get_hw_interface (vnm, hw_if_index);
508 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
510 if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
511 return VNET_API_ERROR_SYSCALL_ERROR_1;
513 if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
515 sa = pool_elt_at_index (im->sad, t->output_sa_index);
516 ipsec_sa_set_crypto_alg (sa, alg);
517 ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
519 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
521 sa = pool_elt_at_index (im->sad, t->output_sa_index);
522 ipsec_sa_set_integ_alg (sa, alg);
523 ipsec_mk_key (&sa->integ_key, key, vec_len (key));
525 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
527 sa = pool_elt_at_index (im->sad, t->input_sa_index);
528 ipsec_sa_set_crypto_alg (sa, alg);
529 ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
531 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
533 sa = pool_elt_at_index (im->sad, t->input_sa_index);
534 ipsec_sa_set_integ_alg (sa, alg);
535 ipsec_mk_key (&sa->integ_key, key, vec_len (key));
538 return VNET_API_ERROR_INVALID_VALUE;
545 ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
548 ipsec_main_t *im = &ipsec_main;
549 vnet_hw_interface_t *hi;
550 ipsec_tunnel_if_t *t;
551 ipsec_sa_t *sa, *old_sa;
552 u32 sa_index, old_sa_index;
555 hi = vnet_get_hw_interface (vnm, hw_if_index);
556 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
558 sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
561 clib_warning ("SA with ID %u not found", sa_id);
562 return VNET_API_ERROR_INVALID_VALUE;
565 if (ipsec_is_sa_used (sa_index))
567 clib_warning ("SA with ID %u is already in use", sa_id);
568 return VNET_API_ERROR_INVALID_VALUE;
571 sa = pool_elt_at_index (im->sad, sa_index);
575 old_sa_index = t->input_sa_index;
576 old_sa = pool_elt_at_index (im->sad, old_sa_index);
578 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^
579 ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa))
581 clib_warning ("IPsec interface SA endpoints type can't be changed");
582 return VNET_API_ERROR_INVALID_VALUE;
585 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
587 ipsec6_tunnel_key_t key;
589 /* unset old inbound hash entry. packets should stop arriving */
590 key.remote_ip = old_sa->tunnel_src_addr.ip6;
591 key.spi = clib_host_to_net_u32 (old_sa->spi);
593 p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key);
595 hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key);
597 /* set new inbound SA, then set new hash entry */
598 t->input_sa_index = sa_index;
599 key.remote_ip = sa->tunnel_src_addr.ip6;
600 key.spi = clib_host_to_net_u32 (sa->spi);
602 hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key,
607 ipsec4_tunnel_key_t key;
609 /* unset old inbound hash entry. packets should stop arriving */
610 key.remote_ip = old_sa->tunnel_src_addr.ip4.as_u32;
611 key.spi = clib_host_to_net_u32 (old_sa->spi);
613 p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
615 hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
617 /* set new inbound SA, then set new hash entry */
618 t->input_sa_index = sa_index;
619 key.remote_ip = sa->tunnel_src_addr.ip4.as_u32;
620 key.spi = clib_host_to_net_u32 (sa->spi);
622 hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
628 old_sa_index = t->output_sa_index;
629 old_sa = pool_elt_at_index (im->sad, old_sa_index);
631 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^
632 ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa))
634 clib_warning ("IPsec interface SA endpoints type can't be changed");
635 return VNET_API_ERROR_INVALID_VALUE;
638 t->output_sa_index = sa_index;
641 /* remove sa_id to sa_index mapping on old SA */
642 if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
643 hash_unset (im->sa_index_by_sa_id, old_sa->id);
645 if (ipsec_add_del_sa_sess_cb (im, old_sa_index, 0))
647 clib_warning ("IPsec backend add/del callback returned error");
648 return VNET_API_ERROR_SYSCALL_ERROR_1;
650 pool_put (im->sad, old_sa);
657 ipsec_tunnel_if_init (vlib_main_t * vm)
659 ipsec_main_t *im = &ipsec_main;
661 /* initialize the ipsec-if ip4 hash */
662 im->ipsec4_if_pool_index_by_key =
663 hash_create (0, sizeof (ipsec4_tunnel_key_t));
664 /* initialize the ipsec-if ip6 hash */
665 im->ipsec6_if_pool_index_by_key = hash_create_mem (0,
667 (ipsec6_tunnel_key_t),
669 im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
671 udp_register_dst_port (vm, UDP_DST_PORT_ipsec, ipsec4_if_input_node.index,
676 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
680 * fd.io coding-style-patch-verification: ON
683 * eval: (c-set-style "gnu")