summaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/nat44-ed/nat44_ed_inlines.h
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2022-01-10 21:57:27 +0000
committerOle Tr�an <otroan@employees.org>2022-01-24 12:59:46 +0000
commit56c492aa0502751de2dd9d890096a82c5f04776d (patch)
treea2b8a1c300853070b26f9953a10bd1a4e41f3bdd /src/plugins/nat/nat44-ed/nat44_ed_inlines.h
parent4634d02501235d3803a17839eeaf076110abcb18 (diff)
nat: TCP state tracking based on RFC 7857/RFC 6146
Implement proper state machine based on above RFCs. ACKs to SYNs/FINs are no longer required/tracked. This is more friendly to peers and accounts for lost packets and retransmits. This change also means that all traffic is translated and forwarded while in transitory timeout, which helps delivering e.g. retransmitted FINs, FINACKs and other messages. Also support reopening a session in transitory timeout after seeing both FINs by seeing both SYNs again. This helps quick connection reestablishment if the peers want to. Type: improvement Signed-off-by: Klement Sekera <ksekera@cisco.com> Signed-off-by: Miklos Tirpak <miklos.tirpak@gmail.com> Change-Id: Ibf521c79463472db97e593bfa02b32b4a06dfd2a
Diffstat (limited to 'src/plugins/nat/nat44-ed/nat44_ed_inlines.h')
-rw-r--r--src/plugins/nat/nat44-ed/nat44_ed_inlines.h380
1 files changed, 301 insertions, 79 deletions
diff --git a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h
index cb418960249..a13f250cd3b 100644
--- a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h
+++ b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h
@@ -24,6 +24,7 @@
#include <vnet/fib/ip4_fib.h>
#include <nat/lib/log.h>
+#include <nat/lib/ipfix_logging.h>
#include <nat/nat44-ed/nat44_ed.h>
always_inline void
@@ -171,6 +172,26 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
return 0;
}
+always_inline int
+nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state)
+{
+ static int lookup[] = {
+ [NAT44_ED_TCP_STATE_CLOSED] = 0,
+ [NAT44_ED_TCP_STATE_SYN_I2O] = 0,
+ [NAT44_ED_TCP_STATE_SYN_O2I] = 0,
+ [NAT44_ED_TCP_STATE_ESTABLISHED] = 1,
+ [NAT44_ED_TCP_STATE_FIN_I2O] = 1,
+ [NAT44_ED_TCP_STATE_FIN_O2I] = 1,
+ [NAT44_ED_TCP_STATE_RST_TRANS] = 0,
+ [NAT44_ED_TCP_STATE_FIN_TRANS] = 0,
+ [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O] = 0,
+ [NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I] = 0,
+ [NAT44_ED_TCP_N_STATE] = 0,
+ };
+ ASSERT (state <= ARRAY_LEN (lookup));
+ return lookup[state];
+}
+
always_inline u32
nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
{
@@ -184,10 +205,10 @@ nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
return sm->timeouts.udp;
case IP_PROTOCOL_TCP:
{
- if (s->state)
- return sm->timeouts.tcp.transitory;
- else
+ if (nat44_ed_tcp_is_established (s->tcp_state))
return sm->timeouts.tcp.established;
+ else
+ return sm->timeouts.tcp.transitory;
}
default:
return sm->timeouts.udp;
@@ -340,8 +361,7 @@ nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
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))
+ if (now >= sess_timeout_time)
{
nat44_ed_free_session_data (sm, s, thread_index, 0);
nat_ed_session_delete (sm, s, thread_index, 0);
@@ -701,101 +721,303 @@ is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
}
always_inline void
-nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
- vlib_buffer_t *b, u32 thread_index)
+nat44_ed_session_reopen (u32 thread_index, snat_session_t *s)
{
- 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;
- 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))
- ses->state = 0;
- if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
- (ses->state & NAT44_SES_O2I_SYN))
- ses->state = 0;
- if (tcp_flags & TCP_FLAG_SYN)
- ses->state |= NAT44_SES_I2O_SYN;
- 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))
+ nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr,
+ s->in2out.port, &s->ext_host_nat_addr,
+ s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
+ &s->ext_host_addr, s->ext_host_port, s->proto,
+ nat44_ed_is_twice_nat_session (s));
+
+ nat_ipfix_logging_nat44_ses_delete (
+ thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
+ s->in2out.port, s->out2in.port, s->in2out.fib_index);
+ nat_ipfix_logging_nat44_ses_create (
+ thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto,
+ s->in2out.port, s->out2in.port, s->in2out.fib_index);
+
+ nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
+ s->in2out.port, &s->ext_host_nat_addr,
+ s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
+ &s->ext_host_addr, s->ext_host_port, s->proto, 0);
+ s->total_pkts = 0;
+ s->total_bytes = 0;
+}
+
+always_inline void
+nat44_ed_init_tcp_state_stable (snat_main_t *sm)
+{
+ /* first make sure whole table is initialised in a way where state
+ * is not changed, then define special cases */
+ nat44_ed_tcp_state_e s;
+ for (s = 0; s < NAT44_ED_TCP_N_STATE; ++s)
{
- if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq)
+ int i;
+ for (i = 0; i < NAT44_ED_N_DIR; ++i)
{
- ses->state |= NAT44_SES_O2I_FIN_ACK;
- if (nat44_is_ses_closed (ses))
- { // if session is now closed, save the timestamp
- ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
- ses->last_lru_update = now;
+ int j = 0;
+ for (j = 0; j < NAT44_ED_TCP_N_FLAG; ++j)
+ {
+ sm->tcp_state_change_table[s][i][j] = s;
}
}
}
- // 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);
+ /* CLOSED and any kind of SYN -> HALF-OPEN */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_SYN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_SYN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_CLOSED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_SYN_O2I;
+
+ /* HALF-OPEN and any kind of SYN in right direction -> ESTABLISHED */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_SYN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+
+ /* ESTABLISHED and any kind of RST -> RST_TRANS */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_RST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_RST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_FINRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_FINRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_RST_TRANS;
+
+ /* ESTABLISHED and any kind of FIN without RST -> HALF-CLOSED */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_FIN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_FIN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_ESTABLISHED][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_O2I;
+
+ /* HALF-CLOSED and any kind of FIN -> FIN_TRANS */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_FINRST] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_FINRST] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_I2O][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_O2I][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_FIN_TRANS;
+
+ /* RST_TRANS and anything non-RST -> ESTABLISHED */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_NONE] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_NONE] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_FIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_RST_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+
+ /* FIN_TRANS and any kind of SYN -> HALF-REOPEN */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_I2O]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_TRANS][NAT44_ED_DIR_O2I]
+ [NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I;
+
+ /* HALF-REOPEN and any kind of SYN in right direction -> ESTABLISHED */
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
+ [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
+ [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
+ [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
+ [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
+ [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
+ [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFIN] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O]
+ [NAT44_ED_DIR_O2I][NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
+ sm->tcp_state_change_table[NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I]
+ [NAT44_ED_DIR_I2O][NAT44_ED_TCP_FLAG_SYNFINRST] =
+ NAT44_ED_TCP_STATE_ESTABLISHED;
}
+/* TCP state tracking according to RFC 7857 (and RFC 6146, which is referenced
+ * by RFC 7857). Our implementation also goes beyond by supporting creation of
+ * a new session while old session is in transitory timeout after seeing FIN
+ * packets from both sides. */
always_inline void
-nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
- u8 tcp_flags, u32 tcp_ack_number,
- u32 tcp_seq_number, u32 thread_index)
+nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses,
+ u8 tcp_flags, u32 thread_index,
+ nat44_ed_dir_e dir)
{
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))
- ses->state = 0;
- if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
- (ses->state & NAT44_SES_O2I_SYN))
- ses->state = 0;
- if (tcp_flags & TCP_FLAG_SYN)
- ses->state |= NAT44_SES_O2I_SYN;
- 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))
+ nat44_ed_tcp_flag_e flags =
+ tcp_flags & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST);
+
+ u8 old_state = ses->tcp_state;
+ ses->tcp_state = sm->tcp_state_change_table[ses->tcp_state][dir][flags];
+
+ if (old_state != ses->tcp_state)
{
- 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))
- { // if session is now closed, save the timestamp
- ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
- ses->last_lru_update = now;
+ if (nat44_ed_tcp_is_established (ses->tcp_state))
+ {
+ if (NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O == old_state ||
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I == old_state)
+ {
+ nat44_ed_session_reopen (thread_index, ses);
+ }
+ ses->lru_head_index = tsm->tcp_estab_lru_head_index;
}
+ else
+ {
+ if (NAT44_ED_TCP_STATE_ESTABLISHED == old_state)
+ { // need to update last heard otherwise session might get
+ // immediately timed out if it has been idle longer than
+ // transitory timeout
+ ses->last_heard = now;
+ }
+ ses->lru_head_index = tsm->tcp_trans_lru_head_index;
+ }
+ ses->last_lru_update = now;
+ clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+ clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
}
- // 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);
+}
+
+always_inline void
+nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
+ u8 tcp_flags, u32 thread_index)
+{
+ return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
+ NAT44_ED_DIR_I2O);
+}
+
+always_inline void
+nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
+ u8 tcp_flags, u32 thread_index)
+{
+ return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index,
+ NAT44_ED_DIR_O2I);
}
always_inline void
nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
u32 thread_index)
{
- s->last_heard = now;
+ if (NAT44_ED_TCP_STATE_RST_TRANS != s->tcp_state &&
+ NAT44_ED_TCP_STATE_FIN_TRANS != s->tcp_state &&
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O != s->tcp_state &&
+ NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I != s->tcp_state)
+ {
+ s->last_heard = now;
+ }
s->total_pkts++;
s->total_bytes += bytes;
}