WIP: rebase fork onto upstream/main (v1.103.0) #15
+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
|
||||
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)
|
||||
|
||||
// Temporary for 1.100.x: force a full authReconfig + SetNetworkMap
|
||||
// on any peer add or remove. netmapDeltaNeedsAuthReconfig only
|
||||
// considered NodeMutationUpsert of already-known NodeIDs whose
|
||||
// Force a full authReconfig + SetSelfNode on any peer add or
|
||||
// remove. netmapDeltaNeedsAuthReconfig only considered
|
||||
// NodeMutationUpsert of already-known NodeIDs whose
|
||||
// peerRouteConfigChanged, so brand-new peers and removes left
|
||||
// e.lastCfgFull / the engine BART / wgdev's PeerLookupFunc closure
|
||||
// / e.netMap all stale, and Engine.PeerForIP, lookupPeerByIP, and
|
||||
// outbound wgdev encryption all missed those peers. authReconfig
|
||||
// fixes the wireguard side; SetNetworkMap fixes the e.netMap that
|
||||
// PeerForIP reads. The proper per-peer fix lands in the next dev
|
||||
// cycle. See tailscale/corp#43394.
|
||||
// e.lastCfgFull and wgdev's PeerLookupFunc closure stale, and
|
||||
// outbound wgdev encryption missed those peers. authReconfig
|
||||
// fixes the wireguard side; SetSelfNode refreshes the engine's
|
||||
// cached self node. PeerForIP / lookupPeerByIP staleness was
|
||||
// addressed separately in d4f2917c1b, which routes those lookups
|
||||
// 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
|
||||
if needsAuthReconfig {
|
||||
if peersUpsertedOrRemoved {
|
||||
if nm := cn.netMapWithPeers(); nm != nil {
|
||||
b.e.SetNetworkMap(nm)
|
||||
b.e.SetSelfNode(nm.SelfNode)
|
||||
}
|
||||
}
|
||||
b.authReconfigLocked()
|
||||
@@ -3953,7 +3957,11 @@ func (b *LocalBackend) DebugForceNetmapUpdate() {
|
||||
defer b.mu.Unlock()
|
||||
// TODO(nickkhyl): this all should be done in [LocalBackend.setNetMapLocked].
|
||||
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 {
|
||||
b.MagicConn().SetDERPMap(nm.DERPMap)
|
||||
}
|
||||
@@ -8375,8 +8383,8 @@ func (b *LocalBackend) resetForProfileChangeLocked() error {
|
||||
defer newNode.ready()
|
||||
b.setNetMapLocked(nil) // Reset netmap.
|
||||
b.updateFilterLocked(ipn.PrefsView{})
|
||||
// Reset the NetworkMap in the engine
|
||||
b.e.SetNetworkMap(new(netmap.NetworkMap))
|
||||
// Reset the self node in the engine.
|
||||
b.e.SetSelfNode(tailcfg.NodeView{})
|
||||
if prevCC := b.resetControlClientLocked(); prevCC != nil {
|
||||
// Shutdown outside of b.mu to avoid deadlocks.
|
||||
b.goTracker.Go(prevCC.Shutdown)
|
||||
|
||||
@@ -1972,7 +1972,7 @@ func (e *mockEngine) PeerByKey(key.NodePublic) (_ wgint.Peer, ok bool) {
|
||||
return wgint.Peer{}, false
|
||||
}
|
||||
|
||||
func (e *mockEngine) SetNetworkMap(*netmap.NetworkMap) {}
|
||||
func (e *mockEngine) SetSelfNode(tailcfg.NodeView) {}
|
||||
|
||||
func (e *mockEngine) UpdateStatus(*ipnstate.StatusBuilder) {}
|
||||
|
||||
|
||||
+2
-30
@@ -19,20 +19,12 @@ import (
|
||||
"tailscale.com/tsd"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/router"
|
||||
"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) {
|
||||
l1 := logger.WithPrefix(logf, "e1: ")
|
||||
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)
|
||||
|
||||
n := &tailcfg.Node{
|
||||
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()},
|
||||
})
|
||||
e2.SetSelfNode(tailcfg.NodeView{})
|
||||
|
||||
p := wgcfg.Peer{
|
||||
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)
|
||||
|
||||
n := &tailcfg.Node{
|
||||
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()},
|
||||
})
|
||||
e1.SetSelfNode(tailcfg.NodeView{})
|
||||
|
||||
p := wgcfg.Peer{
|
||||
PublicKey: c2.PrivateKey.Public(),
|
||||
|
||||
+14
-15
@@ -45,7 +45,6 @@ import (
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/checkchange"
|
||||
"tailscale.com/util/clientmetric"
|
||||
@@ -142,9 +141,9 @@ type userspaceEngine struct {
|
||||
lastAppliedDisableTUNUDPGRO bool
|
||||
lastAppliedDisableTUNTCPGRO bool
|
||||
|
||||
mu sync.Mutex // guards following; see lock order comment below
|
||||
netMap *netmap.NetworkMap // or nil
|
||||
closing bool // Close was called (even if we're still closing)
|
||||
mu sync.Mutex // guards following; see lock order comment below
|
||||
selfNode tailcfg.NodeView // or invalid if none
|
||||
closing bool // Close was called (even if we're still closing)
|
||||
statusCallback StatusCallback
|
||||
endpoints []tailcfg.Endpoint
|
||||
pendOpen map[flowtrackTuple]*pendingOpenFlow // see pendopen.go
|
||||
@@ -837,7 +836,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
nm := e.netMap
|
||||
self := e.selfNode
|
||||
e.mu.Unlock()
|
||||
|
||||
listenPort := e.confListenPort
|
||||
@@ -848,10 +847,10 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
peerMTUEnable := e.magicConn.ShouldPMTUD()
|
||||
|
||||
isSubnetRouter := false
|
||||
if buildfeatures.HasBird && e.birdClient != nil && nm != nil && nm.SelfNode.Valid() {
|
||||
isSubnetRouter = hasOverlap(nm.SelfNode.PrimaryRoutes(), nm.SelfNode.Hostinfo().RoutableIPs())
|
||||
if buildfeatures.HasBird && e.birdClient != nil && self.Valid() {
|
||||
isSubnetRouter = hasOverlap(self.PrimaryRoutes(), self.Hostinfo().RoutableIPs())
|
||||
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)
|
||||
}
|
||||
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.netMap = nm
|
||||
e.selfNode = self
|
||||
tunGROKnobsChanged := false
|
||||
var curUDP, curTCP bool
|
||||
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
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
if e.netMap == nil {
|
||||
return zero, errors.New("no netmap")
|
||||
if !e.selfNode.Valid() {
|
||||
return zero, errors.New("no self node")
|
||||
}
|
||||
addrs := e.netMap.GetAddresses()
|
||||
addrs := e.selfNode.Addresses()
|
||||
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() {
|
||||
if p.IsSingleIP() && p.Addr().BitLen() == dst.BitLen() {
|
||||
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)) {
|
||||
|
||||
@@ -116,7 +116,7 @@ func TestUserspaceEngineReconfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
e.SetNetworkMap(nm)
|
||||
e.SetSelfNode(nm.SelfNode)
|
||||
err = e.Reconfig(cfg, routerCfg, &dns.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -168,7 +168,7 @@ func TestUserspaceEngineTSMPLearned(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e.SetNetworkMap(nm)
|
||||
e.SetSelfNode(nm.SelfNode)
|
||||
|
||||
newDisco := key.NewDisco()
|
||||
cfg := &wgcfg.Config{
|
||||
@@ -244,7 +244,7 @@ func TestUserspaceEngineTSMPLearnedMismatch(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e.SetNetworkMap(nm)
|
||||
e.SetSelfNode(nm.SelfNode)
|
||||
|
||||
newDisco := key.NewDisco()
|
||||
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{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -175,12 +175,9 @@ type Engine interface {
|
||||
// You don't have to call this.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// SetNetworkMap informs the engine of the latest network map
|
||||
// from the server. The network map's DERPMap field should be
|
||||
// ignored as as it might be disabled; get it from SetDERPMap
|
||||
// instead.
|
||||
// The network map should only be read from.
|
||||
SetNetworkMap(*netmap.NetworkMap)
|
||||
// SetSelfNode informs the engine of the current self node.
|
||||
// The zero (invalid) NodeView indicates no self node.
|
||||
SetSelfNode(tailcfg.NodeView)
|
||||
|
||||
// UpdateStatus populates the network state using the provided
|
||||
// status builder.
|
||||
|
||||
Reference in New Issue
Block a user