From 993b6bee63d4f455db0a6021c9659aad4545acf2 Mon Sep 17 00:00:00 2001 From: Piotr Bronowski Date: Wed, 31 Aug 2022 13:48:14 +0000 Subject: ipsec: introduce fast path ipv4 inbound matching This patch introduces fast path matching for inbound traffic ipv4. Fast path uses bihash tables in order to find matching policy. Adding and removing policies in fast path is much faster than in current implementation. It is still new feature and further work needs and can be done in order to improve perfromance. Type: feature Signed-off-by: Piotr Bronowski Change-Id: Ifbd5bfecc21b76ddf8363f5dc089d77595196675 --- src/vnet/ipsec/ipsec.c | 51 +++++-- src/vnet/ipsec/ipsec.h | 17 ++- src/vnet/ipsec/ipsec_input.c | 54 ++++++- src/vnet/ipsec/ipsec_output.h | 9 +- src/vnet/ipsec/ipsec_spd.c | 151 +++++++++++++++++--- src/vnet/ipsec/ipsec_spd.h | 28 ++-- src/vnet/ipsec/ipsec_spd_fp_lookup.h | 198 +++++++++++++++++++++++--- src/vnet/ipsec/ipsec_spd_policy.c | 269 ++++++++++++++++++++++++----------- src/vnet/ipsec/ipsec_spd_policy.h | 15 +- 9 files changed, 628 insertions(+), 164 deletions(-) (limited to 'src/vnet') diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 2dd077a74a1..e95bd163049 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -495,11 +495,6 @@ ipsec_init (vlib_main_t * vm) if ((error = vlib_call_init_function (vm, ipsec_cli_init))) return error; - im->ipv4_fp_spd_is_enabled = 0; - im->ipv6_fp_spd_is_enabled = 0; - - im->fp_lookup_hash_buckets = IPSEC_FP_HASH_LOOKUP_HASH_BUCKETS; - vec_validate (im->crypto_algs, IPSEC_CRYPTO_N_ALG - 1); a = im->crypto_algs + IPSEC_CRYPTO_ALG_NONE; @@ -638,6 +633,13 @@ ipsec_init (vlib_main_t * vm) vec_validate_init_empty_aligned (im->next_header_registrations, 255, ~0, CLIB_CACHE_LINE_BYTES); + im->fp_spd_ipv4_out_is_enabled = 0; + im->fp_spd_ipv6_out_is_enabled = 0; + im->fp_spd_ipv4_in_is_enabled = 0; + im->fp_spd_ipv6_in_is_enabled = 0; + + im->fp_lookup_hash_buckets = IPSEC_FP_HASH_LOOKUP_HASH_BUCKETS; + return 0; } @@ -652,22 +654,41 @@ ipsec_config (vlib_main_t *vm, unformat_input_t *input) u32 ipsec4_out_spd_hash_num_buckets; u32 ipsec4_in_spd_hash_num_buckets; u32 ipsec_spd_fp_num_buckets; + bool fp_spd_ip4_enabled = false; + bool fp_spd_ip6_enabled = false; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "ipv6-outbound-spd-fast-path on")) { - im->ipv6_fp_spd_is_enabled = 1; + im->fp_spd_ipv6_out_is_enabled = 1; + fp_spd_ip6_enabled = true; } else if (unformat (input, "ipv6-outbound-spd-fast-path off")) - im->ipv6_fp_spd_is_enabled = 0; + im->fp_spd_ipv6_out_is_enabled = 0; else if (unformat (input, "ipv4-outbound-spd-fast-path on")) { - im->ipv4_fp_spd_is_enabled = 1; + im->fp_spd_ipv4_out_is_enabled = 1; im->output_flow_cache_flag = 0; + fp_spd_ip4_enabled = true; } else if (unformat (input, "ipv4-outbound-spd-fast-path off")) - im->ipv4_fp_spd_is_enabled = 0; + im->fp_spd_ipv4_out_is_enabled = 0; + else if (unformat (input, "ipv6-inbound-spd-fast-path on")) + { + im->fp_spd_ipv6_in_is_enabled = 1; + fp_spd_ip6_enabled = true; + } + else if (unformat (input, "ipv6-inbound-spd-fast-path off")) + im->fp_spd_ipv6_in_is_enabled = 0; + else if (unformat (input, "ipv4-inbound-spd-fast-path on")) + { + im->fp_spd_ipv4_in_is_enabled = 1; + im->input_flow_cache_flag = 0; + fp_spd_ip4_enabled = true; + } + else if (unformat (input, "ipv4-inbound-spd-fast-path off")) + im->fp_spd_ipv4_in_is_enabled = 0; else if (unformat (input, "spd-fast-path-num-buckets %d", &ipsec_spd_fp_num_buckets)) { @@ -676,7 +697,7 @@ ipsec_config (vlib_main_t *vm, unformat_input_t *input) << max_log2 (ipsec_spd_fp_num_buckets); } else if (unformat (input, "ipv4-outbound-spd-flow-cache on")) - im->output_flow_cache_flag = im->ipv4_fp_spd_is_enabled ? 0 : 1; + im->output_flow_cache_flag = im->fp_spd_ipv4_out_is_enabled ? 0 : 1; else if (unformat (input, "ipv4-outbound-spd-flow-cache off")) im->output_flow_cache_flag = 0; else if (unformat (input, "ipv4-outbound-spd-hash-buckets %d", @@ -687,7 +708,7 @@ ipsec_config (vlib_main_t *vm, unformat_input_t *input) 1ULL << max_log2 (ipsec4_out_spd_hash_num_buckets); } else if (unformat (input, "ipv4-inbound-spd-flow-cache on")) - im->input_flow_cache_flag = 1; + im->input_flow_cache_flag = im->fp_spd_ipv4_in_is_enabled ? 0 : 1; else if (unformat (input, "ipv4-inbound-spd-flow-cache off")) im->input_flow_cache_flag = 0; else if (unformat (input, "ipv4-inbound-spd-hash-buckets %d", @@ -745,6 +766,14 @@ ipsec_config (vlib_main_t *vm, unformat_input_t *input) im->ipsec4_in_spd_hash_num_buckets); } + if (fp_spd_ip4_enabled) + pool_alloc_aligned (im->fp_ip4_lookup_hashes_pool, + IPSEC_FP_IP4_HASHES_POOL_SIZE, CLIB_CACHE_LINE_BYTES); + + if (fp_spd_ip6_enabled) + pool_alloc_aligned (im->fp_ip6_lookup_hashes_pool, + IPSEC_FP_IP6_HASHES_POOL_SIZE, CLIB_CACHE_LINE_BYTES); + return 0; } diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 06bb299988b..69aa661683a 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -30,6 +30,9 @@ #include +#define IPSEC_FP_IP4_HASHES_POOL_SIZE 128 +#define IPSEC_FP_IP6_HASHES_POOL_SIZE 128 + typedef clib_error_t *(*add_del_sa_sess_cb_t) (u32 sa_index, u8 is_add); typedef clib_error_t *(*check_support_cb_t) (ipsec_sa_t * sa); typedef clib_error_t *(*enable_disable_cb_t) (int is_enable); @@ -143,10 +146,16 @@ typedef struct ipsec_spd_t *spds; /* pool of policies */ ipsec_policy_t *policies; - - u32 ipv4_fp_spd_is_enabled; - u32 ipv6_fp_spd_is_enabled; - + /* pool of bihash tables for ipv4 ipsec rules */ + clib_bihash_16_8_t *fp_ip4_lookup_hashes_pool; + /* pool of bihash tables for ipv6 ipsec rules */ + clib_bihash_40_8_t *fp_ip6_lookup_hashes_pool; + + u32 fp_spd_ipv4_out_is_enabled; + u32 fp_spd_ipv4_in_is_enabled; + u32 fp_spd_ipv6_out_is_enabled; + u32 fp_spd_ipv6_in_is_enabled; + /* pool of fast path mask types */ ipsec_fp_mask_type_entry_t *fp_mask_types; u32 fp_lookup_hash_buckets; /* number of buckets should be power of two */ diff --git a/src/vnet/ipsec/ipsec_input.c b/src/vnet/ipsec/ipsec_input.c index 09166bccf5b..0c572c83e96 100644 --- a/src/vnet/ipsec/ipsec_input.c +++ b/src/vnet/ipsec/ipsec_input.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -149,6 +150,18 @@ ipsec4_input_spd_find_flow_cache_entry (ipsec_main_t *im, u32 sa, u32 da, return p; } +always_inline void +ipsec_fp_in_5tuple_from_ip4_range (ipsec_fp_5tuple_t *tuple, u32 la, u32 ra, + u32 spi, u8 action) +{ + clib_memset (tuple->l3_zero_pad, 0, sizeof (tuple->l3_zero_pad)); + tuple->laddr.as_u32 = la; + tuple->raddr.as_u32 = ra; + tuple->spi = spi; + tuple->action = action; + tuple->is_ipv6 = 0; +} + always_inline ipsec_policy_t * ipsec_input_policy_match (ipsec_spd_t *spd, u32 sa, u32 da, ipsec_spd_policy_type_t policy_type) @@ -317,6 +330,9 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm, ipsec_policy_t *p0 = NULL; u8 has_space0; bool search_flow_cache = false; + ipsec_policy_t *policies[1]; + ipsec_fp_5tuple_t tuples[1]; + bool ip_v6 = true; if (n_left_from > 2) { @@ -351,7 +367,19 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm, search_flow_cache = im->input_flow_cache_flag; esp_or_udp: - if (search_flow_cache) // attempt to match policy in flow cache + if (im->fp_spd_ipv4_in_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd0->fp_spd.ip4_in_lookup_hash_idx)) + { + ipsec_fp_in_5tuple_from_ip4_range ( + &tuples[0], ip0->src_address.as_u32, ip0->dst_address.as_u32, + clib_net_to_host_u32 (esp0->spi), + IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT); + ipsec_fp_in_policy_match_n (&spd0->fp_spd, !ip_v6, tuples, + policies, 1); + p0 = policies[0]; + } + else if (search_flow_cache) // attempt to match policy in flow cache { p0 = ipsec4_input_spd_find_flow_cache_entry ( im, ip0->src_address.as_u32, ip0->dst_address.as_u32, @@ -392,7 +420,16 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm, pi0 = ~0; }; - if (search_flow_cache) + if (im->fp_spd_ipv4_in_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd0->fp_spd.ip4_in_lookup_hash_idx)) + { + tuples->action = IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS; + ipsec_fp_in_policy_match_n (&spd0->fp_spd, !ip_v6, tuples, + policies, 1); + p0 = policies[0]; + } + else if (search_flow_cache) { p0 = ipsec4_input_spd_find_flow_cache_entry ( im, ip0->src_address.as_u32, ip0->dst_address.as_u32, @@ -424,7 +461,18 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm, pi0 = ~0; }; - if (search_flow_cache) + if (im->fp_spd_ipv4_in_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd0->fp_spd.ip4_in_lookup_hash_idx)) + { + tuples->action = IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD; + ipsec_fp_in_policy_match_n (&spd0->fp_spd, !ip_v6, tuples, + policies, 1); + p0 = policies[0]; + } + else + + if (search_flow_cache) { p0 = ipsec4_input_spd_find_flow_cache_entry ( im, ip0->src_address.as_u32, ip0->dst_address.as_u32, diff --git a/src/vnet/ipsec/ipsec_output.h b/src/vnet/ipsec/ipsec_output.h index 1239ed1f192..30f4ebedeb7 100644 --- a/src/vnet/ipsec/ipsec_output.h +++ b/src/vnet/ipsec/ipsec_output.h @@ -179,7 +179,8 @@ ipsec_output_policy_match_n (ipsec_spd_t *spd, clib_memset (policies, 0, n * sizeof (ipsec_policy_t *)); - if (im->ipv4_fp_spd_is_enabled) + if (im->fp_spd_ipv4_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_out_lookup_hash_idx)) { ipsec_fp_5tuple_from_ip4_range_n (tuples, ip4_5tuples, n); counter += ipsec_fp_out_policy_match_n (&spd->fp_spd, 0, tuples, @@ -330,7 +331,8 @@ ipsec_output_policy_match (ipsec_spd_t *spd, u8 pr, u32 la, u32 ra, u16 lp, if (!spd) return 0; - if (im->ipv4_fp_spd_is_enabled) + if (im->fp_spd_ipv4_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_out_lookup_hash_idx)) { ipsec_fp_5tuple_from_ip4_range (&tuples[0], la, ra, lp, rp, pr); ipsec_fp_out_policy_match_n (&spd->fp_spd, 0, tuples, policies, @@ -437,7 +439,8 @@ ipsec6_output_policy_match (ipsec_spd_t *spd, ip6_address_t *la, if (!spd) return 0; - if (im->ipv6_fp_spd_is_enabled) + if (im->fp_spd_ipv6_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_out_lookup_hash_idx)) { ipsec_fp_5tuple_from_ip6_range (&tuples[0], la, ra, lp, rp, pr); diff --git a/src/vnet/ipsec/ipsec_spd.c b/src/vnet/ipsec/ipsec_spd.c index 22dddfd3fa8..aa42f99bee2 100644 --- a/src/vnet/ipsec/ipsec_spd.c +++ b/src/vnet/ipsec/ipsec_spd.c @@ -21,6 +21,7 @@ ipsec_add_del_spd (vlib_main_t * vm, u32 spd_id, int is_add) { ipsec_main_t *im = &ipsec_main; ipsec_spd_t *spd = 0; + ipsec_spd_fp_t *fp_spd = 0; uword *p; u32 spd_index, k, v; @@ -36,6 +37,7 @@ ipsec_add_del_spd (vlib_main_t * vm, u32 spd_id, int is_add) spd = pool_elt_at_index (im->spds, spd_index); if (!spd) return VNET_API_ERROR_INVALID_VALUE; + /* *INDENT-OFF* */ hash_foreach (k, v, im->spd_index_by_sw_if_index, ({ if (v == spd_index) @@ -46,18 +48,64 @@ ipsec_add_del_spd (vlib_main_t * vm, u32 spd_id, int is_add) #define _(s,v) vec_free(spd->policies[IPSEC_SPD_POLICY_##s]); foreach_ipsec_spd_policy_type #undef _ - if (im->ipv4_fp_spd_is_enabled) - { - ipsec_spd_fp_t *fp_spd = &spd->fp_spd; - clib_bihash_free_16_8 (&fp_spd->fp_ip4_lookup_hash); - } + fp_spd = &spd->fp_spd; + + if (im->fp_spd_ipv4_out_is_enabled) + { + if (fp_spd->ip4_out_lookup_hash_idx != INDEX_INVALID) + { + clib_bihash_16_8_t *bihash_table = + pool_elt_at_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_out_lookup_hash_idx); + + clib_bihash_free_16_8 (bihash_table); + vec_free (fp_spd->name4_out); + pool_put_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_out_lookup_hash_idx); + } + } + + if (im->fp_spd_ipv4_in_is_enabled) + { + if (fp_spd->ip4_in_lookup_hash_idx != INDEX_INVALID) + { + clib_bihash_16_8_t *bihash_table = pool_elt_at_index ( + im->fp_ip4_lookup_hashes_pool, fp_spd->ip4_in_lookup_hash_idx); + + clib_bihash_free_16_8 (bihash_table); + vec_free (fp_spd->name4_in); + pool_put_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_in_lookup_hash_idx); + } + } + + if (im->fp_spd_ipv6_out_is_enabled) + { + if (fp_spd->ip6_out_lookup_hash_idx != INDEX_INVALID) + { + clib_bihash_40_8_t *bihash_table = + pool_elt_at_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_out_lookup_hash_idx); - if (im->ipv6_fp_spd_is_enabled) + clib_bihash_free_40_8 (bihash_table); + vec_free (fp_spd->name6_out); + pool_put_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_out_lookup_hash_idx); + } + } + if (im->fp_spd_ipv6_in_is_enabled) { - ipsec_spd_fp_t *fp_spd = &spd->fp_spd; + if (fp_spd->ip6_in_lookup_hash_idx != INDEX_INVALID) + { + clib_bihash_40_8_t *bihash_table = pool_elt_at_index ( + im->fp_ip6_lookup_hashes_pool, fp_spd->ip6_in_lookup_hash_idx); - clib_bihash_free_40_8 (&fp_spd->fp_ip6_lookup_hash); + clib_bihash_free_40_8 (bihash_table); + vec_free (fp_spd->name6_in); + pool_put_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_in_lookup_hash_idx); + } } pool_put (im->spds, spd); @@ -69,24 +117,85 @@ ipsec_add_del_spd (vlib_main_t * vm, u32 spd_id, int is_add) spd_index = spd - im->spds; spd->id = spd_id; hash_set (im->spd_index_by_spd_id, spd_id, spd_index); - if (im->ipv4_fp_spd_is_enabled) + + fp_spd = &spd->fp_spd; + fp_spd->ip4_out_lookup_hash_idx = INDEX_INVALID; + fp_spd->ip4_in_lookup_hash_idx = INDEX_INVALID; + fp_spd->ip6_out_lookup_hash_idx = INDEX_INVALID; + fp_spd->ip6_in_lookup_hash_idx = INDEX_INVALID; + + if (im->fp_spd_ipv4_out_is_enabled) { - ipsec_spd_fp_t *fp_spd = &spd->fp_spd; + if (pool_elts (im->fp_ip4_lookup_hashes_pool) < + pool_max_len (im->fp_ip4_lookup_hashes_pool)) + { + clib_bihash_16_8_t *bihash_table; + fp_spd->name4_out = format (0, "spd_%u_fp_ip4_out", spd_id); + + pool_get (im->fp_ip4_lookup_hashes_pool, bihash_table); + fp_spd->ip4_out_lookup_hash_idx = + bihash_table - im->fp_ip4_lookup_hashes_pool; + clib_bihash_init_16_8 (bihash_table, (char *) fp_spd->name4_out, + im->fp_lookup_hash_buckets, + im->fp_lookup_hash_buckets * + IPSEC_FP_IP4_HASH_MEM_PER_BUCKET); + } + } + + if (im->fp_spd_ipv4_in_is_enabled) + { + if (pool_elts (im->fp_ip4_lookup_hashes_pool) < + pool_max_len (im->fp_ip4_lookup_hashes_pool)) + { + clib_bihash_16_8_t *bihash_table; + fp_spd->name4_in = format (0, "spd_%u_fp_ip4_in", spd_id); + + pool_get (im->fp_ip4_lookup_hashes_pool, bihash_table); + fp_spd->ip4_in_lookup_hash_idx = + bihash_table - im->fp_ip4_lookup_hashes_pool; + clib_bihash_init_16_8 (bihash_table, (char *) fp_spd->name4_in, + im->fp_lookup_hash_buckets, + im->fp_lookup_hash_buckets * + IPSEC_FP_IP4_HASH_MEM_PER_BUCKET); + } + } + if (im->fp_spd_ipv6_out_is_enabled) + { + if (pool_elts (im->fp_ip6_lookup_hashes_pool) < + pool_max_len (im->fp_ip6_lookup_hashes_pool)) + { + clib_bihash_40_8_t *bihash_table; + ipsec_spd_fp_t *fp_spd = &spd->fp_spd; + + fp_spd->name6_out = format (0, "spd_%u_fp_ip6_out", spd_id); - clib_bihash_init_16_8 ( - &fp_spd->fp_ip4_lookup_hash, "SPD_FP ip4 rules lookup bihash", - im->fp_lookup_hash_buckets, - im->fp_lookup_hash_buckets * IPSEC_FP_IP4_HASH_MEM_PER_BUCKET); + fp_spd->name6_out = format (0, "spd_%u_fp_ip6_out", spd_id); + pool_get (im->fp_ip6_lookup_hashes_pool, bihash_table); + fp_spd->ip6_out_lookup_hash_idx = + bihash_table - im->fp_ip6_lookup_hashes_pool; + clib_bihash_init_40_8 (bihash_table, (char *) fp_spd->name6_out, + im->fp_lookup_hash_buckets, + im->fp_lookup_hash_buckets * + IPSEC_FP_IP6_HASH_MEM_PER_BUCKET); + } } - if (im->ipv6_fp_spd_is_enabled) + if (im->fp_spd_ipv6_in_is_enabled) { - ipsec_spd_fp_t *fp_spd = &spd->fp_spd; + if (pool_elts (im->fp_ip6_lookup_hashes_pool) < + pool_max_len (im->fp_ip6_lookup_hashes_pool)) + { + clib_bihash_40_8_t *bihash_table; + ipsec_spd_fp_t *fp_spd = &spd->fp_spd; - clib_bihash_init_40_8 ( - &fp_spd->fp_ip6_lookup_hash, "SPD_FP ip6 rules lookup bihash", - im->fp_lookup_hash_buckets, - im->fp_lookup_hash_buckets * IPSEC_FP_IP6_HASH_MEM_PER_BUCKET); - fp_spd->fp_ip6_lookup_hash_initialized = 1; + fp_spd->name6_in = format (0, "spd_%u_fp_ip6_in", spd_id); + pool_get (im->fp_ip6_lookup_hashes_pool, bihash_table); + fp_spd->ip6_out_lookup_hash_idx = + bihash_table - im->fp_ip6_lookup_hashes_pool; + clib_bihash_init_40_8 (bihash_table, (char *) fp_spd->name6_in, + im->fp_lookup_hash_buckets, + im->fp_lookup_hash_buckets * + IPSEC_FP_IP6_HASH_MEM_PER_BUCKET); + } } } return 0; diff --git a/src/vnet/ipsec/ipsec_spd.h b/src/vnet/ipsec/ipsec_spd.h index 887ae99c101..3a4fd0ec91c 100644 --- a/src/vnet/ipsec/ipsec_spd.h +++ b/src/vnet/ipsec/ipsec_spd.h @@ -42,20 +42,31 @@ typedef enum ipsec_spd_policy_t_ extern u8 *format_ipsec_policy_type (u8 * s, va_list * args); +typedef struct +{ + /* index in the mask types pool */ + u32 mask_type_idx; + /* counts references correspond to given mask type index */ + u32 refcount; +} ipsec_fp_mask_id_t; + /** * @brief A fast path Security Policy Database */ typedef struct { - /** vectors for each of the policy types */ + /** vectors for each of the fast path policy types */ u32 *fp_policies[IPSEC_SPD_POLICY_N_TYPES]; - u32 *fp_mask_types[IPSEC_SPD_POLICY_N_TYPES]; - - clib_bihash_40_8_t fp_ip6_lookup_hash; /* spd fp ip6 lookup hash table. */ - clib_bihash_16_8_t fp_ip4_lookup_hash; /* spd fp ip4 lookup hash table. */ - - u8 fp_ip6_lookup_hash_initialized; - + ipsec_fp_mask_id_t *fp_mask_ids[IPSEC_SPD_POLICY_N_TYPES]; + /* names of bihash tables */ + u8 *name4_out; + u8 *name4_in; + u8 *name6_out; + u8 *name6_in; + u32 ip6_out_lookup_hash_idx; /* fp ip6 lookup hash out index in the pool */ + u32 ip4_out_lookup_hash_idx; /* fp ip4 lookup hash out index in the pool */ + u32 ip6_in_lookup_hash_idx; /* fp ip6 lookup hash in index in the pool */ + u32 ip4_in_lookup_hash_idx; /* fp ip4 lookup hash in index in the pool */ } ipsec_spd_fp_t; /** @@ -67,7 +78,6 @@ typedef struct u32 id; /** vectors for each of the policy types */ u32 *policies[IPSEC_SPD_POLICY_N_TYPES]; - /* TODO remove fp_spd. Use directly ipsec_spd_t for fast path */ ipsec_spd_fp_t fp_spd; } ipsec_spd_t; diff --git a/src/vnet/ipsec/ipsec_spd_fp_lookup.h b/src/vnet/ipsec/ipsec_spd_fp_lookup.h index 3aea86f70a0..e4ef194d68d 100644 --- a/src/vnet/ipsec/ipsec_spd_fp_lookup.h +++ b/src/vnet/ipsec/ipsec_spd_fp_lookup.h @@ -20,18 +20,6 @@ #include -/** - * @brief function handler to perform lookup in fastpath SPD - * for inbound traffic burst of n packets - **/ - -inline u32 -ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6, - ipsec_fp_5tuple_t *tuples, - ipsec_policy_t **policies, u32 *policy_ids, u32 n) -{ - return 0; -} static_always_inline int single_rule_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match) @@ -106,6 +94,164 @@ single_rule_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match) return (1); } +static_always_inline int +single_rule_in_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match) +{ + + u32 sa = clib_net_to_host_u32 (match->laddr.as_u32); + u32 da = clib_net_to_host_u32 (match->raddr.as_u32); + + if (policy->policy == IPSEC_POLICY_ACTION_PROTECT) + { + ipsec_sa_t *s = ipsec_sa_get (policy->sa_index); + + if (match->spi != s->spi) + return (0); + + if (ipsec_sa_is_set_IS_TUNNEL (s)) + { + if (da != clib_net_to_host_u32 (s->tunnel.t_dst.ip.ip4.as_u32)) + return (0); + + if (sa != clib_net_to_host_u32 (s->tunnel.t_src.ip.ip4.as_u32)) + return (0); + } + } + else + { + if (da < clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32)) + return (0); + + if (da > clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32)) + return (0); + + if (sa < clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32)) + return (0); + + if (sa > clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32)) + return (0); + } + return (1); +} + +static_always_inline u32 +ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, + ipsec_policy_t **policies, u32 n) +{ + return 0; +} + +static_always_inline u32 +ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, + ipsec_policy_t **policies, u32 n) + +{ + u32 last_priority[n]; + u32 i = 0; + u32 counter = 0; + ipsec_fp_mask_type_entry_t *mte; + ipsec_fp_mask_id_t *mti; + ipsec_fp_5tuple_t *match = tuples; + ipsec_policy_t *policy; + u32 n_left = n; + clib_bihash_kv_16_8_t kv; + /* result of the lookup */ + clib_bihash_kv_16_8_t result; + ipsec_fp_lookup_value_t *result_val = + (ipsec_fp_lookup_value_t *) &result.value; + u64 *pkey, *pmatch, *pmask; + ipsec_main_t *im = &ipsec_main; + ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp; + ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action]; + clib_bihash_16_8_t *bihash_table = pool_elt_at_index ( + im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_in_lookup_hash_idx); + + /* clear the list of matched policies pointers */ + clib_memset (policies, 0, n * sizeof (*policies)); + clib_memset (last_priority, 0, n * sizeof (u32)); + n_left = n; + while (n_left) + { + vec_foreach (mti, mask_type_ids) + { + mte = im->fp_mask_types + mti->mask_type_idx; + if (mte->mask.action == 0) + continue; + pmatch = (u64 *) match->kv_16_8.key; + pmask = (u64 *) mte->mask.kv_16_8.key; + pkey = (u64 *) kv.key; + + *pkey++ = *pmatch++ & *pmask++; + *pkey = *pmatch & *pmask; + + int res = + clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result); + /* lookup the hash by each packet in the burst for this mask. */ + + if (res == 0) + { + /* There is a hit in the hash table. */ + /* Find the policy with highest priority. */ + /* Store the lookup results in a dedicated array. */ + + if (vec_len (result_val->fp_policies_ids) > 1) + { + u32 *policy_id; + vec_foreach (policy_id, result_val->fp_policies_ids) + { + policy = im->policies + *policy_id; + + if ((last_priority[i] < policy->priority) && + (single_rule_in_match_5tuple (policy, match))) + { + last_priority[i] = policy->priority; + if (policies[i] == 0) + counter++; + policies[i] = policy; + } + } + } + else + { + u32 *policy_id; + ASSERT (vec_len (result_val->fp_policies_ids) == 1); + policy_id = result_val->fp_policies_ids; + policy = im->policies + *policy_id; + if ((last_priority[i] < policy->priority) && + (single_rule_in_match_5tuple (policy, match))) + { + last_priority[i] = policy->priority; + if (policies[i] == 0) + counter++; + policies[i] = policy; + } + } + } + } + + i++; + n_left--; + match++; + } + return counter; +} + +/** + * @brief function handler to perform lookup in fastpath SPD + * for inbound traffic burst of n packets + **/ + +static_always_inline u32 +ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6, + ipsec_fp_5tuple_t *tuples, + ipsec_policy_t **policies, u32 n) +{ + if (is_ipv6) + return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n); + else + return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n); +} + static_always_inline u32 ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, ipsec_policy_t **policies, u32 *ids, u32 n) @@ -115,7 +261,7 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, u32 i = 0; u32 counter = 0; ipsec_fp_mask_type_entry_t *mte; - u32 *mti; + ipsec_fp_mask_id_t *mti; ipsec_fp_5tuple_t *match = tuples; ipsec_policy_t *policy; @@ -128,7 +274,10 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, u64 *pkey, *pmatch, *pmask; ipsec_main_t *im = &ipsec_main; ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp; - u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP6_OUTBOUND]; + ipsec_fp_mask_id_t *mask_type_ids = + pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP6_OUTBOUND]; + clib_bihash_40_8_t *bihash_table = pool_elt_at_index ( + im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_out_lookup_hash_idx); /*clear the list of matched policies pointers */ clib_memset (policies, 0, n * sizeof (*policies)); @@ -138,7 +287,7 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, { vec_foreach (mti, mask_type_ids) { - mte = im->fp_mask_types + *mti; + mte = im->fp_mask_types + mti->mask_type_idx; pmatch = (u64 *) match->kv_40_8.key; pmask = (u64 *) mte->mask.kv_40_8.key; @@ -150,8 +299,8 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, *pkey++ = *pmatch++ & *pmask++; *pkey = *pmatch & *pmask; - int res = clib_bihash_search_inline_2_40_8 ( - &pspd_fp->fp_ip6_lookup_hash, &kv, &result); + int res = + clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result); /* lookup the hash by each packet in the burst for this mask. */ if (res == 0) @@ -216,7 +365,7 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, u32 i = 0; u32 counter = 0; ipsec_fp_mask_type_entry_t *mte; - u32 *mti; + ipsec_fp_mask_id_t *mti; ipsec_fp_5tuple_t *match = tuples; ipsec_policy_t *policy; @@ -229,7 +378,10 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, u64 *pkey, *pmatch, *pmask; ipsec_main_t *im = &ipsec_main; ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp; - u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP4_OUTBOUND]; + ipsec_fp_mask_id_t *mask_type_ids = + pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP4_OUTBOUND]; + clib_bihash_16_8_t *bihash_table = pool_elt_at_index ( + im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_out_lookup_hash_idx); /* clear the list of matched policies pointers */ clib_memset (policies, 0, n * sizeof (*policies)); @@ -239,7 +391,9 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, { vec_foreach (mti, mask_type_ids) { - mte = im->fp_mask_types + *mti; + mte = im->fp_mask_types + mti->mask_type_idx; + if (mte->mask.action != 0) + continue; pmatch = (u64 *) match->kv_16_8.key; pmask = (u64 *) mte->mask.kv_16_8.key; @@ -248,8 +402,8 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples, *pkey++ = *pmatch++ & *pmask++; *pkey = *pmatch & *pmask; - int res = clib_bihash_search_inline_2_16_8 ( - &pspd_fp->fp_ip4_lookup_hash, &kv, &result); + int res = + clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result); /* lookup the hash by each packet in the burst for this mask. */ if (res == 0) diff --git a/src/vnet/ipsec/ipsec_spd_policy.c b/src/vnet/ipsec/ipsec_spd_policy.c index 1334491b228..1d698d53e07 100644 --- a/src/vnet/ipsec/ipsec_spd_policy.c +++ b/src/vnet/ipsec/ipsec_spd_policy.c @@ -80,6 +80,17 @@ ipsec_policy_mk_type (bool is_outbound, return (-1); } +static_always_inline int +ipsec_is_policy_inbound (ipsec_policy_t *policy) +{ + if (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) + return 1; + + return 0; +} + int ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int is_add, u32 * stat_index) @@ -167,9 +178,19 @@ ipsec_add_del_policy (vlib_main_t * vm, * Try adding the policy into fast path SPD first. Only adding to * traditional SPD when failed. **/ - if ((im->ipv4_fp_spd_is_enabled && + if ((im->fp_spd_ipv4_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip4_out_lookup_hash_idx) && policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) || - (im->ipv6_fp_spd_is_enabled && + (im->fp_spd_ipv4_in_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip4_in_lookup_hash_idx) && + (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) || + (im->fp_spd_ipv6_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip6_out_lookup_hash_idx) && policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND)) return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1, stat_index); @@ -195,12 +216,36 @@ ipsec_add_del_policy (vlib_main_t * vm, * traditional SPD when fp delete fails. **/ - if ((im->ipv4_fp_spd_is_enabled && + if ((im->fp_spd_ipv4_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip4_out_lookup_hash_idx) && policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) || - (im->ipv6_fp_spd_is_enabled && + (im->fp_spd_ipv4_in_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip4_in_lookup_hash_idx) && + (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS || + policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) || + (im->fp_spd_ipv6_out_is_enabled && + PREDICT_TRUE (INDEX_INVALID != + spd->fp_spd.ip6_out_lookup_hash_idx) && policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND)) - return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0, - stat_index); + { + if (policy->policy == IPSEC_POLICY_ACTION_PROTECT) + { + index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id); + + if (INDEX_INVALID == sa_index) + return VNET_API_ERROR_SYSCALL_ERROR_1; + policy->sa_index = sa_index; + ipsec_sa_unlock_id (policy->sa_id); + } + else + policy->sa_index = INDEX_INVALID; + + return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0, + stat_index); + } vec_foreach_index (ii, (spd->policies[policy->type])) { @@ -220,7 +265,7 @@ ipsec_add_del_policy (vlib_main_t * vm, } static_always_inline void -release_mask_type_index (ipsec_main_t *im, u32 mask_type_index) +ipsec_fp_release_mask_type (ipsec_main_t *im, u32 mask_type_index) { ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index (im->fp_mask_types, mask_type_index); @@ -281,24 +326,24 @@ fill_ip4_hash_policy_kv (ipsec_fp_5tuple_t *match, ipsec_fp_5tuple_t *mask, } static_always_inline u16 -get_highest_set_bit_u16 (u16 x) +mask_out_highest_set_bit_u16 (u16 x) { x |= x >> 8; x |= x >> 4; x |= x >> 2; x |= x >> 1; - return x ^= x >> 1; + return ~x; } static_always_inline u32 -get_highest_set_bit_u32 (u32 x) +mask_out_highest_set_bit_u32 (u32 x) { x |= x >> 16; x |= x >> 8; x |= x >> 4; x |= x >> 2; x |= x >> 1; - return x ^= x >> 1; + return ~x; } static_always_inline u64 @@ -324,11 +369,9 @@ ipsec_fp_get_policy_ports_mask (ipsec_policy_t *policy, mask->lport = policy->lport.start ^ policy->lport.stop; mask->rport = policy->rport.start ^ policy->rport.stop; - mask->lport = get_highest_set_bit_u16 (mask->lport); - mask->lport = ~(mask->lport - 1) & (~mask->lport); + mask->lport = mask_out_highest_set_bit_u16 (mask->lport); - mask->rport = get_highest_set_bit_u16 (mask->rport); - mask->rport = ~(mask->rport - 1) & (~mask->rport); + mask->rport = mask_out_highest_set_bit_u16 (mask->rport); } else { @@ -337,10 +380,12 @@ ipsec_fp_get_policy_ports_mask (ipsec_policy_t *policy, } mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0; + mask->action = 0; } static_always_inline void -ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask) +ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask, + bool inbound) { u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4; u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4; @@ -360,32 +405,24 @@ ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask) * the bit itself. Remember that policy stores start and stop in the net * order. */ - *plmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask)); - *plmask = clib_host_to_net_u32 (~(*plmask - 1) & (~*plmask)); + *plmask = clib_host_to_net_u32 ( + mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask))); - *prmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)); - *prmask = clib_host_to_net_u32 (~(*prmask - 1) & (~*prmask)); + *prmask = clib_host_to_net_u32 ( + mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask))); - if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) || - (policy->protocol == IP_PROTOCOL_UDP) || - (policy->protocol == IP_PROTOCOL_SCTP))) + if (inbound) { - mask->lport = policy->lport.start ^ policy->lport.stop; - mask->rport = policy->rport.start ^ policy->rport.stop; + if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT) + mask->spi = 0; - mask->lport = get_highest_set_bit_u16 (mask->lport); - mask->lport = ~(mask->lport - 1) & (~mask->lport); - - mask->rport = get_highest_set_bit_u16 (mask->rport); - mask->rport = ~(mask->rport - 1) & (~mask->rport); + mask->protocol = 0; } else { - mask->lport = 0; - mask->rport = 0; + mask->action = 0; + ipsec_fp_get_policy_ports_mask (policy, mask); } - - mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0; } static_always_inline void @@ -437,7 +474,8 @@ ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask) } static_always_inline void -ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple) +ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple, + bool inbound) { memset (tuple, 0, sizeof (*tuple)); tuple->is_ipv6 = policy->is_ipv6; @@ -452,17 +490,39 @@ ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple) tuple->raddr = policy->raddr.start.ip4; } + if (inbound) + { + + if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT || + policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT) && + policy->sa_index != INDEX_INVALID) + { + ipsec_sa_t *s = ipsec_sa_get (policy->sa_index); + tuple->spi = s->spi; + } + else + tuple->spi = INDEX_INVALID; + tuple->action = policy->type; + return; + } + tuple->protocol = policy->protocol; tuple->lport = policy->lport.start; tuple->rport = policy->rport.start; } +static_always_inline int +ipsec_fp_mask_type_idx_cmp (ipsec_fp_mask_id_t *mask_id, u32 *idx) +{ + return mask_id->mask_type_idx == *idx; +} + int ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, ipsec_policy_t *policy, u32 *stat_index) { - u32 mask_index; + u32 mask_index, searched_idx; ipsec_policy_t *vp; ipsec_fp_mask_type_entry_t *mte; u32 policy_index; @@ -474,8 +534,14 @@ ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, ipsec_fp_5tuple_t mask, policy_5tuple; int res; - - ipsec_fp_ip4_get_policy_mask (policy, &mask); + bool inbound = ipsec_is_policy_inbound (policy); + clib_bihash_16_8_t *bihash_table = + inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_in_lookup_hash_idx) : + pool_elt_at_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_out_lookup_hash_idx); + + ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound); pool_get (im->policies, vp); policy_index = vp - im->policies; vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index); @@ -494,17 +560,17 @@ ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, mte = im->fp_mask_types + mask_index; policy->fp_mask_type_id = mask_index; - ipsec_fp_get_policy_5tuple (policy, &policy_5tuple); + ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound); fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv); - res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv, - &result); + res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result); if (res != 0) { /* key was not found crate a new entry */ vec_add1 (key_val->fp_policies_ids, policy_index); - res = clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv, 1); + res = clib_bihash_add_del_16_8 (bihash_table, &kv, 1); + if (res != 0) goto error; } @@ -521,8 +587,7 @@ ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, { vec_add1 (result_val->fp_policies_ids, policy_index); - res = - clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &result, 1); + res = clib_bihash_add_del_16_8 (bihash_table, &result, 1); if (res != 0) goto error; @@ -533,9 +598,19 @@ ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, { clib_memcpy (&mte->mask, &mask, sizeof (mask)); mte->refcount = 0; - vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index); } + searched_idx = + vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index, + ipsec_fp_mask_type_idx_cmp); + if (~0 == searched_idx) + { + ipsec_fp_mask_id_t mask_id = { mask_index, 1 }; + vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id); + } + else + (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++; + mte->refcount++; vec_add1 (fp_spd->fp_policies[policy->type], policy_index); clib_memcpy (vp, policy, sizeof (*vp)); @@ -544,7 +619,7 @@ ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, error: pool_put (im->policies, vp); - release_mask_type_index (im, mask_index); + ipsec_fp_release_mask_type (im, mask_index); return -1; } @@ -553,7 +628,7 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, ipsec_policy_t *policy, u32 *stat_index) { - u32 mask_index; + u32 mask_index, searched_idx; ipsec_policy_t *vp; ipsec_fp_mask_type_entry_t *mte; u32 policy_index; @@ -565,14 +640,20 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, ipsec_fp_5tuple_t mask, policy_5tuple; int res; - ipsec_fp_ip6_get_policy_mask (policy, &mask); + bool inbound = ipsec_is_policy_inbound (policy); + ipsec_fp_ip6_get_policy_mask (policy, &mask); pool_get (im->policies, vp); policy_index = vp - im->policies; vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index); vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index); *stat_index = policy_index; mask_index = find_mask_type_index (im, &mask); + clib_bihash_40_8_t *bihash_table = + inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_in_lookup_hash_idx) : + pool_elt_at_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_out_lookup_hash_idx); if (mask_index == ~0) { @@ -585,17 +666,16 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, mte = im->fp_mask_types + mask_index; policy->fp_mask_type_id = mask_index; - ipsec_fp_get_policy_5tuple (policy, &policy_5tuple); + ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound); fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv); - res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv, - &result); + res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result); if (res != 0) { /* key was not found crate a new entry */ vec_add1 (key_val->fp_policies_ids, policy_index); - res = clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv, 1); + res = clib_bihash_add_del_40_8 (bihash_table, &kv, 1); if (res != 0) goto error; } @@ -612,8 +692,7 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, { vec_add1 (result_val->fp_policies_ids, policy_index); - res = - clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &result, 1); + res = clib_bihash_add_del_40_8 (bihash_table, &result, 1); if (res != 0) goto error; @@ -624,9 +703,19 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, { clib_memcpy (&mte->mask, &mask, sizeof (mask)); mte->refcount = 0; - vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index); } + searched_idx = + vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index, + ipsec_fp_mask_type_idx_cmp); + if (~0 == searched_idx) + { + ipsec_fp_mask_id_t mask_id = { mask_index, 1 }; + vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id); + } + else + (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++; + mte->refcount++; vec_add1 (fp_spd->fp_policies[policy->type], policy_index); clib_memcpy (vp, policy, sizeof (*vp)); @@ -635,7 +724,7 @@ ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, error: pool_put (im->policies, vp); - release_mask_type_index (im, mask_index); + ipsec_fp_release_mask_type (im, mask_index); return -1; } @@ -649,15 +738,20 @@ ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, clib_bihash_kv_40_8_t result; ipsec_fp_lookup_value_t *result_val = (ipsec_fp_lookup_value_t *) &result.value; + bool inbound = ipsec_is_policy_inbound (policy); + clib_bihash_40_8_t *bihash_table = + inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_in_lookup_hash_idx) : + pool_elt_at_index (im->fp_ip6_lookup_hashes_pool, + fp_spd->ip6_out_lookup_hash_idx); ipsec_policy_t *vp; u32 ii, iii, imt; ipsec_fp_ip6_get_policy_mask (policy, &mask); - ipsec_fp_get_policy_5tuple (policy, &policy_5tuple); + ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound); fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv); - res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv, - &result); + res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result); if (res != 0) return -1; @@ -676,8 +770,7 @@ ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, if (vec_len (result_val->fp_policies_ids) == 1) { vec_free (result_val->fp_policies_ids); - clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, - &result, 0); + clib_bihash_add_del_40_8 (bihash_table, &result, 0); } else { @@ -685,17 +778,16 @@ ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, } vec_del1 (fp_spd->fp_policies[policy->type], iii); - vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type]) + vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type]) { - if (*(fp_spd->fp_mask_types[policy->type] + imt) == - vp->fp_mask_type_id) + if ((fp_spd->fp_mask_ids[policy->type] + imt) + ->mask_type_idx == vp->fp_mask_type_id) { - ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index ( - im->fp_mask_types, vp->fp_mask_type_id); - if (mte->refcount == 1) - vec_del1 (fp_spd->fp_mask_types[policy->type], - imt); + if ((fp_spd->fp_mask_ids[policy->type] + imt) + ->refcount-- == 1) + vec_del1 (fp_spd->fp_mask_ids[policy->type], imt); + break; } } @@ -709,7 +801,7 @@ ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, continue; else { - release_mask_type_index (im, vp->fp_mask_type_id); + ipsec_fp_release_mask_type (im, vp->fp_mask_type_id); ipsec_sa_unlock (vp->sa_index); pool_put (im->policies, vp); return 0; @@ -729,15 +821,20 @@ ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, clib_bihash_kv_16_8_t result; ipsec_fp_lookup_value_t *result_val = (ipsec_fp_lookup_value_t *) &result.value; - + bool inbound = ipsec_is_policy_inbound (policy); ipsec_policy_t *vp; u32 ii, iii, imt; - - ipsec_fp_ip4_get_policy_mask (policy, &mask); - ipsec_fp_get_policy_5tuple (policy, &policy_5tuple); + clib_bihash_16_8_t *bihash_table = + inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_in_lookup_hash_idx) : + pool_elt_at_index (im->fp_ip4_lookup_hashes_pool, + fp_spd->ip4_out_lookup_hash_idx); + + ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound); + ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound); fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv); - res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv, - &result); + res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result); + if (res != 0) return -1; @@ -756,8 +853,7 @@ ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, if (vec_len (result_val->fp_policies_ids) == 1) { vec_free (result_val->fp_policies_ids); - clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, - &result, 0); + clib_bihash_add_del_16_8 (bihash_table, &result, 0); } else { @@ -765,17 +861,16 @@ ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, } vec_del1 (fp_spd->fp_policies[policy->type], iii); - vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type]) + vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type]) { - if (*(fp_spd->fp_mask_types[policy->type] + imt) == - vp->fp_mask_type_id) + if ((fp_spd->fp_mask_ids[policy->type] + imt) + ->mask_type_idx == vp->fp_mask_type_id) { - ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index ( - im->fp_mask_types, vp->fp_mask_type_id); - if (mte->refcount == 1) - vec_del1 (fp_spd->fp_mask_types[policy->type], - imt); + if ((fp_spd->fp_mask_ids[policy->type] + imt) + ->refcount-- == 1) + vec_del1 (fp_spd->fp_mask_ids[policy->type], imt); + break; } } @@ -789,7 +884,7 @@ ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd, continue; else { - release_mask_type_index (im, vp->fp_mask_type_id); + ipsec_fp_release_mask_type (im, vp->fp_mask_type_id); ipsec_sa_unlock (vp->sa_index); pool_put (im->policies, vp); return 0; diff --git a/src/vnet/ipsec/ipsec_spd_policy.h b/src/vnet/ipsec/ipsec_spd_policy.h index 57985116c94..34f444efb9c 100644 --- a/src/vnet/ipsec/ipsec_spd_policy.h +++ b/src/vnet/ipsec/ipsec_spd_policy.h @@ -134,10 +134,17 @@ typedef union ip6_address_t ip6_raddr; }; }; - - u16 lport; - u16 rport; - u16 protocol; + union + { + struct + { + u16 lport; + u16 rport; + }; + u32 spi; + }; + u8 protocol; + u8 action; u16 is_ipv6; }; /* for ipv6 */ -- cgit 1.2.3-korg