From c611f36bbc75a7157bbec26a78178872ddc5441f Mon Sep 17 00:00:00 2001 From: Filip Varga Date: Sun, 19 Apr 2020 19:44:49 +0200 Subject: nat: enable force session cleanup Force session cleanup drops NAT db. Also fixing user specific cli/api calls. Type: improvement Change-Id: Ia3e25fcf07fe5fb9a83d55c03fe90aca727b41ac Signed-off-by: Filip Varga --- src/plugins/nat/nat.c | 115 ++++++++++++++++++++++++--------------- src/plugins/nat/nat.h | 16 +++++- src/plugins/nat/nat44/inlines.h | 25 +++++++++ src/plugins/nat/nat44_cli.c | 67 ++++++++++++++++++----- src/plugins/nat/nat_format.c | 86 +---------------------------- src/plugins/nat/test/test_nat.py | 69 +++++++++++++++++++++++ 6 files changed, 236 insertions(+), 142 deletions(-) diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 7cb0b53368c..c30324b7d9e 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -3923,6 +3923,76 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port, s->total_bytes = total_bytes; } +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->global_lru_pool, sm->max_translations); + + dlist_elt_t *head; + pool_get (tsm->global_lru_pool, head); + tsm->global_lru_head_index = head - tsm->global_lru_pool; + clib_dlist_init (tsm->global_lru_pool, tsm->global_lru_head_index); + + if (sm->endpoint_dependent) + { + clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed", + sm->translation_buckets, + sm->translation_memory_size); + clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed, + format_ed_session_kvp); + clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed", + sm->translation_buckets, + sm->translation_memory_size); + clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed, + format_ed_session_kvp); + } + else + { + clib_bihash_init_8_8 (&tsm->in2out, "in2out", + sm->translation_buckets, + sm->translation_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp); + clib_bihash_init_8_8 (&tsm->out2in, "out2in", + sm->translation_buckets, + sm->translation_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp); + } + + // TODO: resolve static mappings (put only to !ED) + pool_alloc (tsm->list_pool, sm->max_translations); + 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); +} + +void +nat44_db_free (snat_main_per_thread_data_t * tsm) +{ + snat_main_t *sm = &snat_main; + + pool_free (tsm->sessions); + pool_free (tsm->global_lru_pool); + + if (sm->endpoint_dependent) + { + clib_bihash_free_16_8 (&tsm->in2out_ed); + clib_bihash_free_16_8 (&tsm->out2in_ed); + } + else + { + clib_bihash_free_8_8 (&tsm->in2out); + clib_bihash_free_8_8 (&tsm->out2in); + } + + // TODO: resolve static mappings (put only to !ED) + pool_free (tsm->users); + pool_free (tsm->list_pool); + clib_bihash_free_8_8 (&tsm->user_hash); +} + static clib_error_t * snat_config (vlib_main_t * vm, unformat_input_t * input) { @@ -4121,52 +4191,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) /* *INDENT-OFF* */ vec_foreach (tsm, sm->per_thread_data) { - pool_alloc (tsm->sessions, sm->max_translations); - pool_alloc (tsm->list_pool, sm->max_translations); - pool_alloc (tsm->global_lru_pool, sm->max_translations); - - dlist_elt_t *head; - pool_get (tsm->global_lru_pool, head); - tsm->global_lru_head_index = head - tsm->global_lru_pool; - clib_dlist_init (tsm->global_lru_pool, - tsm->global_lru_head_index); - - if (sm->endpoint_dependent) - { - clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed", - translation_buckets, - translation_memory_size); - clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed, - format_ed_session_kvp); - - clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed", - translation_buckets, - translation_memory_size); - clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed, - format_ed_session_kvp); - } - else - { - clib_bihash_init_8_8 (&tsm->in2out, "in2out", - translation_buckets, - translation_memory_size); - clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, - format_session_kvp); - - clib_bihash_init_8_8 (&tsm->out2in, "out2in", - translation_buckets, - translation_memory_size); - clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, - format_session_kvp); - } - - clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, - user_memory_size); - clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, - format_user_kvp); + nat44_db_init (tsm); } /* *INDENT-ON* */ - } else { diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 9331901a3bc..bc998da9982 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -716,7 +716,6 @@ extern fib_source_t nat_fib_src_low; /* format functions */ format_function_t format_snat_user; -format_function_t format_snat_user_v2; format_function_t format_snat_static_mapping; format_function_t format_snat_static_map_to_resolve; format_function_t format_snat_session; @@ -1276,6 +1275,21 @@ int nat44_set_session_limit (u32 session_limit, u32 vrf_id); void nat44_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, u8 is_ha); + +/** + * @brief Initialize NAT44 data + * + * @param tsm per thread data + */ +void nat44_db_init (snat_main_per_thread_data_t * tsm); + +/** + * @brief Free NAT44 data + * + * @param tsm per thread data + */ +void nat44_db_free (snat_main_per_thread_data_t * tsm); + /** * @brief Find or create NAT user * diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h index 229daa2425e..a5118ea2fa6 100644 --- a/src/plugins/nat/nat44/inlines.h +++ b/src/plugins/nat/nat44/inlines.h @@ -77,6 +77,28 @@ nat44_global_lru_insert (snat_main_per_thread_data_t * tsm, s->last_lru_update = now; } +static_always_inline void +nat44_sessions_clear () +{ + snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + + /* *INDENT-OFF* */ + vec_foreach (tsm, sm->per_thread_data) + { + u32 ti; + + nat44_db_free (tsm); + nat44_db_init (tsm); + + ti = tsm->snat_thread_index; + // clear per thread session counters + vlib_set_simple_counter (&sm->total_users, ti, 0, 0); + vlib_set_simple_counter (&sm->total_sessions, ti, 0, 0); + } + /* *INDENT-ON* */ +} + static_always_inline void nat44_user_del_sessions (snat_user_t * u, u32 thread_index) { @@ -113,6 +135,9 @@ nat44_user_del (ip4_address_t * addr, u32 fib_index) snat_user_key_t user_key; clib_bihash_kv_8_8_t kv, value; + if (sm->deterministic || sm->endpoint_dependent) + return rv; + user_key.addr.as_u32 = addr->as_u32; user_key.fib_index = fib_index; kv.key = user_key.as_u64; diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index fe08832c641..ad4c1c8fdbd 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -27,8 +27,15 @@ #include #include + +#define UNSUPPORTED_IN_DET_OR_ED_MODE_STR \ + "This command is unsupported in deterministic or endpoint dependent mode" +#define UNSUPPORTED_IN_DET_OR_NON_ED_MODE_STR \ + "This command is unsupported in deterministic or non endpoint dependent mode" #define UNSUPPORTED_IN_DET_MODE_STR \ "This command is unsupported in deterministic mode" +#define SUPPORTED_ONLY_IN_ED_MODE_STR \ + "This command is supported only in endpoint dependent mode" #define SUPPORTED_ONLY_IN_DET_MODE_STR \ "This command is supported only in deterministic mode" @@ -638,7 +645,7 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, snat_session_t *s; if (sm->deterministic || !sm->endpoint_dependent) - return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR); + return clib_error_return (0, UNSUPPORTED_IN_DET_OR_NON_ED_MODE_STR); // print session configuration values vlib_cli_output (vm, "max translations: %u", sm->max_translations); @@ -1474,11 +1481,11 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, { unformat_input_t _line_input, *line_input = &_line_input; clib_error_t *error = 0; - snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + snat_main_t *sm = &snat_main; - int detail = 0, metrics = 0; - snat_user_t *u; + int detail = 0; int i = 0; if (sm->deterministic) @@ -1491,8 +1498,6 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (unformat (line_input, "detail")) detail = 1; - else if (unformat (line_input, "metrics")) - metrics = 1; else { error = clib_error_return (0, "unknown input '%U'", @@ -1503,7 +1508,11 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, unformat_free (line_input); print: - vlib_cli_output (vm, "NAT44 sessions:"); + if (!sm->endpoint_dependent) + vlib_cli_output (vm, "NAT44 sessions:"); + else + vlib_cli_output (vm, "NAT44 ED sessions:"); + /* *INDENT-OFF* */ vec_foreach_index (i, sm->per_thread_data) { @@ -1512,19 +1521,21 @@ print: vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n", i, vlib_worker_threads[i].name, pool_elts (tsm->sessions)); - if (metrics) + + if (!sm->endpoint_dependent) { - u64 now = vlib_time_now (sm->vlib_main); + snat_user_t *u; pool_foreach (u, tsm->users, ({ - vlib_cli_output (vm, " %U", format_snat_user_v2, tsm, u, now); + vlib_cli_output (vm, " %U", format_snat_user, tsm, u, detail); })); } else { - pool_foreach (u, tsm->users, + snat_session_t *s; + pool_foreach (s, tsm->sessions, ({ - vlib_cli_output (vm, " %U", format_snat_user, tsm, u, detail); + vlib_cli_output (vm, " %U\n", format_snat_session, tsm, s); })); } } @@ -1586,8 +1597,8 @@ nat44_del_user_command_fn (vlib_main_t * vm, u32 fib_index = 0; int rv; - if (sm->deterministic) - return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR); + if (sm->deterministic || sm->endpoint_dependent) + return clib_error_return (0, UNSUPPORTED_IN_DET_OR_ED_MODE_STR); /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1620,6 +1631,21 @@ done: return error; } +static clib_error_t * +nat44_clear_sessions_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + snat_main_t *sm = &snat_main; + clib_error_t *error = 0; + + if (sm->deterministic) + return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR); + + nat44_sessions_clear (); + return error; +} + static clib_error_t * nat44_del_session_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -2653,6 +2679,19 @@ VLIB_CLI_COMMAND (nat44_del_user_command, static) = { .function = nat44_del_user_command_fn, }; +/*? + * @cliexpar + * @cliexstart{clear nat44 sessions} + * To clear all NAT44 sessions + * vpp# clear nat44 sessions + * @cliexend +?*/ +VLIB_CLI_COMMAND (nat44_clear_sessions_command, static) = { + .path = "clear nat44 sessions", + .short_help = "clear nat44 sessions", + .function = nat44_clear_sessions_command_fn, +}; + /*? * @cliexpar * @cliexstart{nat44 del session} diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c index 71bdaa6662c..b9241545096 100644 --- a/src/plugins/nat/nat_format.c +++ b/src/plugins/nat/nat_format.c @@ -117,7 +117,7 @@ format_snat_session_state (u8 * s, va_list * args) u8 * format_snat_session (u8 * s, va_list * args) { - snat_main_per_thread_data_t *sm = + snat_main_per_thread_data_t *tsm = va_arg (*args, snat_main_per_thread_data_t *); snat_session_t *sess = va_arg (*args, snat_session_t *); @@ -153,7 +153,7 @@ format_snat_session (u8 * s, va_list * args) clib_net_to_host_u16 (sess->ext_host_port)); } } - s = format (s, " index %llu\n", sess - sm->sessions); + s = format (s, " index %llu\n", sess - tsm->sessions); s = format (s, " last heard %.2f\n", sess->last_heard); s = format (s, " total pkts %d, total bytes %lld\n", sess->total_pkts, sess->total_bytes); @@ -174,8 +174,6 @@ format_snat_session (u8 * s, va_list * args) u8 * format_snat_user (u8 * s, va_list * args) { - - snat_main_t *sm = &snat_main; snat_main_per_thread_data_t *tsm = va_arg (*args, snat_main_per_thread_data_t *); snat_user_t *u = va_arg (*args, snat_user_t *); @@ -204,7 +202,7 @@ format_snat_user (u8 * s, va_list * args) { sess = pool_elt_at_index (tsm->sessions, session_index); - s = format (s, " %U\n", format_snat_session, sm, sess); + s = format (s, " %U\n", format_snat_session, tsm, sess); elt_index = elt->next; elt = pool_elt_at_index (tsm->list_pool, elt_index); @@ -215,84 +213,6 @@ format_snat_user (u8 * s, va_list * args) return s; } -u8 * -format_snat_user_v2 (u8 * s, va_list * args) -{ - - snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm = - va_arg (*args, snat_main_per_thread_data_t *); - snat_user_t *u = va_arg (*args, snat_user_t *); - u64 now = va_arg (*args, u64); - - dlist_elt_t *head, *elt; - u32 elt_index, head_index; - u32 session_index; - snat_session_t *sess; - - u32 udp_sessions = 0; - u32 tcp_sessions = 0; - u32 icmp_sessions = 0; - - u32 timed_out = 0; - u32 transitory = 0; - u32 established = 0; - - u64 sess_timeout_time; - - if (u->nsessions || u->nstaticsessions) - { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - - elt_index = head->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - session_index = elt->value; - - while (session_index != ~0) - { - sess = pool_elt_at_index (tsm->sessions, session_index); - - sess_timeout_time = sess->last_heard + - (f64) nat44_session_get_timeout (sm, sess); - if (now >= sess_timeout_time) - timed_out++; - - switch (sess->in2out.protocol) - { - case SNAT_PROTOCOL_ICMP: - icmp_sessions++; - break; - case SNAT_PROTOCOL_TCP: - tcp_sessions++; - if (sess->state) - transitory++; - else - established++; - break; - case SNAT_PROTOCOL_UDP: - default: - udp_sessions++; - break; - - } - - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - session_index = elt->value; - } - } - - s = format (s, "%U: %d dynamic translations, %d static translations\n", - format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions); - s = format (s, "\t%u timed out, %u transitory, %u established\n", - timed_out, transitory, established); - s = format (s, "\t%u tcp sessions, %u udp sessions, %u icmp sessions\n", - tcp_sessions, udp_sessions, icmp_sessions); - - return s; -} - u8 * format_snat_static_mapping (u8 * s, va_list * args) { diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index 2c0fa1017d6..1cddc405f07 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -1442,6 +1442,38 @@ class TestNAT44(MethodHolder): def tearDownClass(cls): super(TestNAT44, cls).tearDownClass() + def test_clear_sessions(self): + """ NAT44 session clearing test """ + + self.nat44_add_address(self.nat_addr) + flags = self.config_flags.NAT_IS_INSIDE + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg0.sw_if_index, + flags=flags, is_add=1) + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg1.sw_if_index, + is_add=1) + + nat_config = self.vapi.nat_show_config() + self.assertEqual(0, nat_config.endpoint_dependent) + + pkts = self.create_stream_in(self.pg0, self.pg1) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(len(pkts)) + self.verify_capture_out(capture) + + sessions = self.statistics.get_counter('/nat44/total-sessions') + self.assertTrue(sessions[0][0] > 0) + self.logger.info("sessions before clearing: %s" % sessions[0][0]) + + self.vapi.cli("clear nat44 sessions") + + sessions = self.statistics.get_counter('/nat44/total-sessions') + self.assertEqual(sessions[0][0], 0) + self.logger.info("sessions after clearing: %s" % sessions[0][0]) + def test_dynamic(self): """ NAT44 dynamic translation test """ self.nat44_add_address(self.nat_addr) @@ -4565,6 +4597,43 @@ class TestNAT44EndpointDependent(MethodHolder): self.reass_hairpinning(proto=IP_PROTOS.udp) self.reass_hairpinning(proto=IP_PROTOS.icmp) + def test_clear_sessions(self): + """ NAT44 ED session clearing test """ + + self.nat44_add_address(self.nat_addr) + flags = self.config_flags.NAT_IS_INSIDE + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg0.sw_if_index, + flags=flags, is_add=1) + self.vapi.nat44_interface_add_del_feature( + sw_if_index=self.pg1.sw_if_index, + is_add=1) + + nat_config = self.vapi.nat_show_config() + self.assertEqual(1, nat_config.endpoint_dependent) + + pkts = self.create_stream_in(self.pg0, self.pg1) + self.pg0.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + capture = self.pg1.get_capture(len(pkts)) + self.verify_capture_out(capture) + + sessions = self.statistics.get_counter('/nat44/total-sessions') + self.assertTrue(sessions[0][0] > 0) + self.logger.info("sessions before clearing: %s" % sessions[0][0]) + + # just for testing purposes + self.logger.info(self.vapi.cli("show nat44 summary")) + + self.vapi.cli("clear nat44 sessions") + + self.logger.info(self.vapi.cli("show nat44 summary")) + + sessions = self.statistics.get_counter('/nat44/total-sessions') + self.assertEqual(sessions[0][0], 0) + self.logger.info("sessions after clearing: %s" % sessions[0][0]) + def test_dynamic(self): """ NAT44 dynamic translation test """ -- cgit 1.2.3-korg