federation: reuse established tunnel instead of re-dialing peer:9191#59
Open
mastaab wants to merge 1 commit into
Open
federation: reuse established tunnel instead of re-dialing peer:9191#59mastaab wants to merge 1 commit into
mastaab wants to merge 1 commit into
Conversation
mastaab
force-pushed
the
WPB-26951_federation-tunnel-reuse
branch
from
July 20, 2026 17:19
a43c32f to
6aeeed1
Compare
The federation send path only looked up dest:9191 in children_ss and dialed a new outbound DTLS connection on a miss. When our egress NAT rewrites the source port, the peer keys our tunnel under the rewritten port, so its own send path misses and it dials back into us. That dial is redundant (a healthy tunnel between the two coturns already exists) and it is exactly the handshake that fails: our conntrack entry for the dial occupies the local:9191->peer:9191 tuple, so the kernel's clash resolution rewrites the inbound ClientHello fragments to a fresh source port each, and the handshake can never complete (one-way media, paired 10s handshake timeouts on the receiving side). Maintain a peers-by-ip index (peer IP, port zeroed -> established federation socket), registered when any federation handshake completes and unregistered in delete_socket_from_map so entries can never dangle. On a send-path miss of dest:9191, reuse any established tunnel to that peer IP instead of dialing; DTLS application data flows both ways regardless of client/server role (the server-side PONG already proves this path). Only dial when no established tunnel exists at all. One side deploying this heals a pairing: the redundant dial never happens, and the clash precondition is never created on the peer's node. Same thread model as children_ss (federation listener thread).
mastaab
force-pushed
the
WPB-26951_federation-tunnel-reuse
branch
from
July 20, 2026 17:23
6aeeed1 to
4304282
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.
Problem
Federation calls intermittently end up with one-way media and
DTLS handshake timedoutlog pairs. Root cause was proven end-to-end on staging with pcaps, conntrack event logs, and coturn logs:The federation send path only looks up
dest:9191inchildren_ssand dials a new outbound DTLS connection on a miss. When our egress NAT (any k8s node's SNAT) rewrites the dial's source port, the peer keys our tunnel under the rewritten port, so the peer's own send path misses ondest:9191and it dials back into us. That second dial is redundant — a healthy tunnel between the two coturns already exists — and it is exactly the handshake that fails: our dial's conntrack entry occupies thelocal:9191 → peer:9191tuple, so the kernel's clash resolution rewrites the inbound ClientHello fragments to a fresh source port each, coturn sees two phantom clients holding half a ClientHello each, and both half-open handshakes time out at +10s. The peer's media direction never establishes.Fix
Reuse any established federation tunnel to the destination peer instead of dialing:
ur_addr_mapkeyed by peer IP with port zeroed → established federation socket). Registered at the single handshake-completion point indtls_listener.c(covers dialed and accepted tunnels); unregistered indelete_socket_from_map, which every socket close funnels through (close_ioa_socket), so entries can never dangle. A flag on the socket keeps the close-path hook a no-op for non-federation sockets.federation_send_data_imp: on adest:9191miss, look up the peer IP in the index and send over that tunnel (typically the accepted, peer-initiated one). Only dial when no established tunnel exists at all.send_data_from_ioa_socket_nbh/ssl_sendpath, anddest_addris ignored for SSL sockets.Thread model unchanged: the index is only touched on the federation listener thread, exactly like
children_ss(sends are marshaled there via the bufferevent pair; federation socket timers and reads run on the listener engine).One side deploying this heals a pairing: the redundant dial never happens, and its conntrack entry — the clash precondition on the peer's node — is never created. The unpatched peer just receives data on the tunnel it already dialed.
Known limitation
If neither side has any established tunnel and both dial in the same instant, the simultaneous-dial race remains (millisecond window; not the failure in any captured incident). A deterministic-initiator rule would close it and is left as a follow-up.
Verification
Federation: reusing established tunnelin the verbose log.