Skip to content

Commit a5502f5

Browse files
keep track of the local and remote max path id (#63)
* make transport config and transport parameters uniform * remove comment from docs * keep track of the local and remote max path ids * add constant * clippy fixes
1 parent ab977d6 commit a5502f5

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

quinn-proto/src/config/transport.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{fmt, sync::Arc};
22

33
use crate::{
4-
Duration, INITIAL_MTU, MAX_UDP_PAYLOAD, VarInt, VarIntBoundsExceeded, address_discovery,
5-
congestion,
4+
Duration, INITIAL_MTU, MAX_UDP_PAYLOAD, PathId, VarInt, VarIntBoundsExceeded,
5+
address_discovery, congestion,
66
};
77

88
/// Parameters governing the core QUIC state machine
@@ -49,7 +49,7 @@ pub struct TransportConfig {
4949

5050
pub(crate) address_discovery_role: address_discovery::Role,
5151

52-
pub(crate) initial_max_path_id: Option<u32>,
52+
pub(crate) initial_max_path_id: Option<PathId>,
5353
}
5454

5555
impl TransportConfig {
@@ -355,7 +355,7 @@ impl TransportConfig {
355355
// this as max_concurrent_multipath_paths a bit like max_concurrent_bidi_streams etc
356356
// exist now. But this will do for now.
357357
pub fn initial_max_path_id(&mut self, value: Option<u32>) -> &mut Self {
358-
self.initial_max_path_id = value;
358+
self.initial_max_path_id = value.map(Into::into);
359359
self
360360
}
361361
}

quinn-proto/src/connection/mod.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ pub struct Connection {
148148
/// This needs to be ordered because [`Connection::poll_transmit`] needs to
149149
/// deterministically select the next PathId to send on.
150150
///
151-
/// TODO(flub): well does it really? But deterministic is nice for now.
151+
// TODO(flub): well does it really? But deterministic is nice for now.
152152
paths: BTreeMap<PathId, PathState>,
153153
/// Whether MTU detection is supported in this environment
154154
allow_mtud: bool,
@@ -244,6 +244,20 @@ pub struct Connection {
244244
stats: ConnectionStats,
245245
/// QUIC version used for the connection.
246246
version: u32,
247+
248+
/// Local maximum [`PathId`] to be used.
249+
///
250+
/// This is initially set to [`TransportConfig::initial_max_path_id`] when multipath is enabled, or to
251+
/// [`PathId::ZERO`] otherwise.
252+
// TODO(@divma): we probably need an API to imcrease upon the original value
253+
local_max_path_id: PathId,
254+
255+
/// Remote's maximum [`PathId`] to be used.
256+
///
257+
/// This is initially set to the peer's [`TransportParameters::initial_max_path_id`] when
258+
/// multipath is enabled, or to [`PathId::ZERO`] otherwise. A peer may increase this limit by
259+
/// sending [`Frame::MaxPathId`] frames.
260+
remote_max_path_id: PathId,
247261
}
248262

249263
struct PathState {
@@ -377,6 +391,9 @@ impl Connection {
377391
rng,
378392
stats: ConnectionStats::default(),
379393
version,
394+
// peer params are not yet known, so multipath is not enabled
395+
local_max_path_id: PathId::ZERO,
396+
remote_max_path_id: PathId::ZERO,
380397
};
381398
if path_validated {
382399
this.on_path_validated(PathId(0));
@@ -2894,9 +2911,7 @@ impl Connection {
28942911

28952912
// Multipath can only be enabled after the state has reached Established.
28962913
// So this can not happen any earlier.
2897-
if self.is_multipath_enabled() {
2898-
self.issue_first_path_cids(now);
2899-
}
2914+
self.issue_first_path_cids(now);
29002915
Ok(())
29012916
}
29022917
Header::Initial(InitialHeader {
@@ -3396,8 +3411,15 @@ impl Connection {
33963411
Frame::PathAvailable(_) => {
33973412
// TODO(@divma): do stuff
33983413
}
3399-
Frame::MaxPathId(_) => {
3400-
// TODO(@divma): do stuff
3414+
Frame::MaxPathId(path_id) => {
3415+
if self.is_multipath_enabled() {
3416+
// frames that do not increase the path id are ignored
3417+
self.remote_max_path_id = self.remote_max_path_id.max(path_id);
3418+
} else {
3419+
return Err(TransportError::PROTOCOL_VIOLATION(
3420+
"received MAX_PATH_ID frame when not multipath was not negotiated",
3421+
));
3422+
}
34013423
}
34023424
Frame::PathsBlocked(_) => {
34033425
// TODO(@divma): do stuff
@@ -3566,14 +3588,14 @@ impl Connection {
35663588
.push_back(EndpointEventInner::NeedIdentifiers(PathId(0), now, n));
35673589
}
35683590

3569-
/// Issues an initial set of CIDs to the peer for PathId > 0
3591+
/// Issues an initial set of CIDs to the peer for PathId > 0; CIDs for [`PathId::ZERO`] are
3592+
/// issued earlier in the connection process.
35703593
// TODO(flub): Whenever we close paths we need to issue new CIDs as well. Once we do
35713594
// that we probably want to re-use this function but with a max_path_id parameter or
35723595
// something.
35733596
fn issue_first_path_cids(&mut self, now: Instant) {
3574-
debug_assert!(self.is_multipath_enabled());
3575-
if let Some(max_path_id) = self.config.initial_max_path_id {
3576-
for n in 1..(max_path_id + 1) {
3597+
if let Some(PathId(max_path_id)) = self.max_path_id() {
3598+
for n in 1..=max_path_id {
35773599
self.endpoint_events
35783600
.push_back(EndpointEventInner::NeedIdentifiers(
35793601
PathId(n),
@@ -4072,6 +4094,15 @@ impl Connection {
40724094
self.set_reset_token(remote, info.stateless_reset_token);
40734095
}
40744096
self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params);
4097+
4098+
if let (Some(local_max_path_id), Some(remote_max_path_id)) =
4099+
(self.config.initial_max_path_id, params.initial_max_path_id)
4100+
{
4101+
// multipath is enabled, register the local and remote maximums
4102+
self.local_max_path_id = local_max_path_id;
4103+
self.remote_max_path_id = remote_max_path_id;
4104+
}
4105+
40754106
self.peer_params = params;
40764107
let peer_max_udp_payload_size =
40774108
u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
@@ -4411,6 +4442,18 @@ impl Connection {
44114442
new_tokens.push(remote_addr);
44124443
}
44134444
}
4445+
4446+
/// Returns the maximum [`PathId`] to be used in this connection.
4447+
///
4448+
/// This is calculated as minimum between the local and remote's maximums when multipath is
4449+
/// enabled, or `None` when disabled.
4450+
fn max_path_id(&self) -> Option<PathId> {
4451+
if self.is_multipath_enabled() {
4452+
Some(self.remote_max_path_id.min(self.local_max_path_id))
4453+
} else {
4454+
None
4455+
}
4456+
}
44144457
}
44154458

44164459
impl fmt::Debug for Connection {

quinn-proto/src/connection/paths.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ impl PathId {
3333
/// The maximum path ID allowed.
3434
pub const MAX: Self = Self(u32::MAX);
3535

36+
/// The 0 path id.
37+
pub const ZERO: Self = Self(0);
38+
3639
pub(crate) fn size(&self) -> usize {
3740
VarInt(self.0 as u64).size()
3841
}

quinn-proto/src/transport_parameters.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,7 @@ impl TransportParameters {
191191
order
192192
}),
193193
address_discovery_role: config.address_discovery_role,
194-
// TODO(@divma): TransportConfig or..?
195-
initial_max_path_id: config.initial_max_path_id.map(PathId::from),
194+
initial_max_path_id: config.initial_max_path_id,
196195
..Self::default()
197196
}
198197
}

0 commit comments

Comments
 (0)