From be2251b0c5b10a3a556e75c9bfbea96df4799297 Mon Sep 17 00:00:00 2001 From: Marco Varlese Date: Wed, 7 Feb 2018 12:22:41 +0100 Subject: [PATCH] SCTP: shutdown phase This patch addresses some bugs discovered with the shutdown phase which were causing the actual chunks not to leave the output_node. While fixing the issue some minor refactoring was also performed to align the internal functions to a 'common' design. Change-Id: Ieac4f6e78cffad2e6982536f8e9f190a66f328f7 Signed-off-by: Marco Varlese --- src/vnet/sctp/sctp.h | 3 +- src/vnet/sctp/sctp_input.c | 73 ++++++++++++++++++++------------------- src/vnet/sctp/sctp_output.c | 83 ++++++++++++++++++++++++++++----------------- 3 files changed, 92 insertions(+), 67 deletions(-) diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h index 9129aa80682..60a195f47c1 100644 --- a/src/vnet/sctp/sctp.h +++ b/src/vnet/sctp/sctp.h @@ -247,7 +247,8 @@ void sctp_connection_del (sctp_connection_t * sctp_conn); u32 sctp_push_header (transport_connection_t * tconn, vlib_buffer_t * b); void sctp_send_init (sctp_connection_t * sctp_conn); void sctp_send_shutdown (sctp_connection_t * sctp_conn); -void sctp_send_shutdown_ack (sctp_connection_t * sctp_conn); +void sctp_send_shutdown_ack (sctp_connection_t * sctp_conn, + vlib_buffer_t * b); void sctp_send_shutdown_complete (sctp_connection_t * sctp_conn); void sctp_send_heartbeat (sctp_connection_t * sctp_conn); void sctp_flush_frame_to_output (vlib_main_t * vm, u8 thread_index, diff --git a/src/vnet/sctp/sctp_input.c b/src/vnet/sctp/sctp_input.c index 7d5e7555af5..8df95642ce4 100644 --- a/src/vnet/sctp/sctp_input.c +++ b/src/vnet/sctp/sctp_input.c @@ -686,11 +686,10 @@ sctp_is_connection_gapping (sctp_connection_t * sctp_conn, u32 tsn, always_inline u16 sctp_handle_data (sctp_payload_data_chunk_t * sctp_data_chunk, - sctp_connection_t * sctp_conn, vlib_buffer_t * b, + sctp_connection_t * sctp_conn, u8 idx, vlib_buffer_t * b, u16 * next0) { u32 error = 0, n_data_bytes; - u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state); u8 is_gapping = 0; /* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */ @@ -758,13 +757,11 @@ sctp_handle_data (sctp_payload_data_chunk_t * sctp_data_chunk, always_inline u16 sctp_handle_cookie_echo (sctp_header_t * sctp_hdr, sctp_chunks_common_hdr_t * sctp_chunk_hdr, - sctp_connection_t * sctp_conn, vlib_buffer_t * b0) + sctp_connection_t * sctp_conn, u8 idx, + vlib_buffer_t * b0, u16 * next0) { u32 now = sctp_time_now (); - /* Build TCB */ - u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ECHO); - sctp_cookie_echo_chunk_t *cookie_echo = (sctp_cookie_echo_chunk_t *) sctp_hdr; @@ -791,6 +788,7 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr, /* Change state */ sctp_conn->state = SCTP_STATE_ESTABLISHED; + *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4); sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT, sctp_conn->sub_conn[idx].RTO); @@ -804,12 +802,9 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr, always_inline u16 sctp_handle_cookie_ack (sctp_header_t * sctp_hdr, sctp_chunks_common_hdr_t * sctp_chunk_hdr, - sctp_connection_t * sctp_conn, vlib_buffer_t * b0) + sctp_connection_t * sctp_conn, u8 idx, + vlib_buffer_t * b0, u16 * next0) { - - /* Stop T1_COOKIE timer */ - u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ACK); - /* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */ if (sctp_conn->local_tag != sctp_hdr->verification_tag) { @@ -821,6 +816,7 @@ sctp_handle_cookie_ack (sctp_header_t * sctp_hdr, sctp_timer_reset (sctp_conn, idx, SCTP_TIMER_T1_COOKIE); /* Change state */ sctp_conn->state = SCTP_STATE_ESTABLISHED; + *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4); sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT, sctp_conn->sub_conn[idx].RTO); @@ -1090,8 +1086,9 @@ vlib_node_registration_t sctp6_shutdown_phase_node; always_inline u16 sctp_handle_shutdown (sctp_header_t * sctp_hdr, sctp_chunks_common_hdr_t * sctp_chunk_hdr, - sctp_connection_t * sctp_conn, vlib_buffer_t * b0, - u16 sctp_implied_length) + sctp_connection_t * sctp_conn, u8 idx, + vlib_buffer_t * b0, u16 sctp_implied_length, + u16 * next0) { sctp_shutdown_association_chunk_t *shutdown_chunk = (sctp_shutdown_association_chunk_t *) (sctp_hdr); @@ -1113,21 +1110,25 @@ sctp_handle_shutdown (sctp_header_t * sctp_hdr, case SCTP_STATE_ESTABLISHED: if (sctp_check_outstanding_data_chunks (sctp_conn) == 0) sctp_conn->state = SCTP_STATE_SHUTDOWN_RECEIVED; + sctp_send_shutdown_ack (sctp_conn, b0); break; case SCTP_STATE_SHUTDOWN_SENT: - sctp_send_shutdown_ack (sctp_conn); + sctp_send_shutdown_ack (sctp_conn, b0); break; } + *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4); + return SCTP_ERROR_NONE; } always_inline u16 sctp_handle_shutdown_ack (sctp_header_t * sctp_hdr, sctp_chunks_common_hdr_t * sctp_chunk_hdr, - sctp_connection_t * sctp_conn, vlib_buffer_t * b0, - u16 sctp_implied_length) + sctp_connection_t * sctp_conn, u8 idx, + vlib_buffer_t * b0, u16 sctp_implied_length, + u16 * next0) { sctp_shutdown_ack_chunk_t *shutdown_ack_chunk = (sctp_shutdown_ack_chunk_t *) (sctp_hdr); @@ -1153,14 +1154,17 @@ sctp_handle_shutdown_ack (sctp_header_t * sctp_hdr, SCTP_TIMER_T2_SHUTDOWN); sctp_send_shutdown_complete (sctp_conn); + *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4); + return SCTP_ERROR_NONE; } always_inline u16 sctp_handle_shutdown_complete (sctp_header_t * sctp_hdr, sctp_chunks_common_hdr_t * sctp_chunk_hdr, - sctp_connection_t * sctp_conn, - vlib_buffer_t * b0, u16 sctp_implied_length) + sctp_connection_t * sctp_conn, u8 idx, + vlib_buffer_t * b0, u16 sctp_implied_length, + u16 * next0) { sctp_shutdown_complete_chunk_t *shutdown_complete = (sctp_shutdown_complete_chunk_t *) (sctp_hdr); @@ -1185,6 +1189,8 @@ sctp_handle_shutdown_complete (sctp_header_t * sctp_hdr, stream_session_disconnect_notify (&sctp_conn->sub_conn [MAIN_SCTP_SUB_CONN_IDX].connection); + *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4); + return SCTP_ERROR_NONE; } @@ -1257,30 +1263,31 @@ sctp46_shutdown_phase_inline (vlib_main_t * vm, sctp_implied_length = sctp_calculate_implied_length (ip4_hdr, ip6_hdr, is_ip4); - switch (vnet_sctp_get_chunk_type (sctp_chunk_hdr)) + u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state); + + u8 chunk_type = vnet_sctp_get_chunk_type (sctp_chunk_hdr); + switch (chunk_type) { case SHUTDOWN: error0 = - sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn, b0, - sctp_implied_length); - next0 = sctp_next_output (is_ip4); + sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn, + idx, b0, sctp_implied_length, &next0); break; case SHUTDOWN_ACK: error0 = sctp_handle_shutdown_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn, - b0, sctp_implied_length); - next0 = sctp_next_output (is_ip4); + idx, b0, sctp_implied_length, + &next0); break; case SHUTDOWN_COMPLETE: error0 = sctp_handle_shutdown_complete (sctp_hdr, sctp_chunk_hdr, - sctp_conn, b0, - sctp_implied_length); + sctp_conn, idx, b0, + sctp_implied_length, &next0); sctp_connection_cleanup (sctp_conn); - next0 = sctp_next_output (is_ip4); break; /* @@ -1290,8 +1297,7 @@ sctp46_shutdown_phase_inline (vlib_main_t * vm, case DATA: error0 = sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr, - sctp_conn, b0, &next0); - next0 = sctp_next_output (is_ip4); + sctp_conn, idx, b0, &next0); break; /* All UNEXPECTED scenarios (wrong chunk received per state-machine) @@ -1761,15 +1767,13 @@ sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node, case COOKIE_ECHO: error0 = sctp_handle_cookie_echo (sctp_hdr, sctp_chunk_hdr, sctp_conn, - b0); - next0 = sctp_next_output (is_ip4); + idx, b0, &next0); break; case COOKIE_ACK: error0 = sctp_handle_cookie_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn, - b0); - next0 = sctp_next_output (is_ip4); + idx, b0, &next0); break; case SACK: @@ -1793,7 +1797,7 @@ sctp46_established_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node, case DATA: error0 = sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr, - sctp_conn, b0, &next0); + sctp_conn, idx, b0, &next0); break; /* All UNEXPECTED scenarios (wrong chunk received per state-machine) @@ -2064,7 +2068,6 @@ sctp46_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_sctp_common_hdr_params_net_to_host (sctp_chunk_hdr); u8 type = vnet_sctp_get_chunk_type (sctp_chunk_hdr); - #if SCTP_DEBUG_STATE_MACHINE u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state); #endif diff --git a/src/vnet/sctp/sctp_output.c b/src/vnet/sctp/sctp_output.c index dc78c0959ce..276d7e70213 100644 --- a/src/vnet/sctp/sctp_output.c +++ b/src/vnet/sctp/sctp_output.c @@ -751,12 +751,9 @@ sctp_prepare_initack_chunk (sctp_connection_t * sctp_conn, vlib_buffer_t * b, void sctp_prepare_shutdown_chunk (sctp_connection_t * sctp_conn, vlib_buffer_t * b) { - vlib_main_t *vm = vlib_get_main (); u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN); u16 alloc_bytes = sizeof (sctp_shutdown_association_chunk_t); - b = sctp_reuse_buffer (vm, b); - /* As per RFC 4960 the chunk_length value does NOT contemplate * the size of the first header (see sctp_header_t) and any padding */ @@ -805,8 +802,8 @@ sctp_send_shutdown (sctp_connection_t * sctp_conn) sctp_prepare_shutdown_chunk (sctp_conn, b); u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN); - sctp_enqueue_to_output (vm, b, bi, - sctp_conn->sub_conn[idx].connection.is_ip4); + sctp_enqueue_to_output_now (vm, b, bi, + sctp_conn->sub_conn[idx].connection.is_ip4); /* Measure RTT with this */ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now (); @@ -847,34 +844,21 @@ sctp_prepare_shutdown_ack_chunk (sctp_connection_t * sctp_conn, * Send SHUTDOWN_ACK */ void -sctp_send_shutdown_ack (sctp_connection_t * sctp_conn) +sctp_send_shutdown_ack (sctp_connection_t * sctp_conn, vlib_buffer_t * b) { - vlib_buffer_t *b; - u32 bi; - sctp_main_t *tm = vnet_get_sctp_main (); vlib_main_t *vm = vlib_get_main (); if (sctp_check_outstanding_data_chunks (sctp_conn) > 0) return; - if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi))) - return; + sctp_reuse_buffer (vm, b); - b = vlib_get_buffer (vm, bi); - sctp_init_buffer (vm, b); sctp_prepare_shutdown_ack_chunk (sctp_conn, b); u8 idx = sctp_pick_conn_idx_on_chunk (SHUTDOWN_ACK); - sctp_enqueue_to_output (vm, b, bi, - sctp_conn->sub_conn[idx].connection.is_ip4); /* Measure RTT with this */ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now (); - - /* Start the SCTP_TIMER_T2_SHUTDOWN timer */ - sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN, - sctp_conn->sub_conn[idx].RTO); - sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT; } /** @@ -1228,6 +1212,7 @@ sctp46_output_inline (vlib_main_t * vm, n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); + sctp_conn = sctp_connection_get (vnet_buffer (b0)->sctp.connection_index, my_thread_index); @@ -1390,6 +1375,30 @@ sctp46_output_inline (vlib_main_t * vm, /* Change state */ sctp_conn->state = SCTP_STATE_COOKIE_ECHOED; break; + case SCTP_STATE_SHUTDOWN_SENT: + if (chunk_type != SHUTDOWN_COMPLETE) + { + SCTP_DBG_STATE_MACHINE + ("Sending the wrong chunk (%s) based on state-machine status (%s)", + sctp_chunk_to_string (chunk_type), + sctp_state_to_string (sctp_conn->state)); + + error0 = SCTP_ERROR_UNKOWN_CHUNK; + next0 = SCTP_OUTPUT_NEXT_DROP; + goto done; + } + case SCTP_STATE_SHUTDOWN_RECEIVED: + if (chunk_type != SHUTDOWN_ACK) + { + SCTP_DBG_STATE_MACHINE + ("Sending the wrong chunk (%s) based on state-machine status (%s)", + sctp_chunk_to_string (chunk_type), + sctp_state_to_string (sctp_conn->state)); + + error0 = SCTP_ERROR_UNKOWN_CHUNK; + next0 = SCTP_OUTPUT_NEXT_DROP; + goto done; + } default: SCTP_DBG_STATE_MACHINE ("Sending chunk (%s) based on state-machine status (%s)", @@ -1398,18 +1407,30 @@ sctp46_output_inline (vlib_main_t * vm, break; } - if (chunk_type == SHUTDOWN) + switch (chunk_type) { - /* Start the SCTP_TIMER_T2_SHUTDOWN timer */ - sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN, - sctp_conn->sub_conn[idx].RTO); - sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT; - } - - if (chunk_type == DATA) - { - sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX, - sctp_conn->sub_conn[idx].RTO); + case DATA: + { + sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX, + sctp_conn->sub_conn[idx].RTO); + break; + } + case SHUTDOWN: + { + /* Start the SCTP_TIMER_T2_SHUTDOWN timer */ + sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN, + sctp_conn->sub_conn[idx].RTO); + sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT; + break; + } + case SHUTDOWN_ACK: + { + /* Start the SCTP_TIMER_T2_SHUTDOWN timer */ + sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN, + sctp_conn->sub_conn[idx].RTO); + sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT; + break; + } } vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; -- 2.16.6