Revert the meaning of QUIC connection option 'B2NE':
- Without the option, exit STARTUP on loss only if bandwidth is below threshold.
- With the option, always exit STARTUP on loss, even if bandwidth exceeds threshold.
PiperOrigin-RevId: 370097972
Change-Id: Ie789842e7e389328046828fc07fd603fbb7e5700
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h
index 8f5d418..14a0882 100644
--- a/quic/core/congestion_control/bbr2_misc.h
+++ b/quic/core/congestion_control/bbr2_misc.h
@@ -92,7 +92,7 @@
// If true, always exit STARTUP on loss, even if bandwidth exceeds threshold.
// If false, exit STARTUP on loss only if bandwidth is below threshold.
- bool always_exit_startup_on_excess_loss = true;
+ bool always_exit_startup_on_excess_loss = false;
/*
* DRAIN parameters.
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc
index d0f6127..b69a795 100644
--- a/quic/core/congestion_control/bbr2_sender.cc
+++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -132,7 +132,7 @@
params_.ignore_inflight_lo = true;
}
if (ContainsQuicTag(connection_options, kB2NE)) {
- params_.always_exit_startup_on_excess_loss = false;
+ params_.always_exit_startup_on_excess_loss = true;
}
if (ContainsQuicTag(connection_options, kB2SL)) {
params_.startup_loss_exit_use_max_delivered_for_inflight_hi = false;
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc
index e26760e..99acf2c 100644
--- a/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -417,25 +417,6 @@
EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->smoothed_rtt(), 1.0f);
}
-TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2NE) {
- SetConnectionOption(kB2NE);
- DefaultTopologyParams params;
- CreateNetwork(params);
-
- // Transfer 12MB.
- DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
- EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT}));
-
- EXPECT_APPROX_EQ(params.BottleneckBandwidth(),
- sender_->ExportDebugState().bandwidth_hi, 0.01f);
-
- EXPECT_LE(sender_loss_rate_in_packets(), 0.05);
- // The margin here is high, because the aggregation greatly increases
- // smoothed rtt.
- EXPECT_GE(params.RTT() * 4, rtt_stats()->smoothed_rtt());
- EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
-}
-
TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2RC) {
SetConnectionOption(kB2RC);
DefaultTopologyParams params;
@@ -859,6 +840,42 @@
EXPECT_APPROX_EQ(sender_->ExportDebugState().inflight_hi, params.BDP(), 0.1f);
}
+// Verifies that in STARTUP, if we exceed loss threshold in a round, we exit
+// STARTUP at the end of the round even if there's enough bandwidth growth.
+TEST_F(Bbr2DefaultTopologyTest, ExitStartupDueToLossB2NE) {
+ // Set up flags such that any loss will be considered "too high".
+ SetQuicFlag(FLAGS_quic_bbr2_default_startup_full_loss_count, 0);
+ SetQuicFlag(FLAGS_quic_bbr2_default_loss_threshold, 0.0);
+
+ sender_ = SetupBbr2Sender(&sender_endpoint_, /*old_sender=*/nullptr);
+
+ SetConnectionOption(kB2NE);
+ DefaultTopologyParams params;
+ params.switch_queue_capacity_in_bdp = 0.5;
+ CreateNetwork(params);
+
+ // Run until the full bandwidth is reached and check how many rounds it was.
+ sender_endpoint_.AddBytesToTransfer(12 * 1024 * 1024);
+ QuicRoundTripCount max_bw_round = 0;
+ QuicBandwidth max_bw(QuicBandwidth::Zero());
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this, &max_bw, &max_bw_round]() {
+ if (max_bw < sender_->ExportDebugState().bandwidth_hi) {
+ max_bw = sender_->ExportDebugState().bandwidth_hi;
+ max_bw_round = sender_->ExportDebugState().round_trip_count;
+ }
+ return sender_->ExportDebugState().startup.full_bandwidth_reached;
+ },
+ QuicTime::Delta::FromSeconds(5));
+ ASSERT_TRUE(simulator_result);
+ EXPECT_EQ(Bbr2Mode::DRAIN, sender_->ExportDebugState().mode);
+ EXPECT_EQ(sender_->ExportDebugState().round_trip_count, max_bw_round);
+ EXPECT_EQ(
+ 0u,
+ sender_->ExportDebugState().startup.round_trips_without_bandwidth_growth);
+ EXPECT_NE(0u, sender_connection_stats().packets_lost);
+}
+
TEST_F(Bbr2DefaultTopologyTest, SenderPoliced) {
DefaultTopologyParams params;
params.sender_policer_params = TrafficPolicerParams();
diff --git a/quic/core/congestion_control/bbr2_startup.cc b/quic/core/congestion_control/bbr2_startup.cc
index 5a9a532..1bd89c6 100644
--- a/quic/core/congestion_control/bbr2_startup.cc
+++ b/quic/core/congestion_control/bbr2_startup.cc
@@ -112,8 +112,9 @@
new_inflight_hi = model_->max_bytes_delivered_in_round();
}
}
- QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss. inflight_hi:"
- << new_inflight_hi;
+ QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss at round "
+ << model_->RoundTripCount()
+ << ". inflight_hi:" << new_inflight_hi;
// TODO(ianswett): Add a shared method to set inflight_hi in the model.
model_->set_inflight_hi(new_inflight_hi);
model_->set_full_bandwidth_reached();
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index e08d90b..8a86255 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -127,9 +127,10 @@
const QuicTag kB2ON = TAG('B', '2', 'O', 'N'); // Enable BBRv2
const QuicTag kB2NA = TAG('B', '2', 'N', 'A'); // For BBRv2, do not add ack
// height to queueing threshold
-const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, do not exit
- // STARTUP if there's enough
- // bandwidth growth
+const QuicTag kB2NE = TAG('B', '2', 'N', 'E'); // For BBRv2, always exit
+ // STARTUP on loss, even if
+ // bandwidth growth exceeds
+ // threshold.
const QuicTag kB2RP = TAG('B', '2', 'R', 'P'); // For BBRv2, run PROBE_RTT on
// the regular schedule
const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW