nat: enable force session cleanup 15/26615/9
authorFilip Varga <fivarga@cisco.com>
Sun, 19 Apr 2020 17:44:49 +0000 (19:44 +0200)
committerOle Trøan <otroan@employees.org>
Wed, 6 May 2020 08:46:45 +0000 (08:46 +0000)
Force session cleanup drops NAT db.
Also fixing user specific cli/api calls.

Type: improvement

Change-Id: Ia3e25fcf07fe5fb9a83d55c03fe90aca727b41ac
Signed-off-by: Filip Varga <fivarga@cisco.com>
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44/inlines.h
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat_format.c
src/plugins/nat/test/test_nat.py

index 7cb0b53..c30324b 100755 (executable)
@@ -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
        {
index 9331901..bc998da 100644 (file)
@@ -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
  *
index 229daa2..a5118ea 100644 (file)
@@ -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;
index fe08832..ad4c1c8 100644 (file)
 #include <vnet/fib/fib_table.h>
 #include <nat/nat_ha.h>
 
+
+#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}
index 71bdaa6..b924154 100644 (file)
@@ -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)
 {
index 2c0fa10..1cddc40 100644 (file)
@@ -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 """