sctp: migrate old MULTIARCH macros to VLIB_NODE_FN 32/18032/2
authorFilip Tehlar <ftehlar@cisco.com>
Tue, 5 Mar 2019 14:50:19 +0000 (06:50 -0800)
committerDamjan Marion <dmarion@me.com>
Wed, 6 Mar 2019 11:37:57 +0000 (11:37 +0000)
Change-Id: I7248a94977fe11bbe58db53d7ca8ae8c582e7305
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
src/vnet/CMakeLists.txt
src/vnet/sctp/sctp.c
src/vnet/sctp/sctp.h
src/vnet/sctp/sctp_input.c
src/vnet/sctp/sctp_output.c
src/vnet/sctp/sctp_output_node.c [new file with mode: 0644]

index 4c4928a..04fd6d1 100644 (file)
@@ -590,9 +590,15 @@ list(APPEND VNET_SOURCES
   sctp/sctp_pg.c
   sctp/sctp_input.c
   sctp/sctp_output.c
+  sctp/sctp_output_node.c
   sctp/sctp_format.c
 )
 
+list(APPEND VNET_MULTIARCH_SOURCES
+  sctp/sctp_output_node.c
+  sctp/sctp_input.c
+)
+
 list(APPEND VNET_HEADERS
   sctp/sctp_error.def
   sctp/sctp_packet.h
index f849961..08285e4 100644 (file)
@@ -970,6 +970,12 @@ sctp_init (vlib_main_t * vm)
   sctp_main_t *tm = vnet_get_sctp_main ();
   ip_main_t *im = &ip_main;
   ip_protocol_info_t *pi;
+  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "sctp4-established");
+  tm->sctp4_established_phase_node_index = node->index;
+
+  node = vlib_get_node_by_name (vm, (u8 *) "sctp6-established");
+  tm->sctp6_established_phase_node_index = node->index;
+
   /* Session layer, and by implication SCTP, are disabled by default */
   tm->is_enabled = 0;
 
index c40de10..26e69eb 100644 (file)
@@ -530,6 +530,8 @@ typedef struct _sctp_main
   u8 punt_unknown4;
   u8 punt_unknown6;
 
+  u32 sctp4_established_phase_node_index;
+  u32 sctp6_established_phase_node_index;
 } sctp_main_t;
 
 extern sctp_main_t sctp_main;
index 0b24bf7..c41e9cc 100644 (file)
@@ -84,6 +84,7 @@ typedef enum _sctp_input_next
   SCTP_INPUT_N_NEXT
 } sctp_input_next_t;
 
+#ifndef CLIB_MARCH_VARIANT
 char *
 phase_to_string (u8 phase)
 {
@@ -104,6 +105,7 @@ phase_to_string (u8 phase)
     }
   return NULL;
 }
+#endif /* CLIB_MARCH_VARIANT */
 
 #define foreach_sctp4_input_next                 \
   _ (DROP, "error-drop")                         \
@@ -237,7 +239,7 @@ typedef struct
 #define sctp_next_drop(is_ip4) (is_ip4 ? SCTP_NEXT_DROP4                  \
                                       : SCTP_NEXT_DROP6)
 
-void
+static void
 sctp_set_rx_trace_data (sctp_rx_trace_t * rx_trace,
                        sctp_connection_t * sctp_conn,
                        sctp_header_t * sctp_hdr, vlib_buffer_t * b0,
@@ -1116,21 +1118,21 @@ sctp46_rcv_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   return from_frame->n_vectors;
 }
 
-static uword
-sctp4_rcv_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp4_rcv_phase_node) (vlib_main_t * vm,
+                                    vlib_node_runtime_t * node,
+                                    vlib_frame_t * from_frame)
 {
   return sctp46_rcv_phase_inline (vm, node, from_frame, 1 /* is_ip4 */ );
 }
 
-static uword
-sctp6_rcv_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp6_init_phase_node) (vlib_main_t * vm,
+                                     vlib_node_runtime_t * node,
+                                     vlib_frame_t * from_frame)
 {
   return sctp46_rcv_phase_inline (vm, node, from_frame, 0 /* is_ip4 */ );
 }
 
-u8 *
+static u8 *
 format_sctp_rx_trace_short (u8 * s, va_list * args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -1148,7 +1150,6 @@ format_sctp_rx_trace_short (u8 * s, va_list * args)
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp4_rcv_phase_node) =
 {
-  .function = sctp4_rcv_phase,
   .name = "sctp4-rcv",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -1165,12 +1166,9 @@ VLIB_REGISTER_NODE (sctp4_rcv_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_rcv_phase_node, sctp4_rcv_phase);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp6_init_phase_node) =
 {
-  .function = sctp6_rcv_phase,
   .name = "sctp6-rcv",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -1187,11 +1185,6 @@ VLIB_REGISTER_NODE (sctp6_init_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_init_phase_node, sctp6_rcv_phase);
-
-vlib_node_registration_t sctp4_shutdown_phase_node;
-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,
@@ -1469,16 +1462,16 @@ sctp46_shutdown_phase_inline (vlib_main_t * vm,
 
 }
 
-static uword
-sctp4_shutdown_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                     vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp4_shutdown_phase_node) (vlib_main_t * vm,
+                                         vlib_node_runtime_t * node,
+                                         vlib_frame_t * from_frame)
 {
   return sctp46_shutdown_phase_inline (vm, node, from_frame, 1 /* is_ip4 */ );
 }
 
-static uword
-sctp6_shutdown_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                     vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp6_shutdown_phase_node) (vlib_main_t * vm,
+                                         vlib_node_runtime_t * node,
+                                         vlib_frame_t * from_frame)
 {
   return sctp46_shutdown_phase_inline (vm, node, from_frame, 1 /* is_ip4 */ );
 }
@@ -1486,7 +1479,6 @@ sctp6_shutdown_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp4_shutdown_phase_node) =
 {
-  .function = sctp4_shutdown_phase,
   .name = "sctp4-shutdown",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -1503,13 +1495,9 @@ VLIB_REGISTER_NODE (sctp4_shutdown_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_shutdown_phase_node,
-                             sctp4_shutdown_phase);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp6_shutdown_phase_node) =
 {
-  .function = sctp6_shutdown_phase,
   .name = "sctp6-shutdown",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -1526,15 +1514,6 @@ VLIB_REGISTER_NODE (sctp6_shutdown_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_shutdown_phase_node,
-                             sctp6_shutdown_phase);
-
-vlib_node_registration_t sctp4_listen_phase_node;
-vlib_node_registration_t sctp6_listen_phase_node;
-
-vlib_node_registration_t sctp4_established_phase_node;
-vlib_node_registration_t sctp6_established_phase_node;
-
 always_inline u16
 sctp_handle_sack (sctp_selective_ack_chunk_t * sack_chunk,
                  sctp_connection_t * sctp_conn, u8 idx, vlib_buffer_t * b0,
@@ -1815,16 +1794,16 @@ sctp46_listen_process_inline (vlib_main_t * vm,
   return from_frame->n_vectors;
 }
 
-static uword
-sctp4_listen_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                   vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp4_listen_phase_node) (vlib_main_t * vm,
+                                       vlib_node_runtime_t * node,
+                                       vlib_frame_t * from_frame)
 {
   return sctp46_listen_process_inline (vm, node, from_frame, 1 /* is_ip4 */ );
 }
 
-static uword
-sctp6_listen_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                   vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp6_listen_phase_node) (vlib_main_t * vm,
+                                       vlib_node_runtime_t * node,
+                                       vlib_frame_t * from_frame)
 {
   return sctp46_listen_process_inline (vm, node, from_frame, 0 /* is_ip4 */ );
 }
@@ -1833,6 +1812,7 @@ always_inline uword
 sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                                 vlib_frame_t * from_frame, int is_ip4)
 {
+  sctp_main_t *sm = vnet_get_sctp_main ();
   u32 n_left_from, next_index, *from, *to_next;
   u32 my_thread_index = vm->thread_index, errors = 0;
 
@@ -1973,31 +1953,31 @@ sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   errors = session_main_flush_enqueue_events (TRANSPORT_PROTO_SCTP,
                                              my_thread_index);
 
-  sctp_node_inc_counter (vm, is_ip4, sctp4_established_phase_node.index,
-                        sctp6_established_phase_node.index,
+  sctp_node_inc_counter (vm, is_ip4, sm->sctp4_established_phase_node_index,
+                        sm->sctp6_established_phase_node_index,
                         SCTP_ERROR_EVENT_FIFO_FULL, errors);
   sctp_flush_frame_to_output (vm, my_thread_index, is_ip4);
 
   return from_frame->n_vectors;
 }
 
-static uword
-sctp4_established_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                        vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp4_established_phase_node) (vlib_main_t * vm,
+                                            vlib_node_runtime_t * node,
+                                            vlib_frame_t * from_frame)
 {
   return sctp46_established_phase_inline (vm, node, from_frame,
                                          1 /* is_ip4 */ );
 }
 
-static uword
-sctp6_established_phase (vlib_main_t * vm, vlib_node_runtime_t * node,
-                        vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp6_established_phase_node) (vlib_main_t * vm,
+                                            vlib_node_runtime_t * node,
+                                            vlib_frame_t * from_frame)
 {
   return sctp46_established_phase_inline (vm, node, from_frame,
                                          0 /* is_ip4 */ );
 }
 
-u8 *
+static u8 *
 format_sctp_rx_trace (u8 * s, va_list * args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -2016,7 +1996,6 @@ format_sctp_rx_trace (u8 * s, va_list * args)
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp4_listen_phase_node) =
 {
-  .function = sctp4_listen_phase,
   .name = "sctp4-listen",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2033,12 +2012,9 @@ VLIB_REGISTER_NODE (sctp4_listen_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_listen_phase_node, sctp4_listen_phase);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp6_listen_phase_node) =
 {
-  .function = sctp6_listen_phase,
   .name = "sctp6-listen",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2055,12 +2031,9 @@ VLIB_REGISTER_NODE (sctp6_listen_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_listen_phase_node, sctp6_listen_phase);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp4_established_phase_node) =
 {
-  .function = sctp4_established_phase,
   .name = "sctp4-established",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2077,13 +2050,9 @@ VLIB_REGISTER_NODE (sctp4_established_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_established_phase_node,
-                             sctp4_established_phase);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp6_established_phase_node) =
 {
-  .function = sctp6_established_phase,
   .name = "sctp6-established",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2100,9 +2069,6 @@ VLIB_REGISTER_NODE (sctp6_established_phase_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_established_phase_node,
-                             sctp6_established_phase);
-
 /*
  * This is the function executed first for the SCTP graph.
  * It takes care of doing the initial message parsing and
@@ -2295,16 +2261,14 @@ sctp46_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node,
   return from_frame->n_vectors;
 }
 
-static uword
-sctp4_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node,
-                       vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
+                                vlib_frame_t * from_frame)
 {
   return sctp46_input_dispatcher (vm, node, from_frame, 1 /* is_ip4 */ );
 }
 
-static uword
-sctp6_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node,
-                       vlib_frame_t * from_frame)
+VLIB_NODE_FN (sctp6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
+                                vlib_frame_t * from_frame)
 {
   return sctp46_input_dispatcher (vm, node, from_frame, 0 /* is_ip4 */ );
 }
@@ -2312,7 +2276,6 @@ sctp6_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node,
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp4_input_node) =
 {
-  .function = sctp4_input_dispatcher,
   .name = "sctp4-input",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2330,12 +2293,9 @@ VLIB_REGISTER_NODE (sctp4_input_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_input_node, sctp4_input_dispatcher);
-
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (sctp6_input_node) =
 {
-  .function = sctp6_input_dispatcher,
   .name = "sctp6-input",
   /* Takes a vector of packets. */
   .vector_size = sizeof (u32),
@@ -2353,11 +2313,7 @@ VLIB_REGISTER_NODE (sctp6_input_node) =
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_input_node, sctp6_input_dispatcher);
-
-vlib_node_registration_t sctp4_input_node;
-vlib_node_registration_t sctp6_input_node;
-
+#ifndef CLIB_MARCH_VARIANT
 static void
 sctp_dispatch_table_init (sctp_main_t * tm)
 {
@@ -2561,6 +2517,7 @@ sctp_input_init (vlib_main_t * vm)
 }
 
 VLIB_INIT_FUNCTION (sctp_input_init);
+#endif /* CLIB_MARCH_VARIANT */
 
 /*
  * fd.io coding-style-patch-verification: ON
index dbd4ef2..8863012 100644 (file)
 #include <vppinfra/random.h>
 #include <openssl/hmac.h>
 
-vlib_node_registration_t sctp4_output_node;
-vlib_node_registration_t sctp6_output_node;
-
-typedef enum _sctp_output_next
-{
-  SCTP_OUTPUT_NEXT_DROP,
-  SCTP_OUTPUT_NEXT_IP_LOOKUP,
-  SCTP_OUTPUT_N_NEXT
-} sctp_output_next_t;
-
-#define foreach_sctp4_output_next                      \
-  _ (DROP, "error-drop")                        \
-  _ (IP_LOOKUP, "ip4-lookup")
-
-#define foreach_sctp6_output_next                      \
-  _ (DROP, "error-drop")                        \
-  _ (IP_LOOKUP, "ip6-lookup")
-
-static char *sctp_error_strings[] = {
-#define sctp_error(n,s) s,
-#include <vnet/sctp/sctp_error.def>
-#undef sctp_error
-};
-
-typedef struct
-{
-  sctp_header_t sctp_header;
-  sctp_connection_t sctp_connection;
-} sctp_tx_trace_t;
-
 /**
  * Flush tx frame populated by retransmits and timer pops
  */
@@ -1586,347 +1556,6 @@ sctp_validate_output_state_machine (sctp_connection_t * sctp_conn,
 }
 #endif
 
-always_inline u8
-sctp_is_retransmitting (sctp_connection_t * sctp_conn, u8 idx)
-{
-  return sctp_conn->sub_conn[idx].is_retransmitting;
-}
-
-always_inline uword
-sctp46_output_inline (vlib_main_t * vm,
-                     vlib_node_runtime_t * node,
-                     vlib_frame_t * from_frame, int is_ip4)
-{
-  u32 n_left_from, next_index, *from, *to_next;
-  u32 my_thread_index = vm->thread_index;
-
-  from = vlib_frame_vector_args (from_frame);
-  n_left_from = from_frame->n_vectors;
-  next_index = node->cached_next_index;
-  sctp_set_time_now (my_thread_index);
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 bi0;
-         vlib_buffer_t *b0;
-         sctp_header_t *sctp_hdr = 0;
-         sctp_connection_t *sctp_conn;
-         sctp_tx_trace_t *t0;
-         sctp_header_t *th0 = 0;
-         u32 error0 = SCTP_ERROR_PKTS_SENT, next0 =
-           SCTP_OUTPUT_NEXT_IP_LOOKUP;
-
-#if SCTP_DEBUG_STATE_MACHINE
-         u16 packet_length = 0;
-#endif
-
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         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);
-
-         if (PREDICT_FALSE (sctp_conn == 0))
-           {
-             error0 = SCTP_ERROR_INVALID_CONNECTION;
-             next0 = SCTP_OUTPUT_NEXT_DROP;
-             goto done;
-           }
-
-         u8 idx = vnet_buffer (b0)->sctp.subconn_idx;
-
-         th0 = vlib_buffer_get_current (b0);
-
-         if (is_ip4)
-           {
-             ip4_header_t *iph4 = vlib_buffer_push_ip4 (vm,
-                                                        b0,
-                                                        &sctp_conn->sub_conn
-                                                        [idx].connection.
-                                                        lcl_ip.ip4,
-                                                        &sctp_conn->
-                                                        sub_conn
-                                                        [idx].connection.
-                                                        rmt_ip.ip4,
-                                                        IP_PROTOCOL_SCTP, 1);
-
-             u32 checksum = ip4_sctp_compute_checksum (vm, b0, iph4);
-
-             sctp_hdr = ip4_next_header (iph4);
-             sctp_hdr->checksum = checksum;
-
-             vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
-
-#if SCTP_DEBUG_STATE_MACHINE
-             packet_length = clib_net_to_host_u16 (iph4->length);
-#endif
-           }
-         else
-           {
-             ip6_header_t *iph6 = vlib_buffer_push_ip6 (vm,
-                                                        b0,
-                                                        &sctp_conn->sub_conn
-                                                        [idx].
-                                                        connection.lcl_ip.
-                                                        ip6,
-                                                        &sctp_conn->sub_conn
-                                                        [idx].
-                                                        connection.rmt_ip.
-                                                        ip6,
-                                                        IP_PROTOCOL_SCTP);
-
-             int bogus = ~0;
-             u32 checksum = ip6_sctp_compute_checksum (vm, b0, iph6, &bogus);
-             ASSERT (!bogus);
-
-             sctp_hdr = ip6_next_header (iph6);
-             sctp_hdr->checksum = checksum;
-
-             vnet_buffer (b0)->l3_hdr_offset = (u8 *) iph6 - b0->data;
-             vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
-
-#if SCTP_DEBUG_STATE_MACHINE
-             packet_length = clib_net_to_host_u16 (iph6->payload_length);
-#endif
-           }
-
-         sctp_full_hdr_t *full_hdr = (sctp_full_hdr_t *) sctp_hdr;
-         u8 chunk_type = vnet_sctp_get_chunk_type (&full_hdr->common_hdr);
-         if (chunk_type >= UNKNOWN)
-           {
-             clib_warning
-               ("Trying to send an unrecognized chunk... something is really bad.");
-             error0 = SCTP_ERROR_UNKNOWN_CHUNK;
-             next0 = SCTP_OUTPUT_NEXT_DROP;
-             goto done;
-           }
-
-#if SCTP_DEBUG_STATE_MACHINE
-         u8 is_valid =
-           (sctp_conn->sub_conn[idx].connection.lcl_port ==
-            sctp_hdr->src_port
-            || sctp_conn->sub_conn[idx].connection.lcl_port ==
-            sctp_hdr->dst_port)
-           && (sctp_conn->sub_conn[idx].connection.rmt_port ==
-               sctp_hdr->dst_port
-               || sctp_conn->sub_conn[idx].connection.rmt_port ==
-               sctp_hdr->src_port);
-
-         if (!is_valid)
-           {
-             SCTP_DBG_STATE_MACHINE ("BUFFER IS INCORRECT: conn_index = %u, "
-                                     "packet_length = %u, "
-                                     "chunk_type = %u [%s], "
-                                     "connection.lcl_port = %u, sctp_hdr->src_port = %u, "
-                                     "connection.rmt_port = %u, sctp_hdr->dst_port = %u",
-                                     sctp_conn->sub_conn[idx].
-                                     connection.c_index, packet_length,
-                                     chunk_type,
-                                     sctp_chunk_to_string (chunk_type),
-                                     sctp_conn->sub_conn[idx].
-                                     connection.lcl_port, sctp_hdr->src_port,
-                                     sctp_conn->sub_conn[idx].
-                                     connection.rmt_port,
-                                     sctp_hdr->dst_port);
-
-             error0 = SCTP_ERROR_UNKNOWN_CHUNK;
-             next0 = SCTP_OUTPUT_NEXT_DROP;
-             goto done;
-           }
-#endif
-         SCTP_DBG_STATE_MACHINE
-           ("SESSION_INDEX = %u, CONN_INDEX = %u, CURR_CONN_STATE = %u (%s), "
-            "CHUNK_TYPE = %s, " "SRC_PORT = %u, DST_PORT = %u",
-            sctp_conn->sub_conn[idx].connection.s_index,
-            sctp_conn->sub_conn[idx].connection.c_index,
-            sctp_conn->state, sctp_state_to_string (sctp_conn->state),
-            sctp_chunk_to_string (chunk_type), full_hdr->hdr.src_port,
-            full_hdr->hdr.dst_port);
-
-         /* Let's make sure the state-machine does not send anything crazy */
-#if SCTP_DEBUG_STATE_MACHINE
-         if (sctp_validate_output_state_machine (sctp_conn, chunk_type) != 0)
-           {
-             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_UNKNOWN_CHUNK;
-             next0 = SCTP_OUTPUT_NEXT_DROP;
-             goto done;
-
-           }
-#endif
-
-         /* Karn's algorithm: RTT measurements MUST NOT be made using
-          * packets that were retransmitted
-          */
-         if (!sctp_is_retransmitting (sctp_conn, idx))
-           {
-             /* Measure RTT with this */
-             if (chunk_type == DATA
-                 && sctp_conn->sub_conn[idx].RTO_pending == 0)
-               {
-                 sctp_conn->sub_conn[idx].RTO_pending = 1;
-                 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
-               }
-             else
-               sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
-           }
-
-         /* Let's take care of TIMERS */
-         switch (chunk_type)
-           {
-           case COOKIE_ECHO:
-             {
-               sctp_conn->state = SCTP_STATE_COOKIE_ECHOED;
-               break;
-             }
-           case DATA:
-             {
-               SCTP_ADV_DBG_OUTPUT ("PACKET_LENGTH = %u", packet_length);
-
-               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;
-             }
-           case SHUTDOWN_COMPLETE:
-             {
-               sctp_conn->state = SCTP_STATE_CLOSED;
-               break;
-             }
-           }
-
-         vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
-         vnet_buffer (b0)->sw_if_index[VLIB_TX] =
-           sctp_conn->sub_conn[idx].c_fib_index;
-
-         b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
-
-         SCTP_DBG_STATE_MACHINE
-           ("SESSION_INDEX = %u, CONNECTION_INDEX = %u, " "NEW_STATE = %s, "
-            "CHUNK_SENT = %s", sctp_conn->sub_conn[idx].connection.s_index,
-            sctp_conn->sub_conn[idx].connection.c_index,
-            sctp_state_to_string (sctp_conn->state),
-            sctp_chunk_to_string (chunk_type));
-
-         vnet_sctp_common_hdr_params_host_to_net (&full_hdr->common_hdr);
-
-       done:
-         b0->error = node->errors[error0];
-         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
-           {
-             t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
-             if (th0)
-               {
-                 clib_memcpy_fast (&t0->sctp_header, th0,
-                                   sizeof (t0->sctp_header));
-               }
-             else
-               {
-                 clib_memset (&t0->sctp_header, 0, sizeof (t0->sctp_header));
-               }
-             clib_memcpy_fast (&t0->sctp_connection, sctp_conn,
-                               sizeof (t0->sctp_connection));
-           }
-
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-
-  return from_frame->n_vectors;
-}
-
-static uword
-sctp4_output (vlib_main_t * vm, vlib_node_runtime_t * node,
-             vlib_frame_t * from_frame)
-{
-  return sctp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */ );
-}
-
-static uword
-sctp6_output (vlib_main_t * vm, vlib_node_runtime_t * node,
-             vlib_frame_t * from_frame)
-{
-  return sctp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */ );
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (sctp4_output_node) =
-{
-  .function = sctp4_output,.name = "sctp4-output",
-    /* Takes a vector of packets. */
-    .vector_size = sizeof (u32),
-    .n_errors = SCTP_N_ERROR,
-    .error_strings = sctp_error_strings,
-    .n_next_nodes = SCTP_OUTPUT_N_NEXT,
-    .next_nodes = {
-#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
-    foreach_sctp4_output_next
-#undef _
-    },
-    .format_buffer = format_sctp_header,
-    .format_trace = format_sctp_tx_trace,
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (sctp4_output_node, sctp4_output);
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (sctp6_output_node) =
-{
-  .function = sctp6_output,
-  .name = "sctp6-output",
-    /* Takes a vector of packets. */
-  .vector_size = sizeof (u32),
-  .n_errors = SCTP_N_ERROR,
-  .error_strings = sctp_error_strings,
-  .n_next_nodes = SCTP_OUTPUT_N_NEXT,
-  .next_nodes = {
-#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
-    foreach_sctp6_output_next
-#undef _
-  },
-  .format_buffer = format_sctp_header,
-  .format_trace = format_sctp_tx_trace,
-};
-/* *INDENT-ON* */
-
-VLIB_NODE_FUNCTION_MULTIARCH (sctp6_output_node, sctp6_output);
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vnet/sctp/sctp_output_node.c b/src/vnet/sctp/sctp_output_node.c
new file mode 100644 (file)
index 0000000..b36c49d
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2018 SUSE LLC.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vnet/sctp/sctp.h>
+#include <vnet/sctp/sctp_debug.h>
+#include <vppinfra/random.h>
+#include <openssl/hmac.h>
+
+u32
+ip6_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
+                          ip6_header_t * ip0, int *bogus_lengthp);
+
+u32
+ip4_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
+                          ip4_header_t * ip0);
+
+#define foreach_sctp4_output_next                      \
+  _ (DROP, "error-drop")                        \
+  _ (IP_LOOKUP, "ip4-lookup")
+
+#define foreach_sctp6_output_next                      \
+  _ (DROP, "error-drop")                        \
+  _ (IP_LOOKUP, "ip6-lookup")
+
+static char *sctp_error_strings[] = {
+#define sctp_error(n,s) s,
+#include <vnet/sctp/sctp_error.def>
+#undef sctp_error
+};
+
+typedef enum _sctp_output_next
+{
+  SCTP_OUTPUT_NEXT_DROP,
+  SCTP_OUTPUT_NEXT_IP_LOOKUP,
+  SCTP_OUTPUT_N_NEXT
+} sctp_output_next_t;
+
+typedef struct
+{
+  sctp_header_t sctp_header;
+  sctp_connection_t sctp_connection;
+} sctp_tx_trace_t;
+
+always_inline u8
+sctp_is_retransmitting (sctp_connection_t * sctp_conn, u8 idx)
+{
+  return sctp_conn->sub_conn[idx].is_retransmitting;
+}
+
+always_inline uword
+sctp46_output_inline (vlib_main_t * vm,
+                     vlib_node_runtime_t * node,
+                     vlib_frame_t * from_frame, int is_ip4)
+{
+  u32 n_left_from, next_index, *from, *to_next;
+  u32 my_thread_index = vm->thread_index;
+
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+  next_index = node->cached_next_index;
+  sctp_set_time_now (my_thread_index);
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0;
+         vlib_buffer_t *b0;
+         sctp_header_t *sctp_hdr = 0;
+         sctp_connection_t *sctp_conn;
+         sctp_tx_trace_t *t0;
+         sctp_header_t *th0 = 0;
+         u32 error0 = SCTP_ERROR_PKTS_SENT, next0 =
+           SCTP_OUTPUT_NEXT_IP_LOOKUP;
+
+#if SCTP_DEBUG_STATE_MACHINE
+         u16 packet_length = 0;
+#endif
+
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         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);
+
+         if (PREDICT_FALSE (sctp_conn == 0))
+           {
+             error0 = SCTP_ERROR_INVALID_CONNECTION;
+             next0 = SCTP_OUTPUT_NEXT_DROP;
+             goto done;
+           }
+
+         u8 idx = vnet_buffer (b0)->sctp.subconn_idx;
+
+         th0 = vlib_buffer_get_current (b0);
+
+         if (is_ip4)
+           {
+             ip4_header_t *iph4 = vlib_buffer_push_ip4 (vm,
+                                                        b0,
+                                                        &sctp_conn->sub_conn
+                                                        [idx].connection.
+                                                        lcl_ip.ip4,
+                                                        &sctp_conn->
+                                                        sub_conn
+                                                        [idx].connection.
+                                                        rmt_ip.ip4,
+                                                        IP_PROTOCOL_SCTP, 1);
+
+             u32 checksum = ip4_sctp_compute_checksum (vm, b0, iph4);
+
+             sctp_hdr = ip4_next_header (iph4);
+             sctp_hdr->checksum = checksum;
+
+             vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
+
+#if SCTP_DEBUG_STATE_MACHINE
+             packet_length = clib_net_to_host_u16 (iph4->length);
+#endif
+           }
+         else
+           {
+             ip6_header_t *iph6 = vlib_buffer_push_ip6 (vm,
+                                                        b0,
+                                                        &sctp_conn->sub_conn
+                                                        [idx].
+                                                        connection.lcl_ip.
+                                                        ip6,
+                                                        &sctp_conn->sub_conn
+                                                        [idx].
+                                                        connection.rmt_ip.
+                                                        ip6,
+                                                        IP_PROTOCOL_SCTP);
+
+             int bogus = ~0;
+             u32 checksum = ip6_sctp_compute_checksum (vm, b0, iph6, &bogus);
+             ASSERT (!bogus);
+
+             sctp_hdr = ip6_next_header (iph6);
+             sctp_hdr->checksum = checksum;
+
+             vnet_buffer (b0)->l3_hdr_offset = (u8 *) iph6 - b0->data;
+             vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
+
+#if SCTP_DEBUG_STATE_MACHINE
+             packet_length = clib_net_to_host_u16 (iph6->payload_length);
+#endif
+           }
+
+         sctp_full_hdr_t *full_hdr = (sctp_full_hdr_t *) sctp_hdr;
+         u8 chunk_type = vnet_sctp_get_chunk_type (&full_hdr->common_hdr);
+         if (chunk_type >= UNKNOWN)
+           {
+             clib_warning
+               ("Trying to send an unrecognized chunk... something is really bad.");
+             error0 = SCTP_ERROR_UNKNOWN_CHUNK;
+             next0 = SCTP_OUTPUT_NEXT_DROP;
+             goto done;
+           }
+
+#if SCTP_DEBUG_STATE_MACHINE
+         u8 is_valid =
+           (sctp_conn->sub_conn[idx].connection.lcl_port ==
+            sctp_hdr->src_port
+            || sctp_conn->sub_conn[idx].connection.lcl_port ==
+            sctp_hdr->dst_port)
+           && (sctp_conn->sub_conn[idx].connection.rmt_port ==
+               sctp_hdr->dst_port
+               || sctp_conn->sub_conn[idx].connection.rmt_port ==
+               sctp_hdr->src_port);
+
+         if (!is_valid)
+           {
+             SCTP_DBG_STATE_MACHINE ("BUFFER IS INCORRECT: conn_index = %u, "
+                                     "packet_length = %u, "
+                                     "chunk_type = %u [%s], "
+                                     "connection.lcl_port = %u, sctp_hdr->src_port = %u, "
+                                     "connection.rmt_port = %u, sctp_hdr->dst_port = %u",
+                                     sctp_conn->sub_conn[idx].
+                                     connection.c_index, packet_length,
+                                     chunk_type,
+                                     sctp_chunk_to_string (chunk_type),
+                                     sctp_conn->sub_conn[idx].
+                                     connection.lcl_port, sctp_hdr->src_port,
+                                     sctp_conn->sub_conn[idx].
+                                     connection.rmt_port,
+                                     sctp_hdr->dst_port);
+
+             error0 = SCTP_ERROR_UNKNOWN_CHUNK;
+             next0 = SCTP_OUTPUT_NEXT_DROP;
+             goto done;
+           }
+#endif
+         SCTP_DBG_STATE_MACHINE
+           ("SESSION_INDEX = %u, CONN_INDEX = %u, CURR_CONN_STATE = %u (%s), "
+            "CHUNK_TYPE = %s, " "SRC_PORT = %u, DST_PORT = %u",
+            sctp_conn->sub_conn[idx].connection.s_index,
+            sctp_conn->sub_conn[idx].connection.c_index,
+            sctp_conn->state, sctp_state_to_string (sctp_conn->state),
+            sctp_chunk_to_string (chunk_type), full_hdr->hdr.src_port,
+            full_hdr->hdr.dst_port);
+
+         /* Let's make sure the state-machine does not send anything crazy */
+#if SCTP_DEBUG_STATE_MACHINE
+         if (sctp_validate_output_state_machine (sctp_conn, chunk_type) != 0)
+           {
+             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_UNKNOWN_CHUNK;
+             next0 = SCTP_OUTPUT_NEXT_DROP;
+             goto done;
+
+           }
+#endif
+
+         /* Karn's algorithm: RTT measurements MUST NOT be made using
+          * packets that were retransmitted
+          */
+         if (!sctp_is_retransmitting (sctp_conn, idx))
+           {
+             /* Measure RTT with this */
+             if (chunk_type == DATA
+                 && sctp_conn->sub_conn[idx].RTO_pending == 0)
+               {
+                 sctp_conn->sub_conn[idx].RTO_pending = 1;
+                 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+               }
+             else
+               sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+           }
+
+         /* Let's take care of TIMERS */
+         switch (chunk_type)
+           {
+           case COOKIE_ECHO:
+             {
+               sctp_conn->state = SCTP_STATE_COOKIE_ECHOED;
+               break;
+             }
+           case DATA:
+             {
+               SCTP_ADV_DBG_OUTPUT ("PACKET_LENGTH = %u", packet_length);
+
+               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;
+             }
+           case SHUTDOWN_COMPLETE:
+             {
+               sctp_conn->state = SCTP_STATE_CLOSED;
+               break;
+             }
+           }
+
+         vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+           sctp_conn->sub_conn[idx].c_fib_index;
+
+         b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+
+         SCTP_DBG_STATE_MACHINE
+           ("SESSION_INDEX = %u, CONNECTION_INDEX = %u, " "NEW_STATE = %s, "
+            "CHUNK_SENT = %s", sctp_conn->sub_conn[idx].connection.s_index,
+            sctp_conn->sub_conn[idx].connection.c_index,
+            sctp_state_to_string (sctp_conn->state),
+            sctp_chunk_to_string (chunk_type));
+
+         vnet_sctp_common_hdr_params_host_to_net (&full_hdr->common_hdr);
+
+       done:
+         b0->error = node->errors[error0];
+         if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+           {
+             t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
+             if (th0)
+               {
+                 clib_memcpy_fast (&t0->sctp_header, th0,
+                                   sizeof (t0->sctp_header));
+               }
+             else
+               {
+                 clib_memset (&t0->sctp_header, 0, sizeof (t0->sctp_header));
+               }
+             clib_memcpy_fast (&t0->sctp_connection, sctp_conn,
+                               sizeof (t0->sctp_connection));
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  return from_frame->n_vectors;
+}
+
+VLIB_NODE_FN (sctp4_output_node) (vlib_main_t * vm,
+                                 vlib_node_runtime_t * node,
+                                 vlib_frame_t * from_frame)
+{
+  return sctp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */ );
+}
+
+VLIB_NODE_FN (sctp6_output_node) (vlib_main_t * vm,
+                                 vlib_node_runtime_t * node,
+                                 vlib_frame_t * from_frame)
+{
+  return sctp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (sctp4_output_node) =
+{
+    .name = "sctp4-output",
+    /* Takes a vector of packets. */
+    .vector_size = sizeof (u32),
+    .n_errors = SCTP_N_ERROR,
+    .error_strings = sctp_error_strings,
+    .n_next_nodes = SCTP_OUTPUT_N_NEXT,
+    .next_nodes = {
+#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
+    foreach_sctp4_output_next
+#undef _
+    },
+    .format_buffer = format_sctp_header,
+    .format_trace = format_sctp_tx_trace,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (sctp6_output_node) =
+{
+  .name = "sctp6-output",
+    /* Takes a vector of packets. */
+  .vector_size = sizeof (u32),
+  .n_errors = SCTP_N_ERROR,
+  .error_strings = sctp_error_strings,
+  .n_next_nodes = SCTP_OUTPUT_N_NEXT,
+  .next_nodes = {
+#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
+    foreach_sctp6_output_next
+#undef _
+  },
+  .format_buffer = format_sctp_header,
+  .format_trace = format_sctp_tx_trace,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */