28 pool_get (tm->listener_pool, listener);
34 listener - tm->listener_pool;
42 ip_set (&tep->ip, iface_ip, tep->is_ip4);
45 &tep->ip, tep->is_ip4);
61 listener->state = SCTP_STATE_CLOSED;
101 tm->punt_unknown4 = is_add;
103 tm->punt_unknown6 = is_add;
108 u16 * lcl_port,
u8 is_ip4)
113 index = tm->last_v4_address_rotor++;
114 if (tm->last_v4_address_rotor >=
vec_len (tm->ip4_src_addresses))
115 tm->last_v4_address_rotor = 0;
116 lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
120 index = tm->last_v6_address_rotor++;
121 if (tm->last_v6_address_rotor >=
vec_len (tm->ip6_src_addresses))
122 tm->last_v6_address_rotor = 0;
123 clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
171 #define _(sym, str) str, 184 s =
format (s,
"UNKNOWN (%d (0x%x))", state, state);
200 if (sctp_conn->sub_conn[i].connection.is_ip4)
202 s =
format (s,
"[#%d][%s] %U:%d->%U:%d",
203 sctp_conn->sub_conn[i].connection.thread_index,
206 &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
207 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
208 connection.lcl_port),
210 &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
211 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
212 connection.rmt_port));
216 s =
format (s,
"[#%d][%s] %U:%d->%U:%d",
217 sctp_conn->sub_conn[i].connection.thread_index,
220 &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
221 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
222 connection.lcl_port),
224 &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
225 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
226 connection.rmt_port));
236 u32 verbose = va_arg (*args,
u32);
268 sctp_conn->local_initial_tsn =
random_u32 (&time_now);
269 sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
270 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
272 sctp_conn->remote_initial_tsn = 0x0;
273 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
286 sctp_conn->sub_conn[subconn_idx].connection.c_index =
288 sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
289 sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
304 return SCTP_ERROR_MAX_CONNECTIONS;
306 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
307 &lcl_addr, sizeof (lcl_addr));
309 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
310 &rmt_addr, sizeof (rmt_addr));
312 sctp_conn->forming_association_changed = 1;
314 return SCTP_ERROR_NONE;
332 &sctp_main->connections[thread_idx]->sub_conn[
i];
333 ip46_address_t *lcl_ip =
334 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.lcl_ip;
335 ip46_address_t *rmt_ip =
336 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.rmt_ip;
338 if (!sub_conn->connection.is_ip4)
340 if (lcl_ip->ip4.as_u32 == lcl_addr->
as_u32 &&
341 rmt_ip->ip4.as_u32 == rmt_addr->
as_u32)
344 sctp_conn->forming_association_changed = 1;
348 return SCTP_ERROR_NONE;
361 return SCTP_ERROR_MAX_CONNECTIONS;
363 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
364 &lcl_addr, sizeof (lcl_addr));
366 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
367 &rmt_addr, sizeof (rmt_addr));
369 sctp_conn->forming_association_changed = 1;
371 return SCTP_ERROR_NONE;
389 &sctp_main->connections[thread_idx]->sub_conn[
i];
390 ip46_address_t *lcl_ip =
391 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.lcl_ip;
392 ip46_address_t *rmt_ip =
393 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.rmt_ip;
395 if (!sub_conn->connection.is_ip4)
397 if ((lcl_ip->ip6.as_u64[0] == lcl_addr->
as_u64[0]
398 && lcl_ip->ip6.as_u64[1] == lcl_addr->
as_u64[1])
399 && (rmt_ip->ip6.as_u64[0] == rmt_addr->
as_u64[0]
400 && rmt_ip->ip6.as_u64[1] == rmt_addr->
as_u64[1]))
403 sctp_conn->forming_association_changed = 1;
407 return SCTP_ERROR_NONE;
417 sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
418 config.never_delay_sack;
419 sctp_main->connections[thread_idx]->conn_config.never_bundle =
431 pool_get (sctp_main->connections[thread_index], sctp_conn);
436 sctp_conn - sctp_main->connections[thread_index];
438 sctp_conn->local_tag = 0;
449 pool_get (tm->half_open_connections, sctp_conn);
452 sctp_conn - tm->half_open_connections;
463 ip46_address_t lcl_addr;
474 if ((rmt->is_ip4 &&
vec_len (tm->ip4_src_addresses))
475 || (!rmt->is_ip4 &&
vec_len (tm->ip6_src_addresses)))
480 rmt, &lcl_addr, &lcl_port);
495 rmt->peer.sw_if_index,
499 sctp_conn->sub_conn[idx].PMTU = mtu;
502 ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
503 ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
504 sctp_conn->sub_conn[idx].subconn_idx = idx;
505 trans_conn->rmt_port = rmt->port;
506 trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
507 trans_conn->is_ip4 = rmt->is_ip4;
509 trans_conn->fib_index = rmt->fib_index;
519 return sctp_conn->sub_conn[idx].connection.c_index;
536 &sctp_conn->sub_conn[i].connection.lcl_ip,
537 sctp_conn->sub_conn[i].connection.lcl_port);
547 clib_memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
548 pool_put (tm->connections[thread_index], sctp_conn);
566 if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
567 sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
570 (
"Connection %u has still DATA to be enqueued inboud / outboud",
571 sctp_conn->sub_conn[i].connection.c_index);
582 SCTP_DBG (
"Closing connection %u...",
585 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
593 ASSERT (thread_index == 0);
597 if (sctp_conn !=
NULL)
607 if (sctp_conn !=
NULL)
611 sctp_conn->state = SCTP_STATE_CLOSED;
624 if (sctp_conn ==
NULL)
634 return sctp_conn->sub_conn[idx].cwnd;
641 if (sctp_conn->peer_rwnd == 0)
647 clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
648 int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
650 if (available_wnd <= flight_size)
654 return available_wnd -
695 u32 tci = va_arg (*args,
u32);
696 u32 thread_index = va_arg (*args,
u32);
697 u32 verbose = va_arg (*args,
u32);
704 s =
format (s,
"empty\n");
711 u32 tci = va_arg (*args,
u32);
728 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
732 u8 i, total_subs_down = 1;
741 total_subs_down += 1;
746 if (total_subs_down == MAX_SCTP_CONNECTIONS)
762 case SCTP_TIMER_T1_INIT:
765 case SCTP_TIMER_T1_COOKIE:
768 case SCTP_TIMER_T2_SHUTDOWN:
771 case SCTP_TIMER_T3_RXTX:
776 case SCTP_TIMER_T4_HEARTBEAT:
790 u32 connection_index, timer_id;
792 for (i = 0; i <
vec_len (expired_timers); i++)
795 connection_index = expired_timers[
i] & 0x0FFFFFFF;
796 timer_id = expired_timers[
i] >> 28;
798 SCTP_DBG (
"Expired timer ID: %u", timer_id);
808 tw_timer_wheel_16t_2w_512sl_t *tw;
811 tw = &tm->timer_wheels[ii];
828 u32 preallocated_connections_per_thread;
855 if (num_threads == 1)
858 preallocated_connections_per_thread = tm->preallocated_connections;
863 preallocated_connections_per_thread =
864 tm->preallocated_connections / (num_threads - 1);
866 for (; thread < num_threads; thread++)
868 if (preallocated_connections_per_thread)
870 preallocated_connections_per_thread);
892 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
893 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
929 u32 tci = va_arg (*args,
u32);
938 tw_timer_expire_timers_16t_2w_512sl (&
sctp_main.timer_wheels[thread_index],
1005 tm->punt_unknown4 ?
"enabled" :
"disabled");
1007 tm->punt_unknown6 ?
"enabled" :
"disabled");
1013 .path =
"show sctp punt",
1014 .short_help =
"show sctp punt",
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
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.
static void update_cwnd(sctp_connection_t *sctp_conn)
clib_error_t * sctp_main_enable(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)
struct _transport_connection transport_connection_t
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.
struct _transport_proto_vft transport_proto_vft_t
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
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)
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)
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...)
vhost_vring_state_t state
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)
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)
static u8 sctp_next_avail_subconn(sctp_connection_t *sctp_conn)
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)
u8 * format_sctp_connection(u8 *s, va_list *args)
const char * sctp_fsm_states[]
#define ENDPOINT_INVALID_INDEX
transport_connection_t * sctp_session_get_listener(u32 listener_index)
void sctp_api_reference(void)
#define clib_warning(format, args...)
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
#define VLIB_BUFFER_DATA_SIZE
#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,...)
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
void sctp_connection_cleanup(sctp_connection_t *sctp_conn)
Cleans up connection state.
unreliable transport protos
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)
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()
void sctp_connection_close(sctp_connection_t *sctp_conn)
static sctp_connection_t * sctp_sub_connection_add(u8 thread_index)
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