Double the initial congestion window in QuicSentPacketManager
This new behavior is gated on the QuicTag IW2X and a new reloadable flag, quic_allow_client_enabled_2x_initial_cwnd.
Protected by FLAGS_quic_reloadable_flag_quic_allow_client_enabled_2x_initial_cwnd.
PiperOrigin-RevId: 773849231
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h
index 12ffbdd..1e52ff0 100755
--- a/quiche/common/quiche_feature_flags_list.h
+++ b/quiche/common/quiche_feature_flags_list.h
@@ -12,6 +12,7 @@
QUICHE_FLAG(bool, quiche_reloadable_flag_enable_tls_trust_anchor_ids, true, true, "When true, QUIC client and server will support TLS Trust Anchor IDs.")
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_act_upon_invalid_header, true, true, "If true, reject or send error response code upon receiving invalid request or response headers.")
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_add_stream_info_to_idle_close_detail, false, true, "If true, include stream information in idle timeout connection close detail.")
+QUICHE_FLAG(bool, quiche_reloadable_flag_quic_allow_client_enabled_2x_initial_cwnd, false, false, "Doubles the initial congestion window for QUIC connections when initiated by the client")
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_allow_client_enabled_bbr_v2, true, true, "If true, allow client to enable BBRv2 on server via connection option 'B2ON'.")
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_bbr2_extra_acked_window, false, true, "When true, the BBR4 copt sets the extra_acked window to 20 RTTs and BBR5 sets it to 40 RTTs.")
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_bbr2_probe_two_rounds, true, true, "When true, the BB2U copt causes BBR2 to wait two rounds with out draining the queue before exiting PROBE_UP and BB2S has the same effect in STARTUP.")
diff --git a/quiche/quic/core/crypto/crypto_protocol.h b/quiche/quic/core/crypto/crypto_protocol.h
index 244321f..9056c47 100644
--- a/quiche/quic/core/crypto/crypto_protocol.h
+++ b/quiche/quic/core/crypto/crypto_protocol.h
@@ -151,6 +151,7 @@
DEFINE_STATIC_QUIC_TAG(IW10); // Force ICWND to 10
DEFINE_STATIC_QUIC_TAG(IW20); // Force ICWND to 20
DEFINE_STATIC_QUIC_TAG(IW50); // Force ICWND to 50
+DEFINE_STATIC_QUIC_TAG(IW2X); // Force ICWND to 2x its default value.
DEFINE_STATIC_QUIC_TAG(B2ON); // Enable BBRv2
DEFINE_STATIC_QUIC_TAG(B2NA); // For BBRv2, do not add ack
// height to queueing threshold
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 7b4ae68..ec8d3a4 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -3890,6 +3890,30 @@
server_thread_->Resume();
}
+TEST_P(EndToEndTest, NegotiatedDoubledInitialCongestionWindow) {
+ SetQuicReloadableFlag(quic_allow_client_enabled_2x_initial_cwnd, true);
+ client_extra_copts_.push_back(kIW2X);
+
+ ASSERT_TRUE(Initialize());
+
+ // Values are exchanged during crypto handshake, so wait for that to finish.
+ EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+ server_thread_->WaitForCryptoHandshakeConfirmed();
+ server_thread_->Pause();
+ QuicConnection* server_connection = GetServerConnection();
+ ASSERT_NE(server_connection, nullptr);
+ EXPECT_EQ(
+ server_connection->sent_packet_manager().initial_congestion_window(),
+ kInitialCongestionWindow * 2);
+ server_thread_->Resume();
+
+ QuicConnection* client_connection = GetClientConnection();
+ ASSERT_NE(client_connection, nullptr);
+ EXPECT_EQ(
+ client_connection->sent_packet_manager().initial_congestion_window(),
+ kInitialCongestionWindow);
+}
+
TEST_P(EndToEndTest, DifferentFlowControlWindows) {
// Client and server can set different initial flow control receive windows.
// These are sent in CHLO/SHLO. Tests that these values are exchanged properly
diff --git a/quiche/quic/core/quic_sent_packet_manager.cc b/quiche/quic/core/quic_sent_packet_manager.cc
index ae905a5..2c60d23 100644
--- a/quiche/quic/core/quic_sent_packet_manager.cc
+++ b/quiche/quic/core/quic_sent_packet_manager.cc
@@ -187,6 +187,13 @@
initial_congestion_window_ = 50;
send_algorithm_->SetInitialCongestionWindowInPackets(50);
}
+ if (config.HasClientRequestedIndependentOption(kIW2X, perspective) &&
+ GetQuicReloadableFlag(quic_allow_client_enabled_2x_initial_cwnd)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_allow_client_enabled_2x_initial_cwnd);
+ initial_congestion_window_ *= 2;
+ send_algorithm_->SetInitialCongestionWindowInPackets(
+ initial_congestion_window_);
+ }
if (config.HasClientRequestedIndependentOption(kBWS5, perspective)) {
initial_congestion_window_ = 10;
send_algorithm_->SetInitialCongestionWindowInPackets(10);
diff --git a/quiche/quic/core/quic_sent_packet_manager_test.cc b/quiche/quic/core/quic_sent_packet_manager_test.cc
index 0427cfb..d7c051b 100644
--- a/quiche/quic/core/quic_sent_packet_manager_test.cc
+++ b/quiche/quic/core/quic_sent_packet_manager_test.cc
@@ -2121,6 +2121,51 @@
EXPECT_EQ(10u, manager_.initial_congestion_window());
}
+TEST_F(QuicSentPacketManagerTest, ServerCongestionWindowDoubledWithIW2X) {
+ SetQuicReloadableFlag(quic_allow_client_enabled_2x_initial_cwnd, true);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, {kIW2X});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetInitialCongestionWindowInPackets(
+ kInitialCongestionWindow * 2));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ EXPECT_EQ(manager_.initial_congestion_window(), kInitialCongestionWindow * 2);
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ ServerCongestionWindowIsDefaultWithIW2XAndNoFlag) {
+ SetQuicReloadableFlag(quic_allow_client_enabled_2x_initial_cwnd, false);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, {kIW2X});
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetInitialCongestionWindowInPackets(_))
+ .Times(0);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ EXPECT_EQ(manager_.initial_congestion_window(), kInitialCongestionWindow);
+}
+
+TEST_F(QuicSentPacketManagerTest,
+ ClientCongestionWindowIsDefaultWithIW2XAndNoFlag) {
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ SetQuicReloadableFlag(quic_allow_client_enabled_2x_initial_cwnd, false);
+ QuicConfig config;
+ config.SetConnectionOptionsToSend({kIW2X});
+ config.SetClientConnectionOptions({});
+
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_,
+ SetInitialCongestionWindowInPackets(kInitialCongestionWindow * 2))
+ .Times(0);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ EXPECT_EQ(manager_.initial_congestion_window(), kInitialCongestionWindow);
+}
+
TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) {
manager_.EnableMultiplePacketNumberSpacesSupport();
EXPECT_CALL(*send_algorithm_, PacingRate(_))