summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/nat/in2out_ed.c25
-rwxr-xr-xsrc/plugins/nat/nat.c105
-rw-r--r--src/plugins/nat/nat.h28
-rw-r--r--src/plugins/nat/nat44/ed_inlines.h144
-rw-r--r--src/plugins/nat/nat44/inlines.h15
-rw-r--r--src/plugins/nat/nat44_cli.c33
-rw-r--r--src/plugins/nat/nat_api.c3
-rw-r--r--src/plugins/nat/nat_inlines.h73
-rw-r--r--src/plugins/nat/out2in_ed.c21
-rw-r--r--src/plugins/nat/test/test_nat.py105
10 files changed, 391 insertions, 161 deletions
diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c
index f8682d0f3c2..45d9fd0b32c 100644
--- a/src/plugins/nat/in2out_ed.c
+++ b/src/plugins/nat/in2out_ed.c
@@ -31,6 +31,7 @@
#include <nat/nat44/inlines.h>
#include <nat/nat_syslog.h>
#include <nat/nat_ha.h>
+#include <nat/nat44/ed_inlines.h>
static char *nat_in2out_ed_error_strings[] = {
#define _(sym,string) string,
@@ -155,7 +156,7 @@ nat44_i2o_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
&s->out2in);
delete:
- nat44_ed_delete_session (sm, s, ctx->thread_index, 1);
+ nat_ed_session_delete (sm, s, ctx->thread_index, 1);
return 1;
}
@@ -323,7 +324,7 @@ slow_path_ed (snat_main_t * sm,
if (PREDICT_FALSE
(nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
{
- if (!nat_global_lru_free_one (sm, thread_index, now))
+ 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);
@@ -342,7 +343,7 @@ slow_path_ed (snat_main_t * sm,
if (snat_static_mapping_match
(sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
{
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, proto);
if (!s)
{
nat_elog_warn ("create NAT session failed");
@@ -386,7 +387,7 @@ slow_path_ed (snat_main_t * sm,
nat_elog_notice ("addresses exhausted");
b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
nat_free_session_data (sm, s, thread_index, 0);
- nat44_ed_delete_session (sm, s, thread_index, 1);
+ nat_ed_session_delete (sm, s, thread_index, 1);
return NAT_NEXT_DROP;
}
key1.addr = allocated_addr;
@@ -399,7 +400,7 @@ slow_path_ed (snat_main_t * sm,
*sessionp = s;
return next;
}
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, proto);
if (!s)
{
nat_elog_warn ("create NAT session failed");
@@ -601,7 +602,7 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
if (nat44_is_ses_closed (s))
{
nat_free_session_data (sm, s, thread_index, 0);
- nat44_ed_delete_session (sm, s, thread_index, 1);
+ nat_ed_session_delete (sm, s, thread_index, 1);
}
else
s->flags |= SNAT_SESSION_FLAG_OUTPUT_FEATURE;
@@ -857,7 +858,7 @@ nat44_ed_in2out_unknown_proto (snat_main_t * sm,
}
create_ses:
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
if (!s)
{
b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_USER_SESS_EXCEEDED];
@@ -1026,9 +1027,9 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
}
s0 = pool_elt_at_index (tsm->sessions, value0.value);
- if (s0->tcp_close_timestamp)
+ if (s0->tcp_closed_timestamp)
{
- if (now >= s0->tcp_close_timestamp)
+ if (now >= s0->tcp_closed_timestamp)
{
// session is closed, go slow path
next0 = def_slow;
@@ -1049,7 +1050,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
if (now >= sess_timeout_time)
{
nat_free_session_data (sm, s0, thread_index, 0);
- nat44_ed_delete_session (sm, s0, thread_index, 1);
+ nat_ed_session_delete (sm, s0, thread_index, 1);
// session is closed, go slow path
next0 = def_slow;
goto trace0;
@@ -1307,10 +1308,10 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
{
s0 = pool_elt_at_index (tsm->sessions, value0.value);
- if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp)
+ if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
{
nat_free_session_data (sm, s0, thread_index, 0);
- nat44_ed_delete_session (sm, s0, thread_index, 1);
+ nat_ed_session_delete (sm, s0, thread_index, 1);
s0 = NULL;
}
}
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 1fb3a7ff397..ee35a57a3ce 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -34,6 +34,7 @@
#include <vnet/fib/ip4_fib.h>
#include <vnet/ip/reass/ip4_sv_reass.h>
#include <vppinfra/bihash_16_8.h>
+#include <nat/nat44/ed_inlines.h>
#include <vpp/app/version.h>
@@ -593,14 +594,6 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
s->per_user_list_head_index,
per_user_translation_list_elt - tsm->list_pool);
- dlist_elt_t *global_lru_list_elt;
- pool_get (tsm->global_lru_pool, global_lru_list_elt);
- global_lru_list_elt->value = s - tsm->sessions;
- s->global_lru_index = global_lru_list_elt - tsm->global_lru_pool;
- clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
- s->global_lru_index);
- s->last_lru_update = now;
-
s->user_index = u - tsm->users;
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
pool_elts (tsm->sessions));
@@ -611,58 +604,6 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
return s;
}
-int
-nat_global_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
-{
- snat_session_t *s = NULL;
- dlist_elt_t *oldest_elt;
- u64 sess_timeout_time;
- u32 oldest_index;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
- oldest_index = clib_dlist_remove_head (tsm->global_lru_pool,
- tsm->global_lru_head_index);
- if (~0 != oldest_index)
- {
- oldest_elt = pool_elt_at_index (tsm->global_lru_pool, oldest_index);
- s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
-
- sess_timeout_time =
- s->last_heard + (f64) nat44_session_get_timeout (sm, s);
- if (now >= sess_timeout_time
- || (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
- {
- nat_free_session_data (sm, s, thread_index, 0);
- nat44_ed_delete_session (sm, s, thread_index, 0);
- return 1;
- }
- else
- {
- clib_dlist_addhead (tsm->global_lru_pool,
- tsm->global_lru_head_index, oldest_index);
- }
- }
- return 0;
-}
-
-snat_session_t *
-nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now)
-{
- snat_session_t *s;
- snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-
- nat_global_lru_free_one (sm, thread_index, now);
-
- pool_get (tsm->sessions, s);
- clib_memset (s, 0, sizeof (*s));
-
- nat44_global_lru_insert (tsm, s, now);
-
- s->ha_last_refreshed = now;
- vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
- pool_elts (tsm->sessions));
- return s;
-}
-
void
snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
int is_add)
@@ -912,7 +853,7 @@ snat_ed_static_mapping_del_sessions (snat_main_t * sm,
vec_foreach (ses_index, indexes_to_free)
{
s = pool_elt_at_index (tsm->sessions, *ses_index);
- nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
}
vec_free (indexes_to_free);
}
@@ -1617,7 +1558,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
continue;
nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
- nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
});
}));
/* *INDENT-ON* */
@@ -1749,7 +1690,7 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
continue;
nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
- nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
});
/* *INDENT-ON* */
@@ -1866,7 +1807,7 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
vec_foreach (ses_index, ses_to_be_removed)
{
ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
- nat44_ed_delete_session (sm, ses, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1);
}
}else{
vec_foreach (ses_index, ses_to_be_removed)
@@ -3657,6 +3598,11 @@ nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
if (!s)
return;
+ if (sm->endpoint_dependent)
+ {
+ nat_ed_lru_insert (tsm, s, now, proto);
+ }
+
s->last_heard = now;
s->flags = flags;
s->ext_host_addr.as_u32 = eh_addr->as_u32;
@@ -3806,7 +3752,7 @@ nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
return;
}
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, proto);
if (!s)
return;
@@ -3925,12 +3871,29 @@ 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->global_lru_pool, sm->max_translations);
+ pool_alloc (tsm->lru_pool, sm->max_translations);
dlist_elt_t *head;
- pool_get (tsm->global_lru_pool, head);
- tsm->global_lru_head_index = head - tsm->global_lru_pool;
- clib_dlist_init (tsm->global_lru_pool, tsm->global_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->udp_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->icmp_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
if (sm->endpoint_dependent)
{
@@ -3970,7 +3933,7 @@ nat44_db_free (snat_main_per_thread_data_t * tsm)
snat_main_t *sm = &snat_main;
pool_free (tsm->sessions);
- pool_free (tsm->global_lru_pool);
+ pool_free (tsm->lru_pool);
if (sm->endpoint_dependent)
{
@@ -4503,7 +4466,7 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
return VNET_API_ERROR_UNSPECIFIED;
s = pool_elt_at_index (tsm->sessions, value.value);
nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
- nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
return 0;
}
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index e4f7a06ead8..7a4d020dcde 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -264,8 +264,10 @@ typedef CLIB_PACKED(struct
u32 per_user_index;
u32 per_user_list_head_index;
+ /* head of LRU list in which this session is tracked */
+ u32 lru_head_index;
/* index in global LRU list */
- u32 global_lru_index;
+ u32 lru_index;
f64 last_lru_update;
/* Last heard timer */
@@ -290,7 +292,7 @@ typedef CLIB_PACKED(struct
u8 state;
u32 i2o_fin_seq;
u32 o2i_fin_seq;
- u32 tcp_close_timestamp;
+ u64 tcp_closed_timestamp;
/* user index */
u32 user_index;
@@ -468,8 +470,12 @@ typedef struct
dlist_elt_t *list_pool;
/* LRU session list - head is stale, tail is fresh */
- dlist_elt_t *global_lru_pool;
- u32 global_lru_head_index;
+ dlist_elt_t *lru_pool;
+ u32 tcp_trans_lru_head_index;
+ u32 tcp_estab_lru_head_index;
+ u32 udp_lru_head_index;
+ u32 icmp_lru_head_index;
+ u32 unk_proto_lru_head_index;
/* NAT thread index */
u32 snat_thread_index;
@@ -1311,18 +1317,6 @@ snat_session_t *nat_session_alloc_or_recycle (snat_main_t * sm,
u32 thread_index, f64 now);
/**
- * @brief Allocate NAT endpoint-dependent session
- *
- * @param sm snat global configuration data
- * @param thread_index thread index
- * @param now time now
- *
- * @return session data structure on success otherwise zero value
- */
-snat_session_t *nat_ed_session_alloc (snat_main_t * sm, u32 thread_index,
- f64 now);
-
-/**
* @brief Set address and port assignment algorithm for MAP-E CE
*
* @param psid Port Set Identifier value
@@ -1431,8 +1425,6 @@ typedef struct
u16 src_port, dst_port;
} tcp_udp_header_t;
-int nat_global_lru_free_one (snat_main_t * sm, int thread_index, f64 now);
-
#endif /* __included_nat_h__ */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/plugins/nat/nat44/ed_inlines.h b/src/plugins/nat/nat44/ed_inlines.h
new file mode 100644
index 00000000000..37212f36bf5
--- /dev/null
+++ b/src/plugins/nat/nat44/ed_inlines.h
@@ -0,0 +1,144 @@
+/*
+ * simple nat plugin
+ *
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __included_ed_inlines_h__
+#define __included_ed_inlines_h__
+
+#include <float.h>
+#include <vppinfra/clib.h>
+#include <nat/nat.h>
+#include <nat/nat_inlines.h>
+
+static_always_inline int
+nat_ed_lru_insert (snat_main_per_thread_data_t * tsm,
+ snat_session_t * s, f64 now, u8 proto)
+{
+ dlist_elt_t *lru_list_elt;
+ pool_get (tsm->lru_pool, lru_list_elt);
+ s->lru_index = lru_list_elt - tsm->lru_pool;
+ switch (proto)
+ {
+ case IP_PROTOCOL_UDP:
+ s->lru_head_index = tsm->udp_lru_head_index;
+ break;
+ case IP_PROTOCOL_TCP:
+ s->lru_head_index = tsm->tcp_trans_lru_head_index;
+ break;
+ case IP_PROTOCOL_ICMP:
+ s->lru_head_index = tsm->icmp_lru_head_index;
+ break;
+ default:
+ s->lru_head_index = tsm->unk_proto_lru_head_index;
+ break;
+ }
+ clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
+ lru_list_elt->value = s - tsm->sessions;
+ s->last_lru_update = now;
+ return 1;
+}
+
+always_inline void
+nat_ed_session_delete (snat_main_t * sm, snat_session_t * ses,
+ u32 thread_index, int lru_delete
+ /* delete from global LRU list */ )
+{
+ snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
+ thread_index);
+
+ if (lru_delete)
+ {
+ clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+ }
+ pool_put_index (tsm->lru_pool, ses->lru_index);
+ pool_put (tsm->sessions, ses);
+ vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+ pool_elts (tsm->sessions));
+
+}
+
+static_always_inline int
+nat_lru_free_one_with_head (snat_main_t * sm, int thread_index,
+ f64 now, u32 head_index)
+{
+ snat_session_t *s = NULL;
+ dlist_elt_t *oldest_elt;
+ f64 sess_timeout_time;
+ u32 oldest_index;
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
+ if (~0 != oldest_index)
+ {
+ oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
+ s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
+
+ sess_timeout_time =
+ s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+ if (now >= sess_timeout_time
+ || (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp))
+ {
+ nat_free_session_data (sm, s, thread_index, 0);
+ nat_ed_session_delete (sm, s, thread_index, 0);
+ return 1;
+ }
+ else
+ {
+ clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
+ }
+ }
+ return 0;
+}
+
+static_always_inline int
+nat_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
+{
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+ int rc = 0;
+#define _(p) \
+ if ((rc = nat_lru_free_one_with_head (sm, thread_index, now, \
+ tsm->p##_lru_head_index))) \
+ { \
+ return rc; \
+ }
+ _(tcp_trans);
+ _(udp);
+ _(unk_proto);
+ _(icmp);
+ _(tcp_estab);
+#undef _
+ return 0;
+}
+
+static_always_inline snat_session_t *
+nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now, u8 proto)
+{
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+
+ nat_lru_free_one (sm, thread_index, now);
+
+ pool_get (tsm->sessions, s);
+ clib_memset (s, 0, sizeof (*s));
+
+ nat_ed_lru_insert (tsm, s, now, proto);
+
+ s->ha_last_refreshed = now;
+ vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+ pool_elts (tsm->sessions));
+ return s;
+}
+
+#endif
diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h
index a5118ea2fa6..62121dfb0db 100644
--- a/src/plugins/nat/nat44/inlines.h
+++ b/src/plugins/nat/nat44/inlines.h
@@ -59,25 +59,12 @@ nat44_session_reuse_old (snat_main_t * sm, snat_user_t * u,
s->ext_host_port = 0;
s->ext_host_nat_addr.as_u32 = 0;
s->ext_host_nat_port = 0;
- s->tcp_close_timestamp = 0;
+ s->tcp_closed_timestamp = 0;
s->ha_last_refreshed = now;
return s;
}
static_always_inline void
-nat44_global_lru_insert (snat_main_per_thread_data_t * tsm,
- snat_session_t * s, f64 now)
-{
- dlist_elt_t *lru_list_elt;
- pool_get (tsm->global_lru_pool, lru_list_elt);
- s->global_lru_index = lru_list_elt - tsm->global_lru_pool;
- clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
- s->global_lru_index);
- lru_list_elt->value = s - tsm->sessions;
- s->last_lru_update = now;
-}
-
-static_always_inline void
nat44_sessions_clear ()
{
snat_main_t *sm = &snat_main;
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index 8c800d5c373..796e3495594 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -688,9 +688,9 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
tcp_sessions++;
if (s->state)
{
- if (s->tcp_close_timestamp)
+ if (s->tcp_closed_timestamp)
{
- if (now >= s->tcp_close_timestamp)
+ if (now >= s->tcp_closed_timestamp)
{
++transitory_closed;
}
@@ -734,9 +734,9 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
tcp_sessions++;
if (s->state)
{
- if (s->tcp_close_timestamp)
+ if (s->tcp_closed_timestamp)
{
- if (now >= s->tcp_close_timestamp)
+ if (now >= s->tcp_closed_timestamp)
{
++transitory_closed;
}
@@ -758,6 +758,31 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
}));
/* *INDENT-ON* */
count = pool_elts (tsm->sessions);
+ if (sm->endpoint_dependent)
+ {
+ dlist_elt_t *oldest_elt;
+ u32 oldest_index;
+#define _(n, d) \
+ oldest_index = \
+ clib_dlist_remove_head (tsm->lru_pool, tsm->n##_lru_head_index); \
+ if (~0 != oldest_index) \
+ { \
+ oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index); \
+ s = pool_elt_at_index (tsm->sessions, oldest_elt->value); \
+ sess_timeout_time = \
+ s->last_heard + (f64)nat44_session_get_timeout (sm, s); \
+ vlib_cli_output (vm, d " LRU min session timeout %llu (now %llu)", \
+ sess_timeout_time, now); \
+ clib_dlist_addhead (tsm->lru_pool, tsm->n##_lru_head_index, \
+ oldest_index); \
+ }
+ _(tcp_estab, "established tcp");
+ _(tcp_trans, "transitory tcp");
+ _(udp, "udp");
+ _(unk_proto, "unknown protocol");
+ _(icmp, "icmp");
+#undef _
+ }
}
vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index 74f24d85cf8..37af77d11c1 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -31,6 +31,7 @@
#include <nat/nat_msg_enum.h>
#include <vnet/fib/fib_table.h>
#include <vnet/ip/ip_types_api.h>
+#include <nat/nat44/ed_inlines.h>
#define vl_api_nat44_add_del_lb_static_mapping_t_endian vl_noop_handler
#define vl_api_nat44_nat44_lb_static_mapping_details_t_endian vl_noop_handler
@@ -2058,7 +2059,7 @@ static void
{
s = pool_elt_at_index(tsm->sessions, ses_index[0]);
nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
- nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
+ nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
}
}else{
vec_foreach (ses_index, ses_to_be_removed)
diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h
index e5ac421a6f9..d37cb10b6fd 100644
--- a/src/plugins/nat/nat_inlines.h
+++ b/src/plugins/nat/nat_inlines.h
@@ -261,8 +261,11 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
clib_dlist_remove (tsm->list_pool, ses->per_user_index);
pool_put_index (tsm->list_pool, ses->per_user_index);
- clib_dlist_remove (tsm->global_lru_pool, ses->global_lru_index);
- pool_put_index (tsm->global_lru_pool, ses->global_lru_index);
+ if (sm->endpoint_dependent)
+ {
+ clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+ pool_put_index (tsm->lru_pool, ses->lru_index);
+ }
pool_put (tsm->sessions, ses);
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
pool_elts (tsm->sessions));
@@ -280,25 +283,6 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
}
}
-always_inline void
-nat44_ed_delete_session (snat_main_t * sm, snat_session_t * ses,
- u32 thread_index, int global_lru_delete
- /* delete from global LRU list */ )
-{
- snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
- thread_index);
-
- if (global_lru_delete)
- {
- clib_dlist_remove (tsm->global_lru_pool, ses->global_lru_index);
- }
- pool_put_index (tsm->global_lru_pool, ses->global_lru_index);
- pool_put (tsm->sessions, ses);
- vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
- pool_elts (tsm->sessions));
-
-}
-
/** \brief Set TCP session state.
@return 1 if session was closed, otherwise 0
*/
@@ -307,6 +291,7 @@ nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now,
snat_session_t * ses, vlib_buffer_t * b,
u32 thread_index)
{
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags;
u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number;
u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number;
@@ -331,10 +316,23 @@ nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now,
ses->state |= NAT44_SES_O2I_FIN_ACK;
if (nat44_is_ses_closed (ses))
{ // if session is now closed, save the timestamp
- ses->tcp_close_timestamp = now + sm->tcp_transitory_timeout;
+ ses->tcp_closed_timestamp = now + sm->tcp_transitory_timeout;
+ ses->last_lru_update = now;
}
}
}
+
+ // move the session to proper LRU
+ if (ses->state)
+ {
+ ses->lru_head_index = tsm->tcp_trans_lru_head_index;
+ }
+ else
+ {
+ ses->lru_head_index = tsm->tcp_estab_lru_head_index;
+ }
+ clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+ clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
return 0;
}
@@ -344,6 +342,7 @@ nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now,
u32 tcp_ack_number, u32 tcp_seq_number,
u32 thread_index)
{
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
ses->state = NAT44_SES_RST;
if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
@@ -364,9 +363,21 @@ nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now,
ses->state |= NAT44_SES_I2O_FIN_ACK;
if (nat44_is_ses_closed (ses))
{ // if session is now closed, save the timestamp
- ses->tcp_close_timestamp = now + sm->tcp_transitory_timeout;
+ ses->tcp_closed_timestamp = now + sm->tcp_transitory_timeout;
+ ses->last_lru_update = now;
}
}
+ // move the session to proper LRU
+ if (ses->state)
+ {
+ ses->lru_head_index = tsm->tcp_trans_lru_head_index;
+ }
+ else
+ {
+ ses->lru_head_index = tsm->tcp_estab_lru_head_index;
+ }
+ clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+ clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
return 0;
}
@@ -411,7 +422,7 @@ always_inline void
nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
u32 thread_index)
{
- /* don't update too often - timeout is in a magnitude of seconds anyway */
+ /* don't update too often - timeout is in magnitude of seconds anyway */
if (s->last_heard > s->last_lru_update + 1)
{
if (!sm->endpoint_dependent)
@@ -421,13 +432,13 @@ nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
s->per_user_list_head_index, s->per_user_index);
}
-
- clib_dlist_remove (sm->per_thread_data[thread_index].global_lru_pool,
- s->global_lru_index);
- clib_dlist_addtail (sm->per_thread_data[thread_index].global_lru_pool,
- sm->
- per_thread_data[thread_index].global_lru_head_index,
- s->global_lru_index);
+ else
+ {
+ clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
+ s->lru_index);
+ clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
+ s->lru_head_index, s->lru_index);
+ }
s->last_lru_update = s->last_heard;
}
}
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index 9db82e00ab4..e597191d4d2 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -31,6 +31,7 @@
#include <nat/nat44/inlines.h>
#include <nat/nat_syslog.h>
#include <nat/nat_ha.h>
+#include <nat/nat44/ed_inlines.h>
static char *nat_out2in_ed_error_strings[] = {
#define _(sym,string) string,
@@ -181,7 +182,7 @@ nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg)
snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
&s->out2in);
delete:
- nat44_ed_delete_session (sm, s, ctx->thread_index, 1);
+ nat_ed_session_delete (sm, s, ctx->thread_index, 1);
return 1;
}
@@ -216,7 +217,7 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
return 0;
}
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, e_key.protocol);
if (!s)
{
b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
@@ -260,7 +261,7 @@ create_session_for_static_mapping_ed (snat_main_t * sm,
tsm->snat_thread_index))
{
b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
- nat44_ed_delete_session (sm, s, thread_index, 1);
+ nat_ed_session_delete (sm, s, thread_index, 1);
if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 0))
nat_elog_notice ("out2in-ed key del failed");
return 0;
@@ -369,7 +370,7 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip,
(sm, rx_fib_index, thread_index)))
return;
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
if (!s)
{
nat_elog_warn ("create NAT session failed");
@@ -597,7 +598,7 @@ nat44_ed_out2in_unknown_proto (snat_main_t * sm,
new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
/* Create a new session */
- s = nat_ed_session_alloc (sm, thread_index, now);
+ s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
if (!s)
{
b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
@@ -739,9 +740,9 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
}
s0 = pool_elt_at_index (tsm->sessions, value0.value);
- if (s0->tcp_close_timestamp)
+ if (s0->tcp_closed_timestamp)
{
- if (now >= s0->tcp_close_timestamp)
+ if (now >= s0->tcp_closed_timestamp)
{
// session is closed, go slow path
next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
@@ -763,7 +764,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
{
// session is closed, go slow path
nat_free_session_data (sm, s0, thread_index, 0);
- nat44_ed_delete_session (sm, s0, thread_index, 1);
+ nat_ed_session_delete (sm, s0, thread_index, 1);
next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
goto trace0;
}
@@ -1023,10 +1024,10 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
{
s0 = pool_elt_at_index (tsm->sessions, value0.value);
- if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp)
+ if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp)
{
nat_free_session_data (sm, s0, thread_index, 0);
- nat44_ed_delete_session (sm, s0, thread_index, 1);
+ nat_ed_session_delete (sm, s0, thread_index, 1);
s0 = NULL;
}
}
diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py
index a8e2af763d0..2ba7a9b78f3 100644
--- a/src/plugins/nat/test/test_nat.py
+++ b/src/plugins/nat/test/test_nat.py
@@ -7059,6 +7059,111 @@ class TestNAT44EndpointDependent(MethodHolder):
self.logger.info(self.vapi.cli("show nat timeouts"))
+class TestNAT44EndpointDependent2(MethodHolder):
+ """ Endpoint-Dependent mapping and filtering extra test cases """
+
+ translation_buckets = 5
+
+ @classmethod
+ def setUpConstants(cls):
+ super(TestNAT44EndpointDependent2, cls).setUpConstants()
+ cls.vpp_cmdline.extend([
+ "nat", "{", "endpoint-dependent",
+ "translation hash buckets %d" % cls.translation_buckets,
+ "}"
+ ])
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestNAT44EndpointDependent2, cls).setUpClass()
+ cls.vapi.cli("set log class nat level debug")
+
+ cls.nat_addr = '10.0.0.3'
+
+ cls.create_pg_interfaces(range(2))
+
+ for i in cls.pg_interfaces:
+ i.admin_up()
+ i.config_ip4()
+ i.resolve_arp()
+
+ def setUp(self):
+ super(TestNAT44EndpointDependent2, self).setUp()
+ self.vapi.nat_set_timeouts(
+ udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
+ 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)
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestNAT44EndpointDependent2, cls).tearDownClass()
+
+ def init_tcp_session(self, in_if, out_if, sport, ext_dport):
+ # SYN packet in->out
+ p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
+ IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
+ TCP(sport=sport, dport=ext_dport, flags="S"))
+ in_if.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = out_if.get_capture(1)
+ p = capture[0]
+ tcp_port_out = p[TCP].sport
+
+ # SYN + ACK packet out->in
+ p = (Ether(src=out_if.remote_mac, dst=out_if.local_mac) /
+ IP(src=out_if.remote_ip4, dst=self.nat_addr) /
+ TCP(sport=ext_dport, dport=tcp_port_out, flags="SA"))
+ out_if.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ in_if.get_capture(1)
+
+ # ACK packet in->out
+ p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
+ IP(src=in_if.remote_ip4, dst=out_if.remote_ip4) /
+ TCP(sport=sport, dport=ext_dport, flags="A"))
+ in_if.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ out_if.get_capture(1)
+
+ return tcp_port_out
+
+ 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):
+ 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))
+ pkts.append(p)
+
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ self.pg1.get_capture(len(pkts))
+ self.sleep(1.5, "wait for timeouts")
+
+ pkts = []
+ for i in range(0, 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'))
+ pkts.append(p)
+
+ self.pg0.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ self.pg1.get_capture(len(pkts))
+
+
class TestNAT44Out2InDPO(MethodHolder):
""" NAT44 Test Cases using out2in DPO """