From a1018c166a468f7692ab621c743503914266f508 Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Fri, 27 Mar 2020 11:54:53 +0100 Subject: nat: simplify bihash buckets/mem config Derive reasonable values from max translations/max users. Type: improvement Signed-off-by: Klement Sekera Change-Id: I41a96ab63ab138b4160cd60bd6df24fc73791c86 --- src/plugins/nat/in2out.c | 3 +- src/plugins/nat/in2out_ed.c | 6 ++- src/plugins/nat/nat.c | 96 ++++++++++++++++++++++++++++++++-------- src/plugins/nat/nat.h | 5 ++- src/plugins/nat/nat44/inlines.h | 2 +- src/plugins/nat/nat44_cli.c | 3 +- src/plugins/nat/nat_inlines.h | 2 +- src/plugins/nat/test/test_nat.py | 9 ++-- 8 files changed, 95 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index 7ed0a225fef..b8febc17c99 100644 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -273,7 +273,8 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0, if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index))) { b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED]; - nat_ipfix_logging_max_sessions (thread_index, sm->max_translations); + nat_ipfix_logging_max_sessions (thread_index, + sm->max_translations_per_thread); nat_elog_notice ("maximum sessions exceeded"); return SNAT_IN2OUT_NEXT_DROP; } diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c index 2e316f59c3a..49e3812441e 100644 --- a/src/plugins/nat/in2out_ed.c +++ b/src/plugins/nat/in2out_ed.c @@ -351,7 +351,8 @@ slow_path_ed (snat_main_t * sm, if (!nat_lru_free_one (sm, thread_index, now)) { b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED]; - nat_ipfix_logging_max_sessions (thread_index, sm->max_translations); + nat_ipfix_logging_max_sessions (thread_index, + sm->max_translations_per_thread); nat_elog_notice ("maximum sessions exceeded"); return NAT_NEXT_DROP; } @@ -809,7 +810,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm, (sm, rx_fib_index, thread_index))) { b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED]; - nat_ipfix_logging_max_sessions (thread_index, sm->max_translations); + nat_ipfix_logging_max_sessions (thread_index, + sm->max_translations_per_thread); nat_elog_notice ("maximum sessions exceeded"); return 0; } diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index ed01bb4df80..36d03a620d4 100644 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -338,7 +338,7 @@ nat44_set_session_limit (u32 session_limit, u32 vrf_id) vec_validate (sm->max_translations_per_fib, fib_index + 1); for (; len < vec_len (sm->max_translations_per_fib); len++) - sm->max_translations_per_fib[len] = sm->max_translations; + sm->max_translations_per_fib[len] = sm->max_translations_per_thread; } sm->max_translations_per_fib[fib_index] = session_limit; @@ -485,6 +485,13 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index, /* Ever heard of the "user" = src ip4 address before? */ if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { + if (pool_elts (tsm->users) >= sm->max_users_per_thread) + { + vlib_increment_simple_counter (&sm->user_limit_reached, + thread_index, 0, 1); + nat_elog_warn ("maximum user limit reached"); + return NULL; + } /* no, make a new one */ pool_get (tsm->users, u); clib_memset (u, 0, sizeof (*u)); @@ -2578,6 +2585,10 @@ snat_init (vlib_main_t * vm) sm->total_sessions.stat_segment_name = "/nat44/total-sessions"; vlib_validate_simple_counter (&sm->total_sessions, 0); vlib_zero_simple_counter (&sm->total_sessions, 0); + sm->user_limit_reached.name = "user-limit-reached"; + sm->user_limit_reached.stat_segment_name = "/nat44/user-limit-reached"; + vlib_validate_simple_counter (&sm->user_limit_reached, 0); + vlib_zero_simple_counter (&sm->user_limit_reached, 0); /* Init IPFIX logging */ snat_ipfix_logging_init (vm); @@ -3780,13 +3791,25 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port, s->total_bytes = total_bytes; } +static u32 +nat_calc_bihash_buckets (u32 n_elts) +{ + return 1 << (max_log2 (n_elts >> 1) + 1); +} + +static u32 +nat_calc_bihash_memory (u32 n_buckets, uword kv_size) +{ + return n_buckets * (8 + kv_size * 4); +} + void nat44_db_init (snat_main_per_thread_data_t * tsm) { snat_main_t *sm = &snat_main; - pool_alloc (tsm->sessions, sm->max_translations); - pool_alloc (tsm->lru_pool, sm->max_translations); + pool_alloc (tsm->sessions, sm->max_translations_per_thread); + pool_alloc (tsm->lru_pool, sm->max_translations_per_thread); dlist_elt_t *head; @@ -3831,7 +3854,7 @@ nat44_db_init (snat_main_per_thread_data_t * tsm) } // TODO: resolve static mappings (put only to !ED) - pool_alloc (tsm->list_pool, sm->max_translations); + pool_alloc (tsm->list_pool, sm->max_translations_per_thread); clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets, sm->user_memory_size); clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp); @@ -3910,10 +3933,10 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) u32 nat64_st_buckets = 2048; uword nat64_st_memory_size = 256 << 20; - u32 user_buckets = 128; - uword user_memory_size = 64 << 20; - u32 translation_buckets = 1024; - uword translation_memory_size = 128 << 20; + u32 max_users_per_thread = 0; + u32 user_memory_size = 0; + u32 max_translations_per_thread = 0; + u32 translation_memory_size = 0; u32 max_translations_per_user = ~0; @@ -3935,7 +3958,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat - (input, "translation hash buckets %d", &translation_buckets)) + (input, "max translations per thread %d", + &max_translations_per_thread)) ; else if (unformat (input, "udp timeout %d", &udp_timeout)) ; @@ -3947,7 +3971,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) &tcp_established_timeout)); else if (unformat (input, "translation hash memory %d", &translation_memory_size)); - else if (unformat (input, "user hash buckets %d", &user_buckets)) + else + if (unformat + (input, "max users per thread %d", &max_users_per_thread)) ; else if (unformat (input, "user hash memory %d", &user_memory_size)) ; @@ -4000,6 +4026,17 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent)) return clib_error_return (0, "out2in dpo mode available only for simple nat"); + if (sm->endpoint_dependent && max_users_per_thread > 0) + { + return clib_error_return (0, + "setting 'max users' in endpoint-dependent mode is not supported"); + } + + if (sm->endpoint_dependent && max_translations_per_user != ~0) + { + return clib_error_return (0, + "setting 'max translations per user' in endpoint-dependent mode is not supported"); + } /* optionally configurable timeouts for testing purposes */ sm->udp_timeout = udp_timeout; @@ -4007,17 +4044,40 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) sm->tcp_established_timeout = tcp_established_timeout; sm->icmp_timeout = icmp_timeout; - sm->user_buckets = user_buckets; - sm->user_memory_size = user_memory_size; + if (0 == max_users_per_thread) + { + max_users_per_thread = 1024; + } + sm->max_users_per_thread = max_users_per_thread; + sm->user_buckets = nat_calc_bihash_buckets (sm->max_users_per_thread); - sm->translation_buckets = translation_buckets; + if (0 == max_translations_per_thread) + { + // default value based on legacy setting of load factor 10 * default + // translation buckets 1024 + max_translations_per_thread = 10 * 1024; + } + sm->max_translations_per_thread = max_translations_per_thread; + sm->translation_buckets = + nat_calc_bihash_buckets (sm->max_translations_per_thread); + if (0 == translation_memory_size) + { + translation_memory_size = + nat_calc_bihash_memory (sm->translation_buckets, + sizeof (clib_bihash_16_8_t)); + } sm->translation_memory_size = translation_memory_size; - /* do not exceed load factor 10 */ - sm->max_translations = 10 * translation_buckets; - vec_add1 (sm->max_translations_per_fib, sm->max_translations); + if (0 == user_memory_size) + { + user_memory_size = + nat_calc_bihash_memory (sm->max_users_per_thread, + sizeof (clib_bihash_8_8_t)); + } + sm->user_memory_size = user_memory_size; + vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread); sm->max_translations_per_user = max_translations_per_user == ~0 ? - sm->max_translations : max_translations_per_user; + sm->max_translations_per_thread : max_translations_per_user; sm->outside_vrf_id = outside_vrf_id; sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, @@ -4062,7 +4122,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb, nat_ha_sref_ed_cb); clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", - translation_buckets, + sm->translation_buckets, translation_memory_size); clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, format_ed_session_kvp); diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 8b04e18b18b..d5b236dac01 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -635,9 +635,9 @@ typedef struct snat_main_s u32 translation_buckets; uword translation_memory_size; - u32 max_translations; + u32 max_translations_per_thread; u32 *max_translations_per_fib; - + u32 max_users_per_thread; u32 user_buckets; uword user_memory_size; u32 max_translations_per_user; @@ -660,6 +660,7 @@ typedef struct snat_main_s /* counters/gauges */ vlib_simple_counter_main_t total_users; vlib_simple_counter_main_t total_sessions; + vlib_simple_counter_main_t user_limit_reached;; /* API message ID base */ u16 msg_id_base; diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h index 6e462d7c36f..8bfc74012e8 100644 --- a/src/plugins/nat/nat44/inlines.h +++ b/src/plugins/nat/nat44/inlines.h @@ -26,7 +26,7 @@ static_always_inline u8 nat44_maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index) { if (pool_elts (sm->per_thread_data[thread_index].sessions) >= - sm->max_translations) + sm->max_translations_per_thread) return 1; return 0; } diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index ffc5fd43618..18f51b1a6e1 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -643,7 +643,8 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, if (sm->deterministic || !sm->endpoint_dependent) return clib_error_return (0, UNSUPPORTED_IN_DET_OR_NON_ED_MODE_STR); - vlib_cli_output (vm, "max translations: %u", sm->max_translations); + vlib_cli_output (vm, "max translations per thread: %u", + sm->max_translations_per_thread); vlib_cli_output (vm, "max translations per user: %u", sm->max_translations_per_user); diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h index 240ff0e7da9..40ac3d307a8 100644 --- a/src/plugins/nat/nat_inlines.h +++ b/src/plugins/nat/nat_inlines.h @@ -252,7 +252,7 @@ always_inline u8 maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index) { if (pool_elts (sm->per_thread_data[thread_index].sessions) >= - sm->max_translations) + sm->max_translations_per_thread) return 1; return 0; diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index 97f473c95fd..6dee818d4bb 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -7214,14 +7214,14 @@ class TestNAT44EndpointDependent(MethodHolder): class TestNAT44EndpointDependent3(MethodHolder): """ Endpoint-Dependent mapping and filtering extra test cases """ - translation_buckets = 5 + max_translations = 50 @classmethod def setUpConstants(cls): super(TestNAT44EndpointDependent3, cls).setUpConstants() cls.vpp_cmdline.extend([ "nat", "{", "endpoint-dependent", - "translation hash buckets %d" % cls.translation_buckets, + "max translations per thread %d" % cls.max_translations, "}" ]) @@ -7289,9 +7289,8 @@ class TestNAT44EndpointDependent3(MethodHolder): def test_lru_cleanup(self): """ LRU cleanup algorithm """ tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80) - max_translations = 10 * self.translation_buckets pkts = [] - for i in range(0, max_translations - 1): + for i in range(0, self.max_translations - 1): p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) / UDP(sport=7000+i, dport=80)) @@ -7304,7 +7303,7 @@ class TestNAT44EndpointDependent3(MethodHolder): self.sleep(1.5, "wait for timeouts") pkts = [] - for i in range(0, max_translations - 1): + for i in range(0, self.max_translations - 1): p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) / ICMP(id=8000+i, type='echo-request')) -- cgit 1.2.3-korg