15 #ifndef included_vnet_sctp_h 16 #define included_vnet_sctp_h 44 "sctp_buffer_opaque_t too large for vnet_buffer_opaque_t");
46 #define sctp_buffer_opaque(b) \ 47 ((sctp_buffer_opaque_t *)((u8 *)((b)->opaque) + \ 48 STRUCT_OFFSET_OF (vnet_buffer_opaque_t, unused))) 52 #define foreach_sctp_timer \ 53 _(T1_INIT, "T1_INIT") \ 54 _(T1_COOKIE, "T1_COOKIE") \ 55 _(T2_SHUTDOWN, "T2_SHUTDOWN") \ 56 _(T3_RXTX, "T3_RXTX") \ 57 _(T4_HEARTBEAT, "T4_HB") \ 58 _(T5_SHUTDOWN_GUARD, "T5_SHUTDOWN_GUARD") 60 typedef enum _sctp_timers
62 #define _(sym, str) SCTP_TIMER_##sym, 68 #define SCTP_TIMER_HANDLE_INVALID ((u32) ~0) 75 case SCTP_TIMER_T1_INIT:
76 return "SCTP_TIMER_T1_INIT";
77 case SCTP_TIMER_T1_COOKIE:
78 return "SCTP_TIMER_T1_COOKIE";
79 case SCTP_TIMER_T2_SHUTDOWN:
80 return "SCTP_TIMER_T2_SHUTDOWN";
81 case SCTP_TIMER_T3_RXTX:
82 return "SCTP_TIMER_T3_RXTX";
83 case SCTP_TIMER_T4_HEARTBEAT:
84 return "SCTP_TIMER_T4_HEARTBEAT";
85 case SCTP_TIMER_T5_SHUTDOWN_GUARD:
86 return "SCTP_TIMER_T5_SHUTDOWN_GUARD";
91 typedef enum _sctp_error
93 #define sctp_error(n,s) SCTP_ERROR_##n, 101 #define IS_T_BIT_SET(var) ((var) & (1)) 102 #define IS_E_BIT_SET(var) ((var) & (1)) 103 #define IS_B_BIT_SET(var) ((var) & (1<<1)) 104 #define IS_U_BIT_SET(var) ((var) & (1<<2)) 106 #define MAX_SCTP_CONNECTIONS 8 107 #define SCTP_PRIMARY_PATH_IDX 0 109 #if (VLIB_BUFFER_TRACE_TRAJECTORY) 110 #define sctp_trajectory_add_start(b, start) \ 112 (*vlib_buffer_trace_trajectory_cb) (b, start); \ 115 #define sctp_trajectory_add_start(b, start) 118 enum _sctp_subconn_state
127 #define SCTP_INITIAL_SSHTRESH 65535 128 typedef struct _sctp_sub_connection
147 u32 partially_acked_bytes;
168 u8 unacknowledged_hb;
171 u8 is_retransmitting;
184 #define SET_BIT(A,k) ( A[(k/32)] |= (1 << (k%32)) ) 185 #define CLEAR_BIT(A,k) ( A[(k/32)] &= ~(1 << (k%32)) ) 186 #define TEST_BIT(A,k) ( A[(k/32)] & (1 << (k%32)) ) 189 _bytes_swap (
void *pv,
size_t n)
193 for (lo = 0, hi = n - 1; hi >
lo; lo++, hi--)
201 #define ENDIANESS_SWAP(x) _bytes_swap(&x, sizeof(x)); 203 #define MAX_INFLIGHT_PACKETS 128 204 #define MAX_ENQUEABLE_SACKS 2 210 #define SUGGESTED_COOKIE_LIFE_SPAN_INCREMENT 1000 212 typedef struct _sctp_user_configuration
219 typedef struct _sctp_connection
233 u32 local_initial_tsn;
234 u32 remote_initial_tsn;
236 u32 peer_cookie_life_span_increment;
238 u32 overall_err_count;
239 u32 overall_err_treshold;
242 u8 init_retransmit_err;
252 u32 last_unacked_tsn;
253 u32 next_tsn_expected;
271 u8 smallest_PMTU_idx;
273 u8 overall_sending_status;
277 u8 forming_association_changed;
370 #define IP_PROTOCOL_SCTP 132 373 #define foreach_sctp_fsm_state \ 374 _(CLOSED, "CLOSED") \ 375 _(COOKIE_WAIT, "COOKIE_WAIT") \ 376 _(COOKIE_ECHOED, "COOKIE_ECHOED") \ 377 _(ESTABLISHED, "ESTABLISHED") \ 378 _(SHUTDOWN_PENDING, "SHUTDOWN_PENDING") \ 379 _(SHUTDOWN_SENT, "SHUTDOWN_SENT") \ 380 _(SHUTDOWN_RECEIVED, "SHUTDOWN_RECEIVED") \ 381 _(SHUTDOWN_ACK_SENT, "SHUTDOWN_ACK_SENT") 383 typedef enum _sctp_state
385 #define _(sym, str) SCTP_STATE_##sym, 396 case SCTP_STATE_CLOSED:
397 return "SCTP_STATE_CLOSED";
398 case SCTP_STATE_COOKIE_WAIT:
399 return "SCTP_STATE_COOKIE_WAIT";
400 case SCTP_STATE_COOKIE_ECHOED:
401 return "SCTP_STATE_COOKIE_ECHOED";
402 case SCTP_STATE_ESTABLISHED:
403 return "SCTP_STATE_ESTABLISHED";
404 case SCTP_STATE_SHUTDOWN_PENDING:
405 return "SCTP_STATE_SHUTDOWN_PENDING";
406 case SCTP_STATE_SHUTDOWN_SENT:
407 return "SCTP_STATE_SHUTDOWN_SENT";
408 case SCTP_STATE_SHUTDOWN_RECEIVED:
409 return "SCTP_STATE_SHUTDOWN_RECEIVED";
410 case SCTP_STATE_SHUTDOWN_ACK_SENT:
411 return "SCTP_STATE_SHUTDOWN_ACK_SENT";
432 return "HEARTBEAT_ACK";
438 return "SHUTDOWN_ACK";
440 return "OPERATION_ERROR";
442 return "COOKIE_ECHO";
450 return "SHUTDOWN_COMPLETE";
461 return "SCTP_IPV4_ADDRESS_TYPE";
463 return "SCTP_IPV6_ADDRESS_TYPE";
465 return "SCTP_STATE_COOKIE_TYPE";
467 return "SCTP_UNRECOGNIZED_TYPE";
469 return "SCTP_COOKIE_PRESERVATIVE_TYPE";
471 return "SCTP_HOSTNAME_ADDRESS_TYPE";
473 return "SCTP_SUPPORTED_ADDRESS_TYPES";
478 #define SCTP_TICK 0.001 479 #define SHZ (u32) (1/SCTP_TICK) 480 #define SCTP_TSTAMP_RESOLUTION SCTP_TICK 483 #define SCTP_RTO_INIT 3 * SHZ 484 #define SCTP_RTO_MIN 1 * SHZ 485 #define SCTP_RTO_MAX 60 * SHZ 486 #define SCTP_RTO_BURST 4 487 #define SCTP_RTO_ALPHA 1/8 488 #define SCTP_RTO_BETA 1/4 489 #define SCTP_VALID_COOKIE_LIFE 60 * SHZ 490 #define SCTP_ASSOCIATION_MAX_RETRANS 10 // the overall connection 491 #define SCTP_PATH_MAX_RETRANS 5 // number of attempts per destination address 492 #define SCTP_MAX_INIT_RETRANS 8 // number of attempts 493 #define SCTP_HB_INTERVAL 30 * SHZ 494 #define SCTP_HB_MAX_BURST 1 495 #define SCTP_DATA_IDLE_INTERVAL 15 * SHZ 496 #define SCTP_TO_TIMER_TICK SCTP_TICK*10 498 #define SCTP_CONN_RECOVERY 1 << 1 499 #define SCTP_FAST_RECOVERY 1 << 2 501 typedef struct _sctp_lookup_dispatch
506 typedef struct _sctp_main
517 u8 log2_tstamp_clocks_per_tick;
518 f64 tstamp_ticks_per_clock;
529 tw_timer_wheel_16t_2w_512sl_t *timer_wheels;
543 u32 preallocated_connections;
546 u32 local_endpoints_table_memory;
547 u32 local_endpoints_table_buckets;
551 u32 last_v4_address_rotor;
552 u32 last_v6_address_rotor;
556 u32 bytes_per_buffer;
561 u32 sctp4_established_phase_node_index;
562 u32 sctp6_established_phase_node_index;
622 * sctp_main.tstamp_ticks_per_clock;
623 return sctp_main.time_now[thread_index];
630 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
632 ASSERT (tc->sub_conn[conn_idx].timers[timer_id] ==
636 sub->timers[timer_id] =
637 tw_timer_start_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
638 sub->c_c_index, timer_id, interval);
650 tw_timer_stop_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
651 sub->timers[timer_id]);
691 if (sub->parent ==
NULL)
694 if (sub->subconn_idx > 0)
707 #define ABS(x) ((x) > 0) ? (x) : -(x); 716 u64 prev_ts = sctp_conn->sub_conn[conn_idx].rtt_ts;
717 u64 R = prev_ts - now;
719 if (sctp_conn->sub_conn[conn_idx].RTO == 0)
725 if (sctp_conn->sub_conn[conn_idx].RTO ==
SCTP_RTO_MIN && sctp_conn->sub_conn[conn_idx].SRTT == 0)
727 sctp_conn->sub_conn[conn_idx].SRTT = R;
733 sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
737 RTTVAR = (1 -
SCTP_RTO_BETA) * sctp_conn->sub_conn[conn_idx].RTTVAR +
743 sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
745 sctp_conn->sub_conn[conn_idx].SRTT =
751 sctp_conn->sub_conn[conn_idx].SRTT +
752 4 * sctp_conn->sub_conn[conn_idx].RTTVAR;
759 sctp_conn->sub_conn[conn_idx].RTO = RTO;
766 ASSERT (tc->sub_conn[conn_idx].connection.thread_index ==
771 tw_timer_stop_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
772 sub->timers[timer_id]);
774 tc->sub_conn[conn_idx].timers[timer_id] =
775 tw_timer_start_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
776 sub->c_c_index, timer_id, interval);
796 #define SELECT_MAX_RETRIES 8 808 if (sctp_conn->sub_conn[i].cwnd > cwnd)
811 cwnd = sctp_conn->sub_conn[
i].cwnd;
824 if (sctp_conn->sub_conn[i].connection.lcl_ip.ip6.as_u64[0] ==
826 sctp_conn->sub_conn[i].connection.lcl_ip.ip6.as_u64[1] ==
828 sctp_conn->sub_conn[i].connection.rmt_ip.ip6.as_u64[0] ==
830 sctp_conn->sub_conn[i].connection.rmt_ip.ip6.as_u64[1] ==
834 clib_warning (
"Did not find a sub-connection; defaulting to %u",
846 if (sctp_conn->sub_conn[i].connection.lcl_ip.ip4.as_u32 ==
848 && sctp_conn->sub_conn[i].connection.rmt_ip.ip4.as_u32 ==
852 clib_warning (
"Did not find a sub-connection; defaulting to %u",
870 u8 sctp_hdr_opts_len)
894 u8 sctp_hdr_opts_len)
923 if (sctp_conn->sub_conn[i].PMTU <
924 sctp_conn->sub_conn[smallest_pmtu_index].PMTU)
925 smallest_pmtu_index =
i;
929 sctp_conn->smallest_PMTU_idx = smallest_pmtu_index;
940 sctp_conn->sub_conn[
i].cwnd =
941 clib_min (4 * sctp_conn->sub_conn[i].PMTU,
942 clib_max (2 * sctp_conn->sub_conn[i].PMTU, 4380));
948 sctp_conn->sub_conn[
i].partially_acked_bytes = 0;
961 if (sctp_conn->sub_conn[idx].cwnd == 0)
971 u32 inflight = sctp_conn->next_tsn - sctp_conn->last_unacked_tsn;
976 if (sctp_conn->sub_conn[i].is_retransmitting)
978 sctp_conn->sub_conn[
i].cwnd = 1 * sctp_conn->sub_conn[
i].PMTU;
983 if (sctp_conn->sub_conn[i].last_data_ts >
986 sctp_conn->sub_conn[
i].cwnd =
987 clib_max (sctp_conn->sub_conn[i].cwnd / 2,
988 4 * sctp_conn->sub_conn[i].PMTU);
993 if (sctp_conn->sub_conn[i].cwnd <= sctp_conn->sub_conn[i].ssthresh)
1001 sctp_conn->sub_conn[
i].cwnd =
1002 clib_min (sctp_conn->sub_conn[i].PMTU, 1);
1007 sctp_conn->sub_conn[i].cwnd)
1008 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)
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 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)
u16 data_offset
offset relative to ip hdr
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.
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)
vl_api_fib_path_type_t type
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)
u32 tsn
Transmission Sequence Number.
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)
#define sctp_buffer_opaque(b)
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.
STATIC_ASSERT(sizeof(sctp_buffer_opaque_t)<=STRUCT_SIZE_OF(vnet_buffer_opaque_t, unused), "sctp_buffer_opaque_t too large for vnet_buffer_opaque_t")
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.
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.
#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)
u8 subconn_idx
index of the sub_connection being used
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)
u16 ssn
Stream Sequence Number.
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)
vl_api_dhcp_client_state_t state
#define STRUCT_SIZE_OF(t, f)
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.
unformat_function_t unformat_pg_sctp_header
#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