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.
16 #include <vnet/plugin/plugin.h>
17 #include <vpp/app/version.h>
19 #include <sctp/sctp.h>
20 #include <sctp/sctp_debug.h>
22 sctp_main_t sctp_main;
25 sctp_connection_bind (u32 session_index, transport_endpoint_t * tep)
27 sctp_main_t *tm = &sctp_main;
28 sctp_connection_t *listener;
32 pool_get (tm->listener_pool, listener);
33 clib_memset (listener, 0, sizeof (*listener));
35 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
36 SCTP_PRIMARY_PATH_IDX;
37 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
38 listener - tm->listener_pool;
39 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_port = tep->port;
41 /* If we are provided a sw_if_index, bind using one of its IPs */
42 if (ip_is_zero (&tep->ip, 1) && tep->sw_if_index != ENDPOINT_INVALID_INDEX)
44 if ((iface_ip = ip_interface_get_first_ip (tep->sw_if_index,
46 ip_set (&tep->ip, iface_ip, tep->is_ip4);
48 ip_copy (&listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.lcl_ip,
49 &tep->ip, tep->is_ip4);
51 if (tep->sw_if_index != ENDPOINT_INVALID_INDEX)
52 mtu = tep->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
55 vnet_sw_interface_get_mtu (vnet_get_main (), tep->sw_if_index,
58 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].PMTU = mtu;
59 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.is_ip4 = tep->is_ip4;
60 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.proto =
62 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_s_index = session_index;
63 listener->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.fib_index =
65 listener->state = SCTP_STATE_CLOSED;
67 sctp_connection_timers_init (listener);
69 return listener->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index;
73 sctp_session_bind (u32 session_index, transport_endpoint_t * tep)
75 return sctp_connection_bind (session_index, tep);
79 sctp_connection_unbind (u32 listener_index)
81 sctp_main_t *tm = vnet_get_sctp_main ();
82 sctp_connection_t *sctp_conn;
84 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
86 /* Poison the entry */
88 clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
90 pool_put_index (tm->listener_pool, listener_index);
94 sctp_session_unbind (u32 listener_index)
96 sctp_connection_unbind (listener_index);
101 sctp_punt_unknown (vlib_main_t * vm, u8 is_ip4, u8 is_add)
103 sctp_main_t *tm = &sctp_main;
105 tm->punt_unknown4 = is_add;
107 tm->punt_unknown6 = is_add;
111 sctp_alloc_custom_local_endpoint (sctp_main_t * tm, ip46_address_t * lcl_addr,
112 u16 * lcl_port, u8 is_ip4)
117 index = tm->last_v4_address_rotor++;
118 if (tm->last_v4_address_rotor >= vec_len (tm->ip4_src_addresses))
119 tm->last_v4_address_rotor = 0;
120 lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
124 index = tm->last_v6_address_rotor++;
125 if (tm->last_v6_address_rotor >= vec_len (tm->ip6_src_addresses))
126 tm->last_v6_address_rotor = 0;
127 clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
128 sizeof (ip6_address_t));
130 port = transport_alloc_local_port (TRANSPORT_PROTO_SCTP, lcl_addr);
133 clib_warning ("Failed to allocate src port");
141 * Initialize all connection timers as invalid
144 sctp_connection_timers_init (sctp_connection_t * sctp_conn)
148 /* Set all to invalid */
149 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
151 sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
153 for (j = 0; j < SCTP_N_TIMERS; j++)
155 sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
161 * Stop all connection timers
164 sctp_connection_timers_reset (sctp_connection_t * sctp_conn)
167 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
169 for (j = 0; j < SCTP_N_TIMERS; j++)
170 sctp_timer_reset (sctp_conn, i, j);
174 const char *sctp_fsm_states[] = {
175 #define _(sym, str) str,
176 foreach_sctp_fsm_state
181 format_sctp_state (u8 * s, va_list * args)
183 u32 state = va_arg (*args, u32);
185 if (state < SCTP_N_STATES)
186 s = format (s, "%s", sctp_fsm_states[state]);
188 s = format (s, "UNKNOWN (%d (0x%x))", state, state);
193 format_sctp_connection_id (u8 * s, va_list * args)
195 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
200 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
202 if (i > 0 && sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
204 if (sctp_conn->sub_conn[i].connection.is_ip4)
206 s = format (s, "[#%d][%s] %U:%d->%U:%d",
207 sctp_conn->sub_conn[i].connection.thread_index,
210 &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
211 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
212 connection.lcl_port),
214 &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
215 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
216 connection.rmt_port));
220 s = format (s, "[#%d][%s] %U:%d->%U:%d",
221 sctp_conn->sub_conn[i].connection.thread_index,
224 &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
225 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
226 connection.lcl_port),
228 &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
229 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
230 connection.rmt_port));
237 format_sctp_connection (u8 * s, va_list * args)
239 sctp_connection_t *sctp_conn = va_arg (*args, sctp_connection_t *);
240 u32 verbose = va_arg (*args, u32);
244 s = format (s, "%-50U", format_sctp_connection_id, sctp_conn);
247 s = format (s, "%-15U", format_sctp_state, sctp_conn->state);
249 s = format (s, "\n");
256 * Initialize connection send variables.
259 sctp_init_snd_vars (sctp_connection_t * sctp_conn)
263 * We use the time to randomize iss and for setting up the initial
264 * timestamp. Make sure it's updated otherwise syn and ack in the
265 * handshake may make it look as if time has flown in the opposite
269 sctp_set_time_now (vlib_get_thread_index ());
270 time_now = sctp_time_now ();
272 sctp_conn->local_initial_tsn = random_u32 (&time_now);
273 sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
274 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
276 sctp_conn->remote_initial_tsn = 0x0;
277 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
280 always_inline sctp_connection_t *
281 sctp_sub_connection_add (u8 thread_index)
283 sctp_main_t *tm = vnet_get_sctp_main ();
284 sctp_connection_t *sctp_conn = tm->connections[thread_index];
286 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
288 ASSERT (subconn_idx < MAX_SCTP_CONNECTIONS);
290 sctp_conn->sub_conn[subconn_idx].connection.c_index =
291 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index;
292 sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
293 sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
299 sctp_sub_connection_add_ip4 (vlib_main_t * vm,
300 ip4_address_t * lcl_addr,
301 ip4_address_t * rmt_addr)
303 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
305 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
307 if (subconn_idx == MAX_SCTP_CONNECTIONS)
308 return SCTP_ERROR_MAX_CONNECTIONS;
310 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
311 &lcl_addr, sizeof (lcl_addr));
313 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
314 &rmt_addr, sizeof (rmt_addr));
316 sctp_conn->forming_association_changed = 1;
318 return SCTP_ERROR_NONE;
322 sctp_sub_connection_del_ip4 (ip4_address_t * lcl_addr,
323 ip4_address_t * rmt_addr)
325 sctp_main_t *sctp_main = vnet_get_sctp_main ();
327 u32 thread_idx = vlib_get_thread_index ();
330 ASSERT (thread_idx == 0);
332 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
334 sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
335 sctp_sub_connection_t *sub_conn =
336 &sctp_main->connections[thread_idx]->sub_conn[i];
337 ip46_address_t *lcl_ip =
338 &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
339 ip46_address_t *rmt_ip =
340 &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
342 if (!sub_conn->connection.is_ip4)
344 if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
345 rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
347 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
348 sctp_conn->forming_association_changed = 1;
352 return SCTP_ERROR_NONE;
356 sctp_sub_connection_add_ip6 (vlib_main_t * vm,
357 ip6_address_t * lcl_addr,
358 ip6_address_t * rmt_addr)
360 sctp_connection_t *sctp_conn = sctp_sub_connection_add (vm->thread_index);
362 u8 subconn_idx = sctp_next_avail_subconn (sctp_conn);
364 if (subconn_idx == MAX_SCTP_CONNECTIONS)
365 return SCTP_ERROR_MAX_CONNECTIONS;
367 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
368 &lcl_addr, sizeof (lcl_addr));
370 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
371 &rmt_addr, sizeof (rmt_addr));
373 sctp_conn->forming_association_changed = 1;
375 return SCTP_ERROR_NONE;
379 sctp_sub_connection_del_ip6 (ip6_address_t * lcl_addr,
380 ip6_address_t * rmt_addr)
382 sctp_main_t *sctp_main = vnet_get_sctp_main ();
384 u32 thread_idx = vlib_get_thread_index ();
387 ASSERT (thread_idx == 0);
389 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
391 sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
392 sctp_sub_connection_t *sub_conn =
393 &sctp_main->connections[thread_idx]->sub_conn[i];
394 ip46_address_t *lcl_ip =
395 &sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
396 ip46_address_t *rmt_ip =
397 &sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
399 if (!sub_conn->connection.is_ip4)
401 if ((lcl_ip->ip6.as_u64[0] == lcl_addr->as_u64[0]
402 && lcl_ip->ip6.as_u64[1] == lcl_addr->as_u64[1])
403 && (rmt_ip->ip6.as_u64[0] == rmt_addr->as_u64[0]
404 && rmt_ip->ip6.as_u64[1] == rmt_addr->as_u64[1]))
406 sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
407 sctp_conn->forming_association_changed = 1;
411 return SCTP_ERROR_NONE;
415 sctp_configure (sctp_user_configuration_t config)
417 sctp_main_t *sctp_main = vnet_get_sctp_main ();
419 u32 thread_idx = vlib_get_thread_index ();
421 sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
422 config.never_delay_sack;
423 sctp_main->connections[thread_idx]->conn_config.never_bundle =
430 sctp_connection_new (u8 thread_index)
432 sctp_main_t *sctp_main = vnet_get_sctp_main ();
433 sctp_connection_t *sctp_conn;
435 pool_get (sctp_main->connections[thread_index], sctp_conn);
436 clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
437 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
438 SCTP_PRIMARY_PATH_IDX;
439 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
440 sctp_conn - sctp_main->connections[thread_index];
441 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_thread_index = thread_index;
442 sctp_conn->local_tag = 0;
448 sctp_half_open_connection_new (u8 thread_index)
450 sctp_main_t *tm = vnet_get_sctp_main ();
451 sctp_connection_t *sctp_conn = 0;
452 ASSERT (vlib_get_thread_index () == 0);
453 pool_get (tm->half_open_connections, sctp_conn);
454 clib_memset (sctp_conn, 0, sizeof (*sctp_conn));
455 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].c_c_index =
456 sctp_conn - tm->half_open_connections;
457 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].subconn_idx =
458 SCTP_PRIMARY_PATH_IDX;
463 sctp_connection_open (transport_endpoint_cfg_t * rmt)
465 sctp_main_t *tm = vnet_get_sctp_main ();
466 sctp_connection_t *sctp_conn;
467 ip46_address_t lcl_addr;
473 u8 idx = SCTP_PRIMARY_PATH_IDX;
476 * Allocate local endpoint
478 if ((rmt->is_ip4 && vec_len (tm->ip4_src_addresses))
479 || (!rmt->is_ip4 && vec_len (tm->ip6_src_addresses)))
480 rv = sctp_alloc_custom_local_endpoint (tm, &lcl_addr, &lcl_port,
483 rv = transport_alloc_local_endpoint (TRANSPORT_PROTO_SCTP,
484 rmt, &lcl_addr, &lcl_port);
490 * Create connection and send INIT CHUNK
492 thread_id = vlib_get_thread_index ();
493 ASSERT (thread_id == 0);
495 clib_spinlock_lock_if_init (&tm->half_open_lock);
496 sctp_conn = sctp_half_open_connection_new (thread_id);
497 if (rmt->peer.sw_if_index != ENDPOINT_INVALID_INDEX)
498 mtu = rmt->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
499 rmt->peer.sw_if_index,
501 vnet_sw_interface_get_mtu (vnet_get_main (), rmt->peer.sw_if_index,
503 sctp_conn->sub_conn[idx].PMTU = mtu;
505 transport_connection_t *trans_conn = &sctp_conn->sub_conn[idx].connection;
506 ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
507 ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
508 sctp_conn->sub_conn[idx].subconn_idx = idx;
509 trans_conn->rmt_port = rmt->port;
510 trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
511 trans_conn->is_ip4 = rmt->is_ip4;
512 trans_conn->proto = TRANSPORT_PROTO_SCTP;
513 trans_conn->fib_index = rmt->fib_index;
515 sctp_connection_timers_init (sctp_conn);
516 /* The other connection vars will be initialized after INIT_ACK chunk received */
517 sctp_init_snd_vars (sctp_conn);
519 sctp_send_init (sctp_conn);
521 clib_spinlock_unlock_if_init (&tm->half_open_lock);
523 return sctp_conn->sub_conn[idx].connection.c_index;
527 * Cleans up connection state.
532 sctp_connection_cleanup (sctp_connection_t * sctp_conn)
534 sctp_main_t *tm = &sctp_main;
537 /* Cleanup local endpoint if this was an active connect */
538 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
539 transport_endpoint_cleanup (TRANSPORT_PROTO_SCTP,
540 &sctp_conn->sub_conn[i].connection.lcl_ip,
541 sctp_conn->sub_conn[i].connection.lcl_port);
544 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.thread_index;
546 /* Make sure all timers are cleared */
547 sctp_connection_timers_reset (sctp_conn);
549 /* Poison the entry */
551 clib_memset (sctp_conn, 0xFA, sizeof (*sctp_conn));
552 pool_put (tm->connections[thread_index], sctp_conn);
556 sctp_session_open (transport_endpoint_cfg_t * tep)
558 return sctp_connection_open (tep);
562 sctp_check_outstanding_data_chunks (sctp_connection_t * sctp_conn)
565 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
567 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
570 if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
571 sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
574 ("Connection %u has still DATA to be enqueued inboud / outboud",
575 sctp_conn->sub_conn[i].connection.c_index);
580 return 0; /* Indicates no more data to be read/sent */
584 sctp_connection_close (sctp_connection_t * sctp_conn)
586 SCTP_DBG ("Closing connection %u...",
587 sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection.c_index);
589 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
591 sctp_send_shutdown (sctp_conn);
595 sctp_session_close (u32 conn_index, u32 thread_index)
597 ASSERT (thread_index == 0);
599 sctp_connection_t *sctp_conn =
600 sctp_connection_get (conn_index, thread_index);
601 if (sctp_conn != NULL)
602 sctp_connection_close (sctp_conn);
606 sctp_session_cleanup (u32 conn_index, u32 thread_index)
608 sctp_connection_t *sctp_conn =
609 sctp_connection_get (conn_index, thread_index);
611 if (sctp_conn != NULL)
613 sctp_connection_timers_reset (sctp_conn);
614 /* Wait for the session tx events to clear */
615 sctp_conn->state = SCTP_STATE_CLOSED;
620 * Compute maximum segment size for session layer.
623 sctp_session_send_mss (transport_connection_t * trans_conn)
625 sctp_connection_t *sctp_conn =
626 sctp_get_connection_from_transport (trans_conn);
628 if (sctp_conn == NULL)
630 SCTP_DBG ("sctp_conn == NULL");
634 update_cwnd (sctp_conn);
635 update_smallest_pmtu_idx (sctp_conn);
637 u8 idx = sctp_data_subconn_select (sctp_conn);
638 return sctp_conn->sub_conn[idx].cwnd;
642 sctp_snd_space (sctp_connection_t * sctp_conn)
644 /* RFC 4096 Section 6.1; point (A) */
645 if (sctp_conn->peer_rwnd == 0)
648 u8 idx = sctp_data_subconn_select (sctp_conn);
651 clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
652 int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
654 if (available_wnd <= flight_size)
657 /* Finally, let's subtract the DATA chunk headers overhead */
658 return available_wnd -
660 sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t);
664 * Compute TX window session is allowed to fill.
667 sctp_session_send_space (transport_connection_t * trans_conn)
669 sctp_connection_t *sctp_conn =
670 sctp_get_connection_from_transport (trans_conn);
672 return sctp_snd_space (sctp_conn);
675 transport_connection_t *
676 sctp_session_get_transport (u32 conn_index, u32 thread_index)
678 sctp_connection_t *sctp_conn =
679 sctp_connection_get (conn_index, thread_index);
681 if (PREDICT_TRUE (sctp_conn != NULL))
682 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
687 transport_connection_t *
688 sctp_session_get_listener (u32 listener_index)
690 sctp_main_t *tm = vnet_get_sctp_main ();
691 sctp_connection_t *sctp_conn;
692 sctp_conn = pool_elt_at_index (tm->listener_pool, listener_index);
693 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
697 format_sctp_session (u8 * s, va_list * args)
699 u32 tci = va_arg (*args, u32);
700 u32 thread_index = va_arg (*args, u32);
701 u32 verbose = va_arg (*args, u32);
702 sctp_connection_t *tc;
704 tc = sctp_connection_get (tci, thread_index);
706 s = format (s, "%U", format_sctp_connection, tc, verbose);
708 s = format (s, "empty\n");
713 format_sctp_listener_session (u8 * s, va_list * args)
715 u32 tci = va_arg (*args, u32);
716 u32 __clib_unused thread_index = va_arg (*args, u32);
717 sctp_connection_t *tc = sctp_listener_get (tci);
718 return format (s, "%U", format_sctp_connection_id, tc);
722 sctp_expired_timers_cb (u32 conn_index, u32 timer_id)
724 sctp_connection_t *sctp_conn;
726 SCTP_DBG ("%s expired", sctp_timer_to_string (timer_id));
728 sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
729 /* note: the connection may have already disappeared */
730 if (PREDICT_FALSE (sctp_conn == 0))
733 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
734 SCTP_PATH_MAX_RETRANS)
736 // The remote-peer is considered to be unreachable hence shutting down
737 u8 i, total_subs_down = 1;
738 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
740 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
743 u32 now = sctp_time_now ();
744 if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
746 total_subs_down += 1;
747 sctp_conn->sub_conn[i].state = SCTP_SUBCONN_STATE_DOWN;
751 if (total_subs_down == MAX_SCTP_CONNECTIONS)
753 /* Start cleanup. App wasn't notified yet so use delete notify as
754 * opposed to delete to cleanup session layer state. */
755 session_transport_delete_notify (&sctp_conn->sub_conn
756 [SCTP_PRIMARY_PATH_IDX].connection);
758 sctp_connection_timers_reset (sctp_conn);
760 sctp_connection_cleanup (sctp_conn);
767 case SCTP_TIMER_T1_INIT:
768 sctp_send_init (sctp_conn);
770 case SCTP_TIMER_T1_COOKIE:
771 sctp_send_cookie_echo (sctp_conn);
773 case SCTP_TIMER_T2_SHUTDOWN:
774 sctp_send_shutdown (sctp_conn);
776 case SCTP_TIMER_T3_RXTX:
777 sctp_timer_reset (sctp_conn, conn_index, timer_id);
778 sctp_conn->flags |= SCTP_CONN_RECOVERY;
779 sctp_data_retransmit (sctp_conn);
781 case SCTP_TIMER_T4_HEARTBEAT:
782 sctp_timer_reset (sctp_conn, conn_index, timer_id);
788 sctp_send_heartbeat (sctp_conn);
792 sctp_expired_timers_dispatch (u32 * expired_timers)
795 u32 connection_index, timer_id;
797 for (i = 0; i < vec_len (expired_timers); i++)
799 /* Get session index and timer id */
800 connection_index = expired_timers[i] & 0x0FFFFFFF;
801 timer_id = expired_timers[i] >> 28;
803 SCTP_DBG ("Expired timer ID: %u", timer_id);
805 /* Handle expiration */
806 sctp_expired_timers_cb (connection_index, timer_id);
811 sctp_initialize_timer_wheels (sctp_main_t * tm)
813 tw_timer_wheel_16t_2w_512sl_t *tw;
815 foreach_vlib_main (({
816 tw = &tm->timer_wheels[ii];
817 tw_timer_wheel_init_16t_2w_512sl (tw, sctp_expired_timers_dispatch,
818 100e-3 /* timer period 100ms */ , ~0);
819 tw->last_run_time = vlib_time_now (this_vlib_main);
825 sctp_main_enable (vlib_main_t * vm)
827 sctp_main_t *tm = vnet_get_sctp_main ();
828 vlib_thread_main_t *vtm = vlib_get_thread_main ();
829 clib_error_t *error = 0;
832 sctp_connection_t *sctp_conn __attribute__ ((unused));
833 u32 preallocated_connections_per_thread;
835 if ((error = vlib_call_init_function (vm, ip_main_init)))
837 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
839 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
846 ip4_register_protocol (IP_PROTOCOL_SCTP, sctp4_input_node.index);
847 ip6_register_protocol (IP_PROTOCOL_SCTP, sctp6_input_node.index);
850 * Initialize data structures
853 num_threads = 1 /* main thread */ + vtm->n_threads;
854 vec_validate (tm->connections, num_threads - 1);
857 * Preallocate connections. Assume that thread 0 won't
858 * use preallocated threads when running multi-core
860 if (num_threads == 1)
863 preallocated_connections_per_thread = tm->preallocated_connections;
868 preallocated_connections_per_thread =
869 tm->preallocated_connections / (num_threads - 1);
871 for (; thread < num_threads; thread++)
873 if (preallocated_connections_per_thread)
874 pool_init_fixed (tm->connections[thread],
875 preallocated_connections_per_thread);
878 /* Initialize per worker thread tx buffers (used for control messages) */
879 vec_validate (tm->tx_buffers, num_threads - 1);
881 /* Initialize timer wheels */
882 vec_validate (tm->timer_wheels, num_threads - 1);
883 sctp_initialize_timer_wheels (tm);
885 /* Initialize clocks per tick for SCTP timestamp. Used to compute
886 * monotonically increasing timestamps. */
887 tm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
888 / SCTP_TSTAMP_RESOLUTION;
892 clib_spinlock_init (&tm->half_open_lock);
895 vec_validate (tm->tx_frames[0], num_threads - 1);
896 vec_validate (tm->tx_frames[1], num_threads - 1);
897 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
898 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
900 tm->bytes_per_buffer = vlib_buffer_get_default_data_size (vm);
902 vec_validate (tm->time_now, num_threads - 1);
907 sctp_transport_enable_disable (vlib_main_t * vm, u8 is_en)
911 if (sctp_main.is_enabled)
914 return sctp_main_enable (vm);
918 sctp_main.is_enabled = 0;
924 transport_connection_t *
925 sctp_half_open_session_get_transport (u32 conn_index)
927 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (conn_index);
928 return &sctp_conn->sub_conn[SCTP_PRIMARY_PATH_IDX].connection;
932 format_sctp_half_open (u8 * s, va_list * args)
934 u32 tci = va_arg (*args, u32);
935 u32 __clib_unused thread_index = va_arg (*args, u32);
936 sctp_connection_t *sctp_conn = sctp_half_open_connection_get (tci);
937 return format (s, "%U", format_sctp_connection_id, sctp_conn);
941 sctp_update_time (f64 now, u8 thread_index)
943 sctp_set_time_now (thread_index);
944 tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
946 sctp_flush_frames_to_output (thread_index);
950 static const transport_proto_vft_t sctp_proto = {
951 .enable = sctp_transport_enable_disable,
952 .start_listen = sctp_session_bind,
953 .stop_listen = sctp_session_unbind,
954 .connect = sctp_session_open,
955 .close = sctp_session_close,
956 .cleanup = sctp_session_cleanup,
957 .push_header = sctp_push_header,
958 .send_mss = sctp_session_send_mss,
959 .send_space = sctp_session_send_space,
960 .update_time = sctp_update_time,
961 .get_connection = sctp_session_get_transport,
962 .get_listener = sctp_session_get_listener,
963 .get_half_open = sctp_half_open_session_get_transport,
964 .format_connection = format_sctp_session,
965 .format_listener = format_sctp_listener_session,
966 .format_half_open = format_sctp_half_open,
967 .transport_options = {
968 .tx_type = TRANSPORT_TX_DEQUEUE,
969 .service_type = TRANSPORT_SERVICE_VC,
975 sctp_enable_disable (vlib_main_t * vm, u8 is_en)
977 sctp_main_t *sm = vnet_get_sctp_main ();
978 ip_main_t *im = &ip_main;
979 ip_protocol_info_t *pi;
982 if (!sm->is_init && is_en)
984 node = vlib_get_node_by_name (vm, (u8 *) "sctp4-established");
985 sm->sctp4_established_phase_node_index = node->index;
987 node = vlib_get_node_by_name (vm, (u8 *) "sctp6-established");
988 sm->sctp6_established_phase_node_index = node->index;
992 /* Register with IP for header parsing */
993 pi = ip_get_protocol_info (im, IP_PROTOCOL_SCTP);
995 return clib_error_return (0, "SCTP protocol info AWOL");
996 pi->format_header = format_sctp_header;
997 pi->unformat_pg_edit = unformat_pg_sctp_header;
999 /* Register as transport with session layer */
1000 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
1001 FIB_PROTOCOL_IP4, sctp4_output_node.index);
1002 transport_register_protocol (TRANSPORT_PROTO_SCTP, &sctp_proto,
1003 FIB_PROTOCOL_IP6, sctp6_output_node.index);
1006 sctp_transport_enable_disable (vm, is_en);
1011 sctp_format_buffer_opaque_helper (const vlib_buffer_t * b, u8 * s)
1013 sctp_buffer_opaque_t *o = sctp_buffer_opaque (b);
1016 "sctp.connection_index: %d, sctp.sid: %d, sctp.ssn: %d, "
1017 "sctp.tsn: %d, sctp.hdr_offset: %d",
1018 o->sctp.connection_index,
1019 (u32) (o->sctp.sid),
1020 (u32) (o->sctp.ssn),
1021 (u32) (o->sctp.tsn), (u32) (o->sctp.hdr_offset));
1025 (s, "sctp.data_offset: %d, sctp.data_len: %d, sctp.subconn_idx: %d, "
1027 (u32) (o->sctp.data_offset),
1028 (u32) (o->sctp.data_len),
1029 (u32) (o->sctp.subconn_idx), (u32) (o->sctp.flags));
1035 sctp_init (vlib_main_t * vm)
1037 sctp_main_t *sm = vnet_get_sctp_main ();
1039 /* Session layer, and by implication SCTP, are disabled by default */
1043 /* initialize binary API */
1044 sctp_plugin_api_hookup (vm);
1046 vnet_register_format_buffer_opaque_helper
1047 (sctp_format_buffer_opaque_helper);
1051 VLIB_INIT_FUNCTION (sctp_init);
1053 static clib_error_t *
1054 show_sctp_punt_fn (vlib_main_t * vm, unformat_input_t * input,
1055 vlib_cli_command_t * cmd_arg)
1057 sctp_main_t *tm = &sctp_main;
1058 if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1059 return clib_error_return (0, "unknown input `%U'", format_unformat_error,
1061 vlib_cli_output (vm, "IPv4 UDP punt: %s",
1062 tm->punt_unknown4 ? "enabled" : "disabled");
1063 vlib_cli_output (vm, "IPv6 UDP punt: %s",
1064 tm->punt_unknown6 ? "enabled" : "disabled");
1068 VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
1070 .path = "show sctp punt",
1071 .short_help = "show sctp punt",
1072 .function = show_sctp_punt_fn,
1076 static clib_error_t *
1077 sctp_fn (vlib_main_t * vm, unformat_input_t * input,
1078 vlib_cli_command_t * cmd_arg)
1080 unformat_input_t _line_input, *line_input = &_line_input;
1081 clib_error_t *error;
1084 if (!unformat_user (input, unformat_line_input, line_input))
1085 return clib_error_return (0, "expected enable | disable");
1087 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1089 if (unformat (line_input, "enable"))
1091 else if (unformat (line_input, "disable"))
1095 error = clib_error_return (0, "unknown input `%U'",
1096 format_unformat_error, line_input);
1097 unformat_free (line_input);
1102 unformat_free (line_input);
1104 return sctp_enable_disable (vm, is_en);
1108 VLIB_CLI_COMMAND (show_sctp_command, static) =
1111 .short_help = "sctp [enable | disable]",
1112 .function = sctp_fn,
1116 VLIB_PLUGIN_REGISTER () =
1118 .version = VPP_BUILD_VER,
1119 .description = "Stream Control Transmission Protocol (SCTP)",
1120 .default_disabled = 1,
1125 * fd.io coding-style-patch-verification: ON
1128 * eval: (c-set-style "gnu")