* scale to be computed in the same way */
max_fifo = tm->max_rx_fifo ? tm->max_rx_fifo : TCP_MAX_RX_FIFO_SIZE;
- tc->rcv_wscale = tcp_window_compute_scale (max_fifo);
+ /* Compute rcv wscale only if peer advertised support for it */
+ if (tc->state != TCP_STATE_SYN_RCVD || tcp_opts_wscale (&tc->rcv_opts))
+ tc->rcv_wscale = tcp_window_compute_scale (max_fifo);
+
tc->rcv_wnd = tcp_initial_wnd_unscaled (tc);
return clib_min (tc->rcv_wnd, TCP_WND_MAX);
*data++ = TCP_OPTION_MSS;
*data++ = TCP_OPTION_LEN_MSS;
buf = clib_host_to_net_u16 (opts->mss);
- clib_memcpy (data, &buf, sizeof (opts->mss));
+ clib_memcpy_fast (data, &buf, sizeof (opts->mss));
data += sizeof (opts->mss);
opts_len += TCP_OPTION_LEN_MSS;
}
*data++ = TCP_OPTION_TIMESTAMP;
*data++ = TCP_OPTION_LEN_TIMESTAMP;
buf = clib_host_to_net_u32 (opts->tsval);
- clib_memcpy (data, &buf, sizeof (opts->tsval));
+ clib_memcpy_fast (data, &buf, sizeof (opts->tsval));
data += sizeof (opts->tsval);
buf = clib_host_to_net_u32 (opts->tsecr);
- clib_memcpy (data, &buf, sizeof (opts->tsecr));
+ clib_memcpy_fast (data, &buf, sizeof (opts->tsecr));
data += sizeof (opts->tsecr);
opts_len += TCP_OPTION_LEN_TIMESTAMP;
}
for (i = 0; i < n_sack_blocks; i++)
{
buf = clib_host_to_net_u32 (opts->sacks[i].start);
- clib_memcpy (data, &buf, seq_len);
+ clib_memcpy_fast (data, &buf, seq_len);
data += seq_len;
buf = clib_host_to_net_u32 (opts->sacks[i].end);
- clib_memcpy (data, &buf, seq_len);
+ clib_memcpy_fast (data, &buf, seq_len);
data += seq_len;
}
opts_len += 2 + n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
switch (state)
{
case TCP_STATE_ESTABLISHED:
+ case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_FIN_WAIT_1:
+ case TCP_STATE_LAST_ACK:
+ case TCP_STATE_CLOSING:
+ case TCP_STATE_FIN_WAIT_2:
+ case TCP_STATE_TIME_WAIT:
case TCP_STATE_CLOSED:
- case TCP_STATE_CLOSE_WAIT:
return tcp_make_established_options (tc, opts);
case TCP_STATE_SYN_RCVD:
return tcp_make_synack_options (tc, opts);
if (tc->snd_mss < 45)
{
- clib_warning ("snd mss is 0");
/* Assume that at least the min default mss works */
tc->snd_mss = default_min_mss;
tc->rcv_opts.mss = default_min_mss;
{
ih6 = vlib_buffer_get_current (b0);
ASSERT ((ih6->ip_version_traffic_class_and_flow_label & 0xF0) == 0x60);
- clib_memcpy (&src_ip60, &ih6->src_address, sizeof (ip6_address_t));
- clib_memcpy (&dst_ip60, &ih6->dst_address, sizeof (ip6_address_t));
+ clib_memcpy_fast (&src_ip60, &ih6->src_address, sizeof (ip6_address_t));
+ clib_memcpy_fast (&dst_ip60, &ih6->dst_address, sizeof (ip6_address_t));
}
src_port = th0->src_port;
if (PREDICT_FALSE (tcp_get_free_buffer_index (wrk, &bi)))
return;
+ tc->rtt_ts = tcp_time_now_us (tc->c_thread_index);
b = vlib_get_buffer (vm, bi);
tcp_make_synack (tc, b);
tcp_enqueue_to_output (wrk, b, bi, tc->c_is_ip4);
{
case TCP_STATE_ESTABLISHED:
case TCP_STATE_CLOSE_WAIT:
+ case TCP_STATE_TIME_WAIT:
+ case TCP_STATE_FIN_WAIT_2:
return TCP_FLAG_ACK;
case TCP_STATE_SYN_RCVD:
return TCP_FLAG_SYN | TCP_FLAG_ACK;
return TCP_FLAG_SYN;
case TCP_STATE_LAST_ACK:
case TCP_STATE_FIN_WAIT_1:
+ case TCP_STATE_CLOSING:
if (tc->snd_nxt + 1 < tc->snd_una_max)
return TCP_FLAG_ACK;
else
advertise_wnd = tcp_window_to_advertise (tc, next_state);
flags = tcp_make_state_flags (tc, next_state);
-
+ if (PREDICT_FALSE (tc->flags & TCP_CONN_PSH_PENDING))
+ {
+ if (seq_geq (tc->psh_seq, tc->snd_nxt)
+ && seq_lt (tc->psh_seq, tc->snd_nxt + data_len))
+ flags |= TCP_FLAG_PSH;
+ }
th = vlib_buffer_push_tcp (b, tc->c_lcl_port, tc->c_rmt_port, tc->snd_nxt,
tc->rcv_nxt, tcp_hdr_opts_len, flags,
advertise_wnd);
if (maybe_burst)
{
- clib_memcpy ((u8 *) (th + 1),
- tm->wrk_ctx[tc->c_thread_index].cached_opts,
- tc->snd_opts_len);
+ clib_memcpy_fast ((u8 *) (th + 1),
+ tm->wrk_ctx[tc->c_thread_index].cached_opts,
+ tc->snd_opts_len);
}
else
{
{
tc = tcp_half_open_connection_get (index);
/* Note: the connection may have transitioned to ESTABLISHED... */
- if (PREDICT_FALSE (tc == 0))
+ if (PREDICT_FALSE (tc == 0 || tc->state != TCP_STATE_SYN_SENT))
return;
tc->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID;
}
{
tc = tcp_connection_get (index, thread_index);
/* Note: the connection may have been closed and pool_put */
- if (PREDICT_FALSE (tc == 0))
+ if (PREDICT_FALSE (tc == 0 || tc->state < TCP_STATE_SYN_RCVD))
return;
tc->timers[TCP_TIMER_RETRANSMIT] = TCP_TIMER_HANDLE_INVALID;
}
tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
vm->thread_index);
t = vlib_add_trace (vm, node, b, sizeof (*t));
- clib_memcpy (&t->tcp_header, th, sizeof (t->tcp_header));
- clib_memcpy (&t->tcp_connection, tc, sizeof (t->tcp_connection));
+ clib_memcpy_fast (&t->tcp_header, th, sizeof (t->tcp_header));
+ clib_memcpy_fast (&t->tcp_connection, tc, sizeof (t->tcp_connection));
}
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (tcp4_output_node) =
{
- .function = tcp4_output,.name = "tcp4-output",
- /* Takes a vector of packets. */
- .vector_size = sizeof (u32),
- .n_errors = TCP_N_ERROR,
- .error_strings = tcp_error_strings,
- .n_next_nodes = TCP_OUTPUT_N_NEXT,
- .next_nodes = {
+ .function = tcp4_output,
+ .name = "tcp4-output",
+ /* Takes a vector of packets. */
+ .vector_size = sizeof (u32),
+ .n_errors = TCP_N_ERROR,
+ .protocol_hint = VLIB_NODE_PROTO_HINT_TCP,
+ .error_strings = tcp_error_strings,
+ .n_next_nodes = TCP_OUTPUT_N_NEXT,
+ .next_nodes = {
#define _(s,n) [TCP_OUTPUT_NEXT_##s] = n,
foreach_tcp4_output_next
#undef _
- },
- .format_buffer = format_tcp_header,
- .format_trace = format_tcp_tx_trace,
+ },
+ .format_buffer = format_tcp_header,
+ .format_trace = format_tcp_tx_trace,
};
/* *INDENT-ON* */
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
.n_errors = TCP_N_ERROR,
+ .protocol_hint = VLIB_NODE_PROTO_HINT_TCP,
.error_strings = tcp_error_strings,
.n_next_nodes = TCP_OUTPUT_N_NEXT,
.next_nodes = {
else
th0 = ip6_next_header ((ip6_header_t *) th0);
t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
- clib_memcpy (&t0->tcp_header, th0, sizeof (t0->tcp_header));
+ clib_memcpy_fast (&t0->tcp_header, th0,
+ sizeof (t0->tcp_header));
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,