Skip to content

ipn/ipnlocal: manage per-profile subdirectories in TailscaleVarRoot#18485

Merged
creachadair merged 1 commit intomainfrom
mjf/nmc-profile-dir
Jan 23, 2026
Merged

ipn/ipnlocal: manage per-profile subdirectories in TailscaleVarRoot#18485
creachadair merged 1 commit intomainfrom
mjf/nmc-profile-dir

Conversation

@creachadair
Copy link
Copy Markdown
Member

In order to better manage per-profile data resources on the client, add methods
to the LocalBackend to support creation of per-profile directory structures in
local storage. These methods build on the existing TailscaleVarRoot config, and
have the same limitation (i.e., if no local storage is available, it will
report an error when used).

The immediate motivation is to support netmap caching, but we can also use this
mechanism for other per-profile resources including pending taildrop files and
Tailnet Lock authority caches.

This commit only adds the directory-management plumbing; later commits will
handle migrating taildrop, TKA, etc. to this mechanism, as well as caching
network maps.

updates #12639

Change-Id: Ia75741955c7bf885e49c1ad99f856f669a754169
Signed-off-by: M. J. Fromberger fromberger@tailscale.com

@creachadair creachadair requested review from a team and cmol January 22, 2026 17:50
@creachadair creachadair marked this pull request as ready for review January 22, 2026 17:50
Copy link
Copy Markdown
Member

@nickkhyl nickkhyl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid adding more profile-specific functionality to LocalBackend? This seems like a better fit for profileManager and/or nodeBackend.

@creachadair
Copy link
Copy Markdown
Member Author

Can we avoid adding more profile-specific functionality to LocalBackend? This seems like a better fit for profileManager and/or nodeBackend.

We probably could move at least part of it to profileManager. I think to do so we'd also need to move (or duplicate) the var-root plumbing, since this depends both on profile IDs and storage context that the LB currently manages.

I don't have a super strong preference about where it lands. The initial consumer will be netmap caching, which will live on the LB, but I don't think it would be too hard to move it (either now or later).

@nickkhyl
Copy link
Copy Markdown
Member

The initial consumer will be netmap caching, which will live on the LB, but I don't think it would be too hard to move it (either now or later).

Is this set in stone? Have we considered making it an optional feature, as per the Tailscale Client Modularity Guide? Have we considered implementing netmap caching in nodeBackend instead of LocalBackend?

If we've already decided to implement all of this in LocalBackend, rather than making it an optional feature and/or placing it in nodeBackend, then it's probably fine to have these few methods in LocalBackend as well. That said, I'd be interested in catching up on the reasons behind this decision.

But if we haven't made that decision yet and we're still considering alternatives, then implementing this elsewhere may lead to a design that better aligns with our long-term goals of avoiding optional features in LocalBackend and keeping node-specific logic and state in nodeBackend.

(Unlike the CurrentProfileMkdirAll comment above, this isn't a blocker for this PR, but I still wanted to flag it and better understand the reasons before we start adding more code to LocalBackend.)

@creachadair
Copy link
Copy Markdown
Member Author

The initial consumer will be netmap caching, which will live on the LB, but I don't think it would be too hard to move it (either now or later).

Is this set in stone?

No, we're just prototyping the ability to cache network maps. That probably will be an optional feature. When it's enabled, we'll need a place to store the maps for a given profile, and this is meant to be a very-mild generalization, so that we can include other profile-specific data we already store (e.g., taildrop files, AUM chain caches) in a common location.

The latter is optional, however, we don't have to combine them.


// profileMkdirAllLocked implements ProfileMkdirAll.
// The caller must hold b.mu.
func (b *LocalBackend) profileMkdirAllLocked(id ipn.ProfileID, subs ...string) (string, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return an error if id is empty?

As per earlier discussion, we don't expect this to be called for a profile that hasn't been persisted yet anyway, so let's be defensive about it.

In order to better manage per-profile data resources on the client, add methods
to the LocalBackend to support creation of per-profile directory structures in
local storage. These methods build on the existing TailscaleVarRoot config, and
have the same limitation (i.e., if no local storage is available, it will
report an error when used).

The immediate motivation is to support netmap caching, but we can also use this
mechanism for other per-profile resources including pending taildrop files and
Tailnet Lock authority caches.

This commit only adds the directory-management plumbing; later commits will
handle migrating taildrop, TKA, etc. to this mechanism, as well as caching
network maps.

updates #12639

Change-Id: Ia75741955c7bf885e49c1ad99f856f669a754169
Signed-off-by: M. J. Fromberger <fromberger@tailscale.com>
@creachadair creachadair merged commit ce12863 into main Jan 23, 2026
58 checks passed
@creachadair creachadair deleted the mjf/nmc-profile-dir branch January 23, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants