summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2019-02-21 16:46:24 -0800
committerDamjan Marion <dmarion@me.com>2019-02-22 10:55:27 +0000
commite5b17918e78c974b43fe41300d2f5d817e89c30b (patch)
treeefa59300186940fcada3b4018443e14743bb38ed
parent78b5fa6398d02af4f4f92e4bc9cc22c010ae24f9 (diff)
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 <fcoras@cisco.com>
-rw-r--r--src/vnet/tcp/tcp.c2
-rw-r--r--src/vnet/tcp/tcp.h1
-rwxr-xr-xsrc/vnet/tcp/tcp_debug.h4
-rw-r--r--src/vnet/tcp/tcp_output.c44
4 files changed, 37 insertions, 14 deletions
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index c51224447fc..9f35b82a16f 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -840,7 +840,7 @@ format_tcp_vars (u8 * s, va_list * args)
tcp_rcv_wnd_available (tc));
s = format (s, " tsval_recent %u tsval_recent_age %u\n", tc->tsval_recent,
tcp_time_now () - tc->tsval_recent_age);
- s = format (s, " rto %u rto_boff %u srtt %u us %.3f rttvar %u rtt_ts %x",
+ s = format (s, " rto %u rto_boff %u srtt %u us %.3f rttvar %u rtt_ts %.4f",
tc->rto, tc->rto_boff, tc->srtt, tc->mrtt_us * 1000, tc->rttvar,
tc->rtt_ts);
s = format (s, " rtt_seq %u\n", tc->rtt_seq - tc->iss);
diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h
index d1fbf156ed5..a4e7935dfe4 100644
--- a/src/vnet/tcp/tcp.h
+++ b/src/vnet/tcp/tcp.h
@@ -303,6 +303,7 @@ typedef struct _tcp_connection
tcp_options_t rcv_opts; /**< Rx options for connection */
sack_block_t *snd_sacks; /**< Vector of SACKs to send. XXX Fixed size? */
+ u8 snd_sack_pos; /**< Position in vec of first block to send */
sack_scoreboard_t sack_sb; /**< SACK "scoreboard" that tracks holes */
u16 rcv_dupacks; /**< Number of DUPACKs received */
diff --git a/src/vnet/tcp/tcp_debug.h b/src/vnet/tcp/tcp_debug.h
index cf074925435..7ef7558637e 100755
--- a/src/vnet/tcp/tcp_debug.h
+++ b/src/vnet/tcp/tcp_debug.h
@@ -20,8 +20,8 @@
#define TCP_DEBUG (1)
#define TCP_DEBUG_SM (0)
-#define TCP_DEBUG_CC (0)
-#define TCP_DEBUG_CC_STAT (0)
+#define TCP_DEBUG_CC (1)
+#define TCP_DEBUG_CC_STAT (1)
#define TCP_DEBUG_BUFFER_ALLOCATION (0)
#define foreach_tcp_dbg_evt \
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;
}