tcp: timestamp adjustment
[vpp.git] / src / vnet / sctp / sctp_output.c
index 0c865ca..3c2099a 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
  */
@@ -264,21 +234,20 @@ sctp_reuse_buffer (vlib_main_t * vm, vlib_buffer_t * b)
   vnet_buffer (b)->sctp.subconn_idx = MAX_SCTP_CONNECTIONS;
 
   /* Leave enough space for headers */
-  return vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
+  return vlib_buffer_make_headroom (b, TRANSPORT_MAX_HDRS_LEN);
 }
 
 always_inline void *
 sctp_init_buffer (vlib_main_t * vm, vlib_buffer_t * b)
 {
   ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
-  b->flags &= VLIB_BUFFER_NON_DEFAULT_FREELIST;
   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
   b->total_length_not_including_first_buffer = 0;
   vnet_buffer (b)->sctp.flags = 0;
   vnet_buffer (b)->sctp.subconn_idx = MAX_SCTP_CONNECTIONS;
   VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
   /* Leave enough space for headers */
-  return vlib_buffer_make_headroom (b, MAX_HDRS_LEN);
+  return vlib_buffer_make_headroom (b, TRANSPORT_MAX_HDRS_LEN);
 }
 
 always_inline int
@@ -584,8 +553,8 @@ sctp_prepare_cookie_echo_chunk (sctp_connection_t * sctp_conn, u8 idx,
   cookie_echo_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
   vnet_sctp_set_chunk_type (&cookie_echo_chunk->chunk_hdr, COOKIE_ECHO);
   vnet_sctp_set_chunk_length (&cookie_echo_chunk->chunk_hdr, chunk_len);
-  clib_memcpy (&(cookie_echo_chunk->cookie), &sctp_conn->cookie_param,
-              sizeof (sctp_state_cookie_param_t));
+  clib_memcpy_fast (&(cookie_echo_chunk->cookie), &sctp_conn->cookie_param,
+                   sizeof (sctp_state_cookie_param_t));
 
   vnet_buffer (b)->sctp.connection_index =
     sctp_conn->sub_conn[idx].connection.c_index;
@@ -779,7 +748,7 @@ sctp_prepare_initack_chunk_for_collision (sctp_connection_t * sctp_conn,
     clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE);
   state_cookie_param->param_hdr.length =
     clib_host_to_net_u16 (sizeof (sctp_state_cookie_param_t));
-  state_cookie_param->creation_time = clib_host_to_net_u32 (sctp_time_now ());
+  state_cookie_param->creation_time = clib_host_to_net_u64 (sctp_time_now ());
   state_cookie_param->cookie_lifespan =
     clib_host_to_net_u32 (SCTP_VALID_COOKIE_LIFE);
 
@@ -919,7 +888,7 @@ sctp_prepare_initack_chunk (sctp_connection_t * sctp_conn, u8 idx,
     clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE);
   state_cookie_param->param_hdr.length =
     clib_host_to_net_u16 (sizeof (sctp_state_cookie_param_t));
-  state_cookie_param->creation_time = clib_host_to_net_u32 (sctp_time_now ());
+  state_cookie_param->creation_time = clib_host_to_net_u64 (sctp_time_now ());
   state_cookie_param->cookie_lifespan =
     clib_host_to_net_u32 (SCTP_VALID_COOKIE_LIFE);
 
@@ -1239,7 +1208,7 @@ sctp_send_heartbeat (sctp_connection_t * sctp_conn)
   vlib_main_t *vm = vlib_get_main ();
 
   u8 i;
-  u32 now = sctp_time_now ();
+  u64 now = sctp_time_now ();
 
   for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
     {
@@ -1365,21 +1334,30 @@ static void
 sctp_push_hdr_i (sctp_connection_t * sctp_conn, vlib_buffer_t * b,
                 sctp_state_t next_state)
 {
-  u16 data_len =
-    b->current_length + b->total_length_not_including_first_buffer;
+  u16 data_len = b->current_length;
+
+  if (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
+    data_len += b->total_length_not_including_first_buffer;
+
   ASSERT (!b->total_length_not_including_first_buffer
-         || (b->flags & VLIB_BUFFER_NEXT_PRESENT));
+         || (b->flags & VLIB_BUFFER_NEXT_PRESENT)
+         || !(b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID));
 
   SCTP_ADV_DBG_OUTPUT ("b->current_length = %u, "
                       "b->current_data = %p "
                       "data_len = %u",
                       b->current_length, b->current_data, data_len);
 
+  u16 data_padding = vnet_sctp_calculate_padding (b->current_length);
+  if (data_padding > 0)
+    {
+      u8 *p_tail = vlib_buffer_put_uninit (b, data_padding);
+      clib_memset_u8 (p_tail, 0, data_padding);
+    }
+
   u16 bytes_to_add = sizeof (sctp_payload_data_chunk_t);
   u16 chunk_length = data_len + bytes_to_add - sizeof (sctp_header_t);
 
-  bytes_to_add += vnet_sctp_calculate_padding (bytes_to_add + data_len);
-
   sctp_payload_data_chunk_t *data_chunk =
     vlib_buffer_push_uninit (b, bytes_to_add);
 
@@ -1478,7 +1456,7 @@ sctp_prepare_data_retransmit (sctp_connection_t * sctp_conn,
    * Make sure we can retransmit something
    */
   available_bytes =
-    session_tx_fifo_max_dequeue (&sctp_conn->sub_conn[idx].connection);
+    transport_max_tx_dequeue (&sctp_conn->sub_conn[idx].connection);
   ASSERT (available_bytes >= offset);
   available_bytes -= offset;
   if (!available_bytes)
@@ -1501,8 +1479,8 @@ sctp_prepare_data_retransmit (sctp_connection_t * sctp_conn,
   if (PREDICT_TRUE (seg_size <= tm->bytes_per_buffer))
     {
       n_bytes =
-       stream_session_peek_bytes (&sctp_conn->sub_conn[idx].connection, data,
-                                  offset, max_deq_bytes);
+       session_tx_fifo_peek_bytes (&sctp_conn->sub_conn[idx].connection,
+                                   data, offset, max_deq_bytes);
       ASSERT (n_bytes == max_deq_bytes);
       b[0]->current_length = n_bytes;
       sctp_push_hdr_i (sctp_conn, *b, sctp_conn->state);
@@ -1518,6 +1496,8 @@ sctp_data_retransmit (sctp_connection_t * sctp_conn)
   vlib_buffer_t *b = 0;
   u32 bi, n_bytes = 0;
 
+  u8 idx = sctp_data_subconn_select (sctp_conn);
+
   SCTP_DBG_OUTPUT
     ("SCTP_CONN = %p, IDX = %u, S_INDEX = %u, C_INDEX = %u, sctp_conn->[...].LCL_PORT = %u, sctp_conn->[...].RMT_PORT = %u",
      sctp_conn, idx, sctp_conn->sub_conn[idx].connection.s_index,
@@ -1530,8 +1510,6 @@ sctp_data_retransmit (sctp_connection_t * sctp_conn)
       return;
     }
 
-  u8 idx = sctp_data_subconn_select (sctp_conn);
-
   n_bytes =
     sctp_prepare_data_retransmit (sctp_conn, idx, 0,
                                  sctp_conn->sub_conn[idx].cwnd, &b);
@@ -1581,347 +1559,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 (&t0->sctp_header, th0,
-                              sizeof (t0->sctp_header));
-               }
-             else
-               {
-                 memset (&t0->sctp_header, 0, sizeof (t0->sctp_header));
-               }
-             clib_memcpy (&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
  *