X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Ftcp%2Ftcp_input.c;h=fb80d7f575939d27e2fd7f03266d8baa42ff8ba6;hb=b0f662fe93f1db0098f7b50306c2f084644788b1;hp=32de369b4cc3a52f8d5fbcd96dbb15cabedb75d7;hpb=78cc4b0797a983d5d31b9127fea9c2b72ed081d7;p=vpp.git diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index 32de369b4cc..fb80d7f5759 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -509,6 +509,7 @@ tcp_estimate_initial_rtt (tcp_connection_t * tc) if (mrtt > 0 && mrtt < TCP_RTT_MAX) tcp_estimate_rtt (tc, mrtt); + tcp_update_rto (tc); } /** @@ -1638,7 +1639,7 @@ tcp_handle_disconnects (tcp_worker_ctx_t * wrk) { tc = tcp_connection_get (pending_disconnects[i], thread_index); tcp_disconnect_pending_off (tc); - stream_session_disconnect_notify (&tc->connection); + session_transport_closing_notify (&tc->connection); } _vec_len (wrk->pending_disconnects) = 0; } @@ -1647,13 +1648,12 @@ static void tcp_rcv_fin (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b, u32 * error) { + /* Account for the FIN and send ack */ + tc->rcv_nxt += 1; + tcp_program_ack (wrk, tc); /* Enter CLOSE-WAIT and notify session. To avoid lingering * in CLOSE-WAIT, set timer (reuse WAITCLOSE). */ - /* Account for the FIN if nothing else was received */ - if (vnet_buffer (b)->tcp.data_len == 0) - tc->rcv_nxt += 1; - tcp_program_ack (wrk, tc); - tc->state = TCP_STATE_CLOSE_WAIT; + tcp_connection_set_state (tc, TCP_STATE_CLOSE_WAIT); tcp_program_disconnect (wrk, tc); tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc); @@ -2093,7 +2093,6 @@ tcp46_established_inline (vlib_main_t * vm, vlib_node_runtime_t * node, tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index); u32 n_left_from, *from, *first_buffer; u16 err_counters[TCP_N_ERROR] = { 0 }; - u8 is_fin = 0; if (node->flags & VLIB_NODE_FLAG_TRACE) tcp_established_trace_frame (vm, node, frame, is_ip4); @@ -2105,7 +2104,7 @@ tcp46_established_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { u32 bi0, error0 = TCP_ERROR_ACK_OK; vlib_buffer_t *b0; - tcp_header_t *th0 = 0; + tcp_header_t *th0; tcp_connection_t *tc0; if (n_left_from > 1) @@ -2131,13 +2130,6 @@ tcp46_established_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } th0 = tcp_buffer_hdr (b0); - /* N.B. buffer is rewritten if segment is ooo. Thus, th0 becomes a - * dangling reference. */ - is_fin = tcp_is_fin (th0); - - /* SYNs, FINs and data consume sequence numbers */ - vnet_buffer (b0)->tcp.seq_end = vnet_buffer (b0)->tcp.seq_number - + tcp_is_syn (th0) + is_fin + vnet_buffer (b0)->tcp.data_len; /* TODO header prediction fast path */ @@ -2159,7 +2151,7 @@ tcp46_established_inline (vlib_main_t * vm, vlib_node_runtime_t * node, error0 = tcp_segment_rcv (wrk, tc0, b0); /* 8: check the FIN bit */ - if (PREDICT_FALSE (is_fin)) + if (PREDICT_FALSE (tcp_is_fin (th0))) tcp_rcv_fin (wrk, tc0, b0, &error0); done: @@ -2381,10 +2373,8 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, goto drop; } - /* SYNs, FINs and data consume sequence numbers */ - vnet_buffer (b0)->tcp.seq_end = - seq0 + tcp_is_syn (tcp0) + tcp_is_fin (tcp0) + - vnet_buffer (b0)->tcp.data_len; + /* SYNs consume sequence numbers */ + vnet_buffer (b0)->tcp.seq_end += tcp_is_syn (tcp0); /* * 1. check the ACK bit @@ -2462,7 +2452,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, new_tc0->c_thread_index = my_thread_index; new_tc0->rcv_nxt = vnet_buffer (b0)->tcp.seq_end; new_tc0->irs = seq0; - new_tc0->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID; + new_tc0->timers[TCP_TIMER_ESTABLISH_AO] = TCP_TIMER_HANDLE_INVALID; new_tc0->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID; new_tc0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; @@ -2674,10 +2664,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, tcp0 = tcp_buffer_hdr (b0); is_fin0 = tcp_is_fin (tcp0); - /* SYNs, FINs and data consume sequence numbers */ - vnet_buffer (b0)->tcp.seq_end = vnet_buffer (b0)->tcp.seq_number - + tcp_is_syn (tcp0) + is_fin0 + vnet_buffer (b0)->tcp.data_len; - if (CLIB_DEBUG) { tcp_connection_t *tmp; @@ -2685,7 +2671,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, is_ip4); if (tmp->state != tc0->state) { - clib_warning ("state changed"); + if (tc0->state != TCP_STATE_CLOSED) + clib_warning ("state changed"); goto drop; } } @@ -2783,14 +2770,13 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* If FIN is ACKed */ else if (tc0->snd_una == tc0->snd_una_max) { - tc0->state = TCP_STATE_FIN_WAIT_2; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + tcp_connection_set_state (tc0, TCP_STATE_FIN_WAIT_2); /* Stop all retransmit timers because we have nothing more * to send. Enable waitclose though because we're willing to * wait for peer's FIN but not indefinitely. */ tcp_connection_timers_reset (tc0); - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); /* Don't try to deq the FIN acked */ if (tc0->burst_acked > 1) @@ -2819,9 +2805,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { tcp_send_fin (tc0); tcp_connection_timers_reset (tc0); - tc0->state = TCP_STATE_LAST_ACK; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); + tcp_connection_set_state (tc0, TCP_STATE_LAST_ACK); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); } } break; @@ -2832,9 +2817,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (tcp_rcv_ack (wrk, tc0, b0, tcp0, &error0)) goto drop; - tc0->state = TCP_STATE_TIME_WAIT; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME); + tcp_connection_timers_reset (tc0); + tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME); goto drop; break; @@ -2857,14 +2842,13 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, goto drop; } - tc0->state = TCP_STATE_CLOSED; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + tcp_connection_set_state (tc0, TCP_STATE_CLOSED); /* Don't free the connection from the data path since * we can't ensure that we have no packets already enqueued * to output. Rely instead on the waitclose timer */ tcp_connection_timers_reset (tc0); - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME); goto drop; @@ -2896,8 +2880,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, case TCP_STATE_FIN_WAIT_2: if (vnet_buffer (b0)->tcp.data_len) error0 = tcp_segment_rcv (wrk, tc0, b0); - else if (is_fin0) - tc0->rcv_nxt += 1; break; case TCP_STATE_CLOSE_WAIT: case TCP_STATE_CLOSING: @@ -2912,10 +2894,17 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (!is_fin0) goto drop; + TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0); + switch (tc0->state) { case TCP_STATE_ESTABLISHED: - tcp_rcv_fin (wrk, tc0, b0, &error0); + /* Account for the FIN and send ack */ + tc0->rcv_nxt += 1; + tcp_program_ack (wrk, tc0); + tcp_connection_set_state (tc0, TCP_STATE_CLOSE_WAIT); + tcp_program_disconnect (wrk, tc0); + tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME); break; case TCP_STATE_SYN_RCVD: /* Send FIN-ACK, enter LAST-ACK and because the app was not @@ -2924,8 +2913,7 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, tcp_connection_timers_reset (tc0); tc0->rcv_nxt += 1; tcp_send_fin (tc0); - tc0->state = TCP_STATE_LAST_ACK; - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); + tcp_connection_set_state (tc0, TCP_STATE_LAST_ACK); tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); break; case TCP_STATE_CLOSE_WAIT: @@ -2934,19 +2922,19 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, /* move along .. */ break; case TCP_STATE_FIN_WAIT_1: - tc0->state = TCP_STATE_CLOSING; + tc0->rcv_nxt += 1; + tcp_connection_set_state (tc0, TCP_STATE_CLOSING); tcp_program_ack (wrk, tc0); - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); /* Wait for ACK but not forever */ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME); break; case TCP_STATE_FIN_WAIT_2: /* Got FIN, send ACK! Be more aggressive with resource cleanup */ - tc0->state = TCP_STATE_TIME_WAIT; + tc0->rcv_nxt += 1; + tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT); tcp_connection_timers_reset (tc0); - tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME); + tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME); tcp_program_ack (wrk, tc0); - TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0); break; case TCP_STATE_TIME_WAIT: /* Remain in the TIME-WAIT state. Restart the time-wait @@ -2956,7 +2944,6 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, break; } error0 = TCP_ERROR_FIN_RCVD; - TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0); drop: @@ -3391,6 +3378,8 @@ tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error, vnet_buffer (b)->tcp.ack_number = clib_net_to_host_u32 (tcp->ack_number); vnet_buffer (b)->tcp.data_offset = n_advance_bytes; vnet_buffer (b)->tcp.data_len = n_data_bytes; + vnet_buffer (b)->tcp.seq_end = vnet_buffer (b)->tcp.seq_number + + n_data_bytes; vnet_buffer (b)->tcp.flags = 0; *error = is_filtered ? TCP_ERROR_FILTERED : *error; @@ -3704,12 +3693,37 @@ do { \ _(FIN_WAIT_1, TCP_FLAG_ACK | TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); /* FIN in reply to our FIN from the other side */ + _(FIN_WAIT_1, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID); _(FIN_WAIT_1, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_1, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(FIN_WAIT_1, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_1, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_1, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(CLOSING, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(CLOSING, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(CLOSING, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(CLOSING, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(CLOSING, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); /* FIN confirming that the peer (app) has closed */ _(FIN_WAIT_2, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(FIN_WAIT_2, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); @@ -3724,14 +3738,33 @@ do { \ _(CLOSE_WAIT, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(CLOSE_WAIT, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID); _(LAST_ACK, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(LAST_ACK, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(LAST_ACK, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(LAST_ACK, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(LAST_ACK, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, + TCP_ERROR_NONE); + _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK, + TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(TIME_WAIT, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE); _(TIME_WAIT, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);