runtime: initial support for direct udp connections - #364
Open
npry wants to merge 4 commits into
Open
Conversation
npry
force-pushed
the
npry/rt.udp-direct
branch
from
August 10, 2026 09:38
9eb976d to
8d0e998
Compare
Signed-off-by: Nathan Perry <nathan@tailscale.com> Change-Id: If44752523b00f4a1c1996bc9e71ed2096a6a6964 Change-Id: I450622ef6caf97d1bfe868b8f1969f926a6a6964
Signed-off-by: Nathan Perry <nathan@tailscale.com> Change-Id: I1a1470fd619cd5adf5d5865d2175bcb06a6a6964
Signed-off-by: Nathan Perry <nathan@tailscale.com> Change-Id: I6f32afa57e09f80583068ac2506e271a6a6a6964
Make use of the best-path discovered by the path discovery actor in underlay route updates. Signed-off-by: Nathan Perry <nathan@tailscale.com> Change-Id: I747faf484aaa775999acdf01f8a6d3946a6a6964
npry
force-pushed
the
npry/rt.udp-direct
branch
from
August 11, 2026 08:53
8d0e998 to
a7f9899
Compare
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.
2(.5) new actors: path discoverer (the .5 is its per-peer supervised children) and direct udp. Recommend reviewing commit-by-commit.
The direct udp actor is basically plumbing between the dataplane queues and two udp sockets (one IPv4 and one IPv6 (if available)) -- it mostly just shuttles packets back and forth from the socket to the queue. Since it's the only part of the system that knows the UDP local ports, it's also responsible for publishing the fully resolved local endpoints on the bus (it listens to netmon for the set of locally bound addresses, combines with the port, and merges in the IPv4 stun address verbatim). The control actor grabs those and reports them up, and the pd actor also uses them to construct its
CallMeMaybe. I actually totally skipped the underlay transport trait here. I think for modularity, it's probably preferable to use the trait, but it really also felt fine just to plumb it in directly. It just doesn't feel like there's actually that much to it, and we currently don't have a "transport registry" of any description because the transports are all connected through channels instead, and have kind of bespoke shapes anyway. To revisit -- I don't think this should block this PR.The path discoverer actor tracks the
ActivePeersset introduced in #312, and in a similar structure as multiderp, spawns a supervised child actor per active peer. Each of thesePeerPdchildren is responsible for running a periodicCallMeMaybe+Pingprobe and noting which paths come back withPongs from the peer, and with what latency. The best path is chosen and published back to the parent, which aggregates a map ofPeerId -> DynEndpoint(best paths) over time, which gets published to the bus. The route updater is updated to merge in this new best path information. Currently this is strictly preferred over derp, even if in reality derp would have a shorter latency (derp paths aren't pinged currently, just used forCallMeMaybe) -- derp is only used if there is no UDP path for the peer at all. We do it this way just because the derp latency isn't immediately accessible to the route updater -- it could listen for the derp latency map and reconcile this against the peer's derp region, but this will be much simpler to do with the kv store and feels like an edge case, so I left it out for now.