Add QUIC connection option B2RC to disable reno coexistence for BBR2.
Protected by FLAGS_quic_reloadable_flag_quic_bbr2_disable_reno_coexistence.
PiperOrigin-RevId: 345675835
Change-Id: I976a81192b6abdc4b16463d970e43863a9f745ea
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h
index 2134bd6..f81d3cd 100644
--- a/quic/core/congestion_control/bbr2_misc.h
+++ b/quic/core/congestion_control/bbr2_misc.h
@@ -192,6 +192,9 @@
// Can be enabled by connection option 'B2DL'.
bool use_bytes_delivered_for_inflight_hi = false;
+
+ // Can be disabled by connection option 'B2RC'.
+ bool enable_reno_coexistence = true;
};
class QUIC_EXPORT_PRIVATE RoundTripCounter {
diff --git a/quic/core/congestion_control/bbr2_probe_bw.cc b/quic/core/congestion_control/bbr2_probe_bw.cc
index 1b01d9d..5f38005 100644
--- a/quic/core/congestion_control/bbr2_probe_bw.cc
+++ b/quic/core/congestion_control/bbr2_probe_bw.cc
@@ -325,6 +325,10 @@
bool Bbr2ProbeBwMode::IsTimeToProbeForRenoCoexistence(
double probe_wait_fraction,
const Bbr2CongestionEvent& /*congestion_event*/) const {
+ if (!Params().enable_reno_coexistence) {
+ return false;
+ }
+
uint64_t rounds = Params().probe_bw_probe_max_rounds;
if (Params().probe_bw_probe_reno_gain > 0.0) {
QuicByteCount target_bytes_inflight = sender_->GetTargetBytesInflight();
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc
index 2545fa4..5d672d1 100644
--- a/quic/core/congestion_control/bbr2_sender.cc
+++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -150,6 +150,11 @@
QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_use_bytes_delivered);
params_.use_bytes_delivered_for_inflight_hi = true;
}
+ if (GetQuicReloadableFlag(quic_bbr2_disable_reno_coexistence) &&
+ ContainsQuicTag(connection_options, kB2RC)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_disable_reno_coexistence);
+ params_.enable_reno_coexistence = false;
+ }
if (ContainsQuicTag(connection_options, kBSAO)) {
model_.EnableOverestimateAvoidance();
}
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc
index b7fef49..ec7eeeb 100644
--- a/quic/core/congestion_control/bbr2_simulator_test.cc
+++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -432,6 +432,25 @@
EXPECT_APPROX_EQ(params.RTT(), rtt_stats()->min_rtt(), 0.2f);
}
+TEST_F(Bbr2DefaultTopologyTest, SimpleTransferB2RC) {
+ SetConnectionOption(kB2RC);
+ 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, SimpleTransferSmallBuffer) {
DefaultTopologyParams params;
params.switch_queue_capacity_in_bdp = 0.5;
@@ -1245,7 +1264,7 @@
receiver_multiplexer_ =
std::make_unique<simulator::QuicEndpointMultiplexer>(
"Receiver multiplexer", receiver_endpoint_pointers);
- sender_1_ = SetupBbr2Sender(sender_endpoints_[0].get());
+ sender_0_ = SetupBbr2Sender(sender_endpoints_[0].get());
}
~Bbr2MultiSenderTest() {
@@ -1311,6 +1330,14 @@
return sender;
}
+ void SetConnectionOption(SendAlgorithmInterface* sender, QuicTag option) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(option);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender->SetFromConfig(config, Perspective::IS_SERVER);
+ }
+
void CreateNetwork(const MultiSenderTopologyParams& params) {
QUIC_LOG(INFO) << "CreateNetwork with parameters: " << params.ToString();
switch_ = std::make_unique<simulator::Switch>(&simulator_, "Switch",
@@ -1344,7 +1371,7 @@
std::vector<std::unique_ptr<simulator::QuicEndpoint>> sender_endpoints_;
std::vector<std::unique_ptr<simulator::QuicEndpoint>> receiver_endpoints_;
std::unique_ptr<simulator::QuicEndpointMultiplexer> receiver_multiplexer_;
- Bbr2Sender* sender_1_;
+ Bbr2Sender* sender_0_;
std::unique_ptr<simulator::Switch> switch_;
std::vector<std::unique_ptr<simulator::SymmetricLink>> network_links_;
@@ -1503,7 +1530,39 @@
MultiSenderTopologyParams params;
CreateNetwork(params);
- const QuicByteCount transfer_size = 50 * 1024 * 1024;
+ const QuicByteCount transfer_size = 10 * 1024 * 1024;
+ const QuicTime::Delta transfer_time =
+ params.BottleneckBandwidth().TransferTime(transfer_size);
+ QUIC_LOG(INFO) << "Single flow transfer time: " << transfer_time;
+
+ // Transfer 10% of data in first transfer.
+ sender_endpoints_[0]->AddBytesToTransfer(transfer_size);
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() {
+ return receiver_endpoints_[0]->bytes_received() >= 0.1 * transfer_size;
+ },
+ transfer_time);
+ ASSERT_TRUE(simulator_result);
+
+ // Start the second transfer and wait until both finish.
+ sender_endpoints_[1]->AddBytesToTransfer(transfer_size);
+ simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() {
+ return receiver_endpoints_[0]->bytes_received() == transfer_size &&
+ receiver_endpoints_[1]->bytes_received() == transfer_size;
+ },
+ 3 * transfer_time);
+ ASSERT_TRUE(simulator_result);
+}
+
+TEST_F(Bbr2MultiSenderTest, QUIC_SLOW_TEST(Bbr2VsRenoB2RC)) {
+ SetConnectionOption(sender_0_, kB2RC);
+ SetupTcpSender(sender_endpoints_[1].get(), /*reno=*/true);
+
+ MultiSenderTopologyParams params;
+ CreateNetwork(params);
+
+ const QuicByteCount transfer_size = 10 * 1024 * 1024;
const QuicTime::Delta transfer_time =
params.BottleneckBandwidth().TransferTime(transfer_size);
QUIC_LOG(INFO) << "Single flow transfer time: " << transfer_time;
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index ddd3dbd..9b09027 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -137,6 +137,8 @@
// loss, set inflight_hi to the
// max of inflight@send and max
// bytes delivered in round.
+const QuicTag kB2RC = TAG('B', '2', 'R', 'C'); // Disable Reno-coexistence for
+ // BBR2.
const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in
// Bandwidth Sampler with ack
// aggregation
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 0edd9db..0a3a97f 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -11,6 +11,7 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_avoid_too_low_probe_bw_cwnd, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_disable_reno_coexistence, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fewer_startup_round_trips, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_startup_loss_exit_use_max_delivered, true)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_use_bytes_delivered, false)