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)