Skip to content

Return NotAvailable instead of TooMuchData when the peer has no datagram path - #3989

Open
jesup wants to merge 1 commit into
users/jesup/expire_datagramsfrom
users/jesup/reject_datagrams
Open

jesup wants to merge 1 commit into
users/jesup/expire_datagramsfrom
users/jesup/reject_datagrams

Conversation

@jesup

@jesup jesup commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

If the peer supports neither QUIC DATAGRAM nor the HTTP DATAGRAM Capsule fallback (remote_datagram_size() == 0 and the protocol has no Capsule support), Session::send_datagram fell through to the queue, which rejected the datagram as TooMuchData. Return Error::Transport(NotAvailable) instead, which says what actually went wrong.

Neither protocol can reach this today: WebTransport is only enabled when the peer's transport parameters allow QUIC DATAGRAM (handle_settings checks remote_datagram_size() > 0), and connect-udp always has the Capsule fallback. So the branch carries a debug_assert! rather than a test.

@jesup

jesup commented Sep 14, 2026 •

Copy link
Copy Markdown
Member Author

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved blocking issues were identified.

Pull request overview

Prevents unsupported or oversized extended-CONNECT datagrams from entering the outgoing queue.

Changes:

  • Validates peer datagram support and encoded size.
  • Returns NotAvailable when datagrams cannot be sent.
  • Adds WebTransport regression coverage.
File summaries
File Description
neqo-http3/src/features/extended_connect/tests/webtransport/datagrams.rs Tests synchronous rejection and queue preservation.
neqo-http3/src/features/extended_connect/session.rs Validates datagram support and size before queueing.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite (auto)

Note

Copilot is running an experiment and ran this review at Lite.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.94%. Comparing base (1f13246) to head (099c751).

Additional details and impacted files
@@                       Coverage Diff                        @@
##           users/jesup/expire_datagrams    #3989      +/-   ##
================================================================
- Coverage                         97.01%   96.94%   -0.08%     
================================================================
  Files                               118      119       +1     
  Lines                             41527    41441      -86     
  Branches                          41527    41441      -86     
================================================================
- Hits                              40287    40174     -113     
- Misses                             1216     1243      +27     
  Partials                             24       24              
Flag Coverage Δ
freebsd 94.43% <50.00%> (-0.09%) ⬇️
linux 97.16% <50.00%> (-0.07%) ⬇️
macos 95.25% <50.00%> (-0.10%) ⬇️
windows 95.34% <50.00%> (-0.10%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
neqo-common 99.31% <ø> (+<0.01%) ⬆️
neqo-http3 95.37% <50.00%> (-0.04%) ⬇️
neqo-qpack 96.97% <ø> (+0.03%) ⬆️
neqo-transport 97.93% <ø> (-0.11%) ⬇️
neqo-udp 95.37% <ø> (ø)
mtu 89.13% <ø> (ø)

@codspeed

codspeed Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will regress 6 benchmarks

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 13 improved benchmarks
❌ 6 regressed benchmarks
✅ 80 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ Simulation decode 1000 STREAM frames 179.6 µs 226.5 µs -20.71%
❌ Simulation decode 100 STREAM frames 19.2 µs 24 µs -20.13%
❌ Simulation decode 10 STREAM frames 3.3 µs 4 µs -15.93%
❌ Simulation Builder encode+encrypt ACK packet 21.9 µs 22.6 µs -3.26%
❌ Simulation Builder encode+encrypt STREAM packet 27.8 µs 28.6 µs -2.77%
❌ Simulation simulated/pacing-false/varying-seeds 73.3 ms 75 ms -2.31%
⚡ Simulation coalesce_acked_from_zero 1 ranges 555.1 µs 2.8 µs ×200
⚡ Simulation coalesce_acked_from_zero 3 ranges 438.3 µs 3.7 µs ×120
⚡ Simulation coalesce_acked_from_zero 10 ranges 541.1 µs 9.9 µs ×55
⚡ Simulation mark_sent sequential 234.2 µs 210.7 µs +11.16%
⚡ Simulation mark_sent retransmit 33.5 µs 32.3 µs +3.94%
⚡ WallTime walltime/1-streams/each-1000-bytes 132.1 µs 128 µs +3.21%
⚡ WallTime walltime/1000-streams/each-1000-bytes 11.6 ms 11.3 ms +2.89%
⚡ WallTime neqo-s2n 49.8 ms 48.5 ms +2.64%
⚡ WallTime walltime/10-streams/each-1048576-bytes 28.7 ms 28 ms +2.55%
⚡ WallTime 1-conn/1-100mb-resp (aka. Download) 49.4 ms 48.2 ms +2.39%
⚡ WallTime walltime/pacing-true/same-seed 2.1 ms 2 ms +2.35%
⚡ WallTime walltime/1-streams/each-4194304-bytes 10.8 ms 10.6 ms +2.29%
⚡ WallTime 1-conn/1-1b-resp (aka. HPS) 3 ms 2.9 ms +2.17%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing users/jesup/reject_datagrams (099c751) with users/jesup/expire_datagrams (5dfb5fe)1

Open in CodSpeed

Footnotes

  1. No successful run was found on users/jesup/expire_datagrams (1f13246) during the generation of this report, so e6df341 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@jesup
jesup force-pushed the users/jesup/process_when_only_a_datagram branch from f4bbb65 to d2a658d Compare September 14, 2026 05:31
@jesup
jesup requested a review from omansfeld as a code owner September 14, 2026 05:31
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from b9ff5cb to 61a5677 Compare September 14, 2026 05:31
@jesup
jesup force-pushed the users/jesup/process_when_only_a_datagram branch from d2a658d to 7057d30 Compare September 14, 2026 17:56
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from 61a5677 to ae0ac84 Compare September 14, 2026 17:56
@jesup
jesup force-pushed the users/jesup/process_when_only_a_datagram branch from 7057d30 to e16793a Compare September 16, 2026 03:45
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from ae0ac84 to 24ea77f Compare September 16, 2026 03:45
@jesup
jesup force-pushed the users/jesup/process_when_only_a_datagram branch from e16793a to 29d2f7b Compare September 16, 2026 17:19
@codspeed

codspeed Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

@codspeedbot do a separate PR that adds the "edited" trigger. Think hard if other fixes are needed, too.

I opened #4022. It adds the edited trigger to codspeed.yml, so a PR gets a CodSpeed run when its base branch changes. Only codspeed.yml changes. actionlint and zizmor pass, but the workflow hasn't run on GitHub yet.

What it changes:

  • edited trigger: added to the pull_request types, next to the default opened, synchronize and reopened.
  • Base changes only: the three root jobs (bench-matrix, build-neqo, build-others) only run for a non-edited event or when github.event.changes.base is set. Editing a title or description skips everything.

Other fixes I made:

  1. Title edits would have cancelled runs. The concurrency group is per PR, with cancel-in-progress: true. That cancellation happens even when every job in the new run gets skipped. So adding edited alone would have let a PR rename cancel a 35–40 min run. Edits that don't change the base now get their own group (suffixed with run_id), so they cancel nothing. Pushes and base changes still share the per-PR group, so cancellation works as before.
  2. benchmarks could start after a skipped bench-matrix. Its !cancelled() condition doesn't stop it when bench-matrix is skipped, and it would then fail on an empty matrix. It now also requires needs.bench-matrix.result == 'success'.
  3. A stale merge commit could be filed under the new head. CodSpeed files results under pull_request.head.sha, but the job benchmarks refs/pull/N/merge. Right after a base change resolves a conflict, GitHub might not have updated that merge ref yet. I haven't confirmed this happens, so I added a cheap guard. bench-matrix now fails if the checked-out commit neither is the head nor has it as a parent. perfcompare now also waits for bench-matrix, so neither upload job can publish results for the wrong code. bench-matrix finishes long before the builds do, so this adds no delay.

Side effect: when a PR in the stack merges and its branch is deleted, GitHub moves the next PR's base to main. That also counts as a base change, so the next PR now gets a fresh run against main.

Not changed: the other pull_request workflows (check.yml, bench.yml, perfcompare.yml, qns-pr.yml, …) have the same gap. That's why those commits are also missing CI checks and bot comments. I kept #4022 limited to CodSpeed. Having jj-stack change the base before pushing the head would fix all of these workflows at once.

Summary
  • Warming up the performance wizard...
  • Design the base-change trigger for codspeed.yml — Plan: add edited, but only run when the base branch changed; keep title/description edits from cancelling in-progress runs; check that the checked-out merge commit contains the PR head
  • Implement and lint the workflow change — actionlint and zizmor pass
  • Open a separate PR — ci: run PR workflows when a PR's base branch changes #4022
  • Handling comment — Comment handling finished successfully

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

@jesup
jesup force-pushed the users/jesup/expire_datagrams branch from 325e0d2 to 4ba7feb Compare September 25, 2026 10:28
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from 00c69c0 to 83a14a7 Compare September 25, 2026 10:28
@jesup
jesup force-pushed the users/jesup/expire_datagrams branch from 4ba7feb to 31e9004 Compare September 25, 2026 12:35
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from 83a14a7 to 66c3fce Compare September 25, 2026 12:35
@jesup
jesup force-pushed the users/jesup/expire_datagrams branch from 31e9004 to 3a9684b Compare September 25, 2026 15:05
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from 66c3fce to 2f3db78 Compare September 25, 2026 15:05
@jesup
jesup force-pushed the users/jesup/expire_datagrams branch 4 times, most recently from 40e8b3a to 8a6e7f8 Compare September 30, 2026 03:21
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from 2f3db78 to a5622da Compare September 30, 2026 03:30
@jesup
jesup force-pushed the users/jesup/expire_datagrams branch from 8a6e7f8 to 5dfb5fe Compare September 30, 2026 15:32
@jesup
jesup force-pushed the users/jesup/reject_datagrams branch from a5622da to 5c574b1 Compare September 30, 2026 15:32
Comment thread neqo-http3/src/features/extended_connect/session.rs Outdated

@mxinden mxinden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think the pull request title matches the diff. This change does not reject more datagrams than before.

@jesup

jesup commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

I don't think the pull request title matches the diff. This change does not reject more datagrams than before.

Got bit again by git not updating PR titles when I retitle the patch description. I'll correct it

@jesup jesup changed the title Reject datagrams the peer can't accept before they reach the queue Return NotAvailable instead of TooMuchData when the peer has no datagram path Oct 2, 2026
@jesup

jesup commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

The title is fixed now, and I've filled in the description. You're right that it rejects nothing new: it only changes which error an unreachable path returns, and asserts in debug builds that it stays unreachable. This has collapsed down to almost nothing...

…ram path

If the peer supports neither QUIC DATAGRAM nor the HTTP DATAGRAM Capsule
fallback (remote_datagram_size == 0, capsule unsupported), send_datagram fell
through to the queue, which rejected the datagram as TooMuchData.  Return
Error::Transport(NotAvailable) instead.  Neither WebTransport nor connect-udp
can reach this today, so the branch is backed by a debug_assert.
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

No significant performance differences relative to 1f13246.

All results
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1500
       time:   [49.374 ms 49.446 ms 49.558 ms]
       thrpt:  [1.9705 GiB/s 1.9750 GiB/s 1.9779 GiB/s]
Found 3 outliers among 100 measurements (3.00%)
1 (1.00%) high mild
2 (2.00%) high severe
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1500
       time:   [49.913 ms 49.951 ms 49.993 ms]
       thrpt:  [1.9534 GiB/s 1.9550 GiB/s 1.9565 GiB/s]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1500
       time:   [2.9284 ms 2.9298 ms 2.9313 ms]
       thrpt:  [341.15   B/s 341.32   B/s 341.48   B/s]
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high mild
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1500
       time:   [65.882 ms 66.167 ms 66.461 ms]
       thrpt:  [150.46 Kelem/s 151.13 Kelem/s 151.79 Kelem/s]
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high mild
streams-flow-controlled/walltime/1-streams/each-4194304-bytes
       time:   [10.688 ms 10.691 ms 10.693 ms]
       thrpt:  [374.07 MiB/s 374.16 MiB/s 374.25 MiB/s]
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
streams-flow-controlled/walltime/10-streams/each-1048576-bytes
       time:   [27.616 ms 27.627 ms 27.638 ms]
       thrpt:  [361.81 MiB/s 361.97 MiB/s 362.11 MiB/s]
Found 4 outliers among 100 measurements (4.00%)
4 (4.00%) high mild
streams/walltime/1-streams/each-1000-bytes
       time:   [129.00 µs 129.45 µs 130.03 µs]
       thrpt:  [7.3343 MiB/s 7.3670 MiB/s 7.3931 MiB/s]
Found 3 outliers among 100 measurements (3.00%)
3 (3.00%) high mild
streams/walltime/1000-streams/each-1-bytes
       time:   [3.7407 ms 3.7533 ms 3.7654 ms]
       thrpt:  [259.35 KiB/s 260.18 KiB/s 261.06 KiB/s]
streams/walltime/1000-streams/each-1000-bytes
       time:   [11.040 ms 11.044 ms 11.048 ms]
       thrpt:  [86.323 MiB/s 86.355 MiB/s 86.387 MiB/s]
Found 3 outliers among 100 measurements (3.00%)
2 (2.00%) low mild
1 (1.00%) high mild
transfer/walltime/pacing-false/same-seed
       time:   [2.0139 ms 2.0153 ms 2.0168 ms]
       thrpt:  [1.9368 GiB/s 1.9383 GiB/s 1.9396 GiB/s]
transfer/walltime/pacing-false/varying-seeds
       time:   [2.0342 ms 2.0356 ms 2.0371 ms]
       thrpt:  [1.9175 GiB/s 1.9190 GiB/s 1.9203 GiB/s]
transfer/walltime/pacing-true/same-seed
       time:   [2.0311 ms 2.0320 ms 2.0332 ms]
       thrpt:  [1.9212 GiB/s 1.9223 GiB/s 1.9233 GiB/s]
transfer/walltime/pacing-true/varying-seeds
       time:   [2.0669 ms 2.0683 ms 2.0701 ms]
       thrpt:  [1.8870 GiB/s 1.8886 GiB/s 1.8899 GiB/s]

Instructions per cycle

Criterion reported no significant timing changes.

All benchmarks
Benchmark IPC before IPC after ΔIPC
transfer/walltime/pacing-true/same-seed 2.86 2.89 +0.9%
streams/walltime/1000-streams/each-1-bytes 3.33 3.31 -0.7%
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1500 3.16 3.18 +0.5%
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1500 3.24 3.26 +0.5%
streams-flow-controlled/walltime/1-streams/each-4194304-bytes 3.02 3.03 +0.5%
streams/walltime/1000-streams/each-1000-bytes 3.07 3.08 +0.4%
streams/walltime/1-streams/each-1000-bytes 2.55 2.54 -0.3%
transfer/walltime/pacing-true/varying-seeds 2.90 2.89 -0.3%
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1500 3.23 3.22 -0.2%
transfer/walltime/pacing-false/varying-seeds 2.87 2.88 +0.2%
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1500 2.25 2.24 -0.1%
streams-flow-controlled/walltime/10-streams/each-1048576-bytes 3.21 3.21 -0.1%
transfer/walltime/pacing-false/same-seed 2.89 2.90 +0.1%
Profiles for profiler.firefox.com (62)

Download data for profiler.firefox.com or download performance comparison data.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to users/jesup/expire_datagrams at 1f13246.

neqo-pr as clientneqo-pr as server
neqo-pr vs. go-x-net: BP BA
neqo-pr vs. haproxy: BP BA
neqo-pr vs. kwik: 🚀Z 3 ⚠️H L1 C1 🚀6
neqo-pr vs. lsquic: L1 C1
neqo-pr vs. msquic: Z A L1 C1
neqo-pr vs. mvfst: A
neqo-pr vs. neqo: Z A
neqo-pr vs. nginx: BP BA
neqo-pr vs. ngtcp2: Z L1 ⚠️C1 CM
neqo-pr vs. picoquic: Z A
neqo-pr vs. quic-go: A
neqo-pr vs. quiche: BP BA
neqo-pr vs. s2n-quic: CM
neqo-pr vs. tquic: S BP BA
neqo-pr vs. xquic: S R Z A L1 C1
aioquic vs. neqo-pr: ⚠️L1 CM
go-x-net vs. neqo-pr: CM
kwik vs. neqo-pr: BP BA CM
lsquic vs. neqo-pr: ⚠️C1
msquic vs. neqo-pr: CM
mvfst vs. neqo-pr: Z L1 C1 CM
neqo vs. neqo-pr: run cancelled after 20 min
openssl vs. neqo-pr: LR M A CM
quic-go vs. neqo-pr: CM
quic-zig vs. neqo-pr: ⚠️L1 CM
quiche vs. neqo-pr: CM
quinn vs. neqo-pr: ⚠️C1 V2 CM
s2n-quic vs. neqo-pr: ⚠️B C1 BA CM
tquic vs. neqo-pr: CM
xquic vs. neqo-pr: M CM
All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Client/server transfer results

Performance differences relative to 1f13246.

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server Mean±σ Min–Max Median±MAD MiB/s±σ ΔMedian
google-neqo-cubic 69.5 ± 0.4 68.8 – 70.6 69.5 ± 0.3 460.1 ± 2.6 💔 +0.7 (+1.0%)
neqo-neqo-newreno 19.8 ± 0.1 19.4 – 20.3 19.8 ± 0.2 1616.3 ± 11.5 💔 +0.3 (+1.6%)

Table above only shows statistically significant changes. See all results below.

All results

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server Mean±σ Min–Max Median±MAD MiB/s±σ ΔMedian
google-google 133.4 ± 0.5 132.1 – 135.5 133.4 ± 0.6 239.9 ± 1.0
google-neqo-cubic 69.5 ± 0.4 68.8 – 70.6 69.5 ± 0.3 460.1 ± 2.6 💔 +0.7 (+1.0%)
neqo-google-cubic 228.5 ± 27.1 171.6 – 290.5 227.0 ± 31.2 140.0 ± 16.6 -2.8 (-1.2%)
neqo-neqo-cubic 19.5 ± 0.2 19.2 – 19.9 19.5 ± 0.2 1640.9 ± 13.3 -0.1 (-0.7%)
neqo-neqo-cubic-nopacing 19.0 ± 0.1 18.6 – 19.4 19.0 ± 0.1 1681.0 ± 12.9 -0.1 (-0.5%)
neqo-neqo-newreno 19.8 ± 0.1 19.4 – 20.3 19.8 ± 0.2 1616.3 ± 11.5 💔 +0.3 (+1.6%)
neqo-neqo-newreno-nopacing 19.4 ± 0.2 18.9 – 19.9 19.4 ± 0.1 1648.3 ± 13.3 +0.1 (+0.4%)
neqo-quiche-cubic 32.8 ± 0.3 32.3 – 33.5 32.8 ± 0.3 975.1 ± 8.5 +0.2 (+0.5%)
neqo-s2n-cubic 37.7 ± 0.3 37.2 – 38.3 37.8 ± 0.3 847.8 ± 6.0 -0.0 (-0.0%)
quiche-neqo-cubic ⚠️ 38.7 ± 0.3 38.2 – 40.7 38.6 ± 0.2 827.3 ± 6.7 +0.2 (+0.5%)
quiche-quiche 39.0 ± 0.2 38.7 – 39.7 39.0 ± 0.1 819.9 ± 4.1
s2n-neqo-cubic 113.4 ± 0.4 112.3 – 114.3 113.4 ± 0.4 282.2 ± 0.9 +0.1 (+0.1%)
s2n-s2n ⚠️ 167.4 ± 30.0 135.9 – 282.8 160.0 ± 0.8 191.1 ± 34.3

Download data for profiler.firefox.com or download performance comparison data.

This branch has not been deployed

No deployments
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.

4 participants