tcp: improve waitclose in closing states

Change-Id: I90056176194cb2a144d49a3cb283653d8d30f051
Signed-off-by: Florin Coras <fcoras@cisco.com>
This commit is contained in:
Florin Coras
2018-12-21 13:54:09 -08:00
parent 8d6f34e2b1
commit 54ddf43533
6 changed files with 84 additions and 18 deletions

View File

@ -829,6 +829,24 @@ stream_session_delete_notify (transport_connection_t * tc)
}
}
/**
* Notification from transport that session can be closed
*
* Should be called by transport only if it was closed with non-empty
* tx fifo and once it decides to begin the closing procedure prior to
* issuing a delete notify. This gives the chance to the session layer
* to cleanup any outstanding events.
*/
void
session_stream_close_notify (transport_connection_t * tc)
{
stream_session_t *s;
if (!(s = session_get_if_valid (tc->s_index, tc->thread_index)))
return;
s->session_state = SESSION_STATE_CLOSED;
}
/**
* Notify application that connection has been reset.
*/

View File

@ -613,6 +613,7 @@ void stream_session_init_fifos_pointers (transport_connection_t * tc,
int stream_session_accept_notify (transport_connection_t * tc);
void stream_session_disconnect_notify (transport_connection_t * tc);
void stream_session_delete_notify (transport_connection_t * tc);
void session_stream_close_notify (transport_connection_t * tc);
void stream_session_reset_notify (transport_connection_t * tc);
int stream_session_accept (transport_connection_t * tc, u32 listener_index,
u8 notify);

View File

@ -299,6 +299,7 @@ tcp_connection_reset (tcp_connection_t * tc)
case TCP_STATE_FIN_WAIT_1:
case TCP_STATE_FIN_WAIT_2:
case TCP_STATE_CLOSING:
case TCP_STATE_LAST_ACK:
tcp_connection_timers_reset (tc);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
tc->state = TCP_STATE_CLOSED;
@ -1249,38 +1250,65 @@ tcp_timer_waitclose_handler (u32 conn_index)
tc = tcp_connection_get (conn_index, thread_index);
if (!tc)
return;
tc->timers[TCP_TIMER_WAITCLOSE] = TCP_TIMER_HANDLE_INVALID;
/* Session didn't come back with a close(). Send FIN either way
* and switch to LAST_ACK. */
if (tc->state == TCP_STATE_CLOSE_WAIT && (tc->flags & TCP_CONN_FINPNDG))
switch (tc->state)
{
/* Make sure we don't try to send unsent data */
case TCP_STATE_CLOSE_WAIT:
tcp_connection_timers_reset (tc);
if (!(tc->flags & TCP_CONN_FINPNDG))
{
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
break;
}
/* Session didn't come back with a close. Send FIN either way
* and switch to LAST_ACK. */
tcp_cong_recovery_off (tc);
/* Make sure we don't try to send unsent data */
tc->snd_una_max = tc->snd_nxt = tc->snd_una;
tcp_send_fin (tc);
tc->state = TCP_STATE_LAST_ACK;
tcp_connection_set_state (tc, TCP_STATE_LAST_ACK);
/* Make sure we don't wait in LAST ACK forever */
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
/* Don't delete the connection yet */
return;
}
else if (tc->state == TCP_STATE_FIN_WAIT_1)
{
break;
case TCP_STATE_FIN_WAIT_1:
tcp_connection_timers_reset (tc);
/* If FIN pending send it before closing */
if (tc->flags & TCP_CONN_FINPNDG)
tcp_send_fin (tc);
tc->state = TCP_STATE_CLOSED;
/* Wait for session layer to clean up tx events */
{
/* If FIN pending send it before closing and wait as long as
* the rto timeout would wait. Notify session layer that transport
* is closed. We haven't sent everything but we did try. */
tcp_cong_recovery_off (tc);
tcp_send_fin (tc);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE,
clib_max (tc->rto * TCP_TO_TIMER_TICK, 1));
session_stream_close_notify (&tc->connection);
}
else
{
/* We've sent the fin but no progress. Close the connection and
* to make sure everything is flushed, setup a cleanup timer */
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
}
break;
case TCP_STATE_LAST_ACK:
case TCP_STATE_CLOSING:
tcp_connection_timers_reset (tc);
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
return;
break;
default:
tcp_connection_del (tc);
break;
}
tcp_connection_del (tc);
}
/* *INDENT-OFF* */

View File

@ -562,6 +562,13 @@ tcp_get_connection_from_transport (transport_connection_t * tconn)
return (tcp_connection_t *) tconn;
}
always_inline void
tcp_connection_set_state (tcp_connection_t * tc, tcp_state_t state)
{
tc->state = state;
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
}
void tcp_connection_close (tcp_connection_t * tc);
void tcp_connection_cleanup (tcp_connection_t * tc);
void tcp_connection_del (tcp_connection_t * tc);

View File

@ -509,6 +509,7 @@ tcp_estimate_initial_rtt (tcp_connection_t * tc)
if (mrtt > 0 && mrtt < TCP_RTT_MAX)
tcp_estimate_rtt (tc, mrtt);
tcp_update_rto (tc);
}
/**
@ -3710,6 +3711,10 @@ do { \
_(FIN_WAIT_1, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
_(CLOSING, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSING, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSING, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSING, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
/* FIN confirming that the peer (app) has closed */
_(FIN_WAIT_2, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_2, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);

View File

@ -392,9 +392,13 @@ tcp_make_options (tcp_connection_t * tc, tcp_options_t * opts,
switch (state)
{
case TCP_STATE_ESTABLISHED:
case TCP_STATE_FIN_WAIT_1:
case TCP_STATE_CLOSED:
case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_FIN_WAIT_1:
case TCP_STATE_LAST_ACK:
case TCP_STATE_CLOSING:
case TCP_STATE_FIN_WAIT_2:
case TCP_STATE_TIME_WAIT:
case TCP_STATE_CLOSED:
return tcp_make_established_options (tc, opts);
case TCP_STATE_SYN_RCVD:
return tcp_make_synack_options (tc, opts);
@ -1124,6 +1128,8 @@ tcp_make_state_flags (tcp_connection_t * tc, tcp_state_t next_state)
{
case TCP_STATE_ESTABLISHED:
case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_TIME_WAIT:
case TCP_STATE_FIN_WAIT_2:
return TCP_FLAG_ACK;
case TCP_STATE_SYN_RCVD:
return TCP_FLAG_SYN | TCP_FLAG_ACK;
@ -1131,6 +1137,7 @@ tcp_make_state_flags (tcp_connection_t * tc, tcp_state_t next_state)
return TCP_FLAG_SYN;
case TCP_STATE_LAST_ACK:
case TCP_STATE_FIN_WAIT_1:
case TCP_STATE_CLOSING:
if (tc->snd_nxt + 1 < tc->snd_una_max)
return TCP_FLAG_ACK;
else