In QUIC BBRv2, support NetworkParams.max_initial_congestion_window when bootstrapping cwnd.

This makes BBRv2 behave the same w.r.t NetworkParams.max_initial_congestion_window.

Protected by FLAGS_quic_reloadable_flag_quic_bbr2_support_max_bootstrap_cwnd.

PiperOrigin-RevId: 336959204
Change-Id: I888f067c6c0dcb3eaaa1b9191a83dd7ec16344c0
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc
index 6de304a..3185cc0 100644
--- a/quic/core/congestion_control/bbr2_sender.cc
+++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -135,6 +135,11 @@
     QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_use_tcp_inflight_hi_headroom);
     params_.inflight_hi_headroom = 0.15;
   }
+  if (GetQuicReloadableFlag(quic_bbr2_support_max_bootstrap_cwnd) &&
+      config.HasClientRequestedIndependentOption(kICW1, perspective)) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_support_max_bootstrap_cwnd, 1, 4);
+    max_cwnd_when_network_parameters_adjusted_ = 100 * kDefaultTCPMSS;
+  }
 
   ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
 }
@@ -184,7 +189,22 @@
 
     QuicBandwidth effective_bandwidth =
         std::max(params.bandwidth, model_.BandwidthEstimate());
-    cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth));
+    if (GetQuicReloadableFlag(quic_bbr2_support_max_bootstrap_cwnd)) {
+      if (params.max_initial_congestion_window > 0) {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_support_max_bootstrap_cwnd, 2,
+                                     4);
+        max_cwnd_when_network_parameters_adjusted_ =
+            params.max_initial_congestion_window * kDefaultTCPMSS;
+      } else {
+        QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_support_max_bootstrap_cwnd, 3,
+                                     4);
+      }
+      cwnd_ = cwnd_limits().ApplyLimits(
+          std::min(max_cwnd_when_network_parameters_adjusted_,
+                   model_.BDP(effective_bandwidth)));
+    } else {
+      cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth));
+    }
 
     if (!params.allow_cwnd_to_decrease) {
       cwnd_ = std::max(cwnd_, prior_cwnd);
diff --git a/quic/core/congestion_control/bbr2_sender.h b/quic/core/congestion_control/bbr2_sender.h
index 39964a0..1b328fe 100644
--- a/quic/core/congestion_control/bbr2_sender.h
+++ b/quic/core/congestion_control/bbr2_sender.h
@@ -183,6 +183,10 @@
   // Instead, use params() to get read-only access.
   Bbr2Params params_;
 
+  // Max congestion window when adjusting network parameters.
+  QuicByteCount max_cwnd_when_network_parameters_adjusted_ =
+      kMaxInitialCongestionWindow * kDefaultTCPMSS;
+
   Bbr2NetworkModel model_;
 
   const QuicByteCount initial_cwnd_;
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc
index 43a4fd7..4273667 100644
--- a/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -1025,6 +1025,87 @@
   DriveOutOfStartup(params);
 }
 
+TEST_F(Bbr2DefaultTopologyTest,
+       200InitialCongestionWindowWithNetworkParameterAdjusted) {
+  DefaultTopologyParams params;
+  CreateNetwork(params);
+
+  sender_endpoint_.AddBytesToTransfer(1 * 1024 * 1024);
+
+  // Wait until an ACK comes back.
+  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
+  bool simulator_result = simulator_.RunUntilOrTimeout(
+      [this]() { return !sender_->ExportDebugState().min_rtt.IsZero(); },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+
+  // Bootstrap cwnd by a overly large bandwidth sample.
+  sender_connection()->AdjustNetworkParameters(
+      SendAlgorithmInterface::NetworkParams(1024 * params.BottleneckBandwidth(),
+                                            QuicTime::Delta::Zero(), false));
+
+  if (GetQuicReloadableFlag(quic_bbr2_support_max_bootstrap_cwnd)) {
+    // Verify cwnd is capped at 200.
+    EXPECT_EQ(200 * kDefaultTCPMSS,
+              sender_->ExportDebugState().congestion_window);
+    EXPECT_GT(1024 * params.BottleneckBandwidth(), sender_->PacingRate(0));
+  }
+}
+
+TEST_F(Bbr2DefaultTopologyTest,
+       100InitialCongestionWindowFromNetworkParameter) {
+  DefaultTopologyParams params;
+  CreateNetwork(params);
+
+  sender_endpoint_.AddBytesToTransfer(1 * 1024 * 1024);
+  // Wait until an ACK comes back.
+  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
+  bool simulator_result = simulator_.RunUntilOrTimeout(
+      [this]() { return !sender_->ExportDebugState().min_rtt.IsZero(); },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+
+  // Bootstrap cwnd by a overly large bandwidth sample.
+  SendAlgorithmInterface::NetworkParams network_params(
+      1024 * params.BottleneckBandwidth(), QuicTime::Delta::Zero(), false);
+  network_params.max_initial_congestion_window = 100;
+  sender_connection()->AdjustNetworkParameters(network_params);
+
+  if (GetQuicReloadableFlag(quic_bbr2_support_max_bootstrap_cwnd)) {
+    // Verify cwnd is capped at 100.
+    EXPECT_EQ(100 * kDefaultTCPMSS,
+              sender_->ExportDebugState().congestion_window);
+    EXPECT_GT(1024 * params.BottleneckBandwidth(), sender_->PacingRate(0));
+  }
+}
+
+TEST_F(Bbr2DefaultTopologyTest,
+       100InitialCongestionWindowWithNetworkParameterAdjusted) {
+  SetConnectionOption(kICW1);
+  DefaultTopologyParams params;
+  CreateNetwork(params);
+
+  sender_endpoint_.AddBytesToTransfer(1 * 1024 * 1024);
+  // Wait until an ACK comes back.
+  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
+  bool simulator_result = simulator_.RunUntilOrTimeout(
+      [this]() { return !sender_->ExportDebugState().min_rtt.IsZero(); },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+
+  // Bootstrap cwnd by a overly large bandwidth sample.
+  sender_connection()->AdjustNetworkParameters(
+      SendAlgorithmInterface::NetworkParams(1024 * params.BottleneckBandwidth(),
+                                            QuicTime::Delta::Zero(), false));
+
+  if (GetQuicReloadableFlag(quic_bbr2_support_max_bootstrap_cwnd)) {
+    // Verify cwnd is capped at 100.
+    EXPECT_EQ(100 * kDefaultTCPMSS,
+              sender_->ExportDebugState().congestion_window);
+    EXPECT_GT(1024 * params.BottleneckBandwidth(), sender_->PacingRate(0));
+  }
+}
+
 // All Bbr2MultiSenderTests uses the following network topology:
 //
 //   Sender 0  (A Bbr2Sender)