mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
control/controlclient, types/netmap: start plumbing delta netmap updates
Currently only the top four most popular changes: endpoints, DERP home, online, and LastSeen. Updates #1909 Change-Id: I03152da176b2b95232b56acabfb55dcdfaa16b79 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
c0ade132e6
commit
3af051ea27
@@ -203,9 +203,8 @@ type LocalBackend struct {
|
||||
capFileSharing bool // whether netMap contains the file sharing capability
|
||||
capTailnetLock bool // whether netMap contains the tailnet lock capability
|
||||
// hostinfo is mutated in-place while mu is held.
|
||||
hostinfo *tailcfg.Hostinfo
|
||||
// netMap is not mutated in-place once set.
|
||||
netMap *netmap.NetworkMap
|
||||
hostinfo *tailcfg.Hostinfo
|
||||
netMap *netmap.NetworkMap // not mutated in place once set (except for Peers slice)
|
||||
nmExpiryTimer tstime.TimerController // for updating netMap on node expiry; can be nil
|
||||
nodeByAddr map[netip.Addr]tailcfg.NodeView
|
||||
activeLogin string // last logged LoginName from netMap
|
||||
@@ -1121,6 +1120,56 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
|
||||
b.authReconfig()
|
||||
}
|
||||
|
||||
var _ controlclient.NetmapDeltaUpdater = (*LocalBackend)(nil)
|
||||
|
||||
// UpdateNetmapDelta implements controlclient.NetmapDeltaUpdater.
|
||||
func (b *LocalBackend) UpdateNetmapDelta(muts []netmap.NodeMutation) (handled bool) {
|
||||
mc, err := b.magicConn()
|
||||
if err != nil {
|
||||
panic(err) // shouldn't happen
|
||||
}
|
||||
if !mc.UpdateNetmapDelta(muts) {
|
||||
return false
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.updateNetmapDeltaLocked(muts)
|
||||
}
|
||||
|
||||
func (b *LocalBackend) updateNetmapDeltaLocked(muts []netmap.NodeMutation) (handled bool) {
|
||||
if b.netMap == nil {
|
||||
return false
|
||||
}
|
||||
peers := b.netMap.Peers
|
||||
|
||||
for _, m := range muts {
|
||||
// LocalBackend only cares about some types of mutations.
|
||||
// (magicsock cares about different ones.)
|
||||
switch m.(type) {
|
||||
case netmap.NodeMutationOnline, netmap.NodeMutationLastSeen:
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
nodeID := m.NodeIDBeingMutated()
|
||||
idx := b.netMap.PeerIndexByNodeID(nodeID)
|
||||
if idx == -1 {
|
||||
continue
|
||||
}
|
||||
mut := peers[idx].AsStruct()
|
||||
|
||||
switch m := m.(type) {
|
||||
case netmap.NodeMutationOnline:
|
||||
mut.Online = ptr.To(m.Online)
|
||||
case netmap.NodeMutationLastSeen:
|
||||
mut.LastSeen = ptr.To(m.LastSeen)
|
||||
}
|
||||
peers[idx] = mut.View()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// setExitNodeID updates prefs to reference an exit node by ID, rather
|
||||
// than by IP. It returns whether prefs was mutated.
|
||||
func setExitNodeID(prefs *ipn.Prefs, nm *netmap.NetworkMap) (prefsChanged bool) {
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/logid"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/set"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/filter"
|
||||
@@ -879,3 +880,75 @@ func TestWatchNotificationsCallbacks(t *testing.T) {
|
||||
t.Fatalf("unexpected number of watchers in new LocalBackend, want: 0 got: %v", len(b.notifyWatchers))
|
||||
}
|
||||
}
|
||||
|
||||
// tests LocalBackend.updateNetmapDeltaLocked
|
||||
func TestUpdateNetmapDelta(t *testing.T) {
|
||||
var b LocalBackend
|
||||
if b.updateNetmapDeltaLocked(nil) {
|
||||
t.Errorf("updateNetmapDeltaLocked() = true, want false with nil netmap")
|
||||
}
|
||||
|
||||
b.netMap = &netmap.NetworkMap{}
|
||||
for i := 0; i < 5; i++ {
|
||||
b.netMap.Peers = append(b.netMap.Peers, (&tailcfg.Node{ID: (tailcfg.NodeID(i) + 1)}).View())
|
||||
}
|
||||
|
||||
someTime := time.Unix(123, 0)
|
||||
muts, ok := netmap.MutationsFromMapResponse(&tailcfg.MapResponse{
|
||||
PeersChangedPatch: []*tailcfg.PeerChange{
|
||||
{
|
||||
NodeID: 1,
|
||||
DERPRegion: 1,
|
||||
},
|
||||
{
|
||||
NodeID: 2,
|
||||
Online: ptr.To(true),
|
||||
},
|
||||
{
|
||||
NodeID: 3,
|
||||
Online: ptr.To(false),
|
||||
},
|
||||
{
|
||||
NodeID: 4,
|
||||
LastSeen: ptr.To(someTime),
|
||||
},
|
||||
},
|
||||
}, someTime)
|
||||
if !ok {
|
||||
t.Fatal("netmap.MutationsFromMapResponse failed")
|
||||
}
|
||||
|
||||
if !b.updateNetmapDeltaLocked(muts) {
|
||||
t.Fatalf("updateNetmapDeltaLocked() = false, want true with new netmap")
|
||||
}
|
||||
|
||||
wants := []*tailcfg.Node{
|
||||
{
|
||||
ID: 1,
|
||||
DERP: "", // unmodified by the delta
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Online: ptr.To(true),
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Online: ptr.To(false),
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
LastSeen: ptr.To(someTime),
|
||||
},
|
||||
}
|
||||
for _, want := range wants {
|
||||
idx := b.netMap.PeerIndexByNodeID(want.ID)
|
||||
if idx == -1 {
|
||||
t.Errorf("ID %v not found in netmap", want.ID)
|
||||
continue
|
||||
}
|
||||
got := b.netMap.Peers[idx].AsStruct()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("netmap.Peer %v wrong.\n got: %v\nwant: %v", want.ID, logger.AsJSON(got), logger.AsJSON(want))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user