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

Being refactored: ECN additions #1495

Closed
wants to merge 68 commits into from
Closed
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f2c093c
Rollup
larseggert Dec 12, 2023
8234696
Move functionality into neqo-common as non-default feature
larseggert Dec 15, 2023
7983f80
Make clippy happy
larseggert Dec 15, 2023
57512f6
Use trait for socket as suggested by @martinthomson
larseggert Dec 18, 2023
ef2671a
Fix formatting
larseggert Dec 18, 2023
5c09621
Reuse std::os::fd::AsRawFd
larseggert Dec 18, 2023
3944647
Try and restore Windows operation.
larseggert Dec 18, 2023
470a73e
Fix formatting
larseggert Dec 18, 2023
e01dadc
Update neqo-common/src/socket.rs
larseggert Jan 2, 2024
57b0f9a
Address code review comments
larseggert Jan 2, 2024
2a1b774
cfg
larseggert Jan 2, 2024
15a3de4
Sort out use statements
larseggert Jan 2, 2024
5cfabe5
Fixes
larseggert Jan 2, 2024
47cf5f5
Fix call
larseggert Jan 2, 2024
3712419
Attempt
larseggert Jan 2, 2024
c853c30
Attempt
larseggert Jan 3, 2024
8530a72
Hopefully fix Windows
larseggert Jan 4, 2024
3154527
Fixes
larseggert Jan 4, 2024
10eb0e9
Rebase
larseggert Jan 5, 2024
253e1d8
Add tests
larseggert Jan 5, 2024
915a161
Re-enable non-blocking mode (disable in test only)
larseggert Jan 5, 2024
237489d
Use neqo_common::socket
larseggert Jan 5, 2024
3d1a27a
A bunch of progress towards doing ACK_ECN
larseggert Jan 11, 2024
6cb3435
Fix rebase
larseggert Jan 11, 2024
0b14760
Minimize diff to origin/main
larseggert Jan 11, 2024
faf2285
More minimization
larseggert Jan 11, 2024
09da257
Use new Datagram::new method everywhere. Make TOS and TTL path-specific.
larseggert Jan 16, 2024
b81a322
Small tweaks
larseggert Jan 16, 2024
1103fc1
Reformat
larseggert Jan 16, 2024
6cda23a
Disable ECN on a path when ECN-marked packets are persistently lost
larseggert Jan 16, 2024
5c65b90
Remove println!
larseggert Jan 16, 2024
2fcf7a7
Add workflow_dispatch for QNS, reduce rate (#1562)
martinthomson Jan 17, 2024
9d58e64
Make ConnectionIdRef Copy (#1561)
martinthomson Jan 17, 2024
70e3ac4
Fix qlog issues to enable correct qvis rendering (#1544)
larseggert Jan 17, 2024
09c02b7
Rollup
larseggert Dec 12, 2023
ae8f13a
Move functionality into neqo-common as non-default feature
larseggert Dec 15, 2023
76d6b19
Make clippy happy
larseggert Dec 15, 2023
ccd4b65
Use trait for socket as suggested by @martinthomson
larseggert Dec 18, 2023
38c123c
Fix formatting
larseggert Dec 18, 2023
107e51c
Reuse std::os::fd::AsRawFd
larseggert Dec 18, 2023
ef24355
Try and restore Windows operation.
larseggert Dec 18, 2023
d58f846
Fix formatting
larseggert Dec 18, 2023
e721fd6
Update neqo-common/src/socket.rs
larseggert Jan 2, 2024
f32177f
Address code review comments
larseggert Jan 2, 2024
fd18d00
cfg
larseggert Jan 2, 2024
0569faa
Sort out use statements
larseggert Jan 2, 2024
39c6500
Fixes
larseggert Jan 2, 2024
04417c7
Fix call
larseggert Jan 2, 2024
d8a758e
Attempt
larseggert Jan 2, 2024
0d95460
Attempt
larseggert Jan 3, 2024
43554d8
Hopefully fix Windows
larseggert Jan 4, 2024
db599a4
Fixes
larseggert Jan 4, 2024
e02b51a
Rebase
larseggert Jan 5, 2024
f99aec6
Add tests
larseggert Jan 5, 2024
616ffc5
Re-enable non-blocking mode (disable in test only)
larseggert Jan 5, 2024
5b85c09
Use neqo_common::socket
larseggert Jan 5, 2024
22b6236
A bunch of progress towards doing ACK_ECN
larseggert Jan 11, 2024
933e126
Fix rebase
larseggert Jan 11, 2024
7219e7a
Minimize diff to origin/main
larseggert Jan 11, 2024
afefa8f
More minimization
larseggert Jan 11, 2024
93942b2
Use new Datagram::new method everywhere. Make TOS and TTL path-specific.
larseggert Jan 16, 2024
62f963f
Small tweaks
larseggert Jan 16, 2024
0c7554d
Reformat
larseggert Jan 16, 2024
0422462
Disable ECN on a path when ECN-marked packets are persistently lost
larseggert Jan 16, 2024
dbdaa80
Remove println!
larseggert Jan 16, 2024
e06206b
Rebase cleanup
larseggert Jan 17, 2024
c0bf1a1
Merge branch 'feat-ecn' of github.com:larseggert/neqo into feat-ecn
larseggert Jan 17, 2024
052eb06
Address code review comments
larseggert Jan 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/qns.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: QUIC Network Simulator

on:
schedule:
- cron: '42 3 * * *' # Runs at 03:42 UTC (m and h chosen arbitrarily) every day.
- cron: '42 3 * * 2,5' # Runs at 03:42 UTC (m and h chosen arbitrarily) twice a week.
workflow_dispatch:
pull_request:
branch: ["main"]
paths:
Expand Down
2 changes: 1 addition & 1 deletion neqo-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
neqo-crypto = { path = "./../neqo-crypto" }
neqo-transport = { path = "./../neqo-transport" }
neqo-common = { path="./../neqo-common" }
neqo-common = { path="./../neqo-common", features = ["socket"] }
neqo-http3 = { path = "./../neqo-http3" }
neqo-qpack = { path = "./../neqo-qpack" }
structopt = "0.3.7"
Expand Down
35 changes: 17 additions & 18 deletions neqo-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use qlog::{events::EventImportance, streamer::QlogStreamer};

use mio::{net::UdpSocket, Events, Poll, PollOpt, Ready, Token};

use neqo_common::{self as common, event::Provider, hex, qlog::NeqoQlog, Datagram, Role};
use neqo_common::{
self as common, bind, emit_datagram, event::Provider, hex, qlog::NeqoQlog, recv_datagram,
Datagram, Role,
};
use neqo_crypto::{
constants::{TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256},
init, AuthenticationStatus, Cipher, ResumptionToken,
Expand Down Expand Up @@ -345,14 +348,6 @@ impl QuicParameters {
}
}

fn emit_datagram(socket: &mio::net::UdpSocket, d: Datagram) -> io::Result<()> {
let sent = socket.send_to(&d[..], &d.destination())?;
if sent != d.len() {
eprintln!("Unable to send all {} bytes of datagram", d.len());
}
Ok(())
}

fn get_output_file(
url: &Url,
output_dir: &Option<PathBuf>,
Expand Down Expand Up @@ -413,7 +408,9 @@ fn process_loop(

let mut datagrams: Vec<Datagram> = Vec::new();
'read: loop {
match socket.recv_from(&mut buf[..]) {
let mut tos = 0;
let mut ttl = 0;
match recv_datagram(socket, &mut buf[..], &mut tos, &mut ttl) {
Err(ref err)
if err.kind() == ErrorKind::WouldBlock
|| err.kind() == ErrorKind::Interrupted =>
Expand All @@ -430,7 +427,7 @@ fn process_loop(
break 'read;
}
if sz > 0 {
let d = Datagram::new(remote, *local_addr, &buf[..sz]);
let d = Datagram::new(remote, *local_addr, tos, ttl, &buf[..sz]);
datagrams.push(d);
}
}
Expand All @@ -450,7 +447,7 @@ fn process_loop(
'write: loop {
match client.process_output(Instant::now()) {
Output::Datagram(dgram) => {
if let Err(e) = emit_datagram(socket, dgram) {
if let Err(e) = emit_datagram(socket, &dgram) {
eprintln!("UDP write error: {e}");
client.close(Instant::now(), 0, e.to_string());
exiting = true;
Expand Down Expand Up @@ -1046,12 +1043,12 @@ fn main() -> Res<()> {
SocketAddr::V6(..) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from([0; 16])), 0),
};

let socket = match UdpSocket::bind(&local_addr) {
let socket = match bind(&local_addr) {
Err(e) => {
eprintln!("Unable to bind UDP socket: {e}");
exit(1)
}
Ok(s) => s,
Ok(s) => UdpSocket::from_socket(s)?,
};

let poll = Poll::new()?;
Expand Down Expand Up @@ -1140,7 +1137,7 @@ mod old {

use super::{qlog_new, KeyUpdateState, Res};
use mio::{Events, Poll};
use neqo_common::{event::Provider, Datagram};
use neqo_common::{event::Provider, recv_datagram, Datagram};
use neqo_crypto::{AuthenticationStatus, ResumptionToken};
use neqo_transport::{
Connection, ConnectionEvent, EmptyConnectionIdGenerator, Error, Output, State, StreamId,
Expand Down Expand Up @@ -1348,7 +1345,9 @@ mod old {
)?;

'read: loop {
match socket.recv_from(&mut buf[..]) {
let mut tos = 0;
let mut ttl = 0;
match recv_datagram(socket, &mut buf[..], &mut tos, &mut ttl) {
Err(ref err)
if err.kind() == ErrorKind::WouldBlock
|| err.kind() == ErrorKind::Interrupted =>
Expand All @@ -1365,7 +1364,7 @@ mod old {
break 'read;
}
if sz > 0 {
let d = Datagram::new(remote, *local_addr, &buf[..sz]);
let d = Datagram::new(remote, *local_addr, tos, ttl, &buf[..sz]);
client.process_input(&d, Instant::now());
handler.maybe_key_update(client)?;
}
Expand All @@ -1382,7 +1381,7 @@ mod old {
'write: loop {
match client.process_output(Instant::now()) {
Output::Datagram(dgram) => {
if let Err(e) = emit_datagram(socket, dgram) {
if let Err(e) = emit_datagram(socket, &dgram) {
eprintln!("UDP write error: {e}");
client.close(Instant::now(), 0, e.to_string());
exiting = true;
Expand Down
20 changes: 17 additions & 3 deletions neqo-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,30 @@ rust-version = "1.70.0"
license = "MIT OR Apache-2.0"
build = "build.rs"

[build-dependencies]
cfg_aliases = "0.2.0"

[dependencies]
log = {version = "0.4.0", default-features = false}
env_logger = {version = "0.10", default-features = false}
log = { version = "0.4.0", default-features = false }
enum-map = "2.7.3"
env_logger = { version = "0.10", default-features = false }
lazy_static = "1.3.0"
mio = { version = "0.6.17", optional = true }
qlog = "0.11.0"
time = {version = "0.3", features = ["formatting"]}
time = { version = "0.3", features = ["formatting"] }
nix = { git = "https://github.com/larseggert/nix.git", branch = "feat-tos", features = [
"socket",
"net",
"uio",
], optional = true }
Comment on lines +21 to +25
Copy link
Member

Choose a reason for hiding this comment

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

OK, let's continue to block on this being integrated upstream. Worst case, we can take up your fork, but if this can be upstreamed, that's a lot easier.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's in progress. Depends on another PR upstream.


[dev-dependencies]
test-fixture = { path = "../test-fixture" }

[features]
deny-warnings = []
ci = []
socket = ["dep:nix", "dep:mio"]

[target."cfg(windows)".dependencies.winapi]
version = "0.3"
Expand Down
5 changes: 5 additions & 0 deletions neqo-common/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use cfg_aliases::cfg_aliases;
use std::env;

fn main() {
let target = env::var("TARGET").unwrap();
if target.contains("windows") {
println!("cargo:rustc-link-lib=winmm");
}

cfg_aliases! {
posix_socket: { any(target_os = "macos", target_os = "linux", target_os = "android") },
}
}
89 changes: 88 additions & 1 deletion neqo-common/src/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,97 @@
use std::net::SocketAddr;
use std::ops::Deref;

use enum_map::Enum;

use crate::hex_with_len;

// ECN (Explicit Congestion Notification) codepoints mapped to the
// lower 2 bits of the TOS field.
// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
#[derive(Copy, Clone, PartialEq, Eq, Enum)]
#[repr(u8)]
pub enum IpTosEcn {
NotEct = 0b00, // Not-ECT (Not ECN-Capable Transport) [RFC3168]
Ect1 = 0b01, // ECT(1) (ECN-Capable Transport(1))[1] [RFC8311][RFC Errata 5399][RFC9331]
Ect0 = 0b10, // ECT(0) (ECN-Capable Transport(0)) [RFC3168]
Ce = 0b11, // CE (Congestion Experienced) [RFC3168]
}

impl From<u8> for IpTosEcn {
fn from(v: u8) -> Self {
match v & 0b11 {
0b00 => IpTosEcn::NotEct,
0b01 => IpTosEcn::Ect1,
0b10 => IpTosEcn::Ect0,
0b11 => IpTosEcn::Ce,
_ => unreachable!(),
}
}
}

impl From<IpTosEcn> for u8 {
fn from(val: IpTosEcn) -> Self {
val as u8
}
}

impl std::fmt::Debug for IpTosEcn {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
IpTosEcn::NotEct => f.write_str("Not-ECT"),
IpTosEcn::Ect1 => f.write_str("ECT(1)"),
IpTosEcn::Ect0 => f.write_str("ECT(0)"),
IpTosEcn::Ce => f.write_str("CE"),
}
}
}

// DiffServ Codepoints, mapped to the upper six bits of the TOS field.
// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum IpTosDscp {
Cs0 = 0b0000_0000, // [RFC2474]
Cs1 = 0b0010_0000, // [RFC2474]
Cs2 = 0b0100_0000, // [RFC2474]
Cs3 = 0b0110_0000, // [RFC2474]
Cs4 = 0b1000_0000, // [RFC2474]
Cs5 = 0b1010_0000, // [RFC2474]
Cs6 = 0b1100_0000, // [RFC2474]
Cs7 = 0b1110_0000, // [RFC2474]
Af11 = 0b0010_1000, // [RFC2597]
Af12 = 0b0011_0000, // [RFC2597]
Af13 = 0b0011_1000, // [RFC2597]
Af21 = 0b0100_1000, // [RFC2597]
Af22 = 0b0101_0000, // [RFC2597]
Af23 = 0b0101_1000, // [RFC2597]
Af31 = 0b0110_1000, // [RFC2597]
Af32 = 0b0111_0000, // [RFC2597]
Af33 = 0b0111_1000, // [RFC2597]
Af41 = 0b1000_1000, // [RFC2597]
Af42 = 0b1001_0000, // [RFC2597]
Af43 = 0b1001_1000, // [RFC2597]
Ef = 0b1011_1000, // [RFC3246]
VoiceAdmit = 0b1011_0000, // [RFC5865]
Le = 0b0000_0100, // [RFC8622]
}

#[derive(PartialEq, Eq, Clone)]
pub struct Datagram {
src: SocketAddr,
dst: SocketAddr,
tos: u8,
ttl: u8,
d: Vec<u8>,
}

impl Datagram {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, d: V) -> Self {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, tos: u8, ttl: u8, d: V) -> Self {
Self {
src,
dst,
tos,
ttl,
d: d.into(),
}
}
Expand All @@ -34,6 +111,16 @@ impl Datagram {
pub fn destination(&self) -> SocketAddr {
self.dst
}

#[must_use]
pub fn tos(&self) -> u8 {
self.tos
}

#[must_use]
pub fn ttl(&self) -> u8 {
self.ttl
}
}

impl Deref for Datagram {
Expand Down
6 changes: 5 additions & 1 deletion neqo-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ pub mod hrtime;
mod incrdecoder;
pub mod log;
pub mod qlog;
#[cfg(feature = "socket")]
pub mod socket;
pub mod timer;

pub use self::codec::{Decoder, Encoder};
pub use self::datagram::Datagram;
pub use self::datagram::{Datagram, IpTosDscp, IpTosEcn};
pub use self::header::Header;
pub use self::incrdecoder::{
IncrementalDecoderBuffer, IncrementalDecoderIgnore, IncrementalDecoderUint,
};
#[cfg(feature = "socket")]
pub use self::socket::{bind, emit_datagram, recv_datagram};

use std::fmt::Write;

Expand Down
41 changes: 41 additions & 0 deletions neqo-common/src/qlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ impl NeqoQlog {
})
}

#[must_use]
pub fn inner(&self) -> Rc<RefCell<Option<NeqoQlogShared>>> {
Rc::clone(&self.inner)
}

/// Create a disabled `NeqoQlog` configuration.
#[must_use]
pub fn disabled() -> Self {
Expand Down Expand Up @@ -144,3 +149,39 @@ pub fn new_trace(role: Role) -> qlog::TraceSeq {
}),
}
}

#[cfg(test)]
mod test {
use qlog::events::Event;
use test_fixture::EXPECTED_LOG_HEADER;

const EV_DATA: qlog::events::EventData =
qlog::events::EventData::SpinBitUpdated(qlog::events::connectivity::SpinBitUpdated {
state: true,
});

const EXPECTED_LOG_EVENT: &str = concat!(
"\u{1e}",
r#"{"time":0.0,"name":"connectivity:spin_bit_updated","data":{"state":true}}"#,
"\n"
);

#[test]
fn new_neqo_qlog() {
let (_log, contents) = test_fixture::new_neqo_qlog();
assert_eq!(contents.to_string(), EXPECTED_LOG_HEADER);
}

#[test]
fn add_event() {
let (mut log, contents) = test_fixture::new_neqo_qlog();
log.add_event(|| Some(Event::with_time(1.1, EV_DATA)));
assert_eq!(
contents.to_string(),
format!(
"{EXPECTED_LOG_HEADER}{e}",
e = EXPECTED_LOG_EVENT.replace("\"time\":0.0,", "\"time\":1.1,")
)
);
}
}
Loading
Loading