summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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;
}