27 pool_get (tm->listener_pool, listener);
28 memset (listener, 0,
sizeof (*listener));
33 listener - tm->listener_pool;
41 ip_set (&tep->ip, iface_ip, tep->is_ip4);
44 &tep->ip, tep->is_ip4);
58 listener->state = SCTP_STATE_CLOSED;
81 memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
98 tm->punt_unknown4 = is_add;
100 tm->punt_unknown6 = is_add;
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],
168 #define _(sym, str) str, 181 s =
format (s,
"UNKNOWN (%d (0x%x))", state, state);
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));
233 u32 verbose = va_arg (*args,
u32);
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;
281 sctp_conn->sub_conn[subconn_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;
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;
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)
339 sctp_conn->forming_association_changed = 1;
343 return SCTP_ERROR_NONE;
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;
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]))
398 sctp_conn->forming_association_changed = 1;
402 return SCTP_ERROR_NONE;
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 =
426 pool_get (sctp_main->connections[thread_index], sctp_conn);
427 memset (sctp_conn, 0,
sizeof (*sctp_conn));
431 sctp_conn - sctp_main->connections[thread_index];
433 sctp_conn->local_tag = 0;
444 pool_get (tm->half_open_connections, sctp_conn);
445 memset (sctp_conn, 0,
sizeof (*sctp_conn));
447 sctp_conn - tm->half_open_connections;
458 ip46_address_t lcl_addr;
468 if ((rmt->is_ip4 &&
vec_len (tm->ip4_src_addresses))
469 || (!rmt->is_ip4 &&
vec_len (tm->ip6_src_addresses)))
474 rmt, &lcl_addr, &lcl_port);
492 sctp_conn->sub_conn[idx].PMTU = mtu;
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;
502 trans_conn->fib_index = rmt->fib_index;
512 return sctp_conn->sub_conn[idx].connection.c_index;
529 &sctp_conn->sub_conn[i].connection.lcl_ip,
530 sctp_conn->sub_conn[i].connection.lcl_port);
540 memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
541 pool_put (tm->connections[thread_index], sctp_conn);
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);
575 SCTP_DBG (
"Closing connection %u...",
578 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
586 ASSERT (thread_index == 0);
590 if (sctp_conn !=
NULL)
600 if (sctp_conn !=
NULL)
604 sctp_conn->state = SCTP_STATE_CLOSED;
617 if (sctp_conn ==
NULL)
628 return sctp_conn->sub_conn[idx].cwnd;
635 if (sctp_conn->peer_rwnd == 0)
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)
648 return available_wnd -
689 u32 tci = va_arg (*args,
u32);
690 u32 thread_index = va_arg (*args,
u32);
691 u32 verbose = va_arg (*args,
u32);
698 s =
format (s,
"empty\n");
705 u32 tci = va_arg (*args,
u32);
722 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
726 u8 i, total_subs_down = 1;
735 total_subs_down += 1;
740 if (total_subs_down == MAX_SCTP_CONNECTIONS)
756 case SCTP_TIMER_T1_INIT:
759 case SCTP_TIMER_T1_COOKIE:
762 case SCTP_TIMER_T2_SHUTDOWN:
765 case SCTP_TIMER_T3_RXTX:
770 case SCTP_TIMER_T4_HEARTBEAT:
784 u32 connection_index, timer_id;
786 for (i = 0; i <
vec_len (expired_timers); i++)
789 connection_index = expired_timers[
i] & 0x0FFFFFFF;
790 timer_id = expired_timers[
i] >> 28;
792 SCTP_DBG (
"Expired timer ID: %u", timer_id);
802 tw_timer_wheel_16t_2w_512sl_t *tw;
805 tw = &tm->timer_wheels[ii];
822 u32 preallocated_connections_per_thread;
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)
864 preallocated_connections_per_thread);
886 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
887 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
924 u32 tci = va_arg (*args,
u32);
933 tw_timer_expire_timers_16t_2w_512sl (&
sctp_main.timer_wheels[thread_index],
#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
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)
static f64 vlib_time_now(vlib_main_t *vm)
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)
static u32 sctp_set_time_now(u32 thread_index)
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()
pthread_t thread[MAX_CONNS]
vlib_node_registration_t sctp6_input_node
(constructor) VLIB_REGISTER_NODE (sctp6_input_node)
#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...)
void stream_session_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
vhost_vring_state_t state
u8 * format_sctp_session(u8 *s, va_list *args)
static void sctp_connection_unbind(u32 listener_index)
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 void clib_spinlock_init(clib_spinlock_t *p)
void sctp_punt_unknown(vlib_main_t *vm, u8 is_ip4, u8 is_add)
static int sctp_connection_open(transport_endpoint_t *rmt)
#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)
static u32 sctp_time_now(void)
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 VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
#define pool_put(P, E)
Free an object E in pool P.
struct _sctp_connection sctp_connection_t
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
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...)
#define clib_memcpy(a, b, c)
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
#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.
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.
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
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)
int sctp_session_open(transport_endpoint_t *tep)
void sctp_send_cookie_echo(sctp_connection_t *sctp_conn)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
struct _transport_endpoint transport_endpoint_t
static u32 vlib_buffer_free_list_buffer_size(vlib_main_t *vm, vlib_buffer_free_list_index_t index)
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)
int transport_alloc_local_endpoint(u8 proto, transport_endpoint_t *rmt, ip46_address_t *lcl_addr, u16 *lcl_port)
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
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