diff options
-rw-r--r-- | src/plugins/nat/in2out_ed.c | 25 | ||||
-rwxr-xr-x | src/plugins/nat/nat.c | 105 | ||||
-rw-r--r-- | src/plugins/nat/nat.h | 28 | ||||
-rw-r--r-- | src/plugins/nat/nat44/ed_inlines.h | 144 | ||||
-rw-r--r-- | src/plugins/nat/nat44/inlines.h | 15 | ||||
-rw-r--r-- | src/plugins/nat/nat44_cli.c | 33 | ||||
-rw-r--r-- | src/plugins/nat/nat_api.c | 3 | ||||
-rw-r--r-- | src/plugins/nat/nat_inlines.h | 73 | ||||
-rw-r--r-- | src/plugins/nat/out2in_ed.c | 21 | ||||
-rw-r--r-- | src/plugins/nat/test/test_nat.py | 105 |
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 """ |