wgengine: replace Engine.SetNetworkMap with SetSelfNode
The engine only used the netmap to look up self addresses and the self node's primary routes, so pass it the self node directly rather than the whole netmap. Updates #12542 Change-Id: I13c0028eed65d2177baf4cf6c449f5e441845a18 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
1b2062f3c1
commit
87cb2a8d1e
+22
-14
@@ -2103,7 +2103,7 @@ func (b *LocalBackend) setControlClientStatusLocked(c controlclient.Client, st c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.e.SetNetworkMap(st.NetMap)
|
b.e.SetSelfNode(st.NetMap.SelfNode)
|
||||||
|
|
||||||
var cachedHome int
|
var cachedHome int
|
||||||
if c == nil && st.NetMap.Cached && st.NetMap.SelfNode.Valid() {
|
if c == nil && st.NetMap.Cached && st.NetMap.SelfNode.Valid() {
|
||||||
@@ -2514,21 +2514,25 @@ func (b *LocalBackend) UpdateNetmapDelta(muts []netmap.NodeMutation) (handled bo
|
|||||||
}
|
}
|
||||||
ms.UpdateNetmapDelta(muts)
|
ms.UpdateNetmapDelta(muts)
|
||||||
|
|
||||||
// Temporary for 1.100.x: force a full authReconfig + SetNetworkMap
|
// Force a full authReconfig + SetSelfNode on any peer add or
|
||||||
// on any peer add or remove. netmapDeltaNeedsAuthReconfig only
|
// remove. netmapDeltaNeedsAuthReconfig only considered
|
||||||
// considered NodeMutationUpsert of already-known NodeIDs whose
|
// NodeMutationUpsert of already-known NodeIDs whose
|
||||||
// peerRouteConfigChanged, so brand-new peers and removes left
|
// peerRouteConfigChanged, so brand-new peers and removes left
|
||||||
// e.lastCfgFull / the engine BART / wgdev's PeerLookupFunc closure
|
// e.lastCfgFull and wgdev's PeerLookupFunc closure stale, and
|
||||||
// / e.netMap all stale, and Engine.PeerForIP, lookupPeerByIP, and
|
// outbound wgdev encryption missed those peers. authReconfig
|
||||||
// outbound wgdev encryption all missed those peers. authReconfig
|
// fixes the wireguard side; SetSelfNode refreshes the engine's
|
||||||
// fixes the wireguard side; SetNetworkMap fixes the e.netMap that
|
// cached self node. PeerForIP / lookupPeerByIP staleness was
|
||||||
// PeerForIP reads. The proper per-peer fix lands in the next dev
|
// addressed separately in d4f2917c1b, which routes those lookups
|
||||||
// cycle. See tailscale/corp#43394.
|
// through nodeBackend's live data, and as part of the broader
|
||||||
|
// netmap.NetworkMap removal effort the engine no longer caches
|
||||||
|
// the netmap at all (see tailscale/corp#43394). As of 2026-06-24
|
||||||
|
// the only remaining staleness this guards against is
|
||||||
|
// e.lastCfgFull and the wgdev peer set.
|
||||||
needsAuthReconfig = needsAuthReconfig || peersUpsertedOrRemoved
|
needsAuthReconfig = needsAuthReconfig || peersUpsertedOrRemoved
|
||||||
if needsAuthReconfig {
|
if needsAuthReconfig {
|
||||||
if peersUpsertedOrRemoved {
|
if peersUpsertedOrRemoved {
|
||||||
if nm := cn.netMapWithPeers(); nm != nil {
|
if nm := cn.netMapWithPeers(); nm != nil {
|
||||||
b.e.SetNetworkMap(nm)
|
b.e.SetSelfNode(nm.SelfNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.authReconfigLocked()
|
b.authReconfigLocked()
|
||||||
@@ -3953,7 +3957,11 @@ func (b *LocalBackend) DebugForceNetmapUpdate() {
|
|||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
// TODO(nickkhyl): this all should be done in [LocalBackend.setNetMapLocked].
|
// TODO(nickkhyl): this all should be done in [LocalBackend.setNetMapLocked].
|
||||||
nm := b.currentNode().NetMap()
|
nm := b.currentNode().NetMap()
|
||||||
b.e.SetNetworkMap(nm)
|
var self tailcfg.NodeView
|
||||||
|
if nm != nil {
|
||||||
|
self = nm.SelfNode
|
||||||
|
}
|
||||||
|
b.e.SetSelfNode(self)
|
||||||
if nm != nil {
|
if nm != nil {
|
||||||
b.MagicConn().SetDERPMap(nm.DERPMap)
|
b.MagicConn().SetDERPMap(nm.DERPMap)
|
||||||
}
|
}
|
||||||
@@ -8375,8 +8383,8 @@ func (b *LocalBackend) resetForProfileChangeLocked() error {
|
|||||||
defer newNode.ready()
|
defer newNode.ready()
|
||||||
b.setNetMapLocked(nil) // Reset netmap.
|
b.setNetMapLocked(nil) // Reset netmap.
|
||||||
b.updateFilterLocked(ipn.PrefsView{})
|
b.updateFilterLocked(ipn.PrefsView{})
|
||||||
// Reset the NetworkMap in the engine
|
// Reset the self node in the engine.
|
||||||
b.e.SetNetworkMap(new(netmap.NetworkMap))
|
b.e.SetSelfNode(tailcfg.NodeView{})
|
||||||
if prevCC := b.resetControlClientLocked(); prevCC != nil {
|
if prevCC := b.resetControlClientLocked(); prevCC != nil {
|
||||||
// Shutdown outside of b.mu to avoid deadlocks.
|
// Shutdown outside of b.mu to avoid deadlocks.
|
||||||
b.goTracker.Go(prevCC.Shutdown)
|
b.goTracker.Go(prevCC.Shutdown)
|
||||||
|
|||||||
@@ -1972,7 +1972,7 @@ func (e *mockEngine) PeerByKey(key.NodePublic) (_ wgint.Peer, ok bool) {
|
|||||||
return wgint.Peer{}, false
|
return wgint.Peer{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *mockEngine) SetNetworkMap(*netmap.NetworkMap) {}
|
func (e *mockEngine) SetSelfNode(tailcfg.NodeView) {}
|
||||||
|
|
||||||
func (e *mockEngine) UpdateStatus(*ipnstate.StatusBuilder) {}
|
func (e *mockEngine) UpdateStatus(*ipnstate.StatusBuilder) {}
|
||||||
|
|
||||||
|
|||||||
+2
-30
@@ -19,20 +19,12 @@ import (
|
|||||||
"tailscale.com/tsd"
|
"tailscale.com/tsd"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/netmap"
|
|
||||||
"tailscale.com/wgengine"
|
"tailscale.com/wgengine"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func epFromTyped(eps []tailcfg.Endpoint) (ret []netip.AddrPort) {
|
|
||||||
for _, ep := range eps {
|
|
||||||
ret = append(ret, ep.Addr)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.Prefix) {
|
func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.Prefix) {
|
||||||
l1 := logger.WithPrefix(logf, "e1: ")
|
l1 := logger.WithPrefix(logf, "e1: ")
|
||||||
k1 := key.NewNode()
|
k1 := key.NewNode()
|
||||||
@@ -103,17 +95,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
}
|
}
|
||||||
logf("e1 status: %v", *st)
|
logf("e1 status: %v", *st)
|
||||||
|
|
||||||
n := &tailcfg.Node{
|
e2.SetSelfNode(tailcfg.NodeView{})
|
||||||
ID: tailcfg.NodeID(0),
|
|
||||||
Name: "n1",
|
|
||||||
Addresses: []netip.Prefix{a1},
|
|
||||||
AllowedIPs: []netip.Prefix{a1},
|
|
||||||
Endpoints: epFromTyped(st.LocalAddrs),
|
|
||||||
}
|
|
||||||
e2.SetNetworkMap(&netmap.NetworkMap{
|
|
||||||
NodeKey: k2.Public(),
|
|
||||||
Peers: []tailcfg.NodeView{n.View()},
|
|
||||||
})
|
|
||||||
|
|
||||||
p := wgcfg.Peer{
|
p := wgcfg.Peer{
|
||||||
PublicKey: c1.PrivateKey.Public(),
|
PublicKey: c1.PrivateKey.Public(),
|
||||||
@@ -134,17 +116,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
}
|
}
|
||||||
logf("e2 status: %v", *st)
|
logf("e2 status: %v", *st)
|
||||||
|
|
||||||
n := &tailcfg.Node{
|
e1.SetSelfNode(tailcfg.NodeView{})
|
||||||
ID: tailcfg.NodeID(0),
|
|
||||||
Name: "n2",
|
|
||||||
Addresses: []netip.Prefix{a2},
|
|
||||||
AllowedIPs: []netip.Prefix{a2},
|
|
||||||
Endpoints: epFromTyped(st.LocalAddrs),
|
|
||||||
}
|
|
||||||
e1.SetNetworkMap(&netmap.NetworkMap{
|
|
||||||
NodeKey: k1.Public(),
|
|
||||||
Peers: []tailcfg.NodeView{n.View()},
|
|
||||||
})
|
|
||||||
|
|
||||||
p := wgcfg.Peer{
|
p := wgcfg.Peer{
|
||||||
PublicKey: c2.PrivateKey.Public(),
|
PublicKey: c2.PrivateKey.Public(),
|
||||||
|
|||||||
+14
-15
@@ -45,7 +45,6 @@ import (
|
|||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/netmap"
|
|
||||||
"tailscale.com/types/views"
|
"tailscale.com/types/views"
|
||||||
"tailscale.com/util/checkchange"
|
"tailscale.com/util/checkchange"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
@@ -142,9 +141,9 @@ type userspaceEngine struct {
|
|||||||
lastAppliedDisableTUNUDPGRO bool
|
lastAppliedDisableTUNUDPGRO bool
|
||||||
lastAppliedDisableTUNTCPGRO bool
|
lastAppliedDisableTUNTCPGRO bool
|
||||||
|
|
||||||
mu sync.Mutex // guards following; see lock order comment below
|
mu sync.Mutex // guards following; see lock order comment below
|
||||||
netMap *netmap.NetworkMap // or nil
|
selfNode tailcfg.NodeView // or invalid if none
|
||||||
closing bool // Close was called (even if we're still closing)
|
closing bool // Close was called (even if we're still closing)
|
||||||
statusCallback StatusCallback
|
statusCallback StatusCallback
|
||||||
endpoints []tailcfg.Endpoint
|
endpoints []tailcfg.Endpoint
|
||||||
pendOpen map[flowtrackTuple]*pendingOpenFlow // see pendopen.go
|
pendOpen map[flowtrackTuple]*pendingOpenFlow // see pendopen.go
|
||||||
@@ -837,7 +836,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
nm := e.netMap
|
self := e.selfNode
|
||||||
e.mu.Unlock()
|
e.mu.Unlock()
|
||||||
|
|
||||||
listenPort := e.confListenPort
|
listenPort := e.confListenPort
|
||||||
@@ -848,10 +847,10 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||||||
peerMTUEnable := e.magicConn.ShouldPMTUD()
|
peerMTUEnable := e.magicConn.ShouldPMTUD()
|
||||||
|
|
||||||
isSubnetRouter := false
|
isSubnetRouter := false
|
||||||
if buildfeatures.HasBird && e.birdClient != nil && nm != nil && nm.SelfNode.Valid() {
|
if buildfeatures.HasBird && e.birdClient != nil && self.Valid() {
|
||||||
isSubnetRouter = hasOverlap(nm.SelfNode.PrimaryRoutes(), nm.SelfNode.Hostinfo().RoutableIPs())
|
isSubnetRouter = hasOverlap(self.PrimaryRoutes(), self.Hostinfo().RoutableIPs())
|
||||||
e.logf("[v1] Reconfig: hasOverlap(%v, %v) = %v; isSubnetRouter=%v lastIsSubnetRouter=%v",
|
e.logf("[v1] Reconfig: hasOverlap(%v, %v) = %v; isSubnetRouter=%v lastIsSubnetRouter=%v",
|
||||||
nm.SelfNode.PrimaryRoutes(), nm.SelfNode.Hostinfo().RoutableIPs(),
|
self.PrimaryRoutes(), self.Hostinfo().RoutableIPs(),
|
||||||
isSubnetRouter, isSubnetRouter, e.lastIsSubnetRouter)
|
isSubnetRouter, isSubnetRouter, e.lastIsSubnetRouter)
|
||||||
}
|
}
|
||||||
isSubnetRouterChanged := buildfeatures.HasAdvertiseRoutes && isSubnetRouter != e.lastIsSubnetRouter
|
isSubnetRouterChanged := buildfeatures.HasAdvertiseRoutes && isSubnetRouter != e.lastIsSubnetRouter
|
||||||
@@ -1331,9 +1330,9 @@ func (e *userspaceEngine) linkChange(delta *netmon.ChangeDelta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) SetNetworkMap(nm *netmap.NetworkMap) {
|
func (e *userspaceEngine) SetSelfNode(self tailcfg.NodeView) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
e.netMap = nm
|
e.selfNode = self
|
||||||
tunGROKnobsChanged := false
|
tunGROKnobsChanged := false
|
||||||
var curUDP, curTCP bool
|
var curUDP, curTCP bool
|
||||||
if buildfeatures.HasGRO && runtime.GOOS == "linux" && e.controlKnobs != nil {
|
if buildfeatures.HasGRO && runtime.GOOS == "linux" && e.controlKnobs != nil {
|
||||||
@@ -1409,19 +1408,19 @@ func (e *userspaceEngine) mySelfIPMatchingFamily(dst netip.Addr) (src netip.Addr
|
|||||||
var zero netip.Addr
|
var zero netip.Addr
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
if e.netMap == nil {
|
if !e.selfNode.Valid() {
|
||||||
return zero, errors.New("no netmap")
|
return zero, errors.New("no self node")
|
||||||
}
|
}
|
||||||
addrs := e.netMap.GetAddresses()
|
addrs := e.selfNode.Addresses()
|
||||||
if addrs.Len() == 0 {
|
if addrs.Len() == 0 {
|
||||||
return zero, errors.New("no self address in netmap")
|
return zero, errors.New("no self address")
|
||||||
}
|
}
|
||||||
for _, p := range addrs.All() {
|
for _, p := range addrs.All() {
|
||||||
if p.IsSingleIP() && p.Addr().BitLen() == dst.BitLen() {
|
if p.IsSingleIP() && p.Addr().BitLen() == dst.BitLen() {
|
||||||
return p.Addr(), nil
|
return p.Addr(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return zero, errors.New("no self address in netmap matching address family")
|
return zero, errors.New("no self address matching address family")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func TestUserspaceEngineReconfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
e.SetNetworkMap(nm)
|
e.SetSelfNode(nm.SelfNode)
|
||||||
err = e.Reconfig(cfg, routerCfg, &dns.Config{})
|
err = e.Reconfig(cfg, routerCfg, &dns.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -168,7 +168,7 @@ func TestUserspaceEngineTSMPLearned(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
e.SetNetworkMap(nm)
|
e.SetSelfNode(nm.SelfNode)
|
||||||
|
|
||||||
newDisco := key.NewDisco()
|
newDisco := key.NewDisco()
|
||||||
cfg := &wgcfg.Config{
|
cfg := &wgcfg.Config{
|
||||||
@@ -244,7 +244,7 @@ func TestUserspaceEngineTSMPLearnedMismatch(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
e.SetNetworkMap(nm)
|
e.SetSelfNode(nm.SelfNode)
|
||||||
|
|
||||||
newDisco := key.NewDisco()
|
newDisco := key.NewDisco()
|
||||||
cfg := &wgcfg.Config{
|
cfg := &wgcfg.Config{
|
||||||
@@ -485,7 +485,7 @@ func TestTSMPKeyAdvertisement(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ue.SetNetworkMap(nm)
|
ue.SetSelfNode(nm.SelfNode)
|
||||||
err = ue.Reconfig(cfg, routerCfg, &dns.Config{})
|
err = ue.Reconfig(cfg, routerCfg, &dns.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -175,12 +175,9 @@ type Engine interface {
|
|||||||
// You don't have to call this.
|
// You don't have to call this.
|
||||||
Done() <-chan struct{}
|
Done() <-chan struct{}
|
||||||
|
|
||||||
// SetNetworkMap informs the engine of the latest network map
|
// SetSelfNode informs the engine of the current self node.
|
||||||
// from the server. The network map's DERPMap field should be
|
// The zero (invalid) NodeView indicates no self node.
|
||||||
// ignored as as it might be disabled; get it from SetDERPMap
|
SetSelfNode(tailcfg.NodeView)
|
||||||
// instead.
|
|
||||||
// The network map should only be read from.
|
|
||||||
SetNetworkMap(*netmap.NetworkMap)
|
|
||||||
|
|
||||||
// UpdateStatus populates the network state using the provided
|
// UpdateStatus populates the network state using the provided
|
||||||
// status builder.
|
// status builder.
|
||||||
|
|||||||
Reference in New Issue
Block a user