mirror of
https://github.com/tailscale/tailscale.git
synced 2026-04-04 14:43:42 -04:00
Add a new tailcfg.NodeCapability (NodeAttrCacheNetworkMaps) to control whether a node with support for caching network maps will attempt to do so. Update the capability version to reflect this change (mainly as a safety measure, as the control plane does not currently need to know about it). Use the presence (or absence) of the node attribute to decide whether to create and update a netmap cache for each profile. If caching is disabled, discard the cached data; this allows us to use the presence of a cached netmap as an indicator it should be used (unless explicitly overridden). Add a test that verifies the attribute is respected. Reverse the sense of the environment knob to be true by default, with an override to disable caching at the client regardless what the node attribute says. Move the creation/update of the netmap cache (when enabled) until after successfully applying the network map, to reduce the possibility that we will cache (and thus reuse after a restart) a network map that fails to correctly configure the client. Updates #12639 Change-Id: I1df4dd791fdb485c6472a9f741037db6ed20c47e Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
85 lines
2.3 KiB
Go
85 lines
2.3 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package ipnlocal
|
|
|
|
import (
|
|
"tailscale.com/feature/buildfeatures"
|
|
"tailscale.com/ipn/ipnlocal/netmapcache"
|
|
"tailscale.com/types/netmap"
|
|
)
|
|
|
|
// diskCache is the state netmap caching to disk.
|
|
type diskCache struct {
|
|
// all fields guarded by LocalBackend.mu
|
|
|
|
dir string // active profile cache directory
|
|
cache *netmapcache.Cache
|
|
}
|
|
|
|
func (b *LocalBackend) writeNetmapToDiskLocked(nm *netmap.NetworkMap) error {
|
|
if !buildfeatures.HasCacheNetMap || nm == nil || nm.Cached {
|
|
return nil
|
|
}
|
|
b.logf("writing netmap to disk cache")
|
|
|
|
dir, err := b.profileMkdirAllLocked(b.pm.CurrentProfile().ID(), "netmap-cache")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if c := b.diskCache; c.cache == nil || c.dir != dir {
|
|
b.diskCache.cache = netmapcache.NewCache(netmapcache.FileStore(dir))
|
|
b.diskCache.dir = dir
|
|
}
|
|
return b.diskCache.cache.Store(b.currentNode().Context(), nm)
|
|
}
|
|
|
|
func (b *LocalBackend) loadDiskCacheLocked() (om *netmap.NetworkMap, ok bool) {
|
|
if !buildfeatures.HasCacheNetMap {
|
|
return nil, false
|
|
}
|
|
dir, err := b.profileMkdirAllLocked(b.pm.CurrentProfile().ID(), "netmap-cache")
|
|
if err != nil {
|
|
b.logf("profile data directory: %v", err)
|
|
return nil, false
|
|
}
|
|
if c := b.diskCache; c.cache == nil || c.dir != dir {
|
|
b.diskCache.cache = netmapcache.NewCache(netmapcache.FileStore(dir))
|
|
b.diskCache.dir = dir
|
|
}
|
|
nm, err := b.diskCache.cache.Load(b.currentNode().Context())
|
|
if err != nil {
|
|
b.logf("load netmap from cache: %v", err)
|
|
return nil, false
|
|
}
|
|
return nm, true
|
|
}
|
|
|
|
// discardDiskCacheLocked removes a cached network map for the current node, if
|
|
// one exists, and disables the cache.
|
|
func (b *LocalBackend) discardDiskCacheLocked() {
|
|
if !buildfeatures.HasCacheNetMap {
|
|
return
|
|
}
|
|
if b.diskCache.cache == nil {
|
|
return // nothing to do, we do not have a cache
|
|
}
|
|
|
|
// Reaching here, we have a cache directory that needs to be purged.
|
|
// Log errors but do not fail for them.
|
|
store := netmapcache.FileStore(b.diskCache.dir)
|
|
ctx := b.currentNode().Context()
|
|
for key, err := range store.List(ctx, "") {
|
|
if err != nil {
|
|
b.logf("listing cache contents: %v", err)
|
|
break
|
|
}
|
|
if err := store.Remove(ctx, key); err != nil {
|
|
b.logf("discarding cache key %q: %v", key, err)
|
|
}
|
|
}
|
|
|
|
b.diskCache.cache = nil // drop reference
|
|
b.diskCache.dir = ""
|
|
}
|