[quic]Add client connection option MPQM to control the migration when multi-port is enabled. PiperOrigin-RevId: 561995255
diff --git a/quiche/quic/core/crypto/crypto_protocol.h b/quiche/quic/core/crypto/crypto_protocol.h index 2725912..157e2d3 100644 --- a/quiche/quic/core/crypto/crypto_protocol.h +++ b/quiche/quic/core/crypto/crypto_protocol.h
@@ -431,6 +431,8 @@ // INVALID_VERSION const QuicTag kMPQC = TAG('M', 'P', 'Q', 'C'); // Multi-port QUIC connection +const QuicTag kMPQM = TAG('M', 'P', 'Q', 'M'); // Enable multi-port QUIC + // migration // Client Hints triggers. const QuicTag kGWCH = TAG('G', 'W', 'C', 'H');
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc index 58090a8..8cfa2c6 100644 --- a/quiche/quic/core/http/end_to_end_test.cc +++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -5368,7 +5368,7 @@ } TEST_P(EndToEndTest, ClientMultiPortConnection) { - client_config_.SetClientConnectionOptions(QuicTagVector{kMPQC}); + client_config_.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM}); ASSERT_TRUE(Initialize()); if (!version_.HasIetfQuicFrames()) { return; @@ -5414,7 +5414,7 @@ } TEST_P(EndToEndTest, ClientMultiPortMigrationOnPathDegrading) { - client_config_.SetClientConnectionOptions(QuicTagVector{kMPQC}); + client_config_.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM}); ASSERT_TRUE(Initialize()); if (!version_.HasIetfQuicFrames()) { return;
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index 693da98..3a991d8 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -693,6 +693,9 @@ if (perspective_ == Perspective::IS_CLIENT && version().HasIetfQuicFrames() && config.HasClientRequestedIndependentOption(kMPQC, perspective_)) { multi_port_stats_ = std::make_unique<MultiPortStats>(); + if (config.HasClientRequestedIndependentOption(kMPQM, perspective_)) { + multi_port_migration_enabled_ = true; + } } } @@ -6232,7 +6235,7 @@ is_path_degrading_ = true; visitor_->OnPathDegrading(); stats_.num_path_degrading++; - if (multi_port_stats_) { + if (multi_port_stats_ && multi_port_migration_enabled_) { MaybeMigrateToMultiPortPath(); } }
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h index 053017e..60dab8c 100644 --- a/quiche/quic/core/quic_connection.h +++ b/quiche/quic/core/quic_connection.h
@@ -2362,6 +2362,9 @@ std::unique_ptr<MultiPortStats> multi_port_stats_; + // If true, connection will migrate to multi-port path upon path degrading. + bool multi_port_migration_enabled_ = false; + // Client side only. bool active_migration_disabled_ = false;
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index 0e213fd..7ef137d 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc
@@ -13182,12 +13182,22 @@ EXPECT_EQ(kTestRTT, stats->rtt_stats_when_default_path_degrading.latest_rtt()); + EXPECT_CALL(visitor_, OnForwardProgressMadeAfterPathDegrading()); + QuicConnectionPeer::OnForwardProgressMade(&connection_); + EXPECT_TRUE(connection_.GetMultiPortProbingAlarm()->IsSet()); // Since there's already a scheduled probing alarm, manual calls won't have // any effect. connection_.MaybeProbeMultiPortPath(); EXPECT_FALSE(connection_.HasPendingPathValidation()); + // Since kMPQM is not set, migration shouldn't happen + EXPECT_CALL(visitor_, OnPathDegrading()); + EXPECT_CALL(visitor_, MigrateToMultiPortPath(_)).Times(0); + connection_.OnPathDegradingDetected(); + EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath( + &connection_, kNewSelfAddress, connection_.peer_address())); + // Simulate the case where the path validation fails after retries. connection_.GetMultiPortProbingAlarm()->Fire(); EXPECT_TRUE(connection_.HasPendingPathValidation()); @@ -13204,7 +13214,7 @@ EXPECT_FALSE(connection_.HasPendingPathValidation()); EXPECT_FALSE(QuicConnectionPeer::IsAlternativePath( &connection_, kNewSelfAddress, connection_.peer_address())); - EXPECT_EQ(1, connection_.GetStats().num_path_degrading); + EXPECT_EQ(2, connection_.GetStats().num_path_degrading); EXPECT_EQ(1, stats->num_multi_port_probe_failures_when_path_degrading); EXPECT_EQ(0, stats->num_multi_port_probe_failures_when_path_not_degrading); } @@ -13488,7 +13498,7 @@ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); set_perspective(Perspective::IS_CLIENT); QuicConfig config; - config.SetClientConnectionOptions(QuicTagVector{kMPQC}); + config.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM}); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); if (!version().HasIetfQuicFrames()) { @@ -13566,7 +13576,7 @@ .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); set_perspective(Perspective::IS_CLIENT); QuicConfig config; - config.SetClientConnectionOptions(QuicTagVector{kMPQC}); + config.SetClientConnectionOptions(QuicTagVector{kMPQC, kMPQM}); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); if (!version().HasIetfQuicFrames()) {
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc index 8ac35d5..9dcb6a5 100644 --- a/quiche/quic/test_tools/quic_connection_peer.cc +++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -606,5 +606,10 @@ connection->disable_ecn_codepoint_validation_ = true; } +// static +void QuicConnectionPeer::OnForwardProgressMade(QuicConnection* connection) { + connection->OnForwardProgressMade(); +} + } // namespace test } // namespace quic
diff --git a/quiche/quic/test_tools/quic_connection_peer.h b/quiche/quic/test_tools/quic_connection_peer.h index 3c8e068..21e31ba 100644 --- a/quiche/quic/test_tools/quic_connection_peer.h +++ b/quiche/quic/test_tools/quic_connection_peer.h
@@ -238,6 +238,8 @@ // Overrides restrictions on sending ECN for test purposes. static void DisableEcnCodepointValidation(QuicConnection* connection); + + static void OnForwardProgressMade(QuicConnection* connection); }; } // namespace test