summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2018-05-14 06:20:28 -0700
committerMatus Fabian <matfabia@cisco.com>2018-05-17 01:06:17 -0700
commit70a26ac05f2ab9d4cc0669599b09f654de580f36 (patch)
tree4fd5d9f4a1db0f56d6300f399ae84bb92748edbc
parentf9d0568344b4766bc1ddc1be9a7e9afd00e2d832 (diff)
NAT44: nat44_del_session and nat44_user_session_details API update (VPP-1271)
Change-Id: I484d79000c1bbd87ff83847cf567bf3414a719d3 Signed-off-by: Matus Fabian <matfabia@cisco.com>
-rwxr-xr-xsrc/plugins/nat/in2out.c26
-rw-r--r--src/plugins/nat/nat.api24
-rwxr-xr-xsrc/plugins/nat/nat.c115
-rw-r--r--src/plugins/nat/nat.h62
-rw-r--r--src/plugins/nat/nat44_cli.c25
-rw-r--r--src/plugins/nat/nat_api.c68
-rwxr-xr-xsrc/plugins/nat/out2in.c16
-rw-r--r--test/test_nat.py78
-rw-r--r--test/vpp_papi_provider.py34
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,9 +984,19 @@ 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'",
format_unformat_error, line_input);
@@ -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 <addr>:<port> tcp|udp|icmp [vrf <id>]",
+ .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
.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,