X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fipsec%2Fipsec_if.c;h=e7536b2756e7c71f100f0d650286f81b85c3e286;hb=8e1039a8231cd1d817a24256c421b9fc512f45fa;hp=9359a3b772ed07cd4d792c0c35feb74e376bb68a;hpb=922549afb4480842904dcebf51548f307951e1c2;p=vpp.git diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 9359a3b772e..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; } @@ -120,6 +161,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, 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); @@ -133,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; @@ -157,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; @@ -168,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; @@ -186,33 +238,21 @@ 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); - } + 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, @@ -221,8 +261,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, } else { - vnet_interface_main_t *vim = &vnm->interface_main; - /* check if exists */ if (!p) return VNET_API_ERROR_INVALID_VALUE; @@ -230,33 +268,23 @@ 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); - vnet_interface_counter_lock (vim); - vlib_zero_combined_counter (vim->combined_sw_if_counters + - VNET_INTERFACE_COUNTER_TX, hi->sw_if_index); - vlib_zero_combined_counter (vim->combined_sw_if_counters + - VNET_INTERFACE_COUNTER_RX, hi->sw_if_index); - vnet_interface_counter_unlock (vim); + vnet_feature_enable_disable ("interface-output", "ipsec-if-output", + hi->sw_if_index, 0, 0, 0); - /* delete input and output SA */ - sa = pool_elt_at_index (im->sad, t->input_sa_index); + vnet_delete_hw_interface (vnm, t->hw_if_index); - 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; + /* 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); } @@ -340,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) { @@ -357,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) { @@ -368,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) { @@ -379,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; @@ -391,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; }