summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-08-03 00:58:05 -0700
committerNeale Ranns <nranns@cisco.com>2017-08-04 08:21:27 +0000
commit7801ca29b8f1b3a7b2ff68f3f84a0ae02a58b563 (patch)
treedc50748b1e03a0ae93f2214baa7ca98d5e6064fa
parent33129bb9a3e954b7c9ba7a72f16550b1cf91dc9e (diff)
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 <matfabia@cisco.com>
-rw-r--r--src/plugins/snat/in2out.c7
-rw-r--r--src/plugins/snat/snat.c37
-rw-r--r--src/plugins/snat/snat.h11
-rw-r--r--src/scripts/vnet/snat17
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