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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vnet/sctp/sctp.h>
16 #include <vnet/sctp/sctp_debug.h>
18 sctp_main_t sctp_main;
21 sctp_connection_bind (u32 session_index, transport_endpoint_t * tep)
23 sctp_main_t *tm = &sctp_main;
24 sctp_connection_t *listener;
27 pool_get (tm->listener_pool, listener);
28 memset (listener, 0, sizeof (*listener));
30 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 =
33 listener - tm->listener_pool;
34 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_port = tep->port;
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)
39 if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
41 ip_set (&tep->ip, iface_ip, tep->is_ip4);
43 ip_copy (&listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_ip,
44 &tep->ip, tep->is_ip4);
46 u32 mtu = tep->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
49 vnet_sw_interface_get_mtu (vnet_get_main (), tep->sw_if_index,
51 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].PMTU = mtu;
52 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.is_ip4 = tep->is_ip4;
53 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.proto =
55 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_s_index = session_index;
56 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.fib_index =
58 listener->state = SCTP_STATE_CLOSED;
60 sctp_connection_timers_init (listener);
62 return listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index;
66 sctp_session_bind (u32 session_index, transport_endpoint_t * tep)
68 return sctp_connection_bind (session_index, tep);
72 sctp_connection_unbind (u32 listener_index)
74 sctp_main_t *tm = vnet_get_sctp_main ();
75 sctp_connection_t *sctp_conn;
77 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
79 /* Poison the entry */
81 memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
83 pool_put_index (tm->listener_pool, listener_index);
87 sctp_session_unbind (u32 listener_index)
89 sctp_connection_unbind (listener_index);
94 sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
96 sctp_main_t *tm = &sctp_main;
98 tm->punt_unknown4 = is_add;
100 tm->punt_unknown6 = is_add;
104 sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
105 u16 * lcl_port, u8 is_ip4)
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;
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));
123 port = transport_alloc_local_port (TRANSPORT_PROTO_SCTP, lcl_addr);
126 clib_warning ("Failed to allocate src port");
134 * Initialize all connection timers as invalid
137 sctp_connection_timers_init (sctp_connection_t * sctp_conn)
141 /* Set all to invalid */
142 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
144 sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
146 for (j = 0; j < SCTP_N_TIMERS; j++)
148 sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
154 * Stop all connection timers
157 sctp_connection_timers_reset (sctp_connection_t * sctp_conn)
160 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
162 for (j = 0; j < SCTP_N_TIMERS; j++)
163 sctp_timer_reset (sctp_conn, i, j);
167 const char *sctp_fsm_states[] = {
168 #define _(sym, str) str,
169 foreach_sctp_fsm_state
174 format_sctp_state (u8 * s, va_list * args)
176 u32 state = va_arg (*args, u32);
178 if (state < SCTP_N_STATES)
179 s = format (s, "%s", sctp_fsm_states[state]);
181 s = format (s, "UNKNOWN (%d (0x%x))", state, state);
186 format_sctp_connection_id (u8 * s, va_list * args)
188 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
193 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
195 if (sctp_conn->sub_conn[i].connection.is_ip4)
197 s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
199 sctp_conn->sub_conn[i].connection.thread_index,
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),
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));
212 s = format (s, "%U[#%d][%s] %U:%d->%U:%d",
214 sctp_conn->sub_conn[i].connection.thread_index,
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),
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));
230 format_sctp_connection (u8 * s, va_list * args)
232 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
233 u32 verbose = va_arg (*args, u32);
237 s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
240 s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
247 * Initialize connection send variables.
250 sctp_init_snd_vars (sctp_connection_t * sctp_conn)
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
260 sctp_set_time_now (vlib_get_thread_index ());
261 time_now = sctp_time_now ();
263 sctp_conn->local_initial_tsn = random_u32 (&time_now);
264 sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
265 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
267 sctp_conn->remote_initial_tsn = 0x0;
268 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
271 always_inline sctp_connection_t *
272 sctp_sub_connection_add (u8 thread_index)
274 sctp_main_t *tm = vnet_get_sctp_main ();
275 sctp_connection_t *sctp_conn = tm->connections[thread_index];
277 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
279 ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
281 sctp_conn->sub_conn[subconn_idx].connection.c_index =
282 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index;
283 sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
284 sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
290 sctp_sub_connection_add_ip4 (vlib_main_t * vm,
291 ip4_address_t * lcl_addr,
292 ip4_address_t * rmt_addr)
294 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
296 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
298 if (subconn_idx == MAX_SCTP_CONNECTIONS)
299 return SCTP_ERROR_MAX_CONNECTIONS;
301 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
302 &lcl_addr, sizeof (lcl_addr));
304 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
305 &rmt_addr, sizeof (rmt_addr));
307 sctp_conn->forming_association_changed = 1;
309 return SCTP_ERROR_NONE;
313 sctp_sub_connection_del_ip4 (ip4_address_t * lcl_addr,
314 ip4_address_t * rmt_addr)
316 sctp_main_t *sctp_main = vnet_get_sctp_main ();
318 u32 thread_idx = vlib_get_thread_index ();
321 ASSERT (thread_idx == 0);
323 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
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;
333 if (!sub_conn->connection.is_ip4)
335 if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
336 rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
338 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
339 sctp_conn->forming_association_changed = 1;
343 return SCTP_ERROR_NONE;
347 sctp_sub_connection_add_ip6 (vlib_main_t * vm,
348 ip6_address_t * lcl_addr,
349 ip6_address_t * rmt_addr)
351 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
353 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
355 if (subconn_idx == MAX_SCTP_CONNECTIONS)
356 return SCTP_ERROR_MAX_CONNECTIONS;
358 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
359 &lcl_addr, sizeof (lcl_addr));
361 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
362 &rmt_addr, sizeof (rmt_addr));
364 sctp_conn->forming_association_changed = 1;
366 return SCTP_ERROR_NONE;
370 sctp_sub_connection_del_ip6 (ip6_address_t * lcl_addr,
371 ip6_address_t * rmt_addr)
373 sctp_main_t *sctp_main = vnet_get_sctp_main ();
375 u32 thread_idx = vlib_get_thread_index ();
378 ASSERT (thread_idx == 0);
380 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
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;
390 if (!sub_conn->connection.is_ip4)
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]))
397 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
398 sctp_conn->forming_association_changed = 1;
402 return SCTP_ERROR_NONE;
406 sctp_configure (sctp_user_configuration_t config)
408 sctp_main_t *sctp_main = vnet_get_sctp_main ();
410 u32 thread_idx = vlib_get_thread_index ();
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 =
421 sctp_connection_new (u8 thread_index)
423 sctp_main_t *sctp_main = vnet_get_sctp_main ();
424 sctp_connection_t *sctp_conn;
426 pool_get (sctp_main->connections[thread_index], sctp_conn);
427 memset (sctp_conn, 0, sizeof (*sctp_conn));
428 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 =
431 sctp_conn - sctp_main->connections[thread_index];
432 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_thread_index = thread_index;
433 sctp_conn->local_tag = 0;
439 sctp_half_open_connection_new (u8 thread_index)
441 sctp_main_t *tm = vnet_get_sctp_main ();
442 sctp_connection_t *sctp_conn = 0;
443 ASSERT (vlib_get_thread_index () == 0);
444 pool_get (tm->half_open_connections, sctp_conn);
445 memset (sctp_conn, 0, sizeof (*sctp_conn));
446 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
447 sctp_conn - tm->half_open_connections;
448 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
449 SCTP_PRIMARY_PATH_IDX;
454 sctp_connection_open (transport_endpoint_t * rmt)
456 sctp_main_t *tm = vnet_get_sctp_main ();
457 sctp_connection_t *sctp_conn;
458 ip46_address_t lcl_addr;
463 u8 idx = SCTP_PRIMARY_PATH_IDX;
466 * Allocate local endpoint
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,
473 rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_SCTP,
474 rmt, &lcl_addr, &lcl_port);
480 * Create connection and send INIT CHUNK
482 thread_id = vlib_get_thread_index ();
483 ASSERT (thread_id == 0);
485 clib_spinlock_lock_if_init (&tm->half_open_lock);
486 sctp_conn = sctp_half_open_connection_new (thread_id);
487 u32 mtu = rmt->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
490 vnet_sw_interface_get_mtu (vnet_get_main (), rmt->sw_if_index,
492 sctp_conn->sub_conn[idx].PMTU = mtu;
494 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);
497 sctp_conn->sub_conn[idx].subconn_idx = idx;
498 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;
504 sctp_connection_timers_init (sctp_conn);
505 /* The other connection vars will be initialized after INIT_ACK chunk received */
506 sctp_init_snd_vars (sctp_conn);
508 sctp_send_init (sctp_conn);
510 clib_spinlock_unlock_if_init (&tm->half_open_lock);
512 return sctp_conn->sub_conn[idx].connection.c_index;
516 * Cleans up connection state.
521 sctp_connection_cleanup (sctp_connection_t * sctp_conn)
523 sctp_main_t *tm = &sctp_main;
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,
529 &sctp_conn->sub_conn[i].connection.lcl_ip,
530 sctp_conn->sub_conn[i].connection.lcl_port);
533 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.thread_index;
535 /* Make sure all timers are cleared */
536 sctp_connection_timers_reset (sctp_conn);
538 /* Poison the entry */
540 memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
541 pool_put (tm->connections[thread_index], sctp_conn);
545 sctp_session_open (transport_endpoint_t * tep)
547 return sctp_connection_open (tep);
551 sctp_check_outstanding_data_chunks (sctp_connection_t * sctp_conn)
554 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
556 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
559 if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
560 sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
563 ("Connection %u has still DATA to be enqueued inboud / outboud",
564 sctp_conn->sub_conn[i].connection.c_index);
569 return 0; /* Indicates no more data to be read/sent */
573 sctp_connection_close (sctp_connection_t * sctp_conn)
575 SCTP_DBG ("Closing connection %u...",
576 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index);
578 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
580 sctp_send_shutdown (sctp_conn);
584 sctp_session_close (u32 conn_index, u32 thread_index)
586 ASSERT (thread_index == 0);
588 sctp_connection_t *sctp_conn =
589 sctp_connection_get (conn_index, thread_index);
590 if (sctp_conn != NULL)
591 sctp_connection_close (sctp_conn);
595 sctp_session_cleanup (u32 conn_index, u32 thread_index)
597 sctp_connection_t *sctp_conn =
598 sctp_connection_get (conn_index, thread_index);
600 if (sctp_conn != NULL)
602 sctp_connection_timers_reset (sctp_conn);
603 /* Wait for the session tx events to clear */
604 sctp_conn->state = SCTP_STATE_CLOSED;
609 * Compute maximum segment size for session layer.
612 sctp_session_send_mss (transport_connection_t * trans_conn)
614 sctp_connection_t *sctp_conn =
615 sctp_get_connection_from_transport (trans_conn);
617 if (sctp_conn == NULL)
619 SCTP_DBG ("sctp_conn == NULL");
623 update_cwnd (sctp_conn);
624 update_smallest_pmtu_idx (sctp_conn);
626 u8 idx = sctp_data_subconn_select (sctp_conn);
628 return sctp_conn->sub_conn[idx].cwnd;
632 sctp_snd_space (sctp_connection_t * sctp_conn)
634 /* RFC 4096 Section 6.1; point (A) */
635 if (sctp_conn->peer_rwnd == 0)
638 u8 idx = sctp_data_subconn_select (sctp_conn);
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);
644 if (available_wnd <= flight_size)
647 /* Finally, let's subtract the DATA chunk headers overhead */
648 return available_wnd -
650 sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
654 * Compute TX window session is allowed to fill.
657 sctp_session_send_space (transport_connection_t * trans_conn)
659 sctp_connection_t *sctp_conn =
660 sctp_get_connection_from_transport (trans_conn);
662 return sctp_snd_space (sctp_conn);
665 transport_connection_t *
666 sctp_session_get_transport (u32 conn_index, u32 thread_index)
668 sctp_connection_t *sctp_conn =
669 sctp_connection_get (conn_index, thread_index);
671 if (PREDICT_TRUE (sctp_conn != NULL))
672 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
677 transport_connection_t *
678 sctp_session_get_listener (u32 listener_index)
680 sctp_main_t *tm = vnet_get_sctp_main ();
681 sctp_connection_t *sctp_conn;
682 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
683 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
687 format_sctp_session (u8 * s, va_list * args)
689 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;
694 tc = sctp_connection_get (tci, thread_index);
696 s = format (s, "%U", format_sctp_connection, tc, verbose);
698 s = format (s, "empty\n");
703 format_sctp_listener_session (u8 * s, va_list * args)
705 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);
711 sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
713 sctp_connection_t *sctp_conn;
715 sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
716 /* note: the connection may have already disappeared */
717 if (PREDICT_FALSE (sctp_conn == 0))
720 SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
722 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
723 SCTP_PATH_MAX_RETRANS)
725 // The remote-peer is considered to be unreachable hence shutting down
726 u8 i, total_subs_down = 1;
727 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
729 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
732 u32 now = sctp_time_now ();
733 if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
735 total_subs_down += 1;
736 sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
740 if (total_subs_down == MAX_SCTP_CONNECTIONS)
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
745 [SCTP_PRIMARY_PATH_IDX].connection);
747 sctp_connection_timers_reset (sctp_conn);
749 sctp_connection_cleanup (sctp_conn);
756 case SCTP_TIMER_T1_INIT:
757 sctp_send_init (sctp_conn);
759 case SCTP_TIMER_T1_COOKIE:
760 sctp_send_cookie_echo (sctp_conn);
762 case SCTP_TIMER_T2_SHUTDOWN:
763 sctp_send_shutdown (sctp_conn);
765 case SCTP_TIMER_T3_RXTX:
766 sctp_timer_reset (sctp_conn, conn_index, timer_id);
767 sctp_conn->flags |= SCTP_CONN_RECOVERY;
768 sctp_data_retransmit (sctp_conn);
770 case SCTP_TIMER_T4_HEARTBEAT:
771 sctp_timer_reset (sctp_conn, conn_index, timer_id);
777 sctp_send_heartbeat (sctp_conn);
781 sctp_expired_timers_dispatch (u32 * expired_timers)
784 u32 connection_index, timer_id;
786 for (i = 0; i < vec_len (expired_timers); i++)
788 /* Get session index and timer id */
789 connection_index = expired_timers[i] & 0x0FFFFFFF;
790 timer_id = expired_timers[i] >> 28;
792 SCTP_DBG ("Expired timer ID: %u", timer_id);
794 /* Handle expiration */
795 sctp_expired_timers_cb (connection_index, timer_id);
800 sctp_initialize_timer_wheels (sctp_main_t * tm)
802 tw_timer_wheel_16t_2w_512sl_t *tw;
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);
814 sctp_main_enable (vlib_main_t * vm)
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;
821 sctp_connection_t *sctp_conn __attribute__ ((unused));
822 u32 preallocated_connections_per_thread;
824 if ((error = vlib_call_init_function (vm, ip_main_init)))
826 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
828 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
835 ip4_register_protocol (IP_PROTOCOL_SCTP, sctp4_input_node.index);
836 ip6_register_protocol (IP_PROTOCOL_SCTP, sctp6_input_node.index);
839 * Initialize data structures
842 num_threads = 1 /* main thread */ + vtm->n_threads;
843 vec_validate (tm->connections, num_threads - 1);
846 * Preallocate connections. Assume that thread 0 won't
847 * use preallocated threads when running multi-core
849 if (num_threads == 1)
852 preallocated_connections_per_thread = tm->preallocated_connections;
857 preallocated_connections_per_thread =
858 tm->preallocated_connections / (num_threads - 1);
860 for (; thread < num_threads; thread++)
862 if (preallocated_connections_per_thread)
863 pool_init_fixed (tm->connections[thread],
864 preallocated_connections_per_thread);
867 /* Initialize per worker thread tx buffers (used for control messages) */
868 vec_validate (tm->tx_buffers, num_threads - 1);
870 /* Initialize timer wheels */
871 vec_validate (tm->timer_wheels, num_threads - 1);
872 sctp_initialize_timer_wheels (tm);
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;
881 clib_spinlock_init (&tm->half_open_lock);
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);
889 tm->bytes_per_buffer = vlib_buffer_free_list_buffer_size
890 (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
892 vec_validate (tm->time_now, num_threads - 1);
897 sctp_enable_disable (vlib_main_t * vm, u8 is_en)
901 if (sctp_main.is_enabled)
904 return sctp_main_enable (vm);
908 sctp_main.is_enabled = 0;
914 transport_connection_t *
915 sctp_half_open_session_get_transport (u32 conn_index)
917 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
918 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
922 format_sctp_half_open (u8 * s, va_list * args)
924 u32 tci = va_arg (*args, u32);
925 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (tci);
926 return format (s, "%U", format_sctp_connection_id, sctp_conn);
930 sctp_update_time (f64 now, u8 thread_index)
932 sctp_set_time_now (thread_index);
933 tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
935 sctp_flush_frames_to_output (thread_index);
939 const 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,
949 .update_time = sctp_update_time,
950 .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,
956 .tx_type = TRANSPORT_TX_DEQUEUE,
957 .service_type = TRANSPORT_SERVICE_VC,
963 sctp_init (vlib_main_t * vm)
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 */
971 /* Register with IP for header parsing */
972 pi = ip_get_protocol_info (im, IP_PROTOCOL_SCTP);
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;
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);
984 sctp_api_reference ();
989 VLIB_INIT_FUNCTION (sctp_init);
992 * fd.io coding-style-patch-verification: ON
995 * eval: (c-set-style "gnu")