session: deschedule sessions with no data to send

This ensures the scheduler always tracks sessions that are descheduled,
i.e., do not have events in the old io events list. When app retries to
send, clear descheduled flag and potentially the pacer.

Consequently, transports no longer need to reset the pacer when
sessions are rescheduled after a long app tx pause.

This also fixes a tcp bug whereby the pacer was reset too often when
snd_una was equal to snd_nxt as there was no way to distinguish betwen
app tx breaks and congestion.

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: Id3cc6c98cd76299e15030e504380dcf3c04c5189
diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c
index 1d7ebf9..bebabd3 100644
--- a/src/vnet/session/session_node.c
+++ b/src/vnet/session/session_node.c
@@ -1188,8 +1188,14 @@
 
   svm_fifo_unset_event (s->tx_fifo);
   if (svm_fifo_max_dequeue_cons (s->tx_fifo) > ctx->sp.tx_offset)
-    if (svm_fifo_set_event (s->tx_fifo))
-      session_evt_add_head_old (wrk, elt);
+    {
+      if (svm_fifo_set_event (s->tx_fifo))
+	session_evt_add_head_old (wrk, elt);
+    }
+  else
+    {
+      transport_connection_deschedule (ctx->tc);
+    }
 }
 
 always_inline int
@@ -1246,6 +1252,11 @@
 	}
     }
 
+  /* Connection previously descheduled because it had no data to send.
+   * Clear descheduled flag and reset pacer if in use */
+  if (transport_connection_is_descheduled (ctx->tc))
+    transport_connection_clear_descheduled (ctx->tc);
+
   transport_connection_snd_params (ctx->tc, &ctx->sp);
 
   if (!ctx->sp.snd_space)
diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h
index 2cfec06..549f179 100644
--- a/src/vnet/session/transport.h
+++ b/src/vnet/session/transport.h
@@ -327,6 +327,19 @@
   return (tc->flags & TRANSPORT_CONNECTION_F_IS_TX_PACED);
 }
 
+/**
+ * Clear descheduled flag and update pacer if needed
+ *
+ * To add session to scheduler use @ref transport_connection_reschedule
+ */
+always_inline void
+transport_connection_clear_descheduled (transport_connection_t *tc)
+{
+  tc->flags &= ~TRANSPORT_CONNECTION_F_DESCHED;
+  if (transport_connection_is_tx_paced (tc))
+    transport_connection_tx_pacer_reset_bucket (tc, 0 /* bucket */);
+}
+
 u8 *format_transport_pacer (u8 * s, va_list * args);
 
 /**
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 5647b8f..55fa6d1 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -321,7 +321,6 @@
   if (tc->snd_una == tc->snd_nxt)
     {
       tcp_cc_event (tc, TCP_CC_EVT_START_TX);
-      tcp_connection_tx_pacer_reset (tc, tc->cwnd, TRANSPORT_PACER_MIN_BURST);
     }
 
   if (tc->flags & TCP_CONN_PSH_PENDING)