Skip to content

fix: correct UDP errqueue classification and timerfd polling tests - #2309

Merged
fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-udp-errqueue-timerfd-ci
Sep 21, 2026
Merged

fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-udp-errqueue-timerfd-ci

Conversation

@fslongjin

Copy link
Copy Markdown
Member

Summary

Address two independent CI failures:

  1. UDP error queue: classify EMSGSIZE reporting by the actual packet destination, not only the socket's creation family. IPv4 and IPv4-mapped sends must not produce native IPv6 local error records. Reuse the resolved destination snapshot for connected sends on the ordinary output path.
  2. timerfd regression test: equal deadlines do not guarantee that one poll observes all expiry callbacks. Accumulate unique ready descriptors under a fixed monotonic deadline while preserving cancellation, tick-count and cleanup checks.

The UDP policy remains in the existing error queue helper. There are no new locks or protocol states, no changes to timerfd kernel scheduling, and no modifications to gVisor reference tests. The correct IPv6 socket name-query ABI is preserved.

Root cause and coverage

  • Original CI failures: dual-stack PayloadTooBig/2 and /5 returned an error queue record instead of EAGAIN; the same-deadline timerfd test observed 9 ready descriptors while requiring 16 in one call.
  • Added UDP coverage spans IPv4, IPv6 sockets with IPv4 sockaddr, mapped and native IPv6 destinations, connected/explicit sends and RECVERR enablement. Positive cases validate error metadata, destination address/port, and queue consumption.
  • The timerfd case still requires all 16 active timers, exactly one tick each, no cancelled timer events, and empty descriptors after consumption. It does not weaken the expected count or rely on extra sleeps.

Validation

Environment Result
Unmodified master in DragonOS Original gVisor dual-stack failures and both new UDP regression failures reproduced
Linux UDP dunitest 22/22; timerfd 9/9; same-deadline case 20 iterations; gVisor PayloadTooBig 6/6
Fixed DragonOS, QEMU/KVM x86_64, 2 vCPUs UDP 22/22; timerfd 9/9; poll 4/4; alarm 4/4
Fixed DragonOS repeated timerfd case 30 additional iterations passed
Unmodified full gVisor UDP loopback binary 528 passed, 18 existing skips, zero failures
Build / formatting make kernel; FMT_CHECK=1 make fmt; git diff --check

Independent plan, UDP implementation and test reviews found no blocking issues.

Limits

The old timerfd assertion passed ten local baseline iterations; its failure was captured in CI and its assumption is not guaranteed by poll semantics. This change does not claim complete MTU/IPv4 ICMP error queue compatibility. Native IPv6 non-loopback output was reviewed at the code level, not separately exercised end-to-end. Full repository-wide gVisor and dunitest runs are left to CI; existing skips are not counted as passes.

Dual-stack UDP sockets can send IPv4 packets even though their socket
family is IPv6. Do not generate an IPv6 local EMSGSIZE error queue entry
for IPv4 or IPv4-mapped destinations. Require an actual native IPv6
destination in the existing error queue helper and pass the resolved
send destination on the ordinary output path, including connected sends.
Keep native IPv6 error reporting and name-query ABI behavior intact.

Extend the existing UDP dunitest suite across socket and packet families,
connected and explicit sends, and RECVERR enablement. Verify positive
IPv6 error metadata and destination identity as well as empty queues for
IPv4 paths and after consumption.

The same-deadline timerfd test assumed a single poll must observe every
active timer. Poll may legally return a partially ready set. Collect each
active descriptor once within one monotonic deadline, preserve cancelled
descriptor checks, and require one tick per active timer with no unread
ticks left. Use existing fd ownership to clean up assertion failures.

Validation:
- Reproduced both original gVisor dual-stack PayloadTooBig failures and
  both new UDP regression failures on the unmodified master kernel.
- Linux: UDP dunitest 22/22, timerfd 9/9, same-deadline case 20 iterations,
  and original gVisor PayloadTooBig 6/6 pass.
- Fixed DragonOS QEMU/KVM: UDP 22/22, timerfd 9/9, poll 4/4, alarm 4/4;
  same-deadline timerfd case passes 30 additional iterations.
- Unmodified gVisor UDP loopback binary: 528 passed, 18 existing skips,
  zero failures; all six PayloadTooBig variants pass.
- make kernel, FMT_CHECK=1 make fmt, and diff checks pass.

Keep timerfd kernel logic and gVisor reference tests unchanged. Broader
IPv4 ICMP error queue and MTU metadata behavior are outside this change.

Signed-off-by: longjin <longjin@dragonos.org>
@github-actions github-actions Bot added Bug fix A bug is fixed in this pull request test Unitest/User space test labels Sep 21, 2026
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@fslongjin
fslongjin merged commit 1ee38f6 into DragonOS-Community:master Sep 21, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix A bug is fixed in this pull request test Unitest/User space test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant