nat: use correct data types for memory sizes
[vpp.git] / src / plugins / nat / nat.c
index bc2f8c0..8e20df4 100755 (executable)
@@ -33,6 +33,7 @@
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/ip/reass/ip4_sv_reass.h>
+#include <vppinfra/bihash_16_8.h>
 
 #include <vpp/app/version.h>
 
@@ -322,6 +323,16 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
   if (snat_is_session_static (s))
     return;
 
+  ed_bihash_kv_t bihash_key;
+  clib_memset (&bihash_key, 0, sizeof (bihash_key));
+  bihash_key.k.dst_address = s->ext_host_addr.as_u32;
+  bihash_key.k.dst_port = s->ext_host_port;
+  bihash_key.k.src_address = s->out2in.addr.as_u32;
+  bihash_key.k.src_port = s->out2in.port;
+  bihash_key.k.protocol = s->out2in.protocol;
+  clib_bihash_add_del_16_8 (&sm->ed_ext_ports, &bihash_key.kv,
+                           0 /* is_add */ );
+
   snat_free_outside_address_and_port (sm->addresses, thread_index,
                                      &s->out2in);
 }
@@ -447,6 +458,16 @@ nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
   if (snat_is_session_static (s))
     return;
 
+  ed_bihash_kv_t bihash_key;
+  clib_memset (&bihash_key, 0, sizeof (bihash_key));
+  bihash_key.k.dst_address = s->ext_host_addr.as_u32;
+  bihash_key.k.dst_port = s->ext_host_port;
+  bihash_key.k.src_address = s->out2in.addr.as_u32;
+  bihash_key.k.src_port = s->out2in.port;
+  bihash_key.k.protocol = s->out2in.protocol;
+  clib_bihash_add_del_16_8 (&sm->ed_ext_ports, &bihash_key.kv,
+                           0 /* is_add */ );
+
   // should be called for every dynamic session
   snat_free_outside_address_and_port (sm->addresses, thread_index,
                                      &s->out2in);
@@ -490,7 +511,11 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
 
       /* add user */
       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
-       nat_elog_warn ("user_hash keay add failed");
+       {
+         nat_elog_warn ("user_hash key add failed");
+         nat44_delete_user_with_no_session (sm, u, thread_index);
+         return NULL;
+       }
 
       vlib_set_simple_counter (&sm->total_users, thread_index, 0,
                               pool_elts (tsm->users));
@@ -568,6 +593,14 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
                          s->per_user_list_head_index,
                          per_user_translation_list_elt - tsm->list_pool);
 
+      dlist_elt_t *global_lru_list_elt;
+      pool_get (tsm->global_lru_pool, global_lru_list_elt);
+      global_lru_list_elt->value = s - tsm->sessions;
+      s->global_lru_index = global_lru_list_elt - tsm->global_lru_pool;
+      clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
+                         s->global_lru_index);
+      s->last_lru_update = now;
+
       s->user_index = u - tsm->users;
       vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
                               pool_elts (tsm->sessions));
@@ -582,7 +615,7 @@ snat_session_t *
 nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
                      f64 now)
 {
-  snat_session_t *s;
+  snat_session_t *s = NULL;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
 
   dlist_elt_t *oldest_elt;
@@ -608,6 +641,7 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
       return 0;
     }
 
+  /* first try to reuse an expired session from this ip */
   oldest_index =
     clib_dlist_remove_head (tsm->list_pool,
                            u->sessions_per_user_list_head_index);
@@ -615,19 +649,51 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
   s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
 
   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
-  if (now >= sess_timeout_time)
+  if (now >= sess_timeout_time ||
+      (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
     {
       // reuse old session
       clib_dlist_addtail (tsm->list_pool,
                          u->sessions_per_user_list_head_index, oldest_index);
       s = nat44_session_reuse_old (sm, u, s, thread_index, now);
+      s->last_lru_update = now;
     }
   else
     {
-      // alloc new session
       clib_dlist_addhead (tsm->list_pool,
                          u->sessions_per_user_list_head_index, oldest_index);
-    alloc_new:
+      s = NULL;
+    }
+
+alloc_new:
+  /* try to free an expired session from global LRU list */
+  if (!s)
+    {
+      oldest_index = clib_dlist_remove_head (tsm->global_lru_pool,
+                                            tsm->global_lru_head_index);
+      if (~0 != oldest_index)
+       {
+         oldest_elt = pool_elt_at_index (tsm->global_lru_pool, oldest_index);
+         s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
+
+         sess_timeout_time =
+           s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+         if (now >= sess_timeout_time
+             || (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
+           {
+             nat_free_session_data (sm, s, thread_index, 0);
+             nat44_ed_delete_session (sm, s, thread_index, 0);
+           }
+         else
+           {
+             clib_dlist_addhead (tsm->global_lru_pool,
+                                 tsm->global_lru_head_index, oldest_index);
+           }
+         s = NULL;
+       }
+    }
+  if (!s)
+    {
       s = nat44_session_alloc_new (tsm, u, now);
       vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
                               pool_elts (tsm->sessions));
@@ -696,7 +762,7 @@ snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
   else
     ap->fib_index = ~0;
 #define _(N, i, n, s) \
-  clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
+  clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
   ap->busy_##n##_ports = 0; \
   ap->busy_##n##_ports_per_thread = 0;\
   vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
@@ -975,9 +1041,9 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
                    {
 #define _(N, j, n, s) \
                     case SNAT_PROTOCOL_##N: \
-                      if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
+                      if (a->busy_##n##_port_refcounts[e_port]) \
                         return VNET_API_ERROR_INVALID_VALUE; \
-                      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
+                      ++a->busy_##n##_port_refcounts[e_port]; \
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports++; \
@@ -1159,7 +1225,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
                    {
 #define _(N, j, n, s) \
                     case SNAT_PROTOCOL_##N: \
-                      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
+                      --a->busy_##n##_port_refcounts[e_port]; \
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports--; \
@@ -1338,9 +1404,9 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                    {
 #define _(N, j, n, s) \
                     case SNAT_PROTOCOL_##N: \
-                      if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
+                      if (a->busy_##n##_port_refcounts[e_port]) \
                         return VNET_API_ERROR_INVALID_VALUE; \
-                      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
+                      ++a->busy_##n##_port_refcounts[e_port]; \
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports++; \
@@ -1454,7 +1520,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                    {
 #define _(N, j, n, s) \
                     case SNAT_PROTOCOL_##N: \
-                      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
+                      --a->busy_##n##_port_refcounts[e_port]; \
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports--; \
@@ -1821,7 +1887,6 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
     }
 
 #define _(N, i, n, s) \
-  clib_bitmap_free (a->busy_##n##_port_bitmap); \
   vec_free (a->busy_##n##_ports_per_thread);
   foreach_snat_protocol
 #undef _
@@ -2646,10 +2711,8 @@ snat_free_outside_address_and_port (snat_address_t * addresses,
     {
 #define _(N, i, n, s) \
     case SNAT_PROTOCOL_##N: \
-      ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
-        port_host_byte_order) == 1); \
-      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
-        port_host_byte_order, 0); \
+      ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
+      --a->busy_##n##_port_refcounts[port_host_byte_order]; \
       a->busy_##n##_ports--; \
       a->busy_##n##_ports_per_thread[thread_index]--; \
       break;
@@ -2680,9 +2743,9 @@ nat_set_outside_address_and_port (snat_address_t * addresses,
        {
 #define _(N, j, n, s) \
         case SNAT_PROTOCOL_##N: \
-          if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
+          if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
             return VNET_API_ERROR_INSTANCE_IN_USE; \
-          clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
+         ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
           a->busy_##n##_ports_per_thread[thread_index]++; \
           a->busy_##n##_ports++; \
           return 0;
@@ -2897,9 +2960,9 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses,
                       portnum = (port_per_thread * \
                         snat_thread_index) + \
                         snat_random_port(1, port_per_thread) + 1024; \
-                      if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+                      if (a->busy_##n##_port_refcounts[portnum]) \
                         continue; \
-                      clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+                     --a->busy_##n##_port_refcounts[portnum]; \
                       a->busy_##n##_ports_per_thread[thread_index]++; \
                       a->busy_##n##_ports++; \
                       k->addr = a->addr; \
@@ -2934,9 +2997,9 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses,
               portnum = (port_per_thread * \
                 snat_thread_index) + \
                 snat_random_port(1, port_per_thread) + 1024; \
-              if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+             if (a->busy_##n##_port_refcounts[portnum]) \
                 continue; \
-              clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+             ++a->busy_##n##_port_refcounts[portnum]; \
               a->busy_##n##_ports_per_thread[thread_index]++; \
               a->busy_##n##_ports++; \
               k->addr = a->addr; \
@@ -2984,9 +3047,9 @@ nat_alloc_addr_and_port_mape (snat_address_t * addresses,
               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
               j = snat_random_port(0, pow2_mask(m)); \
               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
-              if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+             if (a->busy_##n##_port_refcounts[portnum]) \
                 continue; \
-              clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+             ++a->busy_##n##_port_refcounts[portnum]; \
               a->busy_##n##_ports++; \
               k->addr = a->addr; \
               k->port = clib_host_to_net_u16 (portnum); \
@@ -3032,9 +3095,9 @@ nat_alloc_addr_and_port_range (snat_address_t * addresses,
           while (1) \
             { \
               portnum = snat_random_port(sm->start_port, sm->end_port); \
-              if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+             if (a->busy_##n##_port_refcounts[portnum]) \
                 continue; \
-              clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+             ++a->busy_##n##_port_refcounts[portnum]; \
               a->busy_##n##_ports++; \
               k->addr = a->addr; \
               k->port = clib_host_to_net_u16 (portnum); \
@@ -3854,18 +3917,18 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   snat_main_per_thread_data_t *tsm;
 
   u32 static_mapping_buckets = 1024;
-  u32 static_mapping_memory_size = 64 << 20;
+  uword static_mapping_memory_size = 64 << 20;
 
   u32 nat64_bib_buckets = 1024;
   u32 nat64_bib_memory_size = 128 << 20;
 
   u32 nat64_st_buckets = 2048;
-  u32 nat64_st_memory_size = 256 << 20;
+  uword nat64_st_memory_size = 256 << 20;
 
   u32 user_buckets = 128;
-  u32 user_memory_size = 64 << 20;
+  uword user_memory_size = 64 << 20;
   u32 translation_buckets = 1024;
-  u32 translation_memory_size = 128 << 20;
+  uword translation_memory_size = 128 << 20;
 
   u32 max_translations_per_user = ~0;
 
@@ -4050,6 +4113,16 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
               tsm->cleanup_runs = 0;
               tsm->cleanup_timeout = 0;
 
+              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",
@@ -4063,6 +4136,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
                                          translation_memory_size);
                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
                                                       format_ed_session_kvp);
+                  clib_bihash_init_16_8
+                  (&sm->ed_ext_ports, "ed-nat-5-tuple-port-overload-hash",
+                   translation_buckets, translation_memory_size);
                 }
               else
                 {