Skip to content

Commit 763d75d

Browse files
committed
feat(transport): update ack frequency draft from 00 to 10
1 parent a7e2fb0 commit 763d75d

File tree

7 files changed

+137
-47
lines changed

7 files changed

+137
-47
lines changed

neqo-transport/src/ackrate.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
// option. This file may not be copied, modified, or distributed
55
// except according to those terms.
66

7-
// Management of the peer's ack rate.
7+
//! Local node (i.e. data sender and ack receiver) managing the remote node's
8+
//! (i.e. data receiver and ack sender) ack rate.
9+
//!
10+
//! Implementation of QUIC Acknowledgment Frequency draft 10.
11+
//!
12+
//! <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html>
13+
//!
14+
//! See [`crate::tracking::RecvdPackets`] for data receiver side.
815
916
use std::{cmp::max, time::Duration};
1017

@@ -47,7 +54,14 @@ impl AckRate {
4754
seqno,
4855
u64::try_from(self.packets + 1).unwrap(),
4956
u64::try_from(self.delay.as_micros()).unwrap(),
50-
0,
57+
// > If no ACK_FREQUENCY frames have been received, the data receiver
58+
// > immediately acknowledges any subsequent packets that are received
59+
// > out-of-order, as specified in Section 13.2 of [QUIC-TRANSPORT],
60+
// > corresponding to a default value of 1. A value of 0 indicates
61+
// > out-of-order packets do not elicit an immediate ACK.
62+
//
63+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
64+
1,
5165
])
5266
}
5367

@@ -134,6 +148,7 @@ impl FlexibleAckRate {
134148
}
135149
}
136150

151+
// TODO: Rename to PeerAckFrequency
137152
#[derive(Debug, Clone)]
138153
pub enum PeerAckDelay {
139154
Fixed(Duration),

neqo-transport/src/connection/mod.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -2896,6 +2896,13 @@ impl Connection {
28962896
self.stats.borrow_mut().frame_rx.ping += 1;
28972897
self.crypto.resend_unacked(space);
28982898
// Send an ACK immediately if we might not otherwise do so.
2899+
//
2900+
// TODO: Ackording to ack frequency draft, only
2901+
// IMMEDIATE_ACK_FRAME will send immediate ack, not ping frame.
2902+
// Maybe do so anyways? Or only if peer did not advertise
2903+
// support via transport parameter?
2904+
//
2905+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-5>
28992906
self.acks.immediate_ack(space, now);
29002907
}
29012908
Frame::Ack {
@@ -3029,17 +3036,31 @@ impl Connection {
30293036
}
30303037
Frame::AckFrequency {
30313038
seqno,
3032-
tolerance,
3039+
ack_eliciting_threshold: tolerance,
30333040
delay,
3034-
ignore_order,
3041+
reordering_threshold,
30353042
} => {
30363043
self.stats.borrow_mut().frame_rx.ack_frequency += 1;
3044+
// > The value of this field is in microseconds, unlike the
3045+
// > max_ack_delay transport parameter, which is in milliseconds.
3046+
//
3047+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
30373048
let delay = Duration::from_micros(delay);
30383049
if delay < GRANULARITY {
3050+
// > A value smaller than the min_ack_delay advertised by
3051+
// > the peer is also invalid. Receipt of an invalid value
3052+
// > MUST be treated as a connection error of type
3053+
// > PROTOCOL_VIOLATION.
3054+
//
3055+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
30393056
return Err(Error::ProtocolViolation);
30403057
}
30413058
self.acks
3042-
.ack_freq(seqno, tolerance - 1, delay, ignore_order);
3059+
.ack_freq(seqno, tolerance - 1, delay, reordering_threshold);
3060+
}
3061+
Frame::ImmediateAck {} => {
3062+
self.stats.borrow_mut().frame_rx.immediate_ack += 1;
3063+
self.acks.immediate_ack(space, now);
30433064
}
30443065
Frame::Datagram { data, .. } => {
30453066
self.stats.borrow_mut().frame_rx.datagram += 1;

neqo-transport/src/frame.rs

+36-18
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,14 @@ pub const FRAME_TYPE_PATH_RESPONSE: FrameType = 0x1b;
4848
pub const FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT: FrameType = 0x1c;
4949
pub const FRAME_TYPE_CONNECTION_CLOSE_APPLICATION: FrameType = 0x1d;
5050
pub const FRAME_TYPE_HANDSHAKE_DONE: FrameType = 0x1e;
51-
// draft-ietf-quic-ack-delay
51+
/// > A data sender signals the conditions under which it wants to receive ACK
52+
/// > frames using an ACK_FREQUENCY frame
53+
///
54+
/// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
5255
pub const FRAME_TYPE_ACK_FREQUENCY: FrameType = 0xaf;
56+
// TODO: Use
57+
/// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
58+
pub const FRAME_IMMEDIATE_ACK: FrameType = 0x1f;
5359
// draft-ietf-quic-datagram
5460
pub const FRAME_TYPE_DATAGRAM: FrameType = 0x30;
5561
pub const FRAME_TYPE_DATAGRAM_WITH_LEN: FrameType = 0x31;
@@ -189,18 +195,30 @@ pub enum Frame<'a> {
189195
reason_phrase: String,
190196
},
191197
HandshakeDone,
198+
/// > A data sender signals the conditions under which it wants to receive
199+
/// > ACK frames using an ACK_FREQUENCY frame
200+
///
201+
/// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
192202
AckFrequency {
193-
/// The current ACK frequency sequence number.
203+
/// > the sequence number assigned to the ACK_FREQUENCY frame by the
204+
/// > sender so receivers ignore obsolete frames.
194205
seqno: u64,
195-
/// The number of contiguous packets that can be received without
196-
/// acknowledging immediately.
197-
tolerance: u64,
198-
/// The time to delay after receiving the first packet that is
199-
/// not immediately acknowledged.
206+
/// > the maximum number of ack-eliciting packets the recipient of this
207+
/// > frame receives before sending an acknowledgment.
208+
ack_eliciting_threshold: u64,
209+
/// > the value to which the data sender requests the data receiver
210+
/// > update its max_ack_delay
200211
delay: u64,
201-
/// Ignore reordering when deciding to immediately acknowledge.
202-
ignore_order: bool,
212+
/// > the maximum packet reordering before eliciting an immediate ACK, as
213+
/// > specified in Section 6.2. If no ACK_FREQUENCY frames have been
214+
/// > received, the data receiver immediately acknowledges any subsequent
215+
/// > packets that are received out-of-order, as specified in Section 13.2
216+
/// > of [QUIC-TRANSPORT], corresponding to a default value of 1. A value
217+
/// > of 0 indicates out-of-order packets do not elicit an immediate ACK.
218+
reordering_threshold: u64,
203219
},
220+
/// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-5>
221+
ImmediateAck,
204222
Datagram {
205223
data: &'a [u8],
206224
fill: bool,
@@ -255,6 +273,7 @@ impl<'a> Frame<'a> {
255273
}
256274
Self::HandshakeDone => FRAME_TYPE_HANDSHAKE_DONE,
257275
Self::AckFrequency { .. } => FRAME_TYPE_ACK_FREQUENCY,
276+
Self::ImmediateAck {} => FRAME_IMMEDIATE_ACK,
258277
Self::Datagram { fill, .. } => {
259278
if *fill {
260279
FRAME_TYPE_DATAGRAM
@@ -622,25 +641,24 @@ impl<'a> Frame<'a> {
622641
})
623642
}
624643
FRAME_TYPE_HANDSHAKE_DONE => Ok(Self::HandshakeDone),
644+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-4>
625645
FRAME_TYPE_ACK_FREQUENCY => {
626646
let seqno = dv(dec)?;
627647
let tolerance = dv(dec)?;
628648
if tolerance == 0 {
629649
return Err(Error::FrameEncodingError);
630650
}
631651
let delay = dv(dec)?;
632-
let ignore_order = match d(dec.decode_uint::<u8>())? {
633-
0 => false,
634-
1 => true,
635-
_ => return Err(Error::FrameEncodingError),
636-
};
652+
let reordering_threshold = dv(dec)?;
637653
Ok(Self::AckFrequency {
638654
seqno,
639-
tolerance,
655+
ack_eliciting_threshold: tolerance,
640656
delay,
641-
ignore_order,
657+
reordering_threshold,
642658
})
643659
}
660+
// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-5>
661+
FRAME_IMMEDIATE_ACK => Ok(Self::ImmediateAck {}),
644662
FRAME_TYPE_DATAGRAM | FRAME_TYPE_DATAGRAM_WITH_LEN => {
645663
let fill = (t & DATAGRAM_FRAME_BIT_LEN) == 0;
646664
let data = if fill {
@@ -981,9 +999,9 @@ mod tests {
981999
fn ack_frequency() {
9821000
let f = Frame::AckFrequency {
9831001
seqno: 10,
984-
tolerance: 5,
1002+
ack_eliciting_threshold: 5,
9851003
delay: 2000,
986-
ignore_order: true,
1004+
reordering_threshold: 1,
9871005
};
9881006
just_dec(&f, "40af0a0547d001");
9891007
}

neqo-transport/src/qlog.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ impl From<Frame<'_>> for QuicFrame {
582582
trigger_frame_type: Some(frame_type),
583583
},
584584
Frame::HandshakeDone => Self::HandshakeDone,
585-
Frame::AckFrequency { .. } => Self::Unknown {
585+
Frame::AckFrequency { .. } | Frame::ImmediateAck { .. } => Self::Unknown {
586586
frame_type_value: None,
587587
raw_frame_type: frame.get_type(),
588588
raw: None,

neqo-transport/src/stats.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct FrameStats {
5353
pub new_token: usize,
5454

5555
pub ack_frequency: usize,
56+
pub immediate_ack: usize,
5657
pub datagram: usize,
5758
}
5859

@@ -92,7 +93,11 @@ impl Debug for FrameStats {
9293
self.path_challenge,
9394
self.path_response,
9495
)?;
95-
writeln!(f, " ack_frequency {}", self.ack_frequency)
96+
writeln!(
97+
f,
98+
" ack_frequency {}, immediate_ack {}",
99+
self.ack_frequency, self.immediate_ack
100+
)
96101
}
97102
}
98103

neqo-transport/src/tparams.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,17 @@ pub const INITIAL_SOURCE_CONNECTION_ID: TransportParameterId = 0x0f;
4747
pub const RETRY_SOURCE_CONNECTION_ID: TransportParameterId = 0x10;
4848
pub const VERSION_INFORMATION: TransportParameterId = 0x11;
4949
pub const GREASE_QUIC_BIT: TransportParameterId = 0x2ab2;
50-
pub const MIN_ACK_DELAY: TransportParameterId = 0xff02_de1a;
50+
/// QUIC Ack Frequency draft 10
51+
///
52+
/// > A variable-length integer representing the minimum amount of time, in
53+
/// > microseconds, that the endpoint sending this value is willing to delay an
54+
/// > acknowledgment. This limit could be based on the data receiver's clock or
55+
/// > timer granularity. min_ack_delay is used by the data sender to avoid
56+
/// > requesting too small a value in the Requested Max Ack Delay field of the
57+
/// > ACK_FREQUENCY frame.
58+
///
59+
/// <https://www.ietf.org/archive/id/draft-ietf-quic-ack-frequency-10.html#section-3>
60+
pub const MIN_ACK_DELAY: TransportParameterId = 0xff04_de1b;
5161
pub const MAX_DATAGRAM_FRAME_SIZE: TransportParameterId = 0x0020;
5262

5363
#[derive(Clone, Debug)]

0 commit comments

Comments
 (0)