tcp: cleanup connection/session fixes
[vpp.git] / src / vnet / tcp / tcp_output.c
index fe6d09c..8a88bf8 100644 (file)
@@ -163,8 +163,8 @@ tcp_update_rcv_wnd (tcp_connection_t * tc)
   /*
    * Figure out how much space we have available
    */
-  available_space = stream_session_max_rx_enqueue (&tc->connection);
-  max_fifo = stream_session_rx_fifo_size (&tc->connection);
+  available_space = transport_max_rx_enqueue (&tc->connection);
+  max_fifo = transport_rx_fifo_size (&tc->connection);
 
   ASSERT (tc->rcv_opts.mss < max_fifo);
   if (available_space < tc->rcv_opts.mss && available_space < max_fifo >> 3)
@@ -389,6 +389,8 @@ tcp_make_options (tcp_connection_t * tc, tcp_options_t * opts,
     {
     case TCP_STATE_ESTABLISHED:
     case TCP_STATE_FIN_WAIT_1:
+    case TCP_STATE_CLOSED:
+    case TCP_STATE_CLOSE_WAIT:
       return tcp_make_established_options (tc, opts);
     case TCP_STATE_SYN_RCVD:
       return tcp_make_synack_options (tc, opts);
@@ -675,6 +677,8 @@ tcp_enqueue_to_ip_lookup (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
                          u8 is_ip4, u32 fib_index)
 {
   tcp_enqueue_to_ip_lookup_i (vm, b, bi, is_ip4, fib_index, 0);
+  if (vm->thread_index == 0 && vlib_num_workers ())
+    session_flush_frames_main_thread (vm);
 }
 
 always_inline void
@@ -1210,7 +1214,7 @@ tcp_prepare_retransmit_segment (tcp_connection_t * tc, u32 offset,
   /*
    * Make sure we can retransmit something
    */
-  available_bytes = stream_session_tx_fifo_max_dequeue (&tc->connection);
+  available_bytes = session_tx_fifo_max_dequeue (&tc->connection);
   ASSERT (available_bytes >= offset);
   available_bytes -= offset;
   if (!available_bytes)
@@ -1335,8 +1339,9 @@ done:
  * Reset congestion control, switch cwnd to loss window and try again.
  */
 static void
-tcp_rtx_timeout_cc (tcp_connection_t * tc)
+tcp_rxt_timeout_cc (tcp_connection_t * tc)
 {
+  TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 6);
   tc->prev_ssthresh = tc->ssthresh;
   tc->prev_cwnd = tc->cwnd;
 
@@ -1345,10 +1350,12 @@ tcp_rtx_timeout_cc (tcp_connection_t * tc)
     tcp_cc_fastrecovery_exit (tc);
 
   /* Start again from the beginning */
-  tc->ssthresh = clib_max (tcp_flight_size (tc) / 2, 2 * tc->snd_mss);
+  tc->cc_algo->congestion (tc);
   tc->cwnd = tcp_loss_wnd (tc);
   tc->snd_congestion = tc->snd_una_max;
   tc->rtt_ts = 0;
+  tc->cwnd_acc_bytes = 0;
+
   tcp_recovery_on (tc);
 }
 
@@ -1379,6 +1386,8 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
       tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID;
     }
 
+  TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 1);
+
   if (tc->state >= TCP_STATE_ESTABLISHED)
     {
       /* Lost FIN, retransmit and return */
@@ -1391,7 +1400,8 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
        }
 
       /* Shouldn't be here */
-      if (tc->snd_una == tc->snd_una_max)
+      if ((tc->rto_boff == 0 && tc->snd_una == tc->snd_una_max)
+         || (tc->rto_boff > 0 && seq_geq (tc->snd_una, tc->snd_congestion)))
        {
          tcp_recovery_off (tc);
          return;
@@ -1410,13 +1420,11 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn)
 
       /* First retransmit timeout */
       if (tc->rto_boff == 1)
-       tcp_rtx_timeout_cc (tc);
+       tcp_rxt_timeout_cc (tc);
 
-      tc->snd_nxt = tc->snd_una;
+      tc->snd_una_max = tc->snd_nxt = tc->snd_una;
       tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX);
 
-      TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 1);
-
       /* Send one segment. Note that n_bytes may be zero due to buffer shortfall  */
       n_bytes = tcp_prepare_retransmit_segment (tc, 0, tc->snd_mss, &b);
 
@@ -1547,7 +1555,7 @@ tcp_timer_persist_handler (u32 index)
       || tc->snd_wnd > tc->snd_mss || tcp_in_recovery (tc))
     return;
 
-  available_bytes = stream_session_tx_fifo_max_dequeue (&tc->connection);
+  available_bytes = session_tx_fifo_max_dequeue (&tc->connection);
   offset = tc->snd_una_max - tc->snd_una;
 
   /* Reprogram persist if no new bytes available to send. We may have data
@@ -1623,7 +1631,7 @@ void
 tcp_fast_retransmit_sack (tcp_connection_t * tc)
 {
   vlib_main_t *vm = vlib_get_main ();
-  u32 n_written = 0, offset, max_bytes;
+  u32 n_written = 0, offset, max_bytes, n_segs = 0;
   vlib_buffer_t *b = 0;
   sack_scoreboard_hole_t *hole;
   sack_scoreboard_t *sb;
@@ -1632,14 +1640,17 @@ tcp_fast_retransmit_sack (tcp_connection_t * tc)
   u8 snd_limited = 0, can_rescue = 0;
 
   ASSERT (tcp_in_fastrecovery (tc));
-  TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 0);
 
   old_snd_nxt = tc->snd_nxt;
   sb = &tc->sack_sb;
-  snd_space = tcp_available_snd_space (tc);
+  snd_space = tcp_available_cc_snd_space (tc);
+
+  if (snd_space < tc->snd_mss)
+    goto done;
 
+  TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 0);
   hole = scoreboard_get_hole (sb, sb->cur_rxt_hole);
-  while (hole && snd_space > 0)
+  while (hole && snd_space > 0 && n_segs++ < VLIB_FRAME_SIZE)
     {
       hole = scoreboard_next_rxt_hole (sb, hole,
                                       tcp_fastrecovery_sent_1_smss (tc),
@@ -1713,7 +1724,7 @@ tcp_fast_retransmit_no_sack (tcp_connection_t * tc)
   /* Start resending from first un-acked segment */
   old_snd_nxt = tc->snd_nxt;
   tc->snd_nxt = tc->snd_una;
-  snd_space = tcp_available_snd_space (tc);
+  snd_space = tcp_available_cc_snd_space (tc);
 
   while (snd_space > 0)
     {
@@ -1739,8 +1750,7 @@ tcp_fast_retransmit_no_sack (tcp_connection_t * tc)
 void
 tcp_fast_retransmit (tcp_connection_t * tc)
 {
-  if (tcp_opts_sack_permitted (&tc->rcv_opts)
-      && scoreboard_first_hole (&tc->sack_sb))
+  if (tcp_opts_sack_permitted (&tc->rcv_opts))
     tcp_fast_retransmit_sack (tc);
   else
     tcp_fast_retransmit_no_sack (tc);
@@ -1753,21 +1763,6 @@ tcp_session_has_ooo_data (tcp_connection_t * tc)
   return svm_fifo_has_ooo_data (s->server_rx_fifo);
 }
 
-typedef struct
-{
-  fib_protocol_t nh_proto;
-  vnet_link_t link_type;
-  ip46_address_t ip;
-  u32 sw_if_index;
-} tcp_adj_add_args_t;
-
-void
-tcp_output_add_adj (tcp_adj_add_args_t * args)
-{
-  adj_nbr_add_or_lock (args->nh_proto, args->link_type, &args->ip,
-                      args->sw_if_index);
-}
-
 static void
 tcp_output_handle_link_local (tcp_connection_t * tc0, vlib_buffer_t * b0,
                              u32 * next0, u32 * error0)
@@ -1775,18 +1770,12 @@ tcp_output_handle_link_local (tcp_connection_t * tc0, vlib_buffer_t * b0,
   ip_adjacency_t *adj;
   adj_index_t ai;
 
+  /* Not thread safe but as long as the connection exists the adj should
+   * not be removed */
   ai = adj_nbr_find (FIB_PROTOCOL_IP6, VNET_LINK_IP6, &tc0->c_rmt_ip,
                     tc0->sw_if_index);
   if (ai == ADJ_INDEX_INVALID)
     {
-      tcp_adj_add_args_t args = {
-       .nh_proto = FIB_PROTOCOL_IP6,
-       .link_type = VNET_LINK_IP6,
-       .ip = tc0->c_rmt_ip,
-       .sw_if_index = tc0->sw_if_index
-      };
-      vlib_rpc_call_main_thread (tcp_output_add_adj, (u8 *) & args,
-                                sizeof (args));
       vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
       *next0 = TCP_OUTPUT_NEXT_DROP;
       *error0 = TCP_ERROR_LINK_LOCAL_RW;
@@ -1794,10 +1783,16 @@ tcp_output_handle_link_local (tcp_connection_t * tc0, vlib_buffer_t * b0,
     }
 
   adj = adj_get (ai);
-  if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
+  if (PREDICT_TRUE (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE))
     *next0 = TCP_OUTPUT_NEXT_IP_REWRITE;
   else if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
     *next0 = TCP_OUTPUT_NEXT_IP_ARP;
+  else
+    {
+      *next0 = TCP_OUTPUT_NEXT_DROP;
+      *error0 = TCP_ERROR_LINK_LOCAL_RW;
+    }
+  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ai;
 }
 
 always_inline uword