tka: keep the CompactionDefaults alongside the other limits #6
@@ -162,6 +162,10 @@ type Server struct {
|
|||||||
// 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.
|
||||||
tkaStorage tka.CompactableChonk
|
tkaStorage tka.CompactableChonk
|
||||||
|
|
||||||
|
// onMapRequest, if non-nil, is called at the start of each map poll request.
|
||||||
|
// It can be used in tests to panic or fail if a node contacts control unexpectedly.
|
||||||
|
onMapRequest func(nodeKey key.NodePublic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseURL returns the server's base URL, without trailing slash.
|
// BaseURL returns the server's base URL, without trailing slash.
|
||||||
@@ -1169,6 +1173,12 @@ func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey key.Machi
|
|||||||
go panic(fmt.Sprintf("bad map request: %v", err))
|
go panic(fmt.Sprintf("bad map request: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
if s.onMapRequest != nil {
|
||||||
|
s.onMapRequest(req.NodeKey)
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
if s.AltMapStream != nil {
|
if s.AltMapStream != nil {
|
||||||
// The caller takes over the stream entirely; it must handle
|
// The caller takes over the stream entirely; it must handle
|
||||||
// keeping the HTTP response alive until ctx is done.
|
// keeping the HTTP response alive until ctx is done.
|
||||||
@@ -1620,6 +1630,15 @@ func (s *Server) encode(compress bool, v any) (b []byte, err error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetOnMapRequest sets callback used for testing when a new mapRequest happens.
|
||||||
|
// Pass nil to remove the callback.
|
||||||
|
func (s *Server) SetOnMapRequest(f func(key.NodePublic)) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
s.onMapRequest = f
|
||||||
|
}
|
||||||
|
|
||||||
// filterInvalidIPv6Endpoints removes invalid IPv6 endpoints from eps,
|
// filterInvalidIPv6Endpoints removes invalid IPv6 endpoints from eps,
|
||||||
// modify the slice in place, returning the potentially smaller subset (aliasing
|
// modify the slice in place, returning the potentially smaller subset (aliasing
|
||||||
// the original memory).
|
// the original memory).
|
||||||
|
|||||||
@@ -586,6 +586,31 @@ func (e *Env) Start() {
|
|||||||
if st2.BackendState != "Running" {
|
if st2.BackendState != "Running" {
|
||||||
return fmt.Errorf("[%s] state = %q, want Running", n.name, st2.BackendState)
|
return fmt.Errorf("[%s] state = %q, want Running", n.name, st2.BackendState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply any capabilities for the node to the map.
|
||||||
|
// SetNodeCapMap pushes an updated map response immediately, then wait
|
||||||
|
// until the node reports the capability in its status.
|
||||||
|
if cm := n.vnetNode.WantCapMap(); cm != nil {
|
||||||
|
e.server.ControlServer().SetNodeCapMap(st2.Self.PublicKey, cm)
|
||||||
|
if err := tstest.WaitFor(15*time.Second, func() error {
|
||||||
|
st, err := n.agent.Status(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if st.Self == nil {
|
||||||
|
return fmt.Errorf("self is nil")
|
||||||
|
}
|
||||||
|
for c := range cm {
|
||||||
|
if !st.Self.HasCap(c) {
|
||||||
|
return fmt.Errorf("cap %v not yet received", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("[%s] waiting for capabilities: %w", n.name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ips := fmt.Sprintf("%v", st2.Self.TailscaleIPs)
|
ips := fmt.Sprintf("%v", st2.Self.TailscaleIPs)
|
||||||
e.setNodeTailscale(n.name, "Running "+ips)
|
e.setNodeTailscale(n.name, "Running "+ips)
|
||||||
t.Logf("[%s] up with %v", n.name, st2.Self.TailscaleIPs)
|
t.Logf("[%s] up with %v", n.name, st2.Self.TailscaleIPs)
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"tailscale.com/client/local"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/tstest/integration/testcontrol"
|
"tailscale.com/tstest/integration/testcontrol"
|
||||||
"tailscale.com/tstest/natlab/vmtest"
|
"tailscale.com/tstest/natlab/vmtest"
|
||||||
"tailscale.com/tstest/natlab/vnet"
|
"tailscale.com/tstest/natlab/vnet"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
|
"tailscale.com/types/netmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMacOSAndLinuxCanPing(t *testing.T) {
|
func TestMacOSAndLinuxCanPing(t *testing.T) {
|
||||||
@@ -905,3 +907,74 @@ func TestMullvadExitNode(t *testing.T) {
|
|||||||
env.SetExitNodeIP(client, netip.Addr{})
|
env.SetExitNodeIP(client, netip.Addr{})
|
||||||
check(checkOff2Step, "exit-off (again)", clientWAN)
|
check(checkOff2Step, "exit-off (again)", clientWAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCachedNetmapAfterRestart verifies that two nodes with netmap
|
||||||
|
// caching enabled (NodeAttrCacheNetworkMaps) can re-establish a direct
|
||||||
|
// WireGuard tunnel after both are restarted while the control server is
|
||||||
|
// unreachable. After restart the nodes must use only their on-disk cached
|
||||||
|
// netmaps to re-connect.
|
||||||
|
func TestCachedNetmapAfterRestart(t *testing.T) {
|
||||||
|
env := vmtest.New(t)
|
||||||
|
|
||||||
|
aNet := env.AddNetwork("1.0.0.1", "192.168.1.1/24", vnet.EasyNAT)
|
||||||
|
bNet := env.AddNetwork("2.0.0.1", "192.168.2.1/24", vnet.EasyNAT)
|
||||||
|
|
||||||
|
aNet.SetPostConnectControlBlackhole(true)
|
||||||
|
bNet.SetPostConnectControlBlackhole(true)
|
||||||
|
|
||||||
|
a := env.AddNode("a", aNet,
|
||||||
|
vmtest.OS(vmtest.Gokrazy),
|
||||||
|
tailcfg.NodeCapMap{tailcfg.NodeAttrCacheNetworkMaps: nil})
|
||||||
|
b := env.AddNode("b", bNet,
|
||||||
|
vmtest.OS(vmtest.Gokrazy),
|
||||||
|
tailcfg.NodeCapMap{tailcfg.NodeAttrCacheNetworkMaps: nil})
|
||||||
|
|
||||||
|
connectStep := env.AddStep("Establish initial TSMP tunnel")
|
||||||
|
cutControlStep := env.AddStep("Cut control server access")
|
||||||
|
restartStep := env.AddStep("Restart tailscaled on both nodes")
|
||||||
|
netmapCheckStep := env.AddStep("Check netmap loaded is cached")
|
||||||
|
pingStep := env.AddStep("Ping a → b TSMP (cached netmap, no control)")
|
||||||
|
|
||||||
|
env.Start()
|
||||||
|
|
||||||
|
connectStep.Begin()
|
||||||
|
if err := env.Ping(a, b, tailcfg.PingTSMP, 30*time.Second); err != nil {
|
||||||
|
connectStep.End(err)
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
connectStep.End(nil)
|
||||||
|
|
||||||
|
cutControlStep.Begin()
|
||||||
|
aNet.PostConnectedToControl()
|
||||||
|
bNet.PostConnectedToControl()
|
||||||
|
env.ControlServer().SetOnMapRequest(func(nk key.NodePublic) {
|
||||||
|
panic(fmt.Sprintf("got connection from %v", nk))
|
||||||
|
})
|
||||||
|
cutControlStep.End(nil)
|
||||||
|
|
||||||
|
restartStep.Begin()
|
||||||
|
env.RestartTailscaled(a)
|
||||||
|
env.RestartTailscaled(b)
|
||||||
|
restartStep.End(nil)
|
||||||
|
|
||||||
|
netmapCheckStep.Begin()
|
||||||
|
for _, node := range []*vmtest.Node{a, b} {
|
||||||
|
nm, err := local.GetDebugResultJSON[netmap.NetworkMap](t.Context(), node.Agent().Client, "current-netmap")
|
||||||
|
if err != nil {
|
||||||
|
netmapCheckStep.End(fmt.Errorf("[%s] got err fetching netmap %q", node.Name(), err))
|
||||||
|
t.Fatalf("[%s] got err fetching netmap %q", node.Name(), err)
|
||||||
|
}
|
||||||
|
if !nm.Cached {
|
||||||
|
netmapCheckStep.End(fmt.Errorf("[%s] expected netmap.Cached = true, got: %t", node.Name(), nm.Cached))
|
||||||
|
t.Fatalf("[%s] expected netmap.Cached = true, got: %t", node.Name(), nm.Cached)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netmapCheckStep.End(nil)
|
||||||
|
|
||||||
|
pingStep.Begin()
|
||||||
|
if err := env.Ping(a, b, tailcfg.PingTSMP, 30*time.Second); err != nil {
|
||||||
|
pingStep.End(err)
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pingStep.End(nil)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user