X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fipsec%2Fipsec_if.c;fp=src%2Fvnet%2Fipsec%2Fipsec_if.c;h=0000000000000000000000000000000000000000;hb=12989b538881f9681f078cf1485c51df1251877a;hp=a7372747797501b4eff8835c78c1459e4c3d75fb;hpb=f1653e62fe41e3df429aadaaab22d0cc8aaa227a;p=vpp.git diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c deleted file mode 100644 index a7372747797..00000000000 --- a/src/vnet/ipsec/ipsec_if.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * ipsec_if.c : IPSec interface support - * - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); - -static u8 * -format_ipsec_name (u8 * s, va_list * args) -{ - u32 dev_instance = va_arg (*args, u32); - ipsec_main_t *im = &ipsec_main; - ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance; - - return format (s, "ipsec%d", t->show_instance); -} - -/* Statistics (not really errors) */ -#define foreach_ipsec_if_tx_error \ -_(TX, "good packets transmitted") - -static void -ipsec_if_tunnel_stack (adj_index_t ai) -{ - ipsec_main_t *ipm = &ipsec_main; - ipsec_tunnel_if_t *it; - ip_adjacency_t *adj; - u32 sw_if_index; - - adj = adj_get (ai); - sw_if_index = adj->rewrite_header.sw_if_index; - - if ((vec_len (ipm->ipsec_if_by_sw_if_index) <= sw_if_index) || - (~0 == ipm->ipsec_if_by_sw_if_index[sw_if_index])) - return; - - it = pool_elt_at_index (ipm->tunnel_interfaces, - ipm->ipsec_if_by_sw_if_index[sw_if_index]); - - if (!vnet_hw_interface_is_link_up (vnet_get_main (), it->hw_if_index)) - { - adj_midchain_delegate_unstack (ai); - } - else - { - ipsec_sa_t *sa; - - sa = ipsec_sa_get (it->output_sa_index); - - /* *INDENT-OFF* */ - fib_prefix_t pfx = { - .fp_addr = sa->tunnel_dst_addr, - .fp_len = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? 128 : 32), - .fp_proto = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? - FIB_PROTOCOL_IP6 : - FIB_PROTOCOL_IP4), - }; - /* *INDENT-ON* */ - - adj_midchain_delegate_stack (ai, sa->tx_fib_index, &pfx); - } -} - -/** - * @brief Call back when restacking all adjacencies on a IPSec interface - */ -static adj_walk_rc_t -ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx) -{ - ipsec_if_tunnel_stack (ai); - - return (ADJ_WALK_RC_CONTINUE); -} - -static void -ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it) -{ - fib_protocol_t proto; - - /* - * walk all the adjacencies on the IPSec interface and restack them - */ - FOR_EACH_FIB_IP_PROTOCOL (proto) - { - adj_nbr_walk (it->sw_if_index, proto, ipsec_if_adj_walk_cb, NULL); - } -} - -static clib_error_t * -ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags) -{ - ipsec_main_t *im = &ipsec_main; - clib_error_t *err = 0; - ipsec_tunnel_if_t *t; - vnet_hw_interface_t *hi; - ipsec_sa_t *sa; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance); - t->flags = flags; - - if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) - { - sa = pool_elt_at_index (im->sad, t->input_sa_index); - - err = ipsec_check_support_cb (im, sa); - if (err) - return err; - - err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1); - if (err) - return err; - - sa = pool_elt_at_index (im->sad, t->output_sa_index); - - err = ipsec_check_support_cb (im, sa); - if (err) - return err; - - err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1); - if (err) - return err; - - vnet_hw_interface_set_flags (vnm, hw_if_index, - VNET_HW_INTERFACE_FLAG_LINK_UP); - } - else - { - vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ ); - sa = pool_elt_at_index (im->sad, t->input_sa_index); - err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0); - if (err) - return err; - sa = pool_elt_at_index (im->sad, t->output_sa_index); - err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0); - if (err) - return err; - } - - ipsec_if_tunnel_restack (t); - - return (NULL); -} - -static u8 * -ipsec_if_build_rewrite (vnet_main_t * vnm, - u32 sw_if_index, - vnet_link_t link_type, const void *dst_address) -{ - return (NULL); -} - -static void -ipsec_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai) -{ - adj_nbr_midchain_update_rewrite - (ai, NULL, NULL, ADJ_FLAG_MIDCHAIN_IP_STACK, - ipsec_if_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai), NULL)); - - ipsec_if_tunnel_stack (ai); -} - -/* *INDENT-OFF* */ -VNET_DEVICE_CLASS (ipsec_device_class) = -{ - .name = "IPSec", - .format_device_name = format_ipsec_name, - .admin_up_down_function = ipsec_admin_up_down_function, -}; -/* *INDENT-ON* */ - -/* *INDENT-OFF* */ -VNET_HW_INTERFACE_CLASS (ipsec_hw_class) = -{ - .name = "IPSec", - .build_rewrite = default_build_rewrite, - .update_adjacency = ipsec_if_update_adj, - .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, -}; -/* *INDENT-ON* */ - -static int -ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a) -{ - vnet_main_t *vnm = vnet_get_main (); - ASSERT (vlib_get_thread_index () == 0); - - return ipsec_add_del_tunnel_if_internal (vnm, a, NULL); -} - -int -ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args) -{ - vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback, - (u8 *) args, sizeof (*args)); - return 0; -} - -static u32 -ipsec_tun_mk_input_sa_id (u32 ti) -{ - return (0x80000000 | ti); -} - -static u32 -ipsec_tun_mk_output_sa_id (u32 ti) -{ - return (0xc0000000 | ti); -} - -static void -ipsec_tunnel_feature_set (ipsec_main_t * im, ipsec_tunnel_if_t * t, u8 enable) -{ - u8 arc; - u32 esp4_feature_index, esp6_feature_index; - ipsec_sa_t *sa; - - sa = ipsec_sa_get (t->output_sa_index); - if (sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE && - sa->integ_alg == IPSEC_INTEG_ALG_NONE) - { - esp4_feature_index = im->esp4_no_crypto_tun_feature_index; - esp6_feature_index = im->esp6_no_crypto_tun_feature_index; - } - else - { - esp4_feature_index = im->esp4_encrypt_tun_feature_index; - esp6_feature_index = im->esp6_encrypt_tun_feature_index; - } - - arc = vnet_get_feature_arc_index ("ip4-output"); - - vnet_feature_enable_disable_with_index (arc, esp4_feature_index, - t->sw_if_index, enable, - &t->output_sa_index, - sizeof (t->output_sa_index)); - - arc = vnet_get_feature_arc_index ("ip6-output"); - - vnet_feature_enable_disable_with_index (arc, esp6_feature_index, - t->sw_if_index, enable, - &t->output_sa_index, - sizeof (t->output_sa_index)); -} - -int -ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, - ipsec_add_del_tunnel_args_t * args, - u32 * sw_if_index_p) -{ - ipsec_tunnel_if_t *t; - ipsec_main_t *im = &ipsec_main; - vnet_hw_interface_t *hi = NULL; - u32 hw_if_index = ~0; - u32 sw_if_index = ~0; - uword *p; - u32 dev_instance; - ipsec_key_t crypto_key, integ_key; - ipsec_sa_flags_t flags; - int rv; - int is_ip6 = args->is_ip6; - ipsec4_tunnel_key_t key4; - ipsec6_tunnel_key_t key6; - - if (!is_ip6) - { - key4.remote_ip.as_u32 = args->remote_ip.ip4.as_u32; - key4.spi = clib_host_to_net_u32 (args->remote_spi); - p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64); - } - else - { - key6.remote_ip = args->remote_ip.ip6; - key6.spi = clib_host_to_net_u32 (args->remote_spi); - p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key6); - } - - if (args->is_add) - { - /* check if same src/dst pair exists */ - if (p) - return VNET_API_ERROR_INVALID_VALUE; - - pool_get_aligned_zero (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES); - - dev_instance = t - im->tunnel_interfaces; - if (args->renumber) - t->show_instance = args->show_instance; - else - t->show_instance = dev_instance; - - if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance)) - { - pool_put (im->tunnel_interfaces, t); - return VNET_API_ERROR_INSTANCE_IN_USE; - } - - hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance, - dev_instance); - - flags = IPSEC_SA_FLAG_IS_TUNNEL; - if (args->is_ip6) - flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6; - if (args->udp_encap) - flags |= IPSEC_SA_FLAG_UDP_ENCAP; - if (args->esn) - flags |= IPSEC_SA_FLAG_USE_ESN; - if (args->anti_replay) - flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY; - - ipsec_mk_key (&crypto_key, - args->remote_crypto_key, args->remote_crypto_key_len); - ipsec_mk_key (&integ_key, - args->remote_integ_key, args->remote_integ_key_len); - - rv = ipsec_sa_add_and_lock (ipsec_tun_mk_input_sa_id (dev_instance), - args->remote_spi, - IPSEC_PROTOCOL_ESP, - args->crypto_alg, - &crypto_key, - args->integ_alg, - &integ_key, - (flags | IPSEC_SA_FLAG_IS_INBOUND), - args->tx_table_id, - args->salt, - &args->remote_ip, - &args->local_ip, &t->input_sa_index); - - if (rv) - return rv; - - ipsec_mk_key (&crypto_key, - args->local_crypto_key, args->local_crypto_key_len); - ipsec_mk_key (&integ_key, - args->local_integ_key, args->local_integ_key_len); - - rv = ipsec_sa_add_and_lock (ipsec_tun_mk_output_sa_id (dev_instance), - args->local_spi, - IPSEC_PROTOCOL_ESP, - args->crypto_alg, - &crypto_key, - args->integ_alg, - &integ_key, - flags, - args->tx_table_id, - args->salt, - &args->local_ip, - &args->remote_ip, &t->output_sa_index); - - if (rv) - return rv; - - /* copy the key */ - if (is_ip6) - hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6, - t - im->tunnel_interfaces); - else - hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64, - t - im->tunnel_interfaces); - - hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index, - t - im->tunnel_interfaces, - ipsec_hw_class.index, - t - im->tunnel_interfaces); - - hi = vnet_get_hw_interface (vnm, hw_if_index); - sw_if_index = hi->sw_if_index; - - t->hw_if_index = hw_if_index; - t->sw_if_index = hi->sw_if_index; - - /* Standard default jumbo MTU. */ - vnet_sw_interface_set_mtu (vnm, t->sw_if_index, 9000); - - /* Add the new tunnel to the DB of tunnels per sw_if_index ... */ - vec_validate_init_empty (im->ipsec_if_by_sw_if_index, t->sw_if_index, - ~0); - im->ipsec_if_by_sw_if_index[t->sw_if_index] = dev_instance; - - ipsec_tunnel_feature_set (im, t, 1); - - /*1st interface, register protocol */ - if (pool_elts (im->tunnel_interfaces) == 1) - { - ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP, - ipsec4_if_input_node.index); - ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP, - ipsec6_if_input_node.index); - } - - } - else - { - u32 ti; - - /* check if exists */ - if (!p) - return VNET_API_ERROR_INVALID_VALUE; - - ti = p[0]; - t = pool_elt_at_index (im->tunnel_interfaces, ti); - hi = vnet_get_hw_interface (vnm, t->hw_if_index); - sw_if_index = hi->sw_if_index; - - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */ - - ipsec_tunnel_feature_set (im, t, 0); - vnet_delete_hw_interface (vnm, t->hw_if_index); - - if (is_ip6) - hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6); - else - hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64); - hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance); - - im->ipsec_if_by_sw_if_index[t->sw_if_index] = ~0; - - /* delete input and output SA */ - ipsec_sa_unlock (t->input_sa_index); - ipsec_sa_unlock (t->output_sa_index); - - pool_put (im->tunnel_interfaces, t); - } - - if (sw_if_index_p) - *sw_if_index_p = sw_if_index; - - return 0; -} - -int -ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id, - u8 is_outbound) -{ - ipsec_main_t *im = &ipsec_main; - vnet_hw_interface_t *hi; - ipsec_tunnel_if_t *t; - ipsec_sa_t *sa, *old_sa; - u32 sa_index, old_sa_index; - uword *p; - - hi = vnet_get_hw_interface (vnm, hw_if_index); - t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance); - - sa_index = ipsec_sa_find_and_lock (sa_id); - - if (INDEX_INVALID == sa_index) - { - clib_warning ("SA with ID %u not found", sa_id); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - sa = pool_elt_at_index (im->sad, sa_index); - - if (!is_outbound) - { - old_sa_index = t->input_sa_index; - old_sa = pool_elt_at_index (im->sad, old_sa_index); - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^ - ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa)) - { - clib_warning ("IPsec interface SA endpoints type can't be changed"); - return VNET_API_ERROR_INVALID_VALUE; - } - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa)) - { - ipsec6_tunnel_key_t key; - - /* unset old inbound hash entry. packets should stop arriving */ - key.remote_ip = old_sa->tunnel_src_addr.ip6; - key.spi = clib_host_to_net_u32 (old_sa->spi); - - p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key); - if (p) - hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key); - - /* set new inbound SA, then set new hash entry */ - t->input_sa_index = sa_index; - key.remote_ip = sa->tunnel_src_addr.ip6; - key.spi = clib_host_to_net_u32 (sa->spi); - - hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key, - hi->dev_instance); - } - else - { - ipsec4_tunnel_key_t key; - - /* unset old inbound hash entry. packets should stop arriving */ - key.remote_ip.as_u32 = old_sa->tunnel_src_addr.ip4.as_u32; - key.spi = clib_host_to_net_u32 (old_sa->spi); - - p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64); - if (p) - hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64); - - /* set new inbound SA, then set new hash entry */ - t->input_sa_index = sa_index; - key.remote_ip.as_u32 = sa->tunnel_src_addr.ip4.as_u32; - key.spi = clib_host_to_net_u32 (sa->spi); - - hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64, - hi->dev_instance); - } - } - else - { - old_sa_index = t->output_sa_index; - old_sa = pool_elt_at_index (im->sad, old_sa_index); - - if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^ - ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa)) - { - clib_warning ("IPsec interface SA endpoints type can't be changed"); - return VNET_API_ERROR_INVALID_VALUE; - } - - /* - * re-enable the feature to get the new SA in - * the workers are stopped so no packets are sent in the clear - */ - ipsec_tunnel_feature_set (im, t, 0); - t->output_sa_index = sa_index; - ipsec_tunnel_feature_set (im, t, 1); - } - - /* remove sa_id to sa_index mapping on old SA */ - hash_unset (im->sa_index_by_sa_id, old_sa->id); - - if (ipsec_add_del_sa_sess_cb (im, old_sa_index, 0)) - { - clib_warning ("IPsec backend add/del callback returned error"); - return VNET_API_ERROR_SYSCALL_ERROR_1; - } - - ipsec_sa_unlock (old_sa_index); - - return 0; -} - -clib_error_t * -ipsec_tunnel_if_init (vlib_main_t * vm) -{ - ipsec_main_t *im = &ipsec_main; - - /* initialize the ipsec-if ip4 hash */ - im->ipsec4_if_pool_index_by_key = - hash_create (0, sizeof (ipsec4_tunnel_key_t)); - /* initialize the ipsec-if ip6 hash */ - im->ipsec6_if_pool_index_by_key = hash_create_mem (0, - sizeof - (ipsec6_tunnel_key_t), - sizeof (uword)); - im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword)); - - /* set up feature nodes to drop outbound packets with no crypto alg set */ - ipsec_add_feature ("ip4-output", "esp4-no-crypto", - &im->esp4_no_crypto_tun_feature_index); - ipsec_add_feature ("ip6-output", "esp6-no-crypto", - &im->esp6_no_crypto_tun_feature_index); - - udp_register_dst_port (vlib_get_main (), - UDP_DST_PORT_ipsec, ipsec4_if_input_node.index, 1); - return 0; -} - -VLIB_INIT_FUNCTION (ipsec_tunnel_if_init); - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */