SCTP: shutdown phase 42/10442/3
authorMarco Varlese <marco.varlese@suse.com>
Wed, 7 Feb 2018 11:22:41 +0000 (12:22 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 8 Feb 2018 10:03:23 +0000 (10:03 +0000)
This patch addresses some bugs discovered with the shutdown phase which
were causing the actual chunks not to leave the output_node.
While fixing the issue some minor refactoring was also performed to
align the internal functions to a 'common' design.

Change-Id: Ieac4f6e78cffad2e6982536f8e9f190a66f328f7
Signed-off-by: Marco Varlese <marco.varlese@suse.com>
src/vnet/sctp/sctp.h
src/vnet/sctp/sctp_input.c
src/vnet/sctp/sctp_output.c

index 9129aa8..60a195f 100644 (file)
@@ -247,7 +247,8 @@ void sctp_connection_del (sctp_connection_t * sctp_conn);
 u32 sctp_push_header (transport_connection_t * tconn, vlib_buffer_t * b);
 void sctp_send_init (sctp_connection_t * sctp_conn);
 void sctp_send_shutdown (sctp_connection_t * sctp_conn);
-void sctp_send_shutdown_ack (sctp_connection_t * sctp_conn);
+void sctp_send_shutdown_ack (sctp_connection_t * sctp_conn,
+                            vlib_buffer_t * b);
 void sctp_send_shutdown_complete (sctp_connection_t * sctp_conn);
 void sctp_send_heartbeat (sctp_connection_t * sctp_conn);
 void sctp_flush_frame_to_output (vlib_main_t * vm, u8 thread_index,
index 7d5e755..8df9564 100644 (file)
@@ -686,11 +686,10 @@ sctp_is_connection_gapping (sctp_connection_t * sctp_conn, u32 tsn,
 
 always_inline u16
 sctp_handle_data (sctp_payload_data_chunk_t * sctp_data_chunk,
-                 sctp_connection_t * sctp_conn, vlib_buffer_t * b,
+                 sctp_connection_t * sctp_conn, u8 idx, vlib_buffer_t * b,
                  u16 * next0)
 {
   u32 error = 0, n_data_bytes;
-  u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
   u8 is_gapping = 0;
 
   /* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */
@@ -758,13 +757,11 @@ sctp_handle_data (sctp_payload_data_chunk_t * sctp_data_chunk,
 always_inline u16
 sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
                         sctp_chunks_common_hdr_t * sctp_chunk_hdr,
-                        sctp_connection_t * sctp_conn, vlib_buffer_t * b0)
+                        sctp_connection_t * sctp_conn, u8 idx,
+                        vlib_buffer_t * b0, u16 * next0)
 {
   u32 now = sctp_time_now ();
 
-  /* Build TCB */
-  u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ECHO);
-
   sctp_cookie_echo_chunk_t *cookie_echo =
     (sctp_cookie_echo_chunk_t *) sctp_hdr;
 
@@ -791,6 +788,7 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
 
   /* Change state */
   sctp_conn->state = SCTP_STATE_ESTABLISHED;
+  *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
 
   sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT,
                  sctp_conn->sub_conn[idx].RTO);
@@ -804,12 +802,9 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
 always_inline u16
 sctp_handle_cookie_ack (sctp_header_t * sctp_hdr,
                        sctp_chunks_common_hdr_t * sctp_chunk_hdr,
-                       sctp_connection_t * sctp_conn, vlib_buffer_t * b0)
+                       sctp_connection_t * sctp_conn, u8 idx,
+                       vlib_buffer_t * b0, u16 * next0)
 {
-
-  /* Stop T1_COOKIE timer */
-  u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ACK);
-
   /* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */
   if (sctp_conn->local_tag != sctp_hdr->verification_tag)
     {
@@ -821,6 +816,7 @@ sctp_handle_cookie_ack (sctp_header_t * sctp_hdr,
   sctp_timer_reset (sctp_conn, idx, SCTP_TIMER_T1_COOKIE);
   /* Change state */
   sctp_conn->state = SCTP_STATE_ESTABLISHED;
+  *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
 
   sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT,
                  sctp_conn->sub_conn[idx].RTO);
@@ -1090,8 +1086,9 @@ vlib_node_registration_t sctp6_shutdown_phase_node;
 always_inline u16
 sctp_handle_shutdown (sctp_header_t * sctp_hdr,
                      sctp_chunks_common_hdr_t * sctp_chunk_hdr,
-                     sctp_connection_t * sctp_conn, vlib_buffer_t * b0,
-                     u16 sctp_implied_length)
+                     sctp_connection_t * sctp_conn, u8 idx,
+                     vlib_buffer_t * b0, u16 sctp_implied_length,
+                     u16 * next0)
 {
   sctp_shutdown_association_chunk_t *shutdown_chunk =
     (sctp_shutdown_association_chunk_t *) (sctp_hdr);
@@ -1113,21 +1110,25 @@ sctp_handle_shutdown (sctp_header_t * sctp_hdr,
     case SCTP_STATE_ESTABLISHED:
       if (sctp_check_outstanding_data_chunks (sctp_conn) == 0)
        sctp_conn->state = SCTP_STATE_SHUTDOWN_RECEIVED;
+      sctp_send_shutdown_ack (sctp_conn, b0);
       break;
 
     case SCTP_STATE_SHUTDOWN_SENT:
-      sctp_send_shutdown_ack (sctp_conn);
+      sctp_send_shutdown_ack (sctp_conn, b0);
       break;
     }
 
+  *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
+
   return SCTP_ERROR_NONE;
 }
 
 always_inline u16
 sctp_handle_shutdown_ack (sctp_header_t * sctp_hdr,
                          sctp_chunks_common_hdr_t * sctp_chunk_hdr,
-                         sctp_connection_t * sctp_conn, vlib_buffer_t * b0,
-                         u16 sctp_implied_length)
+                         sctp_connection_t * sctp_conn, u8 idx,
+                         vlib_buffer_t * b0, u16 sctp_implied_length,
+                         u16 * next0)
 {
   sctp_shutdown_ack_chunk_t *shutdown_ack_chunk =
     (sctp_shutdown_ack_chunk_t *) (sctp_hdr);
@@ -1153,14 +1154,17 @@ sctp_handle_shutdown_ack (sctp_header_t * sctp_hdr,
                    SCTP_TIMER_T2_SHUTDOWN);
   sctp_send_shutdown_complete (sctp_conn);
 
+  *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
+
   return SCTP_ERROR_NONE;
 }
 
 always_inline u16
 sctp_handle_shutdown_complete (sctp_header_t * sctp_hdr,
                               sctp_chunks_common_hdr_t * sctp_chunk_hdr,
-                              sctp_connection_t * sctp_conn,
-                              vlib_buffer_t * b0, u16 sctp_implied_length)
+                              sctp_connection_t * sctp_conn, u8 idx,
+                              vlib_buffer_t * b0, u16 sctp_implied_length,
+                              u16 * next0)
 {
   sctp_shutdown_complete_chunk_t *shutdown_complete =
     (sctp_shutdown_complete_chunk_t *) (sctp_hdr);
@@ -1185,6 +1189,8 @@ sctp_handle_shutdown_complete (sctp_header_t * sctp_hdr,
   stream_session_disconnect_notify (&sctp_conn->sub_conn
                                    [MAIN_SCTP_SUB_CONN_IDX].connection);
 
+  *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
+
   return SCTP_ERROR_NONE;
 }
 
@@ -1257,30 +1263,31 @@ sctp46_shutdown_phase_inline (vlib_main_t * vm,
          sctp_implied_length =
            sctp_calculate_implied_length (ip4_hdr, ip6_hdr, is_ip4);
 
-         switch (vnet_sctp_get_chunk_type (sctp_chunk_hdr))
+         u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
+
+         u8 chunk_type = vnet_sctp_get_chunk_type (sctp_chunk_hdr);
+         switch (chunk_type)
            {
            case SHUTDOWN:
              error0 =
-               sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn, b0,
-                                     sctp_implied_length);
-             next0 = sctp_next_output (is_ip4);
+               sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn,
+                                     idx, b0, sctp_implied_length, &next0);
              break;
 
            case SHUTDOWN_ACK:
              error0 =
                sctp_handle_shutdown_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn,
-                                         b0, sctp_implied_length);
-             next0 = sctp_next_output (is_ip4);
+                                         idx, b0, sctp_implied_length,
+                                         &next0);
              break;
 
            case SHUTDOWN_COMPLETE:
              error0 =
                sctp_handle_shutdown_complete (sctp_hdr, sctp_chunk_hdr,
-                                              sctp_conn, b0,
-                                              sctp_implied_length);
+                                              sctp_conn, idx, b0,
+                                              sctp_implied_length, &next0);
 
              sctp_connection_cleanup (sctp_conn);
-             next0 = sctp_next_output (is_ip4);
              break;
 
              /*
@@ -1290,8 +1297,7 @@ sctp46_shutdown_phase_inline (vlib_main_t * vm,
            case DATA:
              error0 =
                sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr,
-                                 sctp_conn, b0, &next0);
-             next0 = sctp_next_output (is_ip4);
+                                 sctp_conn, idx, b0, &next0);
              break;
 
              /* All UNEXPECTED scenarios (wrong chunk received per state-machine)
@@ -1761,15 +1767,13 @@ sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            case COOKIE_ECHO:
              error0 =
                sctp_handle_cookie_echo (sctp_hdr, sctp_chunk_hdr, sctp_conn,
-                                        b0);
-             next0 = sctp_next_output (is_ip4);
+                                        idx, b0, &next0);
              break;
 
            case COOKIE_ACK:
              error0 =
                sctp_handle_cookie_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn,
-                                       b0);
-             next0 = sctp_next_output (is_ip4);
+                                       idx, b0, &next0);
              break;
 
            case SACK:
@@ -1793,7 +1797,7 @@ sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            case DATA:
              error0 =
                sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr,
-                                 sctp_conn, b0, &next0);
+                                 sctp_conn, idx, b0, &next0);
              break;
 
              /* All UNEXPECTED scenarios (wrong chunk received per state-machine)
@@ -2064,7 +2068,6 @@ sctp46_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node,
          vnet_sctp_common_hdr_params_net_to_host (sctp_chunk_hdr);
 
          u8 type = vnet_sctp_get_chunk_type (sctp_chunk_hdr);
-
 #if SCTP_DEBUG_STATE_MACHINE
          u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
 #endif
index dc78c09..276d7e7 100644 (file)
@@ -751,12 +751,9 @@ sctp_prepare_initack_chunk (sctp_connection_t * sctp_conn, vlib_buffer_t * b,
 void
 sctp_prepare_shutdown_chunk (sctp_connection_t * sctp_conn, vlib_buffer_t * b)
 {
-  vlib_main_t *vm = vlib_get_main ();
   u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN);
   u16 alloc_bytes = sizeof (sctp_shutdown_association_chunk_t);
 
-  b = sctp_reuse_buffer (vm, b);
-
   /* As per RFC 4960 the chunk_length value does NOT contemplate
    * the size of the first header (see sctp_header_t) and any padding
    */
@@ -805,8 +802,8 @@ sctp_send_shutdown (sctp_connection_t * sctp_conn)
   sctp_prepare_shutdown_chunk (sctp_conn, b);
 
   u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN);
-  sctp_enqueue_to_output (vm, b, bi,
-                         sctp_conn->sub_conn[idx].connection.is_ip4);
+  sctp_enqueue_to_output_now (vm, b, bi,
+                             sctp_conn->sub_conn[idx].connection.is_ip4);
 
   /* Measure RTT with this */
   sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
@@ -847,34 +844,21 @@ sctp_prepare_shutdown_ack_chunk (sctp_connection_t * sctp_conn,
  * Send SHUTDOWN_ACK
  */
 void
-sctp_send_shutdown_ack (sctp_connection_t * sctp_conn)
+sctp_send_shutdown_ack (sctp_connection_t * sctp_conn, vlib_buffer_t * b)
 {
-  vlib_buffer_t *b;
-  u32 bi;
-  sctp_main_t *tm = vnet_get_sctp_main ();
   vlib_main_t *vm = vlib_get_main ();
 
   if (sctp_check_outstanding_data_chunks (sctp_conn) > 0)
     return;
 
-  if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
-    return;
+  sctp_reuse_buffer (vm, b);
 
-  b = vlib_get_buffer (vm, bi);
-  sctp_init_buffer (vm, b);
   sctp_prepare_shutdown_ack_chunk (sctp_conn, b);
 
   u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN_ACK);
-  sctp_enqueue_to_output (vm, b, bi,
-                         sctp_conn->sub_conn[idx].connection.is_ip4);
 
   /* Measure RTT with this */
   sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
-
-  /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
-  sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
-                 sctp_conn->sub_conn[idx].RTO);
-  sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
 }
 
 /**
@@ -1228,6 +1212,7 @@ sctp46_output_inline (vlib_main_t * vm,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
+
          sctp_conn =
            sctp_connection_get (vnet_buffer (b0)->sctp.connection_index,
                                 my_thread_index);
@@ -1390,6 +1375,30 @@ sctp46_output_inline (vlib_main_t * vm,
              /* Change state */
              sctp_conn->state = SCTP_STATE_COOKIE_ECHOED;
              break;
+           case SCTP_STATE_SHUTDOWN_SENT:
+             if (chunk_type != SHUTDOWN_COMPLETE)
+               {
+                 SCTP_DBG_STATE_MACHINE
+                   ("Sending the wrong chunk (%s) based on state-machine status (%s)",
+                    sctp_chunk_to_string (chunk_type),
+                    sctp_state_to_string (sctp_conn->state));
+
+                 error0 = SCTP_ERROR_UNKOWN_CHUNK;
+                 next0 = SCTP_OUTPUT_NEXT_DROP;
+                 goto done;
+               }
+           case SCTP_STATE_SHUTDOWN_RECEIVED:
+             if (chunk_type != SHUTDOWN_ACK)
+               {
+                 SCTP_DBG_STATE_MACHINE
+                   ("Sending the wrong chunk (%s) based on state-machine status (%s)",
+                    sctp_chunk_to_string (chunk_type),
+                    sctp_state_to_string (sctp_conn->state));
+
+                 error0 = SCTP_ERROR_UNKOWN_CHUNK;
+                 next0 = SCTP_OUTPUT_NEXT_DROP;
+                 goto done;
+               }
            default:
              SCTP_DBG_STATE_MACHINE
                ("Sending chunk (%s) based on state-machine status (%s)",
@@ -1398,18 +1407,30 @@ sctp46_output_inline (vlib_main_t * vm,
              break;
            }
 
-         if (chunk_type == SHUTDOWN)
+         switch (chunk_type)
            {
-             /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
-             sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
-                             sctp_conn->sub_conn[idx].RTO);
-             sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT;
-           }
-
-         if (chunk_type == DATA)
-           {
-             sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
-                                sctp_conn->sub_conn[idx].RTO);
+           case DATA:
+             {
+               sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
+                                  sctp_conn->sub_conn[idx].RTO);
+               break;
+             }
+           case SHUTDOWN:
+             {
+               /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
+               sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
+                               sctp_conn->sub_conn[idx].RTO);
+               sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT;
+               break;
+             }
+           case SHUTDOWN_ACK:
+             {
+               /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
+               sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
+                               sctp_conn->sub_conn[idx].RTO);
+               sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
+               break;
+             }
            }
 
          vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;