tcp: fix sack retransmit beyond snd_nxt 40/22940/2
authorFlorin Coras <fcoras@cisco.com>
Wed, 23 Oct 2019 02:44:45 +0000 (19:44 -0700)
committerDamjan Marion <dmarion@me.com>
Wed, 23 Oct 2019 07:45:00 +0000 (07:45 +0000)
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>
src/vnet/tcp/tcp_input.c
src/vnet/tcp/tcp_output.c

index 10f96fa..744c5bc 100755 (executable)
@@ -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);
        }
index e3228c0..0047f3c 100644 (file)
@@ -1392,6 +1392,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;
@@ -1521,7 +1523,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);
@@ -1922,7 +1925,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)
        {
@@ -1990,6 +1993,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;
     }