From: Florin Coras Date: Mon, 14 Aug 2017 18:25:25 +0000 (-0700) Subject: tcp: state machine improvements X-Git-Tag: v17.10-rc1~231 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=ab0289a85c45699878d203b4a0d2e5b38c36cc55 tcp: state machine improvements - Add SYN_RCVD timeout - Fix FIN_WAIT_1 to CLOSING transition Change-Id: I42ca7fc087f6fdfae15bd7a6175dd3226ed341c7 Signed-off-by: Florin Coras --- diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 78c41b938cf..bc837bb2939 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -329,7 +329,7 @@ application_open_session (application_t * app, session_type_t sst, return rv; /* Store api_context for when the reply comes. Not the nicest thing - * but better allocating a separate half-open pool. */ + * but better than allocating a separate half-open pool. */ tc->s_index = api_context; return 0; diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h index 29d37a06b18..45bc00131f5 100644 --- a/src/vnet/session/application.h +++ b/src/vnet/session/application.h @@ -37,7 +37,7 @@ typedef struct _stream_session_cb_vft int (*session_accept_callback) (stream_session_t * new_session); /* Connection request callback */ - int (*session_connected_callback) (u32 app_index, u32 api_context, + int (*session_connected_callback) (u32 app_index, u32 opaque, stream_session_t * s, u8 code); /** Notify app that session is closing */ diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 3a3e4dfe588..843d474fa19 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -373,7 +373,7 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail) application_t *app; stream_session_t *new_s = 0; u64 handle; - u32 api_context = 0; + u32 opaque = 0; int error = 0; handle = stream_session_half_open_lookup_handle (&tc->lcl_ip, &tc->rmt_ip, @@ -385,9 +385,11 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail) return -1; } - /* Get the app's index from the handle we stored when opening connection */ + /* Get the app's index from the handle we stored when opening connection + * and the opaque (api_context for external apps) from transport session + * index*/ app = application_get (handle >> 32); - api_context = tc->s_index; + opaque = tc->s_index; if (!is_fail) { @@ -406,7 +408,7 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail) } /* Notify client application */ - if (app->cb_fns.session_connected_callback (app->index, api_context, new_s, + if (app->cb_fns.session_connected_callback (app->index, opaque, new_s, is_fail)) { clib_warning ("failed to notify app"); diff --git a/src/vnet/session/stream_session.h b/src/vnet/session/stream_session.h index 4c26321194d..39bf846aca7 100644 --- a/src/vnet/session/stream_session.h +++ b/src/vnet/session/stream_session.h @@ -83,9 +83,6 @@ typedef struct _stream_session_t u32 opaque2; - /** connected (server) session handle */ - u64 server_session_handle; - /** Opaque, pad to a 64-octet boundary */ u64 opaque[1]; } stream_session_t; diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index 10ecf2f31f1..75c9d8dcc3d 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -1106,10 +1106,17 @@ tcp_timer_establish_handler (u32 conn_index) tcp_connection_t *tc; tc = tcp_half_open_connection_get (conn_index); - tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID; - - ASSERT (tc->state == TCP_STATE_SYN_SENT); - stream_session_connect_notify (&tc->connection, 1 /* fail */ ); + if (tc) + { + ASSERT (tc->state == TCP_STATE_SYN_SENT); + tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID; + stream_session_connect_notify (&tc->connection, 1 /* fail */ ); + } + else + { + tc = tcp_connection_get (conn_index, vlib_get_thread_index ()); + ASSERT (tc->state == TCP_STATE_SYN_RCVD); + } tcp_connection_cleanup (tc); } diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index 52610dddaea..8010b446d30 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -97,6 +97,7 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler; * ticks to timer units */ #define TCP_DELACK_TIME 1 /* 0.1s */ #define TCP_ESTABLISH_TIME 750 /* 75s */ +#define TCP_SYN_RCVD_TIME 100 /* 10s */ #define TCP_2MSL_TIME 300 /* 30s */ #define TCP_CLOSEWAIT_TIME 20 /* 0.1s */ #define TCP_CLEANUP_TIME 5 /* 0.5s Time to wait before cleanup */ diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 2d36c85e0c9..a3c4f1d8903 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -2254,8 +2254,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, tc0->snd_wl2 = vnet_buffer (b0)->tcp.ack_number; stream_session_accept_notify (&tc0->connection); - /* Reset SYN-ACK retransmit timer */ + /* Reset SYN-ACK retransmit and SYN_RCV establish timers */ tcp_retransmit_timer_reset (tc0); + tcp_timer_reset (tc0, TCP_TIMER_ESTABLISH); break; case TCP_STATE_ESTABLISHED: /* We can get packets in established state here because they @@ -2281,13 +2282,21 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* If FIN is ACKed */ else if (tc0->snd_una == tc0->snd_una_max) { - ASSERT (tcp_fin (tcp0)); tc0->rcv_nxt += 1; tc0->state = TCP_STATE_FIN_WAIT_2; TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); - /* Stop all timers, 2MSL will be set lower */ - tcp_connection_timers_reset (tc0); + if (tcp_fin (tcp0)) + { + /* Stop all timers, 2MSL will be set lower */ + tcp_connection_timers_reset (tc0); + } + else + { + /* Wait for peer to finish sending its data */ + tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, + TCP_2MSL_TIME); + } } break; case TCP_STATE_FIN_WAIT_2: @@ -2296,8 +2305,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, * acknowledged ("ok") but do not delete the TCB. */ if (tcp_rcv_ack (tc0, b0, tcp0, &next0, &error0)) goto drop; - - /* check if rtx queue is empty and ack CLOSE TODO */ break; case TCP_STATE_CLOSE_WAIT: /* Do the same processing as for the ESTABLISHED state. */ @@ -2311,9 +2318,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (tcp_rcv_ack (tc0, b0, tcp0, &next0, &error0)) goto drop; - /* XXX test that send queue empty */ tc0->state = TCP_STATE_TIME_WAIT; TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); goto drop; break; @@ -2409,10 +2416,12 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* move along .. */ break; case TCP_STATE_FIN_WAIT_1: - tc0->state = TCP_STATE_TIME_WAIT; - tcp_connection_timers_reset (tc0); - tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); + tc0->state = TCP_STATE_CLOSING; + tcp_make_ack (tc0, b0); + next0 = tcp_next_output (is_ip4); TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + /* Wait for ACK but not forever */ + tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); break; case TCP_STATE_FIN_WAIT_2: /* Got FIN, send ACK! */ @@ -2652,6 +2661,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* Reuse buffer to make syn-ack and send */ tcp_make_synack (child0, b0); next0 = tcp_next_output (is_ip4); + tcp_timer_set (child0, TCP_TIMER_ESTABLISH, TCP_SYN_RCVD_TIME); drop: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))