diff options
author | Marco Varlese <marco.varlese@suse.com> | 2018-03-13 15:44:56 +0100 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2018-03-13 23:01:52 +0000 |
commit | 3e9b4656a264066f572dc73f091b3583153b05e2 (patch) | |
tree | baed5eb9d65409d295fec76f031794fcb18a27fc | |
parent | 8145842bf273823192140c57fc773bb92d9db64f (diff) |
SCTP: data retransmission & snd_space fix
This patch addresses two things:
1) The data retransmission which needs to be taken care of when the
SCTP_TIMER_T3_RXTX;
2) The correct calculation of the amount of data transmittable
considered: the local window, the peer window and any data inflight.
Change-Id: I2d03a6cb43e4e7770c4910f8547c66e1026aeace
Signed-off-by: Marco Varlese <marco.varlese@suse.com>
-rw-r--r-- | src/vnet/sctp/sctp.c | 12 | ||||
-rw-r--r-- | src/vnet/sctp/sctp.h | 5 | ||||
-rw-r--r-- | src/vnet/sctp/sctp_output.c | 75 |
3 files changed, 88 insertions, 4 deletions
diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c index 76a1bf41eeb..6e2dccc552e 100644 --- a/src/vnet/sctp/sctp.c +++ b/src/vnet/sctp/sctp.c @@ -628,8 +628,17 @@ sctp_snd_space (sctp_connection_t * sctp_conn) return 0; u8 idx = sctp_data_subconn_select (sctp_conn); + + u32 available_wnd = + clib_min (sctp_conn->peer_rwnd, sctp_conn->sub_conn[idx].cwnd); + int flight_size = (int) (sctp_conn->next_tsn - sctp_conn->last_unacked_tsn); + + if (available_wnd <= flight_size) + return 0; + /* Finally, let's subtract the DATA chunk headers overhead */ - return sctp_conn->sub_conn[idx].cwnd - + return available_wnd - + flight_size - sizeof (sctp_payload_data_chunk_t) - sizeof (sctp_full_hdr_t); } @@ -747,6 +756,7 @@ sctp_expired_timers_cb (u32 conn_index, u32 timer_id) break; case SCTP_TIMER_T3_RXTX: sctp_timer_reset (sctp_conn, conn_index, timer_id); + sctp_conn->flags |= SCTP_CONN_RECOVERY; sctp_data_retransmit (sctp_conn); break; case SCTP_TIMER_T4_HEARTBEAT: diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h index f0ce5949285..d9b2f569e4a 100644 --- a/src/vnet/sctp/sctp.h +++ b/src/vnet/sctp/sctp.h @@ -463,11 +463,12 @@ sctp_optparam_type_to_string (u8 type) #define SCTP_MAX_INIT_RETRANS 8 // number of attempts #define SCTP_HB_INTERVAL 30 * SHZ #define SCTP_HB_MAX_BURST 1 - #define SCTP_DATA_IDLE_INTERVAL 15 * SHZ /* 15 seconds; the time-interval after which the connetion is considered IDLE */ - #define SCTP_TO_TIMER_TICK SCTP_TICK*10 /* Period for converting from SCTP_TICK */ +#define SCTP_CONN_RECOVERY 1 << 1 +#define SCTP_FAST_RECOVERY 1 << 2 + typedef struct _sctp_lookup_dispatch { u8 next, error; diff --git a/src/vnet/sctp/sctp_output.c b/src/vnet/sctp/sctp_output.c index 9ac3feb8aab..f63519212ec 100644 --- a/src/vnet/sctp/sctp_output.c +++ b/src/vnet/sctp/sctp_output.c @@ -1456,10 +1456,65 @@ sctp_push_header (transport_connection_t * trans_conn, vlib_buffer_t * b) return 0; } +u32 +sctp_prepare_data_retransmit (sctp_connection_t * sctp_conn, + u8 idx, + u32 offset, + u32 max_deq_bytes, vlib_buffer_t ** b) +{ + sctp_main_t *tm = vnet_get_sctp_main (); + vlib_main_t *vm = vlib_get_main (); + int n_bytes = 0; + u32 bi, available_bytes, seg_size; + u8 *data; + + ASSERT (sctp_conn->state >= SCTP_STATE_ESTABLISHED); + ASSERT (max_deq_bytes != 0); + + /* + * Make sure we can retransmit something + */ + available_bytes = + stream_session_tx_fifo_max_dequeue (&sctp_conn->sub_conn[idx].connection); + ASSERT (available_bytes >= offset); + available_bytes -= offset; + if (!available_bytes) + return 0; + max_deq_bytes = clib_min (sctp_conn->sub_conn[idx].cwnd, max_deq_bytes); + max_deq_bytes = clib_min (available_bytes, max_deq_bytes); + + seg_size = max_deq_bytes; + + /* + * Allocate and fill in buffer(s) + */ + + if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi))) + return 0; + *b = vlib_get_buffer (vm, bi); + data = sctp_init_buffer (vm, *b); + + /* Easy case, buffer size greater than mss */ + if (PREDICT_TRUE (seg_size <= tm->bytes_per_buffer)) + { + n_bytes = + stream_session_peek_bytes (&sctp_conn->sub_conn[idx].connection, data, + offset, max_deq_bytes); + ASSERT (n_bytes == max_deq_bytes); + b[0]->current_length = n_bytes; + sctp_push_hdr_i (sctp_conn, *b, sctp_conn->state); + } + + return n_bytes; +} + void sctp_data_retransmit (sctp_connection_t * sctp_conn) { - /* TODO: requires use of PEEK/SEND */ + vlib_main_t *vm = vlib_get_main (); + vlib_buffer_t *b = 0; + u32 bi, n_bytes = 0; + SCTP_DBG_OUTPUT ("SCTP_CONN = %p, IDX = %u, S_INDEX = %u, C_INDEX = %u, sctp_conn->[...].LCL_PORT = %u, sctp_conn->[...].RMT_PORT = %u", sctp_conn, idx, sctp_conn->sub_conn[idx].connection.s_index, @@ -1467,6 +1522,24 @@ sctp_data_retransmit (sctp_connection_t * sctp_conn) sctp_conn->sub_conn[idx].connection.lcl_port, sctp_conn->sub_conn[idx].connection.rmt_port); + if (sctp_conn->state >= SCTP_STATE_ESTABLISHED) + { + return; + } + + u8 idx = sctp_data_subconn_select (sctp_conn); + + n_bytes = + sctp_prepare_data_retransmit (sctp_conn, idx, 0, + sctp_conn->sub_conn[idx].cwnd, &b); + if (n_bytes > 0) + SCTP_DBG_OUTPUT ("We have data (%u bytes) to retransmit", n_bytes); + + bi = vlib_get_buffer_index (vm, b); + + sctp_enqueue_to_output_now (vm, b, bi, + sctp_conn->sub_conn[idx].connection.is_ip4); + return; } |