tcp: track pending timers
[vpp.git] / src / vnet / tcp / tcp_input.c
index 964afe3..bdaa28e 100644 (file)
@@ -426,8 +426,6 @@ acceptable:
  * Note that although the original article, srtt and rttvar are scaled
  * to minimize round-off errors, here we don't. Instead, we rely on
  * better precision time measurements.
- *
- * TODO support us rtt resolution
  */
 static void
 tcp_estimate_rtt (tcp_connection_t * tc, u32 mrtt)
@@ -452,16 +450,28 @@ tcp_estimate_rtt (tcp_connection_t * tc, u32 mrtt)
     }
 }
 
+static inline void
+tcp_estimate_rtt_us (tcp_connection_t * tc, f64 mrtt)
+{
+  tc->mrtt_us = tc->mrtt_us + (mrtt - tc->mrtt_us) * 0.125;
+}
+
 /**
- * Update RTT estimate and RTO timer
+ * Update rtt estimate
+ *
+ * We have potentially three sources of rtt measurements:
  *
- * Measure RTT: We have two sources of RTT measurements: TSOPT and ACK
- * timing. Middle boxes are known to fiddle with TCP options so we
- * should give higher priority to ACK timing.
+ * TSOPT       difference between current and echoed timestamp. It has ms
+ *             precision and can be computed per ack
+ * ACK timing  one sequence number is tracked per rtt with us (micro second)
+ *             precision.
+ * rate sample if enabled, all outstanding bytes are tracked with us
+ *             precision. Every ack and sack are a rtt sample
  *
- * This should be called only if previously sent bytes have been acked.
+ * Middle boxes are known to fiddle with TCP options so we give higher
+ * priority to ACK timing.
  *
- * return 1 if valid rtt 0 otherwise
+ * For now, rate sample rtts are only used under congestion.
  */
 static int
 tcp_update_rtt (tcp_connection_t * tc, tcp_rate_sample_t * rs, u32 ack)
@@ -473,19 +483,19 @@ tcp_update_rtt (tcp_connection_t * tc, tcp_rate_sample_t * rs, u32 ack)
   if (tcp_in_cong_recovery (tc))
     {
       /* Accept rtt estimates for samples that have not been retransmitted */
-      if ((tc->cfg_flags & TCP_CFG_F_RATE_SAMPLE)
-         && !(rs->flags & TCP_BTS_IS_RXT))
-       {
-         mrtt = rs->rtt_time * THZ;
-         goto estimate_rtt;
-       }
-      goto done;
+      if (!(tc->cfg_flags & TCP_CFG_F_RATE_SAMPLE)
+         || (rs->flags & TCP_BTS_IS_RXT))
+       goto done;
+      if (rs->rtt_time)
+       tcp_estimate_rtt_us (tc, rs->rtt_time);
+      mrtt = rs->rtt_time * THZ;
+      goto estimate_rtt;
     }
 
   if (tc->rtt_ts && seq_geq (ack, tc->rtt_seq))
     {
       f64 sample = tcp_time_now_us (tc->c_thread_index) - tc->rtt_ts;
-      tc->mrtt_us = tc->mrtt_us + (sample - tc->mrtt_us) * 0.125;
+      tcp_estimate_rtt_us (tc, sample);
       mrtt = clib_max ((u32) (sample * THZ), 1);
       /* Allow measuring of a new RTT */
       tc->rtt_ts = 0;
@@ -1048,10 +1058,11 @@ process_ack:
   if (tc->cfg_flags & TCP_CFG_F_RATE_SAMPLE)
     tcp_bt_sample_delivery_rate (tc, &rs);
 
-  if (tc->bytes_acked)
+  if (tc->bytes_acked + tc->sack_sb.last_sacked_bytes)
     {
-      tcp_program_dequeue (wrk, tc);
       tcp_update_rtt (tc, &rs, vnet_buffer (b)->tcp.ack_number);
+      if (tc->bytes_acked)
+       tcp_program_dequeue (wrk, tc);
     }
 
   TCP_EVT (TCP_EVT_ACK_RCVD, tc);
@@ -1252,26 +1263,6 @@ tcp_session_enqueue_ooo (tcp_connection_t * tc, vlib_buffer_t * b,
   return TCP_ERROR_ENQUEUED_OOO;
 }
 
-/**
- * Check if ACK could be delayed. If ack can be delayed, it should return
- * true for a full frame. If we're always acking return 0.
- */
-always_inline int
-tcp_can_delack (tcp_connection_t * tc)
-{
-  /* Send ack if ... */
-  if (TCP_ALWAYS_ACK
-      /* just sent a rcv wnd 0
-         || (tc->flags & TCP_CONN_SENT_RCV_WND0) != 0 */
-      /* constrained to send ack */
-      || (tc->flags & TCP_CONN_SNDACK) != 0
-      /* we're almost out of tx wnd */
-      || tcp_available_cc_snd_space (tc) < 4 * tc->snd_mss)
-    return 0;
-
-  return 1;
-}
-
 static int
 tcp_buffer_discard_bytes (vlib_buffer_t * b, u32 n_bytes_to_drop)
 {
@@ -1360,14 +1351,6 @@ in_order:
   /* In order data, enqueue. Fifo figures out by itself if any out-of-order
    * segments can be enqueued after fifo tail offset changes. */
   error = tcp_session_enqueue_data (tc, b, n_data_bytes);
-  if (tcp_can_delack (tc))
-    {
-      if (!tcp_timer_is_active (tc, TCP_TIMER_DELACK))
-       tcp_timer_set (&wrk->timer_wheel, tc, TCP_TIMER_DELACK,
-                      tcp_cfg.delack_time);
-      goto done;
-    }
-
   tcp_program_ack (tc);
 
 done: