Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated ACK_FREQUENCY according to draft-ietf-quic-ack-frequency-10 #4670

Merged
merged 32 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d6cde24
added reordering threshold in ack frequency
gaurav2699 Nov 28, 2024
bf614d9
modified log filesd
gaurav2699 Dec 2, 2024
542c781
few refactoring
gaurav2699 Dec 2, 2024
54a90da
minor refactoring
gaurav2699 Dec 2, 2024
8097350
fixed clog
gaurav2699 Dec 2, 2024
e7b4add
fixed clog
gaurav2699 Dec 3, 2024
5fdcc8d
removed IgnoreOrder
gaurav2699 Dec 3, 2024
3f17438
removed IgnoreCE
gaurav2699 Dec 3, 2024
d4ed890
updated names
gaurav2699 Dec 3, 2024
d7d69b8
updated the values
gaurav2699 Dec 3, 2024
93dd676
added logic for reordering
gaurav2699 Dec 4, 2024
4a2c327
removed ignorereordering parameter in connection
gaurav2699 Dec 4, 2024
77474a6
added assert
gaurav2699 Dec 4, 2024
d607245
updated logic for the reordering threshold function
gaurav2699 Dec 4, 2024
7a8cbad
minor change
gaurav2699 Dec 4, 2024
4c0e62a
added unit test
gaurav2699 Dec 5, 2024
6191f1f
added more unit test cases
gaurav2699 Dec 5, 2024
1d1e130
changed the reordering logic
gaurav2699 Dec 11, 2024
4a9aae6
minor refactoring
gaurav2699 Dec 11, 2024
f354d43
minor refactoring
gaurav2699 Dec 12, 2024
2cb10ef
changed variable names
gaurav2699 Dec 15, 2024
5e48229
modified way of implementing to be more optimised
gaurav2699 Dec 16, 2024
d2baaa0
addressed comments
gaurav2699 Dec 17, 2024
95a3533
resolved comments
gaurav2699 Dec 18, 2024
a928db6
modified variable name
gaurav2699 Dec 19, 2024
70b564e
changed the alogrithm logic
gaurav2699 Dec 23, 2024
f53a7fb
resolved comments
gaurav2699 Dec 24, 2024
56f3f00
addressed comments
gaurav2699 Dec 24, 2024
a8f2386
minor change
gaurav2699 Dec 24, 2024
7a37125
minor change to fix the pipeline
gaurav2699 Jan 3, 2025
d94d218
minor change
gaurav2699 Jan 3, 2025
140e052
New Largest Packet Number check shifted
gaurav2699 Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 64 additions & 11 deletions src/core/ack_tracker.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,64 @@
!RangeUpdated;
}

//
// This function implements the logic defined in Section 6.2 [draft-ietf-quic-frequence-10]
// to determine if the reordering threshold has been hit.
//
BOOLEAN
QuicAckTrackerDidHitReorderingThreshold(
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
nibanks marked this conversation as resolved.
Show resolved Hide resolved
_In_ QUIC_ACK_TRACKER* Tracker,
_In_ uint8_t ReorderingThreshold
)
{
if (ReorderingThreshold == 0) {
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
return FALSE;

Check warning on line 110 in src/core/ack_tracker.c

View check run for this annotation

Codecov / codecov/patch

src/core/ack_tracker.c#L110

Added line #L110 was not covered by tests
}

const uint64_t LargestUnacked = QuicRangeGetMax(&Tracker->PacketNumbersToAck);
uint64_t LargestReported = 0; // The largest packet number that could be declared lost

if (Tracker->LargestPacketNumberAcknowledged != 0 &&
Tracker->LargestPacketNumberAcknowledged - ReorderingThreshold + 1 > LargestUnacked) {
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
return FALSE;

Check warning on line 118 in src/core/ack_tracker.c

View check run for this annotation

Codecov / codecov/patch

src/core/ack_tracker.c#L118

Added line #L118 was not covered by tests
}

if (Tracker->LargestPacketNumberAcknowledged >= ReorderingThreshold) {
LargestReported = Tracker->LargestPacketNumberAcknowledged - ReorderingThreshold + 1;
}

//
// Loop through all previous ACK ranges (before last) to find the smallest missing
// packet number that is after the largest reported packet number. If the difference
// between that missing number and the largest unack'ed number is more than the
// reordering threshold, then the condition has been met to send an immediate
// acknowledgement.
//

for (int Index = QuicRangeSize(&Tracker->PacketNumbersToAck) - 1; Index >= 0; --Index) {
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
uint64_t SmallestMissing = 0; // Smallest missing in the previous gap
uint64_t HighestMissing = QuicRangeGet(&Tracker->PacketNumbersToAck, Index)->Low; // Highest missing in the prevous gap
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
if (HighestMissing == 0) {
return FALSE;
}
if (Index != 0) {
SmallestMissing = QuicRangeGetHigh(QuicRangeGet(&Tracker->PacketNumbersToAck, Index - 1)) + 1;
}

if (LargestReported > SmallestMissing) {
if (HighestMissing > LargestReported) {
SmallestMissing = LargestReported;
} else {
return FALSE;
}
}
if (LargestUnacked - SmallestMissing >= ReorderingThreshold) {
return TRUE;
}
}
return FALSE;

Check warning on line 154 in src/core/ack_tracker.c

View check run for this annotation

Codecov / codecov/patch

src/core/ack_tracker.c#L153-L154

Added lines #L153 - L154 were not covered by tests
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
}

_IRQL_requires_max_(DISPATCH_LEVEL)
void
QuicAckTrackerAckPacket(
Expand Down Expand Up @@ -172,7 +230,7 @@

Tracker->AckElicitingPacketsToAcknowledge++;

if (Connection->Send.SendFlags & QUIC_CONN_SEND_FLAG_ACK) {
if ((Connection->Send.SendFlags & QUIC_CONN_SEND_FLAG_ACK) || !NewLargestPacketNumber) {
goto Exit; // Already queued to send an ACK, no more work to do.
}

Expand All @@ -182,10 +240,10 @@
// 1. The packet included an IMMEDIATE_ACK frame.
// 2. ACK delay is disabled (MaxAckDelayMs == 0).
// 3. We have received 'PacketTolerance' ACK eliciting packets.
// 4. We received an ACK eliciting packet that doesn't directly follow the
// previously received packet number. So we assume there might have
// been loss and should indicate this info to the peer. This logic is
// disabled if 'IgnoreReordering' is TRUE.
// 4. We have received an ACK eliciting packet that is out of order and the
// gap between the smallest Unreported Missing packet and the Largest
// Unacked is greater than or equal to the Reordering Threshold value. This logic is
// disabled if the Reordering Threshold is 0.
// 5. The delayed ACK timer fires after the configured time.
//
// If we don't queue an immediate ACK and this is the first ACK eliciting
Expand All @@ -195,12 +253,7 @@
if (AckType == QUIC_ACK_TYPE_ACK_IMMEDIATE ||
Connection->Settings.MaxAckDelayMs == 0 ||
(Tracker->AckElicitingPacketsToAcknowledge >= (uint16_t)Connection->PacketTolerance) ||
(!Connection->State.IgnoreReordering &&
(NewLargestPacketNumber &&
QuicRangeSize(&Tracker->PacketNumbersToAck) > 1 && // There are more than two ranges, i.e. a gap somewhere.
QuicRangeGet(
&Tracker->PacketNumbersToAck,
QuicRangeSize(&Tracker->PacketNumbersToAck) - 1)->Count == 1))) { // The gap is right before the last packet number.
QuicAckTrackerDidHitReorderingThreshold(Tracker, Connection->ReorderingThreshold)) {
//
// Send the ACK immediately.
//
Expand Down
14 changes: 14 additions & 0 deletions src/core/ack_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

--*/

#if defined(__cplusplus)
extern "C" {
#endif

typedef struct QUIC_ACK_TRACKER {

//
Expand Down Expand Up @@ -91,6 +95,12 @@ QuicAckTrackerAddPacketNumber(
_In_ uint64_t PacketNumber
);

BOOLEAN
QuicAckTrackerDidHitReorderingThreshold(
_In_ QUIC_ACK_TRACKER* Tracker,
_In_ uint8_t ReorderingThreshold
);

typedef enum QUIC_ACK_TYPE {
QUIC_ACK_TYPE_NON_ACK_ELICITING,
QUIC_ACK_TYPE_ACK_ELICITING,
Expand Down Expand Up @@ -146,3 +156,7 @@ QuicAckTrackerHasPacketsToAck(
!Tracker->AlreadyWrittenAckFrame &&
QuicRangeSize(&Tracker->PacketNumbersToAck) != 0;
}

#if defined(__cplusplus)
}
#endif
24 changes: 15 additions & 9 deletions src/core/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@
Connection->AckDelayExponent = QUIC_ACK_DELAY_EXPONENT;
Connection->PacketTolerance = QUIC_MIN_ACK_SEND_NUMBER;
Connection->PeerPacketTolerance = QUIC_MIN_ACK_SEND_NUMBER;
Connection->ReorderingThreshold = QUIC_MIN_REORDERING_THRESHOLD;
Connection->PeerReorderingThreshold = QUIC_MIN_REORDERING_THRESHOLD;
Connection->PeerTransportParams.AckDelayExponent = QUIC_TP_ACK_DELAY_EXPONENT_DEFAULT;
Connection->ReceiveQueueTail = &Connection->ReceiveQueue;
QuicSettingsCopy(&Connection->Settings, &MsQuicLib.Settings);
Expand Down Expand Up @@ -5211,12 +5213,12 @@
return FALSE;
}

if (Frame.UpdateMaxAckDelay < MS_TO_US(MsQuicLib.TimerResolutionMs)) {
if (Frame.RequestedMaxAckDelay < MS_TO_US(MsQuicLib.TimerResolutionMs)) {
QuicTraceEvent(
ConnError,
"[conn][%p] ERROR, %s.",
Connection,
"UpdateMaxAckDelay is less than TimerResolution");
"RequestedMaxAckDelay is less than TimerResolution");
QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION);
return FALSE;
}
Expand All @@ -5231,20 +5233,24 @@
}

Connection->NextRecvAckFreqSeqNum = Frame.SequenceNumber + 1;
Connection->State.IgnoreReordering = Frame.IgnoreOrder;
if (Frame.UpdateMaxAckDelay == 0) {
if (Frame.RequestedMaxAckDelay == 0) {
Connection->Settings.MaxAckDelayMs = 0;
} else if (Frame.UpdateMaxAckDelay < 1000) {
} else if (Frame.RequestedMaxAckDelay < 1000) {
Connection->Settings.MaxAckDelayMs = 1;
} else {
CXPLAT_DBG_ASSERT(US_TO_MS(Frame.UpdateMaxAckDelay) <= UINT32_MAX);
Connection->Settings.MaxAckDelayMs = (uint32_t)US_TO_MS(Frame.UpdateMaxAckDelay);
CXPLAT_DBG_ASSERT(US_TO_MS(Frame.RequestedMaxAckDelay) <= UINT32_MAX);
Connection->Settings.MaxAckDelayMs = (uint32_t)US_TO_MS(Frame.RequestedMaxAckDelay);
}
if (Frame.PacketTolerance < UINT8_MAX) {
Connection->PacketTolerance = (uint8_t)Frame.PacketTolerance;
if (Frame.AckElicitingThreshold < UINT8_MAX) {
Connection->PacketTolerance = (uint8_t)Frame.AckElicitingThreshold;
} else {
Connection->PacketTolerance = UINT8_MAX; // Cap to 0xFF for space savings.
}
if (Frame.ReorderingThreshold < UINT8_MAX) {
Connection->ReorderingThreshold = (uint8_t)Frame.ReorderingThreshold;
} else {
Connection->ReorderingThreshold = UINT8_MAX; // Cap to 0xFF for space savings.

Check warning on line 5252 in src/core/connection.c

View check run for this annotation

Codecov / codecov/patch

src/core/connection.c#L5252

Added line #L5252 was not covered by tests
}
QuicTraceLogConnInfo(
UpdatePacketTolerance,
Connection,
Expand Down
21 changes: 15 additions & 6 deletions src/core/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,6 @@ typedef union QUIC_CONNECTION_STATE {
//
BOOLEAN ResumptionEnabled : 1;

//
// When true,acknowledgment that reordering shouldn't elict an
// immediate acknowledgement.
//
BOOLEAN IgnoreReordering : 1;

//
// When true, this indicates that the connection is currently executing
// an API call inline (from a reentrant call on a callback).
Expand Down Expand Up @@ -453,6 +447,21 @@ typedef struct QUIC_CONNECTION {
//
uint8_t PeerPacketTolerance;

//
// The maximum number of packets that can be out of order before an immediate
// acknowledgment (ACK) is triggered. If no specific instructions (ACK_FREQUENCY
// frames) are received from the peer, the receiver will immediately acknowledge
// any out-of-order packets, which means the default value is 1. A value of 0
// means out-of-order packets do not trigger an immediate ACK.
//
uint8_t ReorderingThreshold;
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved

//
// The maximum number of packets that the peer can be out of order before an immediate
// acknowledgment (ACK) is triggered.
//
uint8_t PeerReorderingThreshold;
nibanks marked this conversation as resolved.
Show resolved Hide resolved

//
// The ACK frequency sequence number we are currently using to send.
//
Expand Down
2 changes: 1 addition & 1 deletion src/core/crypto_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ typedef enum eSniNameType {
#define QUIC_TP_ID_MAX_DATAGRAM_FRAME_SIZE 32 // varint
#define QUIC_TP_ID_DISABLE_1RTT_ENCRYPTION 0xBAAD // N/A
#define QUIC_TP_ID_VERSION_NEGOTIATION_EXT 0x11 // Blob
#define QUIC_TP_ID_MIN_ACK_DELAY 0xFF03DE1AULL // varint
#define QUIC_TP_ID_MIN_ACK_DELAY 0xFF04DE1BULL // varint
#define QUIC_TP_ID_CIBIR_ENCODING 0x1000 // {varint, varint}
#define QUIC_TP_ID_GREASE_QUIC_BIT 0x2AB2 // N/A
#define QUIC_TP_ID_RELIABLE_RESET_ENABLED 0x17f7586d2cb570 // varint
Expand Down
52 changes: 14 additions & 38 deletions src/core/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -1234,19 +1234,6 @@ QuicDatagramFrameDecode(
return TRUE;
}

typedef struct QUIC_ACK_FREQUENCY_EXTRAS {

union {
struct {
uint8_t IgnoreOrder : 1;
uint8_t IgnoreCE : 1;
uint8_t Reserved : 6;
};
uint8_t Value;
};

} QUIC_ACK_FREQUENCY_EXTRAS;

_Success_(return != FALSE)
BOOLEAN
QuicAckFrequencyFrameEncode(
Expand All @@ -1259,27 +1246,20 @@ QuicAckFrequencyFrameEncode(
uint16_t RequiredLength =
QuicVarIntSize(QUIC_FRAME_ACK_FREQUENCY) +
QuicVarIntSize(Frame->SequenceNumber) +
QuicVarIntSize(Frame->PacketTolerance) +
QuicVarIntSize(Frame->UpdateMaxAckDelay) +
sizeof(QUIC_ACK_FREQUENCY_EXTRAS);
QuicVarIntSize(Frame->AckElicitingThreshold) +
QuicVarIntSize(Frame->RequestedMaxAckDelay) +
QuicVarIntSize(Frame->ReorderingThreshold);

if (BufferLength < *Offset + RequiredLength) {
return FALSE;
}

CXPLAT_DBG_ASSERT(Frame->IgnoreOrder <= 1); // IgnoreOrder should only be 0 or 1.
CXPLAT_DBG_ASSERT(Frame->IgnoreCE <= 1); // IgnoreCE should only be 0 or 1.

QUIC_ACK_FREQUENCY_EXTRAS Extras = { .Value = 0 };
Extras.IgnoreOrder = Frame->IgnoreOrder;
Extras.IgnoreCE = Frame->IgnoreCE;

Buffer = Buffer + *Offset;
Buffer = QuicVarIntEncode(QUIC_FRAME_ACK_FREQUENCY, Buffer);
Buffer = QuicVarIntEncode(Frame->SequenceNumber, Buffer);
Buffer = QuicVarIntEncode(Frame->PacketTolerance, Buffer);
Buffer = QuicVarIntEncode(Frame->UpdateMaxAckDelay, Buffer);
QuicUint8Encode(Extras.Value, Buffer);
Buffer = QuicVarIntEncode(Frame->AckElicitingThreshold, Buffer);
Buffer = QuicVarIntEncode(Frame->RequestedMaxAckDelay, Buffer);
Buffer = QuicVarIntEncode(Frame->ReorderingThreshold, Buffer);
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
*Offset += RequiredLength;

return TRUE;
Expand All @@ -1295,15 +1275,12 @@ QuicAckFrequencyFrameDecode(
_Out_ QUIC_ACK_FREQUENCY_EX* Frame
)
{
QUIC_ACK_FREQUENCY_EXTRAS Extras;
if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->SequenceNumber) ||
!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->PacketTolerance) ||
!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->UpdateMaxAckDelay) ||
!QuicUint8tDecode(BufferLength, Buffer, Offset, &Extras.Value)) {
!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->AckElicitingThreshold) ||
!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->RequestedMaxAckDelay) ||
!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->ReorderingThreshold)) {
return FALSE;
}
Frame->IgnoreOrder = Extras.IgnoreOrder;
Frame->IgnoreCE = Extras.IgnoreCE;
return TRUE;
}

Expand Down Expand Up @@ -1963,15 +1940,14 @@ QuicFrameLog(

QuicTraceLogVerbose(
FrameLogAckFrequency,
"[%c][%cX][%llu] ACK_FREQUENCY SeqNum:%llu PktTolerance:%llu MaxAckDelay:%llu IgnoreOrder:%hhu IgnoreCE:%hhu",
"[%c][%cX][%llu] ACK_FREQUENCY SeqNum:%llu AckElicitThreshold:%llu MaxAckDelay:%llu ReorderThreshold:%llu",
PtkConnPre(Connection),
PktRxPre(Rx),
PacketNumber,
Frame.SequenceNumber,
Frame.PacketTolerance,
Frame.UpdateMaxAckDelay,
Frame.IgnoreOrder,
Frame.IgnoreCE);
Frame.AckElicitingThreshold,
Frame.RequestedMaxAckDelay,
Frame.ReorderingThreshold);
break;
}

Expand Down Expand Up @@ -2006,7 +1982,7 @@ QuicFrameLog(
Frame.Timestamp);
break;
}

case QUIC_FRAME_RELIABLE_RESET_STREAM: {
QUIC_RELIABLE_RESET_STREAM_EX Frame;
if (!QuicReliableResetFrameDecode(PacketLength, Packet, Offset, &Frame)) {
Expand Down
10 changes: 4 additions & 6 deletions src/core/frame.h
gaurav2699 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ typedef enum QUIC_FRAME_TYPE {
QUIC_FRAME_DATAGRAM_1 = 0x31ULL,
/* 0x32 to 0xad are unused currently */
QUIC_FRAME_ACK_FREQUENCY = 0xafULL,
QUIC_FRAME_IMMEDIATE_ACK = 0xacULL,
QUIC_FRAME_IMMEDIATE_ACK = 0x1fULL,
/* 0xaf to 0x2f4 are unused currently */
QUIC_FRAME_TIMESTAMP = 0x2f5ULL,

Expand Down Expand Up @@ -844,11 +844,9 @@ QuicDatagramFrameDecode(
typedef struct QUIC_ACK_FREQUENCY_EX {

QUIC_VAR_INT SequenceNumber;
QUIC_VAR_INT PacketTolerance;
QUIC_VAR_INT UpdateMaxAckDelay; // In microseconds (us)
BOOLEAN IgnoreOrder;
BOOLEAN IgnoreCE;

QUIC_VAR_INT AckElicitingThreshold;
QUIC_VAR_INT RequestedMaxAckDelay; // In microseconds (us)
QUIC_VAR_INT ReorderingThreshold;
} QUIC_ACK_FREQUENCY_EX;

_Success_(return != FALSE)
Expand Down
6 changes: 6 additions & 0 deletions src/core/quicdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ typedef struct QUIC_RX_PACKET QUIC_RX_PACKET;
//
#define QUIC_MIN_ACK_SEND_NUMBER 2

//
// The value for Reordering threshold when no ACK_FREQUENCY frame is received.
// This means that the receiver will immediately acknowledge any out-of-order packets.
//
#define QUIC_MIN_REORDERING_THRESHOLD 1

//
// The size of the stateless reset token.
//
Expand Down
7 changes: 3 additions & 4 deletions src/core/send.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,10 +894,9 @@ QuicSendWriteFrames(

QUIC_ACK_FREQUENCY_EX Frame;
Frame.SequenceNumber = Connection->SendAckFreqSeqNum;
Frame.PacketTolerance = Connection->PeerPacketTolerance;
Frame.UpdateMaxAckDelay = MS_TO_US(QuicConnGetAckDelay(Connection));
Frame.IgnoreOrder = FALSE;
Frame.IgnoreCE = FALSE;
Frame.AckElicitingThreshold = Connection->PeerPacketTolerance;
Frame.RequestedMaxAckDelay = MS_TO_US(QuicConnGetAckDelay(Connection));
Frame.ReorderingThreshold = Connection->PeerReorderingThreshold;

if (QuicAckFrequencyFrameEncode(
&Frame,
Expand Down
Loading
Loading