X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Ftcp%2Ftcp_input.c;h=1b4e8a6ac21776963409db94e7042db0dd826520;hb=1cfcb78940580c8e3645fca0419d32f9286e942d;hp=f838bc562ffd3dde2d573c262669bfeb2d409f11;hpb=6416e6274d0817a347d5b54bc61b4f1b617ff363;p=vpp.git diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index f838bc562ff..1b4e8a6ac21 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -390,8 +390,9 @@ tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0, /* 4th: check the SYN bit (in window) */ if (PREDICT_FALSE (tcp_syn (th0))) { + /* As per RFC5961 send challenge ack instead of reset */ + tcp_program_ack (wrk, tc0); *error0 = TCP_ERROR_SPURIOUS_SYN; - tcp_send_reset (tc0); goto error; } @@ -507,7 +508,7 @@ tcp_update_rtt (tcp_connection_t * tc, u32 ack) * seq_lt (tc->snd_una, ack). This is a condition for calling update_rtt */ else if (tcp_opts_tstamp (&tc->rcv_opts) && tc->rcv_opts.tsecr) { - u32 now = tcp_time_now_w_thread (tc->c_thread_index); + u32 now = tcp_tstamp (tc); mrtt = clib_max (now - tc->rcv_opts.tsecr, 1); } @@ -1184,12 +1185,10 @@ tcp_cc_recovery_exit (tcp_connection_t * tc) #ifndef CLIB_MARCH_VARIANT void -tcp_cc_fastrecovery_exit (tcp_connection_t * tc) +tcp_cc_fastrecovery_clear (tcp_connection_t * tc) { - tc->cc_algo->recovered (tc); tc->snd_rxt_bytes = 0; tc->rcv_dupacks = 0; - tc->snd_rxt_bytes = 0; tc->rtt_ts = 0; tcp_fastrecovery_off (tc); @@ -1212,8 +1211,9 @@ tcp_cc_congestion_undo (tcp_connection_t * tc) } else if (tcp_in_fastrecovery (tc)) { - tcp_cc_fastrecovery_exit (tc); + tcp_cc_fastrecovery_clear (tc); } + tcp_cc_undo_recovery (tc); ASSERT (tc->rto_boff == 0); TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 5); } @@ -1254,7 +1254,10 @@ tcp_cc_recover (tcp_connection_t * tc) if (tcp_in_recovery (tc)) tcp_cc_recovery_exit (tc); else if (tcp_in_fastrecovery (tc)) - tcp_cc_fastrecovery_exit (tc); + { + tcp_cc_recovered (tc); + tcp_cc_fastrecovery_clear (tc); + } ASSERT (tc->rto_boff == 0); ASSERT (!tcp_in_cong_recovery (tc)); @@ -1263,12 +1266,12 @@ tcp_cc_recover (tcp_connection_t * tc) } static void -tcp_cc_update (tcp_connection_t * tc, vlib_buffer_t * b) +tcp_cc_update (tcp_connection_t * tc, tcp_rate_sample_t * rs) { ASSERT (!tcp_in_cong_recovery (tc) || tcp_is_lost_fin (tc)); /* Congestion avoidance */ - tcp_cc_rcv_ack (tc); + tcp_cc_rcv_ack (tc, rs); /* If a cumulative ack, make sure dupacks is 0 */ tc->rcv_dupacks = 0; @@ -1335,6 +1338,8 @@ tcp_do_fastretransmits (tcp_worker_ctx_t * wrk) for (i = 0; i < vec_len (ongoing_fast_rxt); i++) { tc = tcp_connection_get (ongoing_fast_rxt[i], thread_index); + if (!tc) + continue; if (!tcp_in_fastrecovery (tc)) { tc->flags &= ~TCP_CONN_FRXT_PENDING; @@ -1373,7 +1378,8 @@ tcp_do_fastretransmits (tcp_worker_ctx_t * wrk) * One function to rule them all ... and in the darkness bind them */ static void -tcp_cc_handle_event (tcp_connection_t * tc, u32 is_dack) +tcp_cc_handle_event (tcp_connection_t * tc, tcp_rate_sample_t * rs, + u32 is_dack) { u32 rxt_delivered; @@ -1399,7 +1405,7 @@ tcp_cc_handle_event (tcp_connection_t * tc, u32 is_dack) if (tc->rcv_dupacks > TCP_DUPACK_THRESHOLD && !tc->bytes_acked) { ASSERT (tcp_in_fastrecovery (tc)); - tc->cc_algo->rcv_cong_ack (tc, TCP_CC_DUPACK); + tcp_cc_rcv_cong_ack (tc, TCP_CC_DUPACK, rs); return; } else if (tcp_should_fastrecover (tc)) @@ -1418,7 +1424,7 @@ tcp_cc_handle_event (tcp_connection_t * tc, u32 is_dack) } tcp_cc_init_congestion (tc); - tc->cc_algo->rcv_cong_ack (tc, TCP_CC_DUPACK); + tcp_cc_rcv_cong_ack (tc, TCP_CC_DUPACK, rs); if (tcp_opts_sack_permitted (&tc->rcv_opts)) { @@ -1444,7 +1450,7 @@ tcp_cc_handle_event (tcp_connection_t * tc, u32 is_dack) else if (!tc->bytes_acked || (tc->bytes_acked && !tcp_in_cong_recovery (tc))) { - tc->cc_algo->rcv_cong_ack (tc, TCP_CC_DUPACK); + tcp_cc_rcv_cong_ack (tc, TCP_CC_DUPACK, rs); return; } else @@ -1499,7 +1505,7 @@ partial_ack: } /* Treat as congestion avoidance ack */ - tcp_cc_rcv_ack (tc); + tcp_cc_rcv_ack (tc, rs); return; } @@ -1517,7 +1523,7 @@ partial_ack: /* Post RTO timeout don't try anything fancy */ if (tcp_in_recovery (tc)) { - tcp_cc_rcv_ack (tc); + tcp_cc_rcv_ack (tc, rs); transport_add_tx_event (&tc->connection); return; } @@ -1548,15 +1554,13 @@ partial_ack: else { tcp_fastrecovery_first_on (tc); - /* Reuse last bytes delivered to track total bytes acked */ - tc->sack_sb.last_bytes_delivered += tc->bytes_acked; if (tc->snd_rxt_bytes > tc->bytes_acked) tc->snd_rxt_bytes -= tc->bytes_acked; else tc->snd_rxt_bytes = 0; } - tc->cc_algo->rcv_cong_ack (tc, TCP_CC_PARTIALACK); + tcp_cc_rcv_cong_ack (tc, TCP_CC_PARTIALACK, rs); /* * Since this was a partial ack, try to retransmit some more data @@ -1572,6 +1576,7 @@ tcp_rcv_ack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b, tcp_header_t * th, u32 * error) { u32 prev_snd_wnd, prev_snd_una; + tcp_rate_sample_t rs = { 0 }; u8 is_dack; TCP_EVT_DBG (TCP_EVT_CC_STAT, tc); @@ -1601,7 +1606,7 @@ tcp_rcv_ack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b, TCP_EVT_DBG (TCP_EVT_ACK_RCV_ERR, tc, 1, vnet_buffer (b)->tcp.ack_number); if (tcp_in_fastrecovery (tc) && tc->rcv_dupacks == TCP_DUPACK_THRESHOLD) - tcp_cc_handle_event (tc, 1); + tcp_cc_handle_event (tc, 0, 1); /* Don't drop yet */ return 0; } @@ -1629,6 +1634,9 @@ process_ack: tcp_update_rtt (tc, vnet_buffer (b)->tcp.ack_number); } + if (tc->flags & TCP_CONN_RATE_SAMPLE) + tcp_bt_sample_delivery_rate (tc, &rs); + TCP_EVT_DBG (TCP_EVT_ACK_RCVD, tc); /* @@ -1637,7 +1645,7 @@ process_ack: if (tcp_ack_is_cc_event (tc, b, prev_snd_wnd, prev_snd_una, &is_dack)) { - tcp_cc_handle_event (tc, is_dack); + tcp_cc_handle_event (tc, &rs, is_dack); if (!tcp_in_cong_recovery (tc)) { *error = TCP_ERROR_ACK_OK; @@ -1652,7 +1660,7 @@ process_ack: /* * Update congestion control (slow start/congestion avoidance) */ - tcp_cc_update (tc, b); + tcp_cc_update (tc, &rs); *error = TCP_ERROR_ACK_OK; return 0; } @@ -1692,6 +1700,10 @@ static void tcp_rcv_fin (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b, u32 * error) { + /* Reject out-of-order fins */ + if (vnet_buffer (b)->tcp.seq_end != tc->rcv_nxt) + return; + /* Account for the FIN and send ack */ tc->rcv_nxt += 1; tcp_program_ack (wrk, tc); @@ -1871,7 +1883,7 @@ tcp_session_enqueue_ooo (tcp_connection_t * tc, vlib_buffer_t * b, newest = svm_fifo_newest_ooo_segment (s0->rx_fifo); if (newest) { - offset = ooo_segment_offset (s0->rx_fifo, newest); + offset = ooo_segment_offset_prod (s0->rx_fifo, newest); ASSERT (offset <= vnet_buffer (b)->tcp.seq_number - tc->rcv_nxt); start = tc->rcv_nxt + offset; end = start + ooo_segment_length (s0->rx_fifo, newest); @@ -2526,9 +2538,9 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, * allocate session send reset */ if (session_stream_connect_notify (&new_tc0->connection, 0)) { - clib_warning ("connect notify fail"); tcp_send_reset_w_pkt (new_tc0, b0, my_thread_index, is_ip4); tcp_connection_cleanup (new_tc0); + error0 = TCP_ERROR_CREATE_SESSION_FAIL; goto drop; } @@ -2550,6 +2562,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, tcp_connection_cleanup (new_tc0); tcp_send_reset_w_pkt (tc0, b0, my_thread_index, is_ip4); TCP_EVT_DBG (TCP_EVT_RST_SENT, tc0); + error0 = TCP_ERROR_CREATE_SESSION_FAIL; goto drop; } @@ -2837,7 +2850,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, break; /* Still have outstanding tx data */ - if (transport_max_tx_dequeue (&tc0->connection)) + max_dequeue = transport_max_tx_dequeue (&tc0->connection); + if (max_dequeue > tc0->burst_acked) break; tcp_send_fin (tc0); @@ -3008,6 +3022,7 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, thread_index); tcp_inc_counter (rcv_process, TCP_ERROR_MSG_QUEUE_FULL, errors); tcp_handle_postponed_dequeues (wrk); + tcp_handle_disconnects (wrk); vlib_buffer_free (vm, first_buffer, from_frame->n_vectors); return from_frame->n_vectors; @@ -3187,7 +3202,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node, child0->rto = TCP_RTO_MIN; if (session_stream_accept (&child0->connection, lc0->c_s_index, - 0 /* notify */ )) + lc0->c_thread_index, 0 /* notify */ )) { tcp_connection_cleanup (child0); error0 = TCP_ERROR_CREATE_SESSION_FAIL;