From e5b17918e78c974b43fe41300d2f5d817e89c30b Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 21 Feb 2019 16:46:24 -0800 Subject: tcp: send enough dupacks to cover all sack holes Make sure we send enough dupacks to cover all the holes created in the last frame received. Also make sure we send all the blocks, not just the first. Change-Id: I9597a34ac14473d1cc3ad07d65bc37043e3d0582 Signed-off-by: Florin Coras --- src/vnet/tcp/tcp_output.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'src/vnet/tcp/tcp_output.c') diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index 725ffec0852..4de479c344b 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -253,14 +253,12 @@ tcp_options_write (u8 * data, tcp_options_t * opts) if (tcp_opts_sack (opts)) { int i; - u32 n_sack_blocks = clib_min (vec_len (opts->sacks), - TCP_OPTS_MAX_SACK_BLOCKS); - if (n_sack_blocks != 0) + if (opts->n_sack_blocks != 0) { *data++ = TCP_OPTION_SACK_BLOCK; - *data++ = 2 + n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK; - for (i = 0; i < n_sack_blocks; i++) + *data++ = 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK; + for (i = 0; i < opts->n_sack_blocks; i++) { buf = clib_host_to_net_u32 (opts->sacks[i].start); clib_memcpy_fast (data, &buf, seq_len); @@ -269,7 +267,7 @@ tcp_options_write (u8 * data, tcp_options_t * opts) clib_memcpy_fast (data, &buf, seq_len); data += seq_len; } - opts_len += 2 + n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK; + opts_len += 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK; } } @@ -372,9 +370,13 @@ tcp_make_established_options (tcp_connection_t * tc, tcp_options_t * opts) if (vec_len (tc->snd_sacks)) { opts->flags |= TCP_OPTS_FLAG_SACK; - opts->sacks = tc->snd_sacks; - opts->n_sack_blocks = clib_min (vec_len (tc->snd_sacks), + if (tc->snd_sack_pos >= vec_len (tc->snd_sacks)) + tc->snd_sack_pos = 0; + opts->sacks = &tc->snd_sacks[tc->snd_sack_pos]; + opts->n_sack_blocks = vec_len (tc->snd_sacks) - tc->snd_sack_pos; + opts->n_sack_blocks = clib_min (opts->n_sack_blocks, TCP_OPTS_MAX_SACK_BLOCKS); + tc->snd_sack_pos += opts->n_sack_blocks; len += 2 + TCP_OPTION_LEN_SACK_BLOCK * opts->n_sack_blocks; } } @@ -1250,14 +1252,34 @@ tcp_send_acks (tcp_worker_ctx_t * wrk) { tc = tcp_connection_get (pending_acks[i], thread_index); tc->flags &= ~TCP_CONN_SNDACK; - n_acks = clib_max (1, tc->pending_dupacks); + if (!tc->pending_dupacks) + { + tcp_send_ack (tc); + continue; + } + /* If we're supposed to send dupacks but have no ooo data * send only one ack */ - if (tc->pending_dupacks && !vec_len (tc->snd_sacks)) - n_acks = 1; + if (!vec_len (tc->snd_sacks)) + { + tcp_send_ack (tc); + continue; + } + + /* Start with first sack block */ + tc->snd_sack_pos = 0; + + /* Generate enough dupacks to cover all sack blocks. Do not generate + * more sacks than the number of packets received. But do generate at + * least 3, i.e., the number needed to signal congestion, if needed. */ + n_acks = vec_len (tc->snd_sacks) / TCP_OPTS_MAX_SACK_BLOCKS; + n_acks = clib_min (n_acks, tc->pending_dupacks); + n_acks = clib_max (n_acks, clib_min (tc->pending_dupacks, 3)); for (j = 0; j < n_acks; j++) tcp_send_ack (tc); + tc->pending_dupacks = 0; + tc->snd_sack_pos = 0; } _vec_len (wrk->pending_acks) = 0; } -- cgit 1.2.3-korg