diff --git a/Cargo.lock b/Cargo.lock index 8b0aded8e9..db0d69c052 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4523,9 +4523,9 @@ dependencies = [ [[package]] name = "moq-noq" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e37523750e5f1313c3fd1798c4ffdb00218571054f601c3193ceb4e100e5ca" +checksum = "8f73dd3abdf1efa3b89f903494d93836968f4eb4040a29cde5a03a4c6451535b" dependencies = [ "bytes", "cfg_aliases", @@ -4545,9 +4545,9 @@ dependencies = [ [[package]] name = "moq-noq-proto" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7448c4a6a6713b276b346931f3def60e0a89415cd8172d12f6465fed6501a261" +checksum = "c8ede2ffc5008e6c53798802c257689475f01b12960f37a5f78e91cf4580159b" dependencies = [ "aes-gcm", "aws-lc-rs", @@ -4576,9 +4576,9 @@ dependencies = [ [[package]] name = "moq-noq-udp" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98e7d85788b7ec2437ac3dd83a231c4e403b96a5e53e39a8701ba5d1d4fad4a4" +checksum = "b1e67d81510e43c0a0ce67a310e35938aa1dbd4a34ccef32d10f752719269cf2" dependencies = [ "cfg_aliases", "libc", @@ -9836,9 +9836,9 @@ dependencies = [ [[package]] name = "web-transport-moq" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3bdb2400eb49f82b778165df8da318f94be5a667a840a94fe6fc32f3798746" +checksum = "c2d0167f1b04c31eefb41262fd459b90d72d6f41eea0cbc35d7e2c6279190290" dependencies = [ "bytes", "futures", diff --git a/Cargo.toml b/Cargo.toml index 65170e3b2e..789ecbbfd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,8 +149,8 @@ moq-mux = { version = "0.10.8", path = "rs/moq-mux" } moq-net = { version = "0.3.7", path = "rs/moq-net" } # The MoQ fork of noq (moq-dev/noq). iroh keeps upstream noq, so a build with the # iroh feature carries both stacks. -moq-noq-proto = { version = "1.3.1", default-features = false } -moq-noq-udp = "1.3.1" +moq-noq-proto = { version = "1.3.2", default-features = false } +moq-noq-udp = "1.3.2" # NVENC bindings, forked from ViliamVadocz/nvidia-video-codec-sdk to dlopen the # driver at runtime. Compiles on any platform (macOS included) but only actually # used by moq-video on Linux. @@ -234,7 +234,7 @@ web-transport-iroh = "0.7" # default-features off so the QUIC crypto provider is chosen by moq-tokio's # aws-lc-rs / ring features. # The WebTransport adapter released with moq-noq, from the same repository. -web-transport-moq = { version = "1.3.1", default-features = false } +web-transport-moq = { version = "1.3.2", default-features = false } web-transport-proto = "0.6" web-transport-trait = "0.4" web-transport-wasm = "0.6" diff --git a/quest/m1/README.md b/quest/m1/README.md index 8d9e5cc9cf..50e3d328e9 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -18,7 +18,6 @@ transport, benchmark tooling); worktrees isolate commits, not semantics. ## Quests - [Drill sensitivity](/quest/m1/drill-sensitivity.md) - the nightly drill-sensitivity job passes: the subscriber-leaks-broadcasts mutation applies to the current lite subscriber again -- [BBR classic ECN](/quest/m1/bbr-classic-ecn.md) - Startup and bandwidth probing respond to CE marks before the bottleneck drops packets - [Cluster routing](/quest/m1/cluster-routing.md) - an announcement says where a broadcast originates, not how to reach it, and a relay hears only the prefixes its clients asked for - [lite-07 count settle](/quest/m1/lite-count-settle.md) - moq-lite-07 subscribers stop waiting for a subscription's tail once SUBSCRIBE_END's stream count is reached - [Dropped sources](/quest/m1/dropped-sources.md) - track consumers see the producer's real error on every end path, never `Dropped` diff --git a/quest/m1/bbr-ack-cleanup.md b/quest/m1/bbr-ack-cleanup.md index 02ad06e0f1..702b7b2124 100644 --- a/quest/m1/bbr-ack-cleanup.md +++ b/quest/m1/bbr-ack-cleanup.md @@ -56,6 +56,5 @@ is needed. ## Related -- [Classic ECN](/quest/m1/bbr-classic-ecn.md) - an independent correctness fix in the same controller; coordinate ownership of the shared file - [Loss sampling](/quest/m1/quic/bbr-loss-parity.md) - preserve packet metadata needed by the separate loss-sample repair - [Benchmark comparisons](/quest/m1/performance-comparisons.md) - reusable measurement guidance, not a prerequisite for this fix diff --git a/quest/m1/bbr-classic-ecn.md b/quest/m1/bbr-classic-ecn.md deleted file mode 100644 index d085ba2d8c..0000000000 --- a/quest/m1/bbr-classic-ecn.md +++ /dev/null @@ -1,61 +0,0 @@ -# [M] Make BBR respond to classic ECN - -## Goal - -BBRv3 responds to validated CE marks before a marking bottleneck has to drop -packets, including during Startup and ProbeUp. Keep ECT(0) enabled and ship -the corrected controller through MoQ's published dependency chain. L4S, -new configuration flags, and changing the default controller are out of scope. - -## Plan - -The fix lives in moq-dev/noq. In released 1.3.1 (`ff9d2ab5`), -[`on_congestion_event`](https://github.com/moq-dev/noq/blob/ff9d2ab518cfb155f9ebb9925f1c784665eac92a/noq-proto/src/congestion/bbr3/mod.rs#L1828) -passes CE to the lost-packet path with zero lost bytes. Startup and ProbeUp -skip the short-term loss response, while their high-loss checks see no lost -bytes. A controller reproduction sends eight rounds of 1, 2, 4, ..., 128 -1200-byte packets, 20 ms apart, acknowledging each round after 10 ms and -reporting CE after `on_end_acks`, as the transport does. Both marked and -unmarked controls remain in Startup with a 318,000-byte window and -42,167,347.2 bytes/s pacing. This is a controller result, not an AQM network -measurement. - -[Draft-06 section 3.7](https://www.ietf.org/archive/id/draft-ietf-ccwg-bbr-06.html#section-3.7) -requires an ECN-capable sender to treat CE as congestion, without prescribing -one BBR response. [Google Linux BBRv3](https://github.com/google/bbr/blob/90210de4b779d40496dee0b89081780eeddf2a60/net/ipv4/tcp_bbr.c#L1048) -has a separate Startup ECN response when its ECN mode is eligible. Choose a -classic response consistent with QUIC recovery: stop acceleration and reduce -the permitted sending load on new CE feedback, at most once per recovery -period. Do not fabricate lost bytes or apply repeated reductions for old CE -counts. Preserve the distinction between loss and CE, including undo of -spurious loss. Prefer the existing controller boundary; this fix does not -need a CE-fraction API or Google's L4S policy. - -Extend the existing shared BBR `Sim` with the failing reproduction, then test -through actual QUIC ECN validation and controller callbacks. Cover Startup, -ProbeUp, Cruise, ProbeRTT, repeated ACKs with no new CE, several CE-bearing -ACKs in one recovery period, a later period with new CE, simultaneous loss, -and invalid or missing ECN feedback. Acceptance requires a bounded decrease -in sending load under sustained CE, recovery after marking stops, and no -response on the unmarked control; merely changing an internal state is not -enough. Keep the default CUBIC path working. - -Retain a reproducible rate-limited marking-versus-dropping network case, -recording queue delay, goodput, loss, and response timing. Run deterministic -regressions in fork CI and the network case at least nightly. Provider -availability does not block this lab validation. Record the response rule -and its recovery-period boundary with the results. - -Land the fix in the fork, offer it upstream or record why not, publish an -immutable fork release, and pin the corrected dependency chain here before -completing this quest. Do not wait for the broader QUIC stack release or the -ACK cleanup fix. No wire change or new public API is intended; document any -necessary API change and apply the repository's branch rules. Update stale -controller and relay ECN documentation inline; no separate guide is needed. - -## Related - -- [ACK cleanup](/quest/m1/bbr-ack-cleanup.md) - an independent fix in the same controller; coordinate ownership of the shared file -- [Loss sampling](/quest/m1/quic/bbr-loss-parity.md) - the separate lost-packet sample repair -- [ECN measurement](/quest/m1/quic/ecn-measure.md) - measures the released response on the backbone -- [L4S](/quest/m2/quic-ecn.md) - a separate scalable ECN policy and opt-in configuration diff --git a/quest/m1/close-codes.md b/quest/m1/close-codes.md index f1e3e9a34f..4e52f19d62 100644 --- a/quest/m1/close-codes.md +++ b/quest/m1/close-codes.md @@ -18,9 +18,8 @@ Both bugs are upstream; fix them at the source, release, and bump the pins. `accept_bi` also return a bare `Closed`. Make the first close win, make `close()` a no-op once closed, and have `accept_*` return the recorded reason. Add a qmux test where APPLICATION_CLOSE and EOF arrive together. -- `web-transport-moq` 1.3.1 (`moq-dev/noq`) maps `ApplicationClosed` only - through the HTTP/3 code space in `error.rs`, so a raw `moqt://` code yields - no `session_error()`. Map raw QUIC codes directly. +- `web-transport-moq` 1.3.2 (`moq-dev/noq#11`) maps a raw `moqt://` peer's + `ApplicationClosed` code directly. Done; only the regression below remains. - moq-net's `close(Internal)` after a transport error is correct: closing a closed connection does nothing. Do not work around it here. - One moq-tokio regression runs the issue's three cases (abort after accept, diff --git a/quest/m1/quic/ecn-measure.md b/quest/m1/quic/ecn-measure.md index 56b6658477..2745829780 100644 --- a/quest/m1/quic/ecn-measure.md +++ b/quest/m1/quic/ecn-measure.md @@ -14,7 +14,8 @@ A manual procedure on Linux, run as root, with the commands and what to record written here so the dualpi2 run and any later provider re-check repeat it. -Use the released [classic BBR ECN fix](/quest/m1/bbr-classic-ecn.md) for the +Use moq-noq 1.3.2 or later, which carries the classic BBR CE response +([moq-dev/noq#12](https://github.com/moq-dev/noq/pull/12)), for the controller-response verdict and record the exact dependency version. Provider mark-survival captures alone do not establish a controller response; a result from 1.3.1 is a defective baseline, not evidence that classic ECN cannot help. @@ -35,7 +36,3 @@ from 1.3.1 is a defective baseline, not evidence that classic ECN cannot help. and the tcpdump summaries beside the numbers in the L4S quest's Plan. If neither provider preserves the marks, say so there: L4S stays off and the marking response is only a lab result. - -## Required - -- [Classic BBR ECN](/quest/m1/bbr-classic-ecn.md) - the final response verdict needs the corrected released controller diff --git a/quest/m2/quic-ecn.md b/quest/m2/quic-ecn.md index e4b0e9d24e..3d8e415b83 100644 --- a/quest/m2/quic-ecn.md +++ b/quest/m2/quic-ecn.md @@ -9,9 +9,9 @@ marks fall back to no ECN, and a viewer's session is unaffected. ## Plan -ECT(0) marking and ACK ECN counts are carried end to end, but BBR's -[classic CE response](/quest/m1/bbr-classic-ecn.md) must be corrected before -it is used as the baseline. This quest adds the scalable policy separately. +ECT(0) marking and ACK ECN counts are carried end to end, and BBR's classic +CE response ([moq-dev/noq#12](https://github.com/moq-dev/noq/pull/12), in +moq-noq 1.3.2) is the baseline. This quest adds the scalable policy separately. noq-proto has no ECN knob: `sending_ecn` starts on per path and validation failure or an ACK without counts turns it off, so both `off` and `ect1` need the fork. @@ -35,6 +35,5 @@ need the fork. ## Required -- [Classic BBR ECN](/quest/m1/bbr-classic-ecn.md) - establish a corrected released classic response before comparing L4S - [Measure ECN on the backbone](/quest/m1/quic/ecn-measure.md) - the provider verdict this quest acts on