diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vnet/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/vnet/sctp/sctp.c | 6 | ||||
-rw-r--r-- | src/vnet/sctp/sctp.h | 2 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_input.c | 119 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_output.c | 371 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_output_node.c | 397 |
6 files changed, 449 insertions, 452 deletions
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 4c4928a1c4e..04fd6d18809 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -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 diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c index f84996186e0..08285e42ba5 100644 --- a/src/vnet/sctp/sctp.c +++ b/src/vnet/sctp/sctp.c @@ -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; diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h index c40de10a409..26e69eb797b 100644 --- a/src/vnet/sctp/sctp.h +++ b/src/vnet/sctp/sctp.h @@ -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; diff --git a/src/vnet/sctp/sctp_input.c b/src/vnet/sctp/sctp_input.c index 0b24bf79896..c41e9ccdcae 100644 --- a/src/vnet/sctp/sctp_input.c +++ b/src/vnet/sctp/sctp_input.c @@ -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 diff --git a/src/vnet/sctp/sctp_output.c b/src/vnet/sctp/sctp_output.c index dbd4ef21918..8863012c041 100644 --- a/src/vnet/sctp/sctp_output.c +++ b/src/vnet/sctp/sctp_output.c @@ -17,36 +17,6 @@ #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 index 00000000000..b36c49d3d24 --- /dev/null +++ b/src/vnet/sctp/sctp_output_node.c @@ -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: + */ |