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