summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Dunham <andrew@du.nham.ca>2025-02-11 16:34:20 -0500
committerAndrew Dunham <andrew@du.nham.ca>2025-02-11 16:34:20 -0500
commitbb8b22ff4fb9ce63b74b161de8fb991b5f40a9a3 (patch)
tree00822aae85c9d0d99d54e36b19a688b16390f679
parentbc0cd512ee112d31643ad9e326099e92139aa301 (diff)
downloadtailscale-andrew/wgengine-filter-split.tar.xz
tailscale-andrew/wgengine-filter-split.zip
wgengine/filter: add single-item version of MatchesFromFilterRulesandrew/wgengine-filter-split
In the other repo, we have a few cases where we call MatchesFromFilterRules with a single tailcfg.FilterRule. Rather than allocating a slice and then looping over the single-item slice, split the internal logic out to a function that takes a single FilterRule so we can use that. Updates tailscale/corp#26353 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I95f2a7ee9de130712497259941264f06f3d00777
-rw-r--r--wgengine/filter/tailcfg.go154
1 files changed, 84 insertions, 70 deletions
diff --git a/wgengine/filter/tailcfg.go b/wgengine/filter/tailcfg.go
index ff81077f7..d6f42c65e 100644
--- a/wgengine/filter/tailcfg.go
+++ b/wgengine/filter/tailcfg.go
@@ -31,89 +31,103 @@ var defaultProtosView = views.SliceOf(defaultProtos)
func MatchesFromFilterRules(pf []tailcfg.FilterRule) ([]Match, error) {
mm := make([]Match, 0, len(pf))
var erracc error
-
for _, r := range pf {
- if len(r.SrcBits) > 0 {
- return nil, fmt.Errorf("unexpected SrcBits; control plane should not send this to this client version")
- }
- // Profiling determined that this function was spending a lot
- // of time in runtime.growslice. As such, we attempt to
- // pre-allocate some slices. Multipliers were chosen arbitrarily.
- m := Match{
- Srcs: make([]netip.Prefix, 0, len(r.SrcIPs)),
- Dsts: make([]NetPortRange, 0, 2*len(r.DstPorts)),
- Caps: make([]CapMatch, 0, 3*len(r.CapGrant)),
+ m, err := MatchFromFilterRule(r)
+ if err != nil && erracc == nil {
+ erracc = err
}
+ mm = append(mm, m)
+ }
+ return mm, erracc
+}
- if len(r.IPProto) == 0 {
- m.IPProto = defaultProtosView
- } else {
- filtered := make([]ipproto.Proto, 0, len(r.IPProto))
- for _, n := range r.IPProto {
- if n >= 0 && n <= 0xff {
- filtered = append(filtered, ipproto.Proto(n))
- }
+// MatchFromFilterRule converts a single tailcfg FilterRule into a Match.
+//
+// If an error is returned, the Match result is still valid, containing the
+// portions of the rule that were successfully converted.
+func MatchFromFilterRule(r tailcfg.FilterRule) (m Match, retErr error) {
+ if len(r.SrcBits) > 0 {
+ var zero Match
+ return zero, fmt.Errorf("unexpected SrcBits; control plane should not send this to this client version")
+ }
+
+ // Profiling determined that this function was spending a lot
+ // of time in runtime.growslice. As such, we attempt to
+ // pre-allocate some slices. Multipliers were chosen arbitrarily.
+ m = Match{
+ Srcs: make([]netip.Prefix, 0, len(r.SrcIPs)),
+ Dsts: make([]NetPortRange, 0, 2*len(r.DstPorts)),
+ Caps: make([]CapMatch, 0, 3*len(r.CapGrant)),
+ }
+
+ if len(r.IPProto) == 0 {
+ m.IPProto = defaultProtosView
+ } else {
+ filtered := make([]ipproto.Proto, 0, len(r.IPProto))
+ for _, n := range r.IPProto {
+ if n >= 0 && n <= 0xff {
+ filtered = append(filtered, ipproto.Proto(n))
}
- m.IPProto = views.SliceOf(filtered)
}
+ m.IPProto = views.SliceOf(filtered)
+ }
- for _, s := range r.SrcIPs {
- nets, cap, err := parseIPSet(s)
- if err != nil && erracc == nil {
- erracc = err
- continue
- }
- m.Srcs = append(m.Srcs, nets...)
- if cap != "" {
- m.SrcCaps = append(m.SrcCaps, cap)
- }
+ for _, s := range r.SrcIPs {
+ nets, cap, err := parseIPSet(s)
+ if err != nil && retErr == nil {
+ retErr = err
+ continue
+ }
+ m.Srcs = append(m.Srcs, nets...)
+ if cap != "" {
+ m.SrcCaps = append(m.SrcCaps, cap)
}
- m.SrcsContains = ipset.NewContainsIPFunc(views.SliceOf(m.Srcs))
+ }
+ m.SrcsContains = ipset.NewContainsIPFunc(views.SliceOf(m.Srcs))
- for _, d := range r.DstPorts {
- if d.Bits != nil {
- return nil, fmt.Errorf("unexpected DstBits; control plane should not send this to this client version")
- }
- nets, cap, err := parseIPSet(d.IP)
- if err != nil && erracc == nil {
- erracc = err
- continue
- }
- if cap != "" {
- erracc = fmt.Errorf("unexpected capability %q in DstPorts", cap)
- continue
- }
- for _, net := range nets {
- m.Dsts = append(m.Dsts, NetPortRange{
- Net: net,
- Ports: PortRange{
- First: d.Ports.First,
- Last: d.Ports.Last,
- },
+ for _, d := range r.DstPorts {
+ if d.Bits != nil {
+ var zero Match
+ return zero, fmt.Errorf("unexpected DstBits; control plane should not send this to this client version")
+ }
+ nets, cap, err := parseIPSet(d.IP)
+ if err != nil && retErr == nil {
+ retErr = err
+ continue
+ }
+ if cap != "" {
+ retErr = fmt.Errorf("unexpected capability %q in DstPorts", cap)
+ continue
+ }
+ for _, net := range nets {
+ m.Dsts = append(m.Dsts, NetPortRange{
+ Net: net,
+ Ports: PortRange{
+ First: d.Ports.First,
+ Last: d.Ports.Last,
+ },
+ })
+ }
+ }
+ for _, cm := range r.CapGrant {
+ for _, dstNet := range cm.Dsts {
+ for _, cap := range cm.Caps {
+ m.Caps = append(m.Caps, CapMatch{
+ Dst: dstNet,
+ Cap: cap,
})
}
- }
- for _, cm := range r.CapGrant {
- for _, dstNet := range cm.Dsts {
- for _, cap := range cm.Caps {
- m.Caps = append(m.Caps, CapMatch{
- Dst: dstNet,
- Cap: cap,
- })
- }
- for cap, val := range cm.CapMap {
- m.Caps = append(m.Caps, CapMatch{
- Dst: dstNet,
- Cap: tailcfg.PeerCapability(cap),
- Values: val,
- })
- }
+ for cap, val := range cm.CapMap {
+ m.Caps = append(m.Caps, CapMatch{
+ Dst: dstNet,
+ Cap: tailcfg.PeerCapability(cap),
+ Values: val,
+ })
}
}
-
- mm = append(mm, m)
}
- return mm, erracc
+
+ return m, retErr
}
var (