tcp: send enough dupacks to cover all sack holes 62/17762/9
authorFlorin Coras <fcoras@cisco.com>
Fri, 22 Feb 2019 00:46:24 +0000 (16:46 -0800)
committerDamjan Marion <dmarion@me.com>
Fri, 22 Feb 2019 10:55:27 +0000 (10:55 +0000)
Make sure we send enough dupacks to cover all the holes created in the
last frame received. Also make sure we send all the blocks, not just the
first.

Change-Id: I9597a34ac14473d1cc3ad07d65bc37043e3d0582
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/vnet/tcp/tcp.c
src/vnet/tcp/tcp.h
src/vnet/tcp/tcp_debug.h
src/vnet/tcp/tcp_output.c

index c512244..9f35b82 100644 (file)
@@ -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);
index d1fbf15..a4e7935 100644 (file)
@@ -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 */
index cf07492..7ef7558 100755 (executable)
@@ -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            \
index 725ffec..4de479c 100644 (file)
@@ -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;
 }