prober: support probing DERP regions with nodes in mixed VPCs

Updates tailscale/corp#24232

Change-Id: Ief50a337b61b5791f03d48d7274f4e9c25e5656a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-10-31 07:56:58 -07:00
parent 45354dab9b
commit 027959c1ab
2 changed files with 44 additions and 1 deletions

View File

@ -172,6 +172,15 @@ func (d *derpProber) probeMapFn(ctx context.Context) error {
}
for _, to := range region.Nodes {
if !inSameVPC(server, to) {
// This pair of nodes in the region are in different VPCs; don't expect
// them to be meshed. In the general case, the DERPMap data structure and client
// don't support such a region configuration. This is a special case for
// Tailscale's probers being able to monitor a meta DERP map that's a superset
// of multiple independent DERP maps.
continue
}
if d.meshInterval > 0 {
n := fmt.Sprintf("derp/%s/%s/%s/mesh", region.RegionCode, server.Name, to.Name)
wantProbes[n] = true
@ -204,6 +213,24 @@ func (d *derpProber) probeMapFn(ctx context.Context) error {
return nil
}
func inSameVPC(a, b *tailcfg.DERPNode) bool {
return vpcName(a.Name) == vpcName(b.Name)
}
// vpcName returns the name of a VPC that a DERP Node is running
// in as a function of its DERPNode.Name.
//
// This is a naming convention for the Tailscale-run DERP nodes only
// and is not a thing that's supported by clients. See the comments
// at the caller of this.
func vpcName(n string) string {
_, name, ok := strings.Cut(n, "-vpc")
if !ok || name == "" {
return "default"
}
return name
}
// probeMesh returs a probe class that sends a test packet through a pair of DERP
// servers (or just one server, if 'from' and 'to' are the same). 'from' and 'to'
// are expected to be names (DERPNode.Name) of two DERP servers in the same region.

View File

@ -21,7 +21,7 @@
"tailscale.com/types/key"
)
func TestDerpProber(t *testing.T) {
func TestDERPProber(t *testing.T) {
dm := &tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
0: {
@ -210,3 +210,19 @@ func Test_packetsForSize(t *testing.T) {
})
}
}
func TestInSameVPC(t *testing.T) {
tests := []struct {
a, b string
want bool
}{
{"foo", "bar", true},
{"foo-vpc1", "bar-vpc1", true},
{"foo-vpc1", "bar-vpc2", false},
}
for _, tt := range tests {
if got := inSameVPC(&tailcfg.DERPNode{Name: tt.a}, &tailcfg.DERPNode{Name: tt.b}); got != tt.want {
t.Errorf("inSameVPC(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
}
}
}