From 495d7ffbc82823edccabab960fc81a909f80075d Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 12 Jul 2019 09:15:26 +0000 Subject: ipsec: Reference count the SAs - this remove the need to iterate through all state when deleting an SA - and ensures that if the SA is deleted by the client is remains for use in any state until that state is also removed. Type: feature Change-Id: I438cb67588cb65c701e49a7a9518f88641925419 Signed-off-by: Neale Ranns --- src/vnet/ipsec/ipsec_sa.c | 148 ++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 83 deletions(-) (limited to 'src/vnet/ipsec/ipsec_sa.c') diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index afdecfee10d..e3eff586906 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -123,18 +123,18 @@ ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg) } int -ipsec_sa_add (u32 id, - u32 spi, - ipsec_protocol_t proto, - ipsec_crypto_alg_t crypto_alg, - const ipsec_key_t * ck, - ipsec_integ_alg_t integ_alg, - const ipsec_key_t * ik, - ipsec_sa_flags_t flags, - u32 tx_table_id, - u32 salt, - const ip46_address_t * tun_src, - const ip46_address_t * tun_dst, u32 * sa_out_index) +ipsec_sa_add_and_lock (u32 id, + u32 spi, + ipsec_protocol_t proto, + ipsec_crypto_alg_t crypto_alg, + const ipsec_key_t * ck, + ipsec_integ_alg_t integ_alg, + const ipsec_key_t * ik, + ipsec_sa_flags_t flags, + u32 tx_table_id, + u32 salt, + const ip46_address_t * tun_src, + const ip46_address_t * tun_dst, u32 * sa_out_index) { vlib_main_t *vm = vlib_get_main (); ipsec_main_t *im = &ipsec_main; @@ -150,6 +150,7 @@ ipsec_sa_add (u32 id, pool_get_aligned_zero (im->sad, sa, CLIB_CACHE_LINE_BYTES); fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA); + fib_node_lock (&sa->node); sa_index = sa - im->sad; vlib_validate_combined_counter (&ipsec_sa_counters, sa_index); @@ -272,33 +273,18 @@ ipsec_sa_add (u32 id, return (0); } -u32 -ipsec_sa_del (u32 id) +static void +ipsec_sa_del (ipsec_sa_t * sa) { vlib_main_t *vm = vlib_get_main (); ipsec_main_t *im = &ipsec_main; - ipsec_sa_t *sa = 0; - uword *p; u32 sa_index; - clib_error_t *err; - - p = hash_get (im->sa_index_by_sa_id, id); - - if (!p) - return VNET_API_ERROR_NO_SUCH_ENTRY; - sa_index = p[0]; - sa = pool_elt_at_index (im->sad, sa_index); - if (ipsec_is_sa_used (sa_index)) - { - clib_warning ("sa_id %u used in policy", sa->id); - /* sa used in policy */ - return VNET_API_ERROR_RSRC_IN_USE; - } + sa_index = sa - im->sad; hash_unset (im->sa_index_by_sa_id, sa->id); - err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0); - if (err) - return VNET_API_ERROR_SYSCALL_ERROR_2; + + /* no recovery possible when deleting an SA */ + (void) ipsec_call_add_del_callbacks (im, sa, sa_index, 0); if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa)) { @@ -311,65 +297,61 @@ ipsec_sa_del (u32 id) vnet_crypto_key_del (vm, sa->crypto_key_index); vnet_crypto_key_del (vm, sa->integ_key_index); pool_put (im->sad, sa); - return 0; } void -ipsec_sa_clear (index_t sai) +ipsec_sa_unlock (index_t sai) { - vlib_zero_combined_counter (&ipsec_sa_counters, sai); + ipsec_main_t *im = &ipsec_main; + ipsec_sa_t *sa; + + if (INDEX_INVALID == sai) + return; + + sa = pool_elt_at_index (im->sad, sai); + + fib_node_unlock (&sa->node); } -u8 -ipsec_is_sa_used (u32 sa_index) +index_t +ipsec_sa_find_and_lock (u32 id) { ipsec_main_t *im = &ipsec_main; - ipsec_tun_protect_t *itp; - ipsec_tunnel_if_t *t; - ipsec_policy_t *p; - u32 sai; + ipsec_sa_t *sa; + uword *p; - /* *INDENT-OFF* */ - pool_foreach(p, im->policies, ({ - if (p->policy == IPSEC_POLICY_ACTION_PROTECT) - { - if (p->sa_index == sa_index) - return 1; - } - })); + p = hash_get (im->sa_index_by_sa_id, id); - pool_foreach(t, im->tunnel_interfaces, ({ - if (t->input_sa_index == sa_index) - return 1; - if (t->output_sa_index == sa_index) - return 1; - })); + if (!p) + return INDEX_INVALID; - /* *INDENT-OFF* */ - pool_foreach(itp, ipsec_protect_pool, ({ - FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai, - ({ - if (sai == sa_index) - return 1; - })); - if (itp->itp_out_sa == sa_index) - return 1; - })); - /* *INDENT-ON* */ + sa = pool_elt_at_index (im->sad, p[0]); + fib_node_lock (&sa->node); - return 0; + return (p[0]); } -u32 -ipsec_get_sa_index_by_sa_id (u32 sa_id) +int +ipsec_sa_unlock_id (u32 id) { ipsec_main_t *im = &ipsec_main; - uword *p = hash_get (im->sa_index_by_sa_id, sa_id); + uword *p; + + p = hash_get (im->sa_index_by_sa_id, id); + if (!p) - return ~0; + return VNET_API_ERROR_NO_SUCH_ENTRY; + + ipsec_sa_unlock (p[0]); + + return (0); +} - return p[0]; +void +ipsec_sa_clear (index_t sai) +{ + vlib_zero_combined_counter (&ipsec_sa_counters, sai); } void @@ -402,6 +384,15 @@ ipsec_sa_fib_node_get (fib_node_index_t index) return (&sa->node); } +static ipsec_sa_t * +ipsec_sa_from_fib_node (fib_node_t * node) +{ + ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type); + return ((ipsec_sa_t *) (((char *) node) - + STRUCT_OFFSET_OF (ipsec_sa_t, node))); + +} + /** * Function definition to inform the FIB node that its last lock has gone. */ @@ -412,16 +403,7 @@ ipsec_sa_last_lock_gone (fib_node_t * node) * The ipsec SA is a root of the graph. As such * it never has children and thus is never locked. */ - ASSERT (0); -} - -static ipsec_sa_t * -ipsec_sa_from_fib_node (fib_node_t * node) -{ - ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type); - return ((ipsec_sa_t *) (((char *) node) - - STRUCT_OFFSET_OF (ipsec_sa_t, node))); - + ipsec_sa_del (ipsec_sa_from_fib_node (node)); } /** -- cgit 1.2.3-korg