mirror of
https://github.com/golang/go
synced 2024-11-25 22:28:02 -07:00
a295890c5c
As net package has one of the biggest init time in standard library, I have tried to improve performance by doing two things in net/addrselect.go: 1. Precompute slice with RFC rules. Currently the rules are computed and sorted in init() function. We could save the time and allocations by using prepopulated values in sorted manner. The rules haven't changed since 2015. To be extra safe we could move order validation as test case. It should slightly speed up startup of each binary with "net" package and go dns resolver. It also saves 38 allocations, ~50% of allocations in init phase of `net` module. 2. Replace internal net.IP usage with netip.Addr in `sortByRFC6724` function. It results in ~40% performance improvement on samples from tests. The only risk is the difference between net.IP and netip.Addr behaviour. Init benchmark: Init-8 1.89µs ± 2% 0.12µs ± 3% -93.79% (p=0.000 n=5+5) name old alloc/op new alloc/op delta Init-8 1.05kB ± 0% 0.38kB ± 0% ~ (zero variance) name old allocs/op new allocs/op delta Init-8 39.0 ± 0% 1.0 ± 0% ~ (zero variance) Whole sortByRFC6724 function benchmark: name old time/op new time/op delta SortByRFC6724/0-8 463ns ± 3% 303ns ± 4% -34.72% (p=0.000 n=5+5) SortByRFC6724/1-8 481ns ± 8% 306ns ± 1% -36.46% (p=0.000 n=5+5) SortByRFC6724/2-8 470ns ± 4% 307ns ± 4% -34.77% (p=0.000 n=5+5) SortByRFC6724/3-8 567ns ± 3% 367ns ± 3% -35.28% (p=0.000 n=5+5) SortByRFC6724/4-8 918ns ± 3% 560ns ± 2% -38.93% (p=0.000 n=5+5) Updates #54032 Change-Id: Ic18df1ea73805cb184c6ceb73470ca7f0b922032 Reviewed-on: https://go-review.googlesource.com/c/go/+/419356 Reviewed-by: Heschi Kreinick <heschi@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Damien Neil <dneil@google.com> Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
313 lines
8.5 KiB
Go
313 lines
8.5 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
|
|
|
package net
|
|
|
|
import (
|
|
"net/netip"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestSortByRFC6724(t *testing.T) {
|
|
tests := []struct {
|
|
in []IPAddr
|
|
srcs []netip.Addr
|
|
want []IPAddr
|
|
reverse bool // also test it starting backwards
|
|
}{
|
|
// Examples from RFC 6724 section 10.2:
|
|
|
|
// Prefer matching scope.
|
|
{
|
|
in: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("198.51.100.121")},
|
|
},
|
|
srcs: []netip.Addr{
|
|
netip.MustParseAddr("2001:db8:1::2"),
|
|
netip.MustParseAddr("169.254.13.78"),
|
|
},
|
|
want: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("198.51.100.121")},
|
|
},
|
|
reverse: true,
|
|
},
|
|
|
|
// Prefer matching scope.
|
|
{
|
|
in: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("198.51.100.121")},
|
|
},
|
|
srcs: []netip.Addr{
|
|
netip.MustParseAddr("fe80::1"),
|
|
netip.MustParseAddr("198.51.100.117"),
|
|
},
|
|
want: []IPAddr{
|
|
{IP: ParseIP("198.51.100.121")},
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
},
|
|
reverse: true,
|
|
},
|
|
|
|
// Prefer higher precedence.
|
|
{
|
|
in: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("10.1.2.3")},
|
|
},
|
|
srcs: []netip.Addr{
|
|
netip.MustParseAddr("2001:db8:1::2"),
|
|
netip.MustParseAddr("10.1.2.4"),
|
|
},
|
|
want: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("10.1.2.3")},
|
|
},
|
|
reverse: true,
|
|
},
|
|
|
|
// Prefer smaller scope.
|
|
{
|
|
in: []IPAddr{
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
{IP: ParseIP("fe80::1")},
|
|
},
|
|
srcs: []netip.Addr{
|
|
netip.MustParseAddr("2001:db8:1::2"),
|
|
netip.MustParseAddr("fe80::2"),
|
|
},
|
|
want: []IPAddr{
|
|
{IP: ParseIP("fe80::1")},
|
|
{IP: ParseIP("2001:db8:1::1")},
|
|
},
|
|
reverse: true,
|
|
},
|
|
|
|
// Issue 13283. Having a 10/8 source address does not
|
|
// mean we should prefer 23/8 destination addresses.
|
|
{
|
|
in: []IPAddr{
|
|
{IP: ParseIP("54.83.193.112")},
|
|
{IP: ParseIP("184.72.238.214")},
|
|
{IP: ParseIP("23.23.172.185")},
|
|
{IP: ParseIP("75.101.148.21")},
|
|
{IP: ParseIP("23.23.134.56")},
|
|
{IP: ParseIP("23.21.50.150")},
|
|
},
|
|
srcs: []netip.Addr{
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
netip.MustParseAddr("10.2.3.4"),
|
|
},
|
|
want: []IPAddr{
|
|
{IP: ParseIP("54.83.193.112")},
|
|
{IP: ParseIP("184.72.238.214")},
|
|
{IP: ParseIP("23.23.172.185")},
|
|
{IP: ParseIP("75.101.148.21")},
|
|
{IP: ParseIP("23.23.134.56")},
|
|
{IP: ParseIP("23.21.50.150")},
|
|
},
|
|
reverse: false,
|
|
},
|
|
}
|
|
for i, tt := range tests {
|
|
inCopy := make([]IPAddr, len(tt.in))
|
|
copy(inCopy, tt.in)
|
|
srcCopy := make([]netip.Addr, len(tt.in))
|
|
copy(srcCopy, tt.srcs)
|
|
sortByRFC6724withSrcs(inCopy, srcCopy)
|
|
if !reflect.DeepEqual(inCopy, tt.want) {
|
|
t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
|
|
}
|
|
if tt.reverse {
|
|
copy(inCopy, tt.in)
|
|
copy(srcCopy, tt.srcs)
|
|
for j := 0; j < len(inCopy)/2; j++ {
|
|
k := len(inCopy) - j - 1
|
|
inCopy[j], inCopy[k] = inCopy[k], inCopy[j]
|
|
srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j]
|
|
}
|
|
sortByRFC6724withSrcs(inCopy, srcCopy)
|
|
if !reflect.DeepEqual(inCopy, tt.want) {
|
|
t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestRFC6724PolicyTableOrder(t *testing.T) {
|
|
for i := 0; i < len(rfc6724policyTable)-1; i++ {
|
|
if !(rfc6724policyTable[i].Prefix.Bits() >= rfc6724policyTable[i+1].Prefix.Bits()) {
|
|
t.Errorf("rfc6724policyTable item number %d sorted in wrong order = %d bits, next item = %d bits;", i, rfc6724policyTable[i].Prefix.Bits(), rfc6724policyTable[i+1].Prefix.Bits())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRFC6724PolicyTableContent(t *testing.T) {
|
|
expectedRfc6724policyTable := policyTable{
|
|
{
|
|
Prefix: netip.MustParsePrefix("::1/128"),
|
|
Precedence: 50,
|
|
Label: 0,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("::ffff:0:0/96"),
|
|
Precedence: 35,
|
|
Label: 4,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("::/96"),
|
|
Precedence: 1,
|
|
Label: 3,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("2001::/32"),
|
|
Precedence: 5,
|
|
Label: 5,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("2002::/16"),
|
|
Precedence: 30,
|
|
Label: 2,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("3ffe::/16"),
|
|
Precedence: 1,
|
|
Label: 12,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("fec0::/10"),
|
|
Precedence: 1,
|
|
Label: 11,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("fc00::/7"),
|
|
Precedence: 3,
|
|
Label: 13,
|
|
},
|
|
{
|
|
Prefix: netip.MustParsePrefix("::/0"),
|
|
Precedence: 40,
|
|
Label: 1,
|
|
},
|
|
}
|
|
if !reflect.DeepEqual(rfc6724policyTable, expectedRfc6724policyTable) {
|
|
t.Errorf("rfc6724policyTable has wrong contend = %v; want %v", rfc6724policyTable, expectedRfc6724policyTable)
|
|
}
|
|
}
|
|
|
|
func TestRFC6724PolicyTableClassify(t *testing.T) {
|
|
tests := []struct {
|
|
ip netip.Addr
|
|
want policyTableEntry
|
|
}{
|
|
{
|
|
ip: netip.MustParseAddr("127.0.0.1"),
|
|
want: policyTableEntry{
|
|
Prefix: netip.MustParsePrefix("::ffff:0:0/96"),
|
|
Precedence: 35,
|
|
Label: 4,
|
|
},
|
|
},
|
|
{
|
|
ip: netip.MustParseAddr("2601:645:8002:a500:986f:1db8:c836:bd65"),
|
|
want: policyTableEntry{
|
|
Prefix: netip.MustParsePrefix("::/0"),
|
|
Precedence: 40,
|
|
Label: 1,
|
|
},
|
|
},
|
|
{
|
|
ip: netip.MustParseAddr("::1"),
|
|
want: policyTableEntry{
|
|
Prefix: netip.MustParsePrefix("::1/128"),
|
|
Precedence: 50,
|
|
Label: 0,
|
|
},
|
|
},
|
|
{
|
|
ip: netip.MustParseAddr("2002::ab12"),
|
|
want: policyTableEntry{
|
|
Prefix: netip.MustParsePrefix("2002::/16"),
|
|
Precedence: 30,
|
|
Label: 2,
|
|
},
|
|
},
|
|
}
|
|
for i, tt := range tests {
|
|
got := rfc6724policyTable.Classify(tt.ip)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRFC6724ClassifyScope(t *testing.T) {
|
|
tests := []struct {
|
|
ip netip.Addr
|
|
want scope
|
|
}{
|
|
{netip.MustParseAddr("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2
|
|
{netip.MustParseAddr("::1"), scopeLinkLocal}, // rfc4007#section-4
|
|
{netip.MustParseAddr("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
|
|
{netip.MustParseAddr("fec0::1"), scopeSiteLocal},
|
|
{netip.MustParseAddr("8.8.8.8"), scopeGlobal},
|
|
|
|
{netip.MustParseAddr("ff02::"), scopeLinkLocal}, // IPv6 multicast
|
|
{netip.MustParseAddr("ff05::"), scopeSiteLocal}, // IPv6 multicast
|
|
{netip.MustParseAddr("ff04::"), scopeAdminLocal}, // IPv6 multicast
|
|
{netip.MustParseAddr("ff0e::"), scopeGlobal}, // IPv6 multicast
|
|
|
|
{netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 0, 0, 0}), scopeGlobal}, // IPv4 link-local multicast as 16 bytes
|
|
{netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 2, 2, 2}), scopeGlobal}, // IPv4 global multicast as 16 bytes
|
|
{netip.AddrFrom4([4]byte{0xe0, 0, 0, 0}), scopeGlobal}, // IPv4 link-local multicast as 4 bytes
|
|
{netip.AddrFrom4([4]byte{0xe0, 2, 2, 2}), scopeGlobal}, // IPv4 global multicast as 4 bytes
|
|
}
|
|
for i, tt := range tests {
|
|
got := classifyScope(tt.ip)
|
|
if got != tt.want {
|
|
t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRFC6724CommonPrefixLength(t *testing.T) {
|
|
tests := []struct {
|
|
a netip.Addr
|
|
b IP
|
|
want int
|
|
}{
|
|
{netip.MustParseAddr("fe80::1"), ParseIP("fe80::2"), 64},
|
|
{netip.MustParseAddr("fe81::1"), ParseIP("fe80::2"), 15},
|
|
{netip.MustParseAddr("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
|
|
{netip.AddrFrom4([4]byte{1, 2, 3, 4}), IP{1, 2, 3, 4}, 32},
|
|
{netip.AddrFrom4([4]byte{1, 2, 255, 255}), IP{1, 2, 0, 0}, 16},
|
|
{netip.AddrFrom4([4]byte{1, 2, 127, 255}), IP{1, 2, 0, 0}, 17},
|
|
{netip.AddrFrom4([4]byte{1, 2, 63, 255}), IP{1, 2, 0, 0}, 18},
|
|
{netip.AddrFrom4([4]byte{1, 2, 31, 255}), IP{1, 2, 0, 0}, 19},
|
|
{netip.AddrFrom4([4]byte{1, 2, 15, 255}), IP{1, 2, 0, 0}, 20},
|
|
{netip.AddrFrom4([4]byte{1, 2, 7, 255}), IP{1, 2, 0, 0}, 21},
|
|
{netip.AddrFrom4([4]byte{1, 2, 3, 255}), IP{1, 2, 0, 0}, 22},
|
|
{netip.AddrFrom4([4]byte{1, 2, 1, 255}), IP{1, 2, 0, 0}, 23},
|
|
{netip.AddrFrom4([4]byte{1, 2, 0, 255}), IP{1, 2, 0, 0}, 24},
|
|
}
|
|
for i, tt := range tests {
|
|
got := commonPrefixLen(tt.a, tt.b)
|
|
if got != tt.want {
|
|
t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want)
|
|
}
|
|
}
|
|
|
|
}
|