tcp: fix tail rescue with sacks

Type: fix

Change-Id: Iad73f47cef3d29c4b0b7d1f58f2f2b14ba4b1d38
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index f63ffa6..05db727 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -1924,8 +1924,10 @@
 	      u32 n_segs_new;
 	      int av_wnd;
 
+	      /* Make sure we don't exceed available window and leave space
+	       * for one more packet, to avoid zero window acks */
 	      av_wnd = (int) tc->snd_wnd - (tc->snd_nxt - tc->snd_una);
-	      av_wnd = clib_max (av_wnd, 0);
+	      av_wnd = clib_max (av_wnd - tc->snd_mss, 0);
 	      snd_space = clib_min (snd_space, av_wnd);
 	      snd_space = clib_min (max_deq, snd_space);
 	      burst_size = clib_min (burst_size - n_segs,
@@ -1948,16 +1950,16 @@
 	   * unSACKed sequence number SHOULD be returned, and RescueRxt set to
 	   * RecoveryPoint. HighRxt MUST NOT be updated.
 	   */
-	  max_bytes = clib_min (tc->snd_mss,
-				tc->snd_congestion - tc->snd_una);
+	  hole = scoreboard_last_hole (sb);
+	  max_bytes = clib_min (tc->snd_mss, hole->end - hole->start);
 	  max_bytes = clib_min (max_bytes, snd_space);
-	  offset = tc->snd_congestion - tc->snd_una - max_bytes;
-	  sb->rescue_rxt = tc->snd_congestion;
+	  offset = hole->end - tc->snd_una - max_bytes;
 	  n_written = tcp_prepare_retransmit_segment (wrk, tc, offset,
 						      max_bytes, &b);
 	  if (!n_written)
 	    goto done;
 
+	  sb->rescue_rxt = tc->snd_congestion;
 	  bi = vlib_get_buffer_index (vm, b);
 	  tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4);
 	  n_segs += 1;