ipn, ipn/ipnlocal: add Notify.SelfChange

Add a new bus signal that lets reactive consumers (containerboot, kube
agents, sniproxy, tsconsensus, etc.) react to self-node updates without
having to subscribe to the full netmap. Today those consumers either
watch Notify.NetMap (which on large tailnets is expensive to encode and
ship per watcher) or poll. SelfChange is a cheap, narrow alternative:
addresses, name, key expiry, capabilities, etc.

Consumers that need additional state can react to SelfChange and then
fetch the relevant bits on demand via existing LocalClient methods.

Producer-side, every netmap-bearing setControlClientStatus call now
also publishes SelfChange. Future changes will migrate individual
in-tree consumers off Notify.NetMap to this signal, and eventually
gate the legacy NetMap emission to platforms whose host GUIs still
require it.

Updates #12542

Change-Id: I4441650b0e085d663eb6bf26a03748b7d961ca49
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-04-30 21:12:42 +00:00
committed by Brad Fitzpatrick
parent 9f343fdc0c
commit a6c5d23742
4 changed files with 26 additions and 2 deletions
+14
View File
@@ -118,6 +118,17 @@ type Notify struct {
Prefs *PrefsView // if non-nil && Valid, the new or current preferences
NetMap *netmap.NetworkMap // if non-nil, the new or current netmap
// SelfChange, if non-nil, indicates that this node's own [tailcfg.Node]
// has changed: addresses, name, key expiry, capabilities, etc. It carries
// the new self node so reactive consumers (containerboot, kube agents,
// sniproxy, etc.) can read the current self state without watching the
// full netmap.
//
// Consumers that need additional state (peers, DNS config, packet
// filter) should react to SelfChange by fetching the relevant bits on
// demand via [LocalClient].
SelfChange *tailcfg.Node `json:",omitzero"`
// PeerChanges, if non-nil, is a list of [tailcfg.PeerChange] that have occurred since the last
// full netmap update. This is sent in lieu of a full NetMap when [NotifyPeerChanges] is set in
// the session's mask and a netmap update is derived from an incremental MapResponse.
@@ -196,6 +207,9 @@ func (n Notify) String() string {
if n.NetMap != nil {
sb.WriteString("NetMap{...} ")
}
if n.SelfChange != nil {
fmt.Fprintf(&sb, "SelfChange(%v) ", n.SelfChange.StableID)
}
if n.PeerChanges != nil {
fmt.Fprintf(&sb, "PeerChanges(%d) ", len(n.PeerChanges))
}