nat: free port_bitmap
[vpp.git] / src / plugins / nat / nat.c
index 0ce1a60..c3583ca 100755 (executable)
@@ -742,6 +742,7 @@ int snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id,
 #define _(N, i, n, s) \
   clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
   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);
   foreach_snat_protocol
 #undef _
@@ -816,6 +817,17 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm,
   rp->is_add = is_add;
   rp->tag = vec_dup (tag);
 }
+                                       
+static u32 get_thread_idx_by_port(u16 e_port)
+{
+    snat_main_t * sm = &snat_main;
+    u32 thread_idx = sm->num_workers;
+    if (sm->num_workers > 1)
+    {
+        thread_idx = sm->first_worker_index + sm->workers[(e_port - 1024) / sm->port_per_thread];
+    }      
+    return thread_idx;
+}
 
 /**
  * @brief Add static mapping.
@@ -1003,7 +1015,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports++; \
-                          a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
+                          a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
                         } \
                       break;
                       foreach_snat_protocol
@@ -1148,7 +1160,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports--; \
-                          a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
+                          a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
                         } \
                       break;
                       foreach_snat_protocol
@@ -1320,7 +1332,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports++; \
-                          a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
+                          a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
                         } \
                       break;
                       foreach_snat_protocol
@@ -1423,7 +1435,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       if (e_port > 1024) \
                         { \
                           a->busy_##n##_ports--; \
-                          a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
+                          a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
                         } \
                       break;
                       foreach_snat_protocol
@@ -1596,6 +1608,12 @@ 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 _
+
   if (twice_nat)
     {
       vec_del1 (sm->twice_nat_addresses, i);
@@ -2062,10 +2080,12 @@ static clib_error_t * snat_init (vlib_main_t * vm)
   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
   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;
   sm->log_class = vlib_log_register_class ("nat", 0);
   error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
   sm->error_node_index = error_drop_node->index;
+  sm->mss_clamping = 0;
 
   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
   if (p)
@@ -2466,6 +2486,57 @@ exhausted:
   return 1;
 }
 
+static int
+nat_alloc_addr_and_port_range (snat_address_t * addresses,
+                               u32 fib_index,
+                               u32 thread_index,
+                               snat_session_key_t * k,
+                               u32 * address_indexp,
+                               u16 port_per_thread,
+                               u32 snat_thread_index)
+{
+  snat_main_t *sm = &snat_main;
+  snat_address_t *a = addresses;
+  u16 portnum, ports;
+
+  ports = sm->end_port - sm->start_port + 1;
+
+  if (!vec_len (addresses))
+    goto exhausted;
+
+  switch (k->protocol)
+    {
+#define _(N, i, n, s) \
+    case SNAT_PROTOCOL_##N: \
+      if (a->busy_##n##_ports < ports) \
+        { \
+          while (1) \
+            { \
+              portnum = snat_random_port(sm->start_port, sm->end_port); \
+              if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
+                continue; \
+              clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
+              a->busy_##n##_ports++; \
+              k->addr = a->addr; \
+              k->port = clib_host_to_net_u16 (portnum); \
+              *address_indexp = i; \
+              return 0; \
+            } \
+        } \
+      break;
+      foreach_snat_protocol
+#undef _
+    default:
+      nat_log_info ("unknown protocol");
+      return 1;
+    }
+
+exhausted:
+  /* Totally out of translations to use... */
+  snat_ipfix_logging_addresses_exhausted(0);
+  return 1;
+}
+
 void
 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
 {
@@ -2522,6 +2593,25 @@ format_snat_protocol (u8 * s, va_list * args)
   return s;
 }
 
+u8 *
+format_nat_addr_and_port_alloc_alg (u8 * s, va_list * args)
+{
+  u32 i = va_arg (*args, u32);
+  u8 *t = 0;
+
+  switch (i)
+    {
+#define _(v, N, s) case NAT_ADDR_AND_PORT_ALLOC_ALG_##N: t = (u8 *) s; break;
+      foreach_nat_addr_and_port_alloc_alg
+#undef _
+    default:
+      s = format (s, "unknown");
+      return s;
+    }
+  s = format (s, "%s", t);
+  return s;
+}
+
 u8 * format_snat_key (u8 * s, va_list * args);
 u8 * format_static_mapping_key (u8 * s, va_list * args);
 
@@ -3550,17 +3640,30 @@ nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
 {
   snat_main_t *sm = &snat_main;
 
+  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
   sm->psid = psid;
   sm->psid_offset = psid_offset;
   sm->psid_length = psid_length;
 }
 
+void
+nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
+{
+  snat_main_t *sm = &snat_main;
+
+  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
+  sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
+  sm->start_port = start_port;
+  sm->end_port = end_port;
+}
+
 void
 nat_set_alloc_addr_and_port_default (void)
 {
   snat_main_t *sm = &snat_main;
 
+  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
 }