In quic, adjust blackhole detection configs based on connection options. protected by existing gfe2_reloadable_flag_quic_default_enable_5rto_blackhole_detection. Connection options include 2RTO, 3RTO, 4RTO, 6RTO and client only blackhole detection. PiperOrigin-RevId: 315280821 Change-Id: I21a8f6fc101412a83794821a265c9e312a89b6d8
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index 36ea6ca..fc7d363 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -162,7 +162,13 @@ // 1 RTT of not receiving. const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction. const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR +const QuicTag k2RTO = TAG('2', 'R', 'T', 'O'); // Close connection on 2 RTOs +const QuicTag k3RTO = TAG('3', 'R', 'T', 'O'); // Close connection on 3 RTOs +const QuicTag k4RTO = TAG('4', 'R', 'T', 'O'); // Close connection on 4 RTOs const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs +const QuicTag k6RTO = TAG('6', 'R', 'T', 'O'); // Close connection on 6 RTOs +const QuicTag kCBHD = TAG('C', 'B', 'H', 'D'); // Client only blackhole + // detection. const QuicTag kCONH = TAG('C', 'O', 'N', 'H'); // Conservative Handshake // Retransmissions. const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 0724341..e332a89 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -568,6 +568,28 @@ if (config.HasClientRequestedIndependentOption(kMTUL, perspective_)) { SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow); } + if (default_enable_5rto_blackhole_detection_) { + if (config.HasClientRequestedIndependentOption(kCBHD, perspective_)) { + QUIC_CODE_COUNT(quic_client_only_blackhole_detection); + blackhole_detection_disabled_ = true; + } + if (config.HasClientSentConnectionOption(k2RTO, perspective_)) { + QUIC_CODE_COUNT(quic_2rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 2; + } + if (config.HasClientSentConnectionOption(k3RTO, perspective_)) { + QUIC_CODE_COUNT(quic_3rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 3; + } + if (config.HasClientSentConnectionOption(k4RTO, perspective_)) { + QUIC_CODE_COUNT(quic_4rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 4; + } + if (config.HasClientSentConnectionOption(k6RTO, perspective_)) { + QUIC_CODE_COUNT(quic_6rto_blackhole_detection); + num_rtos_for_blackhole_detection_ = 6; + } + } if (debug_visitor_ != nullptr) { debug_visitor_->OnSetFromConfig(config); @@ -4518,7 +4540,7 @@ } bool QuicConnection::ShouldDetectBlackhole() const { - if (!connected_) { + if (!connected_ || blackhole_detection_disabled_) { return false; } // No blackhole detection before handshake completes.
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 6bd0d38..5d149b4 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -1673,6 +1673,8 @@ QuicIdleNetworkDetector idle_network_detector_; + bool blackhole_detection_disabled_ = false; + const bool use_idle_network_detector_ = GetQuicReloadableFlag(quic_use_idle_network_detector);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index f6e463f..8d096eb 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -6117,6 +6117,10 @@ connection_options.push_back(k5RTO); config.SetConnectionOptionsToSend(connection_options); QuicConfigPeer::SetNegotiated(&config, true); + if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + } if (connection_.version().AuthenticatesHandshakeConnectionIds()) { QuicConfigPeer::SetReceivedOriginalConnectionId( &config, connection_.connection_id()); @@ -10957,6 +10961,161 @@ } } +TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionClient) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kCBHD); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole detection is in progress. + EXPECT_TRUE(connection_.GetBlackholeDetectorAlarm()->IsSet()); +} + +TEST_P(QuicConnectionTest, ClientOnlyBlackholeDetectionServer) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + set_perspective(Perspective::IS_SERVER); + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + if (version().SupportsAntiAmplificationLimit()) { + QuicConnectionPeer::SetAddressValidated(&connection_); + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kCBHD); + config.SetInitialReceivedConnectionOptions(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole detection is disabled. + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); +} + +TEST_P(QuicConnectionTest, 2RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k2RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(2), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 3RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k3RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(3), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 4RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k4RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(4), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + +TEST_P(QuicConnectionTest, 6RtoBlackholeDetection) { + if (!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection)) { + return; + } + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k6RTO); + config.SetConnectionOptionsToSend(connection_options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const size_t kMinRttMs = 40; + RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + EXPECT_FALSE(connection_.GetBlackholeDetectorAlarm()->IsSet()); + // Send stream data. + SendStreamDataToPeer( + GetNthClientInitiatedStreamId(1, connection_.transport_version()), "foo", + 0, FIN, nullptr); + // Verify blackhole delay is expected. + EXPECT_EQ(clock_.Now() + + connection_.sent_packet_manager().GetNetworkBlackholeDelay(6), + QuicConnectionPeer::GetBlackholeDetectionDeadline(&connection_)); +} + } // namespace } // namespace test } // namespace quic