/* 2nd: check the RST bit */
if (tcp_rst (th0))
{
- /* Notify session that connection has been reset. Switch
- * state to closed and await for session to do the cleanup. */
- stream_session_reset_notify (&tc0->connection);
- tc0->state = TCP_STATE_CLOSED;
+ tcp_connection_reset (tc0);
return -1;
}
/* Updates congestion control (slow start/congestion avoidance) */
tcp_cc_rcv_ack (tc);
+ TCP_EVT_DBG (TCP_EVT_ACK_RCVD, tc);
+
/* If everything has been acked, stop retransmit timer
* otherwise update */
if (tc->snd_una == tc->snd_una_max)
* segments can be enqueued after fifo tail offset changes. */
error = tcp_session_enqueue_data (tc, b, n_data_bytes);
+ TCP_EVT_DBG (TCP_EVT_INPUT, tc, n_data_bytes);
+
/* Check if ACK can be delayed */
if (tcp_can_delack (tc))
{
tc0 = tcp_connection_get (vnet_buffer (b0)->tcp.connection_index,
my_thread_index);
+ if (PREDICT_FALSE (tc0 == 0))
+ {
+ error0 = TCP_ERROR_INVALID_CONNECTION;
+ goto drop;
+ }
+
/* Checksum computed by ipx_local no need to compute again */
if (is_ip4)
/* 8: check the FIN bit */
if (tcp_fin (th0))
{
- /* Send ACK and enter CLOSE-WAIT */
- tcp_make_ack (tc0, b0);
- tcp_connection_force_ack (tc0, b0);
- next0 = tcp_next_output (tc0->c_is_ip4);
+ /* Enter CLOSE-WAIT and notify session. Don't send ACK, instead
+ * wait for session to call close. To avoid lingering
+ * in CLOSE-WAIT, set timer (reuse WAITCLOSE). */
tc0->state = TCP_STATE_CLOSE_WAIT;
+ TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0);
stream_session_disconnect_notify (&tc0->connection);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
}
drop:
.name = "tcp4-established",
/* Takes a vector of packets. */
.vector_size = sizeof (u32),
- .n_errors = TCP_N_ERROR,.error_strings = tcp_error_strings,
+ .n_errors = TCP_N_ERROR,
+ .error_strings = tcp_error_strings,
.n_next_nodes = TCP_ESTABLISHED_N_NEXT,
.next_nodes =
{
{
new_tc0->state = TCP_STATE_SYN_RCVD;
- /* Notify app that we have connection XXX */
+ /* Notify app that we have connection */
stream_session_connect_notify (&new_tc0->connection, sst, 0);
tcp_make_synack (new_tc0, b0);
VLIB_NODE_FUNCTION_MULTIARCH (tcp6_syn_sent_node, tcp6_syn_sent_rcv);
/**
- * Handles reception for all states except LISTEN, SYN-SEND and ESTABLISHED
+ * Handles reception for all states except LISTEN, SYN-SENT and ESTABLISHED
* as per RFC793 p. 64
*/
always_inline uword
b0 = vlib_get_buffer (vm, bi0);
tc0 = tcp_connection_get (vnet_buffer (b0)->tcp.connection_index,
my_thread_index);
+ if (PREDICT_FALSE (tc0 == 0))
+ {
+ error0 = TCP_ERROR_INVALID_CONNECTION;
+ goto drop;
+ }
/* Checksum computed by ipx_local no need to compute again */
/* Shoulder tap the server */
stream_session_accept_notify (&tc0->connection);
- tcp_timer_reset (tc0, TCP_TIMER_RETRANSMIT_SYN);
+ /* Reset SYN-ACK retransmit timer */
+ tcp_timer_reset (tc0, TCP_TIMER_RETRANSMIT);
break;
case TCP_STATE_ESTABLISHED:
/* We can get packets in established state here because they
* continue processing in that state. */
if (tcp_rcv_ack (tc0, b0, tcp0, &next0, &error0))
goto drop;
- tc0->state = TCP_STATE_FIN_WAIT_2;
- /* Stop all timers, 2MSL will be set lower */
- tcp_connection_timers_reset (tc0);
+
+ /* If FIN is ACKed */
+ if (tc0->snd_una == tc0->snd_una_max)
+ {
+ tc0->state = TCP_STATE_FIN_WAIT_2;
+ /* Stop all timers, 2MSL will be set lower */
+ tcp_connection_timers_reset (tc0);
+ }
break;
case TCP_STATE_FIN_WAIT_2:
/* In addition to the processing for the ESTABLISHED state, if
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
goto drop;
- tcp_connection_del (tc0);
+ tc0->state = TCP_STATE_CLOSED;
+
+ /* Don't delete the connection/session yet. Instead, wait a
+ * reasonable amount of time until the pipes are cleared. In
+ * particular, this makes sure that we won't have dead sessions
+ * when processing events on the tx path */
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
+
+ /* Stop retransmit */
+ tcp_timer_reset (tc0, TCP_TIMER_RETRANSMIT);
+
goto drop;
break;
case TCP_STATE_SYN_RCVD:
/* Send FIN-ACK notify app and enter CLOSE-WAIT */
tcp_connection_timers_reset (tc0);
- tcp_make_finack (tc0, b0);
+ tcp_make_fin (tc0, b0);
next0 = tcp_next_output (tc0->c_is_ip4);
stream_session_disconnect_notify (&tc0->connection);
tc0->state = TCP_STATE_CLOSE_WAIT;
case TCP_STATE_FIN_WAIT_1:
tc0->state = TCP_STATE_TIME_WAIT;
tcp_connection_timers_reset (tc0);
- tcp_timer_set (tc0, TCP_TIMER_2MSL, TCP_2MSL_TIME);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
break;
case TCP_STATE_FIN_WAIT_2:
/* Got FIN, send ACK! */
tc0->state = TCP_STATE_TIME_WAIT;
- tcp_timer_set (tc0, TCP_TIMER_2MSL, TCP_2MSL_TIME);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
tcp_make_ack (tc0, b0);
next0 = tcp_next_output (is_ip4);
break;
/* Remain in the TIME-WAIT state. Restart the 2 MSL time-wait
* timeout.
*/
- tcp_timer_update (tc0, TCP_TIMER_2MSL, TCP_2MSL_TIME);
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
break;
}
+ TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0);
b0->error = error0 ? node->errors[error0] : 0;
tcp_connection_init_vars (child0);
+ TCP_EVT_DBG (TCP_EVT_SYN_RCVD, child0);
+
/* Reuse buffer to make syn-ack and send */
tcp_make_synack (child0, b0);
next0 = tcp_next_output (is_ip4);
u8 state;
} tcp_rx_trace_t;
-const char *tcp_fsm_states[] = {
-#define _(sym, str) str,
- foreach_tcp_fsm_state
-#undef _
-};
-
-u8 *
-format_tcp_state (u8 * s, va_list * args)
-{
- tcp_state_t *state = va_arg (*args, tcp_state_t *);
-
- if (state[0] < TCP_N_STATES)
- s = format (s, "%s", tcp_fsm_states[state[0]]);
- else
- s = format (s, "UNKNOWN");
-
- return s;
-}
-
u8 *
format_tcp_rx_trace (u8 * s, va_list * args)
{
n_left_to_next -= 1;
b0 = vlib_get_buffer (vm, bi0);
+ vnet_buffer (b0)->tcp.flags = 0;
if (is_ip4)
{
/* Send reset */
next0 = TCP_INPUT_NEXT_RESET;
error0 = TCP_ERROR_NO_LISTENER;
- vnet_buffer (b0)->tcp.flags = 0;
}
b0->error = error0 ? node->errors[error0] : 0;
_(ESTABLISHED, TCP_FLAG_FIN, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_RST, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
/* ACK or FIN-ACK to our FIN */
_(FIN_WAIT_1, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_1, TCP_FLAG_ACK | TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS,