diff options
Diffstat (limited to 'src/vnet/tcp/tcp_output.c')
-rw-r--r-- | src/vnet/tcp/tcp_output.c | 78 |
1 files changed, 57 insertions, 21 deletions
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index ed1c641d80f..2e6036b410a 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -1409,7 +1409,11 @@ tcp_rxt_timeout_cc (tcp_connection_t * tc) /* Cleanly recover cc (also clears up fast retransmit) */ if (tcp_in_fastrecovery (tc)) - tcp_cc_fastrecovery_exit (tc); + { + /* TODO be less aggressive about this */ + scoreboard_clear (&tc->sack_sb); + tcp_cc_fastrecovery_exit (tc); + } /* Start again from the beginning */ tc->cc_algo->congestion (tc); @@ -1487,6 +1491,8 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) /* First retransmit timeout */ if (tc->rto_boff == 1) tcp_rxt_timeout_cc (tc); + else + scoreboard_clear (&tc->sack_sb); /* If we've sent beyond snd_congestion, update it */ if (seq_gt (tc->snd_una_max, tc->snd_congestion)) @@ -1499,9 +1505,6 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) * shortfall */ n_bytes = tcp_prepare_retransmit_segment (tc, 0, tc->snd_mss, &b); - /* TODO be less aggressive about this */ - scoreboard_clear (&tc->sack_sb); - if (n_bytes == 0) { tcp_retransmit_timer_force_update (tc); @@ -1680,7 +1683,7 @@ tcp_timer_persist_handler (u32 index) /** * Retransmit first unacked segment */ -void +int tcp_retransmit_first_unacked (tcp_connection_t * tc) { vlib_main_t *vm = vlib_get_main (); @@ -1691,20 +1694,23 @@ tcp_retransmit_first_unacked (tcp_connection_t * tc) tc->snd_nxt = tc->snd_una; TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 2); + n_bytes = tcp_prepare_retransmit_segment (tc, 0, tc->snd_mss, &b); if (!n_bytes) - return; + return -1; + bi = vlib_get_buffer_index (vm, b); tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4); - tc->snd_nxt = old_snd_nxt; + + return 0; } /** * Do fast retransmit with SACKs */ -void -tcp_fast_retransmit_sack (tcp_connection_t * tc) +int +tcp_fast_retransmit_sack (tcp_connection_t * tc, u32 burst_size) { vlib_main_t *vm = vlib_get_main (); u32 n_written = 0, offset, max_bytes, n_segs = 0; @@ -1720,13 +1726,16 @@ tcp_fast_retransmit_sack (tcp_connection_t * tc) old_snd_nxt = tc->snd_nxt; sb = &tc->sack_sb; snd_space = tcp_available_cc_snd_space (tc); + hole = scoreboard_get_hole (sb, sb->cur_rxt_hole); if (snd_space < tc->snd_mss) - goto done; + { + tcp_program_fastretransmit (tc); + goto done; + } TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 0); - hole = scoreboard_get_hole (sb, sb->cur_rxt_hole); - while (hole && snd_space > 0 && n_segs++ < VLIB_FRAME_SIZE) + while (snd_space > 0 && n_segs < burst_size) { hole = scoreboard_next_rxt_hole (sb, hole, tcp_fastrecovery_sent_1_smss (tc), @@ -1736,7 +1745,21 @@ tcp_fast_retransmit_sack (tcp_connection_t * tc) if (!can_rescue || !(seq_lt (sb->rescue_rxt, tc->snd_una) || seq_gt (sb->rescue_rxt, tc->snd_congestion))) - break; + { + if (tcp_fastrecovery_first (tc)) + break; + + /* We tend to lose the first segment. Try re-resending + * it but only once and after we've tried everything */ + hole = scoreboard_first_hole (sb); + if (hole && hole->start == tc->snd_una) + { + tcp_retransmit_first_unacked (tc); + tcp_fastrecovery_first_on (tc); + n_segs += 1; + } + break; + } /* If rescue rxt undefined or less than snd_una then one segment of * up to SMSS octets that MUST include the highest outstanding @@ -1756,6 +1779,7 @@ tcp_fast_retransmit_sack (tcp_connection_t * tc) bi = vlib_get_buffer_index (vm, b); tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4); + n_segs += 1; break; } @@ -1776,22 +1800,27 @@ tcp_fast_retransmit_sack (tcp_connection_t * tc) tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4); ASSERT (n_written <= snd_space); snd_space -= n_written; + n_segs += 1; } + if (hole) + tcp_program_fastretransmit (tc); + done: /* If window allows, send 1 SMSS of new data */ tc->snd_nxt = old_snd_nxt; + return n_segs; } /** * Fast retransmit without SACK info */ -void -tcp_fast_retransmit_no_sack (tcp_connection_t * tc) +int +tcp_fast_retransmit_no_sack (tcp_connection_t * tc, u32 burst_size) { vlib_main_t *vm = vlib_get_main (); u32 n_written = 0, offset = 0, bi, old_snd_nxt; - int snd_space; + int snd_space, n_segs = 0; vlib_buffer_t *b; ASSERT (tcp_in_fastrecovery (tc)); @@ -1802,7 +1831,7 @@ tcp_fast_retransmit_no_sack (tcp_connection_t * tc) tc->snd_nxt = tc->snd_una; snd_space = tcp_available_cc_snd_space (tc); - while (snd_space > 0) + while (snd_space > 0 && n_segs < burst_size) { offset += n_written; n_written = tcp_prepare_retransmit_segment (tc, offset, snd_space, &b); @@ -1814,22 +1843,29 @@ tcp_fast_retransmit_no_sack (tcp_connection_t * tc) bi = vlib_get_buffer_index (vm, b); tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4); snd_space -= n_written; + n_segs += 1; } + /* More data to resend */ + if (seq_lt (tc->snd_nxt, tc->snd_congestion)) + tcp_program_fastretransmit (tc); + /* Restore snd_nxt. If window allows, send 1 SMSS of new data */ tc->snd_nxt = old_snd_nxt; + + return n_segs; } /** * Do fast retransmit */ -void -tcp_fast_retransmit (tcp_connection_t * tc) +int +tcp_fast_retransmit (tcp_connection_t * tc, u32 burst_size) { if (tcp_opts_sack_permitted (&tc->rcv_opts)) - tcp_fast_retransmit_sack (tc); + return tcp_fast_retransmit_sack (tc, burst_size); else - tcp_fast_retransmit_no_sack (tc); + return tcp_fast_retransmit_no_sack (tc, burst_size); } static u32 |