Skip to content

Commit

Permalink
move support to draft-ietf-quic-multipath-06
Browse files Browse the repository at this point in the history
  • Loading branch information
qdeconinck committed Oct 27, 2023
1 parent 2aa5abd commit 6a53adb
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 78 deletions.
7 changes: 4 additions & 3 deletions apps/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ Options:
--multipath-old Enable (old v4) multipath support.
-A --address ADDR ... Specify addresses to be used instead of the unspecified address. Non-routable addresses will lead to connectivity issues.
-R --rm-addr TIMEADDR ... Specify addresses to stop using after the provided time (format time,addr).
-S --status TIMEADDRSTAT ... Specify status to advertise to the peer after the provided time (format time,addr,status).
-S --status TIMEADDRSTAT ... Specify availability status to advertise to the peer after the provided time (format time,addr,available).
-H --header HEADER ... Add a request header.
-n --requests REQUESTS Send the given number of identical requests [default: 1].
--send-priority-update Send HTTP/3 priority updates if the query string params 'u' or 'i' are present in URLs
Expand Down Expand Up @@ -329,7 +329,7 @@ pub struct ClientArgs {
pub send_priority_update: bool,
pub addrs: Vec<SocketAddr>,
pub rm_addrs: Vec<(std::time::Duration, SocketAddr)>,
pub status: Vec<(std::time::Duration, SocketAddr, u64)>,
pub status: Vec<(std::time::Duration, SocketAddr, bool)>,
}

impl Args for ClientArgs {
Expand Down Expand Up @@ -450,7 +450,8 @@ impl Args for ClientArgs {
Err(_) => return None,
};
let status = match s[2].parse::<u64>() {
Ok(s) => s,
Ok(0) => false,
Ok(_) => true,
Err(_) => return None,
};
Some((std::time::Duration::from_secs(secs), addr, status))
Expand Down
11 changes: 3 additions & 8 deletions apps/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ use std::rc::Rc;

use std::cell::RefCell;

use quiche::PathStatus;
use ring::rand::*;

use slab::Slab;
Expand Down Expand Up @@ -513,14 +512,10 @@ pub fn connect(
}
});

status.retain(|(d, addr, s)| {
status.retain(|(d, addr, available)| {
if app_data_start.elapsed() >= *d {
info!("Advertising path status {s} to {addr:?}");
let status = match s {
1 => PathStatus::Standby,
2 => PathStatus::Available,
s => PathStatus::Unknown(*s),
};
let status = (*available).into();
info!("Advertising path status {status:?} to {addr:?}");
conn.set_path_status(*addr, peer_addr, status, true)
.is_err()
} else {
Expand Down
8 changes: 6 additions & 2 deletions qlog/src/events/quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,14 @@ pub enum QuicFrame {
reason: Option<String>,
},

PathStatus {
PathStandby {
dcid_seq_num: u64,
seq_num: u64,
},

PathAvailable {
dcid_seq_num: u64,
seq_num: u64,
status: u64,
},

Unknown {
Expand Down
123 changes: 96 additions & 27 deletions quiche/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,14 @@ pub enum Frame {
reason: Vec<u8>,
},

PathStatus {
PathStandby {
dcid_seq_num: u64,
seq_num: u64,
},

PathAvailable {
dcid_seq_num: u64,
seq_num: u64,
status: u64,
},
}

Expand Down Expand Up @@ -334,10 +338,14 @@ impl Frame {
reason: b.get_bytes_with_varint_length()?.to_vec(),
},

0x15228c06 => Frame::PathStatus {
0x15228c07 => Frame::PathStandby {
dcid_seq_num: b.get_varint()?,
seq_num: b.get_varint()?,
},

0x15228c08 => Frame::PathAvailable {
dcid_seq_num: b.get_varint()?,
seq_num: b.get_varint()?,
status: b.get_varint()?,
},

_ => return Err(Error::InvalidFrame),
Expand All @@ -359,7 +367,8 @@ impl Frame {
(packet::Type::ZeroRTT, Frame::ConnectionClose { .. }) => false,
(packet::Type::ZeroRTT, Frame::ACKMP { .. }) => false,
(packet::Type::ZeroRTT, Frame::PathAbandon { .. }) => false,
(packet::Type::ZeroRTT, Frame::PathStatus { .. }) => false,
(packet::Type::ZeroRTT, Frame::PathStandby { .. }) => false,
(packet::Type::ZeroRTT, Frame::PathAvailable { .. }) => false,

// ACK, CRYPTO and CONNECTION_CLOSE can be sent on all other packet
// types.
Expand Down Expand Up @@ -609,16 +618,24 @@ impl Frame {
b.put_bytes(reason.as_ref())?;
},

Frame::PathStatus {
Frame::PathStandby {
dcid_seq_num,
seq_num,
} => {
b.put_varint(0x15228c07)?;

b.put_varint(*dcid_seq_num)?;
b.put_varint(*seq_num)?;
},

Frame::PathAvailable {
dcid_seq_num,
seq_num,
status,
} => {
b.put_varint(0x15228c06)?;
b.put_varint(0x15228c08)?;

b.put_varint(*dcid_seq_num)?;
b.put_varint(*seq_num)?;
b.put_varint(*status)?;
},
}

Expand Down Expand Up @@ -831,15 +848,22 @@ impl Frame {
reason.len()
},

Frame::PathStatus {
Frame::PathStandby {
dcid_seq_num,
seq_num,
status,
} => {
4 + // frame size
octets::varint_len(*dcid_seq_num) +
octets::varint_len(*seq_num) +
octets::varint_len(*status)
octets::varint_len(*seq_num)
},

Frame::PathAvailable {
dcid_seq_num,
seq_num,
} => {
4 + // frame size
octets::varint_len(*dcid_seq_num) +
octets::varint_len(*seq_num)
},
}
}
Expand Down Expand Up @@ -1095,14 +1119,20 @@ impl Frame {
reason: Some(String::from_utf8_lossy(reason).into_owned()),
},

Frame::PathStatus {
Frame::PathStandby {
dcid_seq_num,
seq_num,
status,
} => QuicFrame::PathStatus {
} => QuicFrame::PathStandby {
dcid_seq_num: *dcid_seq_num,
seq_num: *seq_num,
},

Frame::PathAvailable {
dcid_seq_num,
seq_num,
} => QuicFrame::PathAvailable {
dcid_seq_num: *dcid_seq_num,
seq_num: *seq_num,
status: *status,
},
}
}
Expand Down Expand Up @@ -1297,16 +1327,24 @@ impl std::fmt::Debug for Frame {
)?;
},

Frame::PathStatus {
Frame::PathStandby {
dcid_seq_num,
seq_num,
status,
..
} => {
write!(
f,
"PATH_STATUS dcid_seq_num={dcid_seq_num:x} seq_num={seq_num:x} status={status:x}",
)?;
"PATH_STANDBY dcid_seq_num={dcid_seq_num:x} seq_num={seq_num:x}",
)?
},

Frame::PathAvailable {
dcid_seq_num,
seq_num,
} => {
write!(
f,
"PATH_AVAILABLE dcid_seq_num={dcid_seq_num:x} seq_num={seq_num:x}",
)?
},
}

Expand Down Expand Up @@ -2432,17 +2470,15 @@ mod tests {
}

#[test]
fn path_status() {
fn path_standby() {
let mut d = [42; 128];

let dcid_seq_num = 0xabcdef00;
let seq_num = 0x42;
let status = 1;

let frame = Frame::PathStatus {
let frame = Frame::PathStandby {
dcid_seq_num,
seq_num,
status,
};

let wire_len = {
Expand All @@ -2451,7 +2487,40 @@ mod tests {
};

assert_eq!(frame.wire_len(), wire_len);
assert_eq!(wire_len, 15);
assert_eq!(wire_len, 14);

let mut b = octets::Octets::with_slice(&d);
assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));

let mut b = octets::Octets::with_slice(&d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());

let mut b = octets::Octets::with_slice(&d);
assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err());

let mut b = octets::Octets::with_slice(&d);
assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err());
}

#[test]
fn path_available() {
let mut d = [42; 128];

let dcid_seq_num = 0xabcdef00;
let seq_num = 0x42;

let frame = Frame::PathAvailable {
dcid_seq_num,
seq_num,
};

let wire_len = {
let mut b = octets::OctetsMut::with_slice(&mut d);
frame.to_bytes(&mut b).unwrap()
};

assert_eq!(frame.wire_len(), wire_len);
assert_eq!(wire_len, 14);

let mut b = octets::Octets::with_slice(&d);
assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
Expand Down
44 changes: 32 additions & 12 deletions quiche/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4117,16 +4117,23 @@ impl Connection {
}
}

// Create PATH_STATUS frames as needed.
while let Some((path_id, seq_num, status)) = self.paths.path_status()
// Create PATH_AVAILABLE/PATH_STANDBY frames as needed.
while let Some((path_id, seq_num, available)) =
self.paths.path_status()
{
let status_path = self.paths.get(path_id)?;
let dcid_seq_num =
status_path.active_dcid_seq.ok_or(Error::InvalidState)?;
let frame = frame::Frame::PathStatus {
dcid_seq_num,
seq_num,
status,
let frame = if available {
frame::Frame::PathAvailable {
dcid_seq_num,
seq_num,
}
} else {
frame::Frame::PathStandby {
dcid_seq_num,
seq_num,
}
};
if push_frame_to_pkt!(b, frames, frame, left) {
self.paths.on_path_status_sent();
Expand Down Expand Up @@ -7641,11 +7648,24 @@ impl Connection {
)?;
},

frame::Frame::PathStatus {
frame::Frame::PathStandby {
dcid_seq_num,
seq_num,
} => {
if !self.use_path_pkt_num_space(epoch) {
return Err(Error::MultiPathViolation);
}
let pid = self
.ids
.get_dcid(dcid_seq_num)?
.path_id
.ok_or(Error::InvalidFrame)?;
self.paths.on_path_status_received(pid, seq_num, false);
},

frame::Frame::PathAvailable {
dcid_seq_num,
seq_num,
status,
..
} => {
if !self.use_path_pkt_num_space(epoch) {
return Err(Error::MultiPathViolation);
Expand All @@ -7655,7 +7675,7 @@ impl Connection {
.get_dcid(dcid_seq_num)?
.path_id
.ok_or(Error::InvalidFrame)?;
self.paths.on_path_status_received(pid, seq_num, status);
self.paths.on_path_status_received(pid, seq_num, true);
},
};
Ok(())
Expand Down Expand Up @@ -8465,7 +8485,7 @@ impl TransportParams {
tp.max_datagram_frame_size = Some(val.get_varint()?);
},

0x0f739bbc1b666d05 => {
0x0f739bbc1b666d06 => {
tp.enable_multipath = true;
},

Expand Down Expand Up @@ -8632,7 +8652,7 @@ impl TransportParams {
}

if tp.enable_multipath {
TransportParams::encode_param(&mut b, 0x0f739bbc1b666d05, 0)?;
TransportParams::encode_param(&mut b, 0x0f739bbc1b666d06, 0)?;
}

let out_len = b.off();
Expand Down
Loading

0 comments on commit 6a53adb

Please sign in to comment.