aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Varlese <marco.varlese@suse.com>2018-03-01 11:19:59 +0100
committerDamjan Marion <dmarion.lists@gmail.com>2018-03-01 11:43:52 +0000
commit3c6a976325f32f880b7e53f50ebe86fa0e8476c9 (patch)
tree298bfe9554135f796ebcb17bd0fb586c117cf1ac
parentafddd83ca17484c0f26efbebb6ff7ebe47fd567f (diff)
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>
-rw-r--r--src/vnet.am6
-rw-r--r--src/vnet/sctp/sctp.api36
-rw-r--r--src/vnet/sctp/sctp.c65
-rw-r--r--src/vnet/sctp/sctp.h32
-rw-r--r--src/vnet/sctp/sctp_api.c114
-rw-r--r--src/vnet/sctp/sctp_error.def5
-rw-r--r--src/vnet/sctp/sctp_input.c28
-rw-r--r--src/vnet/vnet_all_api_h.h1
8 files changed, 248 insertions, 39 deletions
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 <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:
+ */
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 <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