From 70a26ac05f2ab9d4cc0669599b09f654de580f36 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Mon, 14 May 2018 06:20:28 -0700 Subject: [PATCH] NAT44: nat44_del_session and nat44_user_session_details API update (VPP-1271) Change-Id: I484d79000c1bbd87ff83847cf567bf3414a719d3 Signed-off-by: Matus Fabian --- src/plugins/nat/in2out.c | 26 +++++----- src/plugins/nat/nat.api | 24 +++++++-- src/plugins/nat/nat.c | 115 +++++++++++++++++++++++++++++++------------- src/plugins/nat/nat.h | 62 ++++++++++++++++++------ src/plugins/nat/nat44_cli.c | 25 ++++++++-- src/plugins/nat/nat_api.c | 68 +++++++++++++++++++++++--- src/plugins/nat/out2in.c | 16 +++--- test/test_nat.py | 78 +++++++++++++++++++++--------- test/vpp_papi_provider.py | 34 +++++++++---- 9 files changed, 325 insertions(+), 123 deletions(-) diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index 4a0d2653a81..1659ed0fec3 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -498,6 +498,7 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, udp_header_t *udp; snat_session_t *s = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + f64 now = vlib_time_now (sm->vlib_main); if (!sm->forwarding_enabled) return 0; @@ -535,13 +536,16 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, if (ip->protocol == IP_PROTOCOL_TCP) { tcp_header_t *tcp = ip4_next_header(ip); - if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) return 1; } /* Per-user LRU list maintenance */ clib_dlist_remove (tsm->list_pool, s->per_user_index); clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, s->per_user_index); + /* Accounting */ + s->last_heard = now; + s->total_pkts++; return 1; } else @@ -1378,7 +1382,7 @@ snat_in2out_lb (snat_main_t *sm, { if (ip->protocol == IP_PROTOCOL_TCP) { - if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) return 0; } /* Per-user LRU list maintenance */ @@ -1477,7 +1481,7 @@ snat_in2out_lb (snat_main_t *sm, ip->dst_address.as_u32 = s->ext_host_addr.as_u32; } tcp->checksum = ip_csum_fold(sum); - if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + if (nat44_set_tcp_session_state_i2o (sm, s, tcp, thread_index)) return s; } else @@ -1734,8 +1738,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace00; } else { @@ -1928,8 +1930,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp1->checksum = ip_csum_fold(sum1); - if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index)) - goto trace01; } else { @@ -2159,8 +2159,6 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace0; } else { @@ -2677,10 +2675,6 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, src_address /* changed member */); ip0->checksum = ip_csum_fold (sum0); - /* Hairpinning */ - nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port, - s0->ext_host_port, proto0); - if (PREDICT_FALSE (ip4_is_first_fragment (ip0))) { if (PREDICT_TRUE(proto0 == SNAT_PROTOCOL_TCP)) @@ -2697,8 +2691,6 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace0; } else { @@ -2708,6 +2700,10 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, } } + /* Hairpinning */ + nat44_reass_hairpinning (sm, b0, ip0, s0->out2in.port, + s0->ext_host_port, proto0); + /* Accounting */ s0->last_heard = now; s0->total_pkts++; diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api index 24aa5d1aa6f..4192cf19e3a 100644 --- a/src/plugins/nat/nat.api +++ b/src/plugins/nat/nat.api @@ -13,7 +13,7 @@ * limitations under the License. */ -option version = "2.5.0"; +option version = "2.6.0"; /** * @file nat.api @@ -558,7 +558,14 @@ define nat44_user_session_dump { @param last_heard - last heard timer @param total_bytes - count of bytes sent through session @param total_pkts - count of pakets sent through session - @param is_closed - 1 if TCP session is closed + @param is_twicenat - 1 if session is twice-nat + @param ext_host_valid - 1 if external host address and port are valid + @param ext_host_address - external host IPv4 address + @param ext_host_port - external host port + @param ext_host_nat_address - post-NAT external host IPv4 address (valid + only if twice-nat session) + @param ext_host_nat_port - post-NAT external host port (valid only if + twice-nat session) */ define nat44_user_session_details { u32 context; @@ -571,7 +578,12 @@ define nat44_user_session_details { u64 last_heard; u64 total_bytes; u32 total_pkts; - u8 is_closed; + u8 is_twicenat; + u8 ext_host_valid; + u8 ext_host_address[4]; + u16 ext_host_port; + u8 ext_host_nat_address[4]; + u16 ext_host_nat_port; }; /** \brief NAT44 load-balancing address and port pair @@ -665,6 +677,9 @@ manual_endian define nat44_lb_static_mapping_details { @param protocol - IP protocol @param port - port number @param vfr_id - VRF ID + @param ext_host_valid - 1 if external host address and port are valid + @param ext_host_address - external host IPv4 address + @param ext_host_port - external host port */ autoreply define nat44_del_session { u32 client_index; @@ -674,6 +689,9 @@ autoreply define nat44_del_session { u8 protocol; u16 port; u32 vrf_id; + u8 ext_host_valid; + u8 ext_host_address[4]; + u16 ext_host_port; }; /** \brief Enable/disable forwarding for NAT44 diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 4f9b04ad4b0..ae34f235a3d 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -162,8 +162,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) ed_key.fib_index = 0; ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) && - s->state != SNAT_SESSION_TCP_CLOSED) + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0)) clib_warning ("in2out_ed key del failed"); return; } @@ -188,8 +187,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) } ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0) && - s->state != SNAT_SESSION_TCP_CLOSED) + if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0)) clib_warning ("out2in_ed key del failed"); ed_key.l_addr = s->in2out.addr; @@ -203,8 +201,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) } ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; - if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) && - s->state != SNAT_SESSION_TCP_CLOSED) + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0)) clib_warning ("in2out_ed key del failed"); } @@ -220,7 +217,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) s->in2out.fib_index); /* Twice NAT address and port for external host */ - if (is_twice_nat_session (s) && s->state != SNAT_SESSION_TCP_CLOSED) + if (is_twice_nat_session (s)) { for (i = 0; i < vec_len (sm->twice_nat_addresses); i++) { @@ -241,18 +238,16 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) /* Session lookup tables */ kv.key = s->in2out.as_u64; - if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0) && - s->state != SNAT_SESSION_TCP_CLOSED) + if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0)) clib_warning ("in2out key del failed"); kv.key = s->out2in.as_u64; - if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0) && - s->state != SNAT_SESSION_TCP_CLOSED) + if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0)) clib_warning ("out2in key del failed"); if (snat_is_session_static (s)) return; - if (s->outside_address_index != ~0 && s->state != SNAT_SESSION_TCP_CLOSED) + if (s->outside_address_index != ~0) snat_free_outside_address_and_port (sm->addresses, thread_index, &s->out2in, s->outside_address_index); } @@ -931,7 +926,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); if (twice_nat || out2in_only) { - m_key.port = clib_host_to_net_u16 (l_port); + m_key.port = clib_host_to_net_u16 (m->local_port); kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1)) @@ -979,7 +974,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (snat_is_session_static (s)) continue; - if (!addr_only && (clib_net_to_host_u16 (s->out2in.port) != m->local_port)) + if (!addr_only && (clib_net_to_host_u16 (s->in2out.port) != m->local_port)) continue; nat_free_session_data (sm, s, tsm - sm->per_thread_data); @@ -1067,7 +1062,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0)) - clib_warning ("in2out key del failed"); + clib_warning ("out2in key del failed"); } /* Delete session(s) for static mapping if exist */ @@ -1104,6 +1099,9 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (is_lb_session (s)) continue; + if (!snat_is_session_static (s)) + continue; + nat_free_session_data (sm, s, tsm - sm->per_thread_data); clib_dlist_remove (tsm->list_pool, s->per_user_index); pool_put_index (tsm->list_pool, s->per_user_index); @@ -1527,7 +1525,10 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { u = pool_elt_at_index (tsm->users, value.value); - u->nsessions--; + if (snat_is_session_static (ses)) + u->nstaticsessions--; + else + u->nsessions--; } } })); @@ -2695,33 +2696,33 @@ u8 * format_snat_session (u8 * s, va_list * args) s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); } - if (is_twice_nat_session (sess)) + if (is_ed_session (sess) || is_fwd_bypass_session (sess)) { - s = format (s, " external host o2i %U:%d i2o %U:%d\n", - format_ip4_address, &sess->ext_host_addr, - clib_net_to_host_u16 (sess->ext_host_port), - format_ip4_address, &sess->ext_host_nat_addr, - clib_net_to_host_u16 (sess->ext_host_nat_port)); - } - else - { - if (sess->ext_host_addr.as_u32) - s = format (s, " external host %U:%u\n", + if (is_twice_nat_session (sess)) + { + s = format (s, " external host o2i %U:%d i2o %U:%d\n", format_ip4_address, &sess->ext_host_addr, - clib_net_to_host_u16 (sess->ext_host_port)); + clib_net_to_host_u16 (sess->ext_host_port), + format_ip4_address, &sess->ext_host_nat_addr, + clib_net_to_host_u16 (sess->ext_host_nat_port)); + } + else + { + if (sess->ext_host_addr.as_u32) + s = format (s, " external host %U:%u\n", + format_ip4_address, &sess->ext_host_addr, + clib_net_to_host_u16 (sess->ext_host_port)); + } } s = format (s, " last heard %.2f\n", sess->last_heard); s = format (s, " total pkts %d, total bytes %lld\n", sess->total_pkts, sess->total_bytes); - if (sess->in2out.protocol == SNAT_PROTOCOL_TCP) - { - s = format (s, " state %s\n", - sess->state == SNAT_SESSION_TCP_CLOSED ? "closed" : "open"); - } if (snat_is_session_static (sess)) s = format (s, " static translation\n"); else s = format (s, " dynamic translation\n"); + if (is_fwd_bypass_session (sess)) + s = format (s, " forwarding-bypass\n"); if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING) s = format (s, " load-balancing\n"); if (is_twice_nat_session (sess)) @@ -3110,6 +3111,9 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, t = is_in ? &tsm->in2out : &tsm->out2in; if (!clib_bihash_search_8_8 (t, &kv, &value)) { + if (pool_is_free_index (tsm->sessions, value.value)) + return VNET_API_ERROR_UNSPECIFIED; + s = pool_elt_at_index (tsm->sessions, value.value); kv.key = s->in2out.as_u64; clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0); @@ -3121,9 +3125,13 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { u = pool_elt_at_index (tsm->users, value.value); - u->nsessions--; + if (snat_is_session_static (s)) + u->nstaticsessions--; + else + u->nsessions--; } 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); return 0; } @@ -3131,6 +3139,45 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, return VNET_API_ERROR_NO_SUCH_ENTRY; } +int +nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + ip4_address_t *eh_addr, u16 eh_port, u8 proto, + u32 vrf_id, int is_in) +{ + ip4_header_t ip; + clib_bihash_16_8_t *t; + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t kv, value; + u32 thread_index; + u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); + snat_session_t *s; + + ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; + if (sm->num_workers > 1) + thread_index = sm->worker_in2out_cb (&ip, fib_index); + else + thread_index = sm->num_workers; + + t = is_in ? &sm->in2out_ed : &sm->out2in_ed; + key.l_addr.as_u32 = addr->as_u32; + key.r_addr.as_u32 = eh_addr->as_u32; + key.l_port = clib_host_to_net_u16 (port); + key.r_port = clib_host_to_net_u16 (eh_port); + key.proto = proto; + key.fib_index = clib_host_to_net_u32 (fib_index); + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + if (clib_bihash_search_16_8 (t, &kv, &value)) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + if (pool_is_free_index (sm->per_thread_data[thread_index].sessions, value.value)) + return VNET_API_ERROR_UNSPECIFIED; + s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value); + nat_free_session_data (sm, s, thread_index); + nat44_delete_session (sm, s, thread_index); + return 0; +} + void nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length) { diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 78b7962b83e..f889976dd52 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -126,6 +126,12 @@ typedef enum { #undef _ } snat_session_state_t; +#define NAT44_SES_I2O_FIN 1 +#define NAT44_SES_O2I_FIN 2 +#define NAT44_SES_I2O_FIN_ACK 4 +#define NAT44_SES_O2I_FIN_ACK 8 + +#define nat44_is_ses_closed(s) (s->state == 0xf) #define SNAT_SESSION_FLAG_STATIC_MAPPING 1 #define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2 @@ -169,6 +175,8 @@ typedef CLIB_PACKED(struct { /* TCP session state */ u8 state; + u32 i2o_fin_seq; + u32 o2i_fin_seq; }) snat_session_t; @@ -588,6 +596,9 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, u8 *tag); int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, snat_protocol_t proto, u32 vrf_id, int is_in); +int nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + ip4_address_t *eh_addr, u16 eh_port, u8 proto, + u32 vrf_id, int is_in); void nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index); snat_user_t * nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, @@ -710,31 +721,52 @@ nat44_delete_session(snat_main_t * sm, snat_session_t * ses, u32 thread_index) pool_put (tsm->sessions, ses); } -/** \brief Set TCP session stet. +/** \brief Set TCP session state. @return 1 if session was closed, otherwise 0 */ always_inline int -nat44_set_tcp_session_state(snat_main_t * sm, snat_session_t * ses, - tcp_header_t * tcp, u32 thread_index) +nat44_set_tcp_session_state_i2o(snat_main_t * sm, snat_session_t * ses, + tcp_header_t * tcp, u32 thread_index) { - if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_UNKNOWN) - ses->state = SNAT_SESSION_TCP_FIN_WAIT; - else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_FIN_WAIT) - ses->state = SNAT_SESSION_TCP_CLOSING; - else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_FIN_WAIT) - ses->state = SNAT_SESSION_TCP_CLOSE_WAIT; - else if (tcp->flags & TCP_FLAG_FIN && ses->state == SNAT_SESSION_TCP_CLOSE_WAIT) - ses->state = SNAT_SESSION_TCP_LAST_ACK; - else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_CLOSING) - ses->state = SNAT_SESSION_TCP_LAST_ACK; - else if (tcp->flags & TCP_FLAG_ACK && ses->state == SNAT_SESSION_TCP_LAST_ACK) + if (tcp->flags & TCP_FLAG_FIN) + { + ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->state |= NAT44_SES_I2O_FIN; + } + if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) + { + if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq) + ses->state |= NAT44_SES_O2I_FIN_ACK; + } + if (nat44_is_ses_closed (ses)) { nat_free_session_data (sm, ses, thread_index); - ses->state = SNAT_SESSION_TCP_CLOSED; nat44_delete_session (sm, ses, thread_index); return 1; } + return 0; +} +always_inline int +nat44_set_tcp_session_state_o2i(snat_main_t * sm, snat_session_t * ses, + tcp_header_t * tcp, u32 thread_index) +{ + if (tcp->flags & TCP_FLAG_FIN) + { + ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->state |= NAT44_SES_O2I_FIN; + } + if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN)) + { + if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq) + ses->state |= NAT44_SES_I2O_FIN_ACK; + } + if (nat44_is_ses_closed (ses)) + { + nat_free_session_data (sm, ses, thread_index); + nat44_delete_session (sm, ses, thread_index); + return 1; + } return 0; } diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index f07b6dde215..efde4be284c 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -959,10 +959,10 @@ nat44_del_session_command_fn (vlib_main_t * vm, { snat_main_t *sm = &snat_main; unformat_input_t _line_input, *line_input = &_line_input; - int is_in = 0; + int is_in = 0, is_ed = 0; clib_error_t *error = 0; - ip4_address_t addr; - u32 port = 0, vrf_id = sm->outside_vrf_id; + ip4_address_t addr, eh_addr; + u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id; snat_protocol_t proto; int rv; @@ -984,8 +984,18 @@ nat44_del_session_command_fn (vlib_main_t * vm, is_in = 1; vrf_id = sm->inside_vrf_id; } + else if (unformat (line_input, "out")) + { + is_in = 0; + vrf_id = sm->outside_vrf_id; + } else if (unformat (line_input, "vrf %u", &vrf_id)) ; + else + if (unformat + (line_input, "external-host %U:%u", unformat_ip4_address, + &eh_addr, &eh_port)) + is_ed = 1; else { error = clib_error_return (0, "unknown input '%U'", @@ -994,7 +1004,12 @@ nat44_del_session_command_fn (vlib_main_t * vm, } } - rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in); + if (is_ed) + rv = + nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, + snat_proto_to_ip_proto (proto), vrf_id, is_in); + else + rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in); switch (rv) { @@ -1750,7 +1765,7 @@ VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = { ?*/ VLIB_CLI_COMMAND (nat44_del_session_command, static) = { .path = "nat44 del session", - .short_help = "nat44 del session in|out : tcp|udp|icmp [vrf ]", + .short_help = "nat44 del session in|out : tcp|udp|icmp [vrf ] [external-host :]", .function = nat44_del_session_command_fn, }; diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index a1d70f8d46e..11a6f0fee04 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -1157,13 +1157,17 @@ send_nat44_user_details (snat_user_t * u, vl_api_registration_t * reg, { vl_api_nat44_user_details_t *rmp; snat_main_t *sm = &snat_main; - fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4); + ip4_main_t *im = &ip4_main; rmp = vl_msg_api_alloc (sizeof (*rmp)); memset (rmp, 0, sizeof (*rmp)); rmp->_vl_msg_id = ntohs (VL_API_NAT44_USER_DETAILS + sm->msg_id_base); - rmp->vrf_id = ntohl (fib->ft_table_id); + if (!pool_is_free_index (im->fibs, u->fib_index)) + { + fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4); + rmp->vrf_id = ntohl (fib->ft_table_id); + } clib_memcpy (rmp->ip_address, &(u->addr), 4); rmp->nsessions = ntohl (u->nsessions); @@ -1218,7 +1222,10 @@ send_nat44_user_session_details (snat_session_t * s, ntohs (VL_API_NAT44_USER_SESSION_DETAILS + sm->msg_id_base); clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4); clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4); - rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0; + rmp->is_static = snat_is_session_static (s) ? 1 : 0; + rmp->is_twicenat = is_twice_nat_session (s) ? 1 : 0; + rmp->ext_host_valid = is_ed_session (s) + || is_fwd_bypass_session (s) ? 1 : 0; rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard); rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes); rmp->total_pkts = ntohl (s->total_pkts); @@ -1235,8 +1242,16 @@ send_nat44_user_session_details (snat_session_t * s, rmp->inside_port = s->in2out.port; rmp->protocol = ntohs (snat_proto_to_ip_proto (s->in2out.protocol)); } - if (s->in2out.protocol == SNAT_PROTOCOL_TCP) - rmp->is_closed = s->state == SNAT_SESSION_TCP_CLOSED ? 1 : 0; + if (is_ed_session (s) || is_fwd_bypass_session (s)) + { + clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4); + rmp->ext_host_port = s->ext_host_port; + if (is_twice_nat_session (s)) + { + clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4); + rmp->ext_host_nat_port = s->ext_host_nat_port; + } + } vl_api_send_msg (reg, (u8 *) rmp); } @@ -1469,8 +1484,8 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp) { snat_main_t *sm = &snat_main; vl_api_nat44_del_session_reply_t *rmp; - ip4_address_t addr; - u16 port; + ip4_address_t addr, eh_addr; + u16 port, eh_port; u32 vrf_id; int rv = 0; snat_protocol_t proto; @@ -1485,8 +1500,15 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp) port = clib_net_to_host_u16 (mp->port); vrf_id = clib_net_to_host_u32 (mp->vrf_id); proto = ip_proto_to_snat_proto (mp->protocol); + memcpy (&eh_addr.as_u8, mp->ext_host_address, 4); + eh_port = clib_net_to_host_u16 (mp->ext_host_port); - rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in); + if (mp->ext_host_valid) + rv = + nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol, + vrf_id, mp->is_in); + else + rv = nat44_del_session (sm, &addr, port, proto, vrf_id, mp->is_in); send_reply: REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY); @@ -1503,6 +1525,10 @@ vl_api_nat44_del_session_t_print (vl_api_nat44_del_session_t * mp, format_ip4_address, mp->address, clib_net_to_host_u16 (mp->port), mp->protocol, clib_net_to_host_u32 (mp->vrf_id), mp->is_in); + if (mp->ext_host_valid) + s = format (s, "ext_host_address %U ext_host_port %d", + format_ip4_address, mp->ext_host_address, + clib_net_to_host_u16 (mp->ext_host_port)); FINISH; } @@ -1514,9 +1540,35 @@ static void snat_main_t *sm = &snat_main; vl_api_nat44_forwarding_enable_disable_reply_t *rmp; int rv = 0; + u32 *ses_to_be_removed = 0, *ses_index; + snat_main_per_thread_data_t *tsm; + snat_session_t *s; sm->forwarding_enabled = mp->enable != 0; + if (mp->enable == 0) + { + /* *INDENT-OFF* */ + vec_foreach (tsm, sm->per_thread_data) + { + pool_foreach (s, tsm->sessions, + ({ + if (is_fwd_bypass_session(s)) + { + vec_add1 (ses_to_be_removed, s - tsm->sessions); + } + })); + vec_foreach (ses_index, ses_to_be_removed) + { + s = pool_elt_at_index(tsm->sessions, ses_index[0]); + nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); + } + vec_free (ses_to_be_removed); + } + /* *INDENT-ON* */ + } + REPLY_MACRO (VL_API_NAT44_FORWARDING_ENABLE_DISABLE_REPLY); } diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index 6bc25b8cc22..c7eece8897c 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -342,6 +342,7 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, snat_user_t *u; snat_session_t *s = 0; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + f64 now = vlib_time_now (sm->vlib_main); if (ip->protocol == IP_PROTOCOL_ICMP) { @@ -410,13 +411,16 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, if (ip->protocol == IP_PROTOCOL_TCP) { tcp_header_t *tcp = ip4_next_header(ip); - if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index)) return; } /* Per-user LRU list maintenance */ clib_dlist_remove (tsm->list_pool, s->per_user_index); clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, s->per_user_index); + /* Accounting */ + s->last_heard = now; + s->total_pkts++; } /** @@ -1066,7 +1070,7 @@ snat_out2in_lb (snat_main_t *sm, ip->src_address.as_u32 = s->ext_host_nat_addr.as_u32; } tcp->checksum = ip_csum_fold(sum); - if (nat44_set_tcp_session_state (sm, s, tcp, thread_index)) + if (nat44_set_tcp_session_state_o2i (sm, s, tcp, thread_index)) return s; } else @@ -1308,8 +1312,6 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace0; } else { @@ -1488,8 +1490,6 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp1->checksum = ip_csum_fold(sum1); - if (nat44_set_tcp_session_state (sm, s1, tcp1, thread_index)) - goto trace1; } else { @@ -1704,8 +1704,6 @@ snat_out2in_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace00; } else { @@ -1974,8 +1972,6 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, ip4_header_t /* cheat */, length /* changed member */); tcp0->checksum = ip_csum_fold(sum0); - if (nat44_set_tcp_session_state (sm, s0, tcp0, thread_index)) - goto trace0; } else { diff --git a/test/test_nat.py b/test/test_nat.py index 59641a26d5a..e2f34657d25 100644 --- a/test/test_nat.py +++ b/test/test_nat.py @@ -1302,6 +1302,19 @@ class TestNAT44(MethodHolder): finally: self.pg0.remote_hosts[0] = host0 + user = self.pg0.remote_hosts[1] + sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0) + self.assertEqual(len(sessions), 3) + self.assertTrue(sessions[0].ext_host_valid) + self.vapi.nat44_del_session( + sessions[0].inside_ip_address, + sessions[0].inside_port, + sessions[0].protocol, + ext_host_address=sessions[0].ext_host_address, + ext_host_port=sessions[0].ext_host_port) + sessions = self.vapi.nat44_user_session_dump(user.ip4n, 0) + self.assertEqual(len(sessions), 2) + finally: self.vapi.nat44_forwarding_enable_disable(0) self.vapi.nat44_add_del_static_mapping(local_ip=real_ip, @@ -1737,6 +1750,18 @@ class TestNAT44(MethodHolder): self.logger.error(ppp("Unexpected or invalid packet:", p)) raise + sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) + self.assertEqual(len(sessions), 1) + self.assertTrue(sessions[0].ext_host_valid) + self.vapi.nat44_del_session( + sessions[0].inside_ip_address, + sessions[0].inside_port, + sessions[0].protocol, + ext_host_address=sessions[0].ext_host_address, + ext_host_port=sessions[0].ext_host_port) + sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) + self.assertEqual(len(sessions), 0) + @unittest.skipUnless(running_extended_tests(), "part of extended tests") def test_static_lb_multi_clients(self): """ NAT44 local service load balancing - multiple clients""" @@ -2073,6 +2098,7 @@ class TestNAT44(MethodHolder): self.assertTrue(session.protocol in [IP_PROTOS.tcp, IP_PROTOS.udp, IP_PROTOS.icmp]) + self.assertFalse(session.ext_host_valid) # pg4 session dump sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4n, 10) @@ -3908,6 +3934,20 @@ class TestNAT44(MethodHolder): self.logger.error(ppp("Unexpected or invalid packet:", p)) raise + if eh_translate: + sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) + self.assertEqual(len(sessions), 1) + self.assertTrue(sessions[0].ext_host_valid) + self.assertTrue(sessions[0].is_twicenat) + self.vapi.nat44_del_session( + sessions[0].inside_ip_address, + sessions[0].inside_port, + sessions[0].protocol, + ext_host_address=sessions[0].ext_host_nat_address, + ext_host_port=sessions[0].ext_host_nat_port) + sessions = self.vapi.nat44_user_session_dump(server.ip4n, 0) + self.assertEqual(len(sessions), 0) + def test_twice_nat(self): """ Twice NAT44 """ self.twice_nat_common() @@ -4018,7 +4058,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA")) + flags="FA", seq=100, ack=300)) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4030,14 +4070,14 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A")) + flags="A", seq=300, ack=101)) pkts.append(p) # FIN packet out -> in p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA")) + flags="FA", seq=300, ack=101)) pkts.append(p) self.pg1.add_stream(pkts) @@ -4049,7 +4089,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) + flags="A", seq=101, ack=301)) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4081,38 +4121,28 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA")) + flags="FA", seq=100, ack=300)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.get_capture(1) - pkts = [] - - # ACK packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) - pkts.append(p) - - # ACK packet in -> out + # FIN+ACK packet in -> out p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA")) - pkts.append(p) + flags="FA", seq=300, ack=101)) - self.pg0.add_stream(pkts) + self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg1.get_capture(2) + self.pg1.get_capture(1) # ACK packet out -> in p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A")) + flags="A", seq=101, ack=301)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4144,7 +4174,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA")) + flags="FA", seq=100, ack=300)) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4154,7 +4184,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA")) + flags="FA", seq=300, ack=100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4164,7 +4194,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A")) + flags="A", seq=101, ack=301)) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -4174,7 +4204,7 @@ class TestNAT44(MethodHolder): p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A")) + flags="A", seq=301, ack=101)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index b3627317d9b..105a54f55d9 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -1540,7 +1540,9 @@ class VppPapiProvider(object): port, protocol, vrf_id=0, - is_in=1): + is_in=1, + ext_host_address=None, + ext_host_port=0): """Delete NAT44 session :param addr: IPv4 address @@ -1548,14 +1550,28 @@ class VppPapiProvider(object): :param protocol: IP protocol number :param vrf_id: VRF ID :param is_in: 1 if inside network addres and port pari, 0 if outside - """ - return self.api( - self.papi.nat44_del_session, - {'address': addr, - 'port': port, - 'protocol': protocol, - 'vrf_id': vrf_id, - 'is_in': is_in}) + :param ext_host_address: external host IPv4 address + :param ext_host_port: external host port + """ + if ext_host_address is None: + return self.api( + self.papi.nat44_del_session, + {'address': addr, + 'port': port, + 'protocol': protocol, + 'vrf_id': vrf_id, + 'is_in': is_in}) + else: + return self.api( + self.papi.nat44_del_session, + {'address': addr, + 'port': port, + 'protocol': protocol, + 'vrf_id': vrf_id, + 'is_in': is_in, + 'ext_host_valid': 1, + 'ext_host_address': ext_host_address, + 'ext_host_port': ext_host_port}) def nat44_forwarding_enable_disable( self, -- 2.16.6