diff options
Diffstat (limited to 'src/vnet/tcp/tcp_output.c')
-rw-r--r-- | src/vnet/tcp/tcp_output.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index a7b0e398d36..79866aff03a 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -1599,7 +1599,7 @@ tcp_timer_retransmit_handler (u32 tc_index) } if (tcp_opts_sack_permitted (&tc->rcv_opts)) - scoreboard_init_high_rxt (&tc->sack_sb, tc->snd_una + tc->snd_mss); + scoreboard_init_rxt (&tc->sack_sb, tc->snd_una + n_bytes); tcp_program_retransmit (tc); } @@ -1858,7 +1858,7 @@ done: /** * Estimate send space using proportional rate reduction (RFC6937) */ -static int +int tcp_fastrecovery_prr_snd_space (tcp_connection_t * tc) { u32 pipe, prr_out; @@ -1874,13 +1874,24 @@ tcp_fastrecovery_prr_snd_space (tcp_connection_t * tc) } else { - int limit = tc->prr_delivered - prr_out + tc->snd_mss; + int limit; + limit = clib_max ((int) (tc->prr_delivered - prr_out), 0) + tc->snd_mss; space = clib_min (tc->ssthresh - pipe, limit); } space = clib_max (space, prr_out ? 0 : tc->snd_mss); return space; } +static inline u8 +tcp_retransmit_should_retry_head (tcp_connection_t * tc, + sack_scoreboard_t * sb) +{ + u32 tx_adv_sack = sb->high_sacked - tc->snd_congestion; + f64 rr = (f64) tc->ssthresh / tc->prev_cwnd; + + return (tx_adv_sack > (tc->snd_una - tc->prr_start) * rr); +} + #define scoreboard_rescue_rxt_valid(_sb, _tc) \ (seq_geq (_sb->rescue_rxt, _tc->snd_una) \ && seq_leq (_sb->rescue_rxt, _tc->snd_congestion)) @@ -1917,8 +1928,31 @@ tcp_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, return 0; } - TCP_EVT (TCP_EVT_CC_EVT, tc, 0); sb = &tc->sack_sb; + + /* Check if snd_una is a lost retransmit */ + if (seq_gt (sb->high_sacked, tc->snd_congestion) + && tc->rxt_head != tc->snd_una + && tcp_retransmit_should_retry_head (tc, sb)) + { + n_written = tcp_prepare_retransmit_segment (wrk, tc, 0, tc->snd_mss, + &b); + if (!n_written) + { + tcp_program_retransmit (tc); + goto done; + } + bi = vlib_get_buffer_index (vm, b); + tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4); + n_segs = 1; + + tc->rxt_head = tc->snd_una; + tc->rxt_delivered += n_written; + tc->prr_delivered += n_written; + ASSERT (tc->rxt_delivered <= tc->snd_rxt_bytes); + } + + TCP_EVT (TCP_EVT_CC_EVT, tc, 0); hole = scoreboard_get_hole (sb, sb->cur_rxt_hole); max_deq = transport_max_tx_dequeue (&tc->connection); @@ -1931,7 +1965,7 @@ tcp_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, if (!hole) { /* We are out of lost holes to retransmit so send some new data. */ - if (max_deq) + if (max_deq > tc->snd_mss) { u32 n_segs_new, av_window; av_window = tc->snd_wnd - (tc->snd_nxt - tc->snd_una); |