mirror of
https://github.com/juanfont/headscale.git
synced 2026-03-10 15:16:02 +01:00
types: avoid NodeView clone in CanAccess
NodeView.CanAccess called node2.AsStruct() on every check. In peer-map construction we run CanAccess in O(n^2) pair scans (often twice per pair), so that per-call clone multiplied into large heap churn
This commit is contained in:
@@ -800,11 +800,11 @@ func (nv NodeView) InIPSet(set *netipx.IPSet) bool {
|
||||
}
|
||||
|
||||
func (nv NodeView) CanAccess(matchers []matcher.Match, node2 NodeView) bool {
|
||||
if !nv.Valid() {
|
||||
if !nv.Valid() || !node2.Valid() {
|
||||
return false
|
||||
}
|
||||
|
||||
return nv.ж.CanAccess(matchers, node2.AsStruct())
|
||||
return nv.ж.CanAccess(matchers, node2.ж)
|
||||
}
|
||||
|
||||
func (nv NodeView) CanAccessRoute(matchers []matcher.Match, route netip.Prefix) bool {
|
||||
|
||||
73
hscontrol/types/node_benchmark_test.go
Normal file
73
hscontrol/types/node_benchmark_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/juanfont/headscale/hscontrol/policy/matcher"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
|
||||
func BenchmarkNodeViewCanAccess(b *testing.B) {
|
||||
addr := func(ip string) *netip.Addr {
|
||||
parsed := netip.MustParseAddr(ip)
|
||||
return &parsed
|
||||
}
|
||||
|
||||
rules := []tailcfg.FilterRule{
|
||||
{
|
||||
SrcIPs: []string{"100.64.0.1/32"},
|
||||
DstPorts: []tailcfg.NetPortRange{
|
||||
{
|
||||
IP: "100.64.0.2/32",
|
||||
Ports: tailcfg.PortRangeAny,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
matchers := matcher.MatchesFromFilterRules(rules)
|
||||
|
||||
derpLatency := make(map[string]float64, 256)
|
||||
for i := range 128 {
|
||||
derpLatency[fmt.Sprintf("%d-v4", i)] = float64(i) / 10
|
||||
derpLatency[fmt.Sprintf("%d-v6", i)] = float64(i) / 10
|
||||
}
|
||||
|
||||
src := Node{
|
||||
IPv4: addr("100.64.0.1"),
|
||||
}
|
||||
dst := Node{
|
||||
IPv4: addr("100.64.0.2"),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
NetInfo: &tailcfg.NetInfo{
|
||||
DERPLatency: derpLatency,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
srcView := src.View()
|
||||
dstView := dst.View()
|
||||
|
||||
if !srcView.CanAccess(matchers, dstView) {
|
||||
b.Fatal("benchmark setup error: expected source to access destination")
|
||||
}
|
||||
|
||||
b.Run("pointer", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for b.Loop() {
|
||||
srcView.CanAccess(matchers, dstView)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("struct clone", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for b.Loop() {
|
||||
src.CanAccess(matchers, dstView.AsStruct())
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user