gfe-relnote: In QUIC, add a connection option to use 2 * rttvar when calculating PTO timeout. Protected by existing gfe2_reloadable_flag_quic_enable_pto. PiperOrigin-RevId: 278451908 Change-Id: I5f68cad58734bd52e70efce51eefd84646050cac
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index f09c595..9707fb5 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -207,6 +207,8 @@ // since 1st PTO. const QuicTag kPEB2 = TAG('P', 'E', 'B', '2'); // Start exponential backoff // since 2nd PTO. +const QuicTag kPVS1 = TAG('P', 'V', 'S', '1'); // Use 2 * rttvar when + // calculating PTO timeout. // Optional support of truncated Connection IDs. If sent by a peer, the value // is the minimum number of bytes allowed for the connection ID sent to the
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 06f1ebb..443ecbc 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -444,11 +444,11 @@ } if (config.HasClientSentConnectionOption(k7PTO, perspective_)) { max_consecutive_ptos_ = 6; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 3, 8); } if (config.HasClientSentConnectionOption(k8PTO, perspective_)) { max_consecutive_ptos_ = 7; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 4, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 4, 8); } } if (config.HasClientSentConnectionOption(kNSTP, perspective_)) {
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index f9ec1c0..deec82f 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -105,6 +105,7 @@ skip_packet_number_for_pto_(false), always_include_max_ack_delay_for_pto_timeout_(true), pto_exponential_backoff_start_point_(0), + pto_rttvar_multiplier_(4), neuter_handshake_packets_once_( GetQuicReloadableFlag(quic_neuter_handshake_packets_once)) { SetSendAlgorithm(congestion_control_type); @@ -151,12 +152,12 @@ if (GetQuicReloadableFlag(quic_enable_pto)) { if (config.HasClientSentConnectionOption(k2PTO, perspective)) { pto_enabled_ = true; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 2, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 2, 8); } if (config.HasClientSentConnectionOption(k1PTO, perspective)) { pto_enabled_ = true; max_probe_packets_per_pto_ = 1; - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 1, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 1, 8); } } @@ -174,17 +175,21 @@ if (pto_enabled_) { if (config.HasClientSentConnectionOption(kPTOA, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 5, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 5, 8); always_include_max_ack_delay_for_pto_timeout_ = false; } if (config.HasClientSentConnectionOption(kPEB1, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 6, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 6, 8); StartExponentialBackoffAfterNthPto(1); } if (config.HasClientSentConnectionOption(kPEB2, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 7, 7); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 7, 8); StartExponentialBackoffAfterNthPto(2); } + if (config.HasClientSentConnectionOption(kPVS1, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_pto, 8, 8); + pto_rttvar_multiplier_ = 2; + } } // Configure congestion control. @@ -1045,7 +1050,7 @@ } const QuicTime::Delta pto_delay = rtt_stats_.smoothed_rtt() + - std::max(4 * rtt_stats_.mean_deviation(), + std::max(pto_rttvar_multiplier_ * rtt_stats_.mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + (ShouldAddMaxAckDelay() ? peer_max_ack_delay_ : QuicTime::Delta::Zero()); return pto_delay * (1 << (consecutive_pto_count_ -
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h index 5d362f4..2c3cf99 100644 --- a/quic/core/quic_sent_packet_manager.h +++ b/quic/core/quic_sent_packet_manager.h
@@ -641,6 +641,9 @@ // since nth PTO. size_t pto_exponential_backoff_start_point_; + // The multiplier of rttvar when calculating PTO timeout. + int pto_rttvar_multiplier_; + // Latched value of quic_neuter_handshake_packets_once. const bool neuter_handshake_packets_once_; };
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index b7ca395..539ce97 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -3026,6 +3026,35 @@ manager_.GetRetransmissionTime()); } +TEST_F(QuicSentPacketManagerTest, PtoTimeoutRttVarMultiple) { + EnablePto(k1PTO); + // Use 2 * rttvar + QuicConfig config; + QuicTagVector options; + options.push_back(kPVS1); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + EXPECT_CALL(*send_algorithm_, PacingRate(_)) + .WillRepeatedly(Return(QuicBandwidth::Zero())); + EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) + .WillRepeatedly(Return(10 * kDefaultTCPMSS)); + RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); + + SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); + // Verify PTO is correctly set based on 2 times rtt var. + QuicTime::Delta expected_pto_delay = + srtt + 2 * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + EXPECT_EQ(clock_.Now() + expected_pto_delay, + manager_.GetRetransmissionTime()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_time.h b/quic/core/quic_time.h index 9a5ae7d..d4429e3 100644 --- a/quic/core/quic_time.h +++ b/quic/core/quic_time.h
@@ -210,6 +210,9 @@ inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) { return !(lhs < rhs); } +inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs) { + return QuicTime::Delta(lhs.time_offset_ << rhs); +} inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) { return QuicTime::Delta(lhs.time_offset_ >> rhs); }