From 3c6a976325f32f880b7e53f50ebe86fa0e8476c9 Mon Sep 17 00:00:00 2001 From: Marco Varlese Date: Thu, 1 Mar 2018 11:19:59 +0100 Subject: [PATCH] SCTP: API to add a sub-connection This patch adds an API to add a sub-connection following a SRC/DST IP mapping as required by the RFC4960. At the same time, it changes the way the next available sub-connection is being calculated: rather than having an index in the parent connection which is prone to many issues at run-time, the next available sub-connection is being calculated by looking at the state of the set sub-connections and if marked as DOWN it means that is an available slot to be used. Change-Id: I662be6a247bfbbe8bf9aaf3f485183c07ef862fe Signed-off-by: Marco Varlese --- src/vnet.am | 6 ++- src/vnet/sctp/sctp.api | 36 ++++++++++++++ src/vnet/sctp/sctp.c | 65 +++++++++++++++--------- src/vnet/sctp/sctp.h | 32 +++++++++--- src/vnet/sctp/sctp_api.c | 114 +++++++++++++++++++++++++++++++++++++++++++ src/vnet/sctp/sctp_error.def | 5 +- src/vnet/sctp/sctp_input.c | 28 ++++++++--- src/vnet/vnet_all_api_h.h | 1 + 8 files changed, 248 insertions(+), 39 deletions(-) create mode 100644 src/vnet/sctp/sctp.api create mode 100644 src/vnet/sctp/sctp_api.c diff --git a/src/vnet.am b/src/vnet.am index 204c3c2c358..3e1bdd60165 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -542,6 +542,7 @@ API_FILES += vnet/udp/udp.api # Layer 4 protocol: sctp ######################################## libvnet_la_SOURCES += \ + vnet/sctp/sctp_api.c \ vnet/sctp/sctp.c \ vnet/sctp/sctp_pg.c \ vnet/sctp/sctp_input.c \ @@ -552,7 +553,10 @@ nobase_include_HEADERS += \ vnet/sctp/sctp_error.def \ vnet/sctp/sctp_packet.h \ vnet/sctp/sctp_timer.h \ - vnet/sctp/sctp.h + vnet/sctp/sctp.h \ + vnet/sctp/sctp.api.h + +API_FILES += vnet/sctp/sctp.api ######################################## # Tunnel protocol: gre diff --git a/src/vnet/sctp/sctp.api b/src/vnet/sctp/sctp.api new file mode 100644 index 00000000000..f2c48d664f8 --- /dev/null +++ b/src/vnet/sctp/sctp.api @@ -0,0 +1,36 @@ +/* + * 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. + */ + +option version = "1.0.0"; + +/** \brief Configure SCTP source addresses, for active-open SCTP sessions + + SCTP src/dst ports are 16 bits + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_ipv6 - 1 for ipv6, 0 for ipv4 + @param vrf_id - fib table / vrf id for local adjacencies + @param src_address - src address that SCTP will use for this sub-conn + @param dst_address - dst address that SCTP will use for this sub-conn +*/ +autoreply define sctp_add_src_dst_connection { + u32 client_index; + u32 context; + u8 is_ipv6; + u32 vrf_id; + u8 src_address[16]; + u8 dst_address[16]; + }; + diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c index 20f23f22942..b1186a62052 100644 --- a/src/vnet/sctp/sctp.c +++ b/src/vnet/sctp/sctp.c @@ -270,42 +270,62 @@ sctp_sub_connection_add (u8 thread_index) sctp_main_t *tm = vnet_get_sctp_main (); sctp_connection_t *sctp_conn = tm->connections[thread_index]; - sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn].connection.c_index = - sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.c_index; - sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn]. - connection.thread_index = thread_index; - sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn].subconn_idx = - sctp_conn->next_avail_sub_conn; + u8 subconn_idx = sctp_next_avail_subconn (sctp_conn); + + ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS); - sctp_conn->next_avail_sub_conn += 1; + sctp_conn->sub_conn[subconn_idx].connection.c_index = + sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.c_index; + sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index; + sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx; return sctp_conn; } -void -sctp_sub_connection_add_ip4 (u8 thread_index, - sctp_ipv4_addr_param_t * ipv4_addr) +u8 +sctp_sub_connection_add_ip4 (vlib_main_t * vm, + ip4_address_t * lcl_addr, + ip4_address_t * rmt_addr) { - sctp_connection_t *sctp_conn = sctp_sub_connection_add (thread_index); + sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index); + + u8 subconn_idx = sctp_next_avail_subconn (sctp_conn); + + if (subconn_idx == MAX_SCTP_CONNECTIONS) + return SCTP_ERROR_MAX_CONNECTIONS; + + clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip, + &lcl_addr, sizeof (lcl_addr)); - clib_memcpy (&sctp_conn-> - sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip4, - &ipv4_addr->address, sizeof (ipv4_addr->address)); + clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip, + &rmt_addr, sizeof (rmt_addr)); sctp_conn->forming_association_changed = 1; + + return SCTP_ERROR_NONE; } -void -sctp_sub_connection_add_ip6 (u8 thread_index, - sctp_ipv6_addr_param_t * ipv6_addr) +u8 +sctp_sub_connection_add_ip6 (vlib_main_t * vm, + ip6_address_t * lcl_addr, + ip6_address_t * rmt_addr) { - sctp_connection_t *sctp_conn = sctp_sub_connection_add (thread_index); + sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index); + + u8 subconn_idx = sctp_next_avail_subconn (sctp_conn); + + if (subconn_idx == MAX_SCTP_CONNECTIONS) + return SCTP_ERROR_MAX_CONNECTIONS; - clib_memcpy (&sctp_conn-> - sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip6, - &ipv6_addr->address, sizeof (ipv6_addr->address)); + clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip, + &lcl_addr, sizeof (lcl_addr)); + + clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip, + &rmt_addr, sizeof (rmt_addr)); sctp_conn->forming_association_changed = 1; + + return SCTP_ERROR_NONE; } sctp_connection_t * @@ -322,7 +342,6 @@ sctp_connection_new (u8 thread_index) sctp_conn - sctp_main->connections[thread_index]; sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_thread_index = thread_index; sctp_conn->local_tag = 0; - sctp_conn->next_avail_sub_conn = 1; return sctp_conn; } @@ -842,6 +861,8 @@ sctp_init (vlib_main_t * vm) transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto, FIB_PROTOCOL_IP6, sctp6_output_node.index); + sctp_api_reference (); + return 0; } diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h index 815ca172adb..487ff9e4824 100644 --- a/src/vnet/sctp/sctp.h +++ b/src/vnet/sctp/sctp.h @@ -235,8 +235,6 @@ typedef struct _sctp_connection sctp_options_t snd_opts; - u8 next_avail_sub_conn; /**< Represent the index of the next free slot in sub_conn */ - u8 forming_association_changed; /**< This is a flag indicating whether the original association has been modified during the life-span of the association itself. For instance, a new sub-connection might have been added. */ @@ -245,10 +243,17 @@ typedef struct _sctp_connection typedef void (sctp_timer_expiration_handler) (u32 conn_index, u32 timer_id); sctp_connection_t *sctp_connection_new (u8 thread_index); -void sctp_sub_connection_add_ip4 (u8 thread_index, - sctp_ipv4_addr_param_t * ipv4_addr); -void sctp_sub_connection_add_ip6 (u8 thread_index, - sctp_ipv6_addr_param_t * ipv6_addr); + +u8 +sctp_sub_connection_add_ip4 (vlib_main_t * vm, + ip4_address_t * lcl_addr, + ip4_address_t * rmt_addr); + +u8 +sctp_sub_connection_add_ip6 (vlib_main_t * vm, + ip6_address_t * lcl_addr, + ip6_address_t * rmt_addr); + void sctp_connection_close (sctp_connection_t * sctp_conn); void sctp_connection_cleanup (sctp_connection_t * sctp_conn); void sctp_connection_del (sctp_connection_t * sctp_conn); @@ -307,6 +312,8 @@ void sctp_prepare_heartbeat_ack_chunk (sctp_connection_t * sctp_conn, u8 idx, u16 sctp_check_outstanding_data_chunks (sctp_connection_t * sctp_conn); +void sctp_api_reference (void); + #define IP_PROTOCOL_SCTP 132 /** SSCTP FSM state definitions as per RFC4960. */ @@ -830,6 +837,19 @@ vlib_buffer_push_sctp (vlib_buffer_t * b, u16 sp_net, u16 dp_net, sctp_hdr_opts_len); } +always_inline u8 +sctp_next_avail_subconn (sctp_connection_t * sctp_conn) +{ + u8 i; + + for (i = 0; i < MAX_SCTP_CONNECTIONS; i++) + { + if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN) + return i; + } + return MAX_SCTP_CONNECTIONS; +} + always_inline void update_smallest_pmtu_idx (sctp_connection_t * sctp_conn) { diff --git a/src/vnet/sctp/sctp_api.c b/src/vnet/sctp/sctp_api.c new file mode 100644 index 00000000000..2c1b072228f --- /dev/null +++ b/src/vnet/sctp/sctp_api.c @@ -0,0 +1,114 @@ +/* + *------------------------------------------------------------------ + * sctp_api.c - vnet sctp-layer API + * + * 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 +#include + +#include + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +#include + +#define foreach_sctp_api_msg \ +_(SCTP_ADD_SRC_DST_CONNECTION, sctp_add_src_dst_connection) + +static void + vl_api_sctp_add_src_dst_connection_t_handler + (vl_api_sctp_add_src_dst_connection_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + vl_api_sctp_add_src_dst_connection_reply_t *rmp; + int rv; + + if (mp->is_ipv6) + rv = sctp_sub_connection_add_ip6 + (vm, + (ip6_address_t *) mp->src_address, (ip6_address_t *) mp->dst_address); + else + rv = sctp_sub_connection_add_ip4 + (vm, + (ip4_address_t *) mp->src_address, (ip4_address_t *) mp->dst_address); + + REPLY_MACRO (VL_API_SCTP_ADD_SRC_DST_CONNECTION_REPLY); +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (api_main_t * am) +{ +#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); + foreach_vl_msg_name_crc_sctp; +#undef _ +} + +static clib_error_t * +sctp_api_hookup (vlib_main_t * vm) +{ + api_main_t *am = &api_main; + +#define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_sctp_api_msg; +#undef _ + + /* + * Set up the (msg_name, crc, message-id) table + */ + setup_message_id_table (am); + + return 0; +} + +VLIB_API_INIT_FUNCTION (sctp_api_hookup); + +void +sctp_api_reference (void) +{ +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/sctp/sctp_error.def b/src/vnet/sctp/sctp_error.def index a244fac9e63..1f6e2758bb1 100644 --- a/src/vnet/sctp/sctp_error.def +++ b/src/vnet/sctp/sctp_error.def @@ -23,7 +23,7 @@ sctp_error (CREATE_EXISTS, "Connection already exists") sctp_error (INITS_RCVD, "INITs received") sctp_error (CREATE_SESSION_FAIL, "Sessions couldn't be allocated") sctp_error (NO_LISTENER, "no listener for dst port") -sctp_error (LENGTH, "inconsistent ip/tcp lengths") +sctp_error (LENGTH, "inconsistent ip/sctp lengths") sctp_error (DISPATCH, "Dispatch error") sctp_error (ACK_DUP, "Duplicate ACK") sctp_error (DATA_CHUNK_VIOLATION, "DATA chunk received in invalid state") @@ -47,4 +47,5 @@ sctp_error (EVENT_FIFO_FULL, "Events not sent for lack of event fifo space") sctp_error (UNKOWN_CHUNK, "Unrecognized / unknown chunk or chunk-state mismatch") sctp_error (BUNDLING_VIOLATION, "Bundling not allowed") sctp_error (PUNT, "Packets punted") -sctp_error (FILTERED, "Packets filtered") \ No newline at end of file +sctp_error (FILTERED, "Packets filtered") +sctp_error (MAX_CONNECTIONS, "Reached max supported subconnection") \ No newline at end of file diff --git a/src/vnet/sctp/sctp_input.c b/src/vnet/sctp/sctp_input.c index 46a2100cc07..00d0a61feff 100644 --- a/src/vnet/sctp/sctp_input.c +++ b/src/vnet/sctp/sctp_input.c @@ -399,7 +399,10 @@ sctp_handle_init (sctp_header_t * sctp_hdr, clib_memcpy (ip4_addr, &ipv4->address, sizeof (ip4_address_t)); - sctp_sub_connection_add_ip4 (vlib_get_thread_index (), ipv4); + sctp_sub_connection_add_ip4 (vlib_get_main (), + &sctp_conn->sub_conn + [MAIN_SCTP_SUB_CONN_IDX].connection. + lcl_ip.ip4, &ipv4->address); break; } @@ -410,7 +413,10 @@ sctp_handle_init (sctp_header_t * sctp_hdr, clib_memcpy (ip6_addr, &ipv6->address, sizeof (ip6_address_t)); - sctp_sub_connection_add_ip6 (vlib_get_thread_index (), ipv6); + sctp_sub_connection_add_ip6 (vlib_get_main (), + &sctp_conn->sub_conn + [MAIN_SCTP_SUB_CONN_IDX].connection. + lcl_ip.ip6, &ipv6->address); break; } @@ -528,7 +534,10 @@ sctp_handle_init_ack (sctp_header_t * sctp_hdr, sctp_ipv4_addr_param_t *ipv4 = (sctp_ipv4_addr_param_t *) opt_params_hdr; - sctp_sub_connection_add_ip4 (vlib_get_thread_index (), ipv4); + sctp_sub_connection_add_ip4 (vlib_get_main (), + &sctp_conn->sub_conn + [MAIN_SCTP_SUB_CONN_IDX].connection. + lcl_ip.ip4, &ipv4->address); break; } @@ -537,7 +546,10 @@ sctp_handle_init_ack (sctp_header_t * sctp_hdr, sctp_ipv6_addr_param_t *ipv6 = (sctp_ipv6_addr_param_t *) opt_params_hdr; - sctp_sub_connection_add_ip6 (vlib_get_thread_index (), ipv6); + sctp_sub_connection_add_ip6 (vlib_get_main (), + &sctp_conn->sub_conn + [MAIN_SCTP_SUB_CONN_IDX].connection. + lcl_ip.ip6, &ipv6->address); break; } @@ -1541,16 +1553,16 @@ sctp_handle_heartbeat_ack (sctp_hb_ack_chunk_t * sctp_hb_ack_chunk, } always_inline void -sctp_node_inc_counter (vlib_main_t * vm, u32 tcp4_node, u32 tcp6_node, +sctp_node_inc_counter (vlib_main_t * vm, u32 sctp4_node, u32 sctp6_node, u8 is_ip4, u8 evt, u8 val) { if (PREDICT_TRUE (!val)) return; if (is_ip4) - vlib_node_increment_counter (vm, tcp4_node, evt, val); + vlib_node_increment_counter (vm, sctp4_node, evt, val); else - vlib_node_increment_counter (vm, tcp6_node, evt, val); + vlib_node_increment_counter (vm, sctp6_node, evt, val); } always_inline uword @@ -2073,7 +2085,7 @@ sctp46_input_dispatcher (vlib_main_t * vm, vlib_node_runtime_t * node, n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); - vnet_buffer (b0)->tcp.flags = 0; + vnet_buffer (b0)->sctp.flags = 0; fib_index0 = vnet_buffer (b0)->ip.fib_index; /* Checksum computed by ipx_local no need to compute again */ diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h index 4ff34a3d691..dd80a09c7b2 100644 --- a/src/vnet/vnet_all_api_h.h +++ b/src/vnet/vnet_all_api_h.h @@ -68,6 +68,7 @@ #include #include #include +#include /* * fd.io coding-style-patch-verification: ON -- 2.16.6