From 350fd9f571898f003406b1a55152e48ff8719064 Mon Sep 17 00:00:00 2001 From: Diva M Date: Thu, 16 Jan 2025 09:12:11 -0500 Subject: [PATCH] add transport parameter --- quinn-proto/src/config/transport.rs | 18 +++++++++++-- quinn-proto/src/transport_parameters.rs | 36 ++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/quinn-proto/src/config/transport.rs b/quinn-proto/src/config/transport.rs index b85cb5884..23fe22fc7 100644 --- a/quinn-proto/src/config/transport.rs +++ b/quinn-proto/src/config/transport.rs @@ -1,8 +1,8 @@ use std::{fmt, sync::Arc}; use crate::{ - address_discovery, congestion, Duration, VarInt, VarIntBoundsExceeded, INITIAL_MTU, - MAX_UDP_PAYLOAD, + address_discovery, congestion, connection::PathId, Duration, VarInt, VarIntBoundsExceeded, + INITIAL_MTU, MAX_UDP_PAYLOAD, }; /// Parameters governing the core QUIC state machine @@ -48,6 +48,8 @@ pub struct TransportConfig { pub(crate) enable_segmentation_offload: bool, pub(crate) address_discovery_role: address_discovery::Role, + + pub(crate) initial_max_path_id: Option, } impl TransportConfig { @@ -340,6 +342,13 @@ impl TransportConfig { .receive_reports_from_peers(enabled); self } + + /// DOCS :D + // TODO(@divma): decent docs, talk about multipath, reference draft. + pub fn initial_max_path_id(&mut self, value: Option) -> &mut Self { + self.initial_max_path_id = value; + self + } } impl Default for TransportConfig { @@ -382,6 +391,9 @@ impl Default for TransportConfig { enable_segmentation_offload: true, address_discovery_role: address_discovery::Role::default(), + + // disabled multipath by default + initial_max_path_id: None, } } } @@ -414,6 +426,7 @@ impl fmt::Debug for TransportConfig { congestion_controller_factory: _, enable_segmentation_offload, address_discovery_role, + initial_max_path_id, } = self; fmt.debug_struct("TransportConfig") .field("max_concurrent_bidi_streams", max_concurrent_bidi_streams) @@ -442,6 +455,7 @@ impl fmt::Debug for TransportConfig { // congestion_controller_factory not debug .field("enable_segmentation_offload", enable_segmentation_offload) .field("address_discovery_role", address_discovery_role) + .field("initial_max_path_id", initial_max_path_id) .finish_non_exhaustive() } } diff --git a/quinn-proto/src/transport_parameters.rs b/quinn-proto/src/transport_parameters.rs index af8c427f3..0418e99fb 100644 --- a/quinn-proto/src/transport_parameters.rs +++ b/quinn-proto/src/transport_parameters.rs @@ -21,6 +21,7 @@ use crate::{ cid_queue::CidQueue, coding::{BufExt, BufMutExt, UnexpectedEnd}, config::{EndpointConfig, ServerConfig, TransportConfig}, + connection::PathId, shared::ConnectionId, ResetToken, Side, TransportError, VarInt, LOC_CID_COUNT, MAX_CID_SIZE, MAX_STREAM_COUNT, RESET_TOKEN_SIZE, TIMER_GRANULARITY, @@ -115,6 +116,9 @@ macro_rules! make_struct { /// The role of this peer in address discovery, if any. pub(crate) address_discovery_role: address_discovery::Role, + + // Multipath extension + pub(crate) initial_max_path_id: Option, } // We deliberately don't implement the `Default` trait, since that would be public, and @@ -139,6 +143,7 @@ macro_rules! make_struct { grease_transport_parameter: None, write_order: None, address_discovery_role: address_discovery::Role::Disabled, + initial_max_path_id: None, } } } @@ -187,6 +192,8 @@ impl TransportParameters { order }), address_discovery_role: config.address_discovery_role, + // TODO(@divma): TransportConfig or..? + initial_max_path_id: config.initial_max_path_id, ..Self::default() } } @@ -209,6 +216,7 @@ impl TransportParameters { "0-RTT accepted with incompatible transport parameters", )); } + // TODO(@divma): multipath validations? Ok(()) } @@ -396,6 +404,13 @@ impl TransportParameters { w.write(varint_role); } } + TransportParameterId::InitialMaxPathId => { + if let Some(val) = self.initial_max_path_id { + w.write_var(id as u64); + w.write_var(val.size() as u64); + w.write(val); + } + } id => { macro_rules! write_params { {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => { @@ -509,6 +524,19 @@ impl TransportParameters { "address discovery enabled for peer" ); } + TransportParameterId::InitialMaxPathId => { + if params.initial_max_path_id.is_some() { + return Err(Error::Malformed); + } + + let value: PathId = r.get()?; + if len != value.size() { + return Err(Error::Malformed); + } + + params.initial_max_path_id = Some(value); + tracing::debug!(initial_max_path_id=%value, "multipath enabled"); + } _ => { macro_rules! parse { {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => { @@ -674,11 +702,14 @@ pub(crate) enum TransportParameterId { // ObservedAddr = 0x9f81a176, + + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath + InitialMaxPathId = 0x0f739bbc1b666d11, } impl TransportParameterId { /// Array with all supported transport parameter IDs - const SUPPORTED: [Self; 22] = [ + const SUPPORTED: [Self; 23] = [ Self::MaxIdleTimeout, Self::MaxUdpPayloadSize, Self::InitialMaxData, @@ -701,6 +732,7 @@ impl TransportParameterId { Self::GreaseQuicBit, Self::MinAckDelayDraft07, Self::ObservedAddr, + Self::InitialMaxPathId, ]; } @@ -741,6 +773,7 @@ impl TryFrom for TransportParameterId { id if Self::GreaseQuicBit == id => Self::GreaseQuicBit, id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07, id if Self::ObservedAddr == id => Self::ObservedAddr, + id if Self::InitialMaxPathId == id => Self::InitialMaxPathId, _ => return Err(()), }; Ok(param) @@ -780,6 +813,7 @@ mod test { grease_quic_bit: true, min_ack_delay: Some(2_000u32.into()), address_discovery_role: address_discovery::Role::SendOnly, + initial_max_path_id: Some(PathId::MAX), ..TransportParameters::default() }; params.write(&mut buf);