gfe-relnote: In QUIC, truncate IETF ACK ranges if ACK frame does not fit. Protected by existing gfe2_reloadable_flag_quic_enable_version_draft_25_v3.
Also rewrote GetIetfAckFrameSize andAppendIetfAckFrameAndTypeByte.
PiperOrigin-RevId: 299906874
Change-Id: Ib670d89b35c6f35aa7a346027b3604c81c5389e7
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 771848e..eeaf258 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -469,12 +469,34 @@
size_t QuicFramer::GetMinAckFrameSize(
QuicTransportVersion version,
const QuicAckFrame& ack_frame,
+ uint32_t local_ack_delay_exponent,
QuicPacketNumberLength largest_observed_length) {
if (VersionHasIetfQuicFrames(version)) {
- // The minimal ack frame consists of the following four fields: Largest
- // Acknowledged, ACK Delay, ACK Block Count, and First ACK Block. Minimum
- // size of each is 1 byte.
- return kQuicFrameTypeSize + 4;
+ // The minimal ack frame consists of the following fields: Largest
+ // Acknowledged, ACK Delay, 0 ACK Block Count, First ACK Block and ECN
+ // counts.
+ // Type byte + largest acked.
+ size_t min_size =
+ kQuicFrameTypeSize +
+ QuicDataWriter::GetVarInt62Len(LargestAcked(ack_frame).ToUint64());
+ // Ack delay.
+ min_size += QuicDataWriter::GetVarInt62Len(
+ ack_frame.ack_delay_time.ToMicroseconds() >> local_ack_delay_exponent);
+ // 0 ack block count.
+ min_size += QuicDataWriter::GetVarInt62Len(0);
+ // First ack block.
+ min_size += QuicDataWriter::GetVarInt62Len(
+ ack_frame.packets.Empty() ? 0
+ : ack_frame.packets.rbegin()->Length() - 1);
+ // ECN counts.
+ if (ack_frame.ecn_counters_populated &&
+ (ack_frame.ect_0_count || ack_frame.ect_1_count ||
+ ack_frame.ecn_ce_count)) {
+ min_size += (QuicDataWriter::GetVarInt62Len(ack_frame.ect_0_count) +
+ QuicDataWriter::GetVarInt62Len(ack_frame.ect_1_count) +
+ QuicDataWriter::GetVarInt62Len(ack_frame.ecn_ce_count));
+ }
+ return min_size;
}
if (GetQuicReloadableFlag(quic_use_ack_frame_to_get_min_size)) {
QUIC_RELOADABLE_FLAG_COUNT(quic_use_ack_frame_to_get_min_size);
@@ -797,9 +819,9 @@
}
bool can_truncate =
frame.type == ACK_FRAME &&
- free_bytes >= GetMinAckFrameSize(version_.transport_version,
- *frame.ack_frame,
- PACKET_6BYTE_PACKET_NUMBER);
+ free_bytes >= GetMinAckFrameSize(
+ version_.transport_version, *frame.ack_frame,
+ local_ack_delay_exponent_, PACKET_6BYTE_PACKET_NUMBER);
if (can_truncate) {
// Truncate the frame so the packet will not exceed kMaxOutgoingPacketSize.
// Note that we may not use every byte of the writer in this case.
@@ -3739,26 +3761,6 @@
ack_frame->ack_delay_time =
QuicTime::Delta::FromMicroseconds(ack_delay_time_in_us);
}
- if (frame_type == IETF_ACK_ECN) {
- ack_frame->ecn_counters_populated = true;
- if (!reader->ReadVarInt62(&ack_frame->ect_0_count)) {
- set_detailed_error("Unable to read ack ect_0_count.");
- return false;
- }
- if (!reader->ReadVarInt62(&ack_frame->ect_1_count)) {
- set_detailed_error("Unable to read ack ect_1_count.");
- return false;
- }
- if (!reader->ReadVarInt62(&ack_frame->ecn_ce_count)) {
- set_detailed_error("Unable to read ack ecn_ce_count.");
- return false;
- }
- } else {
- ack_frame->ecn_counters_populated = false;
- ack_frame->ect_0_count = 0;
- ack_frame->ect_1_count = 0;
- ack_frame->ecn_ce_count = 0;
- }
if (!visitor_->OnAckFrameStart(QuicPacketNumber(largest_acked),
ack_frame->ack_delay_time)) {
// The visitor suppresses further processing of the packet. Although this is
@@ -3872,6 +3874,27 @@
ack_block_count--;
}
+ if (frame_type == IETF_ACK_ECN) {
+ ack_frame->ecn_counters_populated = true;
+ if (!reader->ReadVarInt62(&ack_frame->ect_0_count)) {
+ set_detailed_error("Unable to read ack ect_0_count.");
+ return false;
+ }
+ if (!reader->ReadVarInt62(&ack_frame->ect_1_count)) {
+ set_detailed_error("Unable to read ack ect_1_count.");
+ return false;
+ }
+ if (!reader->ReadVarInt62(&ack_frame->ecn_ce_count)) {
+ set_detailed_error("Unable to read ack ecn_ce_count.");
+ return false;
+ }
+ } else {
+ ack_frame->ecn_counters_populated = false;
+ ack_frame->ect_0_count = 0;
+ ack_frame->ect_1_count = 0;
+ ack_frame->ecn_ce_count = 0;
+ }
+ // TODO(fayang): Report ECN counts to visitor when they are actually used.
if (!visitor_->OnAckFrameEnd(QuicPacketNumber(block_low))) {
set_detailed_error(
"Error occurs when visitor finishes processing the ACK frame.");
@@ -4587,8 +4610,32 @@
ack_delay_time_us = ack_delay_time_us >> local_ack_delay_exponent_;
ack_frame_size += QuicDataWriter::GetVarInt62Len(ack_delay_time_us);
- // If |ecn_counters_populated| is true and any of the ecn counters is non-0
- // then the ecn counters are included...
+ if (frame.packets.Empty() || frame.packets.Max() != largest_acked) {
+ QUIC_BUG << "Malformed ack frame";
+ // ACK frame serialization will fail and connection will be closed.
+ return ack_frame_size;
+ }
+
+ // Ack block count.
+ ack_frame_size +=
+ QuicDataWriter::GetVarInt62Len(frame.packets.NumIntervals() - 1);
+
+ // First Ack range.
+ auto iter = frame.packets.rbegin();
+ ack_frame_size += QuicDataWriter::GetVarInt62Len(iter->Length() - 1);
+ QuicPacketNumber previous_smallest = iter->min();
+ ++iter;
+
+ // Ack blocks.
+ for (; iter != frame.packets.rend(); ++iter) {
+ const uint64_t gap = previous_smallest - iter->max() - 1;
+ const uint64_t ack_range = iter->Length() - 1;
+ ack_frame_size += (QuicDataWriter::GetVarInt62Len(gap) +
+ QuicDataWriter::GetVarInt62Len(ack_range));
+ previous_smallest = iter->min();
+ }
+
+ // ECN counts.
if (frame.ecn_counters_populated &&
(frame.ect_0_count || frame.ect_1_count || frame.ecn_ce_count)) {
ack_frame_size += QuicDataWriter::GetVarInt62Len(frame.ect_0_count);
@@ -4596,72 +4643,6 @@
ack_frame_size += QuicDataWriter::GetVarInt62Len(frame.ecn_ce_count);
}
- // The rest (ack_block_count, first_ack_block, and additional ack
- // blocks, if any) depends:
- uint64_t ack_block_count = frame.packets.NumIntervals();
- if (ack_block_count == 0) {
- // If the QuicAckFrame has no Intervals, then it is interpreted
- // as an ack of a single packet at QuicAckFrame.largest_acked.
- // The resulting ack will consist of only the frame's
- // largest_ack & first_ack_block fields. The first ack block will be 0
- // (indicating a single packet) and the ack block_count will be 0.
- // Each 0 takes 1 byte when VarInt62 encoded.
- ack_frame_size += 2;
- return ack_frame_size;
- }
-
- auto itr = frame.packets.rbegin();
- QuicPacketNumber ack_block_largest = largest_acked;
- QuicPacketNumber ack_block_smallest;
- if ((itr->max() - 1) == largest_acked) {
- // If largest_acked + 1 is equal to the Max() of the first Interval
- // in the QuicAckFrame then the first Interval is the first ack block of the
- // frame; remaining Intervals are additional ack blocks. The QuicAckFrame's
- // first Interval is encoded in the frame's largest_acked/first_ack_block,
- // the remaining Intervals are encoded in additional ack blocks in the
- // frame, and the packet's ack_block_count is the number of QuicAckFrame
- // Intervals - 1.
- ack_block_smallest = itr->min();
- itr++;
- ack_block_count--;
- } else {
- // If QuicAckFrame.largest_acked is NOT equal to the Max() of
- // the first Interval then it is interpreted as acking a single
- // packet at QuicAckFrame.largest_acked, with additional
- // Intervals indicating additional ack blocks. The encoding is
- // a) The packet's largest_acked is the QuicAckFrame's largest
- // acked,
- // b) the first ack block size is 0,
- // c) The packet's ack_block_count is the number of QuicAckFrame
- // Intervals, and
- // d) The QuicAckFrame Intervals are encoded in additional ack
- // blocks in the packet.
- ack_block_smallest = largest_acked;
- }
- size_t ack_block_count_size = QuicDataWriter::GetVarInt62Len(ack_block_count);
- ack_frame_size += ack_block_count_size;
-
- uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
- size_t first_ack_block_size = QuicDataWriter::GetVarInt62Len(first_ack_block);
- ack_frame_size += first_ack_block_size;
-
- // Account for the remaining Intervals, if any.
- while (ack_block_count != 0) {
- uint64_t gap_size = ack_block_smallest - itr->max();
- // Decrement per the protocol specification
- size_t size_of_gap_size = QuicDataWriter::GetVarInt62Len(gap_size - 1);
- ack_frame_size += size_of_gap_size;
-
- uint64_t block_size = itr->max() - itr->min();
- // Decrement per the protocol specification
- size_t size_of_block_size = QuicDataWriter::GetVarInt62Len(block_size - 1);
- ack_frame_size += size_of_block_size;
-
- ack_block_smallest = itr->min();
- itr++;
- ack_block_count--;
- }
-
return ack_frame_size;
}
@@ -4681,7 +4662,8 @@
GetMinPacketNumberLength(QuicPacketNumber(ack_info.max_block_length));
ack_size =
- GetMinAckFrameSize(version_.transport_version, ack, largest_acked_length);
+ GetMinAckFrameSize(version_.transport_version, ack,
+ local_ack_delay_exponent_, largest_acked_length);
// First ack block length.
ack_size += ack_block_length;
if (ack_info.num_ack_blocks != 0) {
@@ -5147,13 +5129,10 @@
int32_t available_timestamp_and_ack_block_bytes =
writer->capacity() - writer->length() - ack_block_length -
GetMinAckFrameSize(version_.transport_version, frame,
- largest_acked_length) -
+ local_ack_delay_exponent_, largest_acked_length) -
(new_ack_info.num_ack_blocks != 0 ? kNumberOfAckBlocksSize : 0);
DCHECK_LE(0, available_timestamp_and_ack_block_bytes);
- // Write out the type byte by setting the low order bits and doing shifts
- // to make room for the next bit flags to be set.
- // Whether there are multiple ack blocks.
uint8_t type_byte = 0;
SetBit(&type_byte, new_ack_info.num_ack_blocks != 0,
kQuicHasMultipleAckBlocksOffset);
@@ -5374,57 +5353,17 @@
return true;
}
-int QuicFramer::CalculateIetfAckBlockCount(const QuicAckFrame& frame,
- QuicDataWriter* /*writer*/,
- size_t available_space) {
- // Number of blocks requested in the frame
- uint64_t ack_block_count = frame.packets.NumIntervals();
-
- auto itr = frame.packets.rbegin();
-
- int actual_block_count = 1;
- uint64_t block_length = itr->max() - itr->min();
- size_t encoded_size = QuicDataWriter::GetVarInt62Len(block_length);
- if (encoded_size > available_space) {
- return 0;
- }
- available_space -= encoded_size;
- QuicPacketNumber previous_ack_end = itr->min();
- ack_block_count--;
-
- while (ack_block_count) {
- // Each block is a gap followed by another ACK. Calculate each value,
- // determine the encoded lengths, and check against the available space.
- itr++;
- size_t gap = previous_ack_end - itr->max() - 1;
- encoded_size = QuicDataWriter::GetVarInt62Len(gap);
-
- // Add the ACK block.
- block_length = itr->max() - itr->min();
- encoded_size += QuicDataWriter::GetVarInt62Len(block_length);
-
- if (encoded_size > available_space) {
- // No room for this block, so what we've
- // done up to now is all that can be done.
- return actual_block_count;
- }
- available_space -= encoded_size;
- actual_block_count++;
- previous_ack_end = itr->min();
- ack_block_count--;
- }
- // Ran through the whole thing! We can do all blocks.
- return actual_block_count;
-}
-
bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
QuicDataWriter* writer) {
- // Assume frame is an IETF_ACK frame. If |ecn_counters_populated| is true and
- // any of the ECN counters is non-0 then turn it into an IETF_ACK+ECN frame.
uint8_t type = IETF_ACK;
+ uint64_t ecn_size = 0;
if (frame.ecn_counters_populated &&
(frame.ect_0_count || frame.ect_1_count || frame.ecn_ce_count)) {
+ // Change frame type to ACK_ECN if any ECN count is available.
type = IETF_ACK_ECN;
+ ecn_size = (QuicDataWriter::GetVarInt62Len(frame.ect_0_count) +
+ QuicDataWriter::GetVarInt62Len(frame.ect_1_count) +
+ QuicDataWriter::GetVarInt62Len(frame.ecn_ce_count));
}
if (!writer->WriteUInt8(type)) {
@@ -5449,8 +5388,67 @@
set_detailed_error("No room for ack-delay in ack frame");
return false;
}
+
+ if (frame.packets.Empty() || frame.packets.Max() != largest_acked) {
+ QUIC_BUG << "Malformed ack frame: " << frame;
+ set_detailed_error("Malformed ack frame");
+ return false;
+ }
+
+ // Latch ack_block_count for potential truncation.
+ const uint64_t ack_block_count = frame.packets.NumIntervals() - 1;
+ QuicDataWriter count_writer(QuicDataWriter::GetVarInt62Len(ack_block_count),
+ writer->data() + writer->length());
+ if (!writer->WriteVarInt62(ack_block_count)) {
+ set_detailed_error("No room for ack block count in ack frame");
+ return false;
+ }
+ auto iter = frame.packets.rbegin();
+ if (!writer->WriteVarInt62(iter->Length() - 1)) {
+ set_detailed_error("No room for first ack block in ack frame");
+ return false;
+ }
+ QuicPacketNumber previous_smallest = iter->min();
+ ++iter;
+ // Append remaining ACK blocks.
+ uint64_t appended_ack_blocks = 0;
+ for (; iter != frame.packets.rend(); ++iter) {
+ const uint64_t gap = previous_smallest - iter->max() - 1;
+ const uint64_t ack_range = iter->Length() - 1;
+
+ if (writer->remaining() < ecn_size ||
+ writer->remaining() - ecn_size <
+ QuicDataWriter::GetVarInt62Len(gap) +
+ QuicDataWriter::GetVarInt62Len(ack_range)) {
+ // ACK range does not fit, truncate it.
+ break;
+ }
+ const bool success =
+ writer->WriteVarInt62(gap) && writer->WriteVarInt62(ack_range);
+ DCHECK(success);
+ previous_smallest = iter->min();
+ ++appended_ack_blocks;
+ }
+
+ if (appended_ack_blocks < ack_block_count) {
+ // Truncation is needed, rewrite the ack block count.
+ if (QuicDataWriter::GetVarInt62Len(appended_ack_blocks) !=
+ QuicDataWriter::GetVarInt62Len(ack_block_count) ||
+ !count_writer.WriteVarInt62(appended_ack_blocks)) {
+ // This should never happen as ack_block_count is limited by
+ // max_ack_ranges_.
+ QUIC_BUG << "Ack frame truncation fails. ack_block_count: "
+ << ack_block_count
+ << ", appended count: " << appended_ack_blocks;
+ set_detailed_error("ACK frame truncation fails");
+ return false;
+ }
+ QUIC_DLOG(INFO) << ENDPOINT << "ACK ranges get truncated from "
+ << ack_block_count << " to " << appended_ack_blocks;
+ }
+
if (type == IETF_ACK_ECN) {
- // Encode the ACK ECN fields
+ // Encode the ECN counts.
if (!writer->WriteVarInt62(frame.ect_0_count)) {
set_detailed_error("No room for ect_0_count in ack frame");
return false;
@@ -5465,84 +5463,6 @@
}
}
- uint64_t ack_block_count = frame.packets.NumIntervals();
- if (ack_block_count == 0) {
- // If the QuicAckFrame has no Intervals, then it is interpreted
- // as an ack of a single packet at QuicAckFrame.largest_acked.
- // The resulting ack will consist of only the frame's
- // largest_ack & first_ack_block fields. The first ack block will be 0
- // (indicating a single packet) and the ack block_count will be 0.
- if (!writer->WriteVarInt62(0)) {
- set_detailed_error("No room for ack block count in ack frame");
- return false;
- }
- // size of the first block is 1 packet
- if (!writer->WriteVarInt62(0)) {
- set_detailed_error("No room for first ack block in ack frame");
- return false;
- }
- return true;
- }
- // Case 2 or 3
- auto itr = frame.packets.rbegin();
-
- QuicPacketNumber ack_block_largest(largest_acked);
- QuicPacketNumber ack_block_smallest;
- if ((itr->max() - 1) == QuicPacketNumber(largest_acked)) {
- // If largest_acked + 1 is equal to the Max() of the first Interval
- // in the QuicAckFrame then the first Interval is the first ack block of the
- // frame; remaining Intervals are additional ack blocks. The QuicAckFrame's
- // first Interval is encoded in the frame's largest_acked/first_ack_block,
- // the remaining Intervals are encoded in additional ack blocks in the
- // frame, and the packet's ack_block_count is the number of QuicAckFrame
- // Intervals - 1.
- ack_block_smallest = itr->min();
- itr++;
- ack_block_count--;
- } else {
- // If QuicAckFrame.largest_acked is NOT equal to the Max() of
- // the first Interval then it is interpreted as acking a single
- // packet at QuicAckFrame.largest_acked, with additional
- // Intervals indicating additional ack blocks. The encoding is
- // a) The packet's largest_acked is the QuicAckFrame's largest
- // acked,
- // b) the first ack block size is 0,
- // c) The packet's ack_block_count is the number of QuicAckFrame
- // Intervals, and
- // d) The QuicAckFrame Intervals are encoded in additional ack
- // blocks in the packet.
- ack_block_smallest = largest_acked;
- }
-
- if (!writer->WriteVarInt62(ack_block_count)) {
- set_detailed_error("No room for ack block count in ack frame");
- return false;
- }
-
- uint64_t first_ack_block = ack_block_largest - ack_block_smallest;
- if (!writer->WriteVarInt62(first_ack_block)) {
- set_detailed_error("No room for first ack block in ack frame");
- return false;
- }
-
- // For the remaining QuicAckFrame Intervals, if any
- while (ack_block_count != 0) {
- uint64_t gap_size = ack_block_smallest - itr->max();
- if (!writer->WriteVarInt62(gap_size - 1)) {
- set_detailed_error("No room for gap block in ack frame");
- return false;
- }
-
- uint64_t block_size = itr->max() - itr->min();
- if (!writer->WriteVarInt62(block_size - 1)) {
- set_detailed_error("No room for nth ack block in ack frame");
- return false;
- }
-
- ack_block_smallest = itr->min();
- itr++;
- ack_block_count--;
- }
return true;
}