Skip to content

Commit 5b4de66

Browse files
authored
chore: add setCallback to nodeUpdater (#11635)
we need to be able to (re-)set the node callback when we lose and regain connection to a coordinator over the network.
1 parent e725f9d commit 5b4de66

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

tailnet/node.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,28 @@ func (u *nodeUpdater) updateLoop() {
5555
u.logger.Debug(context.Background(), "closing nodeUpdater updateLoop")
5656
return
5757
}
58-
node := u.nodeLocked()
5958
u.dirty = false
6059
u.phase = configuring
6160
u.Broadcast()
6261

62+
callback := u.callback
63+
if callback == nil {
64+
u.logger.Debug(context.Background(), "skipped sending node; no node callback")
65+
continue
66+
}
67+
6368
// We cannot reach nodes without DERP for discovery. Therefore, there is no point in sending
6469
// the node without this, and we can save ourselves from churn in the tailscale/wireguard
6570
// layer.
71+
node := u.nodeLocked()
6672
if node.PreferredDERP == 0 {
6773
u.logger.Debug(context.Background(), "skipped sending node; no PreferredDERP", slog.F("node", node))
6874
continue
6975
}
7076

7177
u.L.Unlock()
7278
u.logger.Debug(context.Background(), "calling nodeUpdater callback", slog.F("node", node))
73-
u.callback(node)
79+
callback(node)
7480
u.L.Lock()
7581
}
7682
}
@@ -155,7 +161,7 @@ func (u *nodeUpdater) setDERPForcedWebsocket(region int, reason string) {
155161
}
156162

157163
// setStatus handles the status callback from the wireguard engine to learn about new endpoints
158-
// (e.g. discovered by STUN)
164+
// (e.g. discovered by STUN). u.L MUST NOT be held
159165
func (u *nodeUpdater) setStatus(s *wgengine.Status, err error) {
160166
u.logger.Debug(context.Background(), "wireguard status", slog.F("status", s), slog.Error(err))
161167
if err != nil {
@@ -181,6 +187,7 @@ func (u *nodeUpdater) setStatus(s *wgengine.Status, err error) {
181187
u.Broadcast()
182188
}
183189

190+
// setAddresses sets the local addresses for the node. u.L MUST NOT be held.
184191
func (u *nodeUpdater) setAddresses(ips []netip.Prefix) {
185192
u.L.Lock()
186193
defer u.L.Unlock()
@@ -192,3 +199,13 @@ func (u *nodeUpdater) setAddresses(ips []netip.Prefix) {
192199
u.dirty = true
193200
u.Broadcast()
194201
}
202+
203+
// setCallback sets the callback for node changes. It also triggers a call
204+
// for the current node immediately. u.L MUST NOT be held.
205+
func (u *nodeUpdater) setCallback(callback func(node *Node)) {
206+
u.L.Lock()
207+
defer u.L.Unlock()
208+
u.callback = callback
209+
u.dirty = true
210+
u.Broadcast()
211+
}

tailnet/node_internal_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,44 @@ func TestNodeUpdater_setAddresses_same(t *testing.T) {
441441
}()
442442
_ = testutil.RequireRecvCtx(ctx, t, done)
443443
}
444+
445+
func TestNodeUpdater_setCallback(t *testing.T) {
446+
t.Parallel()
447+
ctx := testutil.Context(t, testutil.WaitShort)
448+
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
449+
id := tailcfg.NodeID(1)
450+
nodeKey := key.NewNode().Public()
451+
discoKey := key.NewDisco().Public()
452+
uut := newNodeUpdater(
453+
logger,
454+
nil,
455+
id, nodeKey, discoKey,
456+
)
457+
defer uut.close()
458+
459+
// Given: preferred DERP is 1
460+
addrs := []netip.Prefix{netip.MustParsePrefix("192.168.0.200/32")}
461+
uut.L.Lock()
462+
uut.preferredDERP = 1
463+
uut.addresses = slices.Clone(addrs)
464+
uut.L.Unlock()
465+
466+
// When: we set callback
467+
nodeCh := make(chan *Node)
468+
uut.setCallback(func(n *Node) {
469+
nodeCh <- n
470+
})
471+
472+
// Then: we get a node update
473+
node := testutil.RequireRecvCtx(ctx, t, nodeCh)
474+
require.Equal(t, nodeKey, node.Key)
475+
require.Equal(t, discoKey, node.DiscoKey)
476+
require.Equal(t, 1, node.PreferredDERP)
477+
478+
done := make(chan struct{})
479+
go func() {
480+
defer close(done)
481+
uut.close()
482+
}()
483+
_ = testutil.RequireRecvCtx(ctx, t, done)
484+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy