Add kAFF2 enabling the sending of AckFrequencyFrame upon handshake completion.
Protected by FLAGS_quic_reloadable_flag_quic_can_send_ack_frequency.
PiperOrigin-RevId: 337855733
Change-Id: I45e3c11605e37c01e217a7a86237f35cdfb806c9
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 57c9989..b5ed5c7 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -167,6 +167,8 @@
// AckFrequencyFrame.
const QuicTag kAFF1 = TAG('A', 'F', 'F', '1'); // Use SRTT in building
// AckFrequencyFrame.
+const QuicTag kAFF2 = TAG('A', 'F', 'F', '2'); // Send AckFrequencyFrame upon
+ // handshake completion.
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
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index c3fa8fb..e9fd55e 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -592,6 +592,10 @@
}
sent_packet_manager_.SetFromConfig(config);
+ if (perspective_ == Perspective::IS_SERVER &&
+ config.HasClientSentConnectionOption(kAFF2, perspective_)) {
+ send_ack_frequency_on_handshake_completion_ = true;
+ }
if (config.HasReceivedBytesForConnectionId() &&
can_truncate_connection_ids_) {
packet_creator_.SetServerConnectionIdLength(
@@ -2636,6 +2640,7 @@
if (!ack_frequency_sent_ && sent_packet_manager_.CanSendAckFrequency()) {
if (packet_creator_.NextSendingPacketNumber() >=
FirstSendingPacketNumber() + kMinReceivedBeforeAckDecimation) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 3, 3);
ack_frequency_sent_ = true;
auto frame = sent_packet_manager_.GetUpdatedAckFrequencyFrame();
visitor_->SendAckFrequency(frame);
@@ -3402,6 +3407,20 @@
void QuicConnection::OnHandshakeComplete() {
sent_packet_manager_.SetHandshakeConfirmed();
+ if (send_ack_frequency_on_handshake_completion_ &&
+ sent_packet_manager_.CanSendAckFrequency()) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 2, 3);
+ auto ack_frequency_frame =
+ sent_packet_manager_.GetUpdatedAckFrequencyFrame();
+ // This AckFrequencyFrame is meant to only update the max_ack_delay. Set
+ // packet tolerance to the default value for now.
+ ack_frequency_frame.packet_tolerance =
+ kDefaultRetransmittablePacketsBeforeAck;
+ visitor_->SendAckFrequency(ack_frequency_frame);
+ if (!connected_) {
+ return;
+ }
+ }
// This may have changed the retransmission timer, so re-arm it.
SetRetransmissionAlarm();
if (default_enable_5rto_blackhole_detection_) {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index a009954..2932584 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -1891,6 +1891,11 @@
// Indicate whether any ENCRYPTION_HANDSHAKE packet has been sent.
bool handshake_packet_sent_ = false;
+ // Indicate whether to send an AckFrequencyFrame upon handshake completion.
+ // The AckFrequencyFrame sent will updates client's max_ack_delay, which if
+ // chosen properly can reduce the CPU and bandwidth usage for ACK frames.
+ bool send_ack_frequency_on_handshake_completion_ = false;
+
// Indicate whether AckFrequency frame has been sent.
bool ack_frequency_sent_ = false;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 738bc2e..42d19e2 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -12493,6 +12493,41 @@
SendStreamDataToPeer(/*id=*/1, "baz", /*offset=*/6, NO_FIN, nullptr);
}
+TEST_P(QuicConnectionTest, SendAckFrequencyFrameUponHandshakeCompletion) {
+ if (!version().HasIetfQuicFrames()) {
+ return;
+ }
+ SetQuicReloadableFlag(quic_can_send_ack_frequency, true);
+ set_perspective(Perspective::IS_SERVER);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMinAckDelayMs(&config, /*min_ack_delay_ms=*/1);
+ QuicTagVector quic_tag_vector;
+ // Enable sending AckFrequency upon handshake completion.
+ quic_tag_vector.push_back(kAFF2);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, quic_tag_vector);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+
+ QuicAckFrequencyFrame captured_frame;
+ EXPECT_CALL(visitor_, SendAckFrequency(_))
+ .WillOnce(Invoke([&captured_frame](const QuicAckFrequencyFrame& frame) {
+ captured_frame = frame;
+ }));
+
+ connection_.OnHandshakeComplete();
+
+ EXPECT_EQ(captured_frame.packet_tolerance, 2u);
+ EXPECT_EQ(captured_frame.max_ack_delay,
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index a1126c0..01ec240 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -120,7 +120,7 @@
// Default minimum delayed ack time, in ms (used only for sender control of ack
// frequency).
-const uint32_t kDefaultMinAckDelayTimeMs = 1;
+const uint32_t kDefaultMinAckDelayTimeMs = 5;
// Default shift of the ACK delay in the IETF QUIC ACK frame.
const uint32_t kDefaultAckDelayExponent = 3;
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index bdad0e4..01e2840 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -726,13 +726,17 @@
return frame;
}
- QUIC_RELOADABLE_FLAG_COUNT(quic_can_send_ack_frequency);
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 1, 3);
frame.packet_tolerance = kMaxRetransmittablePacketsBeforeAck;
auto rtt = use_smoothed_rtt_in_ack_delay_ ? rtt_stats_.SmoothedOrInitialRtt()
: rtt_stats_.MinOrInitialRtt();
frame.max_ack_delay = rtt * kAckDecimationDelay;
frame.max_ack_delay = std::max(frame.max_ack_delay, peer_min_ack_delay_);
-
+ // TODO(haoyuewang) Remove this once kDefaultMinAckDelayTimeMs is updated to
+ // 5 ms on the client side.
+ frame.max_ack_delay =
+ std::max(frame.max_ack_delay,
+ QuicTime::Delta::FromMilliseconds(kDefaultMinAckDelayTimeMs));
return frame;
}
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 5504e8e..0ce3b43 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -4431,12 +4431,12 @@
// Set up RTTs.
auto* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(8),
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(80),
/*ack_delay=*/QuicTime::Delta::Zero(),
/*now=*/QuicTime::Zero());
// Make sure srtt and min_rtt are different.
rtt_stats->UpdateRtt(
- QuicTime::Delta::FromMilliseconds(16),
+ QuicTime::Delta::FromMilliseconds(160),
/*ack_delay=*/QuicTime::Delta::Zero(),
/*now=*/QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(24));
@@ -4461,12 +4461,12 @@
// Set up RTTs.
auto* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(8),
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(80),
/*ack_delay=*/QuicTime::Delta::Zero(),
/*now=*/QuicTime::Zero());
// Make sure srtt and min_rtt are different.
rtt_stats->UpdateRtt(
- QuicTime::Delta::FromMilliseconds(16),
+ QuicTime::Delta::FromMilliseconds(160),
/*ack_delay=*/QuicTime::Delta::Zero(),
/*now=*/QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(24));