blob: ffa86343b4731c0f182b9cbf6cb5912d3ad08c79 [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);
28 memset (listener, 0, sizeof (*listener));
29
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)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010081 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);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100427 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);
445 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
454sctp_connection_open (transport_endpoint_t * rmt)
455{
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 (),
488 rmt->sw_if_index,
489 VNET_MTU_IP4) :
490 vnet_sw_interface_get_mtu (vnet_get_main (), rmt->sw_if_index,
491 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)
540 memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
541 pool_put (tm->connections[thread_index], sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100542}
543
544int
545sctp_session_open (transport_endpoint_t * tep)
546{
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);
627
628 return sctp_conn->sub_conn[idx].cwnd;
Marco Varlese191a5942017-10-30 18:17:21 +0100629}
630
631u16
632sctp_snd_space (sctp_connection_t * sctp_conn)
633{
Marco Varlese6e4d4a32018-03-12 12:36:59 +0100634 /* RFC 4096 Section 6.1; point (A) */
635 if (sctp_conn->peer_rwnd == 0)
636 return 0;
637
638 u8 idx = sctp_data_subconn_select (sctp_conn);
Marco Varlese3e9b4652018-03-13 15:44:56 +0100639
640 u32 available_wnd =
641 clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
642 int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
643
644 if (available_wnd <= flight_size)
645 return 0;
646
Marco Varlesef3ab4892018-02-19 15:23:13 +0100647 /* Finally, let's subtract the DATA chunk headers overhead */
Marco Varlese3e9b4652018-03-13 15:44:56 +0100648 return available_wnd -
649 flight_size -
Marco Varlesef3ab4892018-02-19 15:23:13 +0100650 sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
Marco Varlese191a5942017-10-30 18:17:21 +0100651}
652
Marco Varlesef3ab4892018-02-19 15:23:13 +0100653/**
654 * Compute TX window session is allowed to fill.
655 */
Marco Varlese191a5942017-10-30 18:17:21 +0100656u32
657sctp_session_send_space (transport_connection_t * trans_conn)
658{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100659 sctp_connection_t *sctp_conn =
660 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100661
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100662 return sctp_snd_space (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100663}
664
665transport_connection_t *
666sctp_session_get_transport (u32 conn_index, u32 thread_index)
667{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100668 sctp_connection_t *sctp_conn =
669 sctp_connection_get (conn_index, thread_index);
Marco Varlese2802bd72018-02-15 13:45:39 +0100670
671 if (PREDICT_TRUE (sctp_conn != NULL))
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100672 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese2802bd72018-02-15 13:45:39 +0100673
674 return NULL;
Marco Varlese191a5942017-10-30 18:17:21 +0100675}
676
677transport_connection_t *
678sctp_session_get_listener (u32 listener_index)
679{
680 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100681 sctp_connection_t *sctp_conn;
682 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100683 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100684}
685
686u8 *
687format_sctp_session (u8 * s, va_list * args)
688{
Marco Varlesef3ab4892018-02-19 15:23:13 +0100689 u32 tci = va_arg (*args, u32);
690 u32 thread_index = va_arg (*args, u32);
691 u32 verbose = va_arg (*args, u32);
692 sctp_connection_t *tc;
693
694 tc = sctp_connection_get (tci, thread_index);
695 if (tc)
696 s = format (s, "%U", format_sctp_connection, tc, verbose);
697 else
698 s = format (s, "empty\n");
699 return s;
Marco Varlese191a5942017-10-30 18:17:21 +0100700}
701
702u8 *
703format_sctp_listener_session (u8 * s, va_list * args)
704{
Marco Varlesef3ab4892018-02-19 15:23:13 +0100705 u32 tci = va_arg (*args, u32);
706 sctp_connection_t *tc = sctp_listener_get (tci);
707 return format (s, "%U", format_sctp_connection_id, tc);
Marco Varlese191a5942017-10-30 18:17:21 +0100708}
709
710void
Marco Varlesef47276f2018-02-06 09:01:39 +0100711sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
Marco Varlese191a5942017-10-30 18:17:21 +0100712{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100713 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100714
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100715 sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
Marco Varlese191a5942017-10-30 18:17:21 +0100716 /* note: the connection may have already disappeared */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100717 if (PREDICT_FALSE (sctp_conn == 0))
Marco Varlese191a5942017-10-30 18:17:21 +0100718 return;
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100719
720 SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100721
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100722 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
Marco Varlese54432f82018-02-15 17:01:56 +0100723 SCTP_PATH_MAX_RETRANS)
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100724 {
725 // The remote-peer is considered to be unreachable hence shutting down
Marco Varlese54432f82018-02-15 17:01:56 +0100726 u8 i, total_subs_down = 1;
727 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
728 {
729 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
730 continue;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100731
Marco Varlese54432f82018-02-15 17:01:56 +0100732 u32 now = sctp_time_now ();
733 if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
734 {
735 total_subs_down += 1;
736 sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
737 }
738 }
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100739
Marco Varlese54432f82018-02-15 17:01:56 +0100740 if (total_subs_down == MAX_SCTP_CONNECTIONS)
741 {
742 /* Start cleanup. App wasn't notified yet so use delete notify as
743 * opposed to delete to cleanup session layer state. */
744 stream_session_delete_notify (&sctp_conn->sub_conn
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100745 [SCTP_PRIMARY_PATH_IDX].connection);
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100746
Marco Varlese54432f82018-02-15 17:01:56 +0100747 sctp_connection_timers_reset (sctp_conn);
748
749 sctp_connection_cleanup (sctp_conn);
750 }
Marco Varlese9e09ff32018-03-05 12:31:45 +0100751 return;
752 }
753
754 switch (timer_id)
755 {
756 case SCTP_TIMER_T1_INIT:
757 sctp_send_init (sctp_conn);
758 break;
759 case SCTP_TIMER_T1_COOKIE:
760 sctp_send_cookie_echo (sctp_conn);
761 break;
762 case SCTP_TIMER_T2_SHUTDOWN:
763 sctp_send_shutdown (sctp_conn);
764 break;
765 case SCTP_TIMER_T3_RXTX:
766 sctp_timer_reset (sctp_conn, conn_index, timer_id);
Marco Varlese3e9b4652018-03-13 15:44:56 +0100767 sctp_conn->flags |= SCTP_CONN_RECOVERY;
Marco Varlese9e09ff32018-03-05 12:31:45 +0100768 sctp_data_retransmit (sctp_conn);
769 break;
770 case SCTP_TIMER_T4_HEARTBEAT:
771 sctp_timer_reset (sctp_conn, conn_index, timer_id);
772 goto heartbeat;
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100773 }
774 return;
775
776heartbeat:
777 sctp_send_heartbeat (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100778}
779
Marco Varlese191a5942017-10-30 18:17:21 +0100780static void
781sctp_expired_timers_dispatch (u32 * expired_timers)
782{
783 int i;
784 u32 connection_index, timer_id;
785
786 for (i = 0; i < vec_len (expired_timers); i++)
787 {
788 /* Get session index and timer id */
789 connection_index = expired_timers[i] & 0x0FFFFFFF;
790 timer_id = expired_timers[i] >> 28;
791
Marco Varlesef47276f2018-02-06 09:01:39 +0100792 SCTP_DBG ("Expired timer ID: %u", timer_id);
793
Marco Varlese191a5942017-10-30 18:17:21 +0100794 /* Handle expiration */
Marco Varlesedf5a99c2018-02-06 13:48:30 +0100795 sctp_expired_timers_cb (connection_index, timer_id);
Marco Varlese191a5942017-10-30 18:17:21 +0100796 }
797}
798
799void
800sctp_initialize_timer_wheels (sctp_main_t * tm)
801{
802 tw_timer_wheel_16t_2w_512sl_t *tw;
803 /* *INDENT-OFF* */
804 foreach_vlib_main (({
805 tw = &tm->timer_wheels[ii];
806 tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
807 100e-3 /* timer period 100ms */ , ~0);
808 tw->last_run_time = vlib_time_now (this_vlib_main);
809 }));
810 /* *INDENT-ON* */
811}
812
813clib_error_t *
814sctp_main_enable (vlib_main_t * vm)
815{
816 sctp_main_t *tm = vnet_get_sctp_main ();
817 vlib_thread_main_t *vtm = vlib_get_thread_main ();
818 clib_error_t *error = 0;
819 u32 num_threads;
820 int thread;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100821 sctp_connection_t *sctp_conn __attribute__ ((unused));
Marco Varlese191a5942017-10-30 18:17:21 +0100822 u32 preallocated_connections_per_thread;
823
824 if ((error = vlib_call_init_function (vm, ip_main_init)))
825 return error;
826 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
827 return error;
828 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
829 return error;
830
831 /*
832 * Registrations
833 */
834
835 ip4_register_protocol (IP_PROTOCOL_SCTP, sctp4_input_node.index);
836 ip6_register_protocol (IP_PROTOCOL_SCTP, sctp6_input_node.index);
837
838 /*
839 * Initialize data structures
840 */
841
842 num_threads = 1 /* main thread */ + vtm->n_threads;
843 vec_validate (tm->connections, num_threads - 1);
844
845 /*
846 * Preallocate connections. Assume that thread 0 won't
847 * use preallocated threads when running multi-core
848 */
849 if (num_threads == 1)
850 {
851 thread = 0;
852 preallocated_connections_per_thread = tm->preallocated_connections;
853 }
854 else
855 {
856 thread = 1;
857 preallocated_connections_per_thread =
858 tm->preallocated_connections / (num_threads - 1);
859 }
860 for (; thread < num_threads; thread++)
861 {
862 if (preallocated_connections_per_thread)
863 pool_init_fixed (tm->connections[thread],
864 preallocated_connections_per_thread);
865 }
866
867 /* Initialize per worker thread tx buffers (used for control messages) */
868 vec_validate (tm->tx_buffers, num_threads - 1);
869
870 /* Initialize timer wheels */
871 vec_validate (tm->timer_wheels, num_threads - 1);
872 sctp_initialize_timer_wheels (tm);
873
874 /* Initialize clocks per tick for SCTP timestamp. Used to compute
875 * monotonically increasing timestamps. */
876 tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
877 / SCTP_TSTAMP_RESOLUTION;
878
879 if (num_threads > 1)
880 {
Marco Varlesef47276f2018-02-06 09:01:39 +0100881 clib_spinlock_init (&tm->half_open_lock);
Marco Varlese191a5942017-10-30 18:17:21 +0100882 }
883
884 vec_validate (tm->tx_frames[0], num_threads - 1);
885 vec_validate (tm->tx_frames[1], num_threads - 1);
886 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
887 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
888
889 tm->bytes_per_buffer = vlib_buffer_free_list_buffer_size
890 (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
891
892 vec_validate (tm->time_now, num_threads - 1);
893 return error;
894}
895
896clib_error_t *
897sctp_enable_disable (vlib_main_t * vm, u8 is_en)
898{
899 if (is_en)
900 {
901 if (sctp_main.is_enabled)
902 return 0;
903
904 return sctp_main_enable (vm);
905 }
906 else
907 {
908 sctp_main.is_enabled = 0;
909 }
910
911 return 0;
912}
913
914transport_connection_t *
915sctp_half_open_session_get_transport (u32 conn_index)
916{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100917 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100918 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100919}
920
921u8 *
922format_sctp_half_open (u8 * s, va_list * args)
923{
924 u32 tci = va_arg (*args, u32);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100925 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (tci);
926 return format (s, "%U", format_sctp_connection_id, sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100927}
928
Marco Varlese21c8baf2018-02-02 17:17:51 +0100929void
930sctp_update_time (f64 now, u8 thread_index)
931{
932 sctp_set_time_now (thread_index);
933 tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
934 now);
935 sctp_flush_frames_to_output (thread_index);
936}
937
Marco Varlese191a5942017-10-30 18:17:21 +0100938/* *INDENT OFF* */
939const static transport_proto_vft_t sctp_proto = {
940 .enable = sctp_enable_disable,
941 .bind = sctp_session_bind,
942 .unbind = sctp_session_unbind,
943 .open = sctp_session_open,
944 .close = sctp_session_close,
945 .cleanup = sctp_session_cleanup,
946 .push_header = sctp_push_header,
947 .send_mss = sctp_session_send_mss,
948 .send_space = sctp_session_send_space,
Marco Varlese21c8baf2018-02-02 17:17:51 +0100949 .update_time = sctp_update_time,
Marco Varlese191a5942017-10-30 18:17:21 +0100950 .get_connection = sctp_session_get_transport,
951 .get_listener = sctp_session_get_listener,
952 .get_half_open = sctp_half_open_session_get_transport,
953 .format_connection = format_sctp_session,
954 .format_listener = format_sctp_listener_session,
955 .format_half_open = format_sctp_half_open,
Florin Coras371ca502018-02-21 12:07:41 -0800956 .tx_type = TRANSPORT_TX_DEQUEUE,
957 .service_type = TRANSPORT_SERVICE_VC,
Marco Varlese191a5942017-10-30 18:17:21 +0100958};
959
960/* *INDENT ON* */
961
962clib_error_t *
963sctp_init (vlib_main_t * vm)
964{
965 sctp_main_t *tm = vnet_get_sctp_main ();
966 ip_main_t *im = &ip_main;
967 ip_protocol_info_t *pi;
968 /* Session layer, and by implication SCTP, are disabled by default */
969 tm->is_enabled = 0;
970
971 /* Register with IP for header parsing */
972 pi = ip_get_protocol_info (im, IP_PROTOCOL_SCTP);
973 if (pi == 0)
974 return clib_error_return (0, "SCTP protocol info AWOL");
975 pi->format_header = format_sctp_header;
976 pi->unformat_pg_edit = unformat_pg_sctp_header;
977
978 /* Register as transport with session layer */
979 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
980 FIB_PROTOCOL_IP4, sctp4_output_node.index);
981 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
982 FIB_PROTOCOL_IP6, sctp6_output_node.index);
983
Marco Varlese3c6a9762018-03-01 11:19:59 +0100984 sctp_api_reference ();
985
Marco Varlese191a5942017-10-30 18:17:21 +0100986 return 0;
987}
988
989VLIB_INIT_FUNCTION (sctp_init);
990
991/*
992 * fd.io coding-style-patch-verification: ON
993 *
994 * Local Variables:
995 * eval: (c-set-style "gnu")
996 * End:
997 */