From 75c48c1fff9831b4e8bc6c9f8b2bf4f6720b61fe Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Fri, 2 Aug 2019 15:17:21 -0700 Subject: [PATCH] tcp: cleanup timers Type:refactor Change-Id: I37dbc8b55827d66c2578d6ab8b86ed7e18198aa6 Signed-off-by: Florin Coras --- src/vnet/tcp/tcp.c | 54 +------------- src/vnet/tcp/tcp.h | 5 +- src/vnet/tcp/tcp_input.c | 3 - src/vnet/tcp/tcp_output.c | 178 +++++++++++++++++++++++++--------------------- 4 files changed, 98 insertions(+), 142 deletions(-) diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index adff77c14ad..752257f4100 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -213,7 +213,6 @@ tcp_half_open_connection_cleanup (tcp_connection_t * tc) /* Make sure this is the owning thread */ if (tc->c_thread_index != vlib_get_thread_index ()) return 1; - tcp_timer_reset (tc, TCP_TIMER_ESTABLISH_AO); tcp_timer_reset (tc, TCP_TIMER_RETRANSMIT_SYN); tcp_half_open_connection_del (tc); return 0; @@ -1288,55 +1287,6 @@ tcp_connection_tx_pacer_reset (tcp_connection_t * tc, u32 window, start_bucket, last_time); } -static void -tcp_timer_keep_handler (u32 conn_index) -{ - u32 thread_index = vlib_get_thread_index (); - tcp_connection_t *tc; - - tc = tcp_connection_get (conn_index, thread_index); - tc->timers[TCP_TIMER_KEEP] = TCP_TIMER_HANDLE_INVALID; - - tcp_connection_close (tc); -} - -static void -tcp_timer_establish_handler (u32 conn_index) -{ - tcp_connection_t *tc; - - tc = tcp_connection_get (conn_index, vlib_get_thread_index ()); - /* note: the connection may have already disappeared */ - if (PREDICT_FALSE (tc == 0)) - return; - ASSERT (tc->state == TCP_STATE_SYN_RCVD); - tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID; - tcp_connection_set_state (tc, TCP_STATE_CLOSED); - tcp_connection_timers_reset (tc); - /* Start cleanup. Do NOT delete the session until we do the connection - * cleanup. Otherwise, we end up with a dangling session index in the - * tcp connection. */ - tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME); -} - -static void -tcp_timer_establish_ao_handler (u32 conn_index) -{ - tcp_connection_t *tc; - - tc = tcp_half_open_connection_get (conn_index); - if (!tc) - return; - - ASSERT (tc->state == TCP_STATE_SYN_SENT); - /* Notify app if we haven't tried to clean this up already */ - if (!(tc->flags & TCP_CONN_HALF_OPEN_DONE)) - session_stream_connect_notify (&tc->connection, 1 /* fail */ ); - - tc->timers[TCP_TIMER_ESTABLISH_AO] = TCP_TIMER_HANDLE_INVALID; - tcp_connection_cleanup (tc); -} - static void tcp_timer_waitclose_handler (u32 conn_index) { @@ -1346,6 +1296,7 @@ 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; switch (tc->state) @@ -1412,11 +1363,8 @@ static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] = tcp_timer_retransmit_handler, tcp_timer_delack_handler, tcp_timer_persist_handler, - tcp_timer_keep_handler, tcp_timer_waitclose_handler, tcp_timer_retransmit_syn_handler, - tcp_timer_establish_handler, - tcp_timer_establish_ao_handler, }; /* *INDENT-ON* */ diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index aa93bbfbd12..ae50947b797 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -71,11 +71,8 @@ format_function_t format_tcp_rcv_sacks; _(RETRANSMIT, "RETRANSMIT") \ _(DELACK, "DELAYED ACK") \ _(PERSIST, "PERSIST") \ - _(KEEP, "KEEP") \ _(WAITCLOSE, "WAIT CLOSE") \ _(RETRANSMIT_SYN, "RETRANSMIT SYN") \ - _(ESTABLISH, "ESTABLISH") \ - _(ESTABLISH_AO, "ESTABLISH_AO") \ typedef enum _tcp_timers { @@ -98,7 +95,6 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler; #define TCP_TO_TIMER_TICK TCP_TICK*10 /* Period for converting from TCP * ticks to timer units */ #define TCP_DELACK_TIME 1 /* 0.1s */ -#define TCP_ESTABLISH_TIME 750 /* 75s */ #define TCP_SYN_RCVD_TIME 600 /* 60s */ #define TCP_2MSL_TIME 300 /* 30s */ #define TCP_CLOSEWAIT_TIME 20 /* 2s */ @@ -113,6 +109,7 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler; #define TCP_RTO_SYN_RETRIES 3 /* SYN retries without doubling RTO */ #define TCP_RTO_INIT 1 * THZ /* Initial retransmit timer */ #define TCP_RTO_BOFF_MAX 8 /* Max number of retries before reset */ +#define TCP_ESTABLISH_TIME (60 * THZ) /* Connection establish timeout */ /** TCP connection flags */ #define foreach_tcp_connection_flag \ diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 2fadab59eb8..504133cf2a7 100755 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -2439,7 +2439,6 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, new_tc0->c_thread_index = my_thread_index; new_tc0->rcv_nxt = vnet_buffer (b0)->tcp.seq_end; new_tc0->irs = seq0; - new_tc0->timers[TCP_TIMER_ESTABLISH_AO] = TCP_TIMER_HANDLE_INVALID; new_tc0->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID; new_tc0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; @@ -2714,7 +2713,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* Reset SYN-ACK retransmit and SYN_RCV establish timers */ tcp_retransmit_timer_reset (tc0); - tcp_timer_reset (tc0, TCP_TIMER_ESTABLISH); if (session_stream_accept_notify (&tc0->connection)) { error0 = TCP_ERROR_MSG_QUEUE_FULL; @@ -3160,7 +3158,6 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node, TCP_EVT_DBG (TCP_EVT_SYN_RCVD, child0, 1); child0->tx_fifo_size = transport_tx_fifo_size (&child0->connection); tcp_send_synack (child0); - tcp_timer_set (child0, TCP_TIMER_ESTABLISH, TCP_SYN_RCVD_TIME); drop: diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index 751d8b31382..ef8b756e4e8 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -942,7 +942,6 @@ tcp_send_syn (tcp_connection_t * tc) * Setup retransmit and establish timers before requesting buffer * such that we can return if we've ran out. */ - tcp_timer_set (tc, TCP_TIMER_ESTABLISH_AO, TCP_ESTABLISH_TIME); tcp_timer_update (tc, TCP_TIMER_RETRANSMIT_SYN, tc->rto * TCP_TO_TIMER_TICK); @@ -1467,8 +1466,8 @@ tcp_cc_init_rxt_timeout (tcp_connection_t * tc) tcp_recovery_on (tc); } -static inline void -tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) +void +tcp_timer_retransmit_handler (u32 tc_index) { u32 thread_index = vlib_get_thread_index (); tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index); @@ -1477,25 +1476,17 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) vlib_buffer_t *b = 0; u32 bi, n_bytes; - if (is_syn) - { - tc = tcp_half_open_connection_get (index); - /* Note: the connection may have transitioned to ESTABLISHED... */ - if (PREDICT_FALSE (tc == 0 || tc->state != TCP_STATE_SYN_SENT)) - return; - tc->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID; - } - else - { - tc = tcp_connection_get (index, thread_index); - /* Note: the connection may have been closed and pool_put */ - if (PREDICT_FALSE (tc == 0 || tc->state == TCP_STATE_SYN_SENT)) - return; - tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID; - /* Wait-close and retransmit could pop at the same time */ - if (tc->state == TCP_STATE_CLOSED) - return; - } + tc = tcp_connection_get (tc_index, thread_index); + + /* Note: the connection may have been closed and pool_put */ + if (PREDICT_FALSE (tc == 0 || tc->state == TCP_STATE_SYN_SENT)) + return; + + tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID; + + /* Wait-close and retransmit could pop at the same time */ + if (tc->state == TCP_STATE_CLOSED) + return; if (tc->state >= TCP_STATE_ESTABLISHED) { @@ -1551,19 +1542,20 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) /* First retransmit timeout */ if (tc->rto_boff == 1) - tcp_cc_init_rxt_timeout (tc); + { + tcp_cc_init_rxt_timeout (tc); + /* Record timestamp. Eifel detection algorithm RFC3522 */ + tc->snd_rxt_ts = tcp_tstamp (tc); + } if (tc->flags & TCP_CONN_RATE_SAMPLE) tcp_bt_flush_samples (tc); /* If we've sent beyond snd_congestion, update it */ tc->snd_congestion = seq_max (tc->snd_nxt, tc->snd_congestion); - tc->snd_nxt = tc->snd_una; - tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX); - /* Send one segment. Note that n_bytes may be zero due to buffer - * shortfall */ + /* Send one segment. n_bytes may be zero due to buffer shortfall */ n_bytes = tcp_prepare_retransmit_segment (wrk, tc, 0, tc->snd_mss, &b); if (!n_bytes) { @@ -1572,73 +1564,39 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) } bi = vlib_get_buffer_index (vm, b); - - /* For first retransmit, record timestamp (Eifel detection RFC3522) */ - if (tc->rto_boff == 1) - tc->snd_rxt_ts = tcp_tstamp (tc); - tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4); + + tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX); tcp_retransmit_timer_force_update (tc); } - /* Retransmit for SYN */ - else if (tc->state == TCP_STATE_SYN_SENT) + /* Retransmit SYN-ACK */ + else if (tc->state == TCP_STATE_SYN_RCVD) { - /* Half-open connection actually moved to established but we were - * waiting for syn retransmit to pop to call cleanup from the right - * thread. */ - if (tc->flags & TCP_CONN_HALF_OPEN_DONE) - { - if (tcp_half_open_connection_cleanup (tc)) - TCP_DBG ("could not remove half-open connection"); - return; - } - TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 2); - /* Try without increasing RTO a number of times. If this fails, - * start growing RTO exponentially */ - tc->rto_boff += 1; - if (tc->rto_boff > TCP_RTO_SYN_RETRIES) - tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX); + tc->rtt_ts = 0; - tcp_timer_update (tc, TCP_TIMER_RETRANSMIT_SYN, - tc->rto * TCP_TO_TIMER_TICK); + /* Passive open establish timeout */ + if (tc->rto > TCP_ESTABLISH_TIME >> 1) + { + tcp_connection_set_state (tc, TCP_STATE_CLOSED); + tcp_connection_timers_reset (tc); + tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME); + return; + } if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1))) { - tcp_timer_update (tc, TCP_TIMER_RETRANSMIT_SYN, 1); + tcp_timer_update (tc, TCP_TIMER_RETRANSMIT, 1); return; } - b = vlib_get_buffer (vm, bi); - tcp_init_buffer (vm, b); - tcp_make_syn (tc, b); - - tc->rtt_ts = 0; - TCP_EVT_DBG (TCP_EVT_SYN_RXT, tc, 0); - - /* This goes straight to ipx_lookup. Retransmit timer set already */ - tcp_push_ip_hdr (wrk, tc, b); - tcp_enqueue_to_ip_lookup (wrk, b, bi, tc->c_is_ip4, tc->c_fib_index); - } - /* Retransmit SYN-ACK */ - else if (tc->state == TCP_STATE_SYN_RCVD) - { - TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 2); - tc->rto_boff += 1; if (tc->rto_boff > TCP_RTO_SYN_RETRIES) tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX); - tc->rtt_ts = 0; tcp_retransmit_timer_force_update (tc); - if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1))) - { - tcp_timer_update (tc, TCP_TIMER_RETRANSMIT, 1); - return; - } - b = vlib_get_buffer (vm, bi); tcp_init_buffer (vm, b); tcp_make_synack (tc, b); @@ -1654,16 +1612,72 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) } } +/** + * SYN retransmit timer handler. Active open only. + */ void -tcp_timer_retransmit_handler (u32 index) +tcp_timer_retransmit_syn_handler (u32 tc_index) { - tcp_timer_retransmit_handler_i (index, 0); -} + u32 thread_index = vlib_get_thread_index (); + tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index); + vlib_main_t *vm = wrk->vm; + tcp_connection_t *tc; + vlib_buffer_t *b = 0; + u32 bi; -void -tcp_timer_retransmit_syn_handler (u32 index) -{ - tcp_timer_retransmit_handler_i (index, 1); + tc = tcp_half_open_connection_get (tc_index); + + /* Note: the connection may have transitioned to ESTABLISHED... */ + if (PREDICT_FALSE (tc == 0 || tc->state != TCP_STATE_SYN_SENT)) + return; + + tc->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID; + + /* Half-open connection actually moved to established but we were + * waiting for syn retransmit to pop to call cleanup from the right + * thread. */ + if (tc->flags & TCP_CONN_HALF_OPEN_DONE) + { + if (tcp_half_open_connection_cleanup (tc)) + TCP_DBG ("could not remove half-open connection"); + return; + } + + TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 2); + tc->rtt_ts = 0; + + /* Active open establish timeout */ + if (tc->rto >= TCP_ESTABLISH_TIME >> 1) + { + session_stream_connect_notify (&tc->connection, 1 /* fail */ ); + tcp_connection_cleanup (tc); + return; + } + + if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1))) + { + tcp_timer_update (tc, TCP_TIMER_RETRANSMIT_SYN, 1); + return; + } + + /* Try without increasing RTO a number of times. If this fails, + * start growing RTO exponentially */ + tc->rto_boff += 1; + if (tc->rto_boff > TCP_RTO_SYN_RETRIES) + tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX); + + b = vlib_get_buffer (vm, bi); + tcp_init_buffer (vm, b); + tcp_make_syn (tc, b); + + TCP_EVT_DBG (TCP_EVT_SYN_RXT, tc, 0); + + /* This goes straight to ipx_lookup */ + tcp_push_ip_hdr (wrk, tc, b); + tcp_enqueue_to_ip_lookup (wrk, b, bi, tc->c_is_ip4, tc->c_fib_index); + + tcp_timer_update (tc, TCP_TIMER_RETRANSMIT_SYN, + tc->rto * TCP_TO_TIMER_TICK); } /** -- 2.16.6