mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
control/controlclient: flesh out mapSession to break up gigantic method
Now mapSession has a bunch more fields and methods, rather than being just one massive func with a ton of local variables. So far there are no major new optimizations, though. It should behave the same as before. This has been done with an eye towards testability (so tests can set all the callback funcs as needed, or not, without a huge Direct client or long-running HTTP requests), but this change doesn't add new tests yet. That will follow in the changes which flesh out the NetmapUpdater interface. Updates #1909 Change-Id: Iad4e7442d5bbbe2614bd4b1dc4b02e27504898df Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
1b223566dd
commit
b5ff68a968
@@ -4,10 +4,13 @@
|
||||
package controlclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -330,8 +333,9 @@ func formatNodes(nodes []*tailcfg.Node) string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func newTestMapSession(t *testing.T) *mapSession {
|
||||
ms := newMapSession(key.NewNode())
|
||||
func newTestMapSession(t testing.TB, nu NetmapUpdater) *mapSession {
|
||||
ms := newMapSession(key.NewNode(), nu)
|
||||
t.Cleanup(ms.Close)
|
||||
ms.logf = t.Logf
|
||||
return ms
|
||||
}
|
||||
@@ -346,7 +350,7 @@ func TestNetmapForResponse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
nm1 := ms.netmapForResponse(&tailcfg.MapResponse{
|
||||
Node: new(tailcfg.Node),
|
||||
PacketFilter: somePacketFilter,
|
||||
@@ -367,7 +371,7 @@ func TestNetmapForResponse(t *testing.T) {
|
||||
})
|
||||
t.Run("implicit_dnsconfig", func(t *testing.T) {
|
||||
someDNSConfig := &tailcfg.DNSConfig{Domains: []string{"foo", "bar"}}
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
nm1 := ms.netmapForResponse(&tailcfg.MapResponse{
|
||||
Node: new(tailcfg.Node),
|
||||
DNSConfig: someDNSConfig,
|
||||
@@ -384,7 +388,7 @@ func TestNetmapForResponse(t *testing.T) {
|
||||
}
|
||||
})
|
||||
t.Run("collect_services", func(t *testing.T) {
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
var nm *netmap.NetworkMap
|
||||
wantCollect := func(v bool) {
|
||||
t.Helper()
|
||||
@@ -417,7 +421,7 @@ func TestNetmapForResponse(t *testing.T) {
|
||||
wantCollect(true)
|
||||
})
|
||||
t.Run("implicit_domain", func(t *testing.T) {
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
var nm *netmap.NetworkMap
|
||||
want := func(v string) {
|
||||
t.Helper()
|
||||
@@ -445,7 +449,7 @@ func TestNetmapForResponse(t *testing.T) {
|
||||
ComputedName: "foo",
|
||||
ComputedNameWithHost: "foo",
|
||||
}
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
mapRes := &tailcfg.MapResponse{
|
||||
Node: someNode,
|
||||
}
|
||||
@@ -564,7 +568,7 @@ func TestDeltaDERPMap(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ms := newTestMapSession(t)
|
||||
ms := newTestMapSession(t, nil)
|
||||
for stepi, s := range tt.steps {
|
||||
nm := ms.netmapForResponse(&tailcfg.MapResponse{DERPMap: s.got})
|
||||
if !reflect.DeepEqual(nm.DERPMap, s.want) {
|
||||
@@ -574,3 +578,64 @@ func TestDeltaDERPMap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type countingNetmapUpdater struct {
|
||||
full atomic.Int64
|
||||
}
|
||||
|
||||
func (nu *countingNetmapUpdater) UpdateFullNetmap(nm *netmap.NetworkMap) {
|
||||
nu.full.Add(1)
|
||||
}
|
||||
|
||||
func BenchmarkMapSessionDelta(b *testing.B) {
|
||||
for _, size := range []int{10, 100, 1_000, 10_000} {
|
||||
b.Run(fmt.Sprintf("size_%d", size), func(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
nu := &countingNetmapUpdater{}
|
||||
ms := newTestMapSession(b, nu)
|
||||
res := &tailcfg.MapResponse{
|
||||
Node: &tailcfg.Node{
|
||||
ID: 1,
|
||||
Name: "foo.bar.ts.net.",
|
||||
},
|
||||
}
|
||||
for i := 0; i < size; i++ {
|
||||
res.Peers = append(res.Peers, &tailcfg.Node{
|
||||
ID: tailcfg.NodeID(i + 2),
|
||||
Name: fmt.Sprintf("peer%d.bar.ts.net.", i),
|
||||
DERP: "127.3.3.40:10",
|
||||
Addresses: []netip.Prefix{netip.MustParsePrefix("100.100.2.3/32"), netip.MustParsePrefix("fd7a:115c:a1e0::123/128")},
|
||||
AllowedIPs: []netip.Prefix{netip.MustParsePrefix("100.100.2.3/32"), netip.MustParsePrefix("fd7a:115c:a1e0::123/128")},
|
||||
Endpoints: []string{"192.168.1.2:345", "192.168.1.3:678"},
|
||||
Hostinfo: (&tailcfg.Hostinfo{
|
||||
OS: "fooOS",
|
||||
Hostname: "MyHostname",
|
||||
Services: []tailcfg.Service{
|
||||
{Proto: "peerapi4", Port: 1234},
|
||||
{Proto: "peerapi6", Port: 1234},
|
||||
{Proto: "peerapi-dns-proxy", Port: 1},
|
||||
},
|
||||
}).View(),
|
||||
LastSeen: ptr.To(time.Unix(int64(i), 0)),
|
||||
})
|
||||
}
|
||||
ms.HandleNonKeepAliveMapResponse(ctx, res)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
// Now for the core of the benchmark loop, just toggle
|
||||
// a single node's online status.
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := ms.HandleNonKeepAliveMapResponse(ctx, &tailcfg.MapResponse{
|
||||
OnlineChange: map[tailcfg.NodeID]bool{
|
||||
2: i%2 == 0,
|
||||
},
|
||||
}); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user