Internal change PiperOrigin-RevId: 515182736
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index 9d4f882..dbede25 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -1324,6 +1324,20 @@ last_received_packet_info_.header.packet_number; } + switch (last_received_packet_info_.ecn_codepoint) { + case ECN_NOT_ECT: + break; + case ECN_ECT0: + stats_.num_ecn_marks_received.ect0++; + break; + case ECN_ECT1: + stats_.num_ecn_marks_received.ect1++; + break; + case ECN_CE: + stats_.num_ecn_marks_received.ce++; + break; + } + // Record packet receipt to populate ack info before processing stream // frames, since the processing may result in sending a bundled ack. QuicTime receipt_time = idle_network_detector_.time_of_last_received_packet(); @@ -3630,6 +3644,9 @@ stats_.bytes_sent += encrypted_length; ++stats_.packets_sent; + if (packet->has_ack_ecn) { + stats_.num_ack_frames_sent_with_ecn++; + } QuicByteCount bytes_not_retransmitted = packet->bytes_not_retransmitted.value_or(0);
diff --git a/quiche/quic/core/quic_connection_stats.h b/quiche/quic/core/quic_connection_stats.h index 82b0255..336435e 100644 --- a/quiche/quic/core/quic_connection_stats.h +++ b/quiche/quic/core/quic_connection_stats.h
@@ -188,6 +188,14 @@ QuicPacketCount num_tls_server_zero_rtt_packets_received_after_discarding_decrypter = 0; + // Counts the number of packets received with each Explicit Congestion + // Notification (ECN) codepoint, except Not-ECT. There is one counter across + // all packet number spaces. + QuicEcnCounts num_ecn_marks_received; + + // Counts the number of ACK frames sent with ECN counts. + QuicPacketCount num_ack_frames_sent_with_ecn = 0; + // True if address is validated via decrypting HANDSHAKE or 1-RTT packet. bool address_validated_via_decrypting_packet = false;
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index 84c8cdb..a235314 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc
@@ -16877,12 +16877,26 @@ connection_.SupportsMultiplePacketNumberSpaces() ? connection_.received_packet_manager().GetAckFrame(APPLICATION_DATA) : connection_.received_packet_manager().ack_frame(); + // Send two PINGs so that the ACK goes too. The second packet should not + // include an ACK, which checks that the packet state is cleared properly. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + if (connection_.version().HasIetfQuicFrames()) { + QuicConnectionPeer::SendPing(&connection_); + QuicConnectionPeer::SendPing(&connection_); + } + QuicConnectionStats stats = connection_.GetStats(); if (GetQuicRestartFlag(quic_receive_ecn)) { ASSERT_TRUE(ack_frame.ecn_counters.has_value()); EXPECT_EQ(ack_frame.ecn_counters->ect0, 1); + EXPECT_EQ(stats.num_ack_frames_sent_with_ecn, + connection_.version().HasIetfQuicFrames() ? 1 : 0); } else { EXPECT_FALSE(ack_frame.ecn_counters.has_value()); + EXPECT_EQ(stats.num_ack_frames_sent_with_ecn, 0); } + EXPECT_EQ(stats.num_ecn_marks_received.ect0, 1); + EXPECT_EQ(stats.num_ecn_marks_received.ect1, 0); + EXPECT_EQ(stats.num_ecn_marks_received.ce, 0); } TEST_P(QuicConnectionTest, EcnMarksCoalescedPacket) { @@ -16914,6 +16928,16 @@ std::make_unique<TaggingEncrypter>(ENCRYPTION_HANDSHAKE)); EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(2); ProcessCoalescedPacket(packets, ECN_ECT0); + // Send two PINGs so that the ACKs go too. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + if (connection_.version().HasIetfQuicFrames()) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + QuicConnectionPeer::SendPing(&connection_); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + QuicConnectionPeer::SendPing(&connection_); + } + QuicConnectionStats stats = connection_.GetStats(); ack_frame = connection_.SupportsMultiplePacketNumberSpaces() ? connection_.received_packet_manager().GetAckFrame(HANDSHAKE_DATA) @@ -16929,6 +16953,16 @@ EXPECT_TRUE(ack_frame.ecn_counters.has_value()); EXPECT_EQ(ack_frame.ecn_counters->ect0, 1); } + if (GetQuicRestartFlag(quic_receive_ecn)) { + EXPECT_EQ(stats.num_ecn_marks_received.ect0, 2); + EXPECT_EQ(stats.num_ack_frames_sent_with_ecn, + connection_.version().HasIetfQuicFrames() ? 2 : 0); + } else { + EXPECT_EQ(stats.num_ecn_marks_received.ect0, 0); + EXPECT_EQ(stats.num_ack_frames_sent_with_ecn, 0); + } + EXPECT_EQ(stats.num_ecn_marks_received.ect1, 0); + EXPECT_EQ(stats.num_ecn_marks_received.ce, 0); } TEST_P(QuicConnectionTest, EcnMarksUndecryptableCoalescedPacket) { @@ -17047,6 +17081,12 @@ // Should be recorded as ECT(0), not CE. EXPECT_EQ(ack_frame.ecn_counters->ect0, connection_.SupportsMultiplePacketNumberSpaces() ? 1 : 2); + QuicConnectionStats stats = connection_.GetStats(); + EXPECT_EQ(stats.num_ecn_marks_received.ect0, + GetQuicRestartFlag(quic_receive_ecn) ? 2 : 0); + EXPECT_EQ(stats.num_ecn_marks_received.ect1, 0); + EXPECT_EQ(stats.num_ecn_marks_received.ce, + GetQuicRestartFlag(quic_receive_ecn) ? 1 : 0); } TEST_P(QuicConnectionTest, ReceivedPacketInfoDefaults) {
diff --git a/quiche/quic/core/quic_packet_creator.cc b/quiche/quic/core/quic_packet_creator.cc index 2a0974f..5599f8f 100644 --- a/quiche/quic/core/quic_packet_creator.cc +++ b/quiche/quic/core/quic_packet_creator.cc
@@ -492,6 +492,7 @@ void QuicPacketCreator::ClearPacket() { packet_.has_ack = false; packet_.has_stop_waiting = false; + packet_.has_ack_ecn = false; packet_.has_crypto_handshake = NOT_HANDSHAKE; packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; @@ -1829,6 +1830,9 @@ if (frame.type == ACK_FRAME) { packet_.has_ack = true; packet_.largest_acked = LargestAcked(*frame.ack_frame); + if (frame.ack_frame->ecn_counters.has_value()) { + packet_.has_ack_ecn = true; + } } else if (frame.type == STOP_WAITING_FRAME) { packet_.has_stop_waiting = true; } else if (frame.type == ACK_FREQUENCY_FRAME) {
diff --git a/quiche/quic/core/quic_packets.cc b/quiche/quic/core/quic_packets.cc index 746737b..39e7eaf 100644 --- a/quiche/quic/core/quic_packets.cc +++ b/quiche/quic/core/quic_packets.cc
@@ -441,6 +441,7 @@ encryption_level(other.encryption_level), has_ack(other.has_ack), has_stop_waiting(other.has_stop_waiting), + has_ack_ecn(other.has_ack_ecn), transmission_type(other.transmission_type), largest_acked(other.largest_acked), has_ack_frame_copy(other.has_ack_frame_copy), @@ -498,6 +499,7 @@ copy->peer_address = serialized.peer_address; copy->bytes_not_retransmitted = serialized.bytes_not_retransmitted; copy->initial_header = serialized.initial_header; + copy->has_ack_ecn = serialized.has_ack_ecn; if (copy_buffer) { copy->encrypted_buffer = CopyBuffer(serialized);
diff --git a/quiche/quic/core/quic_packets.h b/quiche/quic/core/quic_packets.h index c26a88a..d1eb52b 100644 --- a/quiche/quic/core/quic_packets.h +++ b/quiche/quic/core/quic_packets.h
@@ -376,6 +376,7 @@ // TODO(fayang): Remove has_ack and has_stop_waiting. bool has_ack; bool has_stop_waiting; + bool has_ack_ecn = false; // ack frame contains ECN counts. TransmissionType transmission_type; // The largest acked of the AckFrame in this packet if has_ack is true, // 0 otherwise.