In QUIC, add a copt to enable overshooting detection. Protected by gfe2_reloadable_flag_quic_enable_overshooting_detection.

PiperOrigin-RevId: 323844168
Change-Id: I3776c6459611870e85aa7031cde53d4cc8d7e350
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index 05d62ea..7389067 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -120,9 +120,10 @@
       enable_ack_aggregation_during_startup_(false),
       expire_ack_aggregation_in_startup_(false),
       drain_to_target_(false),
-      network_parameters_adjusted_(false),
-      bytes_lost_with_network_parameters_adjusted_(0),
-      bytes_lost_multiplier_with_network_parameters_adjusted_(2),
+      detect_overshooting_(false),
+      bytes_lost_while_detecting_overshooting_(0),
+      bytes_lost_multiplier_while_detecting_overshooting_(2),
+      cwnd_to_calculate_min_pacing_rate_(initial_congestion_window_),
       max_congestion_window_with_network_parameters_adjusted_(
           kMaxInitialCongestionWindow * kDefaultTCPMSS) {
   if (stats_) {
@@ -142,6 +143,8 @@
   if (mode_ == STARTUP) {
     initial_congestion_window_ = congestion_window * kDefaultTCPMSS;
     congestion_window_ = congestion_window * kDefaultTCPMSS;
+    cwnd_to_calculate_min_pacing_rate_ = std::min(
+        initial_congestion_window_, cwnd_to_calculate_min_pacing_rate_);
   }
 }
 
@@ -254,10 +257,10 @@
     drain_to_target_ = true;
   }
   if (config.HasClientRequestedIndependentOption(kBWM3, perspective)) {
-    bytes_lost_multiplier_with_network_parameters_adjusted_ = 3;
+    bytes_lost_multiplier_while_detecting_overshooting_ = 3;
   }
   if (config.HasClientRequestedIndependentOption(kBWM4, perspective)) {
-    bytes_lost_multiplier_with_network_parameters_adjusted_ = 4;
+    bytes_lost_multiplier_while_detecting_overshooting_ = 4;
   }
   if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) {
     sampler_.SetMaxAckHeightTrackerWindowLength(2 * kBandwidthWindowSize);
@@ -288,6 +291,15 @@
     max_congestion_window_with_network_parameters_adjusted_ =
         100 * kDefaultTCPMSS;
   }
+  if (GetQuicReloadableFlag(quic_enable_overshooting_detection) &&
+      config.HasClientRequestedIndependentOption(kDTOS, perspective)) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_enable_overshooting_detection);
+    detect_overshooting_ = true;
+    // DTOS would allow pacing rate drop to IW 10 / min_rtt if overshooting is
+    // detected.
+    cwnd_to_calculate_min_pacing_rate_ =
+        std::min(initial_congestion_window_, 10 * kDefaultTCPMSS);
+  }
 
   ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
 }
@@ -354,7 +366,7 @@
       QuicBandwidth new_pacing_rate =
           QuicBandwidth::FromBytesAndTimeDelta(congestion_window_, GetMinRtt());
       pacing_rate_ = std::max(pacing_rate_, new_pacing_rate);
-      network_parameters_adjusted_ = true;
+      detect_overshooting_ = true;
     }
   }
 }
@@ -766,29 +778,27 @@
     return;
   }
 
-  if (network_parameters_adjusted_) {
-    bytes_lost_with_network_parameters_adjusted_ += bytes_lost;
+  if (detect_overshooting_) {
+    bytes_lost_while_detecting_overshooting_ += bytes_lost;
     // Check for overshooting with network parameters adjusted when pacing rate
     // > target_rate and loss has been detected.
     if (pacing_rate_ > target_rate &&
-        bytes_lost_with_network_parameters_adjusted_ > 0) {
+        bytes_lost_while_detecting_overshooting_ > 0) {
       if (has_non_app_limited_sample_ ||
-          bytes_lost_with_network_parameters_adjusted_ *
-                  bytes_lost_multiplier_with_network_parameters_adjusted_ >
+          bytes_lost_while_detecting_overshooting_ *
+                  bytes_lost_multiplier_while_detecting_overshooting_ >
               initial_congestion_window_) {
         // We are fairly sure overshoot happens if 1) there is at least one
         // non app-limited bw sample or 2) half of IW gets lost. Slow pacing
         // rate.
-        // Do not let the pacing rate drop below the connection's initial pacing
-        // rate.
-        pacing_rate_ =
-            std::max(target_rate, QuicBandwidth::FromBytesAndTimeDelta(
-                                      initial_congestion_window_, GetMinRtt()));
+        pacing_rate_ = std::max(
+            target_rate, QuicBandwidth::FromBytesAndTimeDelta(
+                             cwnd_to_calculate_min_pacing_rate_, GetMinRtt()));
         if (stats_) {
           stats_->overshooting_detected_with_network_parameters_adjusted = true;
         }
-        bytes_lost_with_network_parameters_adjusted_ = 0;
-        network_parameters_adjusted_ = false;
+        bytes_lost_while_detecting_overshooting_ = 0;
+        detect_overshooting_ = false;
       }
     }
   }
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h
index 446f0dd..d89e3fe 100644
--- a/quic/core/congestion_control/bbr_sender.h
+++ b/quic/core/congestion_control/bbr_sender.h
@@ -384,15 +384,17 @@
   // or it's time for high gain mode.
   bool drain_to_target_;
 
-  // True if network parameters are adjusted, and this will be reset if
-  // overshooting is detected and pacing rate gets slowed.
-  bool network_parameters_adjusted_;
-  // Bytes lost after network parameters gets adjusted.
-  QuicByteCount bytes_lost_with_network_parameters_adjusted_;
-  // Decrease pacing rate after parameters adjusted if
-  // bytes_lost_with_network_parameters_adjusted_ *
-  // bytes_lost_multiplier_with_network_parameters_adjusted_ > IW.
-  uint8_t bytes_lost_multiplier_with_network_parameters_adjusted_;
+  // If true, slow down pacing rate in STARTUP when overshooting is detected.
+  bool detect_overshooting_;
+  // Bytes lost while detect_overshooting_ is true.
+  QuicByteCount bytes_lost_while_detecting_overshooting_;
+  // Slow down pacing rate if
+  // bytes_lost_while_detecting_overshooting_ *
+  // bytes_lost_multiplier_while_detecting_overshooting_ > IW.
+  uint8_t bytes_lost_multiplier_while_detecting_overshooting_;
+  // When overshooting is detected, do not drop pacing_rate_ below this value /
+  // min_rtt.
+  QuicByteCount cwnd_to_calculate_min_pacing_rate_;
 
   // Max congestion window when adjusting network parameters.
   QuicByteCount max_congestion_window_with_network_parameters_adjusted_;
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc
index 000216b..0e94b6b 100644
--- a/quic/core/congestion_control/bbr_sender_test.cc
+++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -1298,5 +1298,21 @@
   EXPECT_EQ(prior_bandwidth_estimate, sender_->BandwidthEstimate());
 }
 
+TEST_F(BbrSenderTest, EnableOvershootingDetection) {
+  if (!GetQuicReloadableFlag(quic_enable_overshooting_detection)) {
+    return;
+  }
+  SetConnectionOption(kDTOS);
+  CreateSmallBufferSetup();
+  // Set a overly large initial cwnd.
+  sender_->SetInitialCongestionWindowInPackets(200);
+  const QuicConnectionStats& stats = bbr_sender_.connection()->GetStats();
+  EXPECT_FALSE(stats.overshooting_detected_with_network_parameters_adjusted);
+  DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(30));
+
+  // Verify overshooting is detected.
+  EXPECT_TRUE(stats.overshooting_detected_with_network_parameters_adjusted);
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index f6bebf9..ca972c1 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -292,6 +292,8 @@
                                                 // resumption * 4 > IW.
 const QuicTag kICW1 = TAG('I', 'C', 'W', '1');  // Max initial congestion window
                                                 // 100.
+const QuicTag kDTOS = TAG('D', 'T', 'O', 'S');  // Enable overshooting
+                                                // detection.
 
 // Enable path MTU discovery experiment.
 const QuicTag kMTUH = TAG('M', 'T', 'U', 'H');  // High-target MTU discovery.