tcp: fast retransmit improvements

Patch is too large to be ported to 18.10 just days before release.

- handle fast retransmits outside of established node and limit the
retransmit burst size to avoid tx losses and worsening congestion.
- in the absance of a tx pacer, use slow start after fast retransmit
exists
- add fast retransmit heuristic that re-retries sending the first
segment if everything else fails
- fine tuning

Change-Id: I84a2ab8fbba8b97f1d2b26584dc11a1e2c33c8d2
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/tcp/tcp_debug.h b/src/vnet/tcp/tcp_debug.h
index ccf12da..8f626b1 100755
--- a/src/vnet/tcp/tcp_debug.h
+++ b/src/vnet/tcp/tcp_debug.h
@@ -629,6 +629,8 @@
 
 #define TCP_EVT_CC_EVT_HANDLER(_tc, _sub_evt, ...)			\
 {									\
+  if (_tc->snd_una != _tc->iss)						\
+    TCP_EVT_CC_STAT_PRINT (_tc);					\
   ELOG_TYPE_DECLARE (_e) =						\
   {									\
     .format = "cc: %s snd_space %u snd_una %u out %u flight %u",	\
@@ -788,9 +790,11 @@
 
 #define STATS_INTERVAL 1
 
-#define TCP_EVT_CC_RTO_STAT_HANDLER(_tc, ...)				\
-{									\
-if (_tc->c_cc_stat_tstamp + STATS_INTERVAL < tcp_time_now())		\
+#define tcp_cc_time_to_print_stats(_tc)					\
+  _tc->c_cc_stat_tstamp + STATS_INTERVAL < tcp_time_now() 		\
+  || tcp_in_fastrecovery (_tc)						\
+
+#define TCP_EVT_CC_RTO_STAT_PRINT(_tc)					\
 {									\
   ELOG_TYPE_DECLARE (_e) =						\
   {									\
@@ -801,29 +805,40 @@
   ed->data[0] = _tc->rto;						\
   ed->data[1] = _tc->srtt;						\
   ed->data[2] = _tc->rttvar;						\
+}
+
+#define TCP_EVT_CC_RTO_STAT_HANDLER(_tc, ...)				\
+{									\
+if (tcp_cc_time_to_print_stats (_tc))					\
+{									\
+  TCP_EVT_CC_RTO_STAT_PRINT (_tc);					\
 }									\
 }
-#define TCP_EVT_CC_SND_STAT_HANDLER(_tc, ...)				\
-{									\
-if (_tc->c_cc_stat_tstamp + STATS_INTERVAL < tcp_time_now())		\
+
+#define TCP_EVT_CC_SND_STAT_PRINT(_tc)					\
 {									\
   ELOG_TYPE_DECLARE (_e) =						\
   {									\
-    .format = "snd_stat: dack %u sacked %u lost %u out %u rxt %u",	\
+    .format = "snd_stat: cc_space %u sacked %u lost %u out %u rxt %u",	\
     .format_args = "i4i4i4i4i4",					\
   };									\
   DECLARE_ETD(_tc, _e, 5);						\
-  ed->data[0] = _tc->rcv_dupacks;					\
+  ed->data[0] = tcp_available_cc_snd_space (_tc);			\
   ed->data[1] = _tc->sack_sb.sacked_bytes;				\
   ed->data[2] = _tc->sack_sb.lost_bytes;				\
   ed->data[3] = tcp_bytes_out (_tc);					\
   ed->data[3] = _tc->snd_rxt_bytes;					\
+}
+
+#define TCP_EVT_CC_SND_STAT_HANDLER(_tc, ...)				\
+{									\
+if (tcp_cc_time_to_print_stats (_tc))					\
+{									\
+    TCP_EVT_CC_SND_STAT_PRINT(_tc);					\
 }									\
 }
 
-#define TCP_EVT_CC_STAT_HANDLER(_tc, ...)				\
-{									\
-if (_tc->c_cc_stat_tstamp + STATS_INTERVAL < tcp_time_now())		\
+#define TCP_EVT_CC_STAT_PRINT(_tc)					\
 {									\
   ELOG_TYPE_DECLARE (_e) =						\
   {									\
@@ -836,7 +851,15 @@
   ed->data[2] = tcp_snd_space (_tc);					\
   ed->data[3] = _tc->ssthresh;						\
   ed->data[4] = _tc->snd_wnd;						\
-  TCP_EVT_CC_RTO_STAT_HANDLER (_tc);					\
+  TCP_EVT_CC_RTO_STAT_PRINT (_tc);					\
+  TCP_EVT_CC_SND_STAT_PRINT (_tc);					\
+}
+
+#define TCP_EVT_CC_STAT_HANDLER(_tc, ...)				\
+{									\
+if (tcp_cc_time_to_print_stats (_tc))					\
+{									\
+  TCP_EVT_CC_STAT_PRINT (_tc);						\
   _tc->c_cc_stat_tstamp = tcp_time_now();				\
 }									\
 }