Skip to content

ts_netstack_smoltcp{_core}: improve netstack accept rate, drain closes#141

Merged
dylan-tailscale merged 1 commit intomainfrom
dylan/tcp-accept
Apr 28, 2026
Merged

ts_netstack_smoltcp{_core}: improve netstack accept rate, drain closes#141
dylan-tailscale merged 1 commit intomainfrom
dylan/tcp-accept

Conversation

@dylan-tailscale
Copy link
Copy Markdown
Collaborator

Moves listening sockets to the accept queue when they reach SYN-RECEIVED (or SYN-SENT) rather than waiting for them to become ESTABLISHED. This opens a new listening socket ready to accept connections from a new remote much earlier than before, meaning there's a much shorter gap where no socket is actually listening on the port. Previously, this gap was mostly responsible for the poor accept rate; under heavy accept load, many potential clients would get a RST while the previous listening socket was stuck in SYN-RECEIVED waiting to transition to ESTABLISHED.

This improved the accept rate to ~60% under heavy load; adding calls to pump_tcp_accept() whenever polling resulted in a changed socket state improved the accept rate to 99%+.

Finally, drains the queue of pending TCP closes on the async side of the netstack; previously, the pending closes were never drained when running the netstack async.

Closes #28 .

Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs
Comment thread ts_netstack_smoltcp_core/src/lib.rs
Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs
@dylan-tailscale dylan-tailscale self-assigned this Apr 24, 2026
Copy link
Copy Markdown
Collaborator

@npry npry left a comment

Choose a reason for hiding this comment

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

Good work on these — the one change I'd push for is splitting the accept queue from the half-open queue, if you agree

Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs
Comment thread ts_netstack_smoltcp_core/src/lib.rs
Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs Outdated
Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs
Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs Outdated
Copy link
Copy Markdown
Collaborator

@npry npry left a comment

Choose a reason for hiding this comment

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

changes look good! just the one note

Comment thread ts_netstack_smoltcp_core/src/socket_impl/tcp/listener.rs Outdated
Moves listening sockets to a new half-open queue when they reach SYN-RECEIVED
then moves those to the accept queue when they become ESTABLISHED. This opens a
new listening socket ready to accept connections from a new remote much earlier
than before, meaning there's a much shorter gap where no socket is actually
listening on the port. Previously, this gap was mostly responsible for the poor
accept rate; under heavy accept load, many potential clients would get a RST
while the previous listening socket was stuck in SYN-RECEIVED waiting to
transition to ESTABLISHED.

This improved the accept rate to ~60% under heavy load; adding calls to
pump_tcp_accept() whenever polling resulted in a changed socket state improved
the accept rate to 99%+.

Finally, drains the queue of pending TCP closes on the async side of the
netstack; previously, the pending closes were never drained when running
the netstack async.

Signed-off-by: Dylan Bargatze <dylan@tailscale.com>
@dylan-tailscale dylan-tailscale merged commit 7e3ef8a into main Apr 28, 2026
18 checks passed
@dylan-tailscale dylan-tailscale deleted the dylan/tcp-accept branch April 28, 2026 18:24
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.

ts_netstack: poor TCP accept performance

2 participants