tcp: updates to connection closing procedure (VPP-996)
- add separate TIME_WAIT time constant - fix output node for TIME_WAIT acks - ensure snd_nxt is snd_una_max after retransmitting fin - debugging improvements Change-Id: Ic947153346979853f2526824b229126e47aead86 Signed-off-by: Florin Coras <fcoras@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
b4d3c96f89
commit
a096f2d182
@ -314,19 +314,22 @@ tcp_connection_close (tcp_connection_t * tc)
|
|||||||
tc->state = TCP_STATE_FIN_WAIT_1;
|
tc->state = TCP_STATE_FIN_WAIT_1;
|
||||||
break;
|
break;
|
||||||
case TCP_STATE_CLOSE_WAIT:
|
case TCP_STATE_CLOSE_WAIT:
|
||||||
|
tcp_connection_timers_reset (tc);
|
||||||
tcp_send_fin (tc);
|
tcp_send_fin (tc);
|
||||||
tc->state = TCP_STATE_LAST_ACK;
|
tc->state = TCP_STATE_LAST_ACK;
|
||||||
|
tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
|
||||||
break;
|
break;
|
||||||
case TCP_STATE_FIN_WAIT_1:
|
case TCP_STATE_FIN_WAIT_1:
|
||||||
|
tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
clib_warning ("state: %u", tc->state);
|
TCP_DBG ("state: %u", tc->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
|
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
|
||||||
|
|
||||||
/* If in CLOSED and WAITCLOSE timer is not set, delete connection now */
|
/* If in CLOSED and WAITCLOSE timer is not set, delete connection now */
|
||||||
if (tc->timers[TCP_TIMER_WAITCLOSE] == TCP_TIMER_HANDLE_INVALID
|
if (!tcp_timer_is_active (tc, TCP_TIMER_WAITCLOSE)
|
||||||
&& tc->state == TCP_STATE_CLOSED)
|
&& tc->state == TCP_STATE_CLOSED)
|
||||||
tcp_connection_del (tc);
|
tcp_connection_del (tc);
|
||||||
}
|
}
|
||||||
@ -344,6 +347,7 @@ tcp_session_cleanup (u32 conn_index, u32 thread_index)
|
|||||||
{
|
{
|
||||||
tcp_connection_t *tc;
|
tcp_connection_t *tc;
|
||||||
tc = tcp_connection_get (conn_index, thread_index);
|
tc = tcp_connection_get (conn_index, thread_index);
|
||||||
|
tcp_connection_timers_reset (tc);
|
||||||
|
|
||||||
/* Wait for the session tx events to clear */
|
/* Wait for the session tx events to clear */
|
||||||
tc->state = TCP_STATE_CLOSED;
|
tc->state = TCP_STATE_CLOSED;
|
||||||
@ -748,6 +752,31 @@ format_tcp_state (u8 * s, va_list * args)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *tcp_connection_flags_str[] = {
|
||||||
|
#define _(sym, str) str,
|
||||||
|
foreach_tcp_connection_flag
|
||||||
|
#undef _
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 *
|
||||||
|
format_tcp_connection_flags (u8 * s, va_list * args)
|
||||||
|
{
|
||||||
|
tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
|
||||||
|
int i, last = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < TCP_CONN_N_FLAG_BITS; i++)
|
||||||
|
if (tc->flags & (1 << i))
|
||||||
|
last = i;
|
||||||
|
for (i = 0; i < last; i++)
|
||||||
|
{
|
||||||
|
if (tc->flags & (1 << i))
|
||||||
|
s = format (s, "%s, ", tcp_connection_flags_str[i]);
|
||||||
|
}
|
||||||
|
if (last >= 0)
|
||||||
|
s = format (s, "%s", tcp_connection_flags_str[last]);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
const char *tcp_conn_timers[] = {
|
const char *tcp_conn_timers[] = {
|
||||||
#define _(sym, str) str,
|
#define _(sym, str) str,
|
||||||
foreach_tcp_timer
|
foreach_tcp_timer
|
||||||
@ -796,6 +825,8 @@ u8 *
|
|||||||
format_tcp_vars (u8 * s, va_list * args)
|
format_tcp_vars (u8 * s, va_list * args)
|
||||||
{
|
{
|
||||||
tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
|
tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
|
||||||
|
s = format (s, " flags: %U timers: %U\n", format_tcp_connection_flags, tc,
|
||||||
|
format_tcp_timers, tc);
|
||||||
s = format (s, " snd_una %u snd_nxt %u snd_una_max %u",
|
s = format (s, " snd_una %u snd_nxt %u snd_una_max %u",
|
||||||
tc->snd_una - tc->iss, tc->snd_nxt - tc->iss,
|
tc->snd_una - tc->iss, tc->snd_nxt - tc->iss,
|
||||||
tc->snd_una_max - tc->iss);
|
tc->snd_una_max - tc->iss);
|
||||||
@ -866,7 +897,7 @@ format_tcp_connection (u8 * s, va_list * args)
|
|||||||
{
|
{
|
||||||
s = format (s, "%-15U", format_tcp_state, tc->state);
|
s = format (s, "%-15U", format_tcp_state, tc->state);
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
s = format (s, " %U\n%U", format_tcp_timers, tc, format_tcp_vars, tc);
|
s = format (s, "\n%U", format_tcp_vars, tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -100,7 +100,7 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler;
|
|||||||
#define TCP_SYN_RCVD_TIME 600 /* 60s */
|
#define TCP_SYN_RCVD_TIME 600 /* 60s */
|
||||||
#define TCP_2MSL_TIME 300 /* 30s */
|
#define TCP_2MSL_TIME 300 /* 30s */
|
||||||
#define TCP_CLOSEWAIT_TIME 20 /* 2s */
|
#define TCP_CLOSEWAIT_TIME 20 /* 2s */
|
||||||
#define TCP_TIMEWAIT_TIME 20 /* 2s */
|
#define TCP_TIMEWAIT_TIME 100 /* 10s */
|
||||||
#define TCP_CLEANUP_TIME 10 /* 1s Time to wait before cleanup */
|
#define TCP_CLEANUP_TIME 10 /* 1s Time to wait before cleanup */
|
||||||
#define TCP_TIMER_PERSIST_MIN 2 /* 0.2s */
|
#define TCP_TIMER_PERSIST_MIN 2 /* 0.2s */
|
||||||
|
|
||||||
@ -114,9 +114,9 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler;
|
|||||||
#define foreach_tcp_connection_flag \
|
#define foreach_tcp_connection_flag \
|
||||||
_(SNDACK, "Send ACK") \
|
_(SNDACK, "Send ACK") \
|
||||||
_(FINSNT, "FIN sent") \
|
_(FINSNT, "FIN sent") \
|
||||||
_(SENT_RCV_WND0, "Sent 0 receive window") \
|
_(SENT_RCV_WND0, "Sent 0 rcv_wnd") \
|
||||||
_(RECOVERY, "Recovery on") \
|
_(RECOVERY, "Recovery") \
|
||||||
_(FAST_RECOVERY, "Fast Recovery on") \
|
_(FAST_RECOVERY, "Fast Recovery") \
|
||||||
_(FR_1_SMSS, "Sent 1 SMSS") \
|
_(FR_1_SMSS, "Sent 1 SMSS") \
|
||||||
_(HALF_OPEN_DONE, "Half-open completed") \
|
_(HALF_OPEN_DONE, "Half-open completed") \
|
||||||
_(FINPNDG, "FIN pending")
|
_(FINPNDG, "FIN pending")
|
||||||
|
@ -2352,7 +2352,7 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
*/
|
*/
|
||||||
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
|
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
|
||||||
{
|
{
|
||||||
clib_warning ("connection not accepted");
|
TCP_DBG ("connection not accepted");
|
||||||
tcp_send_reset_w_pkt (tc0, b0, is_ip4);
|
tcp_send_reset_w_pkt (tc0, b0, is_ip4);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
@ -2431,7 +2431,7 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
|
|
||||||
tc0->state = TCP_STATE_TIME_WAIT;
|
tc0->state = TCP_STATE_TIME_WAIT;
|
||||||
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
|
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
|
||||||
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
|
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -2441,11 +2441,14 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
* delete the TCB, enter the CLOSED state, and return. */
|
* delete the TCB, enter the CLOSED state, and return. */
|
||||||
|
|
||||||
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
|
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
|
||||||
goto drop;
|
{
|
||||||
|
error0 = TCP_ERROR_ACK_INVALID;
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
tc0->snd_una = vnet_buffer (b0)->tcp.ack_number;
|
tc0->snd_una = vnet_buffer (b0)->tcp.ack_number;
|
||||||
/* Apparently our FIN was lost */
|
/* Apparently our ACK for the peer's FIN was lost */
|
||||||
if (is_fin0)
|
if (is_fin0 && tc0->snd_una != tc0->snd_una_max)
|
||||||
{
|
{
|
||||||
tcp_send_fin (tc0);
|
tcp_send_fin (tc0);
|
||||||
goto drop;
|
goto drop;
|
||||||
@ -2453,13 +2456,13 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
|
|
||||||
tc0->state = TCP_STATE_CLOSED;
|
tc0->state = TCP_STATE_CLOSED;
|
||||||
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
|
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
|
||||||
|
tcp_connection_timers_reset (tc0);
|
||||||
|
|
||||||
/* Don't delete the connection/session yet. Instead, wait a
|
/* Don't delete the connection/session yet. Instead, wait a
|
||||||
* reasonable amount of time until the pipes are cleared. In
|
* reasonable amount of time until the pipes are cleared. In
|
||||||
* particular, this makes sure that we won't have dead sessions
|
* particular, this makes sure that we won't have dead sessions
|
||||||
* when processing events on the tx path */
|
* when processing events on the tx path */
|
||||||
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
|
tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
|
||||||
tcp_retransmit_timer_reset (tc0);
|
|
||||||
|
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
@ -2473,7 +2476,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
|
|||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
tcp_make_ack (tc0, b0);
|
tcp_make_ack (tc0, b0);
|
||||||
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
|
next0 = tcp_next_output (is_ip4);
|
||||||
|
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
|
||||||
|
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
|
@ -1055,7 +1055,6 @@ tcp_send_fin (tcp_connection_t * tc)
|
|||||||
u32 bi;
|
u32 bi;
|
||||||
u8 fin_snt = 0;
|
u8 fin_snt = 0;
|
||||||
|
|
||||||
|
|
||||||
if (PREDICT_FALSE (tcp_get_free_buffer_index (tm, &bi)))
|
if (PREDICT_FALSE (tcp_get_free_buffer_index (tm, &bi)))
|
||||||
return;
|
return;
|
||||||
b = vlib_get_buffer (vm, bi);
|
b = vlib_get_buffer (vm, bi);
|
||||||
@ -1072,6 +1071,10 @@ tcp_send_fin (tcp_connection_t * tc)
|
|||||||
tc->snd_una_max += 1;
|
tc->snd_una_max += 1;
|
||||||
tc->snd_nxt = tc->snd_una_max;
|
tc->snd_nxt = tc->snd_una_max;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tc->snd_nxt = tc->snd_una_max;
|
||||||
|
}
|
||||||
tcp_retransmit_timer_force_update (tc);
|
tcp_retransmit_timer_force_update (tc);
|
||||||
TCP_EVT_DBG (TCP_EVT_FIN_SENT, tc);
|
TCP_EVT_DBG (TCP_EVT_FIN_SENT, tc);
|
||||||
}
|
}
|
||||||
@ -1381,6 +1384,13 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shouldn't be here */
|
||||||
|
if (tc->snd_una == tc->snd_una_max)
|
||||||
|
{
|
||||||
|
tcp_recovery_off (tc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* We're not in recovery so make sure rto_boff is 0 */
|
/* We're not in recovery so make sure rto_boff is 0 */
|
||||||
if (!tcp_in_recovery (tc) && tc->rto_boff > 0)
|
if (!tcp_in_recovery (tc) && tc->rto_boff > 0)
|
||||||
{
|
{
|
||||||
@ -1485,7 +1495,8 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ASSERT (tc->state == TCP_STATE_CLOSED);
|
ASSERT (tc->state == TCP_STATE_CLOSED);
|
||||||
TCP_DBG ("connection state: %d", tc->state);
|
if (CLIB_DEBUG)
|
||||||
|
TCP_DBG ("connection state: %U", format_tcp_connection, tc, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user