aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/sctp
diff options
context:
space:
mode:
authorMarco Varlese <marco.varlese@suse.com>2018-02-02 17:17:51 +0100
committerFlorin Coras <florin.coras@gmail.com>2018-02-05 15:09:52 +0000
commit21c8baf9a77b49af3dd54a7f64ce34dc932f10c3 (patch)
treecc542b1b297617616b129bc34d056e7fa269a495 /src/vnet/sctp
parent7b0933a97d8830e288ab3e350b07656196599847 (diff)
SCTP: calculate RTO / RTT and RTTVAR as per RFC
This patch addresses the need to calculate the RTO / RTT and RTTVAR according to the rules depicted by the RFC4960 at section 6.3.1 Change-Id: I1d346f3c67610070b3f602f32c7738d58b99ffed Signed-off-by: Marco Varlese <marco.varlese@suse.com>
Diffstat (limited to 'src/vnet/sctp')
-rw-r--r--src/vnet/sctp/sctp.c14
-rw-r--r--src/vnet/sctp/sctp.h73
-rw-r--r--src/vnet/sctp/sctp_input.c26
-rw-r--r--src/vnet/sctp/sctp_output.c56
4 files changed, 122 insertions, 47 deletions
diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c
index d0f37f4346e..bd62c3213e9 100644
--- a/src/vnet/sctp/sctp.c
+++ b/src/vnet/sctp/sctp.c
@@ -135,6 +135,7 @@ sctp_connection_timers_init (sctp_connection_t * sctp_conn)
for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
{
sctp_conn->sub_conn[i].RTO = SCTP_RTO_INIT;
+
for (j = 0; j < SCTP_N_TIMERS; j++)
{
sctp_conn->sub_conn[i].timers[j] = SCTP_TIMER_HANDLE_INVALID;
@@ -601,7 +602,6 @@ sctp_timer_init_handler (u32 conn_index, u32 timer_id)
{
sctp_connection_t *sctp_conn;
- clib_warning ("");
sctp_conn = sctp_connection_get (conn_index, vlib_get_thread_index ());
/* note: the connection may have already disappeared */
if (PREDICT_FALSE (sctp_conn == 0))
@@ -650,8 +650,6 @@ sctp_expired_timers_dispatch (u32 * expired_timers)
(*sctp_timer_expiration_handlers[timer_id]) (connection_index,
timer_id);
}
-
- clib_warning ("");
}
void
@@ -783,6 +781,15 @@ format_sctp_half_open (u8 * s, va_list * args)
return format (s, "%U", format_sctp_connection_id, sctp_conn);
}
+void
+sctp_update_time (f64 now, u8 thread_index)
+{
+ sctp_set_time_now (thread_index);
+ tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
+ now);
+ sctp_flush_frames_to_output (thread_index);
+}
+
/* *INDENT OFF* */
const static transport_proto_vft_t sctp_proto = {
.enable = sctp_enable_disable,
@@ -795,6 +802,7 @@ const static transport_proto_vft_t sctp_proto = {
.send_mss = sctp_session_send_mss,
.send_space = sctp_session_send_space,
.tx_fifo_offset = NULL, //sctp_session_tx_fifo_offset,
+ .update_time = sctp_update_time,
.get_connection = sctp_session_get_transport,
.get_listener = sctp_session_get_listener,
.get_half_open = sctp_half_open_session_get_transport,
diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h
index 8f80d840c33..0634f019af7 100644
--- a/src/vnet/sctp/sctp.h
+++ b/src/vnet/sctp/sctp.h
@@ -79,9 +79,11 @@ typedef struct _sctp_sub_connection
u32 cwnd; /**< The current congestion window. */
u32 ssthresh; /**< The current ssthresh value. */
+ u32 rtt_ts; /**< USED to hold the timestamp of when the packet has been sent */
+
u32 RTO; /**< The current retransmission timeout value. */
u32 SRTT; /**< The current smoothed round-trip time. */
- u32 RTTVAR; /**< The current RTT variation. */
+ f32 RTTVAR; /**< The current RTT variation. */
u32 partially_acked_bytes; /**< The tracking method for increase of cwnd when in
congestion avoidance mode (see Section 7.2.2).*/
@@ -195,9 +197,6 @@ typedef struct _sctp_connection
u32 rcv_a_rwnd; /**< LOCAL max seg size that includes options. To be updated by congestion algos, etc. */
u32 snd_a_rwnd; /**< REMOTE max seg size that includes options. To be updated if peer pushes back on window, etc.*/
- u32 rtt_ts;
- u32 rtt_seq;
-
u8 overall_sending_status; /**< 0 indicates first fragment of a user message
1 indicates normal stream
2 indicates last fragment of a user message */
@@ -523,7 +522,7 @@ sctp_timer_set (sctp_connection_t * tc, u8 conn_idx, u8 timer_id,
SCTP_TIMER_HANDLE_INVALID);
sctp_sub_connection_t *sub = &tc->sub_conn[conn_idx];
- tc->sub_conn[conn_idx].timers[timer_id] =
+ sub->timers[timer_id] =
tw_timer_start_16t_2w_512sl (&sctp_main.timer_wheels[sub->c_thread_index],
sub->c_c_index, timer_id, interval);
}
@@ -542,15 +541,6 @@ sctp_timer_reset (sctp_connection_t * tc, u8 conn_idx, u8 timer_id)
sub->timers[timer_id] = SCTP_TIMER_HANDLE_INVALID;
}
-always_inline void
-sctp_update_time (f64 now, u32 thread_index)
-{
- sctp_set_time_now (thread_index);
- tw_timer_expire_timers_16t_2w_512sl (&sctp_main.timer_wheels[thread_index],
- now);
- sctp_flush_frames_to_output (thread_index);
-}
-
/**
* Try to cleanup half-open connection
*
@@ -599,6 +589,61 @@ sctp_time_now (void)
return sctp_main.time_now[vlib_get_thread_index ()];
}
+#define ABS(x) ((x) > 0) ? (x) : -(x);
+
+always_inline void
+sctp_calculate_rto (sctp_connection_t * sctp_conn, u8 conn_idx)
+{
+ /* See RFC4960, 6.3.1. RTO Calculation */
+ u32 RTO = 0;
+ f32 RTTVAR = 0;
+ u32 now = sctp_time_now ();
+ u32 prev_ts = sctp_conn->sub_conn[conn_idx].rtt_ts;
+ u32 R = prev_ts - now;
+
+ if (sctp_conn->sub_conn[conn_idx].RTO == 0) // C1: Let's initialize our RTO
+ {
+ sctp_conn->sub_conn[conn_idx].RTO = SCTP_RTO_MIN;
+ return;
+ }
+
+ if (sctp_conn->sub_conn[conn_idx].RTO == SCTP_RTO_MIN && sctp_conn->sub_conn[conn_idx].SRTT == 0) // C2: First RTT calculation
+ {
+ sctp_conn->sub_conn[conn_idx].SRTT = R;
+ RTTVAR = R / 2;
+
+ if (RTTVAR == 0)
+ RTTVAR = 100e-3; /* 100 ms */
+
+ sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
+ }
+ else // C3: RTT already exists; let's recalculate
+ {
+ RTTVAR = (1 - SCTP_RTO_BETA) * sctp_conn->sub_conn[conn_idx].RTTVAR +
+ SCTP_RTO_BETA * ABS (sctp_conn->sub_conn[conn_idx].SRTT - R);
+
+ if (RTTVAR == 0)
+ RTTVAR = 100e-3; /* 100 ms */
+
+ sctp_conn->sub_conn[conn_idx].RTTVAR = RTTVAR;
+
+ sctp_conn->sub_conn[conn_idx].SRTT =
+ (1 - SCTP_RTO_ALPHA) * sctp_conn->sub_conn[conn_idx].SRTT +
+ SCTP_RTO_ALPHA * R;
+ }
+
+ RTO =
+ sctp_conn->sub_conn[conn_idx].SRTT +
+ 4 * sctp_conn->sub_conn[conn_idx].RTTVAR;
+ if (RTO < SCTP_RTO_MIN) // C6
+ RTO = SCTP_RTO_MIN;
+
+ if (RTO > SCTP_RTO_MAX) // C7
+ RTO = SCTP_RTO_MAX;
+
+ sctp_conn->sub_conn[conn_idx].RTO = RTO;
+}
+
always_inline void
sctp_timer_update (sctp_connection_t * tc, u8 conn_idx, u8 timer_id,
u32 interval)
diff --git a/src/vnet/sctp/sctp_input.c b/src/vnet/sctp/sctp_input.c
index 44624500016..0337e9f8aa0 100644
--- a/src/vnet/sctp/sctp_input.c
+++ b/src/vnet/sctp/sctp_input.c
@@ -427,8 +427,8 @@ sctp_is_valid_init_ack (sctp_header_t * sctp_hdr,
always_inline u16
sctp_handle_init_ack (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b0,
- u16 sctp_implied_length)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 sctp_implied_length)
{
sctp_init_ack_chunk_t *init_ack_chunk =
(sctp_init_ack_chunk_t *) (sctp_hdr);
@@ -450,6 +450,8 @@ sctp_handle_init_ack (sctp_header_t * sctp_hdr,
if (sctp_is_bundling (sctp_implied_length, &init_ack_chunk->chunk_hdr))
return SCTP_ERROR_BUNDLING_VIOLATION;
+ sctp_calculate_rto (sctp_conn, idx);
+
/* remote_tag to be placed in the VERIFICATION_TAG field of the COOKIE_ECHO chunk */
sctp_conn->remote_tag = init_ack_chunk->initiate_tag;
sctp_conn->remote_initial_tsn =
@@ -535,7 +537,7 @@ sctp_handle_init_ack (sctp_header_t * sctp_hdr,
/* Start the T1_COOKIE timer */
sctp_timer_set (sctp_conn, sctp_pick_conn_idx_on_chunk (COOKIE_ECHO),
- SCTP_TIMER_T1_COOKIE, SCTP_RTO_INIT);
+ SCTP_TIMER_T1_COOKIE, sctp_conn->sub_conn[idx].RTO);
return SCTP_ERROR_NONE;
}
@@ -764,6 +766,7 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
sctp_connection_t * sctp_conn, vlib_buffer_t * b0)
{
+ u32 now = sctp_time_now ();
/* Build TCB */
u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ECHO);
@@ -777,7 +780,8 @@ sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
return SCTP_ERROR_INVALID_TAG;
}
- u32 now = sctp_time_now ();
+ sctp_calculate_rto (sctp_conn, idx);
+
u32 creation_time =
clib_net_to_host_u32 (cookie_echo->cookie.creation_time);
u32 cookie_lifespan =
@@ -815,14 +819,14 @@ sctp_handle_cookie_ack (sctp_header_t * sctp_hdr,
return SCTP_ERROR_INVALID_TAG;
}
+ sctp_calculate_rto (sctp_conn, idx);
+
sctp_timer_reset (sctp_conn, idx, SCTP_TIMER_T1_COOKIE);
/* Change state */
sctp_conn->state = SCTP_STATE_ESTABLISHED;
stream_session_accept_notify (&sctp_conn->sub_conn[idx].connection);
- sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T3_RXTX, SCTP_RTO_INIT);
-
return SCTP_ERROR_NONE;
}
@@ -959,11 +963,10 @@ sctp46_rcv_phase_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
error0 =
sctp_handle_init_ack (sctp_hdr, sctp_chunk_hdr,
- new_sctp_conn, b0,
+ new_sctp_conn, idx, b0,
sctp_implied_length);
sctp_init_mss (new_sctp_conn);
- //sctp_init_snd_vars (new_sctp_conn);
if (session_stream_connect_notify
(&new_sctp_conn->sub_conn[idx].connection, 0))
@@ -1416,7 +1419,12 @@ sctp_handle_sack (sctp_selective_ack_chunk_t * sack_chunk,
return SCTP_ERROR_INVALID_TAG;
}
- sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX, SCTP_RTO_INIT);
+ sctp_calculate_rto (sctp_conn, idx);
+
+ sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
+ sctp_conn->sub_conn[idx].RTO);
+
+ sctp_conn->sub_conn[idx].RTO_pending = 0;
*next0 = sctp_next_output (sctp_conn->sub_conn[idx].connection.is_ip4);
diff --git a/src/vnet/sctp/sctp_output.c b/src/vnet/sctp/sctp_output.c
index 3d870ff5bd4..ed9ffd36262 100644
--- a/src/vnet/sctp/sctp_output.c
+++ b/src/vnet/sctp/sctp_output.c
@@ -556,6 +556,9 @@ sctp_prepare_cookie_ack_chunk (sctp_connection_t * sctp_conn,
vnet_sctp_set_chunk_type (&cookie_ack_chunk->chunk_hdr, COOKIE_ACK);
vnet_sctp_set_chunk_length (&cookie_ack_chunk->chunk_hdr, chunk_len);
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+
vnet_buffer (b)->sctp.connection_index =
sctp_conn->sub_conn[idx].connection.c_index;
}
@@ -589,6 +592,10 @@ sctp_prepare_cookie_echo_chunk (sctp_connection_t * sctp_conn,
vnet_sctp_set_chunk_length (&cookie_echo_chunk->chunk_hdr, chunk_len);
clib_memcpy (&(cookie_echo_chunk->cookie), sc,
sizeof (sctp_state_cookie_param_t));
+
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+
vnet_buffer (b)->sctp.connection_index =
sctp_conn->sub_conn[idx].connection.c_index;
}
@@ -732,6 +739,9 @@ sctp_prepare_initack_chunk (sctp_connection_t * sctp_conn, vlib_buffer_t * b,
sctp_conn->local_tag = init_ack_chunk->initiate_tag;
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+
vnet_buffer (b)->sctp.connection_index =
sctp_conn->sub_conn[idx].connection.c_index;
}
@@ -799,6 +809,9 @@ sctp_send_shutdown (sctp_connection_t * sctp_conn)
sctp_push_ip_hdr (tm, &sctp_conn->sub_conn[idx], b);
sctp_enqueue_to_output_now (vm, b, bi,
sctp_conn->sub_conn[idx].connection.is_ip4);
+
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
}
/**
@@ -858,8 +871,12 @@ sctp_send_shutdown_ack (sctp_connection_t * sctp_conn)
sctp_enqueue_to_ip_lookup (vm, b, bi,
sctp_conn->sub_conn[idx].connection.is_ip4);
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+
/* Start the SCTP_TIMER_T2_SHUTDOWN timer */
- sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN, SCTP_RTO_INIT);
+ sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
+ sctp_conn->sub_conn[idx].RTO);
sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
}
@@ -1034,35 +1051,28 @@ sctp_send_init (sctp_connection_t * sctp_conn)
sctp_init_buffer (vm, b);
sctp_prepare_init_chunk (sctp_conn, b);
- /* Measure RTT with this */
- sctp_conn->rtt_ts = sctp_time_now ();
- sctp_conn->rtt_seq = sctp_conn->next_tsn;
-
sctp_push_ip_hdr (tm, &sctp_conn->sub_conn[idx], b);
sctp_enqueue_to_ip_lookup_now (vm, b, bi,
sctp_conn->sub_conn[idx].c_is_ip4);
+ /* Measure RTT with this */
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
+
/* Start the T1_INIT timer */
- sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T1_INIT, SCTP_RTO_INIT);
+ sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T1_INIT,
+ sctp_conn->sub_conn[idx].RTO);
+
/* Change state to COOKIE_WAIT */
sctp_conn->state = SCTP_STATE_COOKIE_WAIT;
}
-always_inline u8
-sctp_in_cong_recovery (sctp_connection_t * sctp_conn)
-{
- return 0;
-}
-
/**
* Push SCTP header and update connection variables
*/
static void
-sctp_push_hdr_i (sctp_connection_t * sctp_conn, vlib_buffer_t * b,
+sctp_push_hdr_i (sctp_connection_t * sctp_conn, u8 idx, vlib_buffer_t * b,
sctp_state_t next_state)
{
- u8 idx = sctp_pick_conn_idx_on_chunk (DATA);
-
u16 data_len =
b->current_length + b->total_length_not_including_first_buffer;
ASSERT (!b->total_length_not_including_first_buffer
@@ -1112,13 +1122,17 @@ sctp_push_header (transport_connection_t * trans_conn, vlib_buffer_t * b)
{
sctp_connection_t *sctp_conn =
sctp_get_connection_from_transport (trans_conn);
- sctp_push_hdr_i (sctp_conn, b, SCTP_STATE_ESTABLISHED);
- if (sctp_conn->rtt_ts == 0 && !sctp_in_cong_recovery (sctp_conn))
+ u8 idx = sctp_pick_conn_idx_on_chunk (DATA);
+
+ sctp_push_hdr_i (sctp_conn, idx, b, SCTP_STATE_ESTABLISHED);
+
+ if (sctp_conn->sub_conn[idx].RTO_pending == 0)
{
- sctp_conn->rtt_ts = sctp_time_now ();
- sctp_conn->rtt_seq = sctp_conn->next_tsn;
+ sctp_conn->sub_conn[idx].RTO_pending = 1;
+ sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
}
+
sctp_trajectory_add_start (b0, 3);
return 0;
@@ -1341,14 +1355,14 @@ sctp46_output_inline (vlib_main_t * vm,
{
/* Start the SCTP_TIMER_T2_SHUTDOWN timer */
sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
- SCTP_RTO_INIT);
+ sctp_conn->sub_conn[idx].RTO);
sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT;
}
if (chunk_type == DATA)
{
sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
- SCTP_RTO_INIT);
+ sctp_conn->sub_conn[idx].RTO);
}
vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;