17 #include <vpp/app/version.h> 32 pool_get (tm->listener_pool, listener);
38 listener - tm->listener_pool;
46 ip_set (&tep->ip, iface_ip, tep->is_ip4);
49 &tep->ip, tep->is_ip4);
65 listener->state = SCTP_STATE_CLOSED;
105 tm->punt_unknown4 = is_add;
107 tm->punt_unknown6 = is_add;
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],
175 #define _(sym, str) str, 188 s =
format (s,
"UNKNOWN (%d (0x%x))", state, state);
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));
240 u32 verbose = va_arg (*args,
u32);
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;
290 sctp_conn->sub_conn[subconn_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;
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;
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)
348 sctp_conn->forming_association_changed = 1;
352 return SCTP_ERROR_NONE;
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;
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]))
407 sctp_conn->forming_association_changed = 1;
411 return SCTP_ERROR_NONE;
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 =
435 pool_get (sctp_main->connections[thread_index], sctp_conn);
440 sctp_conn - sctp_main->connections[thread_index];
442 sctp_conn->local_tag = 0;
453 pool_get (tm->half_open_connections, sctp_conn);
456 sctp_conn - tm->half_open_connections;
467 ip46_address_t lcl_addr;
478 if ((rmt->is_ip4 &&
vec_len (tm->ip4_src_addresses))
479 || (!rmt->is_ip4 &&
vec_len (tm->ip6_src_addresses)))
484 rmt, &lcl_addr, &lcl_port);
499 rmt->peer.sw_if_index,
503 sctp_conn->sub_conn[idx].PMTU = mtu;
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;
523 return sctp_conn->sub_conn[idx].connection.c_index;
540 &sctp_conn->sub_conn[i].connection.lcl_ip,
541 sctp_conn->sub_conn[i].connection.lcl_port);
551 clib_memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
552 pool_put (tm->connections[thread_index], sctp_conn);
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);
586 SCTP_DBG (
"Closing connection %u...",
589 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
597 ASSERT (thread_index == 0);
601 if (sctp_conn !=
NULL)
611 if (sctp_conn !=
NULL)
615 sctp_conn->state = SCTP_STATE_CLOSED;
628 if (sctp_conn ==
NULL)
638 return sctp_conn->sub_conn[idx].cwnd;
645 if (sctp_conn->peer_rwnd == 0)
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)
658 return available_wnd -
699 u32 tci = va_arg (*args,
u32);
700 u32 thread_index = va_arg (*args,
u32);
701 u32 verbose = va_arg (*args,
u32);
708 s =
format (s,
"empty\n");
715 u32 tci = va_arg (*args,
u32);
716 u32 __clib_unused thread_index = va_arg (*args,
u32);
733 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
737 u8 i, total_subs_down = 1;
746 total_subs_down += 1;
751 if (total_subs_down == MAX_SCTP_CONNECTIONS)
767 case SCTP_TIMER_T1_INIT:
770 case SCTP_TIMER_T1_COOKIE:
773 case SCTP_TIMER_T2_SHUTDOWN:
776 case SCTP_TIMER_T3_RXTX:
781 case SCTP_TIMER_T4_HEARTBEAT:
795 u32 connection_index, timer_id;
797 for (i = 0; i <
vec_len (expired_timers); i++)
800 connection_index = expired_timers[
i] & 0x0FFFFFFF;
801 timer_id = expired_timers[
i] >> 28;
803 SCTP_DBG (
"Expired timer ID: %u", timer_id);
813 tw_timer_wheel_16t_2w_512sl_t *tw;
816 tw = &tm->timer_wheels[ii];
833 u32 preallocated_connections_per_thread;
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)
875 preallocated_connections_per_thread);
897 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
898 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
934 u32 tci = va_arg (*args,
u32);
935 u32 __clib_unused thread_index = va_arg (*args,
u32);
944 tw_timer_expire_timers_16t_2w_512sl (&
sctp_main.timer_wheels[thread_index],
967 .transport_options = {
982 if (!sm->is_init && is_en)
985 sm->sctp4_established_phase_node_index = node->
index;
988 sm->sctp6_established_phase_node_index = node->
index;
1016 "sctp.connection_index: %d, sctp.sid: %d, sctp.ssn: %d, " 1017 "sctp.tsn: %d, sctp.hdr_offset: %d",
1025 (s,
"sctp.data_offset: %d, sctp.data_len: %d, sctp.subconn_idx: %d, " 1062 tm->punt_unknown4 ?
"enabled" :
"disabled");
1064 tm->punt_unknown6 ?
"enabled" :
"disabled");
1070 .path =
"show sctp punt",
1071 .short_help =
"show sctp punt",
1089 if (
unformat (line_input,
"enable"))
1091 else if (
unformat (line_input,
"disable"))
1111 .short_help =
"sctp [enable | disable]",
1118 .version = VPP_BUILD_VER,
1119 .description =
"Stream Control Transmission Protocol (SCTP)",
1120 .default_disabled = 1,
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
static clib_error_t * sctp_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
void sctp_connection_timers_reset(sctp_connection_t *sctp_conn)
Stop all connection timers.
u16 sctp_check_outstanding_data_chunks(sctp_connection_t *sctp_conn)
struct _sctp_main sctp_main_t
void sctp_connection_timers_init(sctp_connection_t *sctp_conn)
Initialize all connection timers as invalid.
#define ENDPOINT_INVALID_INDEX
static void update_cwnd(sctp_connection_t *sctp_conn)
clib_error_t * sctp_main_enable(vlib_main_t *vm)
clib_error_t * sctp_plugin_api_hookup(vlib_main_t *vm)
void sctp_flush_frames_to_output(u8 thread_index)
Flush v4 and v6 sctp and ip-lookup tx frames for thread index.
#define SCTP_DBG(_fmt, _args...)
static int sctp_alloc_custom_local_endpoint(sctp_main_t *tm, ip46_address_t *lcl_addr, u16 *lcl_port, u8 is_ip4)
void sctp_init_snd_vars(sctp_connection_t *sctp_conn)
Initialize connection send variables.
void ip_copy(ip46_address_t *dst, ip46_address_t *src, u8 is_ip4)
void ip6_register_protocol(u32 protocol, u32 node_index)
vnet_main_t * vnet_get_main(void)
static clib_error_t * ip4_lookup_init(vlib_main_t *vm)
transport_connection_t * sctp_half_open_session_get_transport(u32 conn_index)
void sctp_send_init(sctp_connection_t *sctp_conn)
struct _sctp_sub_connection sctp_sub_connection_t
void ip_set(ip46_address_t *dst, void *src, u8 is_ip4)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void session_transport_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
static f64 vlib_time_now(vlib_main_t *vm)
static u64 sctp_time_now(void)
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
#define foreach_sctp_fsm_state
SSCTP FSM state definitions as per RFC4960.
clib_error_t * sctp_transport_enable_disable(vlib_main_t *vm, u8 is_en)
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
clib_error_t * sctp_enable_disable(vlib_main_t *vm, u8 is_en)
u8 * format_sctp_half_open(u8 *s, va_list *args)
u16 sctp_session_send_mss(transport_connection_t *trans_conn)
Compute maximum segment size for session layer.
void * ip_interface_get_first_ip(u32 sw_if_index, u8 is_ip4)
static void update_smallest_pmtu_idx(sctp_connection_t *sctp_conn)
static u32 vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vnet_mtu_t af)
u16 data_offset
offset relative to ip hdr
static u32 sctp_connection_bind(u32 session_index, transport_endpoint_t *tep)
void ip4_register_protocol(u32 protocol, u32 node_index)
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
struct _sctp_user_configuration sctp_user_configuration_t
u8 sctp_configure(sctp_user_configuration_t config)
void vnet_register_format_buffer_opaque_helper(vnet_buffer_opquae_formatter_t fn)
static sctp_main_t * vnet_get_sctp_main()
int sctp_session_open(transport_endpoint_cfg_t *tep)
vlib_node_registration_t sctp6_input_node
(constructor) VLIB_REGISTER_NODE (sctp6_input_node)
#define clib_memcpy(d, s, n)
#define SCTP_PATH_MAX_RETRANS
unformat_function_t * unformat_pg_edit
u8 * format_sctp_listener_session(u8 *s, va_list *args)
u32 sctp_session_unbind(u32 listener_index)
#define VLIB_INIT_FUNCTION(x)
transport_connection_t * sctp_session_get_transport(u32 conn_index, u32 thread_index)
#define clib_error_return(e, args...)
static u8 * sctp_format_buffer_opaque_helper(const vlib_buffer_t *b, u8 *s)
u8 * format_sctp_session(u8 *s, va_list *args)
static void sctp_connection_unbind(u32 listener_index)
pthread_t thread[MAX_CONNS]
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_cfg_t *rmt_cfg, ip46_address_t *lcl_addr, u16 *lcl_port)
sctp_connection_t * sctp_connection_new(u8 thread_index)
void sctp_session_cleanup(u32 conn_index, u32 thread_index)
#define vlib_call_init_function(vm, x)
void sctp_data_retransmit(sctp_connection_t *sctp_conn)
static int sctp_connection_open(transport_endpoint_cfg_t *rmt)
struct _transport_proto_vft transport_proto_vft_t
static void clib_spinlock_init(clib_spinlock_t *p)
void sctp_punt_unknown(vlib_main_t *vm, u8 is_ip4, u8 is_add)
#define SCTP_DBG_OUTPUT(_fmt, _args...)
static void sctp_timer_reset(sctp_connection_t *tc, u8 conn_idx, u8 timer_id)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
static sctp_connection_t * sctp_get_connection_from_transport(transport_connection_t *tconn)
format_function_t * format_header
void sctp_initialize_timer_wheels(sctp_main_t *tm)
u8 sctp_sub_connection_add_ip4(vlib_main_t *vm, ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
u32 sctp_session_bind(u32 session_index, transport_endpoint_t *tep)
#define pool_put(P, E)
Free an object E in pool P.
struct _sctp_connection sctp_connection_t
static u64 sctp_set_time_now(u32 thread_index)
static char * sctp_timer_to_string(u8 timer_id)
u8 * format_sctp_connection_id(u8 *s, va_list *args)
#define foreach_vlib_main(body)
#define MAX_SCTP_CONNECTIONS
static clib_error_t * show_sctp_punt_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
u8 * format_sctp_state(u8 *s, va_list *args)
#define SCTP_TSTAMP_RESOLUTION
Time stamp resolution.
vlib_node_registration_t sctp4_output_node
(constructor) VLIB_REGISTER_NODE (sctp4_output_node)
u32 tsn
Transmission Sequence Number.
static u8 sctp_next_avail_subconn(sctp_connection_t *sctp_conn)
static_always_inline u32 vlib_buffer_get_default_data_size(vlib_main_t *vm)
struct sctp_buffer_opaque_t::@632 sctp
u8 sctp_sub_connection_del_ip4(ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
clib_error_t * ip_main_init(vlib_main_t *vm)
static_always_inline uword vlib_get_thread_index(void)
#define sctp_buffer_opaque(b)
u8 * format_sctp_connection(u8 *s, va_list *args)
const char * sctp_fsm_states[]
transport_connection_t * sctp_session_get_listener(u32 listener_index)
#define clib_warning(format, args...)
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
struct _transport_connection transport_connection_t
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
vlib_main_t vlib_node_runtime_t * node
#define pool_init_fixed(pool, max_elts)
initialize a fixed-size, preallocated pool
void transport_endpoint_cleanup(u8 proto, ip46_address_t *lcl_ip, u16 port)
void transport_register_protocol(transport_proto_t transport_proto, const transport_proto_vft_t *vft, fib_protocol_t fib_proto, u32 output_node)
Register transport virtual function table.
#define VLIB_CLI_COMMAND(x,...)
u16 hdr_offset
offset relative to ip hdr
static sctp_connection_t * sctp_half_open_connection_get(u32 conn_index)
#define pool_put_index(p, i)
Free pool element with given index.
u16 sctp_snd_space(sctp_connection_t *sctp_conn)
#define SCTP_PRIMARY_PATH_IDX
u8 subconn_idx
index of the sub_connection being used
void sctp_connection_cleanup(sctp_connection_t *sctp_conn)
Cleans up connection state.
u16 ssn
Stream Sequence Number.
u8 ip_is_zero(ip46_address_t *ip46_address, u8 is_ip4)
void sctp_update_time(f64 now, u8 thread_index)
static sctp_connection_t * sctp_connection_get(u32 conn_index, u32 thread_index)
void sctp_send_cookie_echo(sctp_connection_t *sctp_conn)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u8 * format_sctp_header(u8 *s, va_list *args)
VLIB buffer representation.
unreliable transport protos
clib_error_t * sctp_init(vlib_main_t *vm)
u8 sctp_sub_connection_del_ip6(ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
void sctp_send_heartbeat(sctp_connection_t *sctp_conn)
static u32 random_u32(u32 *seed)
32-bit random number generator
void sctp_expired_timers_cb(u32 conn_index, u32 timer_id)
static vlib_thread_main_t * vlib_get_thread_main()
vl_api_dhcp_client_state_t state
void sctp_connection_close(sctp_connection_t *sctp_conn)
static sctp_connection_t * sctp_sub_connection_add(u8 thread_index)
unformat_function_t unformat_pg_sctp_header
static sctp_connection_t * sctp_listener_get(u32 tli)
#define SCTP_TIMER_HANDLE_INVALID
int transport_alloc_local_port(u8 proto, ip46_address_t *ip)
Allocate local port and add if successful add entry to local endpoint table to mark the pair as used...
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
vlib_node_registration_t sctp4_input_node
(constructor) VLIB_REGISTER_NODE (sctp4_input_node)
static u8 sctp_data_subconn_select(sctp_connection_t *sctp_conn)
void sctp_send_shutdown(sctp_connection_t *sctp_conn)
sctp_connection_t * sctp_half_open_connection_new(u8 thread_index)
u8 sctp_sub_connection_add_ip6(vlib_main_t *vm, ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
#define SCTP_CONN_RECOVERY
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
void sctp_session_close(u32 conn_index, u32 thread_index)
u32 sctp_session_send_space(transport_connection_t *trans_conn)
Compute TX window session is allowed to fill.
static void sctp_expired_timers_dispatch(u32 *expired_timers)
static const transport_proto_vft_t sctp_proto