summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2018-05-04 03:57:42 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2018-05-08 16:03:30 +0000
commitebdf190a9c4a514329de7e5e9b9178c3af055122 (patch)
tree3b6d8fdd1e4cf2c3fc8d1bb0202308334d1223ee /src/plugins/nat
parent7220f42cbed7ccde0738e74fd498db1770b24cb7 (diff)
NAT44: TCP connection close detection (VPP-1266)
Change-Id: Iba1cc1179ee80478e29888790a6476571d1904dc Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/nat')
-rwxr-xr-xsrc/plugins/nat/in2out.c20
-rw-r--r--src/plugins/nat/nat.api4
-rwxr-xr-xsrc/plugins/nat/nat.c34
-rw-r--r--src/plugins/nat/nat.h30
-rw-r--r--src/plugins/nat/nat44_cli.c44
-rw-r--r--src/plugins/nat/nat_api.c2
-rwxr-xr-xsrc/plugins/nat/out2in.c10
7 files changed, 131 insertions, 13 deletions
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index 3ec65e80cba..d3369b6b49c 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -532,6 +532,11 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip,
s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value);
if (is_fwd_bypass_session (s))
{
+ if (ip->protocol == IP_PROTOCOL_TCP)
+ {
+ tcp_header_t *tcp = ip4_next_header(ip);
+ nat44_set_tcp_session_state (sm, s, tcp, thread_index);
+ }
/* 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,
@@ -1369,7 +1374,15 @@ snat_in2out_lb (snat_main_t *sm,
{
s = pool_elt_at_index (tsm->sessions, s_value.value);
if (is_fwd_bypass_session (s))
- return 0;
+ {
+ if (ip->protocol == IP_PROTOCOL_TCP)
+ nat44_set_tcp_session_state (sm, s, tcp, thread_index);
+ /* 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);
+ return 0;
+ }
}
else
{
@@ -1457,6 +1470,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);
+ nat44_set_tcp_session_state (sm, s, tcp, thread_index);
}
else
{
@@ -1715,6 +1729,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{
@@ -1907,6 +1922,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp1->checksum = ip_csum_fold(sum1);
+ nat44_set_tcp_session_state (sm, s1, tcp1, thread_index);
}
else
{
@@ -2136,6 +2152,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{
@@ -2668,6 +2685,7 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{
diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api
index 23c89adef7a..24aa5d1aa6f 100644
--- a/src/plugins/nat/nat.api
+++ b/src/plugins/nat/nat.api
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-option version = "2.4.1";
+option version = "2.5.0";
/**
* @file nat.api
@@ -558,6 +558,7 @@ 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
*/
define nat44_user_session_details {
u32 context;
@@ -570,6 +571,7 @@ define nat44_user_session_details {
u64 last_heard;
u64 total_bytes;
u32 total_pkts;
+ u8 is_closed;
};
/** \brief NAT44 load-balancing address and port pair
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 8e4d9df929c..68b43c05ea1 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -162,7 +162,8 @@ 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))
+ if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
+ s->state != SNAT_SESSION_TCP_CLOSED)
clib_warning ("in2out_ed key del failed");
return;
}
@@ -187,7 +188,8 @@ 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))
+ if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0) &&
+ s->state != SNAT_SESSION_TCP_CLOSED)
clib_warning ("out2in_ed key del failed");
ed_key.l_addr = s->in2out.addr;
@@ -201,7 +203,8 @@ 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))
+ if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0) &&
+ s->state != SNAT_SESSION_TCP_CLOSED)
clib_warning ("in2out_ed key del failed");
}
@@ -217,7 +220,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))
+ if (is_twice_nat_session (s) && s->state != SNAT_SESSION_TCP_CLOSED)
{
for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
{
@@ -238,16 +241,18 @@ 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))
+ if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0) &&
+ s->state != SNAT_SESSION_TCP_CLOSED)
clib_warning ("in2out key del failed");
kv.key = s->out2in.as_u64;
- if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
+ if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0) &&
+ s->state != SNAT_SESSION_TCP_CLOSED)
clib_warning ("out2in key del failed");
if (snat_is_session_static (s))
return;
- if (s->outside_address_index != ~0)
+ if (s->outside_address_index != ~0 && s->state != SNAT_SESSION_TCP_CLOSED)
snat_free_outside_address_and_port (sm->addresses, thread_index,
&s->out2in, s->outside_address_index);
}
@@ -333,6 +338,11 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index)
s->flags = 0;
s->total_bytes = 0;
s->total_pkts = 0;
+ s->state = 0;
+ s->ext_host_addr.as_u32 = 0;
+ s->ext_host_port = 0;
+ s->ext_host_nat_addr.as_u32 = 0;
+ s->ext_host_nat_port = 0;
}
else
{
@@ -2696,12 +2706,18 @@ u8 * format_snat_session (u8 * s, va_list * args)
else
{
if (sess->ext_host_addr.as_u32)
- s = format (s, " external host %U\n",
- format_ip4_address, &sess->ext_host_addr);
+ 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
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 775376fcbab..61d26b2076c 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -115,8 +115,10 @@ typedef enum {
_(3, TCP_ESTABLISHED, "tcp-established") \
_(4, TCP_FIN_WAIT, "tcp-fin-wait") \
_(5, TCP_CLOSE_WAIT, "tcp-close-wait") \
- _(6, TCP_LAST_ACK, "tcp-last-ack") \
- _(7, ICMP_ACTIVE, "icmp-active")
+ _(6, TCP_CLOSING, "tcp-closing") \
+ _(7, TCP_LAST_ACK, "tcp-last-ack") \
+ _(8, TCP_CLOSED, "tcp-closed") \
+ _(9, ICMP_ACTIVE, "icmp-active")
typedef enum {
#define _(v, N, s) SNAT_SESSION_##N = v,
@@ -164,6 +166,9 @@ typedef CLIB_PACKED(struct {
/* External hos address and port after translation */
ip4_address_t ext_host_nat_addr; /* 74-77 */
u16 ext_host_nat_port; /* 78-79 */
+
+ /* TCP session state */
+ u8 state;
}) snat_session_t;
@@ -681,4 +686,25 @@ user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static)
}
}
+always_inline void
+nat44_set_tcp_session_state(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)
+ {
+ nat_free_session_data (sm, ses, thread_index);
+ ses->state = SNAT_SESSION_TCP_CLOSED;
+ }
+}
+
#endif /* __included_snat_h__ */
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index 2f1e9a019ac..f07b6dde215 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -158,6 +158,38 @@ done:
}
static clib_error_t *
+nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ snat_main_t *sm = &snat_main;
+ snat_main_per_thread_data_t *tsm;
+ int i;
+ int verbose = 0;
+
+ if (unformat (input, "detail"))
+ verbose = 1;
+ else if (unformat (input, "verbose"))
+ verbose = 2;
+
+ vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed, verbose);
+ vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed, verbose);
+ vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local,
+ verbose);
+ vlib_cli_output (vm, "%U",
+ format_bihash_8_8, &sm->static_mapping_by_external,
+ verbose);
+ vec_foreach_index (i, sm->per_thread_data)
+ {
+ tsm = vec_elt_at_index (sm->per_thread_data, i);
+ vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->in2out, verbose);
+ vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->out2in, verbose);
+ vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose);
+ }
+
+ return 0;
+}
+
+static clib_error_t *
nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
@@ -1490,6 +1522,18 @@ VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
/*?
* @cliexpar
+ * @cliexstart{show nat44 hash tables}
+ * Show NAT44 hash tables
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_show_hash, static) = {
+ .path = "show nat44 hash tables",
+ .short_help = "show nat44 hash tables [detail|verbose]",
+ .function = nat44_show_hash_commnad_fn,
+};
+
+/*?
+ * @cliexpar
* @cliexstart{nat44 add address}
* Add/delete NAT44 pool address.
* To add NAT44 pool address use:
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index 4c815f0bc13..a1d70f8d46e 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -1235,6 +1235,8 @@ 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;
vl_api_send_msg (reg, (u8 *) rmp);
}
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c
index a0128b8d61d..c0f5a3c835a 100755
--- a/src/plugins/nat/out2in.c
+++ b/src/plugins/nat/out2in.c
@@ -407,6 +407,11 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index,
clib_warning ("in2out_ed key add failed");
}
+ if (ip->protocol == IP_PROTOCOL_TCP)
+ {
+ tcp_header_t *tcp = ip4_next_header(ip);
+ nat44_set_tcp_session_state (sm, s, tcp, thread_index);
+ }
/* 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,
@@ -1058,6 +1063,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);
+ nat44_set_tcp_session_state (sm, s, tcp, thread_index);
}
else
{
@@ -1300,6 +1306,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{
@@ -1478,6 +1485,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp1->checksum = ip_csum_fold(sum1);
+ nat44_set_tcp_session_state (sm, s1, tcp1, thread_index);
}
else
{
@@ -1692,6 +1700,7 @@ snat_out2in_node_fn (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{
@@ -1960,6 +1969,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm,
ip4_header_t /* cheat */,
length /* changed member */);
tcp0->checksum = ip_csum_fold(sum0);
+ nat44_set_tcp_session_state (sm, s0, tcp0, thread_index);
}
else
{