* Figure out how much space we have available
*/
available_space = transport_max_rx_enqueue (&tc->connection);
- if (PREDICT_FALSE (available_space < tc->rcv_opts.mss))
- {
- tc->rcv_wnd = 0;
- return;
- }
/*
* Use the above and what we know about what we've previously advertised
*/
observed_wnd = (i32) tc->rcv_wnd - (tc->rcv_nxt - tc->rcv_las);
- /* Bad. Thou shalt not shrink */
+ /* Check if we are about to retract the window. Do the comparison before
+ * rounding to avoid errors. Per RFC7323 sec. 2.4 we could remove this */
if (PREDICT_FALSE ((i32) available_space < observed_wnd))
{
- wnd = clib_max (observed_wnd, 0);
+ wnd = round_down_pow2 (clib_max (observed_wnd, 0), 1 << tc->rcv_wscale);
TCP_EVT (TCP_EVT_RCV_WND_SHRUNK, tc, observed_wnd, available_space);
}
else
{
- wnd = available_space;
+ /* Make sure we have a multiple of 1 << rcv_wscale. We round down to
+ * avoid advertising a window larger than what can be buffered */
+ wnd = round_down_pow2 (available_space, 1 << tc->rcv_wscale);
}
- /* Make sure we have a multiple of rcv_wscale */
- if (wnd && tc->rcv_wscale)
- {
- wnd &= ~((1 << tc->rcv_wscale) - 1);
- if (wnd == 0)
- wnd = 1 << tc->rcv_wscale;
- }
+ if (PREDICT_FALSE (wnd < tc->rcv_opts.mss))
+ wnd = 0;
tc->rcv_wnd = clib_min (wnd, TCP_WND_MAX << tc->rcv_wscale);
}
fib_protocol_t fib_proto;
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
- return;
+ {
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
+ return;
+ }
b = vlib_get_buffer (vm, bi);
sw_if_index = vnet_buffer (pkt)->sw_if_index[VLIB_RX];
u8 flags;
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
- return;
+ {
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
+ return;
+ }
b = vlib_get_buffer (vm, bi);
tcp_init_buffer (vm, b);
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_timer_update (&wrk->timer_wheel, tc, TCP_TIMER_RETRANSMIT_SYN, 1);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_timer_update (&wrk->timer_wheel, tc, TCP_TIMER_RETRANSMIT, 1);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
else
/* Make sure retransmit retries a fin not data */
tc->flags |= TCP_CONN_FINSNT;
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_update_rcv_wnd (tc);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
b = vlib_get_buffer (vm, bi);
}
}
-/**
- * Delayed ack timer handler
- *
- * Sends delayed ACK when timer expires
- */
-void
-tcp_timer_delack_handler (tcp_connection_t * tc)
-{
- tcp_send_ack (tc);
-}
-
/**
* Send window update ack
*
if (PREDICT_TRUE (seg_size <= bytes_per_buffer))
{
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
- return 0;
+ {
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
+ return 0;
+ }
*b = vlib_get_buffer (vm, bi);
data = tcp_init_buffer (vm, *b);
n_bytes = session_tx_fifo_peek_bytes (&tc->connection, data, offset,
{
if (n_bufs)
vlib_buffer_free (vm, wrk->tx_buffers, n_bufs);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return 0;
}
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_timer_update (&wrk->timer_wheel, tc, TCP_TIMER_RETRANSMIT, 1);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_timer_update (&wrk->timer_wheel, tc, TCP_TIMER_RETRANSMIT_SYN, 1);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}
if (PREDICT_FALSE (!vlib_buffer_alloc (vm, &bi, 1)))
{
tcp_persist_timer_set (&wrk->timer_wheel, tc);
+ tcp_worker_stats_inc (wrk, no_buffer, 1);
return;
}