tcp: state machine improvements 45/8045/2
authorFlorin Coras <fcoras@cisco.com>
Mon, 14 Aug 2017 18:25:25 +0000 (11:25 -0700)
committerDave Barach <openvpp@barachs.net>
Tue, 15 Aug 2017 12:33:31 +0000 (12:33 +0000)
- Add SYN_RCVD timeout
- Fix FIN_WAIT_1 to CLOSING transition

Change-Id: I42ca7fc087f6fdfae15bd7a6175dd3226ed341c7
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/vnet/session/application.c
src/vnet/session/application.h
src/vnet/session/session.c
src/vnet/session/stream_session.h
src/vnet/tcp/tcp.c
src/vnet/tcp/tcp.h
src/vnet/tcp/tcp_input.c

index 78c41b9..bc837bb 100644 (file)
@@ -329,7 +329,7 @@ application_open_session (application_t * app, session_type_t sst,
     return rv;
 
   /* Store api_context for when the reply comes. Not the nicest thing
-   * but better allocating a separate half-open pool.  */
+   * but better than allocating a separate half-open pool. */
   tc->s_index = api_context;
 
   return 0;
index 29d37a0..45bc001 100644 (file)
@@ -37,7 +37,7 @@ typedef struct _stream_session_cb_vft
   int (*session_accept_callback) (stream_session_t * new_session);
 
   /* Connection request callback */
-  int (*session_connected_callback) (u32 app_index, u32 api_context,
+  int (*session_connected_callback) (u32 app_index, u32 opaque,
                                     stream_session_t * s, u8 code);
 
   /** Notify app that session is closing */
index 3a3e4df..843d474 100644 (file)
@@ -373,7 +373,7 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail)
   application_t *app;
   stream_session_t *new_s = 0;
   u64 handle;
-  u32 api_context = 0;
+  u32 opaque = 0;
   int error = 0;
 
   handle = stream_session_half_open_lookup_handle (&tc->lcl_ip, &tc->rmt_ip,
@@ -385,9 +385,11 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail)
       return -1;
     }
 
-  /* Get the app's index from the handle we stored when opening connection */
+  /* Get the app's index from the handle we stored when opening connection
+   * and the opaque (api_context for external apps) from transport session
+   * index*/
   app = application_get (handle >> 32);
-  api_context = tc->s_index;
+  opaque = tc->s_index;
 
   if (!is_fail)
     {
@@ -406,7 +408,7 @@ stream_session_connect_notify (transport_connection_t * tc, u8 is_fail)
     }
 
   /* Notify client application */
-  if (app->cb_fns.session_connected_callback (app->index, api_context, new_s,
+  if (app->cb_fns.session_connected_callback (app->index, opaque, new_s,
                                              is_fail))
     {
       clib_warning ("failed to notify app");
index 4c26321..39bf846 100644 (file)
@@ -83,9 +83,6 @@ typedef struct _stream_session_t
 
   u32 opaque2;
 
-  /** connected (server) session handle */
-  u64 server_session_handle;
-
   /** Opaque, pad to a 64-octet boundary */
   u64 opaque[1];
 } stream_session_t;
index 10ecf2f..75c9d8d 100644 (file)
@@ -1106,10 +1106,17 @@ tcp_timer_establish_handler (u32 conn_index)
   tcp_connection_t *tc;
 
   tc = tcp_half_open_connection_get (conn_index);
-  tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
-
-  ASSERT (tc->state == TCP_STATE_SYN_SENT);
-  stream_session_connect_notify (&tc->connection, 1 /* fail */ );
+  if (tc)
+    {
+      ASSERT (tc->state == TCP_STATE_SYN_SENT);
+      tc->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
+      stream_session_connect_notify (&tc->connection, 1 /* fail */ );
+    }
+  else
+    {
+      tc = tcp_connection_get (conn_index, vlib_get_thread_index ());
+      ASSERT (tc->state == TCP_STATE_SYN_RCVD);
+    }
   tcp_connection_cleanup (tc);
 }
 
index 52610dd..8010b44 100644 (file)
@@ -97,6 +97,7 @@ extern timer_expiration_handler tcp_timer_retransmit_syn_handler;
                                                 * ticks to timer units */
 #define TCP_DELACK_TIME         1      /* 0.1s */
 #define TCP_ESTABLISH_TIME      750    /* 75s */
+#define TCP_SYN_RCVD_TIME      100     /* 10s */
 #define TCP_2MSL_TIME           300    /* 30s */
 #define TCP_CLOSEWAIT_TIME     20      /* 0.1s */
 #define TCP_CLEANUP_TIME       5       /* 0.5s Time to wait before cleanup */
index 2d36c85..a3c4f1d 100644 (file)
@@ -2254,8 +2254,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              tc0->snd_wl2 = vnet_buffer (b0)->tcp.ack_number;
              stream_session_accept_notify (&tc0->connection);
 
-             /* Reset SYN-ACK retransmit timer */
+             /* Reset SYN-ACK retransmit and SYN_RCV establish timers */
              tcp_retransmit_timer_reset (tc0);
+             tcp_timer_reset (tc0, TCP_TIMER_ESTABLISH);
              break;
            case TCP_STATE_ESTABLISHED:
              /* We can get packets in established state here because they
@@ -2281,13 +2282,21 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              /* If FIN is ACKed */
              else if (tc0->snd_una == tc0->snd_una_max)
                {
-                 ASSERT (tcp_fin (tcp0));
                  tc0->rcv_nxt += 1;
                  tc0->state = TCP_STATE_FIN_WAIT_2;
                  TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
 
-                 /* Stop all timers, 2MSL will be set lower */
-                 tcp_connection_timers_reset (tc0);
+                 if (tcp_fin (tcp0))
+                   {
+                     /* Stop all timers, 2MSL will be set lower */
+                     tcp_connection_timers_reset (tc0);
+                   }
+                 else
+                   {
+                     /* Wait for peer to finish sending its data */
+                     tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE,
+                                       TCP_2MSL_TIME);
+                   }
                }
              break;
            case TCP_STATE_FIN_WAIT_2:
@@ -2296,8 +2305,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
               * acknowledged ("ok") but do not delete the TCB. */
              if (tcp_rcv_ack (tc0, b0, tcp0, &next0, &error0))
                goto drop;
-
-             /* check if rtx queue is empty and ack CLOSE TODO */
              break;
            case TCP_STATE_CLOSE_WAIT:
              /* Do the same processing as for the ESTABLISHED state. */
@@ -2311,9 +2318,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              if (tcp_rcv_ack (tc0, b0, tcp0, &next0, &error0))
                goto drop;
 
-             /* XXX test that send queue empty */
              tc0->state = TCP_STATE_TIME_WAIT;
              TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+             tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
              goto drop;
 
              break;
@@ -2409,10 +2416,12 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              /* move along .. */
              break;
            case TCP_STATE_FIN_WAIT_1:
-             tc0->state = TCP_STATE_TIME_WAIT;
-             tcp_connection_timers_reset (tc0);
-             tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
+             tc0->state = TCP_STATE_CLOSING;
+             tcp_make_ack (tc0, b0);
+             next0 = tcp_next_output (is_ip4);
              TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+             /* Wait for ACK but not forever */
+             tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
              break;
            case TCP_STATE_FIN_WAIT_2:
              /* Got FIN, send ACK! */
@@ -2652,6 +2661,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          /* Reuse buffer to make syn-ack and send */
          tcp_make_synack (child0, b0);
          next0 = tcp_next_output (is_ip4);
+         tcp_timer_set (child0, TCP_TIMER_ESTABLISH, TCP_SYN_RCVD_TIME);
 
        drop:
          if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))