summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2025-09-09 13:18:25 -0700
committerBrad Fitzpatrick <bradfitz@tailscale.com>2025-09-09 13:18:25 -0700
commita9c7aa702c98e678eda0dfa251eccb91dc9ce06d (patch)
treec7667c361282ecc97713ed01eb0f79747b8accdb
parent77250a301aee83d67c1bbe497391500f7c70e7b4 (diff)
downloadtailscale-bradfitz/lite-on-restart.tar.xz
tailscale-bradfitz/lite-on-restart.zip
control/controlclient: don't send dup lite map update requestsbradfitz/lite-on-restart
On control server connection break, the updateRoutine loops and sends the same lite update. This stops that, to be nicer to the server. Updates tailscale/corp#32114 Change-Id: I3acf4b5de4514cd4ce109a31cc424d916bdeba3f Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
-rw-r--r--control/controlclient/direct.go20
1 files changed, 20 insertions, 0 deletions
diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go
index 47283a673..99d1df992 100644
--- a/control/controlclient/direct.go
+++ b/control/controlclient/direct.go
@@ -8,6 +8,7 @@ import (
"bytes"
"cmp"
"context"
+ "crypto/sha256"
"encoding/binary"
"encoding/json"
"errors"
@@ -93,6 +94,7 @@ type Direct struct {
mu sync.Mutex // mutex guards the following fields
serverLegacyKey key.MachinePublic // original ("legacy") nacl crypto_box-based public key; only used for signRegisterRequest on Windows now
serverNoiseKey key.MachinePublic
+ lastLiteHash [sha256.Size]byte // last hash of lite map request we sent to control for which we got a 200 OK
sfGroup singleflight.Group[struct{}, *NoiseClient] // protects noiseClient creation.
noiseClient *NoiseClient
@@ -939,6 +941,12 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
return err
}
+ bodyHash := sha256.Sum256(bodyData)
+ if !isStreaming && nu == nil && c.lastLiteHashEquals(bodyHash) {
+ vlogf("netmap: skipping lite update; previous was identical and succeeded")
+ return nil
+ }
+
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -1000,6 +1008,10 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
watchdogTimer.Reset(watchdogTimeout)
if nu == nil {
+ c.mu.Lock()
+ c.lastLiteHash = bodyHash
+ c.mu.Unlock()
+
io.Copy(io.Discard, res.Body)
return nil
}
@@ -1138,6 +1150,14 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
return nil
}
+// lastLiteHashEquals reports whether the last sent lite map request hash
+// is equal to the given hash.
+func (c *Direct) lastLiteHashEquals(hash [sha256.Size]byte) bool {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.lastLiteHash == hash
+}
+
func (c *Direct) handleDebugMessage(ctx context.Context, debug *tailcfg.Debug) error {
if code := debug.Exit; code != nil {
c.logf("exiting process with status %v per controlplane", *code)