Improve session debugging

Also improves builtin client code.

Change-Id: I8bca1aa632028f95c373726efb0abf2ee0eff414
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index 36d85e4..9b7b2f6 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -461,13 +461,12 @@
 u8 *
 format_tcp_state (u8 * s, va_list * args)
 {
-  tcp_state_t *state = va_arg (*args, tcp_state_t *);
+  u32 state = va_arg (*args, u32);
 
-  if (*state < TCP_N_STATES)
-    s = format (s, "%s", tcp_fsm_states[*state]);
+  if (state < TCP_N_STATES)
+    s = format (s, "%s", tcp_fsm_states[state]);
   else
-    s = format (s, "UNKNOWN (%d (0x%x))", *state, *state);
-
+    s = format (s, "UNKNOWN (%d (0x%x))", state, state);
   return s;
 }
 
@@ -503,7 +502,51 @@
 }
 
 u8 *
-format_tcp_connection (u8 * s, va_list * args)
+format_tcp_congestion_status (u8 * s, va_list * args)
+{
+  tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
+  if (tcp_in_recovery (tc))
+    s = format (s, "recovery");
+  else if (tcp_in_fastrecovery (tc))
+    s = format (s, "fastrecovery");
+  else
+    s = format (s, "none");
+  return s;
+}
+
+u8 *
+format_tcp_vars (u8 * s, va_list * args)
+{
+  tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
+  s = format (s, " snd_una %u snd_nxt %u snd_una_max %u\n",
+	      tc->snd_una - tc->iss, tc->snd_nxt - tc->iss,
+	      tc->snd_una_max - tc->iss);
+  s = format (s, " rcv_nxt %u rcv_las %u\n",
+	      tc->rcv_nxt - tc->irs, tc->rcv_las - tc->irs);
+  s = format (s, " snd_wnd %u rcv_wnd %u snd_wl1 %u snd_wl2 %u\n",
+	      tc->snd_wnd, tc->rcv_wnd, tc->snd_wl1 - tc->irs,
+	      tc->snd_wl2 - tc->iss);
+  s = format (s, " flight size %u send space %u rcv_wnd available %d\n",
+	      tcp_flight_size (tc), tcp_snd_space (tc),
+	      tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las));
+  s = format (s, " cong %U ", format_tcp_congestion_status, tc);
+  s = format (s, "cwnd %u ssthresh %u rtx_bytes %u bytes_acked %u\n",
+	      tc->cwnd, tc->ssthresh, tc->rtx_bytes, tc->bytes_acked);
+  s = format (s, " prev_ssthresh %u snd_congestion %u\n", tc->prev_ssthresh,
+	      tc->snd_congestion - tc->iss);
+  s = format (s, " rto %u rto_boff %u srtt %u rttvar %u rtt_ts %u ", tc->rto,
+	      tc->rto_boff, tc->srtt, tc->rttvar, tc->rtt_ts);
+  s = format (s, "rtt_seq %u\n", tc->rtt_seq);
+  if (scoreboard_first_hole (&tc->sack_sb))
+    s = format (s, " scoreboard: %U\n", format_tcp_scoreboard, &tc->sack_sb);
+  if (vec_len (tc->snd_sacks))
+    s = format (s, " sacks tx: %U\n", format_tcp_sacks, tc);
+
+  return s;
+}
+
+u8 *
+format_tcp_connection_id (u8 * s, va_list * args)
 {
   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
   if (!tc)
@@ -527,11 +570,18 @@
 }
 
 u8 *
-format_tcp_connection_verbose (u8 * s, va_list * args)
+format_tcp_connection (u8 * s, va_list * args)
 {
   tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
-  s = format (s, "%U %U %U", format_tcp_connection, tc, format_tcp_state,
-	      &tc->state, format_tcp_timers, tc);
+  u32 verbose = va_arg (*args, u32);
+
+  s = format (s, "%-50U", format_tcp_connection_id, tc);
+  if (verbose)
+    {
+      s = format (s, "%-15U", format_tcp_state, tc->state);
+      if (verbose > 1)
+	s = format (s, " %U\n%U", format_tcp_timers, tc, format_tcp_vars, tc);
+    }
   return s;
 }
 
@@ -540,11 +590,12 @@
 {
   u32 tci = va_arg (*args, u32);
   u32 thread_index = va_arg (*args, u32);
+  u32 verbose = va_arg (*args, u32);
   tcp_connection_t *tc;
 
   tc = tcp_connection_get (tci, thread_index);
   if (tc)
-    return format (s, "%U", format_tcp_connection, tc);
+    return format (s, "%U", format_tcp_connection, tc, verbose);
   else
     return format (s, "empty");
 }
@@ -554,7 +605,7 @@
 {
   u32 tci = va_arg (*args, u32);
   tcp_connection_t *tc = tcp_listener_get (tci);
-  return format (s, "%U", format_tcp_connection, tc);
+  return format (s, "%U", format_tcp_connection_id, tc);
 }
 
 u8 *
@@ -562,7 +613,7 @@
 {
   u32 tci = va_arg (*args, u32);
   tcp_connection_t *tc = tcp_half_open_connection_get (tci);
-  return format (s, "%U", format_tcp_connection, tc);
+  return format (s, "%U", format_tcp_connection_id, tc);
 }
 
 u8 *
@@ -659,12 +710,18 @@
 
 /**
  * Compute tx window session is allowed to fill.
+ *
+ * Takes into account available send space, snd_mss and the congestion
+ * state of the connection. If possible, the value returned is a multiple
+ * of snd_mss.
+ *
+ * @param tc tcp connection
+ * @return number of bytes session is allowed to write
  */
 u32
-tcp_session_send_space (transport_connection_t * trans_conn)
+tcp_snd_space (tcp_connection_t * tc)
 {
   int snd_space;
-  tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
 
   /* If we haven't gotten dupacks or if we did and have gotten sacked bytes
    * then we can still send */
@@ -698,6 +755,13 @@
 }
 
 u32
+tcp_session_send_space (transport_connection_t * trans_conn)
+{
+  tcp_connection_t *tc = (tcp_connection_t *) trans_conn;
+  return tcp_snd_space (tc);
+}
+
+u32
 tcp_session_tx_fifo_offset (transport_connection_t * trans_conn)
 {
   tcp_connection_t *tc = (tcp_connection_t *) trans_conn;