tcp: improve waitclose in closing states
Change-Id: I90056176194cb2a144d49a3cb283653d8d30f051 Signed-off-by: Florin Coras <fcoras@cisco.com>
This commit is contained in:
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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* */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user