aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilip Varga <fivarga@cisco.com>2020-02-25 14:31:33 +0100
committerOle Trøan <otroan@employees.org>2020-03-13 11:17:13 +0000
commita73f2d6f53c224668bd6bbea1a980ee4313c794f (patch)
treec40965985639940beb294e8688aedbe30e47a548
parentc27b43673237c3971c1c170646b531728e0d8eb1 (diff)
nat: timed out session scavenging upgrade
Patch changes the behavior of session scavenging and fixes multiple nat issues. Allows proper session clearing and removes issue with lingering sessions in session db. Patch also updates and fixes CLI/API calls for better readability of session state metrics. Fixes security issue that would allow attacker to reuse timed out session in both directions (in2out/out2in). Type: improvement Signed-off-by: Filip Varga <fivarga@cisco.com> Change-Id: I78897585a2a57291fad5db6d457941aa0a0457bd
-rwxr-xr-xsrc/plugins/nat/in2out.c3
-rw-r--r--src/plugins/nat/in2out_ed.c55
-rwxr-xr-xsrc/plugins/nat/nat.c214
-rw-r--r--src/plugins/nat/nat.h31
-rw-r--r--src/plugins/nat/nat44/inlines.h218
-rw-r--r--src/plugins/nat/nat44_cli.c195
-rw-r--r--src/plugins/nat/nat_api.c8
-rw-r--r--src/plugins/nat/nat_format.c91
-rwxr-xr-xsrc/plugins/nat/out2in.c3
-rw-r--r--src/plugins/nat/out2in_ed.c17
-rw-r--r--src/plugins/nat/test/test_nat.py73
11 files changed, 615 insertions, 293 deletions
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index 7b712523f29..10acf187208 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -264,9 +264,6 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
};
nat44_is_idle_session_ctx_t ctx0;
- nat44_session_try_cleanup (&ip0->src_address, rx_fib_index0, thread_index,
- now);
-
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c
index 581d7b4ef60..ca737d56663 100644
--- a/src/plugins/nat/in2out_ed.c
+++ b/src/plugins/nat/in2out_ed.c
@@ -209,14 +209,18 @@ slow_path_ed (snat_main_t * sm,
};
nat44_is_idle_session_ctx_t ctx;
- nat44_session_try_cleanup (&key->l_addr, rx_fib_index, thread_index, now);
+ u32 cleared = 0;
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
- b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
- nat_ipfix_logging_max_sessions (thread_index, sm->max_translations);
- nat_elog_notice ("maximum sessions exceeded");
- return NAT_NEXT_DROP;
+ if (PREDICT_FALSE
+ (!(cleared = nat44_users_cleanup (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_elog_notice ("maximum sessions exceeded");
+ return NAT_NEXT_DROP;
+ }
}
key0.addr = key->l_addr;
@@ -224,6 +228,7 @@ slow_path_ed (snat_main_t * sm,
key1.protocol = key0.protocol = proto;
key0.fib_index = rx_fib_index;
key1.fib_index = sm->outside_fib_index;
+
/* First try to match static mapping by local address and port */
if (snat_static_mapping_match
(sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
@@ -234,9 +239,16 @@ slow_path_ed (snat_main_t * sm,
sm->port_per_thread,
tsm->snat_thread_index))
{
- nat_elog_notice ("addresses exhausted");
- b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
- return NAT_NEXT_DROP;
+ if (cleared || !nat44_out_of_ports_cleanup (thread_index, now) ||
+ snat_alloc_outside_address_and_port (sm->addresses,
+ rx_fib_index, thread_index,
+ &key1, sm->port_per_thread,
+ tsm->snat_thread_index))
+ {
+ nat_elog_notice ("addresses exhausted");
+ b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
+ return NAT_NEXT_DROP;
+ }
}
}
else
@@ -246,16 +258,19 @@ slow_path_ed (snat_main_t * sm,
*sessionp = s;
return next;
}
-
is_sm = 1;
}
- if (proto == SNAT_PROTOCOL_TCP)
+ if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP))
{
- if (!tcp_flags_is_init
- (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
+ if (PREDICT_FALSE
+ (!tcp_flags_is_init
+ (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)))
{
b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN];
+ if (!is_sm)
+ snat_free_outside_address_and_port (sm->addresses,
+ thread_index, &key1);
return NAT_NEXT_DROP;
}
}
@@ -932,9 +947,23 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
next0 = def_slow;
goto trace0;
}
-
s0 = pool_elt_at_index (tsm->sessions, value0.value);
+ // drop if session expired
+ u64 sess_timeout_time;
+ sess_timeout_time = s0->last_heard +
+ (f64) nat44_session_get_timeout (sm, s0);
+ if (now >= sess_timeout_time)
+ {
+ // delete session
+ nat_free_session_data (sm, s0, thread_index, 0);
+ nat44_delete_session (sm, s0, thread_index);
+
+ next0 = NAT_NEXT_DROP;
+ goto trace0;
+ }
+ //
+
b0->flags |= VNET_BUFFER_F_IS_NATED;
if (!is_output_feature)
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 07147083e52..4803eeb64de 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -26,6 +26,7 @@
#include <nat/nat64.h>
#include <nat/nat66.h>
#include <nat/nat_inlines.h>
+#include <nat/nat44/inlines.h>
#include <nat/nat_affinity.h>
#include <nat/nat_syslog.h>
#include <nat/nat_ha.h>
@@ -325,6 +326,133 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
&s->out2in);
}
+void
+nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
+ u32 thread_index, u8 is_ha)
+{
+ snat_session_key_t key;
+ nat_ed_ses_key_t ed_key;
+ clib_bihash_kv_16_8_t ed_kv;
+ snat_main_per_thread_data_t *tsm =
+ vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ if (is_fwd_bypass_session (s))
+ {
+ if (snat_is_unk_proto_session (s))
+ {
+ ed_key.proto = s->in2out.port;
+ ed_key.r_port = 0;
+ ed_key.l_port = 0;
+ }
+ else
+ {
+ ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+ ed_key.l_port = s->in2out.port;
+ ed_key.r_port = s->ext_host_port;
+ }
+
+ ed_key.l_addr = s->in2out.addr;
+ ed_key.r_addr = s->ext_host_addr;
+ ed_key.fib_index = 0;
+ ed_kv.key[0] = ed_key.as_u64[0];
+ ed_kv.key[1] = ed_key.as_u64[1];
+
+ if (PREDICT_FALSE
+ (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
+ nat_elog_warn ("in2out_ed key del failed");
+ return;
+ }
+
+ /* session lookup tables */
+ if (is_affinity_sessions (s))
+ nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
+ s->in2out.protocol, s->out2in.port);
+ ed_key.l_addr = s->out2in.addr;
+ ed_key.r_addr = s->ext_host_addr;
+ ed_key.fib_index = s->out2in.fib_index;
+ if (snat_is_unk_proto_session (s))
+ {
+ ed_key.proto = s->in2out.port;
+ ed_key.r_port = 0;
+ ed_key.l_port = 0;
+ }
+ else
+ {
+ ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
+ ed_key.l_port = s->out2in.port;
+ ed_key.r_port = s->ext_host_port;
+ }
+ ed_kv.key[0] = ed_key.as_u64[0];
+ ed_kv.key[1] = ed_key.as_u64[1];
+
+ if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
+ nat_elog_warn ("out2in_ed key del failed");
+
+ ed_key.l_addr = s->in2out.addr;
+ ed_key.fib_index = s->in2out.fib_index;
+
+ if (!snat_is_unk_proto_session (s))
+ ed_key.l_port = s->in2out.port;
+
+ if (is_twice_nat_session (s))
+ {
+ ed_key.r_addr = s->ext_host_nat_addr;
+ ed_key.r_port = s->ext_host_nat_port;
+ }
+
+ ed_kv.key[0] = ed_key.as_u64[0];
+ ed_kv.key[1] = ed_key.as_u64[1];
+
+ if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
+ nat_elog_warn ("in2out_ed key del failed");
+
+ if (!is_ha)
+ {
+ nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
+ &s->in2out.addr, s->in2out.port,
+ &s->ext_host_nat_addr, s->ext_host_nat_port,
+ &s->out2in.addr, s->out2in.port,
+ &s->ext_host_addr, s->ext_host_port,
+ s->in2out.protocol, is_twice_nat_session (s));
+ }
+
+ if (snat_is_unk_proto_session (s))
+ return;
+
+ // is this correct ?
+ if (!is_ha)
+ {
+ snat_ipfix_logging_nat44_ses_delete (thread_index,
+ s->in2out.addr.as_u32,
+ s->out2in.addr.as_u32,
+ s->in2out.protocol,
+ s->in2out.port,
+ s->out2in.port,
+ s->in2out.fib_index);
+ nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
+ s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
+ thread_index);
+ }
+
+ /* Twice NAT address and port for external host */
+ if (is_twice_nat_session (s))
+ {
+ key.protocol = s->in2out.protocol;
+ key.port = s->ext_host_nat_port;
+ key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
+ snat_free_outside_address_and_port (sm->twice_nat_addresses,
+ thread_index, &key);
+ }
+
+ if (snat_is_session_static (s))
+ return;
+
+ // should be called for every dynamic session
+ snat_free_outside_address_and_port (sm->addresses, thread_index,
+ &s->out2in);
+}
+
+
snat_user_t *
nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
u32 thread_index)
@@ -345,6 +473,9 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
/* no, make a new one */
pool_get (tsm->users, u);
clib_memset (u, 0, sizeof (*u));
+
+ u->min_session_timeout = 0;
+
u->addr.as_u32 = addr->as_u32;
u->fib_index = fib_index;
@@ -453,13 +584,30 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
{
snat_session_t *s;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
- dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
- u32 oldest_index;
+
+ dlist_elt_t *oldest_elt;
u64 sess_timeout_time;
+ u32 oldest_index;
+ // no sessions
if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
goto alloc_new;
+ // no free sessions
+ if (PREDICT_FALSE
+ ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user))
+ {
+ if (nat44_max_translations_per_user_cleanup (u, thread_index, now))
+ goto alloc_new;
+
+ nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
+ clib_net_to_host_u32 (u->addr.as_u32));
+ snat_ipfix_logging_max_entries_per_user (thread_index,
+ sm->max_translations_per_user,
+ u->addr.as_u32);
+ return 0;
+ }
+
oldest_index =
clib_dlist_remove_head (tsm->list_pool,
u->sessions_per_user_list_head_index);
@@ -469,61 +617,21 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
if (now >= sess_timeout_time)
{
+ // reuse old session
clib_dlist_addtail (tsm->list_pool,
u->sessions_per_user_list_head_index, oldest_index);
- nat_free_session_data (sm, s, thread_index, 0);
- if (snat_is_session_static (s))
- u->nstaticsessions--;
- else
- u->nsessions--;
- s->flags = 0;
- s->total_bytes = 0;
- s->total_pkts = 0;
- s->state = 0;
- s->ext_host_addr.as_u32 = 0;
- s->ext_host_port = 0;
- s->ext_host_nat_addr.as_u32 = 0;
- s->ext_host_nat_port = 0;
+ s = nat44_session_reuse_old (sm, u, s, thread_index, now);
}
else
{
+ // alloc new session
clib_dlist_addhead (tsm->list_pool,
u->sessions_per_user_list_head_index, oldest_index);
- if ((u->nsessions + u->nstaticsessions) >=
- sm->max_translations_per_user)
- {
- nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
- clib_net_to_host_u32 (u->addr.as_u32));
- snat_ipfix_logging_max_entries_per_user
- (thread_index, sm->max_translations_per_user, u->addr.as_u32);
- return 0;
- }
- else
- {
- alloc_new:
- pool_get (tsm->sessions, s);
- clib_memset (s, 0, sizeof (*s));
-
- /* Create list elts */
- pool_get (tsm->list_pool, per_user_translation_list_elt);
- clib_dlist_init (tsm->list_pool,
- per_user_translation_list_elt - tsm->list_pool);
-
- per_user_translation_list_elt->value = s - tsm->sessions;
- s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
- s->per_user_list_head_index = u->sessions_per_user_list_head_index;
-
- clib_dlist_addtail (tsm->list_pool,
- s->per_user_list_head_index,
- per_user_translation_list_elt - tsm->list_pool);
- }
-
+ alloc_new:
+ s = nat44_session_alloc_new (tsm, u, now);
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
pool_elts (tsm->sessions));
}
-
- s->ha_last_refreshed = now;
-
return s;
}
@@ -2370,7 +2478,6 @@ snat_init (vlib_main_t * vm)
sm->fq_in2out_output_index = ~0;
sm->fq_out2in_index = ~0;
-
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;
@@ -3768,9 +3875,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
u8 static_mapping_only = 0;
u8 static_mapping_connection_tracking = 0;
+ // configurable timeouts
u32 udp_timeout = SNAT_UDP_TIMEOUT;
u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
-
u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
@@ -3851,9 +3958,11 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
/* optionally configurable timeouts for testing purposes */
sm->udp_timeout = udp_timeout;
- sm->icmp_timeout = icmp_timeout;
sm->tcp_transitory_timeout = tcp_transitory_timeout;
sm->tcp_established_timeout = tcp_established_timeout;
+ sm->icmp_timeout = icmp_timeout;
+
+ sm->min_timeout = nat44_minimal_timeout (sm);
sm->user_buckets = user_buckets;
sm->user_memory_size = user_memory_size;
@@ -3936,6 +4045,11 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
vec_foreach (tsm, sm->per_thread_data)
{
tsm->min_session_timeout = 0;
+
+ tsm->cleared = 0;
+ tsm->cleanup_runs = 0;
+ tsm->cleanup_timeout = 0;
+
if (sm->endpoint_dependent)
{
clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 9bcce9d43cc..647bec0cd07 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -349,6 +349,8 @@ typedef struct
u32 sessions_per_user_list_head_index;
u32 nsessions;
u32 nstaticsessions;
+ /* discovered minimum session timeout time */
+ u64 min_session_timeout;
} snat_user_t;
typedef struct
@@ -519,6 +521,12 @@ typedef struct
/* discovered minimum session timeout time */
u64 min_session_timeout;
+
+ /* session scavenging */
+ u32 cleared;
+ u32 cleanup_runs;
+ f64 cleanup_timeout;
+
} snat_main_per_thread_data_t;
struct snat_main_s;
@@ -676,10 +684,14 @@ typedef struct snat_main_s
u32 inside_fib_index;
/* values of various timeouts */
+
+ // min timeout of all proto timeouts
+ u32 min_timeout;
+ // proto timeouts
u32 udp_timeout;
- u32 icmp_timeout;
u32 tcp_transitory_timeout;
u32 tcp_established_timeout;
+ u32 icmp_timeout;
/* TCP MSS clamping */
u16 mss_clamping;
@@ -703,6 +715,7 @@ typedef struct snat_main_s
ip4_main_t *ip4_main;
ip_lookup_main_t *ip4_lookup_main;
api_main_t *api_main;
+
} snat_main_t;
typedef struct
@@ -750,6 +763,7 @@ extern fib_source_t nat_fib_src_low;
/* format functions */
format_function_t format_snat_user;
+format_function_t format_snat_user_v2;
format_function_t format_snat_static_mapping;
format_function_t format_snat_static_map_to_resolve;
format_function_t format_snat_session;
@@ -1294,6 +1308,16 @@ void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
u32 thread_index, u8 is_ha);
/**
+ * @brief Free NAT44 ED session data (lookup keys, external addrres port)
+ *
+ * @param s NAT session
+ * @param thread_index thread index
+ * @param is_ha is HA event
+ */
+void
+nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
+ u32 thread_index, u8 is_ha);
+/**
* @brief Find or create NAT user
*
* @param addr IPv4 address
@@ -1302,8 +1326,9 @@ void nat_free_session_data (snat_main_t * sm, snat_session_t * s,
*
* @return NAT user data structure on success otherwise zero value
*/
-snat_user_t *nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr,
- u32 fib_index, u32 thread_index);
+snat_user_t *nat_user_get_or_create (snat_main_t * sm,
+ ip4_address_t * addr, u32 fib_index,
+ u32 thread_index);
/**
* @brief Allocate new NAT session or recycle last used
diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h
index 0c8487b473d..7cc24750423 100644
--- a/src/plugins/nat/nat44/inlines.h
+++ b/src/plugins/nat/nat44/inlines.h
@@ -31,13 +31,66 @@ nat44_maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index)
return 0;
}
-static_always_inline void
-nat44_session_cleanup (snat_session_t * s, u32 thread_index)
+static_always_inline f64
+nat44_minimal_timeout (snat_main_t * sm)
{
- snat_main_t *sm = &snat_main;
+ f64 min_timeout;
+
+ min_timeout = clib_min (sm->udp_timeout, sm->icmp_timeout);
+ min_timeout = clib_min (min_timeout, sm->icmp_timeout);
+ min_timeout = clib_min (min_timeout, sm->tcp_transitory_timeout);
+ min_timeout = clib_min (min_timeout, sm->tcp_established_timeout);
+
+ return min_timeout;
+}
+
+static_always_inline snat_session_t *
+nat44_session_reuse_old (snat_main_t * sm, snat_user_t * u,
+ snat_session_t * s, u32 thread_index, f64 now)
+{
+ nat44_free_session_data (sm, s, thread_index, 0);
+ if (snat_is_session_static (s))
+ u->nstaticsessions--;
+ else
+ u->nsessions--;
+ s->flags = 0;
+ s->total_bytes = 0;
+ s->total_pkts = 0;
+ s->state = 0;
+ s->ext_host_addr.as_u32 = 0;
+ s->ext_host_port = 0;
+ s->ext_host_nat_addr.as_u32 = 0;
+ s->ext_host_nat_port = 0;
+ //
+ s->ha_last_refreshed = now;
+ return s;
+}
+
+
+static_always_inline snat_session_t *
+nat44_session_alloc_new (snat_main_per_thread_data_t * tsm, snat_user_t * u,
+ f64 now)
+{
+ snat_session_t *s;
+ dlist_elt_t *per_user_translation_list_elt;
- nat_free_session_data (sm, s, thread_index, 0);
- nat44_delete_session (sm, s, thread_index);
+ pool_get (tsm->sessions, s);
+ clib_memset (s, 0, sizeof (*s));
+ /* Create list elts */
+ pool_get (tsm->list_pool, per_user_translation_list_elt);
+ clib_dlist_init (tsm->list_pool,
+ per_user_translation_list_elt - tsm->list_pool);
+
+ per_user_translation_list_elt->value = s - tsm->sessions;
+ s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
+ s->per_user_list_head_index = u->sessions_per_user_list_head_index;
+
+ clib_dlist_addtail (tsm->list_pool,
+ s->per_user_list_head_index,
+ per_user_translation_list_elt - tsm->list_pool);
+
+ s->ha_last_refreshed = now;
+ return s;
}
static_always_inline void
@@ -59,7 +112,10 @@ nat44_user_del_sessions (snat_user_t * u, u32 thread_index)
{
s = pool_elt_at_index (tsm->sessions, elt->value);
elt = pool_elt_at_index (tsm->list_pool, elt->next);
- nat44_session_cleanup (s, thread_index);
+
+ nat44_free_session_data (sm, s, thread_index, 0);
+ // TODO: needs refactoring as in nat44_user_session_cleanup
+ nat44_delete_session (sm, s, thread_index);
}
}
@@ -108,9 +164,10 @@ nat44_user_del (ip4_address_t * addr, u32 fib_index)
return rv;
}
-static_always_inline void
-nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
+static_always_inline u32
+nat44_user_session_cleanup (snat_user_t * u, u32 thread_index, f64 now)
{
+ u32 cleared = 0;
dlist_elt_t *elt;
snat_session_t *s;
u64 sess_timeout_time;
@@ -118,6 +175,10 @@ nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
snat_main_t *sm = &snat_main;
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ if (now < u->min_session_timeout)
+ goto done;
+ u->min_session_timeout = now + sm->min_timeout;
+
// get head
elt = pool_elt_at_index (tsm->list_pool,
u->sessions_per_user_list_head_index);
@@ -133,102 +194,121 @@ nat44_user_try_cleanup (snat_user_t * u, u32 thread_index, f64 now)
(f64) nat44_session_get_timeout (sm, s);
if (now < sess_timeout_time)
- {
- tsm->min_session_timeout =
- clib_min (sess_timeout_time, tsm->min_session_timeout);
- continue;
- }
+ continue;
+
+ // do cleanup of this call (refactor for ED NAT44 only)
+ nat44_free_session_data (sm, s, thread_index, 0);
+
+ clib_dlist_remove (tsm->list_pool, s->per_user_index);
+ pool_put_index (tsm->list_pool, s->per_user_index);
+ pool_put (tsm->sessions, s);
+ vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+ pool_elts (tsm->sessions));
- nat44_session_cleanup (s, thread_index);
+ if (snat_is_session_static (s))
+ u->nstaticsessions--;
+ else
+ u->nsessions--;
+
+ cleared++;
}
+done:
+ return cleared;
}
-static_always_inline void
-nat44_session_try_cleanup (ip4_address_t * addr,
- u32 fib_index, u32 thread_index, f64 now)
+static_always_inline u32
+nat44_users_cleanup (u32 thread_index, f64 now)
{
+ snat_main_t *sm = &snat_main;
+ snat_main_per_thread_data_t *tsm;
+
+ u32 cleared = 0;
+
+ snat_user_key_t u_key;
+ clib_bihash_kv_8_8_t kv;
+
snat_user_t *u = 0;
- snat_user_key_t user_key;
- clib_bihash_kv_8_8_t kv, value;
+ u32 pool_index;
- snat_main_t *sm = &snat_main;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
- user_key.addr.as_u32 = addr->as_u32;
- user_key.fib_index = fib_index;
- kv.key = user_key.as_u64;
+ if (now < tsm->min_session_timeout)
+ goto done;
+ tsm->min_session_timeout = now + sm->min_timeout;
+ // consider
+ tsm->cleanup_timeout = tsm->min_session_timeout;
- // lookup user for this traffic
- if (PREDICT_FALSE (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)))
+ pool_index = ~0;
+ do
{
- // there is still place and a new user can be created
- if (PREDICT_TRUE (pool_elts (tsm->sessions) < sm->max_translations))
- return;
+ pool_index = pool_next_index (tsm->users, pool_index);
+ if (pool_index == ~0)
+ break;
+ u = pool_elt_at_index (tsm->users, pool_index);
- if (now >= tsm->min_session_timeout)
- {
- tsm->min_session_timeout = ~0;
- // there is no place so we try to cleanup all users in this thread
- /* *INDENT-OFF* */
- pool_foreach (u, tsm->users,
- ({ nat44_user_try_cleanup (u, thread_index, now); }));
- /* *INDENT-ON* */
- if (~0 == tsm->min_session_timeout)
- {
- tsm->min_session_timeout = 0;
- }
- }
- return;
- }
+ cleared += nat44_user_session_cleanup (u, thread_index, now);
- if (now >= tsm->min_session_timeout)
- {
- tsm->min_session_timeout = ~0;
- // each time user creates a new session we try to cleanup expired sessions
- nat44_user_try_cleanup (pool_elt_at_index (tsm->users, value.value),
- thread_index, now);
- if (~0 == tsm->min_session_timeout)
+ if (u->nstaticsessions == 0 && u->nsessions == 0)
{
- tsm->min_session_timeout = 0;
+ u_key.addr.as_u32 = u->addr.as_u32;
+ u_key.fib_index = u->fib_index;
+ kv.key = u_key.as_u64;
+
+ // delete user
+ pool_put_index (tsm->list_pool,
+ u->sessions_per_user_list_head_index);
+ pool_put (tsm->users, u);
+ clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
+
+ // update total users counter
+ vlib_set_simple_counter (&sm->total_users, thread_index, 0,
+ pool_elts (tsm->users));
}
}
+ while (1);
+ tsm->cleared += cleared;
+ tsm->cleanup_runs++;
+done:
+ return cleared;
}
-static_always_inline void
-nat44_force_session_cleanup (void)
+static_always_inline u32
+nat44_out_of_ports_cleanup (u32 thread_index, f64 now)
{
- snat_user_t *u = 0;
+ return nat44_users_cleanup (thread_index, now);
+}
+
+static_always_inline u32
+nat44_max_translations_per_user_cleanup (snat_user_t * u, u32 thread_index,
+ f64 now)
+{
+ return nat44_user_session_cleanup (u, thread_index, now);
+}
+static_always_inline u32
+nat44_force_users_cleanup (void)
+{
snat_main_t *sm = &snat_main;
snat_main_per_thread_data_t *tsm;
- vlib_main_t *vm = vlib_get_main ();
- f64 now = vlib_time_now (vm);
-
- // TODO: consider own timeouts
+ f64 now = vlib_time_now (vlib_get_main ());
+ u32 cleared = 0;
if (sm->num_workers > 1)
{
/* *INDENT-OFF* */
vec_foreach (tsm, sm->per_thread_data)
{
- pool_foreach (u, tsm->users,
- ({
- nat44_user_try_cleanup (u, tsm->thread_index, now);
- }));
+ cleared += nat44_users_cleanup (tsm->thread_index, now);
}
/* *INDENT-ON* */
}
else
{
tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
- /* *INDENT-OFF* */
- pool_foreach (u, tsm->users,
- ({
- nat44_user_try_cleanup (u, tsm->thread_index, now);
- }));
- /* *INDENT-ON* */
+ cleared += nat44_users_cleanup (tsm->thread_index, now);
}
+ return cleared;
}
#endif /* included_nat44_inlines_h__ */
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index 11e87092ae7..45e00693676 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -122,9 +122,7 @@ nat44_session_cleanup_command_fn (vlib_main_t * vm,
vlib_cli_command_t * cmd)
{
clib_error_t *error = 0;
-
- nat44_force_session_cleanup ();
-
+ nat44_force_users_cleanup ();
return error;
}
@@ -645,56 +643,26 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
{
snat_main_per_thread_data_t *tsm;
snat_main_t *sm = &snat_main;
- snat_address_t *a;
snat_session_t *s;
- u32 free_ports, free_ports_addr;
- if (sm->deterministic)
+ if (sm->deterministic || !sm->endpoint_dependent)
return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
- if (sm->endpoint_dependent)
- vlib_cli_output (vm, "mode: endpoint-depenent");
-
- // print timeouts
- vlib_cli_output (vm, "icmp timeout: %u", sm->icmp_timeout);
- vlib_cli_output (vm, "udp timeout: %u", sm->udp_timeout);
-
- vlib_cli_output (vm, "tcp established timeout: %u",
- sm->tcp_established_timeout);
- vlib_cli_output (vm, "tcp transitory timeout: %u",
- sm->tcp_transitory_timeout);
-
// print session configuration values
vlib_cli_output (vm, "max translations: %u", sm->max_translations);
vlib_cli_output (vm, "max translations per user: %u",
sm->max_translations_per_user);
- // do we need also twice-nat addresses ??
- if (vec_len (sm->addresses))
- {
- free_ports = 0;
- /* *INDENT-OFF* */
- vec_foreach (a, sm->addresses)
- {
- free_ports_addr = sm->port_per_thread;
-
- #define _(N, i, n, s) \
- free_ports_addr -= a->busy_##n##_ports;
- foreach_snat_protocol
- #undef _
+ u32 count = 0;
- vlib_cli_output (vm, "addr: %U free ports: %u out of: %u",
- format_ip4_address, &a->addr, free_ports_addr, sm->port_per_thread);
+ u64 now = vlib_time_now (sm->vlib_main);
+ u64 sess_timeout_time;
- free_ports += free_ports_addr;
- }
- /* *INDENT-ON* */
- vlib_cli_output (vm, "free ports overall: %u out of: %u",
- free_ports,
- vec_len (sm->addresses) * sm->port_per_thread);
- }
+ u32 udp_sessions = 0;
+ u32 tcp_sessions = 0;
+ u32 icmp_sessions = 0;
- u32 count = 0;
+ u32 timed_out = 0;
u32 transitory = 0;
u32 established = 0;
@@ -703,14 +671,44 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
/* *INDENT-OFF* */
vec_foreach (tsm, sm->per_thread_data)
{
- count += vec_len (tsm->sessions);
pool_foreach (s, tsm->sessions,
({
- if (s->state)
- transitory++;
- else
- established++;
+ sess_timeout_time = s->last_heard +
+ (f64) nat44_session_get_timeout (sm, s);
+ if (now >= sess_timeout_time)
+ timed_out++;
+
+ switch (s->in2out.protocol)
+ {
+ case SNAT_PROTOCOL_ICMP:
+ icmp_sessions++;
+ break;
+ case SNAT_PROTOCOL_TCP:
+ tcp_sessions++;
+ if (s->state)
+ transitory++;
+ else
+ established++;
+ break;
+ case SNAT_PROTOCOL_UDP:
+ default:
+ udp_sessions++;
+ break;
+ }
}));
+ count += pool_elts (tsm->sessions);
+
+ vlib_cli_output (vm, "tid[%u] session scavenging cleared: %u",
+ tsm->thread_index, tsm->cleared);
+ vlib_cli_output (vm, "tid[%u] session scavenging cleanup runs: %u",
+ tsm->thread_index, tsm->cleanup_runs);
+
+ if (now < tsm->cleanup_timeout)
+ vlib_cli_output (vm, "tid[%u] session scavenging next run in: %f",
+ tsm->thread_index, tsm->cleanup_timeout - now);
+ else
+ vlib_cli_output (vm, "tid[%u] session scavenging next run in: 0",
+ tsm->thread_index);
}
/* *INDENT-ON* */
}
@@ -720,17 +718,51 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
/* *INDENT-OFF* */
pool_foreach (s, tsm->sessions,
({
- if (s->state)
- transitory++;
- else
- established++;
+ sess_timeout_time = s->last_heard +
+ (f64) nat44_session_get_timeout (sm, s);
+ if (now >= sess_timeout_time)
+ timed_out++;
+
+ switch (s->in2out.protocol)
+ {
+ case SNAT_PROTOCOL_ICMP:
+ icmp_sessions++;
+ break;
+ case SNAT_PROTOCOL_TCP:
+ tcp_sessions++;
+ if (s->state)
+ transitory++;
+ else
+ established++;
+ break;
+ case SNAT_PROTOCOL_UDP:
+ default:
+ udp_sessions++;
+ break;
+ }
}));
/* *INDENT-ON* */
- count = vec_len (tsm->sessions);
+ count = pool_elts (tsm->sessions);
+
+ vlib_cli_output (vm, "tid[0] session scavenging cleared: %u",
+ tsm->cleared);
+ vlib_cli_output (vm, "tid[0] session scavenging cleanup runs: %u",
+ tsm->cleanup_runs);
+
+ if (now < tsm->cleanup_timeout)
+ vlib_cli_output (vm, "tid[0] session scavenging next run in: %f",
+ tsm->cleanup_timeout - now);
+ else
+ vlib_cli_output (vm, "tid[0] session scavenging next run in: 0");
}
- vlib_cli_output (vm, "established sessions: %u", established);
- vlib_cli_output (vm, "transitory sessions: %u", transitory);
- vlib_cli_output (vm, "sessions: %u", count);
+
+ vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
+ vlib_cli_output (vm, "total sessions: %u", count);
+ vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
+ vlib_cli_output (vm, "total tcp established sessions: %u", established);
+ vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
+ vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
+ vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
return 0;
}
@@ -1439,20 +1471,38 @@ static clib_error_t *
nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
- int verbose = 0;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ clib_error_t *error = 0;
snat_main_t *sm = &snat_main;
snat_main_per_thread_data_t *tsm;
+
+ int detail = 0, metrics = 0;
snat_user_t *u;
int i = 0;
if (sm->deterministic)
return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
- if (unformat (input, "detail"))
- verbose = 1;
+ if (!unformat_user (input, unformat_line_input, line_input))
+ goto print;
- vlib_cli_output (vm, "NAT44 sessions:");
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "detail"))
+ detail = 1;
+ else if (unformat (line_input, "metrics"))
+ metrics = 1;
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ break;
+ }
+ }
+ unformat_free (line_input);
+print:
+ vlib_cli_output (vm, "NAT44 sessions:");
/* *INDENT-OFF* */
vec_foreach_index (i, sm->per_thread_data)
{
@@ -1461,14 +1511,24 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n",
i, vlib_worker_threads[i].name,
pool_elts (tsm->sessions));
- pool_foreach (u, tsm->users,
- ({
- vlib_cli_output (vm, " %U", format_snat_user, tsm, u, verbose);
- }));
+ if (metrics)
+ {
+ u64 now = vlib_time_now (sm->vlib_main);
+ pool_foreach (u, tsm->users,
+ ({
+ vlib_cli_output (vm, " %U", format_snat_user_v2, tsm, u, now);
+ }));
+ }
+ else
+ {
+ pool_foreach (u, tsm->users,
+ ({
+ vlib_cli_output (vm, " %U", format_snat_user, tsm, u, detail);
+ }));
+ }
}
/* *INDENT-ON* */
-
- return 0;
+ return error;
}
static clib_error_t *
@@ -1896,10 +1956,9 @@ set_timeout_command_fn (vlib_main_t * vm,
goto done;
}
}
-
done:
unformat_free (line_input);
-
+ sm->min_timeout = nat44_minimal_timeout (sm);
return error;
}
@@ -1910,6 +1969,8 @@ nat_show_timeouts_command_fn (vlib_main_t * vm,
{
snat_main_t *sm = &snat_main;
+ // fix text
+ vlib_cli_output (vm, "min session cleanup timeout: %dsec", sm->min_timeout);
vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
vlib_cli_output (vm, "tcp-established timeout: %dsec",
sm->tcp_established_timeout);
@@ -2535,7 +2596,7 @@ VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
?*/
VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
.path = "show nat44 sessions",
- .short_help = "show nat44 sessions [detail]",
+ .short_help = "show nat44 sessions [detail|metrics]",
.function = nat44_show_sessions_command_fn,
};
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index d8c2c5fd1c9..a71c888b6c6 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -247,9 +247,7 @@ vl_api_nat44_session_cleanup_t_handler (vl_api_nat44_session_cleanup_t * mp)
snat_main_t *sm = &snat_main;
vl_api_nat44_session_cleanup_reply_t *rmp;
int rv = 0;
-
- nat44_force_session_cleanup ();
-
+ nat44_force_users_cleanup ();
REPLY_MACRO (VL_API_NAT44_SESSION_CLEANUP_REPLY);
}
@@ -338,6 +336,8 @@ vl_api_nat_set_timeouts_t_handler (vl_api_nat_set_timeouts_t * mp)
sm->tcp_transitory_timeout = ntohl (mp->tcp_transitory);
sm->icmp_timeout = ntohl (mp->icmp);
+ sm->min_timeout = nat44_minimal_timeout (sm);
+
rv = nat64_set_icmp_timeout (ntohl (mp->icmp));
if (rv)
goto send_reply;
@@ -747,10 +747,8 @@ vl_api_nat44_del_user_t_handler (vl_api_nat44_del_user_t * mp)
vl_api_nat44_del_user_reply_t *rmp;
ip4_address_t addr;
int rv;
-
memcpy (&addr.as_u8, mp->ip_address, 4);
rv = nat44_user_del (&addr, ntohl (mp->fib_index));
-
REPLY_MACRO (VL_API_NAT44_DEL_USER_REPLY);
}
diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c
index 17f64b9b222..71bdaa6662c 100644
--- a/src/plugins/nat/nat_format.c
+++ b/src/plugins/nat/nat_format.c
@@ -18,6 +18,7 @@
*/
#include <nat/nat.h>
+#include <nat/nat_inlines.h>
#include <nat/nat_det.h>
uword
@@ -173,7 +174,9 @@ format_snat_session (u8 * s, va_list * args)
u8 *
format_snat_user (u8 * s, va_list * args)
{
- snat_main_per_thread_data_t *sm =
+
+ snat_main_t *sm = &snat_main;
+ snat_main_per_thread_data_t *tsm =
va_arg (*args, snat_main_per_thread_data_t *);
snat_user_t *u = va_arg (*args, snat_user_t *);
int verbose = va_arg (*args, int);
@@ -191,20 +194,20 @@ format_snat_user (u8 * s, va_list * args)
if (u->nsessions || u->nstaticsessions)
{
head_index = u->sessions_per_user_list_head_index;
- head = pool_elt_at_index (sm->list_pool, head_index);
+ head = pool_elt_at_index (tsm->list_pool, head_index);
elt_index = head->next;
- elt = pool_elt_at_index (sm->list_pool, elt_index);
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
session_index = elt->value;
while (session_index != ~0)
{
- sess = pool_elt_at_index (sm->sessions, session_index);
+ sess = pool_elt_at_index (tsm->sessions, session_index);
s = format (s, " %U\n", format_snat_session, sm, sess);
elt_index = elt->next;
- elt = pool_elt_at_index (sm->list_pool, elt_index);
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
session_index = elt->value;
}
}
@@ -213,6 +216,84 @@ format_snat_user (u8 * s, va_list * args)
}
u8 *
+format_snat_user_v2 (u8 * s, va_list * args)
+{
+
+ snat_main_t *sm = &snat_main;
+ snat_main_per_thread_data_t *tsm =
+ va_arg (*args, snat_main_per_thread_data_t *);
+ snat_user_t *u = va_arg (*args, snat_user_t *);
+ u64 now = va_arg (*args, u64);
+
+ dlist_elt_t *head, *elt;
+ u32 elt_index, head_index;
+ u32 session_index;
+ snat_session_t *sess;
+
+ u32 udp_sessions = 0;
+ u32 tcp_sessions = 0;
+ u32 icmp_sessions = 0;
+
+ u32 timed_out = 0;
+ u32 transitory = 0;
+ u32 established = 0;
+
+ u64 sess_timeout_time;
+
+ if (u->nsessions || u->nstaticsessions)
+ {
+ head_index = u->sessions_per_user_list_head_index;
+ head = pool_elt_at_index (tsm->list_pool, head_index);
+
+ elt_index = head->next;
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
+ session_index = elt->value;
+
+ while (session_index != ~0)
+ {
+ sess = pool_elt_at_index (tsm->sessions, session_index);
+
+ sess_timeout_time = sess->last_heard +
+ (f64) nat44_session_get_timeout (sm, sess);
+ if (now >= sess_timeout_time)
+ timed_out++;
+
+ switch (sess->in2out.protocol)
+ {
+ case SNAT_PROTOCOL_ICMP:
+ icmp_sessions++;
+ break;
+ case SNAT_PROTOCOL_TCP:
+ tcp_sessions++;
+ if (sess->state)
+ transitory++;
+ else
+ established++;
+ break;
+ case SNAT_PROTOCOL_UDP:
+ default:
+ udp_sessions++;
+ break;
+
+ }
+
+ elt_index = elt->next;
+ elt = pool_elt_at_index (tsm->list_pool, elt_index);
+ session_index = elt->value;
+ }
+ }
+
+ s = format (s, "%U: %d dynamic translations, %d static translations\n",
+ format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
+ s = format (s, "\t%u timed out, %u transitory, %u established\n",
+ timed_out, transitory, established);
+ s = format (s, "\t%u tcp sessions, %u udp sessions, %u icmp sessions\n",
+ tcp_sessions, udp_sessions, icmp_sessions);
+
+ return s;
+}
+
+u8 *
format_snat_static_mapping (u8 * s, va_list * args)
{
snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c
index 144f324dbf4..f920599b059 100755
--- a/src/plugins/nat/out2in.c
+++ b/src/plugins/nat/out2in.c
@@ -188,9 +188,6 @@ create_session_for_static_mapping (snat_main_t * sm,
udp_header_t *udp0;
nat44_is_idle_session_ctx_t ctx0;
- nat44_session_try_cleanup (&in2out.addr, in2out.fib_index, thread_index,
- now);
-
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index 91b8d5a8aae..420b7b7a863 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -203,8 +203,6 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
snat_session_key_t eh_key;
nat44_is_idle_session_ctx_t ctx;
- nat44_session_try_cleanup (&l_key.addr, l_key.fib_index, thread_index, now);
-
if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index)))
{
b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
@@ -764,6 +762,21 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
}
s0 = pool_elt_at_index (tsm->sessions, value0.value);
+ // drop if session expired
+ u64 sess_timeout_time;
+ sess_timeout_time = s0->last_heard +
+ (f64) nat44_session_get_timeout (sm, s0);
+ if (now >= sess_timeout_time)
+ {
+ // delete session
+ nat_free_session_data (sm, s0, thread_index, 0);
+ nat44_delete_session (sm, s0, thread_index);
+
+ next0 = NAT_NEXT_DROP;
+ goto trace0;
+ }
+ //
+
old_addr0 = ip0->dst_address.as_u32;
new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32;
vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py
index d16204e7217..89af40c4d18 100644
--- a/src/plugins/nat/test/test_nat.py
+++ b/src/plugins/nat/test/test_nat.py
@@ -6886,79 +6886,6 @@ class TestNAT44EndpointDependent(MethodHolder):
self.pg0.remote_ip4)
self.assertEqual(users[0].nsessions, 1)
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
- def test_session_limit_per_user(self):
- """ Maximum sessions per user limit """
- self.nat44_add_address(self.nat_addr)
- flags = self.config_flags.NAT_IS_INSIDE
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg0.sw_if_index,
- flags=flags, is_add=1)
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg1.sw_if_index,
- is_add=1)
- self.vapi.set_ipfix_exporter(collector_address=self.pg2.remote_ip4,
- src_address=self.pg2.local_ip4,
- path_mtu=512,
- template_interval=10)
- self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
- tcp_transitory=240, icmp=60)
-
- # get maximum number of translations per user
- nat44_config = self.vapi.nat_show_config()
-
- pkts = []
- for port in range(0, nat44_config.max_translations_per_user):
- p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
- UDP(sport=1025 + port, dport=1025 + port))
- pkts.append(p)
-
- self.pg0.add_stream(pkts)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- capture = self.pg1.get_capture(len(pkts))
-
- self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
- src_port=self.ipfix_src_port,
- enable=1)
-
- p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
- UDP(sport=3001, dport=3002))
- self.pg0.add_stream(p)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- capture = self.pg1.assert_nothing_captured()
-
- # verify IPFIX logging
- self.vapi.ipfix_flush()
- sleep(1)
- capture = self.pg2.get_capture(10)
- ipfix = IPFIXDecoder()
- # first load template
- for p in capture:
- self.assertTrue(p.haslayer(IPFIX))
- if p.haslayer(Template):
- ipfix.add_template(p.getlayer(Template))
- # verify events in data set
- for p in capture:
- if p.haslayer(Data):
- data = ipfix.decode_data_set(p.getlayer(Set))
- self.verify_ipfix_max_entries_per_user(
- data,
- nat44_config.max_translations_per_user,
- self.pg0.remote_ip4)
-
- sleep(6)
- p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
- UDP(sport=3001, dport=3002))
- self.pg0.add_stream(p)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- self.pg1.get_capture(1)
-
def test_syslog_sess(self):
""" Test syslog session creation and deletion """
self.vapi.syslog_set_filter(