From 7801ca29b8f1b3a7b2ff68f3f84a0ae02a58b563 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Thu, 3 Aug 2017 00:58:05 -0700 Subject: [PATCH] SNAT: fix address and port allocation for multiple worker threads (VPP-925) 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 --- src/plugins/snat/in2out.c | 7 ++++--- src/plugins/snat/snat.c | 37 +++++++++++++++++++++++++++---------- src/plugins/snat/snat.h | 11 ++++++++--- src/scripts/vnet/snat | 17 ++++++++++++----- 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c index eb5b9da5dc7..abe0d9dbe87 100644 --- a/src/plugins/snat/in2out.c +++ b/src/plugins/snat/in2out.c @@ -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]; diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index f927915ca6d..9fbc1e542d4 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -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); diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index 61ed52f61e2..aa0f82fc9df 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -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); diff --git a/src/scripts/vnet/snat b/src/scripts/vnet/snat index 87fd699ee51..a711519ecdf 100644 --- a/src/scripts/vnet/snat +++ b/src/scripts/vnet/snat @@ -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 -- 2.16.6