Update CWND calculations to match the latest BBR draft. https://www.ietf.org/archive/id/draft-ietf-ccwg-bbr-05.html

Removes B205 from BBRv3, because it's default enabled. Change B2HR to set `inflight_hi_headroom` to 0.10 instead of 0.15, because 0.15 is the default.

PiperOrigin-RevId: 911969463
diff --git a/quiche/quic/core/congestion_control/bbr2_misc.h b/quiche/quic/core/congestion_control/bbr2_misc.h
index e9ee27b..9d78bee 100644
--- a/quiche/quic/core/congestion_control/bbr2_misc.h
+++ b/quiche/quic/core/congestion_control/bbr2_misc.h
@@ -112,6 +112,7 @@
 
   // If true, include extra acked during STARTUP and proactively reduce extra
   // acked when bandwidth increases.
+  // Always true in BBR3, so this value is ignored.
   bool startup_include_extra_acked = false;
 
 
diff --git a/quiche/quic/core/congestion_control/bbr3_sender.cc b/quiche/quic/core/congestion_control/bbr3_sender.cc
index 1f248f6..4fe8829 100644
--- a/quiche/quic/core/congestion_control/bbr3_sender.cc
+++ b/quiche/quic/core/congestion_control/bbr3_sender.cc
@@ -62,7 +62,6 @@
   // The BBR IETF draft uses 0.9 as the PROBE_DOWN pacing gain.
   params_.probe_bw_probe_down_pacing_gain = 0.9f;
   // STARTUP has a shorter MaxAckHeightTracker window of 1 round.
-  params_.startup_include_extra_acked = true;
   model_.SetMaxAckHeightTrackerWindowLength(1);
   // Use the derived startup pacing gain in the IETF draft.
   model_.set_pacing_gain(kDerivedStartupPacingGain);
@@ -94,7 +93,8 @@
     params_.startup_full_bw_rounds = 2;
   }
   if (ContainsQuicTag(connection_options, kB2HR)) {
-    params_.inflight_hi_headroom = 0.15;
+    // The default is 0.15.
+    params_.inflight_hi_headroom = 0.10;
   }
   if (ContainsQuicTag(connection_options, kICW1)) {
     max_cwnd_when_network_parameters_adjusted_ = 100 * kDefaultTCPMSS;
@@ -148,15 +148,15 @@
   if (ContainsQuicTag(connection_options, kB202)) {
     params_.max_probe_up_queue_rounds = 1;
   }
+  if (ContainsQuicTag(connection_options, kBB2U)) {
+    params_.max_probe_up_queue_rounds = 2;
+  }
   if (ContainsQuicTag(connection_options, kB203)) {
     params_.probe_up_ignore_inflight_hi = false;
   }
   if (ContainsQuicTag(connection_options, kB204)) {
     model_.SetReduceExtraAckedOnBandwidthIncrease(true);
   }
-  if (ContainsQuicTag(connection_options, kB205)) {
-    params_.startup_include_extra_acked = true;
-  }
   if (ContainsQuicTag(connection_options, kBBRA)) {
     model_.SetStartNewAggregationEpochAfterFullRound(true);
   }
@@ -175,9 +175,6 @@
     // so ensure we're not ignoring it.
     params_.probe_up_ignore_inflight_hi = false;
   }
-  if (ContainsQuicTag(connection_options, kBB2U)) {
-    params_.max_probe_up_queue_rounds = 2;
-  }
 }
 
 Limits<QuicByteCount> Bbr3Sender::GetCwndLimitsByMode() const {
@@ -425,24 +422,28 @@
 }
 
 void Bbr3Sender::UpdateCongestionWindow(QuicByteCount bytes_acked) {
-  QuicByteCount target_cwnd = GetTargetCongestionWindow(model_.cwnd_gain());
+  // From "Congestion Window" section of bbr3-draft.
+  QuicByteCount max_inflight =
+      model_.BDP(model_.BandwidthEstimate(), model_.cwnd_gain()) +
+      model_.MaxAckHeight();
+  max_inflight = ApplyQuantizationBudget(max_inflight);
 
   const QuicByteCount prior_cwnd = cwnd_;
-  if (model_.full_bandwidth_reached() || Params().startup_include_extra_acked) {
-    target_cwnd += model_.MaxAckHeight();
-    cwnd_ = std::min(prior_cwnd + bytes_acked, target_cwnd);
-  } else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * initial_cwnd_) {
-    cwnd_ = prior_cwnd + bytes_acked;
+  // Never increase CWND by more than bytes_acked.
+  if (model_.full_bandwidth_reached()) {
+    cwnd_ = std::min(cwnd_ + bytes_acked, max_inflight);
+  } else if (cwnd_ < max_inflight ||
+             model_.total_bytes_acked() < initial_cwnd_) {
+    // For the first flight of packets in STARTUP, increase CWND by bytes_acked.
+    cwnd_ = cwnd_ + bytes_acked;
   }
 
   const QuicByteCount desired_cwnd = cwnd_;
-
   cwnd_ = GetCwndLimitsByMode().ApplyLimits(cwnd_);
   const QuicByteCount model_limited_cwnd = cwnd_;
-
   cwnd_ = params_.cwnd_limits.ApplyLimits(cwnd_);
 
-  QUIC_DVLOG(3) << this << " Updating CWND. target_cwnd:" << target_cwnd
+  QUIC_DVLOG(3) << this << " Updating CWND. max_inflight:" << max_inflight
                 << ", max_ack_height:" << model_.MaxAckHeight()
                 << ", full_bw:" << model_.full_bandwidth_reached()
                 << ", bytes_acked:" << bytes_acked
@@ -453,9 +454,14 @@
                 << " => (final_cwnd) " << cwnd_;
 }
 
-QuicByteCount Bbr3Sender::GetTargetCongestionWindow(float gain) const {
-  return std::max(model_.BDP(model_.BandwidthEstimate(), gain),
-                  params_.cwnd_limits.Min());
+QuicByteCount Bbr3Sender::ApplyQuantizationBudget(
+    QuicByteCount inflight_cap) const {
+  // TODO(ianswett): Ensure inflight_cap is at least the offload budget.
+  inflight_cap = std::max(inflight_cap, kDefaultMinimumCongestionWindow);
+  if (mode_ == Bbr2Mode::PROBE_BW && probe_bw_.phase == ProbePhase::PROBE_UP) {
+    inflight_cap += 2 * kDefaultTCPMSS;
+  }
+  return inflight_cap;
 }
 
 void Bbr3Sender::OnPacketSent(QuicTime sent_time, QuicByteCount bytes_in_flight,
diff --git a/quiche/quic/core/congestion_control/bbr3_sender.h b/quiche/quic/core/congestion_control/bbr3_sender.h
index a3aea6a..ab4243d 100644
--- a/quiche/quic/core/congestion_control/bbr3_sender.h
+++ b/quiche/quic/core/congestion_control/bbr3_sender.h
@@ -119,7 +119,7 @@
  private:
   void UpdatePacingRate(QuicByteCount bytes_acked);
   void UpdateCongestionWindow(QuicByteCount bytes_acked);
-  QuicByteCount GetTargetCongestionWindow(float gain) const;
+  QuicByteCount ApplyQuantizationBudget(QuicByteCount inflight_cap) const;
   // Helper function for Bbr2Mode transitions.
   void LeaveStartup(QuicTime now);
   Bbr2Mode OnCongestionEventStartup(
diff --git a/quiche/quic/core/congestion_control/bbr3_simulator_test.cc b/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
index 9818b12..402dedf 100644
--- a/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
+++ b/quiche/quic/core/congestion_control/bbr3_simulator_test.cc
@@ -379,7 +379,7 @@
   ASSERT_TRUE(simulator_result);
   const auto debug_state = sender_->ExportDebugState();
   EXPECT_EQ(Bbr2Mode::DRAIN, debug_state.mode);
-  EXPECT_EQ(2u, debug_state.round_trip_count - max_bw_round);
+  EXPECT_EQ(3u, debug_state.round_trip_count - max_bw_round);
   EXPECT_EQ(3u, debug_state.startup.round_trips_without_bandwidth_growth);
   EXPECT_EQ(0u, sender_connection_stats().packets_lost);
   EXPECT_APPROX_EQ(params.BottleneckBandwidth(), debug_state.bandwidth_hi,
@@ -789,7 +789,7 @@
   // This is much farther off when aggregation is present,
   // Ideally BSAO or another option would fix this.
   EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_est, 0.6f);
+                   sender_->ExportDebugState().bandwidth_est, 0.8f);
   EXPECT_LE(sender_loss_rate_in_packets(), 0.35);
 
   // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
@@ -1056,76 +1056,6 @@
                    sender_->ExportDebugState().bandwidth_hi, 0.95f);
 }
 
-// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205
-TEST_F(Bbr3DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB205)) {
-  SetConnectionOption(kB205);
-  DefaultTopologyParams params;
-  params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
-  params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
-  CreateNetwork(params);
-
-  sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024);
-
-  simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
-  EXPECT_TRUE(Bbr3ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
-  QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
-
-  EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_est, 0.1f);
-  EXPECT_LE(sender_loss_rate_in_packets(), 0.10);
-
-  // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
-  params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
-  TestLink()->set_bandwidth(params.test_link.bandwidth);
-
-  bool simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
-      QuicTime::Delta::FromSeconds(50));
-  EXPECT_TRUE(simulator_result);
-  // Ensure the full bandwidth is discovered.
-  EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_hi, 0.1f);
-}
-
-// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205
-// in the presence of ACK aggregation.
-TEST_F(Bbr3DefaultTopologyTest,
-       QUIC_SLOW_TEST(BandwidthIncreaseB205Aggregation)) {
-  SetConnectionOption(kB205);
-  DefaultTopologyParams params;
-  params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000);
-  params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
-  CreateNetwork(params);
-
-  // 2 RTTs of aggregation, with a max of 10kb.
-  EnableAggregation(10 * 1024, 2 * params.RTT());
-
-  // Reduce the payload to 2MB because 10MB takes too long.
-  sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024);
-
-  simulator_.RunFor(QuicTime::Delta::FromSeconds(15));
-  EXPECT_TRUE(Bbr3ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
-  QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow();
-
-  // This is much farther off when aggregation is present,
-  // Ideally BSAO or another option would fix this.
-  EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_est, 0.45f);
-  EXPECT_LE(sender_loss_rate_in_packets(), 0.15);
-
-  // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
-  params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000);
-  TestLink()->set_bandwidth(params.test_link.bandwidth);
-
-  bool simulator_result = simulator_.RunUntilOrTimeout(
-      [this]() { return sender_endpoint_.bytes_to_transfer() == 0; },
-      QuicTime::Delta::FromSeconds(50));
-  EXPECT_TRUE(simulator_result);
-  // Ensure at least 5% of full bandwidth is discovered.
-  EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_hi, 0.9f);
-}
-
 // Test Bbr2's reaction to a 100x bandwidth increase during a transfer with BB2U
 TEST_F(Bbr3DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseBB2U)) {
   SetConnectionOption(kBB2U);
@@ -1180,7 +1110,7 @@
   // This is much farther off when aggregation is present,
   // Ideally BSAO or another option would fix this.
   EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_est, 0.45f);
+                   sender_->ExportDebugState().bandwidth_est, 0.8f);
   EXPECT_LE(sender_loss_rate_in_packets(), 0.30);
 
   // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
@@ -1220,7 +1150,7 @@
   // This is much farther off when aggregation is present,
   // Ideally BSAO or another option would fix this.
   EXPECT_APPROX_EQ(params.test_link.bandwidth,
-                   sender_->ExportDebugState().bandwidth_est, 0.45f);
+                   sender_->ExportDebugState().bandwidth_est, 0.80f);
   EXPECT_LE(sender_loss_rate_in_packets(), 0.30);
 
   // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps.
@@ -1540,7 +1470,7 @@
   const auto debug_state = sender_->ExportDebugState();
   EXPECT_EQ(Bbr2Mode::DRAIN, debug_state.mode);
   EXPECT_GE(2u, debug_state.round_trip_count - max_bw_round);
-  EXPECT_EQ(2u, debug_state.startup.round_trips_without_bandwidth_growth);
+  EXPECT_EQ(1u, debug_state.startup.round_trips_without_bandwidth_growth);
   EXPECT_NE(0u, sender_connection_stats().packets_lost);
   EXPECT_FALSE(debug_state.last_sample_is_app_limited);
 
@@ -1573,7 +1503,7 @@
   const auto debug_state = sender_->ExportDebugState();
   EXPECT_EQ(Bbr2Mode::DRAIN, debug_state.mode);
   EXPECT_GE(2u, debug_state.round_trip_count - max_bw_round);
-  EXPECT_EQ(2u, debug_state.startup.round_trips_without_bandwidth_growth);
+  EXPECT_EQ(1u, debug_state.startup.round_trips_without_bandwidth_growth);
   EXPECT_NE(0u, sender_connection_stats().packets_lost);
   EXPECT_FALSE(debug_state.last_sample_is_app_limited);