CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
tcp_tx_trace_t *t = va_arg (*args, tcp_tx_trace_t *);
+ tcp_connection_t *tc = &t->tcp_connection;
u32 indent = format_get_indent (s);
- s = format (s, "%U\n%U%U",
- format_tcp_header, &t->tcp_header, 128,
- format_white_space, indent,
- format_tcp_connection, &t->tcp_connection, 1);
+ s = format (s, "%U state %U\n%U%U", format_tcp_connection_id, tc,
+ format_tcp_state, tc->state, format_white_space, indent,
+ format_tcp_header, &t->tcp_header, 128);
return s;
}
if (tc->snd_una == tc->snd_nxt)
{
tcp_cc_event (tc, TCP_CC_EVT_START_TX);
- tcp_connection_tx_pacer_reset (tc, tc->cwnd, TRANSPORT_PACER_MIN_MSS);
+ tcp_connection_tx_pacer_reset (tc, tc->cwnd, TRANSPORT_PACER_MIN_BURST);
}
}
tcp_push_ip_hdr (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
vlib_buffer_t * b)
{
- tcp_header_t *th = vlib_buffer_get_current (b);
- vlib_main_t *vm = wrk->vm;
if (tc->c_is_ip4)
{
- ip4_header_t *ih;
- ih = vlib_buffer_push_ip4 (vm, b, &tc->c_lcl_ip4,
- &tc->c_rmt_ip4, IP_PROTOCOL_TCP,
- tcp_csum_offload (tc));
- th->checksum = ip4_tcp_udp_compute_checksum (vm, b, ih);
+ vlib_buffer_push_ip4 (wrk->vm, b, &tc->c_lcl_ip4, &tc->c_rmt_ip4,
+ IP_PROTOCOL_TCP, tcp_csum_offload (tc));
}
else
{
- ip6_header_t *ih;
- int bogus = ~0;
-
- ih = vlib_buffer_push_ip6_custom (vm, b, &tc->c_lcl_ip6,
- &tc->c_rmt_ip6, IP_PROTOCOL_TCP,
- tc->ipv6_flow_label);
- th->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ih, &bogus);
- ASSERT (!bogus);
+ vlib_buffer_push_ip6_custom (wrk->vm, b, &tc->c_lcl_ip6, &tc->c_rmt_ip6,
+ IP_PROTOCOL_TCP, tc->ipv6_flow_label);
}
}
* Sends delayed ACK when timer expires
*/
void
-tcp_timer_delack_handler (u32 index)
+tcp_timer_delack_handler (u32 index, u32 thread_index)
{
- u32 thread_index = vlib_get_thread_index ();
tcp_connection_t *tc;
tc = tcp_connection_get (index, thread_index);
- tc->timers[TCP_TIMER_DELACK] = TCP_TIMER_HANDLE_INVALID;
tcp_send_ack (tc);
}
tc->bytes_retrans += n_bytes;
tc->segs_retrans += 1;
+ tcp_workerp_stats_inc (wrk, rxt_segs, 1);
TCP_EVT (TCP_EVT_CC_RTX, tc, offset, n_bytes);
return n_bytes;
}
void
-tcp_timer_retransmit_handler (u32 tc_index)
+tcp_timer_retransmit_handler (u32 tc_index, u32 thread_index)
{
- u32 thread_index = vlib_get_thread_index ();
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
vlib_main_t *vm = wrk->vm;
tcp_connection_t *tc;
vlib_buffer_t *b = 0;
u32 bi, n_bytes;
+ tcp_workerp_stats_inc (wrk, tr_events, 1);
tc = tcp_connection_get (tc_index, thread_index);
/* Note: the connection may have been closed and pool_put */
if (PREDICT_FALSE (tc == 0 || tc->state == TCP_STATE_SYN_SENT))
return;
- tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID;
-
/* Wait-close and retransmit could pop at the same time */
if (tc->state == TCP_STATE_CLOSED)
return;
tcp_send_reset (tc);
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
session_transport_closing_notify (&tc->connection);
+ session_transport_closed_notify (&tc->connection);
tcp_connection_timers_reset (tc);
tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.closewait_time);
+ tcp_workerp_stats_inc (wrk, tr_abort, 1);
return;
}
tcp_connection_set_state (tc, TCP_STATE_CLOSED);
tcp_connection_timers_reset (tc);
tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time);
+ tcp_workerp_stats_inc (wrk, tr_abort, 1);
return;
}
* SYN retransmit timer handler. Active open only.
*/
void
-tcp_timer_retransmit_syn_handler (u32 tc_index)
+tcp_timer_retransmit_syn_handler (u32 tc_index, u32 thread_index)
{
- u32 thread_index = vlib_get_thread_index ();
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
vlib_main_t *vm = wrk->vm;
tcp_connection_t *tc;
if (PREDICT_FALSE (tc == 0 || tc->state != TCP_STATE_SYN_SENT))
return;
- tc->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID;
-
/* Half-open connection actually moved to established but we were
* waiting for syn retransmit to pop to call cleanup from the right
* thread. */
*
*/
void
-tcp_timer_persist_handler (u32 index)
+tcp_timer_persist_handler (u32 index, u32 thread_index)
{
- u32 thread_index = vlib_get_thread_index ();
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
u32 bi, max_snd_bytes, available_bytes, offset;
tcp_main_t *tm = vnet_get_tcp_main ();
if (!tc)
return;
- /* Make sure timer handle is set to invalid */
- tc->timers[TCP_TIMER_PERSIST] = TCP_TIMER_HANDLE_INVALID;
-
/* Problem already solved or worse */
if (tc->state == TCP_STATE_CLOSED || tc->snd_wnd > tc->snd_mss
|| (tc->flags & TCP_CONN_FINSNT))
}
if (available_bytes <= offset)
- {
- ASSERT (tcp_timer_is_active (tc, TCP_TIMER_RETRANSMIT));
- return;
- }
+ return;
/* Increment RTO backoff */
tc->rto_boff += 1;
u32 tx_adv_sack = sb->high_sacked - tc->snd_congestion;
f64 rr = (f64) tc->ssthresh / tc->prev_cwnd;
+ if (tcp_fastrecovery_first (tc))
+ return 1;
+
return (tx_adv_sack > (tc->snd_una - tc->prr_start) * rr);
}
tcp_retransmit_sack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
u32 burst_size)
{
- u8 snd_limited = 0, can_rescue = 0, reset_pacer = 0;
u32 n_written = 0, offset, max_bytes, n_segs = 0;
- u32 bi, max_deq, burst_bytes, sent_bytes;
+ u8 snd_limited = 0, can_rescue = 0;
+ u32 bi, max_deq, burst_bytes;
sack_scoreboard_hole_t *hole;
vlib_main_t *vm = wrk->vm;
vlib_buffer_t *b = 0;
snd_space = tcp_fastrecovery_prr_snd_space (tc);
if (snd_space < tc->snd_mss)
- {
- reset_pacer = burst_bytes > tc->snd_mss;
- goto done;
- }
-
- reset_pacer = snd_space < burst_bytes;
+ goto done;
sb = &tc->sack_sb;
ASSERT (tc->rxt_delivered <= tc->snd_rxt_bytes);
}
+ tcp_fastrecovery_first_off (tc);
+
TCP_EVT (TCP_EVT_CC_EVT, tc, 0);
hole = scoreboard_get_hole (sb, sb->cur_rxt_hole);
u32 n_segs_new;
int av_wnd;
+ /* Make sure we don't exceed available window and leave space
+ * for one more packet, to avoid zero window acks */
av_wnd = (int) tc->snd_wnd - (tc->snd_nxt - tc->snd_una);
- av_wnd = clib_max (av_wnd, 0);
+ av_wnd = clib_max (av_wnd - tc->snd_mss, 0);
snd_space = clib_min (snd_space, av_wnd);
snd_space = clib_min (max_deq, snd_space);
burst_size = clib_min (burst_size - n_segs,
* unSACKed sequence number SHOULD be returned, and RescueRxt set to
* RecoveryPoint. HighRxt MUST NOT be updated.
*/
- max_bytes = clib_min (tc->snd_mss,
- tc->snd_congestion - tc->snd_una);
+ hole = scoreboard_last_hole (sb);
+ max_bytes = clib_min (tc->snd_mss, hole->end - hole->start);
max_bytes = clib_min (max_bytes, snd_space);
- offset = tc->snd_congestion - tc->snd_una - max_bytes;
- sb->rescue_rxt = tc->snd_congestion;
+ offset = hole->end - tc->snd_una - max_bytes;
n_written = tcp_prepare_retransmit_segment (wrk, tc, offset,
max_bytes, &b);
if (!n_written)
goto done;
+ sb->rescue_rxt = tc->snd_congestion;
bi = vlib_get_buffer_index (vm, b);
tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4);
n_segs += 1;
done:
- if (reset_pacer)
- {
- transport_connection_tx_pacer_reset_bucket (&tc->connection);
- }
- else
- {
- sent_bytes = clib_min (n_segs * tc->snd_mss, burst_bytes);
- transport_connection_tx_pacer_update_bytes (&tc->connection,
- sent_bytes);
- }
-
+ transport_connection_tx_pacer_reset_bucket (&tc->connection, 0);
return n_segs;
}
tcp_worker_ctx_t *wrk;
u32 n_segs;
+ if (PREDICT_FALSE (tc->state == TCP_STATE_CLOSED))
+ return 0;
+
wrk = tcp_get_worker (tc->c_thread_index);
if (tcp_opts_sack_permitted (&tc->rcv_opts))
tcp46_output_trace_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 * to_next, u32 n_bufs)
{
- u32 n_trace = vlib_get_trace_count (vm, node);
tcp_connection_t *tc;
tcp_tx_trace_t *t;
vlib_buffer_t *b;
tcp_header_t *th;
int i;
- for (i = 0; i < clib_min (n_trace, n_bufs); i++)
+ for (i = 0; i < n_bufs; i++)
{
b = vlib_get_buffer (vm, to_next[i]);
+ if (!(b->flags & VLIB_BUFFER_IS_TRACED))
+ continue;
th = vlib_buffer_get_current (b);
tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
vm->thread_index);
tcp_output_push_ip (vlib_main_t * vm, vlib_buffer_t * b0,
tcp_connection_t * tc0, u8 is_ip4)
{
- u8 __clib_unused *ih0;
- tcp_header_t __clib_unused *th0 = vlib_buffer_get_current (b0);
-
- TCP_EVT (TCP_EVT_OUTPUT, tc0, th0->flags, b0->current_length);
+ TCP_EVT (TCP_EVT_OUTPUT, tc0,
+ ((tcp_header_t *) vlib_buffer_get_current (b0))->flags,
+ b0->current_length);
if (is_ip4)
- ih0 = vlib_buffer_push_ip4 (vm, b0, &tc0->c_lcl_ip4, &tc0->c_rmt_ip4,
- IP_PROTOCOL_TCP, tcp_csum_offload (tc0));
+ vlib_buffer_push_ip4 (vm, b0, &tc0->c_lcl_ip4, &tc0->c_rmt_ip4,
+ IP_PROTOCOL_TCP, tcp_csum_offload (tc0));
else
- ih0 =
- vlib_buffer_push_ip6_custom (vm, b0, &tc0->c_lcl_ip6, &tc0->c_rmt_ip6,
- IP_PROTOCOL_TCP, tc0->ipv6_flow_label);
-
+ vlib_buffer_push_ip6_custom (vm, b0, &tc0->c_lcl_ip6, &tc0->c_rmt_ip6,
+ IP_PROTOCOL_TCP, tc0->ipv6_flow_label);
}
always_inline void