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 <marco.varlese@suse.com>
This commit is contained in:
Marco Varlese
2018-03-01 11:19:59 +01:00
committed by Damjan Marion
parent afddd83ca1
commit 3c6a976325
8 changed files with 248 additions and 39 deletions

View File

@ -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

36
src/vnet/sctp/sctp.api Normal file
View File

@ -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];
};

View File

@ -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);
sctp_conn->next_avail_sub_conn += 1;
ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
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);
clib_memcpy (&sctp_conn->
sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip4,
&ipv4_addr->address, sizeof (ipv4_addr->address));
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[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);
clib_memcpy (&sctp_conn->
sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip6,
&ipv6_addr->address, sizeof (ipv6_addr->address));
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[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;
}

View File

@ -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)
{

114
src/vnet/sctp/sctp_api.c Normal file
View File

@ -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 <vnet/vnet.h>
#include <vlibmemory/api.h>
#include <vnet/sctp/sctp.h>
#include <vnet/vnet_msg_enum.h>
#define vl_typedefs /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_typedefs
#define vl_endianfun /* define message structures */
#include <vnet/vnet_all_api_h.h>
#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 <vnet/vnet_all_api_h.h>
#undef vl_printfun
#include <vlibapi/api_helper_macros.h>
#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 <vnet/sctp/sctp.api.h>
#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:
*/

View File

@ -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")
sctp_error (FILTERED, "Packets filtered")
sctp_error (MAX_CONNECTIONS, "Reached max supported subconnection")

View File

@ -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 */

View File

@ -68,6 +68,7 @@
#include <vnet/ip/punt.api.h>
#include <vnet/pg/pg.api.h>
#include <vnet/feature/feature.api.h>
#include <vnet/sctp/sctp.api.h>
/*
* fd.io coding-style-patch-verification: ON