diff options
Diffstat (limited to 'src/vnet/tcp/tcp_output.c')
-rw-r--r-- | src/vnet/tcp/tcp_output.c | 167 |
1 files changed, 115 insertions, 52 deletions
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index 7b0303f3033..79cc95e9f0b 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -1188,21 +1188,21 @@ tcp_send_ack (tcp_connection_t * tc) } void -tcp_program_ack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc) +tcp_program_ack (tcp_connection_t * tc) { if (!(tc->flags & TCP_CONN_SNDACK)) { - vec_add1 (wrk->pending_acks, tc->c_c_index); + session_add_self_custom_tx_evt (&tc->connection, 1); tc->flags |= TCP_CONN_SNDACK; } } void -tcp_program_dupack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc) +tcp_program_dupack (tcp_connection_t * tc) { if (!(tc->flags & TCP_CONN_SNDACK)) { - vec_add1 (wrk->pending_acks, tc->c_c_index); + session_add_self_custom_tx_evt (&tc->connection, 1); tc->flags |= TCP_CONN_SNDACK; } if (tc->pending_dupacks < 255) @@ -1210,51 +1210,13 @@ tcp_program_dupack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc) } void -tcp_send_acks (tcp_worker_ctx_t * wrk) +tcp_program_fastretransmit (tcp_connection_t * tc) { - u32 thread_index, *pending_acks; - tcp_connection_t *tc; - int i, j, n_acks; - - if (!vec_len (wrk->pending_acks)) - return; - - thread_index = wrk->vm->thread_index; - pending_acks = wrk->pending_acks; - for (i = 0; i < vec_len (pending_acks); i++) + if (!(tc->flags & TCP_CONN_FRXT_PENDING)) { - tc = tcp_connection_get (pending_acks[i], thread_index); - tc->flags &= ~TCP_CONN_SNDACK; - if (!tc->pending_dupacks) - { - tcp_send_ack (tc); - continue; - } - - /* If we're supposed to send dupacks but have no ooo data - * send only one ack */ - if (!vec_len (tc->snd_sacks)) - { - tcp_send_ack (tc); - continue; - } - - /* Start with first sack block */ - tc->snd_sack_pos = 0; - - /* Generate enough dupacks to cover all sack blocks. Do not generate - * more sacks than the number of packets received. But do generate at - * least 3, i.e., the number needed to signal congestion, if needed. */ - n_acks = vec_len (tc->snd_sacks) / TCP_OPTS_MAX_SACK_BLOCKS; - n_acks = clib_min (n_acks, tc->pending_dupacks); - n_acks = clib_max (n_acks, clib_min (tc->pending_dupacks, 3)); - for (j = 0; j < n_acks; j++) - tcp_send_ack (tc); - - tc->pending_dupacks = 0; - tc->snd_sack_pos = 0; + session_add_self_custom_tx_evt (&tc->connection, 0); + tc->flags |= TCP_CONN_FRXT_PENDING; } - _vec_len (wrk->pending_acks) = 0; } /** @@ -1281,7 +1243,6 @@ tcp_timer_delack_handler (u32 index) void tcp_send_window_update_ack (tcp_connection_t * tc) { - tcp_worker_ctx_t *wrk = tcp_get_worker (tc->c_thread_index); u32 win; if (tcp_zero_rwnd_sent (tc)) @@ -1290,7 +1251,7 @@ tcp_send_window_update_ack (tcp_connection_t * tc) if (win > 0) { tcp_zero_rwnd_sent_off (tc); - tcp_program_ack (wrk, tc); + tcp_program_ack (tc); } } } @@ -1853,7 +1814,7 @@ tcp_fast_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, snd_space = tcp_available_cc_snd_space (tc); if (snd_space < tc->snd_mss) { - tcp_program_fastretransmit (wrk, tc); + tcp_program_fastretransmit (tc); return 0; } @@ -1877,7 +1838,7 @@ tcp_fast_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, snd_space / tc->snd_mss); n_segs_now = tcp_fast_retransmit_unsent (wrk, tc, burst_size); if (max_deq > n_segs_now * tc->snd_mss) - tcp_program_fastretransmit (wrk, tc); + tcp_program_fastretransmit (tc); n_segs += n_segs_now; goto done; } @@ -1929,7 +1890,7 @@ tcp_fast_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, } if (hole) - tcp_program_fastretransmit (wrk, tc); + tcp_program_fastretransmit (tc); done: return n_segs; @@ -1990,7 +1951,7 @@ send_unsent: burst_size = clib_min (burst_size - n_segs, snd_space / tc->snd_mss); n_segs_now = tcp_fast_retransmit_unsent (wrk, tc, burst_size); if (max_deq > n_segs_now * tc->snd_mss) - tcp_program_fastretransmit (wrk, tc); + tcp_program_fastretransmit (tc); n_segs += n_segs_now; } @@ -2011,6 +1972,108 @@ tcp_fast_retransmit (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, else return tcp_fast_retransmit_no_sack (wrk, tc, burst_size); } + +static int +tcp_send_acks (tcp_connection_t * tc, u32 max_burst_size) +{ + int j, n_acks; + + if (!tc->pending_dupacks) + { + tcp_send_ack (tc); + return 1; + } + + /* If we're supposed to send dupacks but have no ooo data + * send only one ack */ + if (!vec_len (tc->snd_sacks)) + { + tcp_send_ack (tc); + return 1; + } + + /* Start with first sack block */ + tc->snd_sack_pos = 0; + + /* Generate enough dupacks to cover all sack blocks. Do not generate + * more sacks than the number of packets received. But do generate at + * least 3, i.e., the number needed to signal congestion, if needed. */ + n_acks = vec_len (tc->snd_sacks) / TCP_OPTS_MAX_SACK_BLOCKS; + n_acks = clib_min (n_acks, tc->pending_dupacks); + n_acks = clib_max (n_acks, clib_min (tc->pending_dupacks, 3)); + for (j = 0; j < clib_min (n_acks, max_burst_size); j++) + tcp_send_ack (tc); + + if (n_acks < max_burst_size) + { + tc->pending_dupacks = 0; + tc->snd_sack_pos = 0; + return n_acks; + } + else + { + TCP_DBG ("constrained by burst size"); + tc->pending_dupacks = n_acks - max_burst_size; + tcp_program_dupack (tc); + return max_burst_size; + } +} + +static int +tcp_do_fastretransmit (tcp_connection_t * tc, u32 max_burst_size) +{ + u32 n_segs = 0, burst_size, sent_bytes, burst_bytes; + tcp_worker_ctx_t *wrk; + + wrk = tcp_get_worker (tc->c_thread_index); + burst_bytes = transport_connection_tx_pacer_burst (&tc->connection, + wrk->vm-> + clib_time.last_cpu_time); + burst_size = clib_min (max_burst_size, burst_bytes / tc->snd_mss); + if (!burst_size) + { + tcp_program_fastretransmit (tc); + return 0; + } + + n_segs = tcp_fast_retransmit (wrk, tc, burst_size); + sent_bytes = clib_min (n_segs * tc->snd_mss, burst_bytes); + transport_connection_tx_pacer_update_bytes (&tc->connection, sent_bytes); + return n_segs; +} + +int +tcp_session_custom_tx (void *conn, u32 max_burst_size) +{ + tcp_connection_t *tc = (tcp_connection_t *) conn; + u32 n_segs = 0; + + if (tcp_in_fastrecovery (tc) && (tc->flags & TCP_CONN_FRXT_PENDING)) + { + tc->flags &= ~TCP_CONN_FRXT_PENDING; + n_segs = tcp_do_fastretransmit (tc, max_burst_size); + max_burst_size -= n_segs; + } + + if (!(tc->flags & TCP_CONN_SNDACK)) + return n_segs; + + tc->flags &= ~TCP_CONN_SNDACK; + + /* We have retransmitted packets and no dupack */ + if (n_segs && !tc->pending_dupacks) + return n_segs; + + if (!max_burst_size) + { + tcp_program_ack (tc); + return max_burst_size; + } + + n_segs += tcp_send_acks (tc, max_burst_size); + + return n_segs; +} #endif /* CLIB_MARCH_VARIANT */ static void |