blob: d0f37f4346e13545be9c42ec031d0a38737db03f [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
30 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].parent = listener;
31 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_c_index =
32 listener - tm->listener_pool;
33 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.lcl_port = tep->port;
34
35 /* If we are provided a sw_if_index, bind using one of its IPs */
36 if (ip_is_zero (&tep->ip, 1) && tep->sw_if_index != ENDPOINT_INVALID_INDEX)
37 {
38 if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
39 tep->is_ip4)))
40 ip_set (&tep->ip, iface_ip, tep->is_ip4);
41 }
42 ip_copy (&listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.lcl_ip,
43 &tep->ip, tep->is_ip4);
44
45 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.is_ip4 = tep->is_ip4;
46 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.proto =
47 TRANSPORT_PROTO_SCTP;
48 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_s_index = session_index;
49 listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.fib_index =
50 tep->fib_index;
51 listener->state = SCTP_STATE_CLOSED;
52
53 sctp_connection_timers_init (listener);
54
55 return listener->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_c_index;
56}
57
58u32
59sctp_session_bind (u32 session_index, transport_endpoint_t * tep)
60{
61 return sctp_connection_bind (session_index, tep);
62}
63
64static void
65sctp_connection_unbind (u32 listener_index)
66{
67 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010068 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +010069
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010070 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
Marco Varlese191a5942017-10-30 18:17:21 +010071
72 /* Poison the entry */
73 if (CLIB_DEBUG > 0)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +010074 memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
Marco Varlese191a5942017-10-30 18:17:21 +010075
76 pool_put_index (tm->listener_pool, listener_index);
77}
78
79u32
80sctp_session_unbind (u32 listener_index)
81{
82 sctp_connection_unbind (listener_index);
83 return 0;
84}
85
86void
87sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
88{
89 sctp_main_t *tm = &sctp_main;
90 if (is_ip4)
91 tm->punt_unknown4 = is_add;
92 else
93 tm->punt_unknown6 = is_add;
94}
95
96static int
97sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
98 u16 * lcl_port, u8 is_ip4)
99{
100 int index, port;
101 if (is_ip4)
102 {
103 index = tm->last_v4_address_rotor++;
104 if (tm->last_v4_address_rotor >= vec_len (tm->ip4_src_addresses))
105 tm->last_v4_address_rotor = 0;
106 lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
107 }
108 else
109 {
110 index = tm->last_v6_address_rotor++;
111 if (tm->last_v6_address_rotor >= vec_len (tm->ip6_src_addresses))
112 tm->last_v6_address_rotor = 0;
113 clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
114 sizeof (ip6_address_t));
115 }
116 port = transport_alloc_local_port (TRANSPORT_PROTO_SCTP, lcl_addr);
117 if (port < 1)
118 {
119 clib_warning ("Failed to allocate src port");
120 return -1;
121 }
122 *lcl_port = port;
123 return 0;
124}
125
126/**
127 * Initialize all connection timers as invalid
128 */
129void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100130sctp_connection_timers_init (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100131{
132 int i, j;
133
134 /* Set all to invalid */
135 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100136 {
137 sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
138 for (j = 0; j < SCTP_N_TIMERS; j++)
139 {
140 sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
141 }
142 }
Marco Varlese191a5942017-10-30 18:17:21 +0100143}
144
145/**
146 * Stop all connection timers
147 */
148void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100149sctp_connection_timers_reset (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100150{
151 int i, j;
152 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
153 {
154 for (j = 0; j < SCTP_N_TIMERS; j++)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100155 sctp_timer_reset (sctp_conn, i, j);
Marco Varlese191a5942017-10-30 18:17:21 +0100156 }
157}
158
159const char *sctp_fsm_states[] = {
160#define _(sym, str) str,
161 foreach_sctp_fsm_state
162#undef _
163};
164
165u8 *
166format_sctp_state (u8 * s, va_list * args)
167{
168 u32 state = va_arg (*args, u32);
169
170 if (state < SCTP_N_STATES)
171 s = format (s, "%s", sctp_fsm_states[state]);
172 else
173 s = format (s, "UNKNOWN (%d (0x%x))", state, state);
174 return s;
175}
176
177u8 *
178format_sctp_connection_id (u8 * s, va_list * args)
179{
180 /*
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100181 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
182 if (!sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100183 return s;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100184 if (sctp_conn->c_is_ip4)
Marco Varlese191a5942017-10-30 18:17:21 +0100185 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100186 s = format (s, "[#%d][%s] %U:%d->%U:%d", sctp_conn->c_thread_index, "T",
187 format_ip4_address, &sctp_conn->c_lcl_ip4,
188 clib_net_to_host_u16 (sctp_conn->c_lcl_port), format_ip4_address,
189 &sctp_conn->c_rmt_ip4, clib_net_to_host_u16 (sctp_conn->c_rmt_port));
Marco Varlese191a5942017-10-30 18:17:21 +0100190 }
191 else
192 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100193 s = format (s, "[#%d][%s] %U:%d->%U:%d", sctp_conn->c_thread_index, "T",
194 format_ip6_address, &sctp_conn->c_lcl_ip6,
195 clib_net_to_host_u16 (sctp_conn->c_lcl_port), format_ip6_address,
196 &sctp_conn->c_rmt_ip6, clib_net_to_host_u16 (sctp_conn->c_rmt_port));
Marco Varlese191a5942017-10-30 18:17:21 +0100197 }
198 */
199 return s;
200}
201
202u8 *
203format_sctp_connection (u8 * s, va_list * args)
204{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100205 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
Marco Varlese191a5942017-10-30 18:17:21 +0100206 u32 verbose = va_arg (*args, u32);
207
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100208 if (!sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100209 return s;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100210 s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100211 if (verbose)
212 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100213 s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
Marco Varlese191a5942017-10-30 18:17:21 +0100214 }
215
216 return s;
217}
218
219/**
220 * Initialize connection send variables.
221 */
222void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100223sctp_init_snd_vars (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100224{
225 u32 time_now;
Marco Varlese191a5942017-10-30 18:17:21 +0100226 /*
227 * We use the time to randomize iss and for setting up the initial
228 * timestamp. Make sure it's updated otherwise syn and ack in the
229 * handshake may make it look as if time has flown in the opposite
230 * direction for us.
231 */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100232
Marco Varlese191a5942017-10-30 18:17:21 +0100233 sctp_set_time_now (vlib_get_thread_index ());
234 time_now = sctp_time_now ();
235
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100236 sctp_conn->local_initial_tsn = random_u32 (&time_now);
237 sctp_conn->remote_initial_tsn = 0x0;
238 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
239 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
Marco Varlese191a5942017-10-30 18:17:21 +0100240}
241
242/**
243 * Update max segment size we're able to process.
244 *
245 * The value is constrained by our interface's MTU and IP options. It is
246 * also what we advertise to our peer.
247 */
248void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100249sctp_update_rcv_mss (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100250{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100251 sctp_conn->smallest_PMTU = DEFAULT_A_RWND; /* TODO find our iface MTU */
252 sctp_conn->a_rwnd = DEFAULT_A_RWND - sizeof (sctp_full_hdr_t);
253 sctp_conn->rcv_opts.a_rwnd = sctp_conn->a_rwnd;
254 sctp_conn->rcv_a_rwnd = sctp_conn->a_rwnd; /* This will be updated by our congestion algos */
Marco Varlese191a5942017-10-30 18:17:21 +0100255}
256
257void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100258sctp_init_mss (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100259{
260 SCTP_DBG ("CONN_INDEX = %u",
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100261 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.c_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100262
263 u16 default_a_rwnd = 536;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100264 sctp_update_rcv_mss (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100265
266 /* TODO cache mss and consider PMTU discovery */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100267 sctp_conn->snd_a_rwnd =
268 clib_min (sctp_conn->rcv_opts.a_rwnd, sctp_conn->a_rwnd);
Marco Varlese191a5942017-10-30 18:17:21 +0100269
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100270 if (sctp_conn->snd_a_rwnd < sizeof (sctp_full_hdr_t))
Marco Varlese191a5942017-10-30 18:17:21 +0100271 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100272 SCTP_ADV_DBG ("sctp_conn->snd_a_rwnd < sizeof(sctp_full_hdr_t)");
Marco Varlese191a5942017-10-30 18:17:21 +0100273 /* Assume that at least the min default mss works */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100274 sctp_conn->snd_a_rwnd = default_a_rwnd;
275 sctp_conn->rcv_opts.a_rwnd = default_a_rwnd;
Marco Varlese191a5942017-10-30 18:17:21 +0100276 }
277
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100278 ASSERT (sctp_conn->snd_a_rwnd > sizeof (sctp_full_hdr_t));
Marco Varlese191a5942017-10-30 18:17:21 +0100279}
280
281always_inline sctp_connection_t *
282sctp_sub_connection_add (u8 thread_index)
283{
284 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100285 sctp_connection_t *sctp_conn = tm->connections[thread_index];
Marco Varlese191a5942017-10-30 18:17:21 +0100286
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100287 sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn].connection.c_index =
288 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.c_index;
289 sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn].
290 connection.thread_index = thread_index;
291 sctp_conn->sub_conn[sctp_conn->next_avail_sub_conn].parent = sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100292
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100293 sctp_conn->next_avail_sub_conn += 1;
Marco Varlese191a5942017-10-30 18:17:21 +0100294
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100295 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100296}
297
298void
299sctp_sub_connection_add_ip4 (u8 thread_index,
300 sctp_ipv4_addr_param_t * ipv4_addr)
301{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100302 sctp_connection_t *sctp_conn = sctp_sub_connection_add (thread_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100303
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100304 clib_memcpy (&sctp_conn->
305 sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip4,
Marco Varlese191a5942017-10-30 18:17:21 +0100306 &ipv4_addr->address, sizeof (ipv4_addr->address));
307}
308
309void
310sctp_sub_connection_add_ip6 (u8 thread_index,
311 sctp_ipv6_addr_param_t * ipv6_addr)
312{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100313 sctp_connection_t *sctp_conn = sctp_sub_connection_add (thread_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100314
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100315 clib_memcpy (&sctp_conn->
316 sub_conn[sctp_conn->next_avail_sub_conn].connection.lcl_ip.ip6,
Marco Varlese191a5942017-10-30 18:17:21 +0100317 &ipv6_addr->address, sizeof (ipv6_addr->address));
318}
319
320sctp_connection_t *
321sctp_connection_new (u8 thread_index)
322{
323 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100324 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100325
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100326 pool_get (tm->connections[thread_index], sctp_conn);
327 memset (sctp_conn, 0, sizeof (*sctp_conn));
328 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].parent = sctp_conn;
329 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_c_index =
330 sctp_conn - tm->connections[thread_index];
331 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_thread_index = thread_index;
332 sctp_conn->local_tag = 0;
333 sctp_conn->next_avail_sub_conn = 1;
Marco Varlese191a5942017-10-30 18:17:21 +0100334
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100335 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100336}
337
338sctp_connection_t *
339sctp_half_open_connection_new (u8 thread_index)
340{
341 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100342 sctp_connection_t *sctp_conn = 0;
Marco Varlese191a5942017-10-30 18:17:21 +0100343 ASSERT (vlib_get_thread_index () == 0);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100344 pool_get (tm->half_open_connections, sctp_conn);
345 memset (sctp_conn, 0, sizeof (*sctp_conn));
346 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].c_c_index =
347 sctp_conn - tm->half_open_connections;
348 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].parent = sctp_conn;
349 return sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100350}
351
352static inline int
353sctp_connection_open (transport_endpoint_t * rmt)
354{
355 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100356 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100357 ip46_address_t lcl_addr;
358 u16 lcl_port;
359 uword thread_id;
360 int rv;
361
362 u8 idx = sctp_pick_conn_idx_on_state (SCTP_STATE_CLOSED);
363
364 /*
365 * Allocate local endpoint
366 */
367 if ((rmt->is_ip4 && vec_len (tm->ip4_src_addresses))
368 || (!rmt->is_ip4 && vec_len (tm->ip6_src_addresses)))
369 rv = sctp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
370 rmt->is_ip4);
371 else
372 rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_SCTP,
373 rmt, &lcl_addr, &lcl_port);
374
375 if (rv)
376 return -1;
377
378 /*
379 * Create connection and send INIT CHUNK
380 */
381 thread_id = vlib_get_thread_index ();
382 ASSERT (thread_id == 0);
383
384 clib_spinlock_lock_if_init (&tm->half_open_lock);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100385 sctp_conn = sctp_half_open_connection_new (thread_id);
Marco Varlese191a5942017-10-30 18:17:21 +0100386
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100387 transport_connection_t *trans_conn = &sctp_conn->sub_conn[idx].connection;
388 ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
389 ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
390 sctp_conn->sub_conn[idx].parent = sctp_conn;
391 trans_conn->rmt_port = rmt->port;
392 trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
393 trans_conn->is_ip4 = rmt->is_ip4;
394 trans_conn->proto = TRANSPORT_PROTO_SCTP;
395 trans_conn->fib_index = rmt->fib_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100396
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100397 sctp_connection_timers_init (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100398 /* The other connection vars will be initialized after INIT_ACK chunk received */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100399 sctp_init_snd_vars (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100400
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100401 sctp_send_init (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100402
403 clib_spinlock_unlock_if_init (&tm->half_open_lock);
404
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100405 return sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100406}
407
408/**
409 * Cleans up connection state.
410 *
411 * No notifications.
412 */
413void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100414sctp_connection_cleanup (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100415{
416 sctp_main_t *tm = &sctp_main;
417 u8 i;
418
419 /* Cleanup local endpoint if this was an active connect */
420 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
421 transport_endpoint_cleanup (TRANSPORT_PROTO_SCTP,
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100422 &sctp_conn->sub_conn[i].connection.lcl_ip,
423 sctp_conn->sub_conn[i].connection.lcl_port);
Marco Varlese191a5942017-10-30 18:17:21 +0100424
425 /* Check if connection is not yet fully established */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100426 if (sctp_conn->state == SCTP_STATE_COOKIE_WAIT)
Marco Varlese191a5942017-10-30 18:17:21 +0100427 {
428
429 }
430 else
431 {
432 int thread_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100433 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.thread_index;
Marco Varlese191a5942017-10-30 18:17:21 +0100434
435 /* Make sure all timers are cleared */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100436 sctp_connection_timers_reset (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100437
438 /* Poison the entry */
439 if (CLIB_DEBUG > 0)
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100440 memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
441 pool_put (tm->connections[thread_index], sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100442 }
443}
444
445int
446sctp_session_open (transport_endpoint_t * tep)
447{
448 return sctp_connection_open (tep);
449}
450
451u16
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100452sctp_check_outstanding_data_chunks (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100453{
454 return 0; /* Indicates no more data to be read/sent */
455}
456
457void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100458sctp_connection_close (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100459{
460 SCTP_DBG ("Closing connection %u...",
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100461 sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection.c_index);
Marco Varlese191a5942017-10-30 18:17:21 +0100462
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100463 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
Marco Varlese191a5942017-10-30 18:17:21 +0100464
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100465 sctp_send_shutdown (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100466}
467
468void
469sctp_session_close (u32 conn_index, u32 thread_index)
470{
471 ASSERT (thread_index == 0);
472
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100473 sctp_connection_t *sctp_conn;
474 sctp_conn = sctp_connection_get (conn_index, thread_index);
475 sctp_connection_close (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100476}
477
478void
479sctp_session_cleanup (u32 conn_index, u32 thread_index)
480{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100481 sctp_connection_t *sctp_conn;
482 sctp_conn = sctp_connection_get (conn_index, thread_index);
483 sctp_connection_timers_reset (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100484
485 /* Wait for the session tx events to clear */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100486 sctp_conn->state = SCTP_STATE_CLOSED;
Marco Varlese191a5942017-10-30 18:17:21 +0100487}
488
489/**
490 * Update snd_mss to reflect the effective segment size that we can send
491 */
492void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100493sctp_update_snd_mss (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +0100494{
495 /* The overhead for the sctp_header_t and sctp_chunks_common_hdr_t
496 * (the sum equals to sctp_full_hdr_t) is already taken into account
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100497 * for the sctp_conn->a_rwnd computation.
Marco Varlese191a5942017-10-30 18:17:21 +0100498 * So let's not account it again here.
499 */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100500 sctp_conn->snd_hdr_length =
Marco Varlese191a5942017-10-30 18:17:21 +0100501 sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100502 sctp_conn->snd_a_rwnd =
503 clib_min (sctp_conn->a_rwnd,
504 sctp_conn->rcv_opts.a_rwnd) - sctp_conn->snd_hdr_length;
Marco Varlese191a5942017-10-30 18:17:21 +0100505
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100506 SCTP_DBG ("sctp_conn->snd_a_rwnd = %u, sctp_conn->snd_hdr_length = %u ",
507 sctp_conn->snd_a_rwnd, sctp_conn->snd_hdr_length);
Marco Varlese191a5942017-10-30 18:17:21 +0100508
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100509 ASSERT (sctp_conn->snd_a_rwnd > 0);
Marco Varlese191a5942017-10-30 18:17:21 +0100510}
511
512u16
513sctp_session_send_mss (transport_connection_t * trans_conn)
514{
515 SCTP_DBG ("CONN_INDEX: %u", trans_conn->c_index);
516
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100517 sctp_connection_t *sctp_conn =
518 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100519
520 if (trans_conn == NULL)
521 {
522 SCTP_DBG ("trans_conn == NULL");
523 return 0;
524 }
525
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100526 if (sctp_conn == NULL)
Marco Varlese191a5942017-10-30 18:17:21 +0100527 {
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100528 SCTP_DBG ("sctp_conn == NULL");
Marco Varlese191a5942017-10-30 18:17:21 +0100529 return 0;
530 }
531 /* Ensure snd_mss does accurately reflect the amount of data we can push
532 * in a segment. This also makes sure that options are updated according to
533 * the current state of the connection. */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100534 sctp_update_snd_mss (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100535
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100536 return sctp_conn->snd_a_rwnd;
Marco Varlese191a5942017-10-30 18:17:21 +0100537}
538
539u16
540sctp_snd_space (sctp_connection_t * sctp_conn)
541{
542 /* TODO: This requires a real implementation */
543 if (sctp_conn == NULL)
544 {
545 SCTP_DBG ("sctp_conn == NULL");
546 return 0;
547 }
548
549 if (sctp_conn->state != SCTP_STATE_ESTABLISHED)
550 {
551 SCTP_DBG_STATE_MACHINE
552 ("Trying to send DATA while not in SCTP_STATE_ESTABLISHED");
553 return 0;
554 }
555
556 return sctp_conn->snd_a_rwnd;
557}
558
559u32
560sctp_session_send_space (transport_connection_t * trans_conn)
561{
562 SCTP_DBG ("CONN_INDEX: %u", trans_conn->c_index);
563
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100564 sctp_connection_t *sctp_conn =
565 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100566
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100567 return sctp_snd_space (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100568}
569
570transport_connection_t *
571sctp_session_get_transport (u32 conn_index, u32 thread_index)
572{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100573 sctp_connection_t *sctp_conn =
574 sctp_connection_get (conn_index, thread_index);
575 return &sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100576}
577
578transport_connection_t *
579sctp_session_get_listener (u32 listener_index)
580{
581 sctp_main_t *tm = vnet_get_sctp_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100582 sctp_connection_t *sctp_conn;
583 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
584 return &sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100585}
586
587u8 *
588format_sctp_session (u8 * s, va_list * args)
589{
590 return NULL;
591}
592
593u8 *
594format_sctp_listener_session (u8 * s, va_list * args)
595{
596 return NULL;
597}
598
599void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100600sctp_timer_init_handler (u32 conn_index, u32 timer_id)
Marco Varlese191a5942017-10-30 18:17:21 +0100601{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100602 sctp_connection_t *sctp_conn;
Marco Varlese191a5942017-10-30 18:17:21 +0100603
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100604 clib_warning ("");
605 sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
Marco Varlese191a5942017-10-30 18:17:21 +0100606 /* note: the connection may have already disappeared */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100607 if (PREDICT_FALSE (sctp_conn == 0))
Marco Varlese191a5942017-10-30 18:17:21 +0100608 return;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100609 ASSERT (sctp_conn->state == SCTP_STATE_COOKIE_ECHOED);
610
611 switch (timer_id)
612 {
613 case SCTP_TIMER_T4_HEARTBEAT:
614 {
615 clib_warning ("Heartbeat timeout");
616 break;
617 }
618 }
Marco Varlese191a5942017-10-30 18:17:21 +0100619 /* Start cleanup. App wasn't notified yet so use delete notify as
620 * opposed to delete to cleanup session layer state. */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100621 stream_session_delete_notify (&sctp_conn->
Marco Varlese191a5942017-10-30 18:17:21 +0100622 sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection);
Marco Varlese191a5942017-10-30 18:17:21 +0100623
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100624 sctp_connection_timers_reset (sctp_conn);
625
626 sctp_connection_cleanup (sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100627}
628
629/* *INDENT OFF* */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100630static sctp_timer_expiration_handler
631 * sctp_timer_expiration_handlers[SCTP_N_TIMERS] = {
Marco Varlese191a5942017-10-30 18:17:21 +0100632 sctp_timer_init_handler
633};
634
635/* *INDENT ON* */
636
637static void
638sctp_expired_timers_dispatch (u32 * expired_timers)
639{
640 int i;
641 u32 connection_index, timer_id;
642
643 for (i = 0; i < vec_len (expired_timers); i++)
644 {
645 /* Get session index and timer id */
646 connection_index = expired_timers[i] & 0x0FFFFFFF;
647 timer_id = expired_timers[i] >> 28;
648
649 /* Handle expiration */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100650 (*sctp_timer_expiration_handlers[timer_id]) (connection_index,
651 timer_id);
Marco Varlese191a5942017-10-30 18:17:21 +0100652 }
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100653
654 clib_warning ("");
Marco Varlese191a5942017-10-30 18:17:21 +0100655}
656
657void
658sctp_initialize_timer_wheels (sctp_main_t * tm)
659{
660 tw_timer_wheel_16t_2w_512sl_t *tw;
661 /* *INDENT-OFF* */
662 foreach_vlib_main (({
663 tw = &tm->timer_wheels[ii];
664 tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
665 100e-3 /* timer period 100ms */ , ~0);
666 tw->last_run_time = vlib_time_now (this_vlib_main);
667 }));
668 /* *INDENT-ON* */
669}
670
671clib_error_t *
672sctp_main_enable (vlib_main_t * vm)
673{
674 sctp_main_t *tm = vnet_get_sctp_main ();
675 vlib_thread_main_t *vtm = vlib_get_thread_main ();
676 clib_error_t *error = 0;
677 u32 num_threads;
678 int thread;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100679 sctp_connection_t *sctp_conn __attribute__ ((unused));
Marco Varlese191a5942017-10-30 18:17:21 +0100680 u32 preallocated_connections_per_thread;
681
682 if ((error = vlib_call_init_function (vm, ip_main_init)))
683 return error;
684 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
685 return error;
686 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
687 return error;
688
689 /*
690 * Registrations
691 */
692
693 ip4_register_protocol (IP_PROTOCOL_SCTP, sctp4_input_node.index);
694 ip6_register_protocol (IP_PROTOCOL_SCTP, sctp6_input_node.index);
695
696 /*
697 * Initialize data structures
698 */
699
700 num_threads = 1 /* main thread */ + vtm->n_threads;
701 vec_validate (tm->connections, num_threads - 1);
702
703 /*
704 * Preallocate connections. Assume that thread 0 won't
705 * use preallocated threads when running multi-core
706 */
707 if (num_threads == 1)
708 {
709 thread = 0;
710 preallocated_connections_per_thread = tm->preallocated_connections;
711 }
712 else
713 {
714 thread = 1;
715 preallocated_connections_per_thread =
716 tm->preallocated_connections / (num_threads - 1);
717 }
718 for (; thread < num_threads; thread++)
719 {
720 if (preallocated_connections_per_thread)
721 pool_init_fixed (tm->connections[thread],
722 preallocated_connections_per_thread);
723 }
724
725 /* Initialize per worker thread tx buffers (used for control messages) */
726 vec_validate (tm->tx_buffers, num_threads - 1);
727
728 /* Initialize timer wheels */
729 vec_validate (tm->timer_wheels, num_threads - 1);
730 sctp_initialize_timer_wheels (tm);
731
732 /* Initialize clocks per tick for SCTP timestamp. Used to compute
733 * monotonically increasing timestamps. */
734 tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
735 / SCTP_TSTAMP_RESOLUTION;
736
737 if (num_threads > 1)
738 {
739 }
740
741 vec_validate (tm->tx_frames[0], num_threads - 1);
742 vec_validate (tm->tx_frames[1], num_threads - 1);
743 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
744 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
745
746 tm->bytes_per_buffer = vlib_buffer_free_list_buffer_size
747 (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
748
749 vec_validate (tm->time_now, num_threads - 1);
750 return error;
751}
752
753clib_error_t *
754sctp_enable_disable (vlib_main_t * vm, u8 is_en)
755{
756 if (is_en)
757 {
758 if (sctp_main.is_enabled)
759 return 0;
760
761 return sctp_main_enable (vm);
762 }
763 else
764 {
765 sctp_main.is_enabled = 0;
766 }
767
768 return 0;
769}
770
771transport_connection_t *
772sctp_half_open_session_get_transport (u32 conn_index)
773{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100774 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
775 return &sctp_conn->sub_conn[MAIN_SCTP_SUB_CONN_IDX].connection;
Marco Varlese191a5942017-10-30 18:17:21 +0100776}
777
778u8 *
779format_sctp_half_open (u8 * s, va_list * args)
780{
781 u32 tci = va_arg (*args, u32);
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100782 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (tci);
783 return format (s, "%U", format_sctp_connection_id, sctp_conn);
Marco Varlese191a5942017-10-30 18:17:21 +0100784}
785
786/* *INDENT OFF* */
787const static transport_proto_vft_t sctp_proto = {
788 .enable = sctp_enable_disable,
789 .bind = sctp_session_bind,
790 .unbind = sctp_session_unbind,
791 .open = sctp_session_open,
792 .close = sctp_session_close,
793 .cleanup = sctp_session_cleanup,
794 .push_header = sctp_push_header,
795 .send_mss = sctp_session_send_mss,
796 .send_space = sctp_session_send_space,
797 .tx_fifo_offset = NULL, //sctp_session_tx_fifo_offset,
798 .get_connection = sctp_session_get_transport,
799 .get_listener = sctp_session_get_listener,
800 .get_half_open = sctp_half_open_session_get_transport,
801 .format_connection = format_sctp_session,
802 .format_listener = format_sctp_listener_session,
803 .format_half_open = format_sctp_half_open,
804};
805
806/* *INDENT ON* */
807
808clib_error_t *
809sctp_init (vlib_main_t * vm)
810{
811 sctp_main_t *tm = vnet_get_sctp_main ();
812 ip_main_t *im = &ip_main;
813 ip_protocol_info_t *pi;
814 /* Session layer, and by implication SCTP, are disabled by default */
815 tm->is_enabled = 0;
816
817 /* Register with IP for header parsing */
818 pi = ip_get_protocol_info (im, IP_PROTOCOL_SCTP);
819 if (pi == 0)
820 return clib_error_return (0, "SCTP protocol info AWOL");
821 pi->format_header = format_sctp_header;
822 pi->unformat_pg_edit = unformat_pg_sctp_header;
823
824 /* Register as transport with session layer */
825 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
826 FIB_PROTOCOL_IP4, sctp4_output_node.index);
827 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
828 FIB_PROTOCOL_IP6, sctp6_output_node.index);
829
830 return 0;
831}
832
833VLIB_INIT_FUNCTION (sctp_init);
834
835/*
836 * fd.io coding-style-patch-verification: ON
837 *
838 * Local Variables:
839 * eval: (c-set-style "gnu")
840 * End:
841 */