Skip to content

fix: Handle ENOBUFS in UDP send#3482

Open
larseggert wants to merge 1 commit intomozilla:mainfrom
larseggert:fix-enobufs
Open

fix: Handle ENOBUFS in UDP send#3482
larseggert wants to merge 1 commit intomozilla:mainfrom
larseggert:fix-enobufs

Conversation

@larseggert
Copy link
Copy Markdown
Collaborator

Based on a discussion with @ianswett yesterday, don't treat ENOBUFS as a fatal error when sending UDP packets.

Copilot AI review requested due to automatic review settings March 17, 2026 02:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates neqo-udp’s UDP send error handling to avoid treating ENOBUFS as a fatal send error, aligning send behavior with transient NIC/stack buffer exhaustion on some platforms.

Changes:

  • Treat ENOBUFS from UdpSocketState::try_send() as io::ErrorKind::WouldBlock instead of a hard error.
  • Add is_enobufs() helper (unix-gated) and update unit tests to account for the new predicate.

You can also share your feedback on Copilot code review. Take the survey.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.17%. Comparing base (07f7838) to head (e992c68).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3482      +/-   ##
==========================================
- Coverage   94.30%   94.17%   -0.13%     
==========================================
  Files         127      131       +4     
  Lines       38711    39053     +342     
  Branches    38711    39053     +342     
==========================================
+ Hits        36505    36777     +272     
- Misses       1365     1427      +62     
- Partials      841      849       +8     
Flag Coverage Δ
freebsd 93.21% <86.36%> (-0.10%) ⬇️
linux 94.27% <86.36%> (-0.01%) ⬇️
macos 94.16% <86.36%> (-0.03%) ⬇️
windows 94.26% <58.33%> (-0.04%) ⬇️

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

Components Coverage Δ
neqo-common 98.49% <ø> (ø)
neqo-crypto 86.90% <ø> (ø)
neqo-http3 93.91% <ø> (ø)
neqo-qpack 94.81% <ø> (ø)
neqo-transport 95.20% <ø> (-0.05%) ⬇️
neqo-udp 82.18% <83.33%> (-0.80%) ⬇️
mtu 86.61% <ø> (ø)

@larseggert larseggert force-pushed the fix-enobufs branch 3 times, most recently from 04de82b to 345f3cf Compare March 17, 2026 09:02
Based on a discussion with @ianswett yesterday, don't treat `ENOBUFS` as a fatal error when sending UDP packets.
@github-actions
Copy link
Copy Markdown
Contributor

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to main at 2cd5820.

neqo-pr as clientneqo-pr as server
neqo-pr vs. go-x-net: BP BA
neqo-pr vs. haproxy: ⚠️C1 BP BA
neqo-pr vs. kwik: S L1 C1 BP BA
neqo-pr vs. linuxquic: ⚠️L1
neqo-pr vs. lsquic: L1 C1
neqo-pr vs. msquic: A L1 C1
neqo-pr vs. mvfst: H DC LR M R Z 3 B U A L1 L2 C1 C2 6 BP BA
neqo-pr vs. neqo: Z A
neqo-pr vs. nginx: BP BA
neqo-pr vs. ngtcp2: CM
neqo-pr vs. picoquic: A
neqo-pr vs. quic-go: A
neqo-pr vs. quiche: BP BA
neqo-pr vs. quinn: ⚠️L1
neqo-pr vs. s2n-quic: BP BA CM
neqo-pr vs. tquic: S BP BA
neqo-pr vs. xquic: A L1 ⚠️C1
aioquic vs. neqo-pr: Z CM
go-x-net vs. neqo-pr: CM
kwik vs. neqo-pr: Z BP BA CM
linuxquic vs. neqo-pr: Z
lsquic vs. neqo-pr: Z
msquic vs. neqo-pr: Z BA CM
mvfst vs. neqo-pr: Z A L1 C1 CM
neqo vs. neqo-pr: Z A ⚠️BP
openssl vs. neqo-pr: LR M A CM
picoquic vs. neqo-pr: Z CM
quic-go vs. neqo-pr: 🚀BA CM
quiche vs. neqo-pr: Z 🚀L1 ⚠️C1 CM
quinn vs. neqo-pr: Z V2 CM
s2n-quic vs. neqo-pr: CM
tquic vs. neqo-pr: Z 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
Copy link
Copy Markdown
Contributor

Benchmark results

No significant performance differences relative to 2cd5820.

All results
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1504: Change within noise threshold.
       time:   [199.79 ms 200.23 ms 200.74 ms]
       thrpt:  [498.15 MiB/s 499.43 MiB/s 500.52 MiB/s]
change:
       time:   [-1.3960% -1.0768% -0.7316] (p = 0.00 < 0.05)
       thrpt:  [+0.7370% +1.0885% +1.4157]
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1504: Change within noise threshold.
       time:   [286.19 ms 287.93 ms 289.71 ms]
       thrpt:  [34.517 Kelem/s 34.730 Kelem/s 34.942 Kelem/s]
change:
       time:   [+0.7749% +1.7085% +2.6814] (p = 0.00 < 0.05)
       thrpt:  [-2.6113% -1.6798% -0.7689]
       Change within noise threshold.
Found 3 outliers among 100 measurements (3.00%)
3 (3.00%) high mild
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1504: No change in performance detected.
       time:   [38.518 ms 38.650 ms 38.798 ms]
       thrpt:  [25.774   B/s 25.873   B/s 25.962   B/s]
change:
       time:   [-0.0674% +0.3627% +0.8649] (p = 0.13 > 0.05)
       thrpt:  [-0.8575% -0.3613% +0.0674]
       No change in performance detected.
Found 5 outliers among 100 measurements (5.00%)
1 (1.00%) high mild
4 (4.00%) high severe
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1504: No change in performance detected.
       time:   [203.70 ms 204.11 ms 204.54 ms]
       thrpt:  [488.91 MiB/s 489.94 MiB/s 490.91 MiB/s]
change:
       time:   [-0.4962% -0.1651% +0.1384] (p = 0.32 > 0.05)
       thrpt:  [-0.1383% +0.1654% +0.4987]
       No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
streams/walltime/1-streams/each-1000-bytes: No change in performance detected.
       time:   [583.76 µs 585.79 µs 588.16 µs]
       change: [-0.2605% +0.2787% +0.8354] (p = 0.31 > 0.05)
       No change in performance detected.
Found 10 outliers among 100 measurements (10.00%)
1 (1.00%) high mild
9 (9.00%) high severe
streams/walltime/1000-streams/each-1-bytes: No change in performance detected.
       time:   [12.479 ms 12.510 ms 12.554 ms]
       change: [-0.0931% +0.2694% +0.6763] (p = 0.18 > 0.05)
       No change in performance detected.
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high severe
streams/walltime/1000-streams/each-1000-bytes: Change within noise threshold.
       time:   [45.341 ms 45.388 ms 45.436 ms]
       change: [+0.8729% +1.0265% +1.1562] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high mild
transfer/walltime/pacing-false/varying-seeds: No change in performance detected.
       time:   [80.282 ms 80.337 ms 80.395 ms]
       change: [-0.3641% -0.1638% -0.0158] (p = 0.06 > 0.05)
       No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
transfer/walltime/pacing-true/varying-seeds: Change within noise threshold.
       time:   [79.728 ms 79.794 ms 79.868 ms]
       change: [-0.2832% -0.1503% -0.0198] (p = 0.02 < 0.05)
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high severe
transfer/walltime/pacing-false/same-seed: Change within noise threshold.
       time:   [80.094 ms 80.152 ms 80.217 ms]
       change: [+0.3772% +0.6063% +0.7907] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
transfer/walltime/pacing-true/same-seed: No change in performance detected.
       time:   [79.841 ms 79.886 ms 79.932 ms]
       change: [-0.2220% -0.0203% +0.1439] (p = 0.84 > 0.05)
       No change in performance detected.
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high mild

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

@github-actions
Copy link
Copy Markdown
Contributor

Client/server transfer results

Performance differences relative to 2cd5820.

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

Client vs. server (params) Mean ± σ Min Max MiB/s ± σ Δ baseline Δ baseline
neqo-neqo-newreno 95.0 ± 4.0 87.8 104.8 336.9 ± 8.0 💚 -1.3 -1.3%
neqo-quiche-cubic 193.2 ± 5.2 185.8 212.1 165.7 ± 6.2 💔 2.6 1.4%
neqo-s2n-cubic 219.0 ± 4.0 212.3 228.8 146.1 ± 8.0 💔 2.2 1.0%

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 (params) Mean ± σ Min Max MiB/s ± σ Δ baseline Δ baseline
google-google-nopacing 450.3 ± 4.5 442.6 462.3 71.1 ± 7.1
google-neqo-cubic 270.6 ± 4.7 261.2 287.8 118.2 ± 6.8 0.8 0.3%
msquic-msquic-nopacing 142.7 ± 47.4 112.4 437.1 224.3 ± 0.7
msquic-neqo-cubic 162.9 ± 46.9 116.9 381.8 196.5 ± 0.7 -0.2 -0.1%
neqo-google-cubic 748.4 ± 10.1 682.0 810.5 42.8 ± 3.2 1.4 0.2%
neqo-msquic-cubic 153.2 ± 4.2 147.1 161.5 208.9 ± 7.6 -0.2 -0.1%
neqo-neqo-cubic 97.7 ± 4.8 89.5 107.0 327.5 ± 6.7 0.5 0.6%
neqo-neqo-cubic-nopacing 95.8 ± 4.2 88.3 104.3 334.0 ± 7.6 -0.7 -0.7%
neqo-neqo-newreno 95.0 ± 4.0 87.8 104.8 336.9 ± 8.0 💚 -1.3 -1.3%
neqo-neqo-newreno-nopacing 95.8 ± 4.7 87.3 104.6 334.1 ± 6.8 -0.4 -0.4%
neqo-quiche-cubic 193.2 ± 5.2 185.8 212.1 165.7 ± 6.2 💔 2.6 1.4%
neqo-s2n-cubic 219.0 ± 4.0 212.3 228.8 146.1 ± 8.0 💔 2.2 1.0%
quiche-neqo-cubic 182.5 ± 6.7 171.8 211.6 175.3 ± 4.8 -1.1 -0.6%
quiche-quiche-nopacing 140.8 ± 4.0 134.9 154.0 227.3 ± 8.0
s2n-neqo-cubic 220.5 ± 4.7 210.5 228.8 145.1 ± 6.8 0.2 0.1%
s2n-s2n-nopacing 296.5 ± 27.7 280.1 425.2 107.9 ± 1.2

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

Copy link
Copy Markdown
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

I would prefer fixing this issue in quinn-udp, thus de-duplicating the logic across the various usages.

quinn-rs/quinn#2293

@larseggert
Copy link
Copy Markdown
Collaborator Author

No objections!

@larseggert
Copy link
Copy Markdown
Collaborator Author

@mxinden quinn-rs/quinn#2293 got closed - what now?

@mxinden
Copy link
Copy Markdown
Member

mxinden commented Apr 1, 2026

@larseggert let's try to get to the root of the discussion. I prepared quinn-rs/quinn#2594. Can you help out?

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.

3 participants