[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