aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2019-10-22 19:44:45 -0700
committerAndrew Yourtchenko <ayourtch@gmail.com>2019-10-31 12:16:05 +0000
commitdcc5de6fc321c3828a7f2d55204641e198da5af2 (patch)
treea7585f8123b977fa4766f0581b627d3c9e470c87
parentabe07c8a25a566fd5f7441503a1541b5421c1ad7 (diff)
tcp: fix sack retransmit beyond snd_nxt
Type: fix Ensure that sack retransmit logic does not try to inadvertently send new data. Change-Id: Idfda19643577d9c1b58e2af8d8283cabfbaf98e6 Signed-off-by: Florin Coras <fcoras@cisco.com> (cherry picked from commit 81cb8e4092991d3fd1e24f0862c12548a2d4c714)
-rwxr-xr-xsrc/vnet/tcp/tcp_input.c6
-rw-r--r--src/vnet/tcp/tcp_output.c9
2 files changed, 13 insertions, 2 deletions
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index 22222fba1e2..da499b8c720 100755
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -890,6 +890,12 @@ scoreboard_next_rxt_hole (sack_scoreboard_t * sb,
/* Rule (3): if hole not lost */
else if (seq_lt (hole->start, sb->high_sacked))
{
+ /* And we didn't already retransmit it */
+ if (seq_leq (hole->end, sb->high_rxt))
+ {
+ sb->cur_rxt_hole = TCP_INVALID_SACK_HOLE_INDEX;
+ return 0;
+ }
*snd_limited = 0;
sb->cur_rxt_hole = scoreboard_hole_index (sb, hole);
}
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 08099fffa4e..7362319646a 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -1439,6 +1439,8 @@ tcp_prepare_retransmit_segment (tcp_worker_ctx_t * wrk,
max_deq_bytes = clib_min (available_bytes, max_deq_bytes);
start = tc->snd_una + offset;
+ ASSERT (seq_leq (start + max_deq_bytes, tc->snd_nxt));
+
n_bytes = tcp_prepare_segment (wrk, tc, offset, max_deq_bytes, b);
if (!n_bytes)
return 0;
@@ -1568,7 +1570,8 @@ tcp_timer_retransmit_handler (u32 tc_index)
/* Send the first unacked segment. If we're short on buffers, return
* as soon as possible */
- n_bytes = tcp_prepare_retransmit_segment (wrk, tc, 0, tc->snd_mss, &b);
+ n_bytes = clib_min (tc->snd_mss, tc->snd_nxt - tc->snd_una);
+ n_bytes = tcp_prepare_retransmit_segment (wrk, tc, 0, n_bytes, &b);
if (!n_bytes)
{
tcp_timer_update (tc, TCP_TIMER_RETRANSMIT, 1);
@@ -1962,7 +1965,7 @@ tcp_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
while (snd_space > 0 && n_segs < burst_size)
{
- hole = scoreboard_next_rxt_hole (sb, hole, max_deq, &can_rescue,
+ hole = scoreboard_next_rxt_hole (sb, hole, max_deq != 0, &can_rescue,
&snd_limited);
if (!hole)
{
@@ -2030,6 +2033,8 @@ tcp_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4);
sb->high_rxt += n_written;
+ ASSERT (seq_leq (sb->high_rxt, tc->snd_nxt));
+
snd_space -= n_written;
n_segs += 1;
}