Skip to content

feat(uring): carry ECN on the io_uring UDP path - #3821

Draft
kixelated wants to merge 3 commits into
mainfrom
quest/m2/quic/ecn-uring
Draft

kixelated wants to merge 3 commits into
mainfrom
quest/m2/quic/ecn-uring

Conversation

@kixelated

@kixelated kixelated commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Completes and deletes quest/m2/quic/ecn-uring.md; ecn-measure.md becomes ready and ecn.md (L4S) drops the blocker.

rs/moq-uring/src/udp.rs carried only UDP_SEGMENT on send and UDP_GRO on receive, so a relay on the io_uring runtime never marked ECT(0) and never read a mark back. The peer's ACKs carried no ECN counts and noq-proto disabled ECN on the first one. noq-udp already did this right; this brings the ring's path level with it.

  • udp::Ecn (Ect0/Ect1/Ce, same bits as noq's EcnCodepoint) and udp::Transmit { to, len, segment, ecn }; TxBuf::send takes the struct instead of growing to four arguments.
  • Send writes IP_TOS (v4 or v4-mapped destination) or IPV6_TCLASS beside UDP_SEGMENT in the same control buffer, so a GSO train marks every segment.
  • Bind enables IP_RECVTOS and, on a v6 socket, IPV6_RECVTCLASS too (Linux reports a v4-mapped datagram's mark as IP_TOS). Failure is an error, not a warning.
  • gro_stride becomes a RecvMeta walk over every control message; Packet::ecn() reports the mark (GRO only coalesces datagrams with the same TOS, so one per completion is exact).
  • The noq and quinn adapter passes Transmit::ecn at both send sites and Packet::ecn() into both Endpoint::handle calls. quiche has no ECN API; its callers send unmarked.

Regression

rs/moq-uring/tests/ecn.rs: a worker socket pair round-trips ECT(0) over v4 and v6 as a lone datagram, a GSO train, and with GRO/GSO/multishot off; CE survives; an unmarked send reads back None. Fails on main (no cmsg either way). Runs in the existing rs uring nightly lane and skips loudly below the kernel floor like its siblings.

Verification

cargo clippy -p moq-uring --lib --target x86_64-unknown-linux-gnu -D warnings passes cross-compiled from macOS for the noq, quinn, and qlog feature sets. The test targets cannot be cross-checked from macOS (boring-sys bindgen needs Linux libc headers), so the tests have not run yet; they need a Linux 6.12+ box: just rs uring.

Public API and wire impact

moq-uring is 0.0.1 and unpublished. udp::TxBuf::send signature changes, udp::Ecn, udp::Transmit, and udp::Packet::ecn are new. No wire, config, or doc change; a relay's packets now carry ECT(0) on the io_uring runtime, as they already did on tokio.

🤖 Generated with Claude Code

(written by Claude Opus 5)

kixelated and others added 3 commits September 20, 2026 12:54
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The ring's sends carried only UDP_SEGMENT and its receives only UDP_GRO,
so a relay on the io_uring runtime never marked ECT(0) and never read a
mark back; the peer's ACKs carried no ECN counts and noq disabled ECN on
the first one. TxBuf::send takes a Transmit with the codepoint, the
socket enables IP_RECVTOS and IPV6_RECVTCLASS, and Packet::ecn reports
what arrived. The noq and quinn adapters pass it both ways; quiche has no
ECN API and sends unmarked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kixelated
kixelated force-pushed the quest/m2/quic/ecn-uring branch from b8297f7 to 220c91f Compare September 20, 2026 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant