mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 22:15:51 +00:00
cb96b14bf4
Upstream netaddr has a change that makes it alloc-free, so it's safe to use in hot codepaths. This gets rid of one of the many IP types in our codebase. Performance is currently worse across the board. This is likely due in part to netaddr.IP being a larger value type (4b -> 24b for IPv4, 16b -> 24b for IPv6), and in other part due to missing low-hanging fruit optimizations in netaddr. However, the regression is less bad than it looks at first glance, because we'd micro-optimized packet.IP* in the past few weeks. This change drops us back to roughly where we were at the 1.2 release, but with the benefit of a significant code and architectural simplification. name old time/op new time/op delta pkg:tailscale.com/net/packet goos:linux goarch:amd64 Decode/tcp4-8 12.2ns ± 5% 29.7ns ± 2% +142.32% (p=0.008 n=5+5) Decode/tcp6-8 12.6ns ± 3% 65.1ns ± 2% +418.47% (p=0.008 n=5+5) Decode/udp4-8 11.8ns ± 3% 30.5ns ± 2% +157.94% (p=0.008 n=5+5) Decode/udp6-8 27.1ns ± 1% 65.7ns ± 2% +142.36% (p=0.016 n=4+5) Decode/icmp4-8 24.6ns ± 2% 30.5ns ± 2% +23.65% (p=0.016 n=4+5) Decode/icmp6-8 22.9ns ±51% 65.5ns ± 2% +186.19% (p=0.008 n=5+5) Decode/igmp-8 18.1ns ±44% 30.2ns ± 1% +66.89% (p=0.008 n=5+5) Decode/unknown-8 20.8ns ± 1% 10.6ns ± 9% -49.11% (p=0.016 n=4+5) pkg:tailscale.com/wgengine/filter goos:linux goarch:amd64 Filter/icmp4-8 30.5ns ± 1% 77.9ns ± 3% +155.01% (p=0.008 n=5+5) Filter/tcp4_syn_in-8 43.7ns ± 3% 123.0ns ± 3% +181.72% (p=0.008 n=5+5) Filter/tcp4_syn_out-8 24.5ns ± 2% 45.7ns ± 6% +86.22% (p=0.008 n=5+5) Filter/udp4_in-8 64.8ns ± 1% 210.0ns ± 2% +223.87% (p=0.008 n=5+5) Filter/udp4_out-8 119ns ± 0% 278ns ± 0% +133.78% (p=0.016 n=4+5) Filter/icmp6-8 40.3ns ± 2% 204.4ns ± 4% +407.70% (p=0.008 n=5+5) Filter/tcp6_syn_in-8 35.3ns ± 3% 199.2ns ± 2% +464.95% (p=0.008 n=5+5) Filter/tcp6_syn_out-8 32.8ns ± 2% 81.0ns ± 2% +147.10% (p=0.008 n=5+5) Filter/udp6_in-8 106ns ± 2% 290ns ± 2% +174.48% (p=0.008 n=5+5) Filter/udp6_out-8 184ns ± 2% 314ns ± 3% +70.43% (p=0.016 n=4+5) pkg:tailscale.com/wgengine/tstun goos:linux goarch:amd64 Write-8 9.02ns ± 3% 8.92ns ± 1% ~ (p=0.421 n=5+5) name old alloc/op new alloc/op delta pkg:tailscale.com/net/packet goos:linux goarch:amd64 Decode/tcp4-8 0.00B 0.00B ~ (all equal) Decode/tcp6-8 0.00B 0.00B ~ (all equal) Decode/udp4-8 0.00B 0.00B ~ (all equal) Decode/udp6-8 0.00B 0.00B ~ (all equal) Decode/icmp4-8 0.00B 0.00B ~ (all equal) Decode/icmp6-8 0.00B 0.00B ~ (all equal) Decode/igmp-8 0.00B 0.00B ~ (all equal) Decode/unknown-8 0.00B 0.00B ~ (all equal) pkg:tailscale.com/wgengine/filter goos:linux goarch:amd64 Filter/icmp4-8 0.00B 0.00B ~ (all equal) Filter/tcp4_syn_in-8 0.00B 0.00B ~ (all equal) Filter/tcp4_syn_out-8 0.00B 0.00B ~ (all equal) Filter/udp4_in-8 0.00B 0.00B ~ (all equal) Filter/udp4_out-8 16.0B ± 0% 64.0B ± 0% +300.00% (p=0.008 n=5+5) Filter/icmp6-8 0.00B 0.00B ~ (all equal) Filter/tcp6_syn_in-8 0.00B 0.00B ~ (all equal) Filter/tcp6_syn_out-8 0.00B 0.00B ~ (all equal) Filter/udp6_in-8 0.00B 0.00B ~ (all equal) Filter/udp6_out-8 48.0B ± 0% 64.0B ± 0% +33.33% (p=0.008 n=5+5) name old allocs/op new allocs/op delta pkg:tailscale.com/net/packet goos:linux goarch:amd64 Decode/tcp4-8 0.00 0.00 ~ (all equal) Decode/tcp6-8 0.00 0.00 ~ (all equal) Decode/udp4-8 0.00 0.00 ~ (all equal) Decode/udp6-8 0.00 0.00 ~ (all equal) Decode/icmp4-8 0.00 0.00 ~ (all equal) Decode/icmp6-8 0.00 0.00 ~ (all equal) Decode/igmp-8 0.00 0.00 ~ (all equal) Decode/unknown-8 0.00 0.00 ~ (all equal) pkg:tailscale.com/wgengine/filter goos:linux goarch:amd64 Filter/icmp4-8 0.00 0.00 ~ (all equal) Filter/tcp4_syn_in-8 0.00 0.00 ~ (all equal) Filter/tcp4_syn_out-8 0.00 0.00 ~ (all equal) Filter/udp4_in-8 0.00 0.00 ~ (all equal) Filter/udp4_out-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Filter/icmp6-8 0.00 0.00 ~ (all equal) Filter/tcp6_syn_in-8 0.00 0.00 ~ (all equal) Filter/tcp6_syn_out-8 0.00 0.00 ~ (all equal) Filter/udp6_in-8 0.00 0.00 ~ (all equal) Filter/udp6_out-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Signed-off-by: David Anderson <danderson@tailscale.com>
118 lines
2.2 KiB
Go
118 lines
2.2 KiB
Go
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package filter
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"inet.af/netaddr"
|
|
"tailscale.com/net/packet"
|
|
)
|
|
|
|
// PortRange is a range of TCP and UDP ports.
|
|
type PortRange struct {
|
|
First, Last uint16 // inclusive
|
|
}
|
|
|
|
func (pr PortRange) String() string {
|
|
if pr.First == 0 && pr.Last == 65535 {
|
|
return "*"
|
|
} else if pr.First == pr.Last {
|
|
return fmt.Sprintf("%d", pr.First)
|
|
} else {
|
|
return fmt.Sprintf("%d-%d", pr.First, pr.Last)
|
|
}
|
|
}
|
|
|
|
// contains returns whether port is in pr.
|
|
func (pr PortRange) contains(port uint16) bool {
|
|
return port >= pr.First && port <= pr.Last
|
|
}
|
|
|
|
// NetPortRange combines an IP address prefix and PortRange.
|
|
type NetPortRange struct {
|
|
Net netaddr.IPPrefix
|
|
Ports PortRange
|
|
}
|
|
|
|
func (npr NetPortRange) String() string {
|
|
return fmt.Sprintf("%v:%v", npr.Net, npr.Ports)
|
|
}
|
|
|
|
// Match matches packets from any IP address in Srcs to any ip:port in
|
|
// Dsts.
|
|
type Match struct {
|
|
Dsts []NetPortRange
|
|
Srcs []netaddr.IPPrefix
|
|
}
|
|
|
|
func (m Match) String() string {
|
|
srcs := []string{}
|
|
for _, src := range m.Srcs {
|
|
srcs = append(srcs, src.String())
|
|
}
|
|
dsts := []string{}
|
|
for _, dst := range m.Dsts {
|
|
dsts = append(dsts, dst.String())
|
|
}
|
|
|
|
var ss, ds string
|
|
if len(srcs) == 1 {
|
|
ss = srcs[0]
|
|
} else {
|
|
ss = "[" + strings.Join(srcs, ",") + "]"
|
|
}
|
|
if len(dsts) == 1 {
|
|
ds = dsts[0]
|
|
} else {
|
|
ds = "[" + strings.Join(dsts, ",") + "]"
|
|
}
|
|
return fmt.Sprintf("%v=>%v", ss, ds)
|
|
}
|
|
|
|
type matches []Match
|
|
|
|
func (ms matches) match(q *packet.Parsed) bool {
|
|
for _, m := range ms {
|
|
if !ipInList(q.Src.IP, m.Srcs) {
|
|
continue
|
|
}
|
|
for _, dst := range m.Dsts {
|
|
if !dst.Net.Contains(q.Dst.IP) {
|
|
continue
|
|
}
|
|
if !dst.Ports.contains(q.Dst.Port) {
|
|
continue
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (ms matches) matchIPsOnly(q *packet.Parsed) bool {
|
|
for _, m := range ms {
|
|
if !ipInList(q.Src.IP, m.Srcs) {
|
|
continue
|
|
}
|
|
for _, dst := range m.Dsts {
|
|
if dst.Net.Contains(q.Dst.IP) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func ipInList(ip netaddr.IP, netlist []netaddr.IPPrefix) bool {
|
|
for _, net := range netlist {
|
|
if net.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|