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

feat: ack receiver timestamps #1992

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

sterlingdeng
Copy link

@sterlingdeng sterlingdeng commented Sep 19, 2024

This PR is the implementation that addresses #1988

Manual E2E Testing/Validation instructions: sterlingdeng#2

Surfaces the TransportParameters to the application
Adds ReceiverTimestamps data structure to the space and expose methods.
This commit processes the inbound ACK frames that contain timestamps.
This commit handles sending frames that contain timestamps
Surfaces timing information to the CC interface.
@djc
Copy link
Member

djc commented Sep 20, 2024

I don't think a feature makes sense for this, what's the motivation for that? Suggest squashing all of these commits because I don't think they make much sense on their own.

@billylindeman
Copy link

@djc I suggested using a feature bc it is a draft specification, perhaps we should name the feature after the specification draft-smith-quic-receive-ts https://www.ietf.org/archive/id/draft-smith-quic-receive-ts-00.html

@djc
Copy link
Member

djc commented Sep 21, 2024

@djc I suggested using a feature bc it is a draft specification, perhaps we should name the feature after the specification draft-smith-quic-receive-ts https://www.ietf.org/archive/id/draft-smith-quic-receive-ts-00.html

I don't think that's a good reason to make it a feature. The current API surface will still become part of our public API, and it just adds a bunch of complexity. We've added draft functionality before, should be fine.

@sterlingdeng
Copy link
Author

I can remove the feature flag in a follow up commit. Regarding squashing, my intention for the commits were to keep separate different parts of the PR for review and then squash at the end. If you want me to squash it now, I can do that too.

@djc
Copy link
Member

djc commented Sep 24, 2024

I can remove the feature flag in a follow up commit. Regarding squashing, my intention for the commits were to keep separate different parts of the PR for review and then squash at the end. If you want me to squash it now, I can do that too.

While we are fans of clean commit histories with atomic commits, I think this falls short of that because the commits are not conceptually independent -- it doesn't make sense to add configuration that doesn't do anything, for example.

@sterlingdeng sterlingdeng changed the title Receiver Timestamps feat: ack receiver timestamps Sep 26, 2024
Copy link
Member

@djc djc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a bunch of mostly stylistic feedback.

quinn-proto/src/config.rs Outdated Show resolved Hide resolved
@@ -34,6 +34,20 @@ pub trait Controller: Send + Sync {
) {
}

#[allow(unused_variables)]
/// Packet deliveries were confirmed with timestamps information.
fn on_ack_packet(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these actually changes you'd look to make to the on_ack() interface which you're adding a separate method for to keep it semver-compatible?

If so, should this default implementation call self.on_ack()?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I did it this way to prevent any breaking changes if there were users of the on_ack method. Yea, I think it makes sense for the default implementation to all self.on_ack, and then we can remove the congestion.on_ack call from on_packet_acked and just have it call congestion.on_ack_packet.

quinn-proto/src/connection/mod.rs Outdated Show resolved Hide resolved
quinn-proto/src/connection/mod.rs Outdated Show resolved Hide resolved
quinn-proto/src/connection/mod.rs Outdated Show resolved Hide resolved
quinn-proto/src/frame.rs Outdated Show resolved Hide resolved
quinn-proto/src/frame.rs Outdated Show resolved Hide resolved
self.next_pn -= 1;
}

let delta = self.data.get_var().unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this safe?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the same pattern done on AckIter, where unwrap is used.
I think it's considered safe because this is defined in the spec. If the value is expected to be a VARINT based on the spec but it isn't, we wouldn't be able to proceed in processing the packet.
Another option is to change the return type to be a tuple that includes an error.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't include a SAFETY comment here because the others didn't have them either.

quinn-proto/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines 170 to 179
receive_timestamps_exponent: config
.ack_timestamp_config
.as_ref()
.map(|cfg| cfg.exponent),

max_recv_timestamps_per_ack: config
.ack_timestamp_config
.as_ref()
.map(|cfg| cfg.max_timestamps_per_ack),

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these maybe shouldn't be separate Options, but a tuple wrapped in a single Option?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file, rather than using two individual parameters on the TransportParameters struct, I'm using the AckTimestampConfig and making max_timestamps_per_ack an Option. None signaling that the feature is disabled.
Exponent defaults to 0, which is what the spec states.

It could be worth proposing for the draft that the transport parameters related to this feature are grouped together similar to how PreferredAddress does it.

@@ -343,6 +347,7 @@ pub struct Ack {
pub delay: u64,
pub additional: Bytes,
pub ecn: Option<EcnCounts>,
pub timestamps: Option<Bytes>,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I experimented on having a separate struct for AckWithTimestamps, but the primary function, on_ack_received, that uses Ack is complex and it was easier to just add the timestamps here.

Comment on lines 170 to 179
receive_timestamps_exponent: config
.ack_timestamp_config
.as_ref()
.map(|cfg| cfg.exponent),

max_recv_timestamps_per_ack: config
.ack_timestamp_config
.as_ref()
.map(|cfg| cfg.max_timestamps_per_ack),

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file, rather than using two individual parameters on the TransportParameters struct, I'm using the AckTimestampConfig and making max_timestamps_per_ack an Option. None signaling that the feature is disabled.
Exponent defaults to 0, which is what the spec states.

It could be worth proposing for the draft that the transport parameters related to this feature are grouped together similar to how PreferredAddress does it.

self.next_pn -= 1;
}

let delta = self.data.get_var().unwrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the same pattern done on AckIter, where unwrap is used.
I think it's considered safe because this is defined in the spec. If the value is expected to be a VARINT based on the spec but it isn't, we wouldn't be able to proceed in processing the packet.
Another option is to change the return type to be a tuple that includes an error.

quinn-proto/src/frame.rs Outdated Show resolved Hide resolved
@@ -34,6 +34,20 @@ pub trait Controller: Send + Sync {
) {
}

#[allow(unused_variables)]
/// Packet deliveries were confirmed with timestamps information.
fn on_ack_packet(
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I did it this way to prevent any breaking changes if there were users of the on_ack method. Yea, I think it makes sense for the default implementation to all self.on_ack, and then we can remove the congestion.on_ack call from on_packet_acked and just have it call congestion.on_ack_packet.

fn new(largest: u64, basis_instant: Instant, exponent: u64, mut data: &'a [u8]) -> Self {
// We read and throw away the Timestamp Range Count value because
// it was already used to properly slice the data.
let _ = data.get_var().unwrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unwrap is safe because the data byte slice was sliced using scan_ack_timestamp_blocks, which this get_var() was checked using ?.

self.next_pn -= 1;
}

let delta = self.data.get_var().unwrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't include a SAFETY comment here because the others didn't have them either.

fn new(largest: u64, basis_instant: Instant, exponent: u64, mut data: &'a [u8]) -> Self {
// We read and throw away the Timestamp Range Count value because
// it was already used to properly slice the data.
let _ = data.get_var().unwrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a safety comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants