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);
54 listener->state = SCTP_STATE_CLOSED;
77 memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
94 tm->punt_unknown4 = is_add;
96 tm->punt_unknown6 = is_add;
101 u16 * lcl_port,
u8 is_ip4)
106 index = tm->last_v4_address_rotor++;
107 if (tm->last_v4_address_rotor >=
vec_len (tm->ip4_src_addresses))
108 tm->last_v4_address_rotor = 0;
109 lcl_addr->ip4.as_u32 = tm->ip4_src_addresses[index].as_u32;
113 index = tm->last_v6_address_rotor++;
114 if (tm->last_v6_address_rotor >=
vec_len (tm->ip6_src_addresses))
115 tm->last_v6_address_rotor = 0;
116 clib_memcpy (&lcl_addr->ip6, &tm->ip6_src_addresses[index],
164 #define _(sym, str) str, 177 s =
format (s,
"UNKNOWN (%d (0x%x))", state, state);
191 if (sctp_conn->sub_conn[i].connection.is_ip4)
193 s =
format (s,
"%U[#%d][%s] %U:%d->%U:%d",
195 sctp_conn->sub_conn[i].connection.thread_index,
198 &sctp_conn->sub_conn[i].connection.lcl_ip.ip4,
199 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
200 connection.lcl_port),
202 &sctp_conn->sub_conn[i].connection.rmt_ip.ip4,
203 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
204 connection.rmt_port));
208 s =
format (s,
"%U[#%d][%s] %U:%d->%U:%d",
210 sctp_conn->sub_conn[i].connection.thread_index,
213 &sctp_conn->sub_conn[i].connection.lcl_ip.ip6,
214 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
215 connection.lcl_port),
217 &sctp_conn->sub_conn[i].connection.rmt_ip.ip6,
218 clib_net_to_host_u16 (sctp_conn->sub_conn[i].
219 connection.rmt_port));
229 u32 verbose = va_arg (*args,
u32);
259 sctp_conn->local_initial_tsn =
random_u32 (&time_now);
260 sctp_conn->last_unacked_tsn = sctp_conn->local_initial_tsn;
261 sctp_conn->next_tsn = sctp_conn->local_initial_tsn + 1;
263 sctp_conn->remote_initial_tsn = 0x0;
264 sctp_conn->last_rcvd_tsn = sctp_conn->remote_initial_tsn;
277 sctp_conn->sub_conn[subconn_idx].connection.c_index =
279 sctp_conn->sub_conn[subconn_idx].connection.thread_index = thread_index;
280 sctp_conn->sub_conn[subconn_idx].subconn_idx = subconn_idx;
295 return SCTP_ERROR_MAX_CONNECTIONS;
297 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
298 &lcl_addr, sizeof (lcl_addr));
300 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
301 &rmt_addr, sizeof (rmt_addr));
303 sctp_conn->forming_association_changed = 1;
305 return SCTP_ERROR_NONE;
323 &sctp_main->connections[thread_idx]->sub_conn[
i];
324 ip46_address_t *lcl_ip =
325 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.lcl_ip;
326 ip46_address_t *rmt_ip =
327 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.rmt_ip;
329 if (!sub_conn->connection.is_ip4)
331 if (lcl_ip->ip4.as_u32 == lcl_addr->
as_u32 &&
332 rmt_ip->ip4.as_u32 == rmt_addr->
as_u32)
335 sctp_conn->forming_association_changed = 1;
339 return SCTP_ERROR_NONE;
352 return SCTP_ERROR_MAX_CONNECTIONS;
354 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.lcl_ip,
355 &lcl_addr, sizeof (lcl_addr));
357 clib_memcpy (&sctp_conn->sub_conn[subconn_idx].connection.rmt_ip,
358 &rmt_addr, sizeof (rmt_addr));
360 sctp_conn->forming_association_changed = 1;
362 return SCTP_ERROR_NONE;
380 &sctp_main->connections[thread_idx]->sub_conn[
i];
381 ip46_address_t *lcl_ip =
382 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.lcl_ip;
383 ip46_address_t *rmt_ip =
384 &sctp_main->connections[thread_idx]->sub_conn[
i].connection.rmt_ip;
386 if (!sub_conn->connection.is_ip4)
388 if ((lcl_ip->ip6.as_u64[0] == lcl_addr->
as_u64[0]
389 && lcl_ip->ip6.as_u64[1] == lcl_addr->
as_u64[1])
390 && (rmt_ip->ip6.as_u64[0] == rmt_addr->
as_u64[0]
391 && rmt_ip->ip6.as_u64[1] == rmt_addr->
as_u64[1]))
394 sctp_conn->forming_association_changed = 1;
398 return SCTP_ERROR_NONE;
408 sctp_main->connections[thread_idx]->conn_config.never_delay_sack =
409 config.never_delay_sack;
410 sctp_main->connections[thread_idx]->conn_config.never_bundle =
422 pool_get (sctp_main->connections[thread_index], sctp_conn);
423 memset (sctp_conn, 0,
sizeof (*sctp_conn));
427 sctp_conn - sctp_main->connections[thread_index];
429 sctp_conn->local_tag = 0;
440 pool_get (tm->half_open_connections, sctp_conn);
441 memset (sctp_conn, 0,
sizeof (*sctp_conn));
443 sctp_conn - tm->half_open_connections;
454 ip46_address_t lcl_addr;
464 if ((rmt->is_ip4 &&
vec_len (tm->ip4_src_addresses))
465 || (!rmt->is_ip4 &&
vec_len (tm->ip6_src_addresses)))
470 rmt, &lcl_addr, &lcl_port);
483 sctp_conn->sub_conn[idx].PMTU =
487 ip_copy (&trans_conn->rmt_ip, &rmt->ip, rmt->is_ip4);
488 ip_copy (&trans_conn->lcl_ip, &lcl_addr, rmt->is_ip4);
489 sctp_conn->sub_conn[idx].subconn_idx = idx;
490 trans_conn->rmt_port = rmt->port;
491 trans_conn->lcl_port = clib_host_to_net_u16 (lcl_port);
492 trans_conn->is_ip4 = rmt->is_ip4;
494 trans_conn->fib_index = rmt->fib_index;
504 return sctp_conn->sub_conn[idx].connection.c_index;
521 &sctp_conn->sub_conn[i].connection.lcl_ip,
522 sctp_conn->sub_conn[i].connection.lcl_port);
532 memset (sctp_conn, 0xFA,
sizeof (*sctp_conn));
533 pool_put (tm->connections[thread_index], sctp_conn);
551 if (sctp_conn->sub_conn[i].is_retransmitting == 1 ||
552 sctp_conn->sub_conn[i].enqueue_state != SCTP_ERROR_ENQUEUED)
555 (
"Connection %u has still DATA to be enqueued inboud / outboud",
556 sctp_conn->sub_conn[i].connection.c_index);
567 SCTP_DBG (
"Closing connection %u...",
570 sctp_conn->state = SCTP_STATE_SHUTDOWN_PENDING;
578 ASSERT (thread_index == 0);
582 if (sctp_conn !=
NULL)
592 if (sctp_conn !=
NULL)
596 sctp_conn->state = SCTP_STATE_CLOSED;
609 if (sctp_conn ==
NULL)
620 return sctp_conn->sub_conn[idx].cwnd;
627 if (sctp_conn->peer_rwnd == 0)
633 clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd);
634 int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn);
636 if (available_wnd <= flight_size)
640 return available_wnd -
681 u32 tci = va_arg (*args,
u32);
682 u32 thread_index = va_arg (*args,
u32);
683 u32 verbose = va_arg (*args,
u32);
690 s =
format (s,
"empty\n");
697 u32 tci = va_arg (*args,
u32);
714 if (sctp_conn->sub_conn[conn_index].unacknowledged_hb >
718 u8 i, total_subs_down = 1;
727 total_subs_down += 1;
732 if (total_subs_down == MAX_SCTP_CONNECTIONS)
748 case SCTP_TIMER_T1_INIT:
751 case SCTP_TIMER_T1_COOKIE:
754 case SCTP_TIMER_T2_SHUTDOWN:
757 case SCTP_TIMER_T3_RXTX:
762 case SCTP_TIMER_T4_HEARTBEAT:
776 u32 connection_index, timer_id;
778 for (i = 0; i <
vec_len (expired_timers); i++)
781 connection_index = expired_timers[
i] & 0x0FFFFFFF;
782 timer_id = expired_timers[
i] >> 28;
784 SCTP_DBG (
"Expired timer ID: %u", timer_id);
794 tw_timer_wheel_16t_2w_512sl_t *tw;
797 tw = &tm->timer_wheels[ii];
814 u32 preallocated_connections_per_thread;
841 if (num_threads == 1)
844 preallocated_connections_per_thread = tm->preallocated_connections;
849 preallocated_connections_per_thread =
850 tm->preallocated_connections / (num_threads - 1);
852 for (; thread < num_threads; thread++)
854 if (preallocated_connections_per_thread)
856 preallocated_connections_per_thread);
878 vec_validate (tm->ip_lookup_tx_frames[0], num_threads - 1);
879 vec_validate (tm->ip_lookup_tx_frames[1], num_threads - 1);
916 u32 tci = va_arg (*args,
u32);
925 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)
static uword vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vlib_rx_or_tx_t dir)
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 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.
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
vhost_vring_state_t state
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