diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 2dc710111..e0169f700 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -629,10 +629,8 @@ func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*NetworkM if resp.Debug.LogHeapPprof { go logheap.LogHeap(resp.Debug.LogHeapURL) } - newv := resp.Debug.DERPRoute - if old, ok := controlUseDERPRoute.Load().(opt.Bool); !ok || old != newv { - controlUseDERPRoute.Store(newv) - } + setControlAtomic(&controlUseDERPRoute, resp.Debug.DERPRoute) + setControlAtomic(&controlTrimWGConfig, resp.Debug.TrimWGConfig) } // Temporarily (2020-06-29) support removing all but // discovery-supporting nodes during development, for @@ -964,7 +962,18 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node { return v2 } -var controlUseDERPRoute atomic.Value +// opt.Bool configs from control. +var ( + controlUseDERPRoute atomic.Value + controlTrimWGConfig atomic.Value +) + +func setControlAtomic(dst *atomic.Value, v opt.Bool) { + old, ok := dst.Load().(opt.Bool) + if !ok || old != v { + dst.Store(v) + } +} // DERPRouteFlag reports the last reported value from control for whether // DERP route optimization (Issue 150) should be enabled. @@ -972,3 +981,10 @@ func DERPRouteFlag() opt.Bool { v, _ := controlUseDERPRoute.Load().(opt.Bool) return v } + +// TrimWGConfig reports the last reported value from control for whether +// we should do lazy wireguard configuration. +func TrimWGConfig() opt.Bool { + v, _ := controlTrimWGConfig.Load().(opt.Bool) + return v +} diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 21a6eb4e6..f7f280e76 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -570,6 +570,10 @@ type Debug struct { // highest priority (if set), then this (if set), then the // binary default value. DERPRoute opt.Bool `json:",omitempty"` + + // TrimWGConfig controls whether Tailscale does lazy, on-demand + // wireguard configuration of peers. + TrimWGConfig opt.Bool `json:",omitempty"` } func (k MachineKey) String() string { return fmt.Sprintf("mkey:%x", k[:]) } diff --git a/wgengine/userspace.go b/wgengine/userspace.go index a11fa90cd..7c099571c 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -574,7 +574,10 @@ func (e *userspaceEngine) pinger(peerKey wgcfg.Key, ips []wgcfg.IP) { p.run(ctx, peerKey, ips, srcIP) } -var debugTrimWireguard, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_TRIM_WIREGUARD")) +var ( + debugTrimWireguardEnv = os.Getenv("TS_DEBUG_TRIM_WIREGUARD") + debugTrimWireguard, _ = strconv.ParseBool(debugTrimWireguardEnv) +) // forceFullWireguardConfig reports whether we should give wireguard // our full network map, even for inactive peers @@ -584,9 +587,13 @@ var debugTrimWireguard, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_TRIM_WIREGUARD // and we haven't got enough time testing it. func forceFullWireguardConfig(numPeers int) bool { // Did the user explicitly enable trimmming via the environment variable knob? - if debugTrimWireguard { - return false + if debugTrimWireguardEnv != "" { + return !debugTrimWireguard } + if opt := controlclient.TrimWGConfig(); opt != "" { + return !opt.EqualBool(true) + } + // On iOS with large networks, it's critical, so turn on trimming. // Otherwise we run out of memory from wireguard-go goroutine stacks+buffers. // This will be the default later for all platforms and network sizes.