15 #ifndef included_vnet_sctp_h 16 #define included_vnet_sctp_h 26 #define foreach_sctp_timer \ 27 _(T1_INIT, "T1_INIT") \ 28 _(T1_COOKIE, "T1_COOKIE") \ 29 _(T2_SHUTDOWN, "T2_SHUTDOWN") \ 30 _(T3_RXTX, "T3_RXTX") \ 31 _(T4_HEARTBEAT, "T4_HB") \ 32 _(T5_SHUTDOWN_GUARD, "T5_SHUTDOWN_GUARD") 34 typedef enum _sctp_timers
36 #define _(sym, str) SCTP_TIMER_##sym, 42 #define SCTP_TIMER_HANDLE_INVALID ((u32) ~0) 49 case SCTP_TIMER_T1_INIT:
50 return "SCTP_TIMER_T1_INIT";
51 case SCTP_TIMER_T1_COOKIE:
52 return "SCTP_TIMER_T1_COOKIE";
53 case SCTP_TIMER_T2_SHUTDOWN:
54 return "SCTP_TIMER_T2_SHUTDOWN";
55 case SCTP_TIMER_T3_RXTX:
56 return "SCTP_TIMER_T3_RXTX";
57 case SCTP_TIMER_T4_HEARTBEAT:
58 return "SCTP_TIMER_T4_HEARTBEAT";
59 case SCTP_TIMER_T5_SHUTDOWN_GUARD:
60 return "SCTP_TIMER_T5_SHUTDOWN_GUARD";
65 typedef enum _sctp_error
67 #define sctp_error(n,s) SCTP_ERROR_##n, 75 #define IS_T_BIT_SET(var) ((var) & (1)) 76 #define IS_E_BIT_SET(var) ((var) & (1)) 77 #define IS_B_BIT_SET(var) ((var) & (1<<1)) 78 #define IS_U_BIT_SET(var) ((var) & (1<<2)) 80 #define MAX_SCTP_CONNECTIONS 8 81 #define SCTP_PRIMARY_PATH_IDX 0 83 #if (VLIB_BUFFER_TRACE_TRAJECTORY) 84 #define sctp_trajectory_add_start(b, start) \ 86 (*vlib_buffer_trace_trajectory_cb) (b, start); \ 89 #define sctp_trajectory_add_start(b, start) 92 enum _sctp_subconn_state
101 #define SCTP_INITIAL_SSHTRESH 65535 102 typedef struct _sctp_sub_connection
121 u32 partially_acked_bytes;
142 u8 unacknowledged_hb;
145 u8 is_retransmitting;
158 #define SET_BIT(A,k) ( A[(k/32)] |= (1 << (k%32)) ) 159 #define CLEAR_BIT(A,k) ( A[(k/32)] &= ~(1 << (k%32)) ) 160 #define TEST_BIT(A,k) ( A[(k/32)] & (1 << (k%32)) ) 163 _bytes_swap (
void *pv,
size_t n)
167 for (lo = 0, hi = n - 1; hi >
lo; lo++, hi--)
175 #define ENDIANESS_SWAP(x) _bytes_swap(&x, sizeof(x)); 177 #define MAX_INFLIGHT_PACKETS 128 178 #define MAX_ENQUEABLE_SACKS 2 184 #define SUGGESTED_COOKIE_LIFE_SPAN_INCREMENT 1000 186 typedef struct _sctp_user_configuration
193 typedef struct _sctp_connection
207 u32 local_initial_tsn;
208 u32 remote_initial_tsn;
210 u32 peer_cookie_life_span_increment;
212 u32 overall_err_count;
213 u32 overall_err_treshold;
216 u8 init_retransmit_err;
226 u32 last_unacked_tsn;
227 u32 next_tsn_expected;
245 u8 smallest_PMTU_idx;
247 u8 overall_sending_status;
251 u8 forming_association_changed;
343 #define IP_PROTOCOL_SCTP 132 346 #define foreach_sctp_fsm_state \ 347 _(CLOSED, "CLOSED") \ 348 _(COOKIE_WAIT, "COOKIE_WAIT") \ 349 _(COOKIE_ECHOED, "COOKIE_ECHOED") \ 350 _(ESTABLISHED, "ESTABLISHED") \ 351 _(SHUTDOWN_PENDING, "SHUTDOWN_PENDING") \ 352 _(SHUTDOWN_SENT, "SHUTDOWN_SENT") \ 353 _(SHUTDOWN_RECEIVED, "SHUTDOWN_RECEIVED") \ 354 _(SHUTDOWN_ACK_SENT, "SHUTDOWN_ACK_SENT") 356 typedef enum _sctp_state
358 #define _(sym, str) SCTP_STATE_##sym, 369 case SCTP_STATE_CLOSED:
370 return "SCTP_STATE_CLOSED";
371 case SCTP_STATE_COOKIE_WAIT:
372 return "SCTP_STATE_COOKIE_WAIT";
373 case SCTP_STATE_COOKIE_ECHOED:
374 return "SCTP_STATE_COOKIE_ECHOED";
375 case SCTP_STATE_ESTABLISHED:
376 return "SCTP_STATE_ESTABLISHED";
377 case SCTP_STATE_SHUTDOWN_PENDING:
378 return "SCTP_STATE_SHUTDOWN_PENDING";
379 case SCTP_STATE_SHUTDOWN_SENT:
380 return "SCTP_STATE_SHUTDOWN_SENT";
381 case SCTP_STATE_SHUTDOWN_RECEIVED:
382 return "SCTP_STATE_SHUTDOWN_RECEIVED";
383 case SCTP_STATE_SHUTDOWN_ACK_SENT:
384 return "SCTP_STATE_SHUTDOWN_ACK_SENT";
405 return "HEARTBEAT_ACK";
411 return "SHUTDOWN_ACK";
413 return "OPERATION_ERROR";
415 return "COOKIE_ECHO";
423 return "SHUTDOWN_COMPLETE";
434 return "SCTP_IPV4_ADDRESS_TYPE";
436 return "SCTP_IPV6_ADDRESS_TYPE";
438 return "SCTP_STATE_COOKIE_TYPE";
440 return "SCTP_UNRECOGNIZED_TYPE";
442 return "SCTP_COOKIE_PRESERVATIVE_TYPE";
444 return "SCTP_HOSTNAME_ADDRESS_TYPE";
446 return "SCTP_SUPPORTED_ADDRESS_TYPES";
451 #define SCTP_TICK 0.001 452 #define SHZ (u32) (1/SCTP_TICK) 453 #define SCTP_TSTAMP_RESOLUTION SCTP_TICK 456 #define SCTP_RTO_INIT 3 * SHZ 457 #define SCTP_RTO_MIN 1 * SHZ 458 #define SCTP_RTO_MAX 60 * SHZ 459 #define SCTP_RTO_BURST 4 460 #define SCTP_RTO_ALPHA 1/8 461 #define SCTP_RTO_BETA 1/4 462 #define SCTP_VALID_COOKIE_LIFE 60 * SHZ 463 #define SCTP_ASSOCIATION_MAX_RETRANS 10 // the overall connection 464 #define SCTP_PATH_MAX_RETRANS 5 // number of attempts per destination address 465 #define SCTP_MAX_INIT_RETRANS 8 // number of attempts 466 #define SCTP_HB_INTERVAL 30 * SHZ 467 #define SCTP_HB_MAX_BURST 1 468 #define SCTP_DATA_IDLE_INTERVAL 15 * SHZ 469 #define SCTP_TO_TIMER_TICK SCTP_TICK*10 471 #define SCTP_CONN_RECOVERY 1 << 1 472 #define SCTP_FAST_RECOVERY 1 << 2 474 typedef struct _sctp_lookup_dispatch
479 typedef struct _sctp_main
490 u8 log2_tstamp_clocks_per_tick;
491 f64 tstamp_ticks_per_clock;
502 tw_timer_wheel_16t_2w_512sl_t *timer_wheels;
515 u32 preallocated_connections;
518 u32 local_endpoints_table_memory;
519 u32 local_endpoints_table_buckets;
523 u32 last_v4_address_rotor;
524 u32 last_v6_address_rotor;
528 u32 bytes_per_buffer;
533 u32 sctp4_established_phase_node_index;
534 u32 sctp6_established_phase_node_index;
599 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
601 ASSERT (tc->sub_conn[conn_idx].timers[timer_id] ==
605 sub->timers[timer_id] =
606 tw_timer_start_16t_2w_512sl (&
sctp_main.timer_wheels[sub->c_thread_index],
607 sub->c_c_index, timer_id, interval);
619 tw_timer_stop_16t_2w_512sl (&
sctp_main.timer_wheels[sub->c_thread_index],
620 sub->timers[timer_id]);
660 if (sub->parent ==
NULL)
663 if (sub->subconn_idx > 0)
676 #define ABS(x) ((x) > 0) ? (x) : -(x); 685 u64 prev_ts = sctp_conn->sub_conn[conn_idx].rtt_ts;
686 u64 R = prev_ts - now;
688 if (sctp_conn->sub_conn[conn_idx].RTO == 0)
694 if (sctp_conn->sub_conn[conn_idx].RTO ==
SCTP_RTO_MIN && sctp_conn->sub_conn[conn_idx].SRTT == 0)
696 sctp_conn->sub_conn[conn_idx].SRTT = R;
702 sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
706 RTTVAR = (1 -
SCTP_RTO_BETA) * sctp_conn->sub_conn[conn_idx].RTTVAR +
712 sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
714 sctp_conn->sub_conn[conn_idx].SRTT =
720 sctp_conn->sub_conn[conn_idx].SRTT +
721 4 * sctp_conn->sub_conn[conn_idx].RTTVAR;
728 sctp_conn->sub_conn[conn_idx].RTO = RTO;
735 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
740 tw_timer_stop_16t_2w_512sl (&
sctp_main.timer_wheels[sub->c_thread_index],
741 sub->timers[timer_id]);
743 tc->sub_conn[conn_idx].timers[timer_id] =
744 tw_timer_start_16t_2w_512sl (&
sctp_main.timer_wheels[sub->c_thread_index],
745 sub->c_c_index, timer_id, interval);
765 #define SELECT_MAX_RETRIES 8 777 if (sctp_conn->sub_conn[i].cwnd > cwnd)
780 cwnd = sctp_conn->sub_conn[
i].cwnd;
793 if (sctp_conn->sub_conn[i].connection.lcl_ip.ip6.as_u64[0] ==
795 sctp_conn->sub_conn[i].connection.lcl_ip.ip6.as_u64[1] ==
797 sctp_conn->sub_conn[i].connection.rmt_ip.ip6.as_u64[0] ==
799 sctp_conn->sub_conn[i].connection.rmt_ip.ip6.as_u64[1] ==
803 clib_warning (
"Did not find a sub-connection; defaulting to %u",
815 if (sctp_conn->sub_conn[i].connection.lcl_ip.ip4.as_u32 ==
817 && sctp_conn->sub_conn[i].connection.rmt_ip.ip4.as_u32 ==
821 clib_warning (
"Did not find a sub-connection; defaulting to %u",
839 u8 sctp_hdr_opts_len)
863 u8 sctp_hdr_opts_len)
892 if (sctp_conn->sub_conn[i].PMTU <
893 sctp_conn->sub_conn[smallest_pmtu_index].PMTU)
894 smallest_pmtu_index =
i;
898 sctp_conn->smallest_PMTU_idx = smallest_pmtu_index;
909 sctp_conn->sub_conn[
i].cwnd =
910 clib_min (4 * sctp_conn->sub_conn[i].PMTU,
911 clib_max (2 * sctp_conn->sub_conn[i].PMTU, 4380));
917 sctp_conn->sub_conn[
i].partially_acked_bytes = 0;
930 if (sctp_conn->sub_conn[idx].cwnd == 0)
940 u32 inflight = sctp_conn->next_tsn - sctp_conn->last_unacked_tsn;
945 if (sctp_conn->sub_conn[i].is_retransmitting)
947 sctp_conn->sub_conn[
i].cwnd = 1 * sctp_conn->sub_conn[
i].PMTU;
952 if (sctp_conn->sub_conn[i].last_data_ts >
955 sctp_conn->sub_conn[
i].cwnd =
956 clib_max (sctp_conn->sub_conn[i].cwnd / 2,
957 4 * sctp_conn->sub_conn[i].PMTU);
962 if (sctp_conn->sub_conn[i].cwnd <= sctp_conn->sub_conn[i].ssthresh)
970 sctp_conn->sub_conn[
i].cwnd =
971 clib_min (sctp_conn->sub_conn[i].PMTU, 1);
976 sctp_conn->sub_conn[i].cwnd)
977 sctp_conn->sub_conn[
i].cwnd =
void sctp_flush_frame_to_output(vlib_main_t *vm, u8 thread_index, u8 is_ip4)
Flush tx frame populated by retransmits and timer pops.
#define MAX_INFLIGHT_PACKETS
struct _sctp_main sctp_main_t
static void sctp_timer_set(sctp_connection_t *tc, u8 conn_idx, u8 timer_id, u32 interval)
static void update_cwnd(sctp_connection_t *sctp_conn)
static u8 sctp_sub_conn_id_via_ip4h(sctp_connection_t *sctp_conn, ip4_header_t *ip4h)
void sctp_flush_frames_to_output(u8 thread_index)
Flush v4 and v6 sctp and ip-lookup tx frames for thread index.
#define CLIB_CACHE_LINE_ALIGN_MARK(mark)
u8 sctp_sub_connection_add_ip4(vlib_main_t *vm, ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
static char * sctp_optparam_type_to_string(u8 type)
u8 * format_sctp_scoreboard(u8 *s, va_list *args)
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
void sctp_send_init(sctp_connection_t *sctp_conn)
clib_error_t * vnet_sctp_enable_disable(vlib_main_t *vm, u8 is_en)
struct _sctp_sub_connection sctp_sub_connection_t
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static u64 sctp_time_now(void)
void sctp_connection_cleanup(sctp_connection_t *sctp_conn)
Cleans up connection state.
#define VLIB_BUFFER_PRE_DATA_SIZE
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.
#define SCTP_ADV_DBG(_fmt, _args...)
vlib_node_registration_t sctp6_output_node
(constructor) VLIB_REGISTER_NODE (sctp6_output_node)
static u64 clib_cpu_time_now(void)
u8 * format_sctp_connection(u8 *s, va_list *args)
u8 sctp_sub_connection_add_ip6(vlib_main_t *vm, ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
enum _sctp_timers sctp_timers_e
#define SCTP_HOSTNAME_ADDRESS_TYPE
void sctp_prepare_cookie_ack_chunk(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b)
void sctp_prepare_abort_for_collision(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b, ip4_address_t *ip4_addr, ip6_address_t *ip6_addr)
Convert buffer to ABORT.
#define SCTP_DATA_IDLE_INTERVAL
static void update_smallest_pmtu_idx(sctp_connection_t *sctp_conn)
static void sctp_calculate_rto(sctp_connection_t *sctp_conn, u8 conn_idx)
void sctp_init_mss(sctp_connection_t *sctp_conn)
struct _sctp_user_configuration sctp_user_configuration_t
static void sctp_half_open_connection_del(sctp_connection_t *tc)
Cleanup half-open connection.
static sctp_main_t * vnet_get_sctp_main()
vlib_node_registration_t sctp6_input_node
(constructor) VLIB_REGISTER_NODE (sctp6_input_node)
void sctp_init_snd_vars(sctp_connection_t *sctp_conn)
Initialize connection send variables.
struct _sctp_lookup_dispatch sctp_lookup_dispatch_t
static void sctp_init_cwnd(sctp_connection_t *sctp_conn)
void sctp_prepare_initack_chunk_for_collision(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b, ip4_address_t *ip4_addr, ip6_address_t *ip6_addr)
Convert buffer to INIT-ACK.
static timer_callback_t * timers
vhost_vring_state_t state
void sctp_prepare_sack_chunk(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b)
Convert buffer to SACK.
static int sctp_half_open_connection_cleanup(sctp_connection_t *tc)
Try to cleanup half-open connection.
static ct_connection_t * connections
#define SCTP_STATE_COOKIE_TYPE
#define SCTP_UNRECOGNIZED_TYPE
void sctp_data_retransmit(sctp_connection_t *sctp_conn)
enum _sctp_error sctp_error_t
void sctp_prepare_heartbeat_ack_chunk(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b)
Convert buffer to HEARTBEAT_ACK.
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.
u8 sctp_sub_connection_del_ip4(ip4_address_t *lcl_addr, ip4_address_t *rmt_addr)
static sctp_connection_t * sctp_get_connection_from_transport(transport_connection_t *tconn)
#define foreach_sctp_timer
static void * vlib_buffer_push_sctp_net_order(vlib_buffer_t *b, u16 sp, u16 dp, u8 sctp_hdr_opts_len)
Push SCTP header to buffer.
u8 * format_sctp_tx_trace(u8 *s, va_list *args)
void sctp_connection_close(sctp_connection_t *sctp_conn)
struct _sctp_connection sctp_connection_t
#define SCTP_IPV6_ADDRESS_TYPE
static u64 sctp_set_time_now(u32 thread_index)
static char * sctp_timer_to_string(u8 timer_id)
void() sctp_timer_expiration_handler(u32 conn_index, u32 timer_id)
#define MAX_SCTP_CONNECTIONS
static char * sctp_state_to_string(u8 state)
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)
enum _sctp_state sctp_state_t
#define SCTP_INITIAL_SSHTRESH
static_always_inline uword vlib_get_thread_index(void)
void sctp_api_reference(void)
sctp_connection_t * sctp_connection_new(u8 thread_index)
#define clib_warning(format, args...)
void sctp_connection_timers_reset(sctp_connection_t *sctp_conn)
Stop all connection timers.
u32 sctp_push_header(transport_connection_t *tconn, vlib_buffer_t *b)
struct _transport_connection transport_connection_t
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
void sctp_punt_unknown(vlib_main_t *vm, u8 is_ip4, u8 is_add)
u8 * format_sctp_connection_id(u8 *s, va_list *args)
static u32 sctp_header_bytes()
u8 sctp_configure(sctp_user_configuration_t config)
void sctp_send_shutdown_complete(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b0)
void sctp_prepare_operation_error(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b, u8 err_cause)
Convert buffer to ERROR.
static sctp_connection_t * sctp_half_open_connection_get(u32 conn_index)
#define pool_put_index(p, i)
Free pool element with given index.
#define SCTP_PRIMARY_PATH_IDX
static void * vlib_buffer_push_sctp(vlib_buffer_t *b, u16 sp_net, u16 dp_net, u8 sctp_hdr_opts_len)
Push SCTP header to buffer.
clib_error_t * sctp_init(vlib_main_t *vm)
void sctp_prepare_initack_chunk(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b, ip4_address_t *ip4_addr, u8 add_ip4, ip6_address_t *ip6_addr, u8 add_ip6)
Convert buffer to INIT-ACK.
void sctp_prepare_cookie_echo_chunk(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b, u8 reuse_buffer)
static void sctp_timer_update(sctp_connection_t *tc, u8 conn_idx, u8 timer_id, u32 interval)
struct _vlib_node_registration vlib_node_registration_t
static u8 cwnd_fully_utilized(sctp_connection_t *sctp_conn, u8 idx)
static void * vlib_buffer_push_uninit(vlib_buffer_t *b, u8 size)
Prepend uninitialized data to buffer.
static sctp_connection_t * sctp_connection_get(u32 conn_index, u32 thread_index)
#define SCTP_IPV4_ADDRESS_TYPE
void sctp_send_cookie_echo(sctp_connection_t *sctp_conn)
u8 * format_sctp_header(u8 *s, va_list *args)
VLIB buffer representation.
void sctp_connection_del(sctp_connection_t *sctp_conn)
void sctp_send_heartbeat(sctp_connection_t *sctp_conn)
static char * sctp_chunk_to_string(u8 type)
static u8 sctp_sub_conn_id_via_ip6h(sctp_connection_t *sctp_conn, ip6_header_t *ip6h)
void sctp_connection_timers_init(sctp_connection_t *sctp_conn)
Initialize all connection timers as invalid.
#define SCTP_COOKIE_PRESERVATIVE_TYPE
static sctp_connection_t * sctp_listener_get(u32 tli)
u8 sctp_sub_connection_del_ip6(ip6_address_t *lcl_addr, ip6_address_t *rmt_addr)
#define SCTP_TIMER_HANDLE_INVALID
u32 a_rwnd
Maximum segment size advertised.
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)
static sctp_header_t * sctp_buffer_hdr(vlib_buffer_t *b)
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
static u8 sctp_in_cong_recovery(sctp_connection_t *sctp_conn, u8 idx)
u16 sctp_check_outstanding_data_chunks(sctp_connection_t *sctp_conn)
void sctp_send_shutdown_ack(sctp_connection_t *sctp_conn, u8 idx, vlib_buffer_t *b)
format_function_t format_sctp_state
#define SCTP_SUPPORTED_ADDRESS_TYPES