78627c132f
With netmap caching, the home DERP of the self node was neither saved to
the cache or loaded from it, making nodes not stick to a DERP when
starting without a connection to control.
Instead, make sure that when a cache is available, load that cache,
before looking for DERP servers. This is implemented by allowing a skip
of ReSTUN in setting the DERP map (we must have a DERP map before
setting the home DERP), so the DERP from cache will set itself and be
sticky until a connection to control is established.
Making DERP only change when connected to control is handled by existing
code from f072d017bd.
Updates #19490
Signed-off-by: Claus Lensbøl <claus@tailscale.com>
131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package magicsock
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"tailscale.com/health"
|
|
"tailscale.com/net/netcheck"
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/tstest"
|
|
"tailscale.com/util/eventbus"
|
|
"tailscale.com/util/eventbus/eventbustest"
|
|
)
|
|
|
|
func CheckDERPHeuristicTimes(t *testing.T) {
|
|
if netcheck.PreferredDERPFrameTime <= frameReceiveRecordRate {
|
|
t.Errorf("PreferredDERPFrameTime too low; should be at least frameReceiveRecordRate")
|
|
}
|
|
}
|
|
|
|
func TestForceSetNearestDERP(t *testing.T) {
|
|
derpMap := &tailcfg.DERPMap{
|
|
Regions: map[int]*tailcfg.DERPRegion{
|
|
7: {
|
|
RegionID: 7,
|
|
RegionCode: "test",
|
|
Nodes: []*tailcfg.DERPNode{
|
|
{
|
|
Name: "7a",
|
|
RegionID: 7,
|
|
HostName: "derp7.test.unused",
|
|
IPv4: "127.0.0.1",
|
|
IPv6: "none",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Force the real control health check so we can verify force=true bypasses it.
|
|
tstest.Replace(t, &checkControlHealthDuringNearestDERPInTests, true)
|
|
|
|
bus := eventbustest.NewBus(t)
|
|
ht := health.NewTracker(bus)
|
|
c := newConn(t.Logf)
|
|
ec := bus.Client("magicsock.Conn.Test")
|
|
c.eventClient = ec
|
|
c.homeDERPChangedPub = eventbus.Publish[HomeDERPChanged](ec)
|
|
c.eventBus = bus
|
|
c.derpMap = derpMap
|
|
c.health = ht
|
|
|
|
ht.SetOutOfPollNetMap()
|
|
|
|
tw := eventbustest.NewWatcher(t, bus)
|
|
|
|
got := c.ForceSetNearestDERP(7)
|
|
if got != 7 {
|
|
t.Fatalf("ForceSetNearestDERP(7) = %d, want 7", got)
|
|
}
|
|
if c.myDerp != 7 {
|
|
t.Errorf("c.myDerp = %d after ForceSetNearestDERP, want 7", c.myDerp)
|
|
}
|
|
|
|
if err := eventbustest.Expect(tw, func(e HomeDERPChanged) error {
|
|
if e.Old != 0 || e.New != 7 {
|
|
return fmt.Errorf("got HomeDERPChanged{Old:%d, New:%d}, want {Old:0, New:7}", e.Old, e.New)
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
t.Errorf("expected HomeDERPChanged event: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSetDERPMapDoReStun(t *testing.T) {
|
|
derpMap1 := &tailcfg.DERPMap{
|
|
Regions: map[int]*tailcfg.DERPRegion{
|
|
1: {
|
|
RegionID: 1,
|
|
RegionCode: "cph",
|
|
Nodes: []*tailcfg.DERPNode{
|
|
{Name: "1a", RegionID: 1, HostName: "cph.test.unused", IPv4: "127.0.0.1", IPv6: "none"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
derpMap2 := &tailcfg.DERPMap{
|
|
Regions: map[int]*tailcfg.DERPRegion{
|
|
2: {
|
|
RegionID: 2,
|
|
RegionCode: "inc",
|
|
Nodes: []*tailcfg.DERPNode{
|
|
{Name: "2a", RegionID: 2, HostName: "inc.test.unused", IPv4: "127.0.0.1", IPv6: "none"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var reSTUNCalls int
|
|
tstest.Replace(t, &reSTUNHookForTests, func(_ string) {
|
|
reSTUNCalls++
|
|
})
|
|
|
|
bus := eventbustest.NewBus(t)
|
|
ht := health.NewTracker(bus)
|
|
c := newConn(t.Logf)
|
|
ec := bus.Client("magicsock.Conn.Test")
|
|
c.eventClient = ec
|
|
c.homeDERPChangedPub = eventbus.Publish[HomeDERPChanged](ec)
|
|
c.eventBus = bus
|
|
c.health = ht
|
|
// With a zero private key and everHadKey=true, ReSTUN returns early without
|
|
// spawning updateEndpoints.
|
|
c.everHadKey = true
|
|
|
|
// Should not trigger a ReSTUN.
|
|
c.SetDERPMap(derpMap1, false)
|
|
if reSTUNCalls != 0 {
|
|
t.Errorf("SetDERPMap(dm, doReStun=false): got %d ReSTUN calls, want 0", reSTUNCalls)
|
|
}
|
|
|
|
// doReStun=true: should trigger a ReSTUN.
|
|
c.SetDERPMap(derpMap2, true)
|
|
if reSTUNCalls != 1 {
|
|
t.Errorf("SetDERPMap(dm, doReStun=true): got %d ReSTUN calls, want 1", reSTUNCalls)
|
|
}
|
|
}
|