nat: simplify bihash buckets/mem config 44/27444/9
authorKlement Sekera <ksekera@cisco.com>
Fri, 27 Mar 2020 10:54:53 +0000 (11:54 +0100)
committerOle Trøan <otroan@employees.org>
Thu, 11 Jun 2020 08:02:16 +0000 (08:02 +0000)
Derive reasonable values from max translations/max users.

Type: improvement
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I41a96ab63ab138b4160cd60bd6df24fc73791c86

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_inlines.h
src/plugins/nat/test/test_nat.py

index 7ed0a22..b8febc1 100644 (file)
@@ -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;
     }
index 2e316f5..49e3812 100644 (file)
@@ -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;
        }
index ed01bb4..36d03a6 100644 (file)
@@ -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);
index 8b04e18..d5b236d 100644 (file)
@@ -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;
index 6e462d7..8bfc740 100644 (file)
@@ -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;
 }
index ffc5fd4..18f51b1 100644 (file)
@@ -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);
 
index 240ff0e..40ac3d3 100644 (file)
@@ -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;
index 97f473c..6dee818 100644 (file)
@@ -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'))