nat: timed out session scavenging upgrade 62/25462/14
authorFilip Varga <fivarga@cisco.com>
Tue, 25 Feb 2020 13:31:33 +0000 (14:31 +0100)
committerOle Trøan <otroan@employees.org>
Fri, 13 Mar 2020 11:17:13 +0000 (11:17 +0000)
Patch changes the behavior of session scavenging and fixes multiple
nat issues. Allows proper session clearing and removes issue with lingering sessions
in session db. Patch also updates and fixes CLI/API calls for better readability
of session state metrics. Fixes security issue that would allow attacker to
reuse timed out session in both directions (in2out/out2in).

Type: improvement

Signed-off-by: Filip Varga <fivarga@cisco.com>
Change-Id: I78897585a2a57291fad5db6d457941aa0a0457bd

src/plugins/nat/in2out.c
src/plugins/nat/in2out_ed.c
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_api.c
src/plugins/nat/nat_format.c
src/plugins/nat/out2in.c
src/plugins/nat/out2in_ed.c
src/plugins/nat/test/test_nat.py

index 7b71252..10acf18 100755 (executable)
@@ -264,9 +264,6 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
   };
   nat44_is_idle_session_ctx_t ctx0;
 
-  nat44_session_try_cleanup (&ip0->src_address, rx_fib_index0, thread_index,
-                            now);
-
   if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
     {
       b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
index 581d7b4..ca737d5 100644 (file)
@@ -209,14 +209,18 @@ slow_path_ed (snat_main_t * sm,
   };
   nat44_is_idle_session_ctx_t ctx;
 
-  nat44_session_try_cleanup (&key->l_addr, rx_fib_index, thread_index, now);
+  u32 cleared = 0;
 
   if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
     {
-      b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
-      nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
-      nat_elog_notice ("maximum sessions exceeded");
-      return NAT_NEXT_DROP;
+      if (PREDICT_FALSE
+         (!(cleared = nat44_users_cleanup (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_elog_notice ("maximum sessions exceeded");
+         return NAT_NEXT_DROP;
+       }
     }
 
   key0.addr = key->l_addr;
@@ -224,6 +228,7 @@ slow_path_ed (snat_main_t * sm,
   key1.protocol = key0.protocol = proto;
   key0.fib_index = rx_fib_index;
   key1.fib_index = sm->outside_fib_index;
+
   /* First try to match static mapping by local address and port */
   if (snat_static_mapping_match
       (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
@@ -234,9 +239,16 @@ slow_path_ed (snat_main_t * sm,
                                               sm->port_per_thread,
                                               tsm->snat_thread_index))
        {
-         nat_elog_notice ("addresses exhausted");
-         b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
-         return NAT_NEXT_DROP;
+         if (cleared || !nat44_out_of_ports_cleanup (thread_index, now) ||
+             snat_alloc_outside_address_and_port (sm->addresses,
+                                                  rx_fib_index, thread_index,
+                                                  &key1, sm->port_per_thread,
+                                                  tsm->snat_thread_index))
+           {
+             nat_elog_notice ("addresses exhausted");
+             b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
+             return NAT_NEXT_DROP;
+           }
        }
     }
   else
@@ -246,16 +258,19 @@ slow_path_ed (snat_main_t * sm,
          *sessionp = s;
          return next;
        }
-
       is_sm = 1;
     }
 
-  if (proto == SNAT_PROTOCOL_TCP)
+  if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP))
     {
-      if (!tcp_flags_is_init
-         (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
+      if (PREDICT_FALSE
+         (!tcp_flags_is_init
+          (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
        {
          b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
+         if (!is_sm)
+           snat_free_outside_address_and_port (sm->addresses,
+                                               thread_index, &key1);
          return NAT_NEXT_DROP;
        }
     }
@@ -932,9 +947,23 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
              next0 = def_slow;
              goto trace0;
            }
-
          s0 = pool_elt_at_index (tsm->sessions, value0.value);
 
+         // drop if session expired
+         u64 sess_timeout_time;
+         sess_timeout_time = s0->last_heard +
+           (f64) nat44_session_get_timeout (sm, s0);
+         if (now >= sess_timeout_time)
+           {
+             // delete session
+             nat_free_session_data (sm, s0, thread_index, 0);
+             nat44_delete_session (sm, s0, thread_index);
+
+             next0 = NAT_NEXT_DROP;
+             goto trace0;
+           }
+         //
+
          b0->flags |= VNET_BUFFER_F_IS_NATED;
 
          if (!is_output_feature)
index 0714708..4803eeb 100755 (executable)
@@ -26,6 +26,7 @@
 #include <nat/nat64.h>
 #include <nat/nat66.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat44/inlines.h>
 #include <nat/nat_affinity.h>
 #include <nat/nat_syslog.h>
 #include <nat/nat_ha.h>
@@ -325,6 +326,133 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
                                      &s->out2in);
 }
 
+void
+nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
+                        u32 thread_index, u8 is_ha)
+{
+  snat_session_key_t key;
+  nat_ed_ses_key_t ed_key;
+  clib_bihash_kv_16_8_t ed_kv;
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_index);
+
+  if (is_fwd_bypass_session (s))
+    {
+      if (snat_is_unk_proto_session (s))
+       {
+         ed_key.proto = s->in2out.port;
+         ed_key.r_port = 0;
+         ed_key.l_port = 0;
+       }
+      else
+       {
+         ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+         ed_key.l_port = s->in2out.port;
+         ed_key.r_port = s->ext_host_port;
+       }
+
+      ed_key.l_addr = s->in2out.addr;
+      ed_key.r_addr = s->ext_host_addr;
+      ed_key.fib_index = 0;
+      ed_kv.key[0] = ed_key.as_u64[0];
+      ed_kv.key[1] = ed_key.as_u64[1];
+
+      if (PREDICT_FALSE
+         (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
+       nat_elog_warn ("in2out_ed key del failed");
+      return;
+    }
+
+  /* session lookup tables */
+  if (is_affinity_sessions (s))
+    nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
+                        s->in2out.protocol, s->out2in.port);
+  ed_key.l_addr = s->out2in.addr;
+  ed_key.r_addr = s->ext_host_addr;
+  ed_key.fib_index = s->out2in.fib_index;
+  if (snat_is_unk_proto_session (s))
+    {
+      ed_key.proto = s->in2out.port;
+      ed_key.r_port = 0;
+      ed_key.l_port = 0;
+    }
+  else
+    {
+      ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+      ed_key.l_port = s->out2in.port;
+      ed_key.r_port = s->ext_host_port;
+    }
+  ed_kv.key[0] = ed_key.as_u64[0];
+  ed_kv.key[1] = ed_key.as_u64[1];
+
+  if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
+    nat_elog_warn ("out2in_ed key del failed");
+
+  ed_key.l_addr = s->in2out.addr;
+  ed_key.fib_index = s->in2out.fib_index;
+
+  if (!snat_is_unk_proto_session (s))
+    ed_key.l_port = s->in2out.port;
+
+  if (is_twice_nat_session (s))
+    {
+      ed_key.r_addr = s->ext_host_nat_addr;
+      ed_key.r_port = s->ext_host_nat_port;
+    }
+
+  ed_kv.key[0] = ed_key.as_u64[0];
+  ed_kv.key[1] = ed_key.as_u64[1];
+
+  if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
+    nat_elog_warn ("in2out_ed key del failed");
+
+  if (!is_ha)
+    {
+      nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
+                            &s->in2out.addr, s->in2out.port,
+                            &s->ext_host_nat_addr, s->ext_host_nat_port,
+                            &s->out2in.addr, s->out2in.port,
+                            &s->ext_host_addr, s->ext_host_port,
+                            s->in2out.protocol, is_twice_nat_session (s));
+    }
+
+  if (snat_is_unk_proto_session (s))
+    return;
+
+  // is this correct ?
+  if (!is_ha)
+    {
+      snat_ipfix_logging_nat44_ses_delete (thread_index,
+                                          s->in2out.addr.as_u32,
+                                          s->out2in.addr.as_u32,
+                                          s->in2out.protocol,
+                                          s->in2out.port,
+                                          s->out2in.port,
+                                          s->in2out.fib_index);
+      nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
+                  s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
+                  thread_index);
+    }
+
+  /* Twice NAT address and port for external host */
+  if (is_twice_nat_session (s))
+    {
+      key.protocol = s->in2out.protocol;
+      key.port = s->ext_host_nat_port;
+      key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
+      snat_free_outside_address_and_port (sm->twice_nat_addresses,
+                                         thread_index, &key);
+    }
+
+  if (snat_is_session_static (s))
+    return;
+
+  // should be called for every dynamic session
+  snat_free_outside_address_and_port (sm->addresses, thread_index,
+                                     &s->out2in);
+}
+
+
 snat_user_t *
 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
                        u32 thread_index)
@@ -345,6 +473,9 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
       /* no, make a new one */
       pool_get (tsm->users, u);
       clib_memset (u, 0, sizeof (*u));
+
+      u->min_session_timeout = 0;
+
       u->addr.as_u32 = addr->as_u32;
       u->fib_index = fib_index;
 
@@ -453,13 +584,30 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
 {
   snat_session_t *s;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
-  u32 oldest_index;
+
+  dlist_elt_t *oldest_elt;
   u64 sess_timeout_time;
+  u32 oldest_index;
 
+  // no sessions
   if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
     goto alloc_new;
 
+  // no free sessions
+  if (PREDICT_FALSE
+      ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user))
+    {
+      if (nat44_max_translations_per_user_cleanup (u, thread_index, now))
+       goto alloc_new;
+
+      nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
+                    clib_net_to_host_u32 (u->addr.as_u32));
+      snat_ipfix_logging_max_entries_per_user (thread_index,
+                                              sm->max_translations_per_user,
+                                              u->addr.as_u32);
+      return 0;
+    }
+
   oldest_index =
     clib_dlist_remove_head (tsm->list_pool,
                            u->sessions_per_user_list_head_index);
@@ -469,61 +617,21 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
   if (now >= sess_timeout_time)
     {
+      // reuse old session
       clib_dlist_addtail (tsm->list_pool,
                          u->sessions_per_user_list_head_index, oldest_index);
-      nat_free_session_data (sm, s, thread_index, 0);
-      if (snat_is_session_static (s))
-       u->nstaticsessions--;
-      else
-       u->nsessions--;
-      s->flags = 0;
-      s->total_bytes = 0;
-      s->total_pkts = 0;
-      s->state = 0;
-      s->ext_host_addr.as_u32 = 0;
-      s->ext_host_port = 0;
-      s->ext_host_nat_addr.as_u32 = 0;
-      s->ext_host_nat_port = 0;
+      s = nat44_session_reuse_old (sm, u, s, thread_index, now);
     }
   else
     {
+      // alloc new session
       clib_dlist_addhead (tsm->list_pool,
                          u->sessions_per_user_list_head_index, oldest_index);
-      if ((u->nsessions + u->nstaticsessions) >=
-         sm->max_translations_per_user)
-       {
-         nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
-                        clib_net_to_host_u32 (u->addr.as_u32));
-         snat_ipfix_logging_max_entries_per_user
-           (thread_index, sm->max_translations_per_user, u->addr.as_u32);
-         return 0;
-       }
-      else
-       {
-       alloc_new:
-         pool_get (tsm->sessions, s);
-         clib_memset (s, 0, sizeof (*s));
-
-         /* Create list elts */
-         pool_get (tsm->list_pool, per_user_translation_list_elt);
-         clib_dlist_init (tsm->list_pool,
-                          per_user_translation_list_elt - tsm->list_pool);
-
-         per_user_translation_list_elt->value = s - tsm->sessions;
-         s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
-         s->per_user_list_head_index = u->sessions_per_user_list_head_index;
-
-         clib_dlist_addtail (tsm->list_pool,
-                             s->per_user_list_head_index,
-                             per_user_translation_list_elt - tsm->list_pool);
-       }
-
+    alloc_new:
+      s = nat44_session_alloc_new (tsm, u, now);
       vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
                               pool_elts (tsm->sessions));
     }
-
-  s->ha_last_refreshed = now;
-
   return s;
 }
 
@@ -2370,7 +2478,6 @@ snat_init (vlib_main_t * vm)
   sm->fq_in2out_output_index = ~0;
   sm->fq_out2in_index = ~0;
 
-
   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
   sm->forwarding_enabled = 0;
@@ -3768,9 +3875,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   u8 static_mapping_only = 0;
   u8 static_mapping_connection_tracking = 0;
 
+  // configurable timeouts
   u32 udp_timeout = SNAT_UDP_TIMEOUT;
   u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
-
   u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
   u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
 
@@ -3851,9 +3958,11 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
 
   /* optionally configurable timeouts for testing purposes */
   sm->udp_timeout = udp_timeout;
-  sm->icmp_timeout = icmp_timeout;
   sm->tcp_transitory_timeout = tcp_transitory_timeout;
   sm->tcp_established_timeout = tcp_established_timeout;
+  sm->icmp_timeout = icmp_timeout;
+
+  sm->min_timeout = nat44_minimal_timeout (sm);
 
   sm->user_buckets = user_buckets;
   sm->user_memory_size = user_memory_size;
@@ -3936,6 +4045,11 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
           vec_foreach (tsm, sm->per_thread_data)
             {
              tsm->min_session_timeout = 0;
+
+              tsm->cleared = 0;
+              tsm->cleanup_runs = 0;
+              tsm->cleanup_timeout = 0;
+
               if (sm->endpoint_dependent)
                 {
                   clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
index 9bcce9d..647bec0 100644 (file)
@@ -349,6 +349,8 @@ typedef struct
   u32 sessions_per_user_list_head_index;
   u32 nsessions;
   u32 nstaticsessions;
+  /* discovered minimum session timeout time */
+  u64 min_session_timeout;
 } snat_user_t;
 
 typedef struct
@@ -519,6 +521,12 @@ typedef struct
 
   /* discovered minimum session timeout time */
   u64 min_session_timeout;
+
+  /* session scavenging */
+  u32 cleared;
+  u32 cleanup_runs;
+  f64 cleanup_timeout;
+
 } snat_main_per_thread_data_t;
 
 struct snat_main_s;
@@ -676,10 +684,14 @@ typedef struct snat_main_s
   u32 inside_fib_index;
 
   /* values of various timeouts */
+
+  // min timeout of all proto timeouts
+  u32 min_timeout;
+  // proto timeouts
   u32 udp_timeout;
-  u32 icmp_timeout;
   u32 tcp_transitory_timeout;
   u32 tcp_established_timeout;
+  u32 icmp_timeout;
 
   /* TCP MSS clamping */
   u16 mss_clamping;
@@ -703,6 +715,7 @@ typedef struct snat_main_s
   ip4_main_t *ip4_main;
   ip_lookup_main_t *ip4_lookup_main;
   api_main_t *api_main;
+
 } snat_main_t;
 
 typedef struct
@@ -750,6 +763,7 @@ 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;
@@ -1293,6 +1307,16 @@ int nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
 void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
                            u32 thread_index, u8 is_ha);
 
+/**
+ * @brief Free NAT44 ED session data (lookup keys, external addrres port)
+ *
+ * @param s            NAT session
+ * @param thread_index thread index
+ * @param is_ha        is HA event
+ */
+void
+nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
+                        u32 thread_index, u8 is_ha);
 /**
  * @brief Find or create NAT user
  *
@@ -1302,8 +1326,9 @@ void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
  *
  * @return NAT user data structure on success otherwise zero value
  */
-snat_user_t *nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr,
-                                    u32 fib_index, u32 thread_index);
+snat_user_t *nat_user_get_or_create (snat_main_t * sm,
+                                    ip4_address_t * addr, u32 fib_index,
+                                    u32 thread_index);
 
 /**
  * @brief Allocate new NAT session or recycle last used
index 0c8487b..7cc2475 100644 (file)
@@ -31,13 +31,66 @@ nat44_maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
   return 0;
 }
 
-static_always_inline void
-nat44_session_cleanup (snat_session_t * s, u32 thread_index)
+static_always_inline f64
+nat44_minimal_timeout (snat_main_t * sm)
 {
-  snat_main_t *sm = &snat_main;
+  f64 min_timeout;
+
+  min_timeout = clib_min (sm->udp_timeout, sm->icmp_timeout);
+  min_timeout = clib_min (min_timeout, sm->icmp_timeout);
+  min_timeout = clib_min (min_timeout, sm->tcp_transitory_timeout);
+  min_timeout = clib_min (min_timeout, sm->tcp_established_timeout);
+
+  return min_timeout;
+}
+
+static_always_inline snat_session_t *
+nat44_session_reuse_old (snat_main_t * sm, snat_user_t * u,
+                        snat_session_t * s, u32 thread_index, f64 now)
+{
+  nat44_free_session_data (sm, s, thread_index, 0);
+  if (snat_is_session_static (s))
+    u->nstaticsessions--;
+  else
+    u->nsessions--;
+  s->flags = 0;
+  s->total_bytes = 0;
+  s->total_pkts = 0;
+  s->state = 0;
+  s->ext_host_addr.as_u32 = 0;
+  s->ext_host_port = 0;
+  s->ext_host_nat_addr.as_u32 = 0;
+  s->ext_host_nat_port = 0;
+  //
+  s->ha_last_refreshed = now;
+  return s;
+}
+
+
+static_always_inline snat_session_t *
+nat44_session_alloc_new (snat_main_per_thread_data_t * tsm, snat_user_t * u,
+                        f64 now)
+{
+  snat_session_t *s;
+  dlist_elt_t *per_user_translation_list_elt;
 
-  nat_free_session_data (sm, s, thread_index, 0);
-  nat44_delete_session (sm, s, thread_index);
+  pool_get (tsm->sessions, s);
+  clib_memset (s, 0, sizeof (*s));
+  /* Create list elts */
+  pool_get (tsm->list_pool, per_user_translation_list_elt);
+  clib_dlist_init (tsm->list_pool,
+                  per_user_translation_list_elt - tsm->list_pool);
+
+  per_user_translation_list_elt->value = s - tsm->sessions;
+  s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
+  s->per_user_list_head_index = u->sessions_per_user_list_head_index;
+
+  clib_dlist_addtail (tsm->list_pool,
+                     s->per_user_list_head_index,
+                     per_user_translation_list_elt - tsm->list_pool);
+
+  s->ha_last_refreshed = now;
+  return s;
 }
 
 static_always_inline void
@@ -59,7 +112,10 @@ nat44_user_del_sessions (snat_user_t * u, u32 thread_index)
     {
       s = pool_elt_at_index (tsm->sessions, elt->value);
       elt = pool_elt_at_index (tsm->list_pool, elt->next);
-      nat44_session_cleanup (s, thread_index);
+
+      nat44_free_session_data (sm, s, thread_index, 0);
+      // TODO: needs refactoring as in nat44_user_session_cleanup
+      nat44_delete_session (sm, s, thread_index);
     }
 }
 
@@ -108,9 +164,10 @@ nat44_user_del (ip4_address_t * addr, u32 fib_index)
   return rv;
 }
 
-static_always_inline void
-nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
+static_always_inline u32
+nat44_user_session_cleanup (snat_user_t * u, u32 thread_index, f64 now)
 {
+  u32 cleared = 0;
   dlist_elt_t *elt;
   snat_session_t *s;
   u64 sess_timeout_time;
@@ -118,6 +175,10 @@ nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
   snat_main_t *sm = &snat_main;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
+  if (now < u->min_session_timeout)
+    goto done;
+  u->min_session_timeout = now + sm->min_timeout;
+
   // get head
   elt = pool_elt_at_index (tsm->list_pool,
                           u->sessions_per_user_list_head_index);
@@ -133,102 +194,121 @@ nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
        (f64) nat44_session_get_timeout (sm, s);
 
       if (now < sess_timeout_time)
-       {
-         tsm->min_session_timeout =
-           clib_min (sess_timeout_time, tsm->min_session_timeout);
-         continue;
-       }
+       continue;
+
+      // do cleanup of this call (refactor for ED NAT44 only)
+      nat44_free_session_data (sm, s, thread_index, 0);
+
+      clib_dlist_remove (tsm->list_pool, s->per_user_index);
+      pool_put_index (tsm->list_pool, s->per_user_index);
+      pool_put (tsm->sessions, s);
+      vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+                              pool_elts (tsm->sessions));
 
-      nat44_session_cleanup (s, thread_index);
+      if (snat_is_session_static (s))
+       u->nstaticsessions--;
+      else
+       u->nsessions--;
+
+      cleared++;
     }
+done:
+  return cleared;
 }
 
-static_always_inline void
-nat44_session_try_cleanup (ip4_address_t * addr,
-                          u32 fib_index, u32 thread_index, f64 now)
+static_always_inline u32
+nat44_users_cleanup (u32 thread_index, f64 now)
 {
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm;
+
+  u32 cleared = 0;
+
+  snat_user_key_t u_key;
+  clib_bihash_kv_8_8_t kv;
+
   snat_user_t *u = 0;
-  snat_user_key_t user_key;
-  clib_bihash_kv_8_8_t kv, value;
+  u32 pool_index;
 
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
 
-  user_key.addr.as_u32 = addr->as_u32;
-  user_key.fib_index = fib_index;
-  kv.key = user_key.as_u64;
+  if (now < tsm->min_session_timeout)
+    goto done;
+  tsm->min_session_timeout = now + sm->min_timeout;
+  // consider
+  tsm->cleanup_timeout = tsm->min_session_timeout;
 
-  // lookup user for this traffic
-  if (PREDICT_FALSE (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)))
+  pool_index = ~0;
+  do
     {
-      // there is still place and a new user can be created
-      if (PREDICT_TRUE (pool_elts (tsm->sessions) < sm->max_translations))
-       return;
+      pool_index = pool_next_index (tsm->users, pool_index);
+      if (pool_index == ~0)
+       break;
+      u = pool_elt_at_index (tsm->users, pool_index);
 
-      if (now >= tsm->min_session_timeout)
-       {
-         tsm->min_session_timeout = ~0;
-         // there is no place so we try to cleanup all users in this thread
-          /* *INDENT-OFF* */
-          pool_foreach (u, tsm->users,
-                        ({ nat44_user_try_cleanup (u, thread_index, now); }));
-          /* *INDENT-ON* */
-         if (~0 == tsm->min_session_timeout)
-           {
-             tsm->min_session_timeout = 0;
-           }
-       }
-      return;
-    }
+      cleared += nat44_user_session_cleanup (u, thread_index, now);
 
-  if (now >= tsm->min_session_timeout)
-    {
-      tsm->min_session_timeout = ~0;
-      // each time user creates a new session we try to cleanup expired sessions
-      nat44_user_try_cleanup (pool_elt_at_index (tsm->users, value.value),
-                             thread_index, now);
-      if (~0 == tsm->min_session_timeout)
+      if (u->nstaticsessions == 0 && u->nsessions == 0)
        {
-         tsm->min_session_timeout = 0;
+         u_key.addr.as_u32 = u->addr.as_u32;
+         u_key.fib_index = u->fib_index;
+         kv.key = u_key.as_u64;
+
+         // delete user
+         pool_put_index (tsm->list_pool,
+                         u->sessions_per_user_list_head_index);
+         pool_put (tsm->users, u);
+         clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
+
+         // update total users counter
+         vlib_set_simple_counter (&sm->total_users, thread_index, 0,
+                                  pool_elts (tsm->users));
        }
     }
+  while (1);
+  tsm->cleared += cleared;
+  tsm->cleanup_runs++;
+done:
+  return cleared;
 }
 
-static_always_inline void
-nat44_force_session_cleanup (void)
+static_always_inline u32
+nat44_out_of_ports_cleanup (u32 thread_index, f64 now)
 {
-  snat_user_t *u = 0;
+  return nat44_users_cleanup (thread_index, now);
+}
+
+static_always_inline u32
+nat44_max_translations_per_user_cleanup (snat_user_t * u, u32 thread_index,
+                                        f64 now)
+{
+  return nat44_user_session_cleanup (u, thread_index, now);
+}
 
+static_always_inline u32
+nat44_force_users_cleanup (void)
+{
   snat_main_t *sm = &snat_main;
   snat_main_per_thread_data_t *tsm;
 
-  vlib_main_t *vm = vlib_get_main ();
-  f64 now = vlib_time_now (vm);
-
-  // TODO: consider own timeouts
+  f64 now = vlib_time_now (vlib_get_main ());
+  u32 cleared = 0;
 
   if (sm->num_workers > 1)
     {
       /* *INDENT-OFF* */
       vec_foreach (tsm, sm->per_thread_data)
         {
-          pool_foreach (u, tsm->users,
-          ({
-            nat44_user_try_cleanup (u, tsm->thread_index, now);
-          }));
+          cleared += nat44_users_cleanup (tsm->thread_index, now);
         }
       /* *INDENT-ON* */
     }
   else
     {
       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
-      /* *INDENT-OFF* */
-      pool_foreach (u, tsm->users,
-      ({
-        nat44_user_try_cleanup (u, tsm->thread_index, now);
-      }));
-      /* *INDENT-ON* */
+      cleared += nat44_users_cleanup (tsm->thread_index, now);
     }
+  return cleared;
 }
 
 #endif /* included_nat44_inlines_h__ */
index 11e8709..45e0069 100644 (file)
@@ -122,9 +122,7 @@ nat44_session_cleanup_command_fn (vlib_main_t * vm,
                                  vlib_cli_command_t * cmd)
 {
   clib_error_t *error = 0;
-
-  nat44_force_session_cleanup ();
-
+  nat44_force_users_cleanup ();
   return error;
 }
 
@@ -645,56 +643,26 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
 {
   snat_main_per_thread_data_t *tsm;
   snat_main_t *sm = &snat_main;
-  snat_address_t *a;
   snat_session_t *s;
-  u32 free_ports, free_ports_addr;
 
-  if (sm->deterministic)
+  if (sm->deterministic || !sm->endpoint_dependent)
     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
 
-  if (sm->endpoint_dependent)
-    vlib_cli_output (vm, "mode: endpoint-depenent");
-
-  // print timeouts
-  vlib_cli_output (vm, "icmp timeout: %u", sm->icmp_timeout);
-  vlib_cli_output (vm, "udp timeout: %u", sm->udp_timeout);
-
-  vlib_cli_output (vm, "tcp established timeout: %u",
-                  sm->tcp_established_timeout);
-  vlib_cli_output (vm, "tcp transitory timeout: %u",
-                  sm->tcp_transitory_timeout);
-
   // print session configuration values
   vlib_cli_output (vm, "max translations: %u", sm->max_translations);
   vlib_cli_output (vm, "max translations per user: %u",
                   sm->max_translations_per_user);
 
-  // do we need also twice-nat addresses ??
-  if (vec_len (sm->addresses))
-    {
-      free_ports = 0;
-      /* *INDENT-OFF* */
-      vec_foreach (a, sm->addresses)
-        {
-          free_ports_addr = sm->port_per_thread;
-
-          #define _(N, i, n, s) \
-            free_ports_addr -= a->busy_##n##_ports;
-            foreach_snat_protocol
-          #undef _
+  u32 count = 0;
 
-          vlib_cli_output (vm, "addr: %U free ports: %u out of: %u",
-              format_ip4_address, &a->addr, free_ports_addr, sm->port_per_thread);
+  u64 now = vlib_time_now (sm->vlib_main);
+  u64 sess_timeout_time;
 
-          free_ports += free_ports_addr;
-        }
-      /* *INDENT-ON* */
-      vlib_cli_output (vm, "free ports overall: %u out of: %u",
-                      free_ports,
-                      vec_len (sm->addresses) * sm->port_per_thread);
-    }
+  u32 udp_sessions = 0;
+  u32 tcp_sessions = 0;
+  u32 icmp_sessions = 0;
 
-  u32 count = 0;
+  u32 timed_out = 0;
   u32 transitory = 0;
   u32 established = 0;
 
@@ -703,14 +671,44 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
       /* *INDENT-OFF* */
       vec_foreach (tsm, sm->per_thread_data)
         {
-          count += vec_len (tsm->sessions);
           pool_foreach (s, tsm->sessions,
           ({
-            if (s->state)
-              transitory++;
-            else
-              established++;
+            sess_timeout_time = s->last_heard +
+             (f64) nat44_session_get_timeout (sm, s);
+            if (now >= sess_timeout_time)
+              timed_out++;
+
+            switch (s->in2out.protocol)
+              {
+              case SNAT_PROTOCOL_ICMP:
+                icmp_sessions++;
+                break;
+              case SNAT_PROTOCOL_TCP:
+                tcp_sessions++;
+                if (s->state)
+                  transitory++;
+                else
+                  established++;
+                break;
+              case SNAT_PROTOCOL_UDP:
+              default:
+                udp_sessions++;
+                break;
+              }
           }));
+          count += pool_elts (tsm->sessions);
+
+          vlib_cli_output (vm, "tid[%u] session scavenging cleared: %u",
+              tsm->thread_index, tsm->cleared);
+          vlib_cli_output (vm, "tid[%u] session scavenging cleanup runs: %u",
+              tsm->thread_index, tsm->cleanup_runs);
+
+          if (now < tsm->cleanup_timeout)
+            vlib_cli_output (vm, "tid[%u] session scavenging next run in: %f",
+              tsm->thread_index, tsm->cleanup_timeout - now);
+          else
+            vlib_cli_output (vm, "tid[%u] session scavenging next run in: 0",
+              tsm->thread_index);
         }
       /* *INDENT-ON* */
     }
@@ -720,17 +718,51 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
       /* *INDENT-OFF* */
       pool_foreach (s, tsm->sessions,
       ({
-        if (s->state)
-          transitory++;
-        else
-          established++;
+        sess_timeout_time = s->last_heard +
+           (f64) nat44_session_get_timeout (sm, s);
+        if (now >= sess_timeout_time)
+          timed_out++;
+
+        switch (s->in2out.protocol)
+          {
+          case SNAT_PROTOCOL_ICMP:
+            icmp_sessions++;
+            break;
+          case SNAT_PROTOCOL_TCP:
+            tcp_sessions++;
+            if (s->state)
+              transitory++;
+            else
+              established++;
+            break;
+          case SNAT_PROTOCOL_UDP:
+          default:
+            udp_sessions++;
+            break;
+          }
       }));
       /* *INDENT-ON* */
-      count = vec_len (tsm->sessions);
+      count = pool_elts (tsm->sessions);
+
+      vlib_cli_output (vm, "tid[0] session scavenging cleared: %u",
+                      tsm->cleared);
+      vlib_cli_output (vm, "tid[0] session scavenging cleanup runs: %u",
+                      tsm->cleanup_runs);
+
+      if (now < tsm->cleanup_timeout)
+       vlib_cli_output (vm, "tid[0] session scavenging next run in: %f",
+                        tsm->cleanup_timeout - now);
+      else
+       vlib_cli_output (vm, "tid[0] session scavenging next run in: 0");
     }
-  vlib_cli_output (vm, "established sessions: %u", established);
-  vlib_cli_output (vm, "transitory sessions: %u", transitory);
-  vlib_cli_output (vm, "sessions: %u", count);
+
+  vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
+  vlib_cli_output (vm, "total sessions: %u", count);
+  vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
+  vlib_cli_output (vm, "total tcp established sessions: %u", established);
+  vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
+  vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
+  vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
   return 0;
 }
 
@@ -1439,20 +1471,38 @@ static clib_error_t *
 nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
                                vlib_cli_command_t * cmd)
 {
-  int verbose = 0;
+  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;
+
+  int detail = 0, metrics = 0;
   snat_user_t *u;
   int i = 0;
 
   if (sm->deterministic)
     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
 
-  if (unformat (input, "detail"))
-    verbose = 1;
+  if (!unformat_user (input, unformat_line_input, line_input))
+    goto print;
 
-  vlib_cli_output (vm, "NAT44 sessions:");
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_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'",
+                                    format_unformat_error, line_input);
+         break;
+       }
+    }
+  unformat_free (line_input);
 
+print:
+  vlib_cli_output (vm, "NAT44 sessions:");
   /* *INDENT-OFF* */
   vec_foreach_index (i, sm->per_thread_data)
     {
@@ -1461,14 +1511,24 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
       vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n",
                        i, vlib_worker_threads[i].name,
                        pool_elts (tsm->sessions));
-      pool_foreach (u, tsm->users,
-      ({
-        vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, verbose);
-      }));
+      if (metrics)
+        {
+          u64 now = vlib_time_now (sm->vlib_main);
+          pool_foreach (u, tsm->users,
+          ({
+            vlib_cli_output (vm, "  %U", format_snat_user_v2, tsm, u, now);
+          }));
+        }
+      else
+        {
+          pool_foreach (u, tsm->users,
+          ({
+            vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, detail);
+          }));
+        }
     }
   /* *INDENT-ON* */
-
-  return 0;
+  return error;
 }
 
 static clib_error_t *
@@ -1896,10 +1956,9 @@ set_timeout_command_fn (vlib_main_t * vm,
          goto done;
        }
     }
-
 done:
   unformat_free (line_input);
-
+  sm->min_timeout = nat44_minimal_timeout (sm);
   return error;
 }
 
@@ -1910,6 +1969,8 @@ nat_show_timeouts_command_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
 
+  // fix text
+  vlib_cli_output (vm, "min session cleanup timeout: %dsec", sm->min_timeout);
   vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
   vlib_cli_output (vm, "tcp-established timeout: %dsec",
                   sm->tcp_established_timeout);
@@ -2535,7 +2596,7 @@ VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
 ?*/
 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
   .path = "show nat44 sessions",
-  .short_help = "show nat44 sessions [detail]",
+  .short_help = "show nat44 sessions [detail|metrics]",
   .function = nat44_show_sessions_command_fn,
 };
 
index d8c2c5f..a71c888 100644 (file)
@@ -247,9 +247,7 @@ vl_api_nat44_session_cleanup_t_handler (vl_api_nat44_session_cleanup_t * mp)
   snat_main_t *sm = &snat_main;
   vl_api_nat44_session_cleanup_reply_t *rmp;
   int rv = 0;
-
-  nat44_force_session_cleanup ();
-
+  nat44_force_users_cleanup ();
   REPLY_MACRO (VL_API_NAT44_SESSION_CLEANUP_REPLY);
 }
 
@@ -338,6 +336,8 @@ vl_api_nat_set_timeouts_t_handler (vl_api_nat_set_timeouts_t * mp)
   sm->tcp_transitory_timeout = ntohl (mp->tcp_transitory);
   sm->icmp_timeout = ntohl (mp->icmp);
 
+  sm->min_timeout = nat44_minimal_timeout (sm);
+
   rv = nat64_set_icmp_timeout (ntohl (mp->icmp));
   if (rv)
     goto send_reply;
@@ -747,10 +747,8 @@ vl_api_nat44_del_user_t_handler (vl_api_nat44_del_user_t * mp)
   vl_api_nat44_del_user_reply_t *rmp;
   ip4_address_t addr;
   int rv;
-
   memcpy (&addr.as_u8, mp->ip_address, 4);
   rv = nat44_user_del (&addr, ntohl (mp->fib_index));
-
   REPLY_MACRO (VL_API_NAT44_DEL_USER_REPLY);
 }
 
index 17f64b9..71bdaa6 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <nat/nat.h>
+#include <nat/nat_inlines.h>
 #include <nat/nat_det.h>
 
 uword
@@ -173,7 +174,9 @@ format_snat_session (u8 * s, va_list * args)
 u8 *
 format_snat_user (u8 * s, va_list * args)
 {
-  snat_main_per_thread_data_t *sm =
+
+  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 *);
   int verbose = va_arg (*args, int);
@@ -191,20 +194,20 @@ format_snat_user (u8 * s, va_list * args)
   if (u->nsessions || u->nstaticsessions)
     {
       head_index = u->sessions_per_user_list_head_index;
-      head = pool_elt_at_index (sm->list_pool, head_index);
+      head = pool_elt_at_index (tsm->list_pool, head_index);
 
       elt_index = head->next;
-      elt = pool_elt_at_index (sm->list_pool, elt_index);
+      elt = pool_elt_at_index (tsm->list_pool, elt_index);
       session_index = elt->value;
 
       while (session_index != ~0)
        {
-         sess = pool_elt_at_index (sm->sessions, session_index);
+         sess = pool_elt_at_index (tsm->sessions, session_index);
 
          s = format (s, "  %U\n", format_snat_session, sm, sess);
 
          elt_index = elt->next;
-         elt = pool_elt_at_index (sm->list_pool, elt_index);
+         elt = pool_elt_at_index (tsm->list_pool, elt_index);
          session_index = elt->value;
        }
     }
@@ -212,6 +215,84 @@ 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 144f324..f920599 100755 (executable)
@@ -188,9 +188,6 @@ create_session_for_static_mapping (snat_main_t * sm,
   udp_header_t *udp0;
   nat44_is_idle_session_ctx_t ctx0;
 
-  nat44_session_try_cleanup (&in2out.addr, in2out.fib_index, thread_index,
-                            now);
-
   if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
     {
       b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
index 91b8d5a..420b7b7 100644 (file)
@@ -203,8 +203,6 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
   snat_session_key_t eh_key;
   nat44_is_idle_session_ctx_t ctx;
 
-  nat44_session_try_cleanup (&l_key.addr, l_key.fib_index, thread_index, now);
-
   if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
@@ -764,6 +762,21 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
            }
          s0 = pool_elt_at_index (tsm->sessions, value0.value);
 
+         // drop if session expired
+         u64 sess_timeout_time;
+         sess_timeout_time = s0->last_heard +
+           (f64) nat44_session_get_timeout (sm, s0);
+         if (now >= sess_timeout_time)
+           {
+             // delete session
+             nat_free_session_data (sm, s0, thread_index, 0);
+             nat44_delete_session (sm, s0, thread_index);
+
+             next0 = NAT_NEXT_DROP;
+             goto trace0;
+           }
+         //
+
          old_addr0 = ip0->dst_address.as_u32;
          new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
          vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
index d16204e..89af40c 100644 (file)
@@ -6886,79 +6886,6 @@ class TestNAT44EndpointDependent(MethodHolder):
                          self.pg0.remote_ip4)
         self.assertEqual(users[0].nsessions, 1)
 
-    @unittest.skipUnless(running_extended_tests, "part of extended tests")
-    def test_session_limit_per_user(self):
-        """ Maximum sessions per user limit """
-        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)
-        self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
-                                     src_address=self.pg2.local_ip4,
-                                     path_mtu=512,
-                                     template_interval=10)
-        self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
-                                   tcp_transitory=240, icmp=60)
-
-        # get maximum number of translations per user
-        nat44_config = self.vapi.nat_show_config()
-
-        pkts = []
-        for port in range(0, nat44_config.max_translations_per_user):
-            p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
-                 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
-                 UDP(sport=1025 + port, dport=1025 + port))
-            pkts.append(p)
-
-        self.pg0.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg1.get_capture(len(pkts))
-
-        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                           src_port=self.ipfix_src_port,
-                                           enable=1)
-
-        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
-             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
-             UDP(sport=3001, dport=3002))
-        self.pg0.add_stream(p)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg1.assert_nothing_captured()
-
-        # verify IPFIX logging
-        self.vapi.ipfix_flush()
-        sleep(1)
-        capture = self.pg2.get_capture(10)
-        ipfix = IPFIXDecoder()
-        # first load template
-        for p in capture:
-            self.assertTrue(p.haslayer(IPFIX))
-            if p.haslayer(Template):
-                ipfix.add_template(p.getlayer(Template))
-        # verify events in data set
-        for p in capture:
-            if p.haslayer(Data):
-                data = ipfix.decode_data_set(p.getlayer(Set))
-                self.verify_ipfix_max_entries_per_user(
-                    data,
-                    nat44_config.max_translations_per_user,
-                    self.pg0.remote_ip4)
-
-        sleep(6)
-        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
-             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
-             UDP(sport=3001, dport=3002))
-        self.pg0.add_stream(p)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        self.pg1.get_capture(1)
-
     def test_syslog_sess(self):
         """ Test syslog session creation and deletion """
         self.vapi.syslog_set_filter(