Improve ECN coverage in QuicConnectionTest
PiperOrigin-RevId: 501664181
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index a3a4144..98027d4 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -6,6 +6,7 @@
#include <errno.h>
+#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
@@ -876,13 +877,28 @@
size_t ProcessFramePacketAtLevel(uint64_t number, QuicFrame frame,
EncryptionLevel level) {
- QuicFrames frames;
- frames.push_back(frame);
- return ProcessFramesPacketAtLevel(number, frames, level);
+ return ProcessFramePacketAtLevelWithEcn(number, frame, level, ECN_NOT_ECT);
}
- size_t ProcessFramesPacketAtLevel(uint64_t number, const QuicFrames& frames,
+ size_t ProcessFramePacketAtLevelWithEcn(uint64_t number, QuicFrame frame,
+ EncryptionLevel level,
+ QuicEcnCodepoint ecn_codepoint) {
+ QuicFrames frames;
+ frames.push_back(frame);
+ return ProcessFramesPacketAtLevelWithEcn(number, frames, level,
+ ecn_codepoint);
+ }
+
+ size_t ProcessFramesPacketAtLevel(uint64_t number, QuicFrames frames,
EncryptionLevel level) {
+ return ProcessFramesPacketAtLevelWithEcn(number, frames, level,
+ ECN_NOT_ECT);
+ }
+
+ size_t ProcessFramesPacketAtLevelWithEcn(uint64_t number,
+ const QuicFrames& frames,
+ EncryptionLevel level,
+ QuicEcnCodepoint ecn_codepoint) {
QuicPacketHeader header = ConstructPacketHeader(number, level);
// Set the correct encryption level and encrypter on peer_creator and
// peer_framer, respectively.
@@ -907,7 +923,8 @@
buffer, kMaxOutgoingPacketSize);
connection_.ProcessUdpPacket(
kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
+ QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false, 0,
+ true, nullptr, 0, false, ecn_codepoint));
if (connection_.GetSendAlarm()->IsSet()) {
connection_.GetSendAlarm()->Fire();
}
@@ -924,6 +941,11 @@
};
size_t ProcessCoalescedPacket(std::vector<PacketInfo> packets) {
+ return ProcessCoalescedPacket(packets, ECN_NOT_ECT);
+ }
+
+ size_t ProcessCoalescedPacket(std::vector<PacketInfo> packets,
+ QuicEcnCodepoint ecn_codepoint) {
char coalesced_buffer[kMaxOutgoingPacketSize];
size_t coalesced_size = 0;
bool contains_initial = false;
@@ -970,7 +992,7 @@
connection_.ProcessUdpPacket(
kSelfAddress, kPeerAddress,
QuicReceivedPacket(coalesced_buffer, coalesced_size, clock_.Now(),
- false));
+ false, 0, true, nullptr, 0, false, ecn_codepoint));
if (connection_.GetSendAlarm()->IsSet()) {
connection_.GetSendAlarm()->Fire();
}
@@ -16499,59 +16521,193 @@
TEST_P(QuicConnectionTest, EcnMarksCorrectlyRecorded) {
set_perspective(Perspective::IS_SERVER);
- QuicPacketHeader header = ConstructPacketHeader(1, ENCRYPTION_FORWARD_SECURE);
QuicFrames frames;
- QuicPingFrame ping_frame;
- QuicPaddingFrame padding_frame;
- frames.push_back(QuicFrame(ping_frame));
- frames.push_back(QuicFrame(padding_frame));
- std::unique_ptr<QuicPacket> packet =
- BuildUnsizedDataPacket(&peer_framer_, header, frames);
- char buffer[kMaxOutgoingPacketSize];
- size_t encrypted_length = peer_framer_.EncryptPayload(
- ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(1), *packet, buffer,
- kMaxOutgoingPacketSize);
- QuicReceivedPacket received_packet(buffer, encrypted_length, clock_.Now(),
- false, 0, true, nullptr, 0, false,
- ECN_ECT0);
- if (connection_.SupportsMultiplePacketNumberSpaces()) {
- EXPECT_FALSE(connection_.received_packet_manager()
- .GetAckFrame(APPLICATION_DATA)
- .ecn_counters.has_value());
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, received_packet);
- if (GetQuicRestartFlag(quic_receive_ecn)) {
- EXPECT_TRUE(connection_.received_packet_manager()
- .GetAckFrame(APPLICATION_DATA)
- .ecn_counters.has_value());
- EXPECT_EQ(connection_.received_packet_manager()
- .GetAckFrame(APPLICATION_DATA)
- .ecn_counters->ect0,
- 1);
- } else {
- EXPECT_FALSE(connection_.received_packet_manager()
- .GetAckFrame(APPLICATION_DATA)
- .ecn_counters.has_value());
- }
+ frames.push_back(QuicFrame(QuicPingFrame()));
+ frames.push_back(QuicFrame(QuicPaddingFrame(7)));
+ QuicAckFrame ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+
+ ProcessFramesPacketAtLevelWithEcn(1, frames, ENCRYPTION_FORWARD_SECURE,
+ ECN_ECT0);
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ if (GetQuicRestartFlag(quic_receive_ecn)) {
+ ASSERT_TRUE(ack_frame.ecn_counters.has_value());
+ EXPECT_EQ(ack_frame.ecn_counters->ect0, 1);
} else {
- EXPECT_FALSE(connection_.received_packet_manager()
- .ack_frame()
- .ecn_counters.has_value());
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, received_packet);
- if (GetQuicRestartFlag(quic_receive_ecn)) {
- EXPECT_TRUE(connection_.received_packet_manager()
- .ack_frame()
- .ecn_counters.has_value());
- EXPECT_EQ(
- connection_.received_packet_manager().ack_frame().ecn_counters->ect0,
- 1);
- } else {
- EXPECT_FALSE(connection_.received_packet_manager()
- .ack_frame()
- .ecn_counters.has_value());
- }
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
}
}
+TEST_P(QuicConnectionTest, EcnMarksCoalescedPacket) {
+ if (!connection_.version().CanSendCoalescedPackets() ||
+ !GetQuicRestartFlag(quic_receive_ecn)) {
+ return;
+ }
+ QuicCryptoFrame crypto_frame1{ENCRYPTION_HANDSHAKE, 0, "foo"};
+ QuicFrames frames1;
+ frames1.push_back(QuicFrame(&crypto_frame1));
+ QuicFrames frames2;
+ QuicCryptoFrame crypto_frame2{ENCRYPTION_FORWARD_SECURE, 0, "bar"};
+ frames2.push_back(QuicFrame(&crypto_frame2));
+ std::vector<PacketInfo> packets = {{2, frames1, ENCRYPTION_HANDSHAKE},
+ {3, frames2, ENCRYPTION_FORWARD_SECURE}};
+ QuicAckFrame ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ // Deliver packets.
+ connection_.SetEncrypter(
+ ENCRYPTION_HANDSHAKE,
+ std::make_unique<TaggingEncrypter>(ENCRYPTION_HANDSHAKE));
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(2);
+ ProcessCoalescedPacket(packets, ECN_ECT0);
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ ASSERT_TRUE(ack_frame.ecn_counters.has_value());
+ EXPECT_EQ(ack_frame.ecn_counters->ect0,
+ connection_.SupportsMultiplePacketNumberSpaces() ? 1 : 2);
+ if (connection_.SupportsMultiplePacketNumberSpaces()) {
+ ack_frame = connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(
+ APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_TRUE(ack_frame.ecn_counters.has_value());
+ EXPECT_EQ(ack_frame.ecn_counters->ect0, 1);
+ }
+}
+
+TEST_P(QuicConnectionTest, EcnMarksUndecryptableCoalescedPacket) {
+ if (!connection_.version().CanSendCoalescedPackets() ||
+ !GetQuicRestartFlag(quic_receive_ecn)) {
+ return;
+ }
+ // SetFromConfig is always called after construction from InitializeSession.
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ config.set_max_undecryptable_packets(100);
+ connection_.SetFromConfig(config);
+ QuicCryptoFrame crypto_frame1{ENCRYPTION_HANDSHAKE, 0, "foo"};
+ QuicFrames frames1;
+ frames1.push_back(QuicFrame(&crypto_frame1));
+ QuicFrames frames2;
+ QuicCryptoFrame crypto_frame2{ENCRYPTION_FORWARD_SECURE, 0, "bar"};
+ frames2.push_back(QuicFrame(&crypto_frame2));
+ std::vector<PacketInfo> packets = {{2, frames1, ENCRYPTION_HANDSHAKE},
+ {3, frames2, ENCRYPTION_FORWARD_SECURE}};
+ char coalesced_buffer[kMaxOutgoingPacketSize];
+ size_t coalesced_size = 0;
+ for (const auto& packet : packets) {
+ QuicPacketHeader header =
+ ConstructPacketHeader(packet.packet_number, packet.level);
+ // Set the correct encryption level and encrypter on peer_creator and
+ // peer_framer, respectively.
+ peer_creator_.set_encryption_level(packet.level);
+ peer_framer_.SetEncrypter(packet.level,
+ std::make_unique<TaggingEncrypter>(packet.level));
+ // Set the corresponding decrypter.
+ if (packet.level == ENCRYPTION_HANDSHAKE) {
+ connection_.SetEncrypter(
+ packet.level, std::make_unique<TaggingEncrypter>(packet.level));
+ connection_.SetDefaultEncryptionLevel(packet.level);
+ SetDecrypter(packet.level,
+ std::make_unique<StrictTaggingDecrypter>(packet.level));
+ }
+ // Forward Secure packet is undecryptable.
+ std::unique_ptr<QuicPacket> constructed_packet(
+ ConstructPacket(header, packet.frames));
+
+ char buffer[kMaxOutgoingPacketSize];
+ size_t encrypted_length = peer_framer_.EncryptPayload(
+ packet.level, QuicPacketNumber(packet.packet_number),
+ *constructed_packet, buffer, kMaxOutgoingPacketSize);
+ QUICHE_DCHECK_LE(coalesced_size + encrypted_length, kMaxOutgoingPacketSize);
+ memcpy(coalesced_buffer + coalesced_size, buffer, encrypted_length);
+ coalesced_size += encrypted_length;
+ }
+ QuicAckFrame ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ // Deliver packets, but first remove the Forward Secure decrypter so that
+ // packet has to be buffered.
+ connection_.RemoveDecrypter(ENCRYPTION_FORWARD_SECURE);
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
+ EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(coalesced_buffer, coalesced_size, clock_.Now(), false,
+ 0, true, nullptr, 0, true, ECN_ECT0));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ ASSERT_TRUE(ack_frame.ecn_counters.has_value());
+ EXPECT_EQ(ack_frame.ecn_counters->ect0, 1);
+ if (connection_.SupportsMultiplePacketNumberSpaces()) {
+ ack_frame = connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(
+ APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ }
+ // Send PING packet with ECN_CE, which will change the ECN codepoint in
+ // last_received_packet_info_.
+ ProcessFramePacketAtLevelWithEcn(4, QuicFrame(QuicPingFrame()),
+ ENCRYPTION_HANDSHAKE, ECN_CE);
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ ASSERT_TRUE(ack_frame.ecn_counters.has_value());
+ EXPECT_EQ(ack_frame.ecn_counters->ect0, 1);
+ EXPECT_EQ(ack_frame.ecn_counters->ce, 1);
+ if (connection_.SupportsMultiplePacketNumberSpaces()) {
+ ack_frame = connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(
+ APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ EXPECT_FALSE(ack_frame.ecn_counters.has_value());
+ }
+ // Install decrypter for ENCRYPTION_FORWARD_SECURE. Make sure the original
+ // ECN codepoint is incremented.
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
+ SetDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<StrictTaggingDecrypter>(ENCRYPTION_FORWARD_SECURE));
+ connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
+ ack_frame =
+ connection_.SupportsMultiplePacketNumberSpaces()
+ ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA)
+ : connection_.received_packet_manager().ack_frame();
+ ASSERT_TRUE(ack_frame.ecn_counters.has_value());
+ // Should be recorded as ECT(0), not CE.
+ EXPECT_EQ(ack_frame.ecn_counters->ect0,
+ connection_.SupportsMultiplePacketNumberSpaces() ? 1 : 2);
+}
+
} // namespace
} // namespace test
} // namespace quic