Increase physical UDP receive and send buffers - #2611
Open
alatteri wants to merge 2 commits into
Open
Conversation
alatteri
marked this pull request as ready for review
August 17, 2026 21:43
alatteri
marked this pull request as draft
August 17, 2026 21:49
alatteri
marked this pull request as ready for review
September 4, 2026 16:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phy::udpBind()API for callers that want one shared sizeProblem
ZeroTier currently applies the same 1 MiB request to both
SO_RCVBUFandSO_SNDBUF. On a high-throughput Linux relay carrying sustained real-time UDPtraffic, the physical ZeroTier sockets accumulated 3,205
UdpRcvbufErrors.The socket drop counters reported by
ssaccounted for all 3,205 errors.At the same time:
UdpSndbufErrorsremained zeroaccounting for the 1 MiB request
This isolates the loss point to burst exhaustion of the physical UDP receive
socket rather than the NIC, route, virtual interface, or UDP send socket.
Separate high-throughput sending workloads can run at roughly twice this
relay's data rate and produce larger short spikes. Doubling the send request
provides moderate transient headroom for those bursts without matching the
larger receive allocation.
Change
Phy::udpBind()now accepts independent receive and send sizes. A compatibilityoverload retains the original three-argument behavior by applying a shared size
to both directions, so existing callers do not change behavior.
The production Binder requests:
SO_RCVBUFSO_SNDBUFThe existing fallback behavior is retained: if the operating system rejects a
requested size, ZeroTier retries progressively smaller values.
Send buffer sizing
The deployed relay did not exhibit send-buffer exhaustion, so the send increase
is not presented as a fix for its receive drops. The 2 MiB value is intended as
a balanced default for higher-rate, bursty senders: it doubles upstream's
transient headroom while remaining smaller than the receive request.
Additional send capacity only adds delay when the outbound path is backlogged.
Persistent
Send-Qgrowth orUdpSndbufErrorsstill indicates an underlyingcapacity or scheduling problem rather than a need for unbounded buffering.
Impact
The change does not alter ZeroTier's wire protocol, encryption, routing, or
packet ordering. It adds burst headroom to physical UDP bindings.
Systems may cap or account for socket buffers differently; the existing
best-effort fallback remains in effect.
On Linux, the 4 MiB/2 MiB requests report as 8 MiB receive and 4 MiB send due
to kernel socket-buffer accounting. The deployed host's
net.core.rmem_maxwas already large enough to permit the request.
Validation
make -j2 selftest./zerotier-selftest(including 10,000 UDP packets)make -j2Deployed monitoring
The receive-buffer change was deployed with the original 1 MiB send request and
monitored continuously for 30 minutes 2 seconds under live relay traffic. This
run validates the receive-side change and provides a stable baseline; the 2 MiB
send request was validated separately by build, self-test, and isolated runtime
socket inspection. During the deployed window, the host processed:
The following counters remained zero for the entire run:
UdpInErrorsUdpRcvbufErrorsUdpSndbufErrorsThe ZeroTier service remained active throughout. One downstream receiver was
rebooted during the window, changing outbound traffic volume without causing
any socket-buffer or interface drops on the relay.