tailnet: honor debug MTU for nested paths - #130
Draft
linonetwo wants to merge 2 commits into
Draft
Conversation
Signed-off-by: linonetwo <linonetwo012@gmail.com>
Signed-off-by: linonetwo <linonetwo012@gmail.com>
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
TS_DEBUG_MTUStacked dependency
This draft is stacked on #128 (
wgengine/netstack: keep IPv6 link MTU at least 1280). The first commit shown here is #128; the new behavior is isolated in commit688ad269e. I will rebase this branch ontomainafter #128 is merged or otherwise resolved.The dependency is intentional: an inner packet budget can be below 1280 on a nested encrypted path, but the dual-stack gVisor link endpoint still cannot advertise an IPv6 MTU below RFC 8200's minimum.
Deployment context
We found this in a Coder v2.34.0 Kubernetes deployment where the cluster nodes and user workstations are already connected by an encrypted Tailnet. Kubernetes uses host-gw Pod routing over the nodes' Tailscale interfaces, and the Coder CLI/agent then creates another userspace WireGuard tailnet inside that path.
Identifying names and addresses are omitted. The relevant topology is:
The outer Tailnet peers were direct P2P. The inner Coder connection was not stable:
TS_DEBUG_MTU=1182alone expressed the correct empirical packet budget, but before wgengine/netstack: keep IPv6 link MTU at least 1280 #128 it also made the IPv6-capable gVisor link endpoint advertise the invalid value 1182.With the logical link held at 1280, discovery sized to
1182 + 30 = 1212bytes, and TCP MSS limited to1182 - 40 - 20 = 1122, the same deployment established stable direct P2P over the existing private Tailnet. Repeatedcoder pingmeasurements were approximately 4-7 ms instead of a DERP/reconnect loop. The value 1182 is deployment-specific and is not introduced as a default by this PR.This also matches the fragmentation and throughput behavior previously investigated in coder/coder#15523 for Coder running inside an outer VPN.
Behavior
TS_DEBUG_MTUunset: unchanged (1280-byte inner MTU, 1310-byte padded discovery packet, no MSS rewrite).TS_DEBUG_MTU=1182: netstack link remains 1280 via wgengine/netstack: keep IPv6 link MTU at least 1280 #128; discovery packet is 1212 bytes; TCP MSS is capped at 1122.TS_DEBUG_MTU=1280: unchanged normal behavior.Both CLI and agent should use the same explicit value. This change controls discovery probes and TCP segmentation; applications sending large UDP datagrams still need to respect their path budget independently.
Why reuse
TS_DEBUG_MTU?This keeps the change opt-in and avoids introducing a deployment-specific default or a Coder-only environment variable into the networking fork. More importantly, it makes the existing debug knob internally consistent: the configured MTU now affects the path probe and the TCP packets generated for that path, while #128 preserves the separate IPv6 link-layer invariant.
If maintainers prefer a new supported configuration name instead of extending a debug knob, the implementation can be adjusted without changing the packet-sizing mechanics demonstrated here.
Tests
go test ./disco ./wgengine/netstack -count=1Coverage includes default, 1182, 1280, 1420, UDP payload capping, TCP-only filtering, SYN detection, MSS no-op behavior, and checksum validity after rewriting.