summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/nat')
-rw-r--r--src/plugins/nat/in2out.c3
-rw-r--r--src/plugins/nat/in2out_ed.c6
-rw-r--r--src/plugins/nat/nat.c96
-rw-r--r--src/plugins/nat/nat.h5
-rw-r--r--src/plugins/nat/nat44/inlines.h2
-rw-r--r--src/plugins/nat/nat44_cli.c3
-rw-r--r--src/plugins/nat/nat_inlines.h2
-rw-r--r--src/plugins/nat/test/test_nat.py9
8 files changed, 95 insertions, 31 deletions
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index 7ed0a225fef..b8febc17c99 100644
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -273,7 +273,8 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
- nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
+ nat_ipfix_logging_max_sessions (thread_index,
+ sm->max_translations_per_thread);
nat_elog_notice ("maximum sessions exceeded");
return SNAT_IN2OUT_NEXT_DROP;
}
diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c
index 2e316f59c3a..49e3812441e 100644
--- a/src/plugins/nat/in2out_ed.c
+++ b/src/plugins/nat/in2out_ed.c
@@ -351,7 +351,8 @@ slow_path_ed (snat_main_t * sm,
if (!nat_lru_free_one (sm, thread_index, now))
{
b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
- nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
+ nat_ipfix_logging_max_sessions (thread_index,
+ sm->max_translations_per_thread);
nat_elog_notice ("maximum sessions exceeded");
return NAT_NEXT_DROP;
}
@@ -809,7 +810,8 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
(sm, rx_fib_index, thread_index)))
{
b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
- nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
+ nat_ipfix_logging_max_sessions (thread_index,
+ sm->max_translations_per_thread);
nat_elog_notice ("maximum sessions exceeded");
return 0;
}
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index ed01bb4df80..36d03a620d4 100644
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -338,7 +338,7 @@ nat44_set_session_limit (u32 session_limit, u32 vrf_id)
vec_validate (sm->max_translations_per_fib, fib_index + 1);
for (; len < vec_len (sm->max_translations_per_fib); len++)
- sm->max_translations_per_fib[len] = sm->max_translations;
+ sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
}
sm->max_translations_per_fib[fib_index] = session_limit;
@@ -485,6 +485,13 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
/* Ever heard of the "user" = src ip4 address before? */
if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
{
+ if (pool_elts (tsm->users) >= sm->max_users_per_thread)
+ {
+ vlib_increment_simple_counter (&sm->user_limit_reached,
+ thread_index, 0, 1);
+ nat_elog_warn ("maximum user limit reached");
+ return NULL;
+ }
/* no, make a new one */
pool_get (tsm->users, u);
clib_memset (u, 0, sizeof (*u));
@@ -2578,6 +2585,10 @@ snat_init (vlib_main_t * vm)
sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
vlib_validate_simple_counter (&sm->total_sessions, 0);
vlib_zero_simple_counter (&sm->total_sessions, 0);
+ sm->user_limit_reached.name = "user-limit-reached";
+ sm->user_limit_reached.stat_segment_name = "/nat44/user-limit-reached";
+ vlib_validate_simple_counter (&sm->user_limit_reached, 0);
+ vlib_zero_simple_counter (&sm->user_limit_reached, 0);
/* Init IPFIX logging */
snat_ipfix_logging_init (vm);
@@ -3780,13 +3791,25 @@ nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
s->total_bytes = total_bytes;
}
+static u32
+nat_calc_bihash_buckets (u32 n_elts)
+{
+ return 1 << (max_log2 (n_elts >> 1) + 1);
+}
+
+static u32
+nat_calc_bihash_memory (u32 n_buckets, uword kv_size)
+{
+ return n_buckets * (8 + kv_size * 4);
+}
+
void
nat44_db_init (snat_main_per_thread_data_t * tsm)
{
snat_main_t *sm = &snat_main;
- pool_alloc (tsm->sessions, sm->max_translations);
- pool_alloc (tsm->lru_pool, sm->max_translations);
+ pool_alloc (tsm->sessions, sm->max_translations_per_thread);
+ pool_alloc (tsm->lru_pool, sm->max_translations_per_thread);
dlist_elt_t *head;
@@ -3831,7 +3854,7 @@ nat44_db_init (snat_main_per_thread_data_t * tsm)
}
// TODO: resolve static mappings (put only to !ED)
- pool_alloc (tsm->list_pool, sm->max_translations);
+ pool_alloc (tsm->list_pool, sm->max_translations_per_thread);
clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets,
sm->user_memory_size);
clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
@@ -3910,10 +3933,10 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
u32 nat64_st_buckets = 2048;
uword nat64_st_memory_size = 256 << 20;
- u32 user_buckets = 128;
- uword user_memory_size = 64 << 20;
- u32 translation_buckets = 1024;
- uword translation_memory_size = 128 << 20;
+ u32 max_users_per_thread = 0;
+ u32 user_memory_size = 0;
+ u32 max_translations_per_thread = 0;
+ u32 translation_memory_size = 0;
u32 max_translations_per_user = ~0;
@@ -3935,7 +3958,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat
- (input, "translation hash buckets %d", &translation_buckets))
+ (input, "max translations per thread %d",
+ &max_translations_per_thread))
;
else if (unformat (input, "udp timeout %d", &udp_timeout))
;
@@ -3947,7 +3971,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
&tcp_established_timeout));
else if (unformat (input, "translation hash memory %d",
&translation_memory_size));
- else if (unformat (input, "user hash buckets %d", &user_buckets))
+ else
+ if (unformat
+ (input, "max users per thread %d", &max_users_per_thread))
;
else if (unformat (input, "user hash memory %d", &user_memory_size))
;
@@ -4000,6 +4026,17 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
return clib_error_return (0,
"out2in dpo mode available only for simple nat");
+ if (sm->endpoint_dependent && max_users_per_thread > 0)
+ {
+ return clib_error_return (0,
+ "setting 'max users' in endpoint-dependent mode is not supported");
+ }
+
+ if (sm->endpoint_dependent && max_translations_per_user != ~0)
+ {
+ return clib_error_return (0,
+ "setting 'max translations per user' in endpoint-dependent mode is not supported");
+ }
/* optionally configurable timeouts for testing purposes */
sm->udp_timeout = udp_timeout;
@@ -4007,17 +4044,40 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
sm->tcp_established_timeout = tcp_established_timeout;
sm->icmp_timeout = icmp_timeout;
- sm->user_buckets = user_buckets;
- sm->user_memory_size = user_memory_size;
+ if (0 == max_users_per_thread)
+ {
+ max_users_per_thread = 1024;
+ }
+ sm->max_users_per_thread = max_users_per_thread;
+ sm->user_buckets = nat_calc_bihash_buckets (sm->max_users_per_thread);
- sm->translation_buckets = translation_buckets;
+ if (0 == max_translations_per_thread)
+ {
+ // default value based on legacy setting of load factor 10 * default
+ // translation buckets 1024
+ max_translations_per_thread = 10 * 1024;
+ }
+ sm->max_translations_per_thread = max_translations_per_thread;
+ sm->translation_buckets =
+ nat_calc_bihash_buckets (sm->max_translations_per_thread);
+ if (0 == translation_memory_size)
+ {
+ translation_memory_size =
+ nat_calc_bihash_memory (sm->translation_buckets,
+ sizeof (clib_bihash_16_8_t));
+ }
sm->translation_memory_size = translation_memory_size;
- /* do not exceed load factor 10 */
- sm->max_translations = 10 * translation_buckets;
- vec_add1 (sm->max_translations_per_fib, sm->max_translations);
+ if (0 == user_memory_size)
+ {
+ user_memory_size =
+ nat_calc_bihash_memory (sm->max_users_per_thread,
+ sizeof (clib_bihash_8_8_t));
+ }
+ sm->user_memory_size = user_memory_size;
+ vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
sm->max_translations_per_user = max_translations_per_user == ~0 ?
- sm->max_translations : max_translations_per_user;
+ sm->max_translations_per_thread : max_translations_per_user;
sm->outside_vrf_id = outside_vrf_id;
sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
@@ -4062,7 +4122,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
nat_ha_sref_ed_cb);
clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
- translation_buckets,
+ sm->translation_buckets,
translation_memory_size);
clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
format_ed_session_kvp);
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 8b04e18b18b..d5b236dac01 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -635,9 +635,9 @@ typedef struct snat_main_s
u32 translation_buckets;
uword translation_memory_size;
- u32 max_translations;
+ u32 max_translations_per_thread;
u32 *max_translations_per_fib;
-
+ u32 max_users_per_thread;
u32 user_buckets;
uword user_memory_size;
u32 max_translations_per_user;
@@ -660,6 +660,7 @@ typedef struct snat_main_s
/* counters/gauges */
vlib_simple_counter_main_t total_users;
vlib_simple_counter_main_t total_sessions;
+ vlib_simple_counter_main_t user_limit_reached;;
/* API message ID base */
u16 msg_id_base;
diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h
index 6e462d7c36f..8bfc74012e8 100644
--- a/src/plugins/nat/nat44/inlines.h
+++ b/src/plugins/nat/nat44/inlines.h
@@ -26,7 +26,7 @@ static_always_inline u8
nat44_maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
{
if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
- sm->max_translations)
+ sm->max_translations_per_thread)
return 1;
return 0;
}
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index ffc5fd43618..18f51b1a6e1 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -643,7 +643,8 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
if (sm->deterministic || !sm->endpoint_dependent)
return clib_error_return (0, UNSUPPORTED_IN_DET_OR_NON_ED_MODE_STR);
- vlib_cli_output (vm, "max translations: %u", sm->max_translations);
+ vlib_cli_output (vm, "max translations per thread: %u",
+ sm->max_translations_per_thread);
vlib_cli_output (vm, "max translations per user: %u",
sm->max_translations_per_user);
diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h
index 240ff0e7da9..40ac3d307a8 100644
--- a/src/plugins/nat/nat_inlines.h
+++ b/src/plugins/nat/nat_inlines.h
@@ -252,7 +252,7 @@ always_inline u8
maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
{
if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
- sm->max_translations)
+ sm->max_translations_per_thread)
return 1;
return 0;
diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py
index 97f473c95fd..6dee818d4bb 100644
--- a/src/plugins/nat/test/test_nat.py
+++ b/src/plugins/nat/test/test_nat.py
@@ -7214,14 +7214,14 @@ class TestNAT44EndpointDependent(MethodHolder):
class TestNAT44EndpointDependent3(MethodHolder):
""" Endpoint-Dependent mapping and filtering extra test cases """
- translation_buckets = 5
+ max_translations = 50
@classmethod
def setUpConstants(cls):
super(TestNAT44EndpointDependent3, cls).setUpConstants()
cls.vpp_cmdline.extend([
"nat", "{", "endpoint-dependent",
- "translation hash buckets %d" % cls.translation_buckets,
+ "max translations per thread %d" % cls.max_translations,
"}"
])
@@ -7289,9 +7289,8 @@ class TestNAT44EndpointDependent3(MethodHolder):
def test_lru_cleanup(self):
""" LRU cleanup algorithm """
tcp_port_out = self.init_tcp_session(self.pg0, self.pg1, 2000, 80)
- max_translations = 10 * self.translation_buckets
pkts = []
- for i in range(0, max_translations - 1):
+ for i in range(0, self.max_translations - 1):
p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
UDP(sport=7000+i, dport=80))
@@ -7304,7 +7303,7 @@ class TestNAT44EndpointDependent3(MethodHolder):
self.sleep(1.5, "wait for timeouts")
pkts = []
- for i in range(0, max_translations - 1):
+ for i in range(0, self.max_translations - 1):
p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=64) /
ICMP(id=8000+i, type='echo-request'))