{
ASSERT (timestamp_leq (tc->tsval_recent, tc->rcv_opts.tsval));
tc->tsval_recent = tc->rcv_opts.tsval;
- tc->tsval_recent_age = tcp_time_now_w_thread (tc->c_thread_index);
+ tc->tsval_recent_age = tcp_time_tstamp (tc->c_thread_index);
}
}
tcp_connection_cleanup (tc);
break;
case TCP_STATE_SYN_SENT:
- session_stream_connect_notify (&tc->connection, 1 /* fail */ );
+ session_stream_connect_notify (&tc->connection, SESSION_E_REFUSED);
tcp_connection_cleanup (tc);
break;
case TCP_STATE_ESTABLISHED:
/* If it just so happens that a segment updates tsval_recent for a
* segment over 24 days old, invalidate tsval_recent. */
if (timestamp_lt (tc0->tsval_recent_age + TCP_PAWS_IDLE,
- tcp_time_now_w_thread (tc0->c_thread_index)))
+ tcp_time_tstamp (tc0->c_thread_index)))
{
tc0->tsval_recent = tc0->rcv_opts.tsval;
clib_warning ("paws failed: 24-day old segment");
if (!(seq_leq (tc->snd_una, vnet_buffer (b)->tcp.ack_number)
&& seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)))
{
- if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_una_max)
+ if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)
&& seq_gt (vnet_buffer (b)->tcp.ack_number, tc->snd_una))
{
tc->snd_nxt = vnet_buffer (b)->tcp.ack_number;
/* Dequeue the newly ACKed bytes */
session_tx_fifo_dequeue_drop (&tc->connection, tc->burst_acked);
- tcp_validate_txf_size (tc, tc->snd_una_max - tc->snd_una);
-
- if (PREDICT_FALSE (tc->flags & TCP_CONN_PSH_PENDING))
- {
- if (seq_leq (tc->psh_seq, tc->snd_una))
- tc->flags &= ~TCP_CONN_PSH_PENDING;
- }
+ tcp_validate_txf_size (tc, tc->snd_nxt - tc->snd_una);
if (tcp_is_descheduled (tc))
tcp_reschedule (tc);
{
/* We've probably entered recovery and the peer still has some
* of the data we've sent. Update snd_nxt and accept the ack */
- if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_una_max)
+ if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)
&& seq_gt (vnet_buffer (b)->tcp.ack_number, tc->snd_una))
{
tc->snd_nxt = vnet_buffer (b)->tcp.ack_number;
}
/* Update SACK list if need be */
- if (tcp_opts_sack_permitted (&tc->rcv_opts))
+ if (tcp_opts_sack_permitted (&tc->rcv_opts) && vec_len (tc->snd_sacks))
{
/* Remove SACK blocks that have been delivered */
tcp_update_sack_list (tc, tc->rcv_nxt, tc->rcv_nxt);
ASSERT (n_data_bytes);
tc->data_segs_in += 1;
+ /* Make sure we don't consume trailing bytes */
+ if (PREDICT_FALSE (b->current_length > n_data_bytes))
+ b->current_length = n_data_bytes;
+
/* Handle out-of-order data */
if (PREDICT_FALSE (vnet_buffer (b)->tcp.seq_number != tc->rcv_nxt))
{
return;
hw_if = vnet_get_sup_hw_interface (vnm, sw_if_idx);
- if (hw_if->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)
+ if (hw_if->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO)
tc->cfg_flags |= TCP_CFG_F_TSO;
}
goto drop;
}
- /* Half-open completed recently but the connection was't removed
- * yet by the owning thread */
+ /* Half-open completed or cancelled recently but the connection
+ * was't removed yet by the owning thread */
if (PREDICT_FALSE (tc0->flags & TCP_CONN_HALF_OPEN_DONE))
{
- /* Make sure the connection actually exists */
- ASSERT (tcp_lookup_connection (tc0->c_fib_index, b0,
- my_thread_index, is_ip4));
error0 = TCP_ERROR_SPURIOUS_SYN_ACK;
goto drop;
}
if (tcp_opts_tstamp (&new_tc0->rcv_opts))
{
new_tc0->tsval_recent = new_tc0->rcv_opts.tsval;
- new_tc0->tsval_recent_age = tcp_time_now ();
+ new_tc0->tsval_recent_age = tcp_time_tstamp (my_thread_index);
}
if (tcp_opts_wscale (&new_tc0->rcv_opts))
goto cleanup_ho;
}
+ transport_fifos_init_ooo (&new_tc0->connection);
new_tc0->tx_fifo_size =
transport_tx_fifo_size (&new_tc0->connection);
/* Update rtt with the syn-ack sample */
goto cleanup_ho;
}
+ transport_fifos_init_ooo (&new_tc0->connection);
new_tc0->tx_fifo_size =
transport_tx_fifo_size (&new_tc0->connection);
new_tc0->rtt_ts = 0;
case TCP_STATE_FIN_WAIT_2:
if (vnet_buffer (b0)->tcp.data_len)
error0 = tcp_segment_rcv (wrk, tc0, b0);
+ /* Don't accept out of order fins lower */
+ if (vnet_buffer (b0)->tcp.seq_end != tc0->rcv_nxt)
+ goto drop;
break;
case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_CLOSING:
b = vlib_get_buffer (vm, bi);
- lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
- if (PREDICT_FALSE (lc == 0))
+ /* Flags initialized with connection state after lookup */
+ if (vnet_buffer (b)->tcp.flags == TCP_STATE_LISTEN)
+ {
+ lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
+ }
+ else
{
tcp_connection_t *tc;
tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
thread_index);
if (tc->state != TCP_STATE_TIME_WAIT)
{
+ lc = 0;
error = TCP_ERROR_CREATE_EXISTS;
goto done;
}
lc = tcp_lookup_listener (b, tc->c_fib_index, is_ip4);
/* clean up the old session */
tcp_connection_del (tc);
+ /* listener was cleaned up */
+ if (!lc)
+ {
+ error = TCP_ERROR_NO_LISTENER;
+ goto done;
+ }
}
/* Make sure connection wasn't just created */
goto done;
}
+ transport_fifos_init_ooo (&child->connection);
child->tx_fifo_size = transport_tx_fifo_size (&child->connection);
tcp_send_synack (child);
if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
{
- tcp_rx_trace_t *t;
- t = vlib_add_trace (vm, node, b, sizeof (*t));
- clib_memcpy_fast (&t->tcp_header, tcp_buffer_hdr (b),
- sizeof (t->tcp_header));
- clib_memcpy_fast (&t->tcp_connection, lc,
- sizeof (t->tcp_connection));
+ tcp_rx_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
+ tcp_set_rx_trace_data (t, lc, tcp_buffer_hdr (b), b, is_ip4);
}
n_syns += (error == TCP_ERROR_NONE);
error = tm->dispatch_table[tc->state][flags].error;
tc->segs_in += 1;
+ /* Track connection state when packet was received. It helps
+ * @ref tcp46_listen_inline detect port reuse */
+ vnet_buffer (b)->tcp.flags = tc->state;
+
if (PREDICT_FALSE (error != TCP_ERROR_NONE))
{
b->error = error_node->errors[error];
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
u16 nexts[VLIB_FRAME_SIZE], *next;
- tcp_set_time_now (tcp_get_worker (thread_index));
+ tcp_update_time_now (tcp_get_worker (thread_index));
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
/* *INDENT-ON* */
#ifndef CLIB_MARCH_VARIANT
+void
+tcp_check_gso (tcp_connection_t *tc)
+{
+ tcp_check_tx_offload (tc, tc->c_is_ip4);
+}
+
static void
tcp_dispatch_table_init (tcp_main_t * tm)
{