SCTP: API to add a sub-connection 11/10911/4
authorMarco Varlese <marco.varlese@suse.com>
Thu, 1 Mar 2018 10:19:59 +0000 (11:19 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 1 Mar 2018 11:43:52 +0000 (11:43 +0000)
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>
src/vnet.am
src/vnet/sctp/sctp.api [new file with mode: 0644]
src/vnet/sctp/sctp.c
src/vnet/sctp/sctp.h
src/vnet/sctp/sctp_api.c [new file with mode: 0644]
src/vnet/sctp/sctp_error.def
src/vnet/sctp/sctp_input.c
src/vnet/vnet_all_api_h.h

index 204c3c2..3e1bdd6 100644 (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
diff --git a/src/vnet/sctp/sctp.api b/src/vnet/sctp/sctp.api
new file mode 100644 (file)
index 0000000..f2c48d6
--- /dev/null
@@ -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];
+ };
index 20f23f2..b1186a6 100644 (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);
+
+  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;
 }
 
index 815ca17..487ff9e 100644 (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)
 {
diff --git a/src/vnet/sctp/sctp_api.c b/src/vnet/sctp/sctp_api.c
new file mode 100644 (file)
index 0000000..2c1b072
--- /dev/null
@@ -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:
+ */
index a244fac..1f6e275 100644 (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")
\ 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
index 46a2100..00d0a61 100644 (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 */
index 4ff34a3..dd80a09 100644 (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