X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fipsec%2Fipsec_if.c;h=e7536b2756e7c71f100f0d650286f81b85c3e286;hb=8e1039a8231cd1d817a24256c421b9fc512f45fa;hp=dc882004ceaef8868ae38fc03d28bf46c228c0f0;hpb=3f903397be011223e91ce5a7b9cd5f6be5a0167b;p=vpp.git diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index dc882004cea..e7536b2756e 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -28,7 +28,10 @@ static u8 * format_ipsec_name (u8 * s, va_list * args) { u32 dev_instance = va_arg (*args, u32); - return format (s, "ipsec%d", dev_instance); + ipsec_main_t *im = &ipsec_main; + ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance; + + return format (s, "ipsec%d", t->show_instance); } static uword @@ -49,25 +52,63 @@ ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags) ipsec_sa_t *sa; hi = vnet_get_hw_interface (vnm, hw_if_index); + t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance); + if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) { - t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance); ASSERT (im->cb.check_support_cb); + sa = pool_elt_at_index (im->sad, t->input_sa_index); + err = im->cb.check_support_cb (sa); if (err) return err; + if (im->cb.add_del_sa_sess_cb) + { + err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 1); + if (err) + return err; + } + sa = pool_elt_at_index (im->sad, t->output_sa_index); + err = im->cb.check_support_cb (sa); if (err) return err; + if (im->cb.add_del_sa_sess_cb) + { + err = im->cb.add_del_sa_sess_cb (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 */ ); + { + vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ ); + + sa = pool_elt_at_index (im->sad, t->input_sa_index); + + if (im->cb.add_del_sa_sess_cb) + { + err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 0); + if (err) + return err; + } + + sa = pool_elt_at_index (im->sad, t->output_sa_index); + + if (im->cb.add_del_sa_sess_cb) + { + err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 0); + if (err) + return err; + } + } return /* no error */ 0; } @@ -88,20 +129,17 @@ VNET_HW_INTERFACE_CLASS (ipsec_hw_class) = { .name = "IPSec", .build_rewrite = default_build_rewrite, + .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, }; /* *INDENT-ON* */ -static int -ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, - ipsec_add_del_tunnel_args_t * args); - static int ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a) { vnet_main_t *vnm = vnet_get_main (); - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); - return ipsec_add_del_tunnel_if_internal (vnm, a); + return ipsec_add_del_tunnel_if_internal (vnm, a, NULL); } int @@ -114,14 +152,16 @@ ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args) int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, - ipsec_add_del_tunnel_args_t * args) + ipsec_add_del_tunnel_args_t * args, + u32 * sw_if_index) { ipsec_tunnel_if_t *t; ipsec_main_t *im = &ipsec_main; - vnet_hw_interface_t *hi; + vnet_hw_interface_t *hi = NULL; u32 hw_if_index = ~0; uword *p; ipsec_sa_t *sa; + u32 dev_instance; u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi; p = hash_get (im->ipsec_if_pool_index_by_key, key); @@ -135,6 +175,21 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES); memset (t, 0, sizeof (*t)); + 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); + pool_get (im->sad, sa); memset (sa, 0, sizeof (*sa)); t->input_sa_index = sa - im->sad; @@ -159,10 +214,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, args->remote_crypto_key_len); } - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->input_sa_index, args->is_add) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; - pool_get (im->sad, sa); memset (sa, 0, sizeof (*sa)); t->output_sa_index = sa - im->sad; @@ -170,7 +221,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32; sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32; sa->is_tunnel = 1; - sa->seq = 1; sa->use_esn = args->esn; sa->use_anti_replay = args->anti_replay; sa->integ_alg = args->integ_alg; @@ -188,39 +238,26 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, args->local_crypto_key_len); } - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->output_sa_index, args->is_add) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; - hash_set (im->ipsec_if_pool_index_by_key, key, t - im->tunnel_interfaces); - if (vec_len (im->free_tunnel_if_indices) > 0) - { - hw_if_index = - im->free_tunnel_if_indices[vec_len (im->free_tunnel_if_indices) - - 1]; - _vec_len (im->free_tunnel_if_indices) -= 1; - } - else - { - 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); - hi->output_node_index = ipsec_if_output_node.index; - } + 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); + hi->output_node_index = ipsec_if_output_node.index; t->hw_if_index = hw_if_index; + vnet_feature_enable_disable ("interface-output", "ipsec-if-output", + hi->sw_if_index, 1, 0, 0); + /*1st interface, register protocol */ if (pool_elts (im->tunnel_interfaces) == 1) ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP, ipsec_if_input_node.index); - return hw_if_index; } else { @@ -231,28 +268,29 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, t = pool_elt_at_index (im->tunnel_interfaces, p[0]); hi = vnet_get_hw_interface (vnm, t->hw_if_index); vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */ - vec_add1 (im->free_tunnel_if_indices, t->hw_if_index); - /* delete input and output SA */ - sa = pool_elt_at_index (im->sad, t->input_sa_index); + vnet_feature_enable_disable ("interface-output", "ipsec-if-output", + hi->sw_if_index, 0, 0, 0); - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->input_sa_index, args->is_add) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; + vnet_delete_hw_interface (vnm, t->hw_if_index); + /* delete input and output SA */ + + sa = pool_elt_at_index (im->sad, t->input_sa_index); pool_put (im->sad, sa); sa = pool_elt_at_index (im->sad, t->output_sa_index); - - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->output_sa_index, args->is_add) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; - pool_put (im->sad, sa); hash_unset (im->ipsec_if_pool_index_by_key, key); + hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance); + pool_put (im->tunnel_interfaces, t); } + + if (sw_if_index) + *sw_if_index = hi->sw_if_index; + return 0; } @@ -330,16 +368,15 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, hi = vnet_get_hw_interface (vnm, hw_if_index); t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance); + if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) + return VNET_API_ERROR_SYSCALL_ERROR_1; + if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO) { sa = pool_elt_at_index (im->sad, t->output_sa_index); sa->crypto_alg = alg; sa->crypto_key_len = vec_len (key); clib_memcpy (sa->crypto_key, key, vec_len (key)); - - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->output_sa_index, 0) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; } else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG) { @@ -347,10 +384,6 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, sa->integ_alg = alg; sa->integ_key_len = vec_len (key); clib_memcpy (sa->integ_key, key, vec_len (key)); - - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->output_sa_index, 0) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; } else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO) { @@ -358,10 +391,6 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, sa->crypto_alg = alg; sa->crypto_key_len = vec_len (key); clib_memcpy (sa->crypto_key, key, vec_len (key)); - - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->input_sa_index, 0) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; } else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG) { @@ -369,10 +398,6 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, sa->integ_alg = alg; sa->integ_key_len = vec_len (key); clib_memcpy (sa->integ_key, key, vec_len (key)); - - if (im->cb.add_del_sa_sess_cb && - im->cb.add_del_sa_sess_cb (t->input_sa_index, 0) < 0) - return VNET_API_ERROR_SYSCALL_ERROR_1; } else return VNET_API_ERROR_INVALID_VALUE; @@ -381,12 +406,92 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, } +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_get_sa_index_by_sa_id (sa_id); + if (sa_index == ~0) + { + clib_warning ("SA with ID %u not found", sa_id); + return VNET_API_ERROR_INVALID_VALUE; + } + + if (ipsec_is_sa_used (sa_index)) + { + clib_warning ("SA with ID %u is already in use", sa_id); + return VNET_API_ERROR_INVALID_VALUE; + } + + sa = pool_elt_at_index (im->sad, sa_index); + if (sa->is_tunnel_ip6) + { + clib_warning ("IPsec interface not supported with IPv6 endpoints"); + return VNET_API_ERROR_UNIMPLEMENTED; + } + + if (!is_outbound) + { + u64 key; + + old_sa_index = t->input_sa_index; + old_sa = pool_elt_at_index (im->sad, old_sa_index); + + /* unset old inbound hash entry. packets should stop arriving */ + key = + (u64) old_sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) old_sa->spi; + p = hash_get (im->ipsec_if_pool_index_by_key, key); + if (p) + hash_unset (im->ipsec_if_pool_index_by_key, key); + + /* set new inbound SA, then set new hash entry */ + t->input_sa_index = sa_index; + key = (u64) sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) sa->spi; + hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance); + } + else + { + old_sa_index = t->output_sa_index; + old_sa = pool_elt_at_index (im->sad, old_sa_index); + t->output_sa_index = sa_index; + } + + /* remove sa_id to sa_index mapping on old SA */ + if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index) + hash_unset (im->sa_index_by_sa_id, old_sa->id); + + if (im->cb.add_del_sa_sess_cb) + { + clib_error_t *err; + + err = im->cb.add_del_sa_sess_cb (old_sa_index, 0); + if (err) + return VNET_API_ERROR_SYSCALL_ERROR_1; + } + + pool_put (im->sad, old_sa); + + return 0; +} + + clib_error_t * ipsec_tunnel_if_init (vlib_main_t * vm) { ipsec_main_t *im = &ipsec_main; im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword)); + im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword)); return 0; }