Skip to content

fix(net): support TCP listen backlog updates - #2315

Merged
fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-tcp-relisten-backlog
Sep 21, 2026
Merged

fslongjin merged 1 commit into
DragonOS-Community:masterfrom
fslongjin:codex/fix-tcp-relisten-backlog

Conversation

@fslongjin

Copy link
Copy Markdown
Member

Problem

nginx calls listen() again while configuring its backlog. DragonOS rejected every already-listening TCP socket with EINVAL, producing listen() ... failed, ignored warnings for both address families even though the initial listener remained usable.

Changes

  • Support backlog updates on an existing listener without replacing its bind reservation or address-family domain.
  • Normalize the syscall's int backlog using Linux's unsigned somaxconn comparison, including negative and large arguments.
  • Share bounded per-interface slot growth between initial and repeated listen. This also avoids leaving wildcard listeners with only one slot on non-primary interfaces after growth.
  • Preserve pending connections when shrinking; retire surplus idle/reset slots and stop replacing surplus accepted slots. Use existing event notifications for deferred retirement, without a polling worker.
  • Reclaim closed slots before healthy listeners, rearm retained reset children under the SocketSet lock, and avoid cached accept indices invalidated by resizing.
  • Preserve the receive-policy cache when updating an existing listener registration.
  • Add 40 required dunitest cases across IPv4/IPv6 and specific/wildcard addresses.

Validation

Check Result
Pre-fix DragonOS reproducer 20 of initial 24 cases failed; default nginx reproduced warnings on both listeners
Final new suite on Linux 40/40 passed
Final new suite on DragonOS 40/40 passed, no skips
Existing DragonOS TCP/UDP/socket-option regressions 71/71 passed
Five additional guest repetitions 200/200 passed
Default nginx configuration check and startup Passed without repeated-listen warnings
Default IPv4 and IPv6 HTTP Both passed, 615-byte responses
Reload control command and subsequent IPv4 HTTP Passed; not a claim of complete worker lifecycle coverage
make kernel, make fmt, FMT_CHECK=1 make fmt Passed
Independent adversarial review Plan review and two three-role implementation rounds completed; the closed-slot retirement finding was fixed and re-reviewed

Scope and limits

This remains bounded per-interface smoltcp slot emulation, not Linux's global accept queue. Each interface has at most eight slots, approximately 2 MiB of TCP buffers per listener. Aggregate queue limits and nonzero-backlog saturation behavior are not claimed to match Linux completely.

This does not resolve the separately tracked nginx concurrency, TLS response, graceful-exit, or TCP TIME_WAIT issues. Allocation-failure injection and raw half-open SYN/RST injection were not performed; completed-connection resets are covered. Remote CI will run after submission.

Accept repeated listen calls in the Listening state instead of rejecting the normal nginx backlog configuration path with EINVAL. Normalize the syscall int backlog using the Linux unsigned somaxconn comparison.

Share bounded per-interface slot growth between initial and repeated listening so wildcard listeners can grow on every covered interface. Retain address-family domains and port reservations, preserve pending connections on shrink, and retire excess slots on accept or existing event notifications.

Reclaim Closed slots before healthy listeners and rearm retained reset children under the SocketSet lock. Remove the cached accept index so resizing cannot leave stale indices. Preserve the receive-policy cache when updating an existing listener registration.

Add 40 dunitest cases covering IPv4/IPv6, specific/wildcard addresses, repeated listen, growth, shrink, reset children and backlog boundaries. Register the suite for required CI execution.

Validation: pre-fix DragonOS failed 20 of the initial 24 tests and reproduced both nginx warnings. Final Linux and DragonOS suites pass 40/40; 71 existing guest regressions pass; five additional guest repetitions pass 200/200. Default nginx starts without the warnings and serves both IP families. Kernel build, format checks and two-round independent adversarial review passed.

The implementation remains bounded per-interface slot emulation, not a complete Linux global accept queue. Each interface uses at most eight slots, approximately 2 MiB of TCP buffers per listener.

Signed-off-by: longjin <longjin@dragonos.org>
@github-actions github-actions Bot added the Bug fix A bug is fixed in this pull request label Sep 21, 2026
@fslongjin

Copy link
Copy Markdown
Member Author

@codex review

@fslongjin
fslongjin merged commit 368619e 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant