SNAT: fix address and port allocation for multiple worker threads (VPP-925) 93/7893/5
authorMatus Fabian <matfabia@cisco.com>
Thu, 3 Aug 2017 07:58:05 +0000 (00:58 -0700)
committerNeale Ranns <nranns@cisco.com>
Fri, 4 Aug 2017 08:21:27 +0000 (08:21 +0000)
There is a chance to allocate the same outside address and port.
Assign a block of port numbers to each worker.

Change-Id: I6ef7dc0aab4834705f4e6097c362940d18d747e8
Signed-off-by: Matus Fabian <matfabia@cisco.com>
src/plugins/snat/in2out.c
src/plugins/snat/snat.c
src/plugins/snat/snat.h
src/scripts/vnet/snat

index eb5b9da..abe0d9d 100644 (file)
@@ -356,8 +356,8 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
         }
       s->outside_address_index = ~0;
 
-      if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
-                                               &address_index))
+      if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, thread_index,
+                                               &key1, &address_index))
         {
           ASSERT(0);
 
@@ -375,7 +375,8 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0,
         {
           static_mapping = 0;
           /* Try to create dynamic translation */
-          if (snat_alloc_outside_address_and_port (sm, rx_fib_index0, &key1,
+          if (snat_alloc_outside_address_and_port (sm, rx_fib_index0,
+                                                   thread_index, &key1,
                                                    &address_index))
             {
               b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
index f927915..9fbc1e5 100644 (file)
@@ -888,7 +888,7 @@ fib:
 int snat_set_workers (uword * bitmap)
 {
   snat_main_t *sm = &snat_main;
-  int i;
+  int i, j = 0;
 
   if (sm->num_workers < 2)
     return VNET_API_ERROR_FEATURE_DISABLED;
@@ -900,8 +900,13 @@ int snat_set_workers (uword * bitmap)
   clib_bitmap_foreach (i, bitmap,
     ({
       vec_add1(sm->workers, i);
+      sm->per_thread_data[i].snat_thread_index = j;
+      j++;
     }));
 
+  sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
+  sm->num_snat_thread = _vec_len (sm->workers);
+
   return 0;
 }
 
@@ -936,7 +941,9 @@ static clib_error_t * snat_init (vlib_main_t * vm)
   sm->first_worker_index = 0;
   sm->next_worker = 0;
   sm->num_workers = 0;
+  sm->num_snat_thread = 1;
   sm->workers = 0;
+  sm->port_per_thread = 0xffff - 1024;
   sm->fq_in2out_index = ~0;
   sm->fq_out2in_index = ~0;
   sm->udp_timeout = SNAT_UDP_TIMEOUT;
@@ -955,6 +962,8 @@ static clib_error_t * snat_init (vlib_main_t * vm)
         }
     }
 
+  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
+
   /* Use all available workers by default */
   if (sm->num_workers > 1)
     {
@@ -963,6 +972,10 @@ static clib_error_t * snat_init (vlib_main_t * vm)
       snat_set_workers(bitmap);
       clib_bitmap_free (bitmap);
     }
+  else
+    {
+      sm->per_thread_data[0].snat_thread_index = 0;
+    }
 
   error = snat_api_init(vm, sm);
   if (error)
@@ -1081,8 +1094,16 @@ int snat_static_mapping_match (snat_main_t * sm,
   return 0;
 }
 
-int snat_alloc_outside_address_and_port (snat_main_t * sm, 
+static_always_inline u16
+snat_random_port (snat_main_t * sm, u16 min, u16 max)
+{
+  return min + random_u32 (&sm->random_seed) /
+    (random_u32_max() / (max - min + 1) + 1);
+}
+
+int snat_alloc_outside_address_and_port (snat_main_t * sm,
                                          u32 fib_index,
+                                         u32 thread_index,
                                          snat_session_key_t * k,
                                          u32 * address_indexp)
 {
@@ -1099,14 +1120,13 @@ int snat_alloc_outside_address_and_port (snat_main_t * sm,
         {
 #define _(N, j, n, s) \
         case SNAT_PROTOCOL_##N: \
-          if (a->busy_##n##_ports < (65535-1024)) \
+          if (a->busy_##n##_ports < (sm->port_per_thread * sm->num_snat_thread)) \
             { \
               while (1) \
                 { \
-                  portnum = random_u32 (&sm->random_seed); \
-                  portnum &= 0xFFFF; \
-                  if (portnum < 1024) \
-                    continue; \
+                  portnum = (sm->port_per_thread * \
+                    sm->per_thread_data[thread_index].snat_thread_index) + \
+                    snat_random_port(sm, 0, sm->port_per_thread) + 1024; \
                   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); \
@@ -1731,7 +1751,6 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
   u32 static_mapping_memory_size = 64<<20;
   u8 static_mapping_only = 0;
   u8 static_mapping_connection_tracking = 0;
-  vlib_thread_main_t *tm = vlib_get_thread_main ();
 
   sm->deterministic = 0;
 
@@ -1810,8 +1829,6 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
           clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
                                 user_memory_size);
 
-          vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
-
           clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
                                 translation_memory_size);
 
index 61ed52f..aa0f82f 100644 (file)
@@ -241,6 +241,8 @@ typedef struct {
 
   /* Pool of doubly-linked list elements */
   dlist_elt_t * list_pool;
+
+  u32 snat_thread_index;
 } snat_main_per_thread_data_t;
 
 struct snat_main_s;
@@ -284,6 +286,8 @@ typedef struct snat_main_s {
   u32 * workers;
   snat_get_worker_function_t * worker_in2out_cb;
   snat_get_worker_function_t * worker_out2in_cb;
+  u16 port_per_thread;
+  u32 num_snat_thread;
 
   /* Per thread data */
   snat_main_per_thread_data_t * per_thread_data;
@@ -374,12 +378,13 @@ extern vlib_node_registration_t snat_det_out2in_node;
 extern vlib_node_registration_t snat_hairpin_dst_node;
 extern vlib_node_registration_t snat_hairpin_src_node;
 
-void snat_free_outside_address_and_port (snat_main_t * sm, 
-                                         snat_session_key_t * k, 
+void snat_free_outside_address_and_port (snat_main_t * sm,
+                                         snat_session_key_t * k,
                                          u32 address_index);
 
-int snat_alloc_outside_address_and_port (snat_main_t * sm, 
+int snat_alloc_outside_address_and_port (snat_main_t * sm,
                                          u32 fib_index,
+                                         u32 thread_index,
                                          snat_session_key_t * k,
                                          u32 * address_indexp);
 
index 87fd699..a711519 100644 (file)
@@ -1,10 +1,13 @@
+create packet-generator interface pg0
+create packet-generator interface pg1
+
 packet-generator new {
   name f1
   limit 1000000
   node ip4-input
   size 64-64
   no-recycle
-  worker 0
+  interface pg0
   data {
     UDP: 10.0.0.3 -> 172.16.1.2
     UDP: 3000 -> 3001
@@ -19,7 +22,7 @@ packet-generator new {
   node ip4-input
   size 64-64
   no-recycle
-  worker 1
+  interface pg0
   data {
     UDP: 10.0.0.3 -> 172.16.1.2
     UDP: 3005 -> 3006
@@ -28,7 +31,11 @@ packet-generator new {
 }
 
 snat add address 172.16.1.3
-ip route 172.16.1.2/32 via drop
 set int ip address pg0 10.0.0.1/24
-set int snat in pg0
-trace add pg-input 10
+set int ip address pg1 172.16.1.1/24
+set int state pg0 up
+set int state pg1 up
+set ip arp static pg0 10.0.0.3 abcd.abcd.abcd
+set ip arp static pg0 10.0.0.4 abcd.abcd.abcd
+set ip arp static pg1 172.16.1.2 cdef.abcd.abcd
+set int snat in pg0 out pg1