diff options
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 51 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 17 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_input.c | 54 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_output.h | 9 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_spd.c | 151 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_spd.h | 28 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_spd_fp_lookup.h | 198 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_spd_policy.c | 269 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_spd_policy.h | 15 |
9 files changed, 628 insertions, 164 deletions
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 <vppinfra/bihash_24_16.h> +#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 <vnet/api_errno.h> #include <vnet/ip/ip.h> #include <vnet/feature/feature.h> +#include <vnet/ipsec/ipsec_spd_fp_lookup.h> #include <vnet/ipsec/ipsec.h> #include <vnet/ipsec/esp.h> @@ -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 <vnet/ipsec/ipsec.h> -/** - * @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 */ |