WIP: rebase fork onto upstream/main (v1.103.0) #15

Closed
codinget wants to merge 670 commits from webnet into save/webnet-2026-07-29
6 changed files with 46 additions and 70 deletions
Showing only changes of commit 87cb2a8d1e - Show all commits
+22 -14
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)) {
+4 -4
View File
@@ -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)
+3 -6
View File
@@ -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.