tcp: fast retransmit pacing
Force pacing for fast retransmit to avoid bursts of retransmitted
packets.
Change-Id: I2ff42c328899b36322c4de557b1f7d853dba8fe2
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index ac0e996..154b9ac 100644
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -1199,67 +1199,60 @@
tcp_do_fastretransmits (u32 thread_index)
{
tcp_worker_ctx_t *wrk = &tcp_main.wrk_ctx[thread_index];
- u32 max_burst_size, burst_size, n_segs = 0;
+ u32 max_burst_size, burst_size, n_segs = 0, n_segs_now;
+ u32 *ongoing_fast_rxt, burst_bytes, sent_bytes;
tcp_connection_t *tc;
+ u64 last_cpu_time;
int i;
- if (vec_len (wrk->pending_fast_rxt) == 0)
+ if (vec_len (wrk->pending_fast_rxt) == 0
+ && vec_len (wrk->postponed_fast_rxt) == 0)
return;
- vec_append (wrk->ongoing_fast_rxt, wrk->pending_fast_rxt);
- vec_reset_length (wrk->pending_fast_rxt);
+ last_cpu_time = wrk->vm->clib_time.last_cpu_time;
+ ongoing_fast_rxt = wrk->ongoing_fast_rxt;
+ vec_append (ongoing_fast_rxt, wrk->postponed_fast_rxt);
+ vec_append (ongoing_fast_rxt, wrk->pending_fast_rxt);
+
+ _vec_len (wrk->postponed_fast_rxt) = 0;
+ _vec_len (wrk->pending_fast_rxt) = 0;
max_burst_size = VLIB_FRAME_SIZE / vec_len (wrk->ongoing_fast_rxt);
max_burst_size = clib_max (max_burst_size, 1);
- for (i = 0; i < vec_len (wrk->ongoing_fast_rxt); i++)
+ for (i = 0; i < vec_len (ongoing_fast_rxt); i++)
{
- tc = tcp_connection_get (wrk->ongoing_fast_rxt[i], thread_index);
+ if (n_segs >= VLIB_FRAME_SIZE)
+ {
+ vec_add1 (wrk->postponed_fast_rxt, ongoing_fast_rxt[i]);
+ continue;
+ }
+
+ tc = tcp_connection_get (ongoing_fast_rxt[i], thread_index);
tc->flags &= ~TCP_CONN_FRXT_PENDING;
if (!tcp_in_fastrecovery (tc))
continue;
- /* TODO tx pacer instead of this */
- if (n_segs >= VLIB_FRAME_SIZE)
+ burst_size = clib_min (max_burst_size, VLIB_FRAME_SIZE - n_segs);
+ burst_bytes = transport_connection_tx_pacer_burst (&tc->connection,
+ last_cpu_time);
+ burst_size = clib_min (burst_size, burst_bytes / tc->snd_mss);
+ if (!burst_size)
{
tcp_program_fastretransmit (tc);
continue;
}
- burst_size = clib_min (max_burst_size, VLIB_FRAME_SIZE - n_segs);
+ n_segs_now = tcp_fast_retransmit (tc, burst_size);
+ sent_bytes = clib_min (n_segs_now * tc->snd_mss, burst_bytes);
+ transport_connection_tx_pacer_update_bytes (&tc->connection,
+ sent_bytes);
- if (tc->cwnd > tc->ssthresh + 3 * tc->snd_mss)
- {
- /* The first segment MUST be retransmitted */
- if (tcp_retransmit_first_unacked (tc))
- {
- tcp_program_fastretransmit (tc);
- continue;
- }
-
- /* Post retransmit update cwnd to ssthresh and account for the
- * three segments that have left the network and should've been
- * buffered at the receiver XXX */
- tc->cwnd = tc->ssthresh + 3 * tc->snd_mss;
-
- /* If cwnd allows, send more data */
- if (tcp_opts_sack_permitted (&tc->rcv_opts))
- {
- scoreboard_init_high_rxt (&tc->sack_sb,
- tc->snd_una + tc->snd_mss);
- tc->sack_sb.rescue_rxt = tc->snd_una - 1;
- n_segs += tcp_fast_retransmit_sack (tc, burst_size);
- }
- else
- {
- n_segs += tcp_fast_retransmit_no_sack (tc, burst_size);
- }
- }
- else
- n_segs += tcp_fast_retransmit (tc, burst_size);
+ n_segs += n_segs_now;
}
- vec_reset_length (wrk->ongoing_fast_rxt);
+ _vec_len (ongoing_fast_rxt) = 0;
+ wrk->ongoing_fast_rxt = ongoing_fast_rxt;
}
/**
@@ -1298,6 +1291,7 @@
}
else if (tcp_should_fastrecover (tc))
{
+ u32 byte_rate;
ASSERT (!tcp_in_fastrecovery (tc));
/* Heuristic to catch potential late dupacks
@@ -1313,8 +1307,21 @@
tc->cc_algo->rcv_cong_ack (tc, TCP_CC_DUPACK);
if (tcp_opts_sack_permitted (&tc->rcv_opts))
- tc->sack_sb.high_rxt = tc->snd_una;
+ {
+ tc->cwnd = tc->ssthresh;
+ scoreboard_init_high_rxt (&tc->sack_sb, tc->snd_una);
+ tc->sack_sb.rescue_rxt = tc->snd_una - 1;
+ }
+ else
+ {
+ /* Post retransmit update cwnd to ssthresh and account for the
+ * three segments that have left the network and should've been
+ * buffered at the receiver XXX */
+ tc->cwnd = tc->ssthresh + 3 * tc->snd_mss;
+ }
+ byte_rate = (0.3 * tc->cwnd) / ((f64) TCP_TICK * tc->srtt);
+ transport_connection_tx_pacer_init (&tc->connection, byte_rate, 0);
tcp_program_fastretransmit (tc);
return;
}