summaryrefslogtreecommitdiffstats
path: root/src/vnet/tcp/tcp.c
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2020-02-14 23:41:25 +0000
committerDave Barach <openvpp@barachs.net>2020-02-18 15:53:06 +0000
commitaa3886993c13d71d93ef01dc73b79985d6ec997f (patch)
treea112192692c4bdb66b73579d18582800b597aee0 /src/vnet/tcp/tcp.c
parent4339c36157c0579c60963cea4bafd3ce2521d207 (diff)
tcp: pace timer handling
Type: improvement Signed-off-by: Florin Coras <fcoras@cisco.com> Change-Id: I93067054631d6ae2411a7b08d7b681aed7a121b2
Diffstat (limited to 'src/vnet/tcp/tcp.c')
-rw-r--r--src/vnet/tcp/tcp.c248
1 files changed, 147 insertions, 101 deletions
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index e34f773d7d3..f24ddb3a879 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -1288,103 +1288,23 @@ tcp_session_tx_fifo_offset (transport_connection_t * trans_conn)
}
static void
-tcp_update_time (f64 now, u8 thread_index)
-{
- tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
-
- tcp_set_time_now (wrk);
- tw_timer_expire_timers_16t_2w_512sl (&wrk->timer_wheel, now);
- tcp_flush_frames_to_output (wrk);
-}
-
-static void
-tcp_session_flush_data (transport_connection_t * tconn)
-{
- tcp_connection_t *tc = (tcp_connection_t *) tconn;
- if (tc->flags & TCP_CONN_PSH_PENDING)
- return;
- tc->flags |= TCP_CONN_PSH_PENDING;
- tc->psh_seq = tc->snd_una + transport_max_tx_dequeue (tconn) - 1;
-}
-
-/* *INDENT-OFF* */
-const static transport_proto_vft_t tcp_proto = {
- .enable = vnet_tcp_enable_disable,
- .start_listen = tcp_session_bind,
- .stop_listen = tcp_session_unbind,
- .push_header = tcp_session_push_header,
- .get_connection = tcp_session_get_transport,
- .get_listener = tcp_session_get_listener,
- .get_half_open = tcp_half_open_session_get_transport,
- .connect = tcp_session_open,
- .close = tcp_session_close,
- .cleanup = tcp_session_cleanup,
- .reset = tcp_session_reset,
- .send_mss = tcp_session_send_mss,
- .send_space = tcp_session_send_space,
- .update_time = tcp_update_time,
- .tx_fifo_offset = tcp_session_tx_fifo_offset,
- .flush_data = tcp_session_flush_data,
- .custom_tx = tcp_session_custom_tx,
- .format_connection = format_tcp_session,
- .format_listener = format_tcp_listener_session,
- .format_half_open = format_tcp_half_open_session,
- .transport_options = {
- .tx_type = TRANSPORT_TX_PEEK,
- .service_type = TRANSPORT_SERVICE_VC,
- },
-};
-/* *INDENT-ON* */
-
-void
-tcp_connection_tx_pacer_update (tcp_connection_t * tc)
-{
- if (!transport_connection_is_tx_paced (&tc->connection))
- return;
-
- f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
-
- transport_connection_tx_pacer_update (&tc->connection,
- tcp_cc_get_pacing_rate (tc),
- srtt * CLIB_US_TIME_FREQ);
-}
-
-void
-tcp_connection_tx_pacer_reset (tcp_connection_t * tc, u32 window,
- u32 start_bucket)
-{
- f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
- transport_connection_tx_pacer_reset (&tc->connection,
- tcp_cc_get_pacing_rate (tc),
- start_bucket,
- srtt * CLIB_US_TIME_FREQ);
-}
-
-static void
-tcp_timer_waitclose_handler (u32 conn_index, u32 thread_index)
+tcp_timer_waitclose_handler (tcp_connection_t * tc)
{
- tcp_connection_t *tc;
-
- tc = tcp_connection_get (conn_index, thread_index);
- if (!tc)
- return;
-
switch (tc->state)
{
case TCP_STATE_CLOSE_WAIT:
tcp_connection_timers_reset (tc);
session_transport_closed_notify (&tc->connection);
-
+ /* App never returned with a close */
if (!(tc->flags & TCP_CONN_FINPNDG))
{
- clib_warning ("close-wait with fin sent");
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
+ tcp_worker_stats_inc (tc->c_thread_index, to_closewait, 1);
break;
}
- /* Session didn't come back with a close. Send FIN either way
- * and switch to LAST_ACK. */
+ /* 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_nxt = tc->snd_una;
@@ -1393,7 +1313,7 @@ tcp_timer_waitclose_handler (u32 conn_index, u32 thread_index)
/* Make sure we don't wait in LAST ACK forever */
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.lastack_time);
- tcp_worker_stats_inc (thread_index, to_closewait, 1);
+ tcp_worker_stats_inc (tc->c_thread_index, to_closewait2, 1);
/* Don't delete the connection yet */
break;
@@ -1415,21 +1335,21 @@ tcp_timer_waitclose_handler (u32 conn_index, u32 thread_index)
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
}
- tcp_worker_stats_inc (thread_index, to_finwait1, 1);
+ tcp_worker_stats_inc (tc->c_thread_index, to_finwait1, 1);
break;
case TCP_STATE_LAST_ACK:
tcp_connection_timers_reset (tc);
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
session_transport_closed_notify (&tc->connection);
- tcp_worker_stats_inc (thread_index, to_lastack, 1);
+ tcp_worker_stats_inc (tc->c_thread_index, to_lastack, 1);
break;
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_cfg.cleanup_time);
session_transport_closed_notify (&tc->connection);
- tcp_worker_stats_inc (thread_index, to_closing, 1);
+ tcp_worker_stats_inc (tc->c_thread_index, to_closing, 1);
break;
case TCP_STATE_FIN_WAIT_2:
tcp_send_reset (tc);
@@ -1437,7 +1357,7 @@ tcp_timer_waitclose_handler (u32 conn_index, u32 thread_index)
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
session_transport_closed_notify (&tc->connection);
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
- tcp_worker_stats_inc (thread_index, to_finwait2, 1);
+ tcp_worker_stats_inc (tc->c_thread_index, to_finwait2, 1);
break;
default:
tcp_connection_del (tc);
@@ -1457,15 +1377,144 @@ static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] =
/* *INDENT-ON* */
static void
+tcp_dispatch_pending_timers (tcp_worker_ctx_t * wrk)
+{
+ u32 n_timers, connection_index, timer_id, thread_index, timer_handle;
+ tcp_connection_t *tc;
+ int i;
+
+ if (!(n_timers = clib_fifo_elts (wrk->pending_timers)))
+ return;
+
+ thread_index = wrk->vm->thread_index;
+ for (i = 0; i < clib_min (n_timers, 32); i++)
+ {
+ clib_fifo_sub1 (wrk->pending_timers, timer_handle);
+ connection_index = timer_handle & 0x0FFFFFFF;
+ timer_id = timer_handle >> 28;
+
+ if (PREDICT_TRUE (timer_id != TCP_TIMER_RETRANSMIT_SYN))
+ tc = tcp_connection_get (connection_index, thread_index);
+ else
+ tc = tcp_half_open_connection_get (connection_index);
+
+ if (PREDICT_FALSE (!tc))
+ continue;
+
+ /* Skip timer if it was rearmed while pending dispatch */
+ if (PREDICT_FALSE (tc->timers[timer_id] != TCP_TIMER_HANDLE_INVALID))
+ continue;
+
+ (*timer_expiration_handlers[timer_id]) (tc);
+ }
+}
+
+/**
+ * Flush ip lookup tx frames populated by timer pops
+ */
+static void
+tcp_flush_frames_to_output (tcp_worker_ctx_t * wrk)
+{
+ if (wrk->ip_lookup_tx_frames[0])
+ {
+ vlib_put_frame_to_node (wrk->vm, ip4_lookup_node.index,
+ wrk->ip_lookup_tx_frames[0]);
+ wrk->ip_lookup_tx_frames[0] = 0;
+ }
+ if (wrk->ip_lookup_tx_frames[1])
+ {
+ vlib_put_frame_to_node (wrk->vm, ip6_lookup_node.index,
+ wrk->ip_lookup_tx_frames[1]);
+ wrk->ip_lookup_tx_frames[1] = 0;
+ }
+}
+
+static void
+tcp_update_time (f64 now, u8 thread_index)
+{
+ tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
+
+ tcp_set_time_now (wrk);
+ tw_timer_expire_timers_16t_2w_512sl (&wrk->timer_wheel, now);
+ tcp_dispatch_pending_timers (wrk);
+ tcp_flush_frames_to_output (wrk);
+}
+
+static void
+tcp_session_flush_data (transport_connection_t * tconn)
+{
+ tcp_connection_t *tc = (tcp_connection_t *) tconn;
+ if (tc->flags & TCP_CONN_PSH_PENDING)
+ return;
+ tc->flags |= TCP_CONN_PSH_PENDING;
+ tc->psh_seq = tc->snd_una + transport_max_tx_dequeue (tconn) - 1;
+}
+
+/* *INDENT-OFF* */
+const static transport_proto_vft_t tcp_proto = {
+ .enable = vnet_tcp_enable_disable,
+ .start_listen = tcp_session_bind,
+ .stop_listen = tcp_session_unbind,
+ .push_header = tcp_session_push_header,
+ .get_connection = tcp_session_get_transport,
+ .get_listener = tcp_session_get_listener,
+ .get_half_open = tcp_half_open_session_get_transport,
+ .connect = tcp_session_open,
+ .close = tcp_session_close,
+ .cleanup = tcp_session_cleanup,
+ .reset = tcp_session_reset,
+ .send_mss = tcp_session_send_mss,
+ .send_space = tcp_session_send_space,
+ .update_time = tcp_update_time,
+ .tx_fifo_offset = tcp_session_tx_fifo_offset,
+ .flush_data = tcp_session_flush_data,
+ .custom_tx = tcp_session_custom_tx,
+ .format_connection = format_tcp_session,
+ .format_listener = format_tcp_listener_session,
+ .format_half_open = format_tcp_half_open_session,
+ .transport_options = {
+ .tx_type = TRANSPORT_TX_PEEK,
+ .service_type = TRANSPORT_SERVICE_VC,
+ },
+};
+/* *INDENT-ON* */
+
+void
+tcp_connection_tx_pacer_update (tcp_connection_t * tc)
+{
+ if (!transport_connection_is_tx_paced (&tc->connection))
+ return;
+
+ f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
+
+ transport_connection_tx_pacer_update (&tc->connection,
+ tcp_cc_get_pacing_rate (tc),
+ srtt * CLIB_US_TIME_FREQ);
+}
+
+void
+tcp_connection_tx_pacer_reset (tcp_connection_t * tc, u32 window,
+ u32 start_bucket)
+{
+ f64 srtt = clib_min ((f64) tc->srtt * TCP_TICK, tc->mrtt_us);
+ transport_connection_tx_pacer_reset (&tc->connection,
+ tcp_cc_get_pacing_rate (tc),
+ start_bucket,
+ srtt * CLIB_US_TIME_FREQ);
+}
+
+static void
tcp_expired_timers_dispatch (u32 * expired_timers)
{
u32 thread_index = vlib_get_thread_index ();
u32 connection_index, timer_id, n_expired;
+ tcp_worker_ctx_t *wrk;
tcp_connection_t *tc;
int i;
+ wrk = tcp_get_worker (thread_index);
n_expired = vec_len (expired_timers);
- tcp_worker_stats_inc (thread_index, timer_expirations, n_expired);
+ tcp_workerp_stats_inc (wrk, timer_expirations, n_expired);
/*
* Invalidate all timer handles before dispatching. This avoids dangling
@@ -1486,15 +1535,7 @@ tcp_expired_timers_dispatch (u32 * expired_timers)
tc->timers[timer_id] = TCP_TIMER_HANDLE_INVALID;
}
- /*
- * Dispatch expired timers
- */
- for (i = 0; i < n_expired; i++)
- {
- connection_index = expired_timers[i] & 0x0FFFFFFF;
- timer_id = expired_timers[i] >> 28;
- (*timer_expiration_handlers[timer_id]) (connection_index, thread_index);
- }
+ clib_fifo_add (wrk->pending_timers, expired_timers, n_expired);
}
static void
@@ -2297,14 +2338,19 @@ show_tcp_stats_fn (vlib_main_t * vm, unformat_input_t * input,
for (thread = 0; thread < vec_len (tm->wrk_ctx); thread++)
{
wrk = tcp_get_worker (thread);
- vlib_cli_output (vm, "Thread %d:\n", thread);
+ vlib_cli_output (vm, "Thread %u:\n", thread);
+
+ if (clib_fifo_elts (wrk->pending_timers))
+ vlib_cli_output (vm, " %lu pending timers",
+ clib_fifo_elts (wrk->pending_timers));
#define _(name,type,str) \
if (wrk->stats.name) \
- vlib_cli_output (vm, " %ld %s", wrk->stats.name, str);
+ vlib_cli_output (vm, " %lu %s", wrk->stats.name, str);
foreach_tcp_wrk_stat
#undef _
}
+
return 0;
}