Internal QUICHE change
PiperOrigin-RevId: 337213860
Change-Id: I01f6717bf203f64bf23b5af7d7f2905162514db8
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index de9d9d3..ab0ef01 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -163,7 +163,8 @@
// received before acking
const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after
// 1 RTT of not receiving.
-const QuicTag kAFFE = TAG('A', 'F', 'F', 'E'); // AckFrequencyFrame Enabled.
+const QuicTag kAFFE = TAG('A', 'F', 'F', 'E'); // Enable client receiving
+ // AckFrequencyFrame.
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 f3b0eda..52992d0 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2631,6 +2631,15 @@
}
const QuicFrames QuicConnection::MaybeBundleAckOpportunistically() {
+ if (!ack_frequency_sent_ && sent_packet_manager_.CanSendAckFrequency()) {
+ if (packet_creator_.NextSendingPacketNumber() >=
+ FirstSendingPacketNumber() + kMinReceivedBeforeAckDecimation) {
+ ack_frequency_sent_ = true;
+ auto frame = sent_packet_manager_.GetUpdatedAckFrequencyFrame();
+ visitor_->SendAckFrequency(frame);
+ }
+ }
+
QuicFrames frames;
const bool has_pending_ack =
uber_received_packet_manager_
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index e02b573..3e74191 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -29,6 +29,7 @@
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_max_streams_frame.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
@@ -158,6 +159,9 @@
// Called when a ping needs to be sent.
virtual void SendPing() = 0;
+ // Called when an AckFrequency frame need to be sent.
+ virtual void SendAckFrequency(const QuicAckFrequencyFrame& frame) = 0;
+
// Called to ask if the visitor wants to schedule write resumption as it both
// has pending data to write, and is able to write (e.g. based on flow control
// limits).
@@ -1870,6 +1874,9 @@
// Indicate whether any ENCRYPTION_HANDSHAKE packet has been sent.
bool handshake_packet_sent_ = false;
+ // Indicate whether AckFrequency frame has been sent.
+ bool ack_frequency_sent_ = false;
+
const bool fix_missing_initial_keys_ =
GetQuicReloadableFlag(quic_fix_missing_initial_keys2);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 132bee2..178eb2f 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -12135,6 +12135,47 @@
EXPECT_FALSE(connection_.GetDiscardPreviousOneRttKeysAlarm()->IsSet());
}
+TEST_P(QuicConnectionTest, SendAckFrequencyFrame) {
+ 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);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ connection_.SetFromConfig(config);
+ QuicConnectionPeer::SetAddressValidated(&connection_);
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+
+ connection_.OnHandshakeComplete();
+
+ writer_->SetWritable();
+ QuicPacketCreatorPeer::SetPacketNumber(creator_, 99);
+ // Send packet 100
+ SendStreamDataToPeer(/*id=*/1, "foo", /*offset=*/0, NO_FIN, nullptr);
+
+ QuicAckFrequencyFrame captured_frame;
+ EXPECT_CALL(visitor_, SendAckFrequency(_))
+ .WillOnce(Invoke([&captured_frame](const QuicAckFrequencyFrame& frame) {
+ captured_frame = frame;
+ }));
+ // Send packet 101.
+ SendStreamDataToPeer(/*id=*/1, "bar", /*offset=*/3, NO_FIN, nullptr);
+
+ EXPECT_EQ(captured_frame.packet_tolerance, 10u);
+ EXPECT_EQ(captured_frame.max_ack_delay,
+ QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs));
+
+ // Sending packet 102 does not trigger sending another AckFrequencyFrame.
+ SendStreamDataToPeer(/*id=*/1, "baz", /*offset=*/6, NO_FIN, nullptr);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc
index 28b3446..fddf087 100644
--- a/quic/core/quic_control_frame_manager.cc
+++ b/quic/core/quic_control_frame_manager.cc
@@ -120,13 +120,16 @@
}
void QuicControlFrameManager::WriteOrBufferAckFrequency(
- uint64_t packet_tolerance,
- QuicTime::Delta max_ack_delay) {
+ const QuicAckFrequencyFrame& ack_frequency_frame) {
QUIC_DVLOG(1) << "Writing ACK_FREQUENCY frame";
QuicControlFrameId control_frame_id = ++last_control_frame_id_;
- WriteOrBufferQuicFrame(QuicFrame(new QuicAckFrequencyFrame(
- control_frame_id,
- /*sequence_number=*/control_frame_id, packet_tolerance, max_ack_delay)));
+ // Using the control_frame_id for sequence_number here leaves gaps in
+ // sequence_number.
+ WriteOrBufferQuicFrame(
+ QuicFrame(new QuicAckFrequencyFrame(control_frame_id,
+ /*sequence_number=*/control_frame_id,
+ ack_frequency_frame.packet_tolerance,
+ ack_frequency_frame.max_ack_delay)));
}
void QuicControlFrameManager::WritePing() {
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h
index d79b679..493e7f0 100644
--- a/quic/core/quic_control_frame_manager.h
+++ b/quic/core/quic_control_frame_manager.h
@@ -86,8 +86,8 @@
// Tries to send an AckFrequencyFrame. The frame is buffered if it cannot be
// sent immediately.
- void WriteOrBufferAckFrequency(uint64_t packet_tolerance,
- QuicTime::Delta max_ack_delay);
+ void WriteOrBufferAckFrequency(
+ const QuicAckFrequencyFrame& ack_frequency_frame);
// Sends a PING_FRAME. Do not send PING if there is buffered frames.
void WritePing();
diff --git a/quic/core/quic_control_frame_manager_test.cc b/quic/core/quic_control_frame_manager_test.cc
index 6817699..cf90e90 100644
--- a/quic/core/quic_control_frame_manager_test.cc
+++ b/quic/core/quic_control_frame_manager_test.cc
@@ -243,16 +243,19 @@
manager_->OnCanWrite();
// Send AckFrequencyFrame as frame 6.
- QuicAckFrequencyFrame ack_frequency = {6, 6, 10,
- QuicTime::Delta::FromMilliseconds(24)};
- manager_->WriteOrBufferAckFrequency(10,
- QuicTime::Delta::FromMilliseconds(24));
+ QuicAckFrequencyFrame frame_to_send;
+ frame_to_send.packet_tolerance = 10;
+ frame_to_send.max_ack_delay = QuicTime::Delta::FromMilliseconds(24);
+ manager_->WriteOrBufferAckFrequency(frame_to_send);
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&ClearControlFrame));
manager_->OnCanWrite();
// Ack AckFrequencyFrame.
- EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&ack_frequency)));
+ QuicAckFrequencyFrame expected_ack_frequency = {
+ 6, 6, 10, QuicTime::Delta::FromMilliseconds(24)};
+ EXPECT_TRUE(
+ manager_->OnControlFrameAcked(QuicFrame(&expected_ack_frequency)));
}
TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 4dc2582..106393b 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -5,13 +5,17 @@
#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
#include <algorithm>
+#include <cstddef>
#include <string>
#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_number.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -55,6 +59,11 @@
// losses.
static const uint32_t kConservativeUnpacedBurst = 2;
+// TODO(haoyuewang) Unify this constant and kAckDecimationDelay in
+// quic_received_packet_manager.cc.
+// Ack delay as (RTT >> kAckDelayShift).
+static const int kAckDelayShift = 2;
+
} // namespace
#define ENDPOINT \
@@ -140,6 +149,13 @@
peer_max_ack_delay_ =
QuicTime::Delta::FromMilliseconds(config.ReceivedMaxAckDelayMs());
}
+ if (GetQuicReloadableFlag(quic_can_send_ack_frequency) &&
+ perspective == Perspective::IS_SERVER) {
+ if (config.HasReceivedMinAckDelayMs()) {
+ peer_min_ack_delay_ =
+ QuicTime::Delta::FromMilliseconds(config.ReceivedMinAckDelayMs());
+ }
+ }
if (config.HasClientSentConnectionOption(kMAD0, perspective)) {
rtt_stats_.set_ignore_max_ack_delay(true);
}
@@ -700,6 +716,27 @@
info->state = ACKED;
}
+bool QuicSentPacketManager::CanSendAckFrequency() const {
+ return !peer_min_ack_delay_.IsInfinite() && handshake_finished_;
+}
+
+QuicAckFrequencyFrame QuicSentPacketManager::GetUpdatedAckFrequencyFrame()
+ const {
+ QuicAckFrequencyFrame frame;
+ if (!CanSendAckFrequency()) {
+ QUIC_BUG << "New AckFrequencyFrame is created while it shouldn't.";
+ return frame;
+ }
+
+ QUIC_RELOADABLE_FLAG_COUNT(quic_can_send_ack_frequency);
+ frame.packet_tolerance = kMaxRetransmittablePacketsBeforeAck;
+ auto rtt = rtt_stats_.MinOrInitialRtt();
+ frame.max_ack_delay = rtt >> kAckDelayShift;
+ frame.max_ack_delay = std::max(frame.max_ack_delay, peer_min_ack_delay_);
+
+ return frame;
+}
+
bool QuicSentPacketManager::OnPacketSent(
SerializedPacket* mutable_packet,
QuicTime sent_time,
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index b332034..ef5972a 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -22,6 +22,7 @@
#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_sustained_bandwidth_recorder.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_transmission_info.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
@@ -197,6 +198,10 @@
HasRetransmittableData has_retransmittable_data,
bool measure_rtt);
+ bool CanSendAckFrequency() const;
+
+ QuicAckFrequencyFrame GetUpdatedAckFrequencyFrame() const;
+
// Called when the retransmission timer expires and returns the retransmission
// mode.
RetransmissionTimeoutMode OnRetransmissionTimeout();
@@ -650,6 +655,10 @@
// negotiation or subsequently by AckFrequencyFrame.
QuicTime::Delta peer_max_ack_delay_;
+ // Peer sends min_ack_delay in TransportParameter to advertise its support for
+ // AckFrequencyFrame.
+ QuicTime::Delta peer_min_ack_delay_ = QuicTime::Delta::Infinite();
+
// The history of outstanding max_ack_delays sent to peer. Outstanding means
// a max_ack_delay is sent as part of the last acked AckFrequencyFrame or
// an unacked AckFrequencyFrame after that.
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index ef651a7..4bb16a3 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -10,6 +10,7 @@
#include "absl/strings/string_view.h"
#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -4419,6 +4420,33 @@
EXPECT_EQ(message_frame->message_length, 0);
}
+TEST_F(QuicSentPacketManagerTest, SendAckFrequencyFrame) {
+ SetQuicReloadableFlag(quic_can_send_ack_frequency, true);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedMinAckDelayMs(&config, /*min_ack_delay_ms=*/1);
+ manager_.SetFromConfig(config);
+ manager_.SetHandshakeConfirmed();
+
+ // Set up RTTs.
+ auto* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(8),
+ /*ack_delay=*/QuicTime::Delta::Zero(),
+ /*now=*/QuicTime::Zero());
+ // Make sure srtt and min_rtt are different.
+ rtt_stats->UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(16),
+ /*ack_delay=*/QuicTime::Delta::Zero(),
+ /*now=*/QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(24));
+
+ auto frame = manager_.GetUpdatedAckFrequencyFrame();
+ EXPECT_EQ(frame.max_ack_delay,
+ std::max(rtt_stats->min_rtt() * 0.25,
+ QuicTime::Delta::FromMilliseconds(1u)));
+ EXPECT_EQ(frame.packet_tolerance, 10u);
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 84f0a7f..9705710 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "absl/strings/string_view.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/quic_connection.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_flow_controller.h"
@@ -2003,6 +2004,10 @@
control_frame_manager_.WritePing();
}
+void QuicSession::SendAckFrequency(const QuicAckFrequencyFrame& frame) {
+ control_frame_manager_.WriteOrBufferAckFrequency(frame);
+}
+
bool QuicSession::IsConnectionFlowControlBlocked() const {
return flow_controller_.IsBlocked();
}
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index e84124e..3c04c77 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -16,6 +16,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
#include "net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h"
#include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_connection.h"
@@ -123,6 +124,7 @@
// Adds a connection level WINDOW_UPDATE frame.
void OnAckNeedsRetransmittableFrame() override;
void SendPing() override;
+ void SendAckFrequency(const QuicAckFrequencyFrame& frame) override;
bool WillingAndAbleToWrite() const override;
std::string GetStreamsInfoForLogging() const override;
void OnPathDegrading() override;
diff --git a/quic/test_tools/quic_config_peer.cc b/quic/test_tools/quic_config_peer.cc
index 52325d1..b10453e 100644
--- a/quic/test_tools/quic_config_peer.cc
+++ b/quic/test_tools/quic_config_peer.cc
@@ -99,6 +99,12 @@
}
// static
+void QuicConfigPeer::SetReceivedMinAckDelayMs(QuicConfig* config,
+ uint32_t min_ack_delay_ms) {
+ config->min_ack_delay_ms_.SetReceivedValue(min_ack_delay_ms);
+}
+
+// static
void QuicConfigPeer::SetNegotiated(QuicConfig* config, bool negotiated) {
config->negotiated_ = negotiated;
}
diff --git a/quic/test_tools/quic_config_peer.h b/quic/test_tools/quic_config_peer.h
index 109bd64..98c35a1 100644
--- a/quic/test_tools/quic_config_peer.h
+++ b/quic/test_tools/quic_config_peer.h
@@ -60,6 +60,9 @@
static void SetReceivedMaxPacketSize(QuicConfig* config,
uint32_t max_udp_payload_size);
+ static void SetReceivedMinAckDelayMs(QuicConfig* config,
+ uint32_t min_ack_delay_ms);
+
static void SetNegotiated(QuicConfig* config, bool negotiated);
static void SetReceivedOriginalConnectionId(
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 30798c7..3539628 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -560,6 +560,10 @@
(override));
MOCK_METHOD(void, OnAckNeedsRetransmittableFrame, (), (override));
MOCK_METHOD(void, SendPing, (), (override));
+ MOCK_METHOD(void,
+ SendAckFrequency,
+ (const QuicAckFrequencyFrame& frame),
+ (override));
MOCK_METHOD(bool, AllowSelfAddressChange, (), (const, override));
MOCK_METHOD(HandshakeState, GetHandshakeState, (), (const, override));
MOCK_METHOD(bool,
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index faf2bfd..7968900 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -80,6 +80,7 @@
void OnForwardProgressMadeAfterPathDegrading() override {}
void OnAckNeedsRetransmittableFrame() override {}
void SendPing() override {}
+ void SendAckFrequency(const QuicAckFrequencyFrame& /*frame*/) override {}
bool AllowSelfAddressChange() const override;
HandshakeState GetHandshakeState() const override;
bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& /*frame*/) override {