mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-15 01:53:08 -04:00
LocalBackend.Start previously shut down the previous control client in a goroutine, letting it run concurrently with the new one. An in-flight lite map update carrying stale Hostinfo.RequestTags could then be processed by the control plane after the new client had already changed the node's tags. Control treats such a request as an invalid tag transition and expires the node key to force a reauth, so retagging a node with "tailscale up --advertise-tags" intermittently logged the machine out. Instead, detach the old client under b.mu and shut it down synchronously with the lock released, before creating the new client. Shutdown cancels the old client's in-flight requests and waits for its goroutines to exit, so the cancellation of any stale update reaches the server before the new client sends its first request. Per the deadlock history in #18052, Shutdown must not be called with b.mu held; this uses the same pattern as DisconnectControl. Also teach the testcontrol server to model the control plane's tag transition handling (including expiring the node key on an invalid transition and ignoring updates from canceled requests), add an integration test reproducing the race, and add an ipnlocal test verifying that Start waits for the old client to shut down. Updates #20365 Updates #18052 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: If8c8e145bdadcef1b1b8fe6209453cf5f5a8d616