tcp: add loss signal to cc algo

Type:feature

Change-Id: Ibe1a4c555b55fb929d55b02599aaf099ed522cdf
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h
index 8b943cd..2bc6f22 100644
--- a/src/vnet/tcp/tcp.h
+++ b/src/vnet/tcp/tcp.h
@@ -379,13 +379,14 @@
 {
   const char *name;
   uword (*unformat_cfg) (unformat_input_t * input);
+  void (*init) (tcp_connection_t * tc);
+  void (*cleanup) (tcp_connection_t * tc);
   void (*rcv_ack) (tcp_connection_t * tc, tcp_rate_sample_t *rs);
   void (*rcv_cong_ack) (tcp_connection_t * tc, tcp_cc_ack_t ack,
 			tcp_rate_sample_t *rs);
   void (*congestion) (tcp_connection_t * tc);
+  void (*loss) (tcp_connection_t * tc);
   void (*recovered) (tcp_connection_t * tc);
-  void (*init) (tcp_connection_t * tc);
-  void (*cleanup) (tcp_connection_t * tc);
 };
 /* *INDENT-ON* */
 
@@ -900,7 +901,7 @@
 int tcp_fast_retransmit (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
 			 u32 burst_size);
 void tcp_cc_init_congestion (tcp_connection_t * tc);
-void tcp_cc_fastrecovery_exit (tcp_connection_t * tc);
+void tcp_cc_fastrecovery_clear (tcp_connection_t * tc);
 
 fib_node_index_t tcp_lookup_rmt_in_fib (tcp_connection_t * tc);
 
@@ -958,6 +959,12 @@
   tc->cc_algo->rcv_cong_ack (tc, ack_type, rs);
 }
 
+static inline void
+tcp_cc_loss (tcp_connection_t * tc)
+{
+  tc->cc_algo->loss (tc);
+}
+
 always_inline void
 tcp_timer_set (tcp_connection_t * tc, u8 timer_id, u32 interval)
 {
diff --git a/src/vnet/tcp/tcp_cubic.c b/src/vnet/tcp/tcp_cubic.c
index 80d4308..0b4226d 100644
--- a/src/vnet/tcp/tcp_cubic.c
+++ b/src/vnet/tcp/tcp_cubic.c
@@ -106,6 +106,18 @@
 }
 
 static void
+cubic_loss (tcp_connection_t * tc)
+{
+  cubic_data_t *cd = (cubic_data_t *) tcp_cc_data (tc);
+
+  tc->ssthresh = clib_max (tc->cwnd * beta_cubic, 2 * tc->snd_mss);
+  tc->cwnd = tcp_loss_wnd (tc);
+  cd->t_start = cubic_time (tc->c_thread_index);
+  cd->K = 0;
+  cd->w_max = 0;
+}
+
+static void
 cubic_recovered (tcp_connection_t * tc)
 {
   cubic_data_t *cd = (cubic_data_t *) tcp_cc_data (tc);
@@ -217,6 +229,7 @@
   .name = "cubic",
   .unformat_cfg = cubic_unformat_config,
   .congestion = cubic_congestion,
+  .loss = cubic_loss,
   .recovered = cubic_recovered,
   .rcv_ack = cubic_rcv_ack,
   .rcv_cong_ack = newreno_rcv_cong_ack,
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index 848028f..5a7ae5e 100644
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -1183,14 +1183,11 @@
   TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 3);
 }
 
-#ifndef CLIB_MARCH_VARIANT
-void
-tcp_cc_fastrecovery_exit (tcp_connection_t * tc)
+static inline void
+tcp_cc_fastrecovery_clear_inline (tcp_connection_t * tc)
 {
-  tc->cc_algo->recovered (tc);
   tc->snd_rxt_bytes = 0;
   tc->rcv_dupacks = 0;
-  tc->snd_rxt_bytes = 0;
   tc->rtt_ts = 0;
 
   tcp_fastrecovery_off (tc);
@@ -1198,6 +1195,20 @@
 
   TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 3);
 }
+
+static void
+tcp_cc_fastrecovery_exit (tcp_connection_t * tc)
+{
+  tc->cc_algo->recovered (tc);
+  tcp_cc_fastrecovery_clear_inline (tc);
+}
+
+#ifndef CLIB_MARCH_VARIANT
+void
+tcp_cc_fastrecovery_clear (tcp_connection_t * tc)
+{
+  tcp_cc_fastrecovery_clear_inline (tc);
+}
 #endif /* CLIB_MARCH_VARIANT */
 
 static void
diff --git a/src/vnet/tcp/tcp_newreno.c b/src/vnet/tcp/tcp_newreno.c
index 3887b34..7e37efb 100644
--- a/src/vnet/tcp/tcp_newreno.c
+++ b/src/vnet/tcp/tcp_newreno.c
@@ -15,19 +15,26 @@
 
 #include <vnet/tcp/tcp.h>
 
-void
+static void
 newreno_congestion (tcp_connection_t * tc)
 {
   tc->ssthresh = clib_max (tcp_flight_size (tc) / 2, 2 * tc->snd_mss);
 }
 
-void
+static void
+newreno_loss (tcp_connection_t * tc)
+{
+  tc->ssthresh = clib_max (tcp_flight_size (tc) / 2, 2 * tc->snd_mss);
+  tc->cwnd = tcp_loss_wnd (tc);
+}
+
+static void
 newreno_recovered (tcp_connection_t * tc)
 {
   tc->cwnd = tc->ssthresh;
 }
 
-void
+static void
 newreno_rcv_ack (tcp_connection_t * tc, tcp_rate_sample_t * rs)
 {
   if (tcp_in_slowstart (tc))
@@ -72,7 +79,7 @@
     }
 }
 
-void
+static void
 newreno_conn_init (tcp_connection_t * tc)
 {
   tc->ssthresh = tc->snd_wnd;
@@ -82,6 +89,7 @@
 const static tcp_cc_algorithm_t tcp_newreno = {
   .name = "newreno",
   .congestion = newreno_congestion,
+  .loss = newreno_loss,
   .recovered = newreno_recovered,
   .rcv_ack = newreno_rcv_ack,
   .rcv_cong_ack = newreno_rcv_cong_ack,
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 7cf85c3..8537b1f 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -1472,26 +1472,22 @@
  * Reset congestion control, switch cwnd to loss window and try again.
  */
 static void
-tcp_rxt_timeout_cc (tcp_connection_t * tc)
+tcp_cc_init_rxt_timeout (tcp_connection_t * tc)
 {
   TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 6);
   tc->prev_ssthresh = tc->ssthresh;
   tc->prev_cwnd = tc->cwnd;
 
-  /* Cleanly recover cc (also clears up fast retransmit) */
+  /* Clear fast recovery state if needed */
   if (tcp_in_fastrecovery (tc))
-    {
-      /* TODO be less aggressive about this */
-      scoreboard_clear (&tc->sack_sb);
-      tcp_cc_fastrecovery_exit (tc);
-    }
-  else
-    tc->rcv_dupacks = 0;
+    tcp_cc_fastrecovery_clear (tc);
+
+  /* Let cc algo decide loss cwnd and ssthresh */
+  tcp_cc_loss (tc);
 
   /* Start again from the beginning */
-  tc->cc_algo->congestion (tc);
-  tc->cwnd = tcp_loss_wnd (tc);
   tc->snd_congestion = tc->snd_nxt;
+  tc->rcv_dupacks = 0;
   tc->rtt_ts = 0;
   tc->cwnd_acc_bytes = 0;
   tcp_connection_tx_pacer_reset (tc, tc->cwnd, 2 * tc->snd_mss);
@@ -1577,11 +1573,12 @@
        * to first un-acked byte  */
       tc->rto_boff += 1;
 
+      /* TODO be less aggressive about clearing scoreboard */
+      scoreboard_clear (&tc->sack_sb);
+
       /* First retransmit timeout */
       if (tc->rto_boff == 1)
-	tcp_rxt_timeout_cc (tc);
-      else
-	scoreboard_clear (&tc->sack_sb);
+	tcp_cc_init_rxt_timeout (tc);
 
       if (tc->flags & TCP_CONN_RATE_SAMPLE)
 	tcp_bt_flush_samples (tc);