From 3b8bad4252652995d5b95467d39befc79a1a26db Mon Sep 17 00:00:00 2001 From: Rogan Lynch Date: Fri, 5 Dec 2025 08:40:51 -0800 Subject: [PATCH] feat(mapper): add SendDirectUpdate method for direct MapResponse delivery Add SendDirectUpdate method to LockFreeBatcher to enable sending MapResponse messages directly to specific nodes without going through the change broadcast system. This is useful for targeted updates like PingRequests that need to be delivered immediately to a specific node. The method: - Validates the MapResponse and node existence - Checks for active connections - Sends directly via the node's send method - Logs delivery status for debugging This lays the groundwork for implementing ping functionality that requires direct node communication. Related to #2902 --- hscontrol/mapper/batcher_lockfree.go | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hscontrol/mapper/batcher_lockfree.go b/hscontrol/mapper/batcher_lockfree.go index d40b36b0..c793af39 100644 --- a/hscontrol/mapper/batcher_lockfree.go +++ b/hscontrol/mapper/batcher_lockfree.go @@ -449,6 +449,38 @@ func (b *LockFreeBatcher) MapResponseFromChange(id types.NodeID, c change.Change } } +// SendDirectUpdate sends a MapResponse directly to a specific node without going through +// the change broadcast system. This is useful for targeted updates like PingRequests. +func (b *LockFreeBatcher) SendDirectUpdate(id types.NodeID, resp *tailcfg.MapResponse) error { + if resp == nil { + return fmt.Errorf("cannot send nil MapResponse to node %d", id) + } + + // Look up the node connection + nodeConn, exists := b.nodes.Load(id) + if !exists { + return fmt.Errorf("node %d not found in batcher", id) + } + + // Check if node has active connections + if !nodeConn.hasActiveConnections() { + return fmt.Errorf("node %d has no active connections", id) + } + + // Send the MapResponse directly + err := nodeConn.send(resp) + if err != nil { + return fmt.Errorf("failed to send direct update to node %d: %w", id, err) + } + + log.Debug(). + Uint64("node.id", id.Uint64()). + Bool("has_ping_request", resp.PingRequest != nil). + Msg("Successfully sent direct update to node") + + return nil +} + // connectionEntry represents a single connection to a node. type connectionEntry struct { id string // unique connection ID