blob: 41548bc0d7ab1fdb0f76b53f28a4b781cc82e4e5 [file] [log] [blame]
Marco Varlese191a5942017-10-30 18:17:21 +01001/*
2 * Copyright (c) 2017 SUSE LLC.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <vnet/sctp/sctp.h>
16#include <vnet/sctp/sctp_debug.h>
17
18sctp_main_t sctp_main;
19
20static u32
21sctp_connection_bind (u32 session_index, transport_endpoint_t * tep)
22{
23 sctp_main_t *tm = &sctp_main;
24 sctp_connection_t *listener;
25 void *iface_ip;
26
27 pool_get (tm->listener_pool, listener);
Dave Barachb7b92992018-10-17 10:38:51 -040028 clib_memset (listener, 0, sizeof (*listener));
Marco Varlese191a5942017-10-30 18:17:21 +010029
Marco Varlesec7fe4f32018-03-05 15:12:29 +010030 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
31 SCTP_PRIMARY_PATH_IDX;
32 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
Marco Varlese191a5942017-10-30 18:17:21 +010033 listener - tm->listener_pool;
Marco Varlesec7fe4f32018-03-05 15:12:29 +010034 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_port = tep->port;
Marco Varlese191a5942017-10-30 18:17:21 +010035
36 /* If we are provided a sw_if_index, bind using one of its IPs */
37 if (ip_is_zero (&tep->ip, 1) && tep->sw_if_index != ENDPOINT_INVALID_INDEX)
38 {
39 if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
40 tep->is_ip4)))
41 ip_set (&tep->ip, iface_ip, tep->is_ip4);
42 }
Marco Varlesec7fe4f32018-03-05 15:12:29 +010043 ip_copy (&listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_ip,
Marco Varlese191a5942017-10-30 18:17:21 +010044 &tep->ip, tep->is_ip4);
45
Ole Troand7231612018-06-07 10:17:57 +020046 u32 mtu = tep->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
47 tep->sw_if_index,
48 VNET_MTU_IP4) :
49 vnet_sw_interface_get_mtu (vnet_get_main (), tep->sw_if_index,
50 VNET_MTU_IP6);
51 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].PMTU = mtu;
Marco Varlesec7fe4f32018-03-05 15:12:29 +010052 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.is_ip4 = tep->is_ip4;
53 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.proto =
Marco Varlese191a5942017-10-30 18:17:21 +010054 TRANSPORT_PROTO_SCTP;
Marco Varlesec7fe4f32018-03-05 15:12:29 +010055 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_s_index = session_index;
56 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.fib_index =
Marco Varlese191a5942017-10-30 18:17:21 +010057 tep->fib_index;
58 listener->state = SCTP_STATE_CLOSED;
59
60 sctp_connection_timers_init (listener);
61
Marco Varlesec7fe4f32018-03-05 15:12:29 +010062 return listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index;
Marco Varlese191a5942017-10-30 18:17:21 +010063}
64
65u32
66sctp_session_bind (u32 session_index, transport_endpoint_t * tep)
67{
68 return sctp_connection_bind (session_index, tep);
69}
70
71static void
72sctp_connection_unbind (u32 listener_index)
73{
74 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010075 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +010076
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010077 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
Marco Varlese191a5942017-10-30 18:17:21 +010078
79 /* Poison the entry */
80 if (CLIB_DEBUG > 0)
Dave Barachb7b92992018-10-17 10:38:51 -040081 clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
Marco Varlese191a5942017-10-30 18:17:21 +010082
83 pool_put_index (tm->listener_pool, listener_index);
84}
85
86u32
87sctp_session_unbind (u32 listener_index)
88{
89 sctp_connection_unbind (listener_index);
90 return 0;
91}
92
93void
94sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
95{
96 sctp_main_t *tm = &sctp_main;
97 if (is_ip4)
98 tm->punt_unknown4 = is_add;
99 else
100 tm->punt_unknown6 = is_add;
101}
102
103static int
104sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
105 u16 * lcl_port, u8 is_ip4)
106{
107 int index, port;
108 if (is_ip4)
109 {
110 index = tm->last_v4_address_rotor++;
111 if (tm->last_v4_address_rotor >= vec_len (tm->ip4_src_addresses))
112 tm->last_v4_address_rotor = 0;
113 lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
114 }
115 else
116 {
117 index = tm->last_v6_address_rotor++;
118 if (tm->last_v6_address_rotor >= vec_len (tm->ip6_src_addresses))
119 tm->last_v6_address_rotor = 0;
120 clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
121 sizeof (ip6_address_t));
122 }
123 port = transport_alloc_local_port (TRANSPORT_PROTO_SCTP, lcl_addr);
124 if (port < 1)
125 {
126 clib_warning ("Failed to allocate src port");
127 return -1;
128 }
129 *lcl_port = port;
130 return 0;
131}
132
133/**
134 * Initialize all connection timers as invalid
135 */
136void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100137sctp_connection_timers_init (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100138{
139 int i, j;
140
141 /* Set all to invalid */
142 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100143 {
144 sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
Marco Varlese21c8baf2018-02-02 17:17:51 +0100145
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100146 for (j = 0; j < SCTP_N_TIMERS; j++)
147 {
148 sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
149 }
150 }
Marco Varlese191a5942017-10-30 18:17:21 +0100151}
152
153/**
154 * Stop all connection timers
155 */
156void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100157sctp_connection_timers_reset (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100158{
159 int i, j;
160 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
161 {
162 for (j = 0; j < SCTP_N_TIMERS; j++)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100163 sctp_timer_reset (sctp_conn, i, j);
Marco Varlese191a5942017-10-30 18:17:21 +0100164 }
165}
166
167const char *sctp_fsm_states[] = {
168#define _(sym, str) str,
169 foreach_sctp_fsm_state
170#undef _
171};
172
173u8 *
174format_sctp_state (u8 * s, va_list * args)
175{
176 u32 state = va_arg (*args, u32);
177
178 if (state < SCTP_N_STATES)
179 s = format (s, "%s", sctp_fsm_states[state]);
180 else
181 s = format (s, "UNKNOWN (%d (0x%x))", state, state);
182 return s;
183}
184
185u8 *
186format_sctp_connection_id (u8 * s, va_list * args)
187{
Marco Varlesef3ab4892018-02-19 15:23:13 +0100188 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
189 if (!sctp_conn)
190 return s;
191
192 u8 i;
193 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
194 {
195 if (sctp_conn->sub_conn[i].connection.is_ip4)
196 {
197 s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
198 s,
199 sctp_conn->sub_conn[i].connection.thread_index,
200 "T",
201 format_ip4_address,
202 &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
203 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
204 connection.lcl_port),
205 format_ip4_address,
206 &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
207 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
208 connection.rmt_port));
209 }
210 else
211 {
212 s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
213 s,
214 sctp_conn->sub_conn[i].connection.thread_index,
215 "T",
216 format_ip6_address,
217 &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
218 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
219 connection.lcl_port),
220 format_ip6_address,
221 &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
222 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
223 connection.rmt_port));
224 }
225 }
Marco Varlese191a5942017-10-30 18:17:21 +0100226 return s;
227}
228
229u8 *
230format_sctp_connection (u8 * s, va_list * args)
231{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100232 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
Marco Varlese191a5942017-10-30 18:17:21 +0100233 u32 verbose = va_arg (*args, u32);
234
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100235 if (!sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100236 return s;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100237 s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100238 if (verbose)
239 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100240 s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
Marco Varlese191a5942017-10-30 18:17:21 +0100241 }
242
243 return s;
244}
245
246/**
247 * Initialize connection send variables.
248 */
249void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100250sctp_init_snd_vars (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100251{
252 u32 time_now;
Marco Varlese191a5942017-10-30 18:17:21 +0100253 /*
254 * We use the time to randomize iss and for setting up the initial
255 * timestamp. Make sure it's updated otherwise syn and ack in the
256 * handshake may make it look as if time has flown in the opposite
257 * direction for us.
258 */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100259
Marco Varlese191a5942017-10-30 18:17:21 +0100260 sctp_set_time_now (vlib_get_thread_index ());
261 time_now = sctp_time_now ();
262
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100263 sctp_conn->local_initial_tsn = random_u32 (&time_now);
Marco Varlesef3ab4892018-02-19 15:23:13 +0100264 sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
265 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
266
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100267 sctp_conn->remote_initial_tsn = 0x0;
268 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
Marco Varlese191a5942017-10-30 18:17:21 +0100269}
270
271always_inline sctp_connection_t *
272sctp_sub_connection_add (u8 thread_index)
273{
274 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100275 sctp_connection_t *sctp_conn = tm->connections[thread_index];
Marco Varlese191a5942017-10-30 18:17:21 +0100276
Marco Varlese3c6a9762018-03-01 11:19:59 +0100277 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100278
Marco Varlese3c6a9762018-03-01 11:19:59 +0100279 ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
280
281 sctp_conn->sub_conn[subconn_idx].connection.c_index =
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100282 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index;
Marco Varlese3c6a9762018-03-01 11:19:59 +0100283 sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
284 sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
Marco Varlese191a5942017-10-30 18:17:21 +0100285
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100286 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100287}
288
Marco Varlese3c6a9762018-03-01 11:19:59 +0100289u8
290sctp_sub_connection_add_ip4 (vlib_main_t * vm,
291 ip4_address_t * lcl_addr,
292 ip4_address_t * rmt_addr)
Marco Varlese191a5942017-10-30 18:17:21 +0100293{
Marco Varlese3c6a9762018-03-01 11:19:59 +0100294 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100295
Marco Varlese3c6a9762018-03-01 11:19:59 +0100296 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
297
298 if (subconn_idx == MAX_SCTP_CONNECTIONS)
299 return SCTP_ERROR_MAX_CONNECTIONS;
300
301 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
302 &lcl_addr, sizeof (lcl_addr));
303
304 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
305 &rmt_addr, sizeof (rmt_addr));
Marco Varleseeacf3cf2018-02-26 14:52:25 +0100306
307 sctp_conn->forming_association_changed = 1;
Marco Varlese3c6a9762018-03-01 11:19:59 +0100308
309 return SCTP_ERROR_NONE;
Marco Varlese191a5942017-10-30 18:17:21 +0100310}
311
Marco Varlese3c6a9762018-03-01 11:19:59 +0100312u8
Marco Varlese465c0872018-03-01 14:01:46 +0100313sctp_sub_connection_del_ip4 (ip4_address_t * lcl_addr,
314 ip4_address_t * rmt_addr)
315{
316 sctp_main_t *sctp_main = vnet_get_sctp_main ();
317
318 u32 thread_idx = vlib_get_thread_index ();
319 u8 i;
320
321 ASSERT (thread_idx == 0);
322
323 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
324 {
325 sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
326 sctp_sub_connection_t *sub_conn =
327 &sctp_main->connections[thread_idx]->sub_conn[i];
328 ip46_address_t *lcl_ip =
329 &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
330 ip46_address_t *rmt_ip =
331 &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
332
333 if (!sub_conn->connection.is_ip4)
334 continue;
335 if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
336 rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
337 {
338 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
339 sctp_conn->forming_association_changed = 1;
340 break;
341 }
342 }
343 return SCTP_ERROR_NONE;
344}
345
346u8
Marco Varlese3c6a9762018-03-01 11:19:59 +0100347sctp_sub_connection_add_ip6 (vlib_main_t * vm,
348 ip6_address_t * lcl_addr,
349 ip6_address_t * rmt_addr)
Marco Varlese191a5942017-10-30 18:17:21 +0100350{
Marco Varlese3c6a9762018-03-01 11:19:59 +0100351 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100352
Marco Varlese3c6a9762018-03-01 11:19:59 +0100353 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
354
355 if (subconn_idx == MAX_SCTP_CONNECTIONS)
356 return SCTP_ERROR_MAX_CONNECTIONS;
357
358 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
359 &lcl_addr, sizeof (lcl_addr));
360
361 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
362 &rmt_addr, sizeof (rmt_addr));
Marco Varleseeacf3cf2018-02-26 14:52:25 +0100363
364 sctp_conn->forming_association_changed = 1;
Marco Varlese3c6a9762018-03-01 11:19:59 +0100365
366 return SCTP_ERROR_NONE;
Marco Varlese191a5942017-10-30 18:17:21 +0100367}
368
Marco Varlese465c0872018-03-01 14:01:46 +0100369u8
370sctp_sub_connection_del_ip6 (ip6_address_t * lcl_addr,
371 ip6_address_t * rmt_addr)
372{
373 sctp_main_t *sctp_main = vnet_get_sctp_main ();
374
375 u32 thread_idx = vlib_get_thread_index ();
376 u8 i;
377
378 ASSERT (thread_idx == 0);
379
380 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
381 {
382 sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
383 sctp_sub_connection_t *sub_conn =
384 &sctp_main->connections[thread_idx]->sub_conn[i];
385 ip46_address_t *lcl_ip =
386 &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
387 ip46_address_t *rmt_ip =
388 &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
389
390 if (!sub_conn->connection.is_ip4)
391 continue;
392 if ((lcl_ip->ip6.as_u64[0] == lcl_addr->as_u64[0]
393 && lcl_ip->ip6.as_u64[1] == lcl_addr->as_u64[1])
394 && (rmt_ip->ip6.as_u64[0] == rmt_addr->as_u64[0]
395 && rmt_ip->ip6.as_u64[1] == rmt_addr->as_u64[1]))
396 {
397 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
398 sctp_conn->forming_association_changed = 1;
399 break;
400 }
401 }
402 return SCTP_ERROR_NONE;
403}
404
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100405u8
406sctp_configure (sctp_user_configuration_t config)
407{
408 sctp_main_t *sctp_main = vnet_get_sctp_main ();
409
410 u32 thread_idx = vlib_get_thread_index ();
411
412 sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
413 config.never_delay_sack;
414 sctp_main->connections[thread_idx]->conn_config.never_bundle =
415 config.never_bundle;
416
417 return 0;
418}
419
Marco Varlese191a5942017-10-30 18:17:21 +0100420sctp_connection_t *
421sctp_connection_new (u8 thread_index)
422{
Marco Varlese15cc6a82018-02-21 12:39:52 +0100423 sctp_main_t *sctp_main = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100424 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100425
Marco Varlese15cc6a82018-02-21 12:39:52 +0100426 pool_get (sctp_main->connections[thread_index], sctp_conn);
Dave Barachb7b92992018-10-17 10:38:51 -0400427 clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100428 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
429 SCTP_PRIMARY_PATH_IDX;
430 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
Marco Varlese15cc6a82018-02-21 12:39:52 +0100431 sctp_conn - sctp_main->connections[thread_index];
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100432 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_thread_index = thread_index;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100433 sctp_conn->local_tag = 0;
Marco Varlese191a5942017-10-30 18:17:21 +0100434
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100435 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100436}
437
438sctp_connection_t *
439sctp_half_open_connection_new (u8 thread_index)
440{
441 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100442 sctp_connection_t *sctp_conn = 0;
Marco Varlese191a5942017-10-30 18:17:21 +0100443 ASSERT (vlib_get_thread_index () == 0);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100444 pool_get (tm->half_open_connections, sctp_conn);
Dave Barachb7b92992018-10-17 10:38:51 -0400445 clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100446 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100447 sctp_conn - tm->half_open_connections;
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100448 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
449 SCTP_PRIMARY_PATH_IDX;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100450 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100451}
452
453static inline int
Florin Coras5665ced2018-10-25 18:03:45 -0700454sctp_connection_open (transport_endpoint_cfg_t * rmt)
Marco Varlese191a5942017-10-30 18:17:21 +0100455{
456 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100457 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100458 ip46_address_t lcl_addr;
459 u16 lcl_port;
460 uword thread_id;
461 int rv;
462
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100463 u8 idx = SCTP_PRIMARY_PATH_IDX;
Marco Varlese191a5942017-10-30 18:17:21 +0100464
465 /*
466 * Allocate local endpoint
467 */
468 if ((rmt->is_ip4 && vec_len (tm->ip4_src_addresses))
469 || (!rmt->is_ip4 && vec_len (tm->ip6_src_addresses)))
470 rv = sctp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
471 rmt->is_ip4);
472 else
473 rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_SCTP,
474 rmt, &lcl_addr, &lcl_port);
475
476 if (rv)
477 return -1;
478
479 /*
480 * Create connection and send INIT CHUNK
481 */
482 thread_id = vlib_get_thread_index ();
483 ASSERT (thread_id == 0);
484
485 clib_spinlock_lock_if_init (&tm->half_open_lock);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100486 sctp_conn = sctp_half_open_connection_new (thread_id);
Ole Troand7231612018-06-07 10:17:57 +0200487 u32 mtu = rmt->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
Florin Coras5665ced2018-10-25 18:03:45 -0700488 rmt->peer.sw_if_index,
Ole Troand7231612018-06-07 10:17:57 +0200489 VNET_MTU_IP4) :
Florin Coras5665ced2018-10-25 18:03:45 -0700490 vnet_sw_interface_get_mtu (vnet_get_main (), rmt->peer.sw_if_index,
Ole Troand7231612018-06-07 10:17:57 +0200491 VNET_MTU_IP6);
492 sctp_conn->sub_conn[idx].PMTU = mtu;
Marco Varlese191a5942017-10-30 18:17:21 +0100493
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100494 transport_connection_t *trans_conn = &sctp_conn->sub_conn[idx].connection;
495 ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
496 ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
Marco Varlese04e5d642018-02-23 17:43:06 +0100497 sctp_conn->sub_conn[idx].subconn_idx = idx;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100498 trans_conn->rmt_port = rmt->port;
499 trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
500 trans_conn->is_ip4 = rmt->is_ip4;
501 trans_conn->proto = TRANSPORT_PROTO_SCTP;
502 trans_conn->fib_index = rmt->fib_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100503
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100504 sctp_connection_timers_init (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100505 /* The other connection vars will be initialized after INIT_ACK chunk received */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100506 sctp_init_snd_vars (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100507
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100508 sctp_send_init (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100509
510 clib_spinlock_unlock_if_init (&tm->half_open_lock);
511
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100512 return sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100513}
514
515/**
516 * Cleans up connection state.
517 *
518 * No notifications.
519 */
520void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100521sctp_connection_cleanup (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100522{
523 sctp_main_t *tm = &sctp_main;
524 u8 i;
525
526 /* Cleanup local endpoint if this was an active connect */
527 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
528 transport_endpoint_cleanup (TRANSPORT_PROTO_SCTP,
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100529 &sctp_conn->sub_conn[i].connection.lcl_ip,
530 sctp_conn->sub_conn[i].connection.lcl_port);
Marco Varlese191a5942017-10-30 18:17:21 +0100531
Marco Varlese200fa322018-02-26 16:33:54 +0100532 int thread_index =
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100533 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.thread_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100534
Marco Varlese200fa322018-02-26 16:33:54 +0100535 /* Make sure all timers are cleared */
536 sctp_connection_timers_reset (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100537
Marco Varlese200fa322018-02-26 16:33:54 +0100538 /* Poison the entry */
539 if (CLIB_DEBUG > 0)
Dave Barachb7b92992018-10-17 10:38:51 -0400540 clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
Marco Varlese200fa322018-02-26 16:33:54 +0100541 pool_put (tm->connections[thread_index], sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100542}
543
544int
Florin Coras5665ced2018-10-25 18:03:45 -0700545sctp_session_open (transport_endpoint_cfg_t * tep)
Marco Varlese191a5942017-10-30 18:17:21 +0100546{
547 return sctp_connection_open (tep);
548}
549
550u16
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100551sctp_check_outstanding_data_chunks (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100552{
Marco Varlese54432f82018-02-15 17:01:56 +0100553 u8 i;
554 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
555 {
556 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
557 continue;
558
559 if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
560 sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
561 {
562 SCTP_DBG_OUTPUT
Marco Varlesef3ab4892018-02-19 15:23:13 +0100563 ("Connection %u has still DATA to be enqueued inboud / outboud",
564 sctp_conn->sub_conn[i].connection.c_index);
Marco Varlese54432f82018-02-15 17:01:56 +0100565 return 1;
566 }
567
568 }
Marco Varlese191a5942017-10-30 18:17:21 +0100569 return 0; /* Indicates no more data to be read/sent */
570}
571
572void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100573sctp_connection_close (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100574{
575 SCTP_DBG ("Closing connection %u...",
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100576 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100577
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100578 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
Marco Varlese191a5942017-10-30 18:17:21 +0100579
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100580 sctp_send_shutdown (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100581}
582
583void
584sctp_session_close (u32 conn_index, u32 thread_index)
585{
586 ASSERT (thread_index == 0);
Marco Varlesef3ab4892018-02-19 15:23:13 +0100587
Marco Varlese15cc6a82018-02-21 12:39:52 +0100588 sctp_connection_t *sctp_conn =
589 sctp_connection_get (conn_index, thread_index);
Marco Varlesea38783e2018-02-13 12:38:52 +0100590 if (sctp_conn != NULL)
591 sctp_connection_close (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100592}
593
594void
595sctp_session_cleanup (u32 conn_index, u32 thread_index)
596{
Marco Varlese15cc6a82018-02-21 12:39:52 +0100597 sctp_connection_t *sctp_conn =
598 sctp_connection_get (conn_index, thread_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100599
Marco Varlesea38783e2018-02-13 12:38:52 +0100600 if (sctp_conn != NULL)
601 {
602 sctp_connection_timers_reset (sctp_conn);
603 /* Wait for the session tx events to clear */
604 sctp_conn->state = SCTP_STATE_CLOSED;
605 }
Marco Varlese191a5942017-10-30 18:17:21 +0100606}
607
608/**
Marco Varlesef3ab4892018-02-19 15:23:13 +0100609 * Compute maximum segment size for session layer.
Marco Varlese191a5942017-10-30 18:17:21 +0100610 */
Marco Varlese191a5942017-10-30 18:17:21 +0100611u16
612sctp_session_send_mss (transport_connection_t * trans_conn)
613{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100614 sctp_connection_t *sctp_conn =
615 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100616
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100617 if (sctp_conn == NULL)
Marco Varlese191a5942017-10-30 18:17:21 +0100618 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100619 SCTP_DBG ("sctp_conn == NULL");
Marco Varlese191a5942017-10-30 18:17:21 +0100620 return 0;
621 }
Marco Varlese191a5942017-10-30 18:17:21 +0100622
Marco Varlesef3ab4892018-02-19 15:23:13 +0100623 update_cwnd (sctp_conn);
624 update_smallest_pmtu_idx (sctp_conn);
625
Marco Varlese6e4d4a32018-03-12 12:36:59 +0100626 u8 idx = sctp_data_subconn_select (sctp_conn);
Marco Varlese6e4d4a32018-03-12 12:36:59 +0100627 return sctp_conn->sub_conn[idx].cwnd;
Marco Varlese191a5942017-10-30 18:17:21 +0100628}
629
630u16
631sctp_snd_space (sctp_connection_t * sctp_conn)
632{
Marco Varlese6e4d4a32018-03-12 12:36:59 +0100633 /* RFC 4096 Section 6.1; point (A) */
634 if (sctp_conn->peer_rwnd == 0)
635 return 0;
636
637 u8 idx = sctp_data_subconn_select (sctp_conn);
Marco Varlese3e9b4652018-03-13 15:44:56 +0100638
639 u32 available_wnd =
640 clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
641 int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
642
643 if (available_wnd <= flight_size)
644 return 0;
645
Marco Varlesef3ab4892018-02-19 15:23:13 +0100646 /* Finally, let's subtract the DATA chunk headers overhead */
Marco Varlese3e9b4652018-03-13 15:44:56 +0100647 return available_wnd -
648 flight_size -
Marco Varlesef3ab4892018-02-19 15:23:13 +0100649 sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
Marco Varlese191a5942017-10-30 18:17:21 +0100650}
651
Marco Varlesef3ab4892018-02-19 15:23:13 +0100652/**
653 * Compute TX window session is allowed to fill.
654 */
Marco Varlese191a5942017-10-30 18:17:21 +0100655u32
656sctp_session_send_space (transport_connection_t * trans_conn)
657{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100658 sctp_connection_t *sctp_conn =
659 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100660
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100661 return sctp_snd_space (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100662}
663
664transport_connection_t *
665sctp_session_get_transport (u32 conn_index, u32 thread_index)
666{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100667 sctp_connection_t *sctp_conn =
668 sctp_connection_get (conn_index, thread_index);
Marco Varlese2802bd72018-02-15 13:45:39 +0100669
670 if (PREDICT_TRUE (sctp_conn != NULL))
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100671 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese2802bd72018-02-15 13:45:39 +0100672
673 return NULL;
Marco Varlese191a5942017-10-30 18:17:21 +0100674}
675
676transport_connection_t *
677sctp_session_get_listener (u32 listener_index)
678{
679 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100680 sctp_connection_t *sctp_conn;
681 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100682 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100683}
684
685u8 *
686format_sctp_session (u8 * s, va_list * args)
687{
Marco Varlesef3ab4892018-02-19 15:23:13 +0100688 u32 tci = va_arg (*args, u32);
689 u32 thread_index = va_arg (*args, u32);
690 u32 verbose = va_arg (*args, u32);
691 sctp_connection_t *tc;
692
693 tc = sctp_connection_get (tci, thread_index);
694 if (tc)
695 s = format (s, "%U", format_sctp_connection, tc, verbose);
696 else
697 s = format (s, "empty\n");
698 return s;
Marco Varlese191a5942017-10-30 18:17:21 +0100699}
700
701u8 *
702format_sctp_listener_session (u8 * s, va_list * args)
703{
Marco Varlesef3ab4892018-02-19 15:23:13 +0100704 u32 tci = va_arg (*args, u32);
705 sctp_connection_t *tc = sctp_listener_get (tci);
706 return format (s, "%U", format_sctp_connection_id, tc);
Marco Varlese191a5942017-10-30 18:17:21 +0100707}
708
709void
Marco Varlesef47276f2018-02-06 09:01:39 +0100710sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
Marco Varlese191a5942017-10-30 18:17:21 +0100711{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100712 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100713
Marco Varlese93826732018-09-27 16:43:57 +0200714 SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
715
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100716 sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
Marco Varlese191a5942017-10-30 18:17:21 +0100717 /* note: the connection may have already disappeared */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100718 if (PREDICT_FALSE (sctp_conn == 0))
Marco Varlese191a5942017-10-30 18:17:21 +0100719 return;
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100720
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100721 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
Marco Varlese54432f82018-02-15 17:01:56 +0100722 SCTP_PATH_MAX_RETRANS)
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100723 {
724 // The remote-peer is considered to be unreachable hence shutting down
Marco Varlese54432f82018-02-15 17:01:56 +0100725 u8 i, total_subs_down = 1;
726 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
727 {
728 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
729 continue;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100730
Marco Varlese54432f82018-02-15 17:01:56 +0100731 u32 now = sctp_time_now ();
732 if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
733 {
734 total_subs_down += 1;
735 sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
736 }
737 }
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100738
Marco Varlese54432f82018-02-15 17:01:56 +0100739 if (total_subs_down == MAX_SCTP_CONNECTIONS)
740 {
741 /* Start cleanup. App wasn't notified yet so use delete notify as
742 * opposed to delete to cleanup session layer state. */
743 stream_session_delete_notify (&sctp_conn->sub_conn
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100744 [SCTP_PRIMARY_PATH_IDX].connection);
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100745
Marco Varlese54432f82018-02-15 17:01:56 +0100746 sctp_connection_timers_reset (sctp_conn);
747
748 sctp_connection_cleanup (sctp_conn);
749 }
Marco Varlese9e09ff32018-03-05 12:31:45 +0100750 return;
751 }
752
753 switch (timer_id)
754 {
755 case SCTP_TIMER_T1_INIT:
756 sctp_send_init (sctp_conn);
757 break;
758 case SCTP_TIMER_T1_COOKIE:
759 sctp_send_cookie_echo (sctp_conn);
760 break;
761 case SCTP_TIMER_T2_SHUTDOWN:
762 sctp_send_shutdown (sctp_conn);
763 break;
764 case SCTP_TIMER_T3_RXTX:
765 sctp_timer_reset (sctp_conn, conn_index, timer_id);
Marco Varlese3e9b4652018-03-13 15:44:56 +0100766 sctp_conn->flags |= SCTP_CONN_RECOVERY;
Marco Varlese9e09ff32018-03-05 12:31:45 +0100767 sctp_data_retransmit (sctp_conn);
768 break;
769 case SCTP_TIMER_T4_HEARTBEAT:
770 sctp_timer_reset (sctp_conn, conn_index, timer_id);
771 goto heartbeat;
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100772 }
773 return;
774
775heartbeat:
776 sctp_send_heartbeat (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100777}
778
Marco Varlese191a5942017-10-30 18:17:21 +0100779static void
780sctp_expired_timers_dispatch (u32 * expired_timers)
781{
782 int i;
783 u32 connection_index, timer_id;
784
785 for (i = 0; i < vec_len (expired_timers); i++)
786 {
787 /* Get session index and timer id */
788 connection_index = expired_timers[i] & 0x0FFFFFFF;
789 timer_id = expired_timers[i] >> 28;
790
Marco Varlesef47276f2018-02-06 09:01:39 +0100791 SCTP_DBG ("Expired timer ID: %u", timer_id);
792
Marco Varlese191a5942017-10-30 18:17:21 +0100793 /* Handle expiration */
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100794 sctp_expired_timers_cb (connection_index, timer_id);
Marco Varlese191a5942017-10-30 18:17:21 +0100795 }
796}
797
798void
799sctp_initialize_timer_wheels (sctp_main_t * tm)
800{
801 tw_timer_wheel_16t_2w_512sl_t *tw;
802 /* *INDENT-OFF* */
803 foreach_vlib_main (({
804 tw = &tm->timer_wheels[ii];
805 tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
806 100e-3 /* timer period 100ms */ , ~0);
807 tw->last_run_time = vlib_time_now (this_vlib_main);
808 }));
809 /* *INDENT-ON* */
810}
811
812clib_error_t *
813sctp_main_enable (vlib_main_t * vm)
814{
815 sctp_main_t *tm = vnet_get_sctp_main ();
816 vlib_thread_main_t *vtm = vlib_get_thread_main ();
817 clib_error_t *error = 0;
818 u32 num_threads;
819 int thread;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100820 sctp_connection_t *sctp_conn __attribute__ ((unused));
Marco Varlese191a5942017-10-30 18:17:21 +0100821 u32 preallocated_connections_per_thread;
822
823 if ((error = vlib_call_init_function (vm, ip_main_init)))
824 return error;
825 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
826 return error;
827 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
828 return error;
829
830 /*
831 * Registrations
832 */
833
834 ip4_register_protocol (IP_PROTOCOL_SCTP, sctp4_input_node.index);
835 ip6_register_protocol (IP_PROTOCOL_SCTP, sctp6_input_node.index);
836
837 /*
838 * Initialize data structures
839 */
840
841 num_threads = 1 /* main thread */ + vtm->n_threads;
842 vec_validate (tm->connections, num_threads - 1);
843
844 /*
845 * Preallocate connections. Assume that thread 0 won't
846 * use preallocated threads when running multi-core
847 */
848 if (num_threads == 1)
849 {
850 thread = 0;
851 preallocated_connections_per_thread = tm->preallocated_connections;
852 }
853 else
854 {
855 thread = 1;
856 preallocated_connections_per_thread =
857 tm->preallocated_connections / (num_threads - 1);
858 }
859 for (; thread < num_threads; thread++)
860 {
861 if (preallocated_connections_per_thread)
862 pool_init_fixed (tm->connections[thread],
863 preallocated_connections_per_thread);
864 }
865
866 /* Initialize per worker thread tx buffers (used for control messages) */
867 vec_validate (tm->tx_buffers, num_threads - 1);
868
869 /* Initialize timer wheels */
870 vec_validate (tm->timer_wheels, num_threads - 1);
871 sctp_initialize_timer_wheels (tm);
872
873 /* Initialize clocks per tick for SCTP timestamp. Used to compute
874 * monotonically increasing timestamps. */
875 tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
876 / SCTP_TSTAMP_RESOLUTION;
877
878 if (num_threads > 1)
879 {
Marco Varlesef47276f2018-02-06 09:01:39 +0100880 clib_spinlock_init (&tm->half_open_lock);
Marco Varlese191a5942017-10-30 18:17:21 +0100881 }
882
883 vec_validate (tm->tx_frames[0], num_threads - 1);
884 vec_validate (tm->tx_frames[1], num_threads - 1);
885 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
886 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
887
888 tm->bytes_per_buffer = vlib_buffer_free_list_buffer_size
889 (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
890
891 vec_validate (tm->time_now, num_threads - 1);
892 return error;
893}
894
895clib_error_t *
896sctp_enable_disable (vlib_main_t * vm, u8 is_en)
897{
898 if (is_en)
899 {
900 if (sctp_main.is_enabled)
901 return 0;
902
903 return sctp_main_enable (vm);
904 }
905 else
906 {
907 sctp_main.is_enabled = 0;
908 }
909
910 return 0;
911}
912
913transport_connection_t *
914sctp_half_open_session_get_transport (u32 conn_index)
915{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100916 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100917 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100918}
919
920u8 *
921format_sctp_half_open (u8 * s, va_list * args)
922{
923 u32 tci = va_arg (*args, u32);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100924 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (tci);
925 return format (s, "%U", format_sctp_connection_id, sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100926}
927
Marco Varlese21c8baf2018-02-02 17:17:51 +0100928void
929sctp_update_time (f64 now, u8 thread_index)
930{
931 sctp_set_time_now (thread_index);
932 tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
933 now);
934 sctp_flush_frames_to_output (thread_index);
935}
936
Marco Varlese191a5942017-10-30 18:17:21 +0100937/* *INDENT OFF* */
938const static transport_proto_vft_t sctp_proto = {
939 .enable = sctp_enable_disable,
940 .bind = sctp_session_bind,
941 .unbind = sctp_session_unbind,
942 .open = sctp_session_open,
943 .close = sctp_session_close,
944 .cleanup = sctp_session_cleanup,
945 .push_header = sctp_push_header,
946 .send_mss = sctp_session_send_mss,
947 .send_space = sctp_session_send_space,
Marco Varlese21c8baf2018-02-02 17:17:51 +0100948 .update_time = sctp_update_time,
Marco Varlese191a5942017-10-30 18:17:21 +0100949 .get_connection = sctp_session_get_transport,
950 .get_listener = sctp_session_get_listener,
951 .get_half_open = sctp_half_open_session_get_transport,
952 .format_connection = format_sctp_session,
953 .format_listener = format_sctp_listener_session,
954 .format_half_open = format_sctp_half_open,
Florin Coras371ca502018-02-21 12:07:41 -0800955 .tx_type = TRANSPORT_TX_DEQUEUE,
956 .service_type = TRANSPORT_SERVICE_VC,
Marco Varlese191a5942017-10-30 18:17:21 +0100957};
958
959/* *INDENT ON* */
960
961clib_error_t *
962sctp_init (vlib_main_t * vm)
963{
964 sctp_main_t *tm = vnet_get_sctp_main ();
965 ip_main_t *im = &ip_main;
966 ip_protocol_info_t *pi;
967 /* Session layer, and by implication SCTP, are disabled by default */
968 tm->is_enabled = 0;
969
970 /* Register with IP for header parsing */
971 pi = ip_get_protocol_info (im, IP_PROTOCOL_SCTP);
972 if (pi == 0)
973 return clib_error_return (0, "SCTP protocol info AWOL");
974 pi->format_header = format_sctp_header;
975 pi->unformat_pg_edit = unformat_pg_sctp_header;
976
977 /* Register as transport with session layer */
978 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
979 FIB_PROTOCOL_IP4, sctp4_output_node.index);
980 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
981 FIB_PROTOCOL_IP6, sctp6_output_node.index);
982
Marco Varlese3c6a9762018-03-01 11:19:59 +0100983 sctp_api_reference ();
984
Marco Varlese191a5942017-10-30 18:17:21 +0100985 return 0;
986}
987
988VLIB_INIT_FUNCTION (sctp_init);
989
990/*
991 * fd.io coding-style-patch-verification: ON
992 *
993 * Local Variables:
994 * eval: (c-set-style "gnu")
995 * End:
996 */