Use a smaller lower bound(5ms) to clamp the initial rtt, when setting initial rtt from a trusted value. Currently only the min_rtt from CachedNetworkParameters is considered trusted. Protected by FLAGS_quic_reloadable_flag_quic_use_lower_min_for_trusted_irtt. PiperOrigin-RevId: 431821410
diff --git a/quic/core/congestion_control/send_algorithm_interface.h b/quic/core/congestion_control/send_algorithm_interface.h index 4271603..3135f21 100644 --- a/quic/core/congestion_control/send_algorithm_interface.h +++ b/quic/core/congestion_control/send_algorithm_interface.h
@@ -34,8 +34,7 @@ // Network Params for AdjustNetworkParameters. struct QUIC_NO_EXPORT NetworkParams { NetworkParams() = default; - NetworkParams(const QuicBandwidth& bandwidth, - const QuicTime::Delta& rtt, + NetworkParams(const QuicBandwidth& bandwidth, const QuicTime::Delta& rtt, bool allow_cwnd_to_decrease) : bandwidth(bandwidth), rtt(rtt), @@ -47,7 +46,8 @@ max_initial_congestion_window == other.max_initial_congestion_window && burst_token == other.burst_token && - allow_cwnd_to_decrease == other.allow_cwnd_to_decrease; + allow_cwnd_to_decrease == other.allow_cwnd_to_decrease && + is_rtt_trusted == other.is_rtt_trusted; } QuicBandwidth bandwidth = QuicBandwidth::Zero(); @@ -55,6 +55,7 @@ int max_initial_congestion_window = 0; int burst_token = 0; bool allow_cwnd_to_decrease = false; + bool is_rtt_trusted = false; }; static SendAlgorithmInterface* Create(
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index cad9cac..ccf2d3a 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -1672,7 +1672,11 @@ // QuicSentPacketManager::SetInitialRtt clamps the initial_rtt to between // [min_initial_rtt, max_initial_rtt]. const QuicTime::Delta min_initial_rtt = - QuicTime::Delta::FromMicroseconds(kMinInitialRoundTripTimeUs); + server_connection->sent_packet_manager().use_lower_min_irtt() + ? QuicTime::Delta::FromMicroseconds( + kMinTrustedInitialRoundTripTimeUs) + : QuicTime::Delta::FromMicroseconds( + kMinUntrustedInitialRoundTripTimeUs); const QuicTime::Delta max_initial_rtt = QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs); const QuicTime::Delta expected_initial_rtt =
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc index 8edcb69..5b1fe05 100644 --- a/quic/core/http/quic_server_session_base.cc +++ b/quic/core/http/quic_server_session_base.cc
@@ -47,8 +47,13 @@ void QuicServerSessionBase::OnConfigNegotiated() { QuicSpdySession::OnConfigNegotiated(); - if (!config()->HasReceivedConnectionOptions()) { - return; + const bool use_lower_min_irtt = + connection()->sent_packet_manager().use_lower_min_irtt(); + + if (!use_lower_min_irtt) { + if (!config()->HasReceivedConnectionOptions()) { + return; + } } const CachedNetworkParameters* cached_network_params = @@ -61,20 +66,29 @@ cached_network_params != nullptr) { if (cached_network_params->serving_region() == serving_region_) { QUIC_CODE_COUNT(quic_server_received_network_params_at_same_region); - if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kTRTT)) { + if ((!use_lower_min_irtt || config()->HasReceivedConnectionOptions()) && + ContainsQuicTag(config()->ReceivedConnectionOptions(), kTRTT)) { QUIC_DLOG(INFO) << "Server: Setting initial rtt to " << cached_network_params->min_rtt_ms() << "ms which is received from a validated address token"; connection()->sent_packet_manager().SetInitialRtt( QuicTime::Delta::FromMilliseconds( - cached_network_params->min_rtt_ms())); + cached_network_params->min_rtt_ms()), + /*trusted=*/use_lower_min_irtt); } } else { QUIC_CODE_COUNT(quic_server_received_network_params_at_different_region); } } + if (use_lower_min_irtt) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_lower_min_for_trusted_irtt, 1, 2); + if (!config()->HasReceivedConnectionOptions()) { + return; + } + } + // Enable bandwidth resumption if peer sent correct connection options. const bool last_bandwidth_resumption = ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h index 214417e..812b28b 100644 --- a/quic/core/quic_constants.h +++ b/quic/core/quic_constants.h
@@ -86,8 +86,11 @@ // Default size of the socket receive buffer in bytes. const QuicByteCount kDefaultSocketReceiveBuffer = 1024 * 1024; -// Don't allow a client to suggest an RTT shorter than 10ms. -const uint32_t kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli; +// The lower bound of an untrusted initial rtt value. +const uint32_t kMinUntrustedInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli; + +// The lower bound of a trusted initial rtt value. +const uint32_t kMinTrustedInitialRoundTripTimeUs = 5 * kNumMicrosPerMilli; // Don't allow a client to suggest an RTT longer than 1 second. const uint32_t kMaxInitialRoundTripTimeUs = kNumMicrosPerSecond;
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h index 5c63ddc..938877f 100644 --- a/quic/core/quic_flags_list.h +++ b/quic/core/quic_flags_list.h
@@ -23,6 +23,8 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_no_probe_up_exit_if_no_queue, true) // If true, 1) NEW_TOKENs sent from a IETF QUIC session will include the cached network parameters proto, 2) A min_rtt received from a validated token will be used to set the initial rtt, 3) Enable bandwidth resumption for IETF QUIC when connection options BWRE or BWMX exists. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_cached_network_parameters_to_address_token2, true) +// If true, 1) QUIC connections will use a lower minimum for trusted initial rtt, 2) When TRTT is received, QUIC server sessions will mark the initial rtt from CachedNetworkParameters as trusted. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_lower_min_for_trusted_irtt, false) // If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false) // If true, QpackEncoder will stop emitting instructions on the encoder stream if amount of buffered data exceeds a hardcoded limit.
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index 588c3ef..0d6c862 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -138,12 +138,14 @@ config.ReceivedInitialRoundTripTimeUs() > 0) { if (!config.HasClientSentConnectionOption(kNRTT, perspective)) { SetInitialRtt(QuicTime::Delta::FromMicroseconds( - config.ReceivedInitialRoundTripTimeUs())); + config.ReceivedInitialRoundTripTimeUs()), + /*trusted=*/false); } } else if (config.HasInitialRoundTripTimeUsToSend() && config.GetInitialRoundTripTimeUsToSend() > 0) { SetInitialRtt(QuicTime::Delta::FromMicroseconds( - config.GetInitialRoundTripTimeUsToSend())); + config.GetInitialRoundTripTimeUsToSend()), + /*trusted=*/false); } if (config.HasReceivedMaxAckDelayMs()) { peer_max_ack_delay_ = @@ -384,8 +386,12 @@ // This calls the old AdjustNetworkParameters interface, and fills certain // fields in SendAlgorithmInterface::NetworkParams // (e.g., quic_bbr_fix_pacing_rate) using GFE flags. - AdjustNetworkParameters(SendAlgorithmInterface::NetworkParams( - bandwidth, rtt, /*allow_cwnd_to_decrease = */ false)); + SendAlgorithmInterface::NetworkParams params( + bandwidth, rtt, /*allow_cwnd_to_decrease = */ false); + // The rtt is trusted because it's a min_rtt measured from a previous + // connection with the same network path between client and server. + params.is_rtt_trusted = true; + AdjustNetworkParameters(params); } void QuicSentPacketManager::AdjustNetworkParameters( @@ -404,8 +410,24 @@ } const QuicBandwidth& bandwidth = params.bandwidth; const QuicTime::Delta& rtt = params.rtt; - if (!rtt.IsZero()) { - SetInitialRtt(rtt); + + if (use_lower_min_irtt()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_lower_min_for_trusted_irtt, 2, 2); + if (!rtt.IsZero()) { + if (params.is_rtt_trusted) { + // Always set initial rtt if it's trusted. + SetInitialRtt(rtt, /*trusted=*/true); + } else if (rtt_stats_.initial_rtt() == + QuicTime::Delta::FromMilliseconds(kInitialRttMs)) { + // Only set initial rtt if we are using the default. This avoids + // overwriting a trusted initial rtt by an untrusted one. + SetInitialRtt(rtt, /*trusted=*/false); + } + } + } else { + if (!rtt.IsZero()) { + SetInitialRtt(rtt, /*trusted=*/false); + } } const QuicByteCount old_cwnd = send_algorithm_->GetCongestionWindow(); if (GetQuicReloadableFlag(quic_conservative_bursts) && using_pacing_ && @@ -1710,9 +1732,10 @@ return pacing_sender_.GetNextReleaseTime(); } -void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) { - const QuicTime::Delta min_rtt = - QuicTime::Delta::FromMicroseconds(kMinInitialRoundTripTimeUs); +void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt, bool trusted) { + const QuicTime::Delta min_rtt = QuicTime::Delta::FromMicroseconds( + trusted ? kMinTrustedInitialRoundTripTimeUs + : kMinUntrustedInitialRoundTripTimeUs); QuicTime::Delta max_rtt = QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs); rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt)));
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h index cb4fdef..7b127b5 100644 --- a/quic/core/quic_sent_packet_manager.h +++ b/quic/core/quic_sent_packet_manager.h
@@ -482,8 +482,13 @@ num_ptos_for_path_degrading_ = num_ptos_for_path_degrading; } - // Sets the initial RTT of the connection. - void SetInitialRtt(QuicTime::Delta rtt); + // Sets the initial RTT of the connection. The inital RTT is clamped to + // - A maximum of kMaxInitialRoundTripTimeUs. + // - A minimum of kMinTrustedInitialRoundTripTimeUs if |trusted|, or + // kMinUntrustedInitialRoundTripTimeUs if not |trusted|. + void SetInitialRtt(QuicTime::Delta rtt, bool trusted); + + bool use_lower_min_irtt() const { return use_lower_min_irtt_; } private: friend class test::QuicConnectionPeer; @@ -756,6 +761,10 @@ // Whether to ignore the ack_delay in received ACKs. bool ignore_ack_delay_; + + // Latched value of --quic_use_lower_min_for_trusted_irtt. + bool use_lower_min_irtt_ = + GetQuicReloadableFlag(quic_use_lower_min_for_trusted_irtt); }; } // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index d038f4f..565eb96 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -2101,6 +2101,7 @@ params.bandwidth = QuicBandwidth::Zero(); params.allow_cwnd_to_decrease = false; params.rtt = kRtt; + params.is_rtt_trusted = true; EXPECT_CALL(*send_algorithm_, AdjustNetworkParameters(params)); EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) @@ -4682,6 +4683,42 @@ QuicTime::Delta::FromMilliseconds(1u))); } +TEST_F(QuicSentPacketManagerTest, SetInitialRtt) { + // Upper bounds. + manager_.SetInitialRtt( + QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs + 1), false); + EXPECT_EQ(manager_.GetRttStats()->initial_rtt().ToMicroseconds(), + kMaxInitialRoundTripTimeUs); + + manager_.SetInitialRtt( + QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs + 1), true); + EXPECT_EQ(manager_.GetRttStats()->initial_rtt().ToMicroseconds(), + kMaxInitialRoundTripTimeUs); + + EXPECT_GT(kMinUntrustedInitialRoundTripTimeUs, + kMinTrustedInitialRoundTripTimeUs); + + // Lower bounds for untrusted rtt. + manager_.SetInitialRtt(QuicTime::Delta::FromMicroseconds( + kMinUntrustedInitialRoundTripTimeUs - 1), + false); + EXPECT_EQ(manager_.GetRttStats()->initial_rtt().ToMicroseconds(), + kMinUntrustedInitialRoundTripTimeUs); + + // Lower bounds for trusted rtt. + manager_.SetInitialRtt(QuicTime::Delta::FromMicroseconds( + kMinUntrustedInitialRoundTripTimeUs - 1), + true); + EXPECT_EQ(manager_.GetRttStats()->initial_rtt().ToMicroseconds(), + kMinUntrustedInitialRoundTripTimeUs - 1); + + manager_.SetInitialRtt( + QuicTime::Delta::FromMicroseconds(kMinTrustedInitialRoundTripTimeUs - 1), + true); + EXPECT_EQ(manager_.GetRttStats()->initial_rtt().ToMicroseconds(), + kMinTrustedInitialRoundTripTimeUs); +} + } // namespace } // namespace test } // namespace quic