diff options
Diffstat (limited to 'src/vnet/tcp/tcp_output.c')
-rw-r--r-- | src/vnet/tcp/tcp_output.c | 44 |
1 files changed, 33 insertions, 11 deletions
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; } |