tka: keep the CompactionDefaults alongside the other limits #6

Merged
codinget merged 216 commits from upstream/2026-05-18 into main 2026-05-18 21:22:49 +02:00
3 changed files with 72 additions and 37 deletions
Showing only changes of commit b313bffbe7 - Show all commits
+20 -10
View File
@@ -16,6 +16,7 @@ import (
"time" "time"
"github.com/klauspost/compress/zstd" "github.com/klauspost/compress/zstd"
"tailscale.com/health"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest/integration/testcontrol" "tailscale.com/tstest/integration/testcontrol"
"tailscale.com/types/key" "tailscale.com/types/key"
@@ -31,6 +32,8 @@ func TestMapAgainstTestControl(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
ht := new(health.Tracker)
serverKey, err := DiscoverServerKey(ctx, baseURL) serverKey, err := DiscoverServerKey(ctx, baseURL)
if err != nil { if err != nil {
t.Fatalf("DiscoverServerKey: %v", err) t.Fatalf("DiscoverServerKey: %v", err)
@@ -41,8 +44,9 @@ func TestMapAgainstTestControl(t *testing.T) {
nodeKey = key.NewNode() nodeKey = key.NewNode()
machineKey = key.NewMachine() machineKey = key.NewMachine()
c, err := NewClient(ClientOpts{ c, err := NewClient(ClientOpts{
ServerURL: baseURL, ServerURL: baseURL,
MachineKey: machineKey, MachineKey: machineKey,
HealthTracker: ht,
}) })
if err != nil { if err != nil {
t.Fatalf("NewClient %s: %v", hostname, err) t.Fatalf("NewClient %s: %v", hostname, err)
@@ -62,8 +66,9 @@ func TestMapAgainstTestControl(t *testing.T) {
nodeKeyB, _ := register("b") nodeKeyB, _ := register("b")
clientA, err := NewClient(ClientOpts{ clientA, err := NewClient(ClientOpts{
ServerURL: baseURL, ServerURL: baseURL,
MachineKey: machineKeyA, MachineKey: machineKeyA,
HealthTracker: ht,
}) })
if err != nil { if err != nil {
t.Fatalf("NewClient A: %v", err) t.Fatalf("NewClient A: %v", err)
@@ -144,6 +149,8 @@ func TestSendMapUpdateAgainstTestControl(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
ht := new(health.Tracker)
serverKey, err := DiscoverServerKey(ctx, baseURL) serverKey, err := DiscoverServerKey(ctx, baseURL)
if err != nil { if err != nil {
t.Fatalf("DiscoverServerKey: %v", err) t.Fatalf("DiscoverServerKey: %v", err)
@@ -154,8 +161,9 @@ func TestSendMapUpdateAgainstTestControl(t *testing.T) {
nodeKey = key.NewNode() nodeKey = key.NewNode()
machineKey = key.NewMachine() machineKey = key.NewMachine()
c, err := NewClient(ClientOpts{ c, err := NewClient(ClientOpts{
ServerURL: baseURL, ServerURL: baseURL,
MachineKey: machineKey, MachineKey: machineKey,
HealthTracker: ht,
}) })
if err != nil { if err != nil {
t.Fatalf("NewClient %s: %v", hostname, err) t.Fatalf("NewClient %s: %v", hostname, err)
@@ -176,8 +184,9 @@ func TestSendMapUpdateAgainstTestControl(t *testing.T) {
// B starts a streaming map poll so we can observe updates about peer A. // B starts a streaming map poll so we can observe updates about peer A.
clientB, err := NewClient(ClientOpts{ clientB, err := NewClient(ClientOpts{
ServerURL: baseURL, ServerURL: baseURL,
MachineKey: machineKeyB, MachineKey: machineKeyB,
HealthTracker: ht,
}) })
if err != nil { if err != nil {
t.Fatalf("NewClient B: %v", err) t.Fatalf("NewClient B: %v", err)
@@ -228,8 +237,9 @@ func TestSendMapUpdateAgainstTestControl(t *testing.T) {
// A pushes its disco key via SendMapUpdate. // A pushes its disco key via SendMapUpdate.
clientA, err := NewClient(ClientOpts{ clientA, err := NewClient(ClientOpts{
ServerURL: baseURL, ServerURL: baseURL,
MachineKey: machineKeyA, MachineKey: machineKeyA,
HealthTracker: ht,
}) })
if err != nil { if err != nil {
t.Fatalf("NewClient A: %v", err) t.Fatalf("NewClient A: %v", err)
+11 -5
View File
@@ -19,6 +19,7 @@ import (
"sync" "sync"
"tailscale.com/control/ts2021" "tailscale.com/control/ts2021"
"tailscale.com/health"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
@@ -43,6 +44,10 @@ type ClientOpts struct {
// Logf is the log function. If nil, logger.Discard is used. // Logf is the log function. If nil, logger.Discard is used.
Logf logger.Logf Logf logger.Logf
// HealthTracker, if non-nil, is the health tracker passed through
// to the underlying noise client. May be nil.
HealthTracker *health.Tracker
} }
// Client is a Tailscale protocol client that speaks to a coordination // Client is a Tailscale protocol client that speaks to a coordination
@@ -155,11 +160,12 @@ func (c *Client) noiseClient(ctx context.Context) (*ts2021.Client, error) {
} }
nc, err := ts2021.NewClient(ts2021.ClientOpts{ nc, err := ts2021.NewClient(ts2021.ClientOpts{
ServerURL: c.serverURL, ServerURL: c.serverURL,
PrivKey: c.opts.MachineKey, PrivKey: c.opts.MachineKey,
ServerPubKey: c.serverPub, ServerPubKey: c.serverPub,
Dialer: tsdial.NewFromFuncForDebug(c.logf, (&net.Dialer{}).DialContext), Dialer: tsdial.NewFromFuncForDebug(c.logf, (&net.Dialer{}).DialContext),
Logf: c.logf, Logf: c.logf,
HealthTracker: c.opts.HealthTracker,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("creating noise client: %w", err) return nil, fmt.Errorf("creating noise client: %w", err)
+41 -22
View File
@@ -156,8 +156,8 @@ type Server struct {
updates map[tailcfg.NodeID]chan updateType updates map[tailcfg.NodeID]chan updateType
authPath map[string]*AuthPath authPath map[string]*AuthPath
nodeKeyAuthed set.Set[key.NodePublic] nodeKeyAuthed set.Set[key.NodePublic]
msgToSend map[key.NodePublic]any // value is *tailcfg.PingRequest or entire *tailcfg.MapResponse msgToSend map[key.NodePublic][]any // FIFO queue per node; values are *tailcfg.PingRequest or *tailcfg.MapResponse
allExpired bool // All nodes will be told their node key is expired. allExpired bool // All nodes will be told their node key is expired.
// tkaStorage records the Tailnet Lock state, if any. // tkaStorage records the Tailnet Lock state, if any.
// If nil, Tailnet Lock is not enabled in the Tailnet. // If nil, Tailnet Lock is not enabled in the Tailnet.
@@ -300,14 +300,16 @@ func (s *Server) AddRawMapResponse(nodeKeyDst key.NodePublic, mr *tailcfg.MapRes
func (s *Server) addDebugMessage(nodeKeyDst key.NodePublic, msg any) bool { func (s *Server) addDebugMessage(nodeKeyDst key.NodePublic, msg any) bool {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
if s.msgToSend == nil {
s.msgToSend = map[key.NodePublic]any{}
}
// Now send the update to the channel
node := s.nodeLocked(nodeKeyDst) node := s.nodeLocked(nodeKeyDst)
if node == nil { if node == nil {
return false return false
} }
updatesCh := s.updates[node.ID]
if updatesCh == nil {
// No streaming poll is registered, so there's nobody to deliver
// the message to.
return false
}
if _, ok := msg.(*tailcfg.MapResponse); ok { if _, ok := msg.(*tailcfg.MapResponse); ok {
if s.suppressAutoMapResponses == nil { if s.suppressAutoMapResponses == nil {
@@ -316,10 +318,14 @@ func (s *Server) addDebugMessage(nodeKeyDst key.NodePublic, msg any) bool {
s.suppressAutoMapResponses.Add(nodeKeyDst) s.suppressAutoMapResponses.Add(nodeKeyDst)
} }
s.msgToSend[nodeKeyDst] = msg mak.Set(&s.msgToSend, nodeKeyDst, append(s.msgToSend[nodeKeyDst], msg))
nodeID := node.ID // sendUpdate returning false here is fine: the channel is a lossy
oldUpdatesCh := s.updates[nodeID] // wake-up signal whose buffer is single-slot. A full buffer means a
return sendUpdate(oldUpdatesCh, updateDebugInjection) // prior wake-up is still pending, and the streaming poll will check
// msgToSend when it processes that wake-up. The queue in msgToSend
// is the source of truth.
sendUpdate(updatesCh, updateDebugInjection)
return true
} }
// Mark the Node key of every node as expired // Mark the Node key of every node as expired
@@ -1472,15 +1478,29 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse,
res.Node.PrimaryRoutes = s.nodeSubnetRoutes[nk] res.Node.PrimaryRoutes = s.nodeSubnetRoutes[nk]
res.Node.AllowedIPs = append(res.Node.Addresses, s.nodeSubnetRoutes[nk]...) res.Node.AllowedIPs = append(res.Node.Addresses, s.nodeSubnetRoutes[nk]...)
// Consume a PingRequest while protected by mutex if it exists // Consume a PingRequest at the head of the queue, if any.
switch m := s.msgToSend[nk].(type) { if q := s.msgToSend[nk]; len(q) > 0 {
case *tailcfg.PingRequest: if pr, ok := q[0].(*tailcfg.PingRequest); ok {
res.PingRequest = m res.PingRequest = pr
delete(s.msgToSend, nk) s.popMsgToSendLocked(nk)
}
} }
return res, nil return res, nil
} }
// popMsgToSendLocked pops the head of the per-node message queue.
// s.mu must be held.
func (s *Server) popMsgToSendLocked(nk key.NodePublic) {
q := s.msgToSend[nk]
if len(q) <= 1 {
delete(s.msgToSend, nk)
return
}
// Zero the head to allow GC of any large referenced response.
q[0] = nil
s.msgToSend[nk] = q[1:]
}
func (s *Server) canGenerateAutomaticMapResponseFor(nk key.NodePublic) bool { func (s *Server) canGenerateAutomaticMapResponseFor(nk key.NodePublic) bool {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@@ -1490,22 +1510,21 @@ func (s *Server) canGenerateAutomaticMapResponseFor(nk key.NodePublic) bool {
func (s *Server) hasPendingRawMapMessage(nk key.NodePublic) bool { func (s *Server) hasPendingRawMapMessage(nk key.NodePublic) bool {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
_, ok := s.msgToSend[nk] return len(s.msgToSend[nk]) > 0
return ok
} }
func (s *Server) takeRawMapMessage(nk key.NodePublic) (mapResJSON []byte, ok bool) { func (s *Server) takeRawMapMessage(nk key.NodePublic) (mapResJSON []byte, ok bool) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
mr, ok := s.msgToSend[nk] q := s.msgToSend[nk]
if !ok { if len(q) == 0 {
return nil, false return nil, false
} }
delete(s.msgToSend, nk) mr := q[0]
s.popMsgToSendLocked(nk)
// If it's a bare PingRequest, wrap it in a MapResponse. // If it's a bare PingRequest, wrap it in a MapResponse.
switch pr := mr.(type) { if pr, ok := mr.(*tailcfg.PingRequest); ok {
case *tailcfg.PingRequest:
mr = &tailcfg.MapResponse{PingRequest: pr} mr = &tailcfg.MapResponse{PingRequest: pr}
} }