summaryrefslogtreecommitdiffstats
path: root/src/vnet/tcp/tcp.c
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2018-12-18 22:44:27 -0800
committerFlorin Coras <fcoras@cisco.com>2018-12-19 02:17:34 -0800
commite96bf63bd0dc483179dc595b65ebd8bf2b310b8b (patch)
treede98f93bf4ac9aab85782b2e3f34d02583d35646 /src/vnet/tcp/tcp.c
parente2ea193171f4701aa575379da0e1bac16a85aa33 (diff)
tcp/session: notify transport of close when tx fifo is not empty
Disconnect transport even if tx fifo is not empty and have transport deal with the problem. In case of tcp, add timer to fin_wait_1. If it expires and we're still in established state, cleanup but only after waiting for session tx events to cleanup. Change-Id: I45759a3c43dd096bb2c03daf5372416c30678d62 Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/tcp/tcp.c')
-rw-r--r--src/vnet/tcp/tcp.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index 285ed624d56..9a3c90425b2 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -290,7 +290,7 @@ tcp_connection_reset (tcp_connection_t * tc)
tcp_connection_timers_reset (tc);
/* Set the cleanup timer, in case the session layer/app don't
* cleanly close the connection */
- tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
+ tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
stream_session_reset_notify (&tc->connection);
break;
case TCP_STATE_CLOSE_WAIT:
@@ -300,7 +300,7 @@ tcp_connection_reset (tcp_connection_t * tc)
tc->state = TCP_STATE_CLOSED;
TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
tcp_connection_timers_reset (tc);
- tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
+ tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
break;
case TCP_STATE_CLOSED:
return;
@@ -336,7 +336,7 @@ tcp_connection_close (tcp_connection_t * tc)
tcp_connection_timers_reset (tc);
tcp_send_fin (tc);
tc->state = TCP_STATE_FIN_WAIT_1;
- tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
+ tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_FINWAIT1_TIME);
break;
case TCP_STATE_ESTABLISHED:
if (!session_tx_fifo_max_dequeue (&tc->connection))
@@ -344,6 +344,9 @@ tcp_connection_close (tcp_connection_t * tc)
else
tc->flags |= TCP_CONN_FINPNDG;
tc->state = TCP_STATE_FIN_WAIT_1;
+ /* Set a timer in case the peer stops responding. Otherwise the
+ * connection will be stuck here forever. */
+ tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_FINWAIT1_TIME);
break;
case TCP_STATE_CLOSE_WAIT:
if (!session_tx_fifo_max_dequeue (&tc->connection))
@@ -373,7 +376,7 @@ tcp_connection_close (tcp_connection_t * tc)
* the session layer a chance to clear unhandled events */
if (!tcp_timer_is_active (tc, TCP_TIMER_WAITCLOSE)
&& tc->state == TCP_STATE_CLOSED)
- tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, 1);
+ tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
}
static void
@@ -1251,11 +1254,6 @@ tcp_timer_waitclose_handler (u32 conn_index)
* and switch to LAST_ACK. */
if (tc->state == TCP_STATE_CLOSE_WAIT)
{
- if (tc->flags & TCP_CONN_FINSNT)
- {
- clib_warning ("FIN was sent and still in CLOSE WAIT. Weird!");
- }
-
/* Make sure we don't try to send unsent data */
tcp_connection_timers_reset (tc);
tcp_cong_recovery_off (tc);
@@ -1269,6 +1267,13 @@ tcp_timer_waitclose_handler (u32 conn_index)
/* Don't delete the connection yet */
return;
}
+ else if (tc->state == TCP_STATE_FIN_WAIT_1)
+ {
+ /* Wait for session layer to clean up tx events */
+ tc->state = TCP_STATE_CLOSED;
+ tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
+ return;
+ }
tcp_connection_del (tc);
}