* SEG.TSval */
else if (!tcp_rst (th0))
{
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
goto error;
}
}
else
{
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
TCP_EVT_DBG (TCP_EVT_SYNACK_RCVD, tc0);
*error0 = TCP_ERROR_SYN_ACKS_RCVD;
}
*error0 = TCP_ERROR_RCV_WND;
+ tc0->errors.below_data_wnd += seq_lt (vnet_buffer (b0)->tcp.seq_end,
+ tc0->rcv_las);
+
/* If not RST, send dup ack */
if (!tcp_rst (th0))
{
- tcp_program_dupack (wrk, tc0);
+ tcp_program_dupack (tc0);
TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
}
goto error;
if (PREDICT_FALSE (tcp_syn (th0)))
{
/* As per RFC5961 send challenge ack instead of reset */
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
*error0 = TCP_ERROR_SPURIOUS_SYN;
goto error;
}
tc->prev_ssthresh = tc->ssthresh;
tc->prev_cwnd = tc->cwnd;
tc->cc_algo->congestion (tc);
+ tc->fr_occurences += 1;
TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 4);
}
#endif /* CLIB_MARCH_VARIANT */
tcp_fastrecovery_off (tc);
tcp_fastrecovery_first_off (tc);
+ tc->flags &= ~TCP_CONN_FRXT_PENDING;
TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 3);
}
|| tcp_should_fastrecover_sack (tc));
}
-#ifndef CLIB_MARCH_VARIANT
-void
-tcp_program_fastretransmit (tcp_worker_ctx_t * wrk, tcp_connection_t * tc)
-{
- if (!(tc->flags & TCP_CONN_FRXT_PENDING))
- {
- vec_add1 (wrk->pending_fast_rxt, tc->c_c_index);
- tc->flags |= TCP_CONN_FRXT_PENDING;
- }
-}
-
-void
-tcp_do_fastretransmits (tcp_worker_ctx_t * wrk)
-{
- u32 *ongoing_fast_rxt, burst_bytes, sent_bytes, thread_index;
- u32 max_burst_size, burst_size, n_segs = 0, n_segs_now;
- tcp_connection_t *tc;
- u64 last_cpu_time;
- int i;
-
- if (vec_len (wrk->pending_fast_rxt) == 0
- && vec_len (wrk->postponed_fast_rxt) == 0)
- return;
-
- thread_index = wrk->vm->thread_index;
- last_cpu_time = wrk->vm->clib_time.last_cpu_time;
- ongoing_fast_rxt = wrk->ongoing_fast_rxt;
- vec_append (ongoing_fast_rxt, wrk->postponed_fast_rxt);
- vec_append (ongoing_fast_rxt, wrk->pending_fast_rxt);
-
- _vec_len (wrk->postponed_fast_rxt) = 0;
- _vec_len (wrk->pending_fast_rxt) = 0;
-
- max_burst_size = VLIB_FRAME_SIZE / vec_len (ongoing_fast_rxt);
- max_burst_size = clib_max (max_burst_size, 1);
-
- for (i = 0; i < vec_len (ongoing_fast_rxt); i++)
- {
- tc = tcp_connection_get (ongoing_fast_rxt[i], thread_index);
- if (!tc)
- continue;
- if (!tcp_in_fastrecovery (tc))
- {
- tc->flags &= ~TCP_CONN_FRXT_PENDING;
- continue;
- }
-
- if (n_segs >= VLIB_FRAME_SIZE)
- {
- vec_add1 (wrk->postponed_fast_rxt, ongoing_fast_rxt[i]);
- continue;
- }
-
- tc->flags &= ~TCP_CONN_FRXT_PENDING;
- burst_size = clib_min (max_burst_size, VLIB_FRAME_SIZE - n_segs);
- burst_bytes = transport_connection_tx_pacer_burst (&tc->connection,
- last_cpu_time);
- burst_size = clib_min (burst_size, burst_bytes / tc->snd_mss);
- if (!burst_size)
- {
- tcp_program_fastretransmit (wrk, tc);
- continue;
- }
-
- n_segs_now = tcp_fast_retransmit (wrk, tc, burst_size);
- sent_bytes = clib_min (n_segs_now * tc->snd_mss, burst_bytes);
- transport_connection_tx_pacer_update_bytes (&tc->connection,
- sent_bytes);
- n_segs += n_segs_now;
- }
- _vec_len (ongoing_fast_rxt) = 0;
- wrk->ongoing_fast_rxt = ongoing_fast_rxt;
-}
-#endif /* CLIB_MARCH_VARIANT */
-
/**
* One function to rule them all ... and in the darkness bind them
*/
{
if (tc->bytes_acked)
goto partial_ack;
- tcp_program_fastretransmit (tcp_get_worker (tc->c_thread_index), tc);
+ tcp_program_fastretransmit (tc);
return;
}
/*
pacer_wnd = clib_max (0.1 * tc->cwnd, 2 * tc->snd_mss);
tcp_connection_tx_pacer_reset (tc, pacer_wnd,
0 /* start bucket */ );
- tcp_program_fastretransmit (tcp_get_worker (tc->c_thread_index),
- tc);
+ tcp_program_fastretransmit (tc);
return;
}
else if (!tc->bytes_acked
/*
* Since this was a partial ack, try to retransmit some more data
*/
- tcp_program_fastretransmit (tcp_get_worker (tc->c_thread_index), tc);
+ tcp_program_fastretransmit (tc);
}
/**
goto process_ack;
}
+ tc->errors.above_ack_wnd += 1;
*error = TCP_ERROR_ACK_FUTURE;
TCP_EVT_DBG (TCP_EVT_ACK_RCV_ERR, tc, 0,
vnet_buffer (b)->tcp.ack_number);
/* If old ACK, probably it's an old dupack */
if (PREDICT_FALSE (seq_lt (vnet_buffer (b)->tcp.ack_number, tc->snd_una)))
{
+ tc->errors.below_ack_wnd += 1;
*error = TCP_ERROR_ACK_OLD;
TCP_EVT_DBG (TCP_EVT_ACK_RCV_ERR, tc, 1,
vnet_buffer (b)->tcp.ack_number);
/*
* Looks okay, process feedback
*/
+
if (tcp_opts_sack_permitted (&tc->rcv_opts))
tcp_rcv_sacks (tc, vnet_buffer (b)->tcp.ack_number);
if (tcp_ack_is_cc_event (tc, b, prev_snd_wnd, prev_snd_una, &is_dack))
{
tcp_cc_handle_event (tc, &rs, is_dack);
+ tc->dupacks_in += is_dack;
if (!tcp_in_cong_recovery (tc))
{
*error = TCP_ERROR_ACK_OK;
/* Account for the FIN and send ack */
tc->rcv_nxt += 1;
- tcp_program_ack (wrk, tc);
+ tcp_program_ack (tc);
/* Enter CLOSE-WAIT and notify session. To avoid lingering
* in CLOSE-WAIT, set timer (reuse WAITCLOSE). */
tcp_connection_set_state (tc, TCP_STATE_CLOSE_WAIT);
ASSERT (data_len);
written = session_enqueue_stream_connection (&tc->connection, b, 0,
1 /* queue event */ , 1);
+ tc->bytes_in += written;
TCP_EVT_DBG (TCP_EVT_INPUT, tc, 0, data_len, written);
}
TCP_EVT_DBG (TCP_EVT_INPUT, tc, 1, data_len, data_len);
+ tc->bytes_in += data_len;
/* Update SACK list if in use */
if (tcp_opts_sack_permitted (&tc->rcv_opts))
vlib_buffer_advance (b, vnet_buffer (b)->tcp.data_offset);
n_data_bytes = vnet_buffer (b)->tcp.data_len;
ASSERT (n_data_bytes);
+ tc->data_segs_in += 1;
/* Handle out-of-order data */
if (PREDICT_FALSE (vnet_buffer (b)->tcp.seq_number != tc->rcv_nxt))
* retransmissions since we may not have any data to send */
if (seq_leq (vnet_buffer (b)->tcp.seq_end, tc->rcv_nxt))
{
- tcp_program_ack (wrk, tc);
+ tcp_program_ack (tc);
error = TCP_ERROR_SEGMENT_OLD;
goto done;
}
/* RFC2581: Enqueue and send DUPACK for fast retransmit */
error = tcp_session_enqueue_ooo (tc, b, n_data_bytes);
- tcp_program_dupack (wrk, tc);
+ tcp_program_dupack (tc);
TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc, vnet_buffer (b)->tcp);
+ tc->errors.above_data_wnd += seq_gt (vnet_buffer (b)->tcp.seq_end,
+ tc->rcv_las + tc->rcv_wnd);
goto done;
}
goto done;
}
- tcp_program_ack (wrk, tc);
+ tcp_program_ack (tc);
done:
return error;
}
else
{
- tcp_program_ack (wrk, new_tc0);
+ tcp_program_ack (new_tc0);
}
drop:
if (!is_fin0)
goto drop;
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
goto drop;
case TCP_STATE_ESTABLISHED:
/* Account for the FIN and send ack */
tc0->rcv_nxt += 1;
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
tcp_connection_set_state (tc0, TCP_STATE_CLOSE_WAIT);
tcp_program_disconnect (wrk, tc0);
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
else
{
tcp_connection_set_state (tc0, TCP_STATE_CLOSING);
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
/* Wait for ACK for our FIN but not forever */
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
}
tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT);
tcp_connection_timers_reset (tc0);
tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
- tcp_program_ack (wrk, tc0);
+ tcp_program_ack (tc0);
session_transport_closed_notify (&tc0->connection);
break;
case TCP_STATE_TIME_WAIT:
flags = tcp->flags & filter_flags;
*next = tm->dispatch_table[tc->state][flags].next;
*error = tm->dispatch_table[tc->state][flags].error;
+ tc->segs_in += 1;
if (PREDICT_FALSE (*error == TCP_ERROR_DISPATCH
|| *next == TCP_INPUT_NEXT_RESET))