Do not bundle ACK in connection close packet if there is an queued ACK.
Protected by FLAGS_quic_reloadable_flag_quic_single_ack_in_packet.
PiperOrigin-RevId: 343893573
Change-Id: I920a8a6c171ca0944fe596dcbe5bc132e3d5b6a6
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 90a1739..bca806e 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -3935,9 +3935,14 @@
// If there was a packet write error, write the smallest close possible.
ScopedPacketFlusher flusher(this);
// Always bundle an ACK with connection close for debugging purpose.
- if (error != QUIC_PACKET_WRITE_ERROR &&
- !uber_received_packet_manager_.IsAckFrameEmpty(
- QuicUtils::GetPacketNumberSpace(encryption_level_))) {
+ bool send_ack = error != QUIC_PACKET_WRITE_ERROR &&
+ !uber_received_packet_manager_.IsAckFrameEmpty(
+ QuicUtils::GetPacketNumberSpace(encryption_level_));
+ if (GetQuicReloadableFlag(quic_single_ack_in_packet)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_single_ack_in_packet, 1, 2);
+ send_ack = !packet_creator_.has_ack() && send_ack;
+ }
+ if (send_ack) {
SendAck();
}
QuicConnectionCloseFrame* frame;
@@ -3977,9 +3982,14 @@
use_encryption_level_context_ ? this : nullptr, level);
// Bundle an ACK of the corresponding packet number space for debugging
// purpose.
- if (error != QUIC_PACKET_WRITE_ERROR &&
- !uber_received_packet_manager_.IsAckFrameEmpty(
- QuicUtils::GetPacketNumberSpace(encryption_level_))) {
+ bool send_ack = error != QUIC_PACKET_WRITE_ERROR &&
+ !uber_received_packet_manager_.IsAckFrameEmpty(
+ QuicUtils::GetPacketNumberSpace(encryption_level_));
+ if (GetQuicReloadableFlag(quic_single_ack_in_packet)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_single_ack_in_packet, 2, 2);
+ send_ack = !packet_creator_.has_ack() && send_ack;
+ }
+ if (send_ack) {
QuicFrames frames;
frames.push_back(GetUpdatedAckFrame());
packet_creator_.FlushAckFrame(frames);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index a329404..2d73601 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -12826,6 +12826,32 @@
EXPECT_FALSE(connection_.IsPathDegrading());
}
+TEST_P(QuicConnectionTest, SingleAckInPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+ connection_.NeuterUnencryptedPackets();
+ connection_.OnHandshakeComplete();
+
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).WillOnce(Invoke([=]() {
+ connection_.SendStreamData3();
+ connection_.CloseConnection(
+ QUIC_INTERNAL_ERROR, "error",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }));
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame1_));
+ ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress,
+ ENCRYPTION_FORWARD_SECURE);
+ ASSERT_FALSE(writer_->ack_frames().empty());
+ if (GetQuicReloadableFlag(quic_single_ack_in_packet)) {
+ EXPECT_EQ(1u, writer_->ack_frames().size());
+ } else {
+ EXPECT_EQ(2u, writer_->ack_frames().size());
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 473106f..3327c5f 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -68,6 +68,7 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_path_response, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_version_negotiation_for_short_connection_ids, true)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_split_up_send_rst_2, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_stop_sending_uses_ietf_error_code, true)
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 087b427..e1e3478 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -1426,6 +1426,8 @@
bool QuicPacketCreator::FlushAckFrame(const QuicFrames& frames) {
QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when "
"generator tries to send ACK frame.";
+ QUIC_BUG_IF(GetQuicReloadableFlag(quic_single_ack_in_packet) && has_ack())
+ << "Trying to flush " << frames << " when there is ACK queued";
for (const auto& frame : frames) {
DCHECK(frame.type == ACK_FRAME || frame.type == STOP_WAITING_FRAME);
if (HasPendingFrames()) {