tcp: avoid rcv wnd more than RX fifo can enqueue 85/28485/2
authorRyujiro Shibuya <ryujiro.shibuya@owmobility.com>
Wed, 24 Jun 2020 07:36:14 +0000 (08:36 +0100)
committerAndrew Yourtchenko <ayourtch@gmail.com>
Tue, 18 Aug 2020 19:47:21 +0000 (19:47 +0000)
Type: fix

Signed-off-by: Ryujiro Shibuya <ryujiro.shibuya@owmobility.com>
Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: Ie358b731f8ecb1fcaebd6e79f5ce5c10802c2814
(cherry picked from commit cc1085647b2ae36e6c086d65b4e81b9f1cf9fc9a)

src/vnet/tcp/tcp_output.c
src/vppinfra/clib.h

index 464cf52..f0f5e82 100644 (file)
@@ -121,6 +121,11 @@ tcp_update_rcv_wnd (tcp_connection_t * tc)
    * Figure out how much space we have available
    */
   available_space = transport_max_rx_enqueue (&tc->connection);
+
+  /* Make sure we have a multiple of 1 << rcv_wscale. We round down to
+   * avoid advertising a window larger than what can be buffered */
+  available_space = round_down_pow2 (available_space, 1 << tc->rcv_wscale);
+
   if (PREDICT_FALSE (available_space < tc->rcv_opts.mss))
     {
       tc->rcv_wnd = 0;
@@ -136,7 +141,7 @@ tcp_update_rcv_wnd (tcp_connection_t * tc)
   /* Bad. Thou shalt not shrink */
   if (PREDICT_FALSE ((i32) available_space < observed_wnd))
     {
-      wnd = clib_max (observed_wnd, 0);
+      wnd = round_pow2 (clib_max (observed_wnd, 0), 1 << tc->rcv_wscale);
       TCP_EVT (TCP_EVT_RCV_WND_SHRUNK, tc, observed_wnd, available_space);
     }
   else
@@ -144,12 +149,6 @@ tcp_update_rcv_wnd (tcp_connection_t * tc)
       wnd = available_space;
     }
 
-  /* Make sure we have a multiple of 1 << rcv_wscale. We round up to
-   * avoid advertising a window less than mss which could happen if
-   * 1 << rcv_wscale < mss */
-  if (wnd && tc->rcv_wscale)
-    wnd = round_pow2 (wnd, 1 << tc->rcv_wscale);
-
   tc->rcv_wnd = clib_min (wnd, TCP_WND_MAX << tc->rcv_wscale);
 }
 
index 8aec1f1..5e62cc8 100644 (file)
@@ -237,6 +237,12 @@ is_pow2 (uword x)
   return 0 == (x & (x - 1));
 }
 
+always_inline uword
+round_down_pow2 (uword x, uword pow2)
+{
+  return (x) & ~(pow2 - 1);
+}
+
 always_inline uword
 round_pow2 (uword x, uword pow2)
 {