wgengine,ipn/ipnlocal: sync wireguard-go peers incrementally on netmap deltas
Previously, any peer added or removed by an incremental netmap delta was only visible to wireguard-go after a full authReconfig: wgcfg's ReconfigDevice re-installed a PeerLookupFunc closing over a freshly built map of every peer's allowed IPs, doing O(n) work per change. Instead, install the wireguard-go device hooks once, backed by live state. Engine.SetPeerConfigFunc installs a single long-lived PeerLookupFunc that queries LocalBackend's per-node RouteManager on demand, and Engine.SyncDevicePeer does O(1) per-peer device sync (remove, or update allowed IPs) as each delta mutation is applied. Full reconfigs keep an O(n peers) device sync for now, but with no lookup closure to reinstall and no removed-peer resurrection race; a later change removes full-config peer syncing entirely. The RouteManager's PeerAllowedIPs accessor backs the new hooks: its sorted output makes unchanged state a no-op update, and its peer filtering mirrors nmcfg.WGCfg, so expired peers and peers predating both DERP and disco contribute no prefixes and thus cannot be lazily created in the device, which matters because wireguard-go validates inbound source IPs against per-peer allowed IPs. The engine's SetPeerByIPPacketFunc callback is now authoritative when installed, since LocalBackend's implementation covers subnet routes and exit-node routes via the RouteManager's outbound table; the engine's own reconfig-time BART table only serves engines running without a LocalBackend. The forced authReconfig on peer add/remove stays for now: the WireGuard device no longer needs it, but OS routes, the quad-100 resolver's MagicDNS hosts map, and tstun's masquerade/jailed peer config are still derived from the full peer set. Making those delta-aware is the next step before gating it. Updates #12542 Change-Id: I3ba8c7c324bca0ad0269279d03f53b1f17fb63a2 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
ff1c7ef23c
commit
f831469c27
@@ -317,15 +317,21 @@ func TestNodeBackendRouteManager(t *testing.T) {
|
||||
wantPeerFor("8.8.8.8", tailcfg.NodeView{}) // exit node not selected
|
||||
|
||||
// Selecting peer 2 as the exit node resolves its stable ID and
|
||||
// installs its /0 routes.
|
||||
nb.updateRouteManagerPrefs(routePrefs{ExitNodeID: "stable2", ExitNodeSelected: true})
|
||||
// installs its /0 routes. The commit reports peer 2's allowed
|
||||
// prefixes as changed.
|
||||
if changed := nb.updateRouteManagerPrefs(routePrefs{ExitNodeID: "stable2", ExitNodeSelected: true}); len(changed) != 1 || changed[p2.Key()] == nil {
|
||||
t.Errorf("updateRouteManagerPrefs(exit=stable2) changed = %v; want just %v", changed, p2.Key())
|
||||
}
|
||||
wantPeerFor("8.8.8.8", p2)
|
||||
|
||||
// A selected exit node that resolves to no current peer must
|
||||
// blackhole internet traffic, not fall back to "no exit node":
|
||||
// the default routes stay in the OS route set with no outbound
|
||||
// peer to carry them.
|
||||
nb.updateRouteManagerPrefs(routePrefs{ExitNodeID: "no-such-node", ExitNodeSelected: true})
|
||||
// peer to carry them. Peer 2's allowed prefixes lose the /0s,
|
||||
// which the commit reports.
|
||||
if changed := nb.updateRouteManagerPrefs(routePrefs{ExitNodeID: "no-such-node", ExitNodeSelected: true}); len(changed) != 1 || changed[p2.Key()] == nil {
|
||||
t.Errorf("updateRouteManagerPrefs(exit=unresolved) changed = %v; want just %v", changed, p2.Key())
|
||||
}
|
||||
wantPeerFor("8.8.8.8", tailcfg.NodeView{})
|
||||
if !nb.routeMgr.OSRoutes().Get(netip.MustParsePrefix("0.0.0.0/0")) {
|
||||
t.Error("unresolved exit node: OSRoutes missing 0.0.0.0/0 blackhole route")
|
||||
@@ -339,12 +345,19 @@ func TestNodeBackendRouteManager(t *testing.T) {
|
||||
|
||||
// Incremental deltas: add peer 3, remove peer 1.
|
||||
p3 := mkPeer(3, "stable3", "100.64.0.3/32")
|
||||
if !nb.UpdateNetmapDelta([]netmap.NodeMutation{
|
||||
changed, handled := nb.UpdateNetmapDelta([]netmap.NodeMutation{
|
||||
netmap.NodeMutationUpsert{Node: p3},
|
||||
netmap.MakeNodeMutationRemove(1),
|
||||
}) {
|
||||
})
|
||||
if !handled {
|
||||
t.Fatal("UpdateNetmapDelta not handled")
|
||||
}
|
||||
if len(changed) != 2 || changed[p3.Key()] == nil {
|
||||
t.Errorf("UpdateNetmapDelta changed = %v; want entries for %v and %v", changed, p3.Key(), p1.Key())
|
||||
}
|
||||
if v, ok := changed[p1.Key()]; !ok || v != nil {
|
||||
t.Errorf("UpdateNetmapDelta changed[%v] = %v, %v; want nil, true for removed peer", p1.Key(), v, ok)
|
||||
}
|
||||
wantPeerFor("100.64.0.3", p3)
|
||||
wantPeerFor("100.64.0.1", tailcfg.NodeView{})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user