u32
tcp_initial_window_to_advertise (tcp_connection_t * tc)
{
+ tcp_main_t *tm = &tcp_main;
u32 max_fifo;
/* Initial wnd for SYN. Fifos are not allocated yet.
* Use some predefined value. For SYN-ACK we still want the
* scale to be computed in the same way */
- max_fifo = TCP_MAX_RX_FIFO_SIZE;
+ max_fifo = tm->max_rx_fifo ? tm->max_rx_fifo : TCP_MAX_RX_FIFO_SIZE;
tc->rcv_wscale = tcp_window_compute_scale (max_fifo);
tc->rcv_wnd = tcp_initial_wnd_unscaled (tc);
initial_wnd = tcp_initial_window_to_advertise (tc);
/* Make and write options */
- memset (&snd_opts, 0, sizeof (snd_opts));
+ clib_memset (&snd_opts, 0, sizeof (snd_opts));
tcp_opts_len = tcp_make_syn_options (&snd_opts, tc->rcv_wscale);
tcp_hdr_opts_len = tcp_opts_len + sizeof (tcp_header_t);
tcp_header_t *th;
u16 initial_wnd;
- memset (snd_opts, 0, sizeof (*snd_opts));
+ clib_memset (snd_opts, 0, sizeof (*snd_opts));
tcp_reuse_buffer (vm, b);
initial_wnd = tcp_initial_window_to_advertise (tc);
u32 bi;
u8 fin_snt = 0;
- tcp_retransmit_timer_force_update (tc);
- if (PREDICT_FALSE (tcp_get_free_buffer_index (tm, &bi)))
- return;
- b = vlib_get_buffer (vm, bi);
- tcp_init_buffer (vm, b);
fin_snt = tc->flags & TCP_CONN_FINSNT;
if (fin_snt)
tc->snd_nxt = tc->snd_una;
+
+ if (PREDICT_FALSE (tcp_get_free_buffer_index (tm, &bi)))
+ {
+ /* Out of buffers so program fin retransmit ASAP */
+ tcp_timer_update (tc, TCP_TIMER_RETRANSMIT, 1);
+ goto post_enqueue;
+ }
+
+ tcp_retransmit_timer_force_update (tc);
+ b = vlib_get_buffer (vm, bi);
+ tcp_init_buffer (vm, b);
tcp_make_fin (tc, b);
tcp_enqueue_to_output_now (vm, b, bi, tc->c_is_ip4);
+ TCP_EVT_DBG (TCP_EVT_FIN_SENT, tc);
+
+post_enqueue:
if (!fin_snt)
{
tc->flags |= TCP_CONN_FINSNT;
{
tc->snd_nxt = tc->snd_una_max;
}
- TCP_EVT_DBG (TCP_EVT_FIN_SENT, tc);
}
always_inline u8
tcp_push_hdr_i (tc, b, TCP_STATE_ESTABLISHED, /* compute opts */ 0,
/* burst */ 1);
tc->snd_una_max = tc->snd_nxt;
- ASSERT (seq_leq (tc->snd_una_max, tc->snd_una + tc->snd_wnd));
+ ASSERT (seq_leq (tc->snd_una_max, tc->snd_una + tc->snd_wnd
+ + tcp_fastrecovery_sent_1_smss (tc) * tc->snd_mss));
tcp_validate_txf_size (tc, tc->snd_una_max - tc->snd_una);
/* If not tracking an ACK, start tracking */
if (tc->rtt_ts == 0 && !tcp_in_cong_recovery (tc))
ASSERT (n_bytes == max_deq_bytes);
b[0]->current_length = n_bytes;
tcp_push_hdr_i (tc, *b, tc->state, /* compute opts */ 0, /* burst */ 0);
+ if (seq_gt (tc->snd_nxt, tc->snd_una_max))
+ tc->snd_una_max = tc->snd_nxt;
}
/* Split mss into multiple buffers */
else
}
tcp_push_hdr_i (tc, *b, tc->state, /* compute opts */ 0, /* burst */ 0);
+ if (seq_gt (tc->snd_nxt, tc->snd_una_max))
+ tc->snd_una_max = tc->snd_nxt;
}
ASSERT (n_bytes > 0);
return;
}
- /* Shouldn't be here */
+ /* Shouldn't be here. This condition is tricky because it has to take
+ * into account boff > 0 due to persist timeout. */
if ((tc->rto_boff == 0 && tc->snd_una == tc->snd_una_max)
- || (tc->rto_boff > 0 && seq_geq (tc->snd_una, tc->snd_congestion)))
+ || (tc->rto_boff > 0 && seq_geq (tc->snd_una, tc->snd_congestion)
+ && !tcp_flight_size (tc)))
{
- tcp_recovery_off (tc);
+ ASSERT (!tcp_in_recovery (tc));
+ tc->rto_boff = 0;
return;
}
- /* We're not in recovery so make sure rto_boff is 0 */
+ /* We're not in recovery so make sure rto_boff is 0. Can be non 0 due
+ * to persist timer timeout */
if (!tcp_in_recovery (tc) && tc->rto_boff > 0)
{
tc->rto_boff = 0;
if (tc->rto_boff == 1)
tcp_rxt_timeout_cc (tc);
+ /* If we've sent beyond snd_congestion, update it */
+ if (seq_gt (tc->snd_una_max, tc->snd_congestion))
+ tc->snd_congestion = tc->snd_una_max;
+
tc->snd_una_max = tc->snd_nxt = tc->snd_una;
tc->rto = clib_min (tc->rto << 1, TCP_RTO_MAX);
- /* Send one segment. Note that n_bytes may be zero due to buffer shortfall */
+ /* Send one segment. Note that n_bytes may be zero due to buffer
+ * shortfall */
n_bytes = tcp_prepare_retransmit_segment (tc, 0, tc->snd_mss, &b);
/* TODO be less aggressive about this */
if (n_bytes == 0)
{
- tcp_retransmit_timer_set (tc);
+ tcp_retransmit_timer_force_update (tc);
return;
}
tc->snd_rxt_ts = tcp_time_now ();
tcp_enqueue_to_output (vm, b, bi, tc->c_is_ip4);
- tcp_retransmit_timer_update (tc);
+ tcp_retransmit_timer_force_update (tc);
}
/* Retransmit for SYN */
else if (tc->state == TCP_STATE_SYN_SENT)
* Try to force the first unsent segment (or buffer)
*/
if (PREDICT_FALSE (tcp_get_free_buffer_index (tm, &bi)))
- return;
+ {
+ tcp_persist_timer_set (tc);
+ return;
+ }
b = vlib_get_buffer (vm, bi);
data = tcp_init_buffer (vm, b);