mirror of https://github.com/golang/go.git
net: precompute rfc6724policyTable in addrselect
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>
This commit is contained in:
parent
3fbcf05d40
commit
a295890c5c
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
package net
|
||||
|
||||
import "sort"
|
||||
import (
|
||||
"net/netip"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func sortByRFC6724(addrs []IPAddr) {
|
||||
if len(addrs) < 2 {
|
||||
|
|
@ -15,14 +18,15 @@ func sortByRFC6724(addrs []IPAddr) {
|
|||
sortByRFC6724withSrcs(addrs, srcAddrs(addrs))
|
||||
}
|
||||
|
||||
func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
|
||||
func sortByRFC6724withSrcs(addrs []IPAddr, srcs []netip.Addr) {
|
||||
if len(addrs) != len(srcs) {
|
||||
panic("internal error")
|
||||
}
|
||||
addrAttr := make([]ipAttr, len(addrs))
|
||||
srcAttr := make([]ipAttr, len(srcs))
|
||||
for i, v := range addrs {
|
||||
addrAttr[i] = ipAttrOf(v.IP)
|
||||
addrAttrIP, _ := netip.AddrFromSlice(v.IP)
|
||||
addrAttr[i] = ipAttrOf(addrAttrIP)
|
||||
srcAttr[i] = ipAttrOf(srcs[i])
|
||||
}
|
||||
sort.Stable(&byRFC6724{
|
||||
|
|
@ -36,8 +40,8 @@ func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
|
|||
// srcsAddrs tries to UDP-connect to each address to see if it has a
|
||||
// route. (This doesn't send any packets). The destination port
|
||||
// number is irrelevant.
|
||||
func srcAddrs(addrs []IPAddr) []IP {
|
||||
srcs := make([]IP, len(addrs))
|
||||
func srcAddrs(addrs []IPAddr) []netip.Addr {
|
||||
srcs := make([]netip.Addr, len(addrs))
|
||||
dst := UDPAddr{Port: 9}
|
||||
for i := range addrs {
|
||||
dst.IP = addrs[i].IP
|
||||
|
|
@ -45,7 +49,7 @@ func srcAddrs(addrs []IPAddr) []IP {
|
|||
c, err := DialUDP("udp", nil, &dst)
|
||||
if err == nil {
|
||||
if src, ok := c.LocalAddr().(*UDPAddr); ok {
|
||||
srcs[i] = src.IP
|
||||
srcs[i], _ = netip.AddrFromSlice(src.IP)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
|
@ -59,8 +63,8 @@ type ipAttr struct {
|
|||
Label uint8
|
||||
}
|
||||
|
||||
func ipAttrOf(ip IP) ipAttr {
|
||||
if ip == nil {
|
||||
func ipAttrOf(ip netip.Addr) ipAttr {
|
||||
if !ip.IsValid() {
|
||||
return ipAttr{}
|
||||
}
|
||||
match := rfc6724policyTable.Classify(ip)
|
||||
|
|
@ -74,7 +78,7 @@ func ipAttrOf(ip IP) ipAttr {
|
|||
type byRFC6724 struct {
|
||||
addrs []IPAddr // addrs to sort
|
||||
addrAttr []ipAttr
|
||||
srcs []IP // or nil if unreachable
|
||||
srcs []netip.Addr // or not valid addr if unreachable
|
||||
srcAttr []ipAttr
|
||||
}
|
||||
|
||||
|
|
@ -108,13 +112,13 @@ func (s *byRFC6724) Less(i, j int) bool {
|
|||
// If DB is known to be unreachable or if Source(DB) is undefined, then
|
||||
// prefer DA. Similarly, if DA is known to be unreachable or if
|
||||
// Source(DA) is undefined, then prefer DB.
|
||||
if SourceDA == nil && SourceDB == nil {
|
||||
if !SourceDA.IsValid() && !SourceDB.IsValid() {
|
||||
return false // "equal"
|
||||
}
|
||||
if SourceDB == nil {
|
||||
if !SourceDB.IsValid() {
|
||||
return preferDA
|
||||
}
|
||||
if SourceDA == nil {
|
||||
if !SourceDA.IsValid() {
|
||||
return preferDB
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +188,7 @@ func (s *byRFC6724) Less(i, j int) bool {
|
|||
return preferDB
|
||||
}
|
||||
|
||||
// Rule 9: Use longest matching prefix.
|
||||
// Rule 9: Use the longest matching prefix.
|
||||
// When DA and DB belong to the same address family (both are IPv6 or
|
||||
// both are IPv4 [but see below]): If CommonPrefixLen(Source(DA), DA) >
|
||||
// CommonPrefixLen(Source(DB), DB), then prefer DA. Similarly, if
|
||||
|
|
@ -212,7 +216,7 @@ func (s *byRFC6724) Less(i, j int) bool {
|
|||
}
|
||||
|
||||
type policyTableEntry struct {
|
||||
Prefix *IPNet
|
||||
Prefix netip.Prefix
|
||||
Precedence uint8
|
||||
Label uint8
|
||||
}
|
||||
|
|
@ -220,90 +224,75 @@ type policyTableEntry struct {
|
|||
type policyTable []policyTableEntry
|
||||
|
||||
// RFC 6724 section 2.1.
|
||||
// Items are sorted by the size of their Prefix.Mask.Size,
|
||||
var rfc6724policyTable = policyTable{
|
||||
{
|
||||
Prefix: mustCIDR("::1/128"),
|
||||
// "::1/128"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}), 128),
|
||||
Precedence: 50,
|
||||
Label: 0,
|
||||
},
|
||||
{
|
||||
Prefix: mustCIDR("::/0"),
|
||||
Precedence: 40,
|
||||
Label: 1,
|
||||
},
|
||||
{
|
||||
// "::ffff:0:0/96"
|
||||
// IPv4-compatible, etc.
|
||||
Prefix: mustCIDR("::ffff:0:0/96"),
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}), 96),
|
||||
Precedence: 35,
|
||||
Label: 4,
|
||||
},
|
||||
{
|
||||
// 6to4
|
||||
Prefix: mustCIDR("2002::/16"),
|
||||
Precedence: 30,
|
||||
Label: 2,
|
||||
},
|
||||
{
|
||||
// Teredo
|
||||
Prefix: mustCIDR("2001::/32"),
|
||||
Precedence: 5,
|
||||
Label: 5,
|
||||
},
|
||||
{
|
||||
Prefix: mustCIDR("fc00::/7"),
|
||||
Precedence: 3,
|
||||
Label: 13,
|
||||
},
|
||||
{
|
||||
Prefix: mustCIDR("::/96"),
|
||||
// "::/96"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 96),
|
||||
Precedence: 1,
|
||||
Label: 3,
|
||||
},
|
||||
{
|
||||
Prefix: mustCIDR("fec0::/10"),
|
||||
// "2001::/32"
|
||||
// Teredo
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x01}), 32),
|
||||
Precedence: 5,
|
||||
Label: 5,
|
||||
},
|
||||
{
|
||||
// "2002::/16"
|
||||
// 6to4
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x02}), 16),
|
||||
Precedence: 30,
|
||||
Label: 2,
|
||||
},
|
||||
{
|
||||
// "3ffe::/16"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x3f, 0xfe}), 16),
|
||||
Precedence: 1,
|
||||
Label: 12,
|
||||
},
|
||||
{
|
||||
// "fec0::/10"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfe, 0xc0}), 10),
|
||||
Precedence: 1,
|
||||
Label: 11,
|
||||
},
|
||||
{
|
||||
Prefix: mustCIDR("3ffe::/16"),
|
||||
Precedence: 1,
|
||||
Label: 12,
|
||||
// "fc00::/7"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfc}), 7),
|
||||
Precedence: 3,
|
||||
Label: 13,
|
||||
},
|
||||
{
|
||||
// "::/0"
|
||||
Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0),
|
||||
Precedence: 40,
|
||||
Label: 1,
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable)))
|
||||
}
|
||||
|
||||
// byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size,
|
||||
// from smallest mask, to largest.
|
||||
type byMaskLength []policyTableEntry
|
||||
|
||||
func (s byMaskLength) Len() int { return len(s) }
|
||||
func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byMaskLength) Less(i, j int) bool {
|
||||
isize, _ := s[i].Prefix.Mask.Size()
|
||||
jsize, _ := s[j].Prefix.Mask.Size()
|
||||
return isize < jsize
|
||||
}
|
||||
|
||||
// mustCIDR calls ParseCIDR and panics on any error, or if the network
|
||||
// is not IPv6.
|
||||
func mustCIDR(s string) *IPNet {
|
||||
ip, ipNet, err := ParseCIDR(s)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if len(ip) != IPv6len {
|
||||
panic("unexpected IP length")
|
||||
}
|
||||
return ipNet
|
||||
}
|
||||
|
||||
// Classify returns the policyTableEntry of the entry with the longest
|
||||
// matching prefix that contains ip.
|
||||
// The table t must be sorted from largest mask size to smallest.
|
||||
func (t policyTable) Classify(ip IP) policyTableEntry {
|
||||
func (t policyTable) Classify(ip netip.Addr) policyTableEntry {
|
||||
// Prefix.Contains() will not match an IPv6 prefix for an IPv4 address.
|
||||
if ip.Is4() {
|
||||
ip = netip.AddrFrom16(ip.As16())
|
||||
}
|
||||
for _, ent := range t {
|
||||
if ent.Prefix.Contains(ip) {
|
||||
return ent
|
||||
|
|
@ -324,17 +313,18 @@ const (
|
|||
scopeGlobal scope = 0xe
|
||||
)
|
||||
|
||||
func classifyScope(ip IP) scope {
|
||||
func classifyScope(ip netip.Addr) scope {
|
||||
if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
||||
return scopeLinkLocal
|
||||
}
|
||||
ipv6 := len(ip) == IPv6len && ip.To4() == nil
|
||||
ipv6 := ip.Is6() && !ip.Is4In6()
|
||||
ipv6AsBytes := ip.As16()
|
||||
if ipv6 && ip.IsMulticast() {
|
||||
return scope(ip[1] & 0xf)
|
||||
return scope(ipv6AsBytes[1] & 0xf)
|
||||
}
|
||||
// Site-local addresses are defined in RFC 3513 section 2.5.6
|
||||
// (and deprecated in RFC 3879).
|
||||
if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
|
||||
if ipv6 && ipv6AsBytes[0] == 0xfe && ipv6AsBytes[1]&0xc0 == 0xc0 {
|
||||
return scopeSiteLocal
|
||||
}
|
||||
return scopeGlobal
|
||||
|
|
@ -350,30 +340,28 @@ func classifyScope(ip IP) scope {
|
|||
// If a and b are different IP versions, 0 is returned.
|
||||
//
|
||||
// See https://tools.ietf.org/html/rfc6724#section-2.2
|
||||
func commonPrefixLen(a, b IP) (cpl int) {
|
||||
if a4 := a.To4(); a4 != nil {
|
||||
a = a4
|
||||
}
|
||||
func commonPrefixLen(a netip.Addr, b IP) (cpl int) {
|
||||
if b4 := b.To4(); b4 != nil {
|
||||
b = b4
|
||||
}
|
||||
if len(a) != len(b) {
|
||||
aAsSlice := a.AsSlice()
|
||||
if len(aAsSlice) != len(b) {
|
||||
return 0
|
||||
}
|
||||
// If IPv6, only up to the prefix (first 64 bits)
|
||||
if len(a) > 8 {
|
||||
a = a[:8]
|
||||
if len(aAsSlice) > 8 {
|
||||
aAsSlice = aAsSlice[:8]
|
||||
b = b[:8]
|
||||
}
|
||||
for len(a) > 0 {
|
||||
if a[0] == b[0] {
|
||||
for len(aAsSlice) > 0 {
|
||||
if aAsSlice[0] == b[0] {
|
||||
cpl += 8
|
||||
a = a[1:]
|
||||
aAsSlice = aAsSlice[1:]
|
||||
b = b[1:]
|
||||
continue
|
||||
}
|
||||
bits := 8
|
||||
ab, bb := a[0], b[0]
|
||||
ab, bb := aAsSlice[0], b[0]
|
||||
for {
|
||||
ab >>= 1
|
||||
bb >>= 1
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -14,7 +15,7 @@ import (
|
|||
func TestSortByRFC6724(t *testing.T) {
|
||||
tests := []struct {
|
||||
in []IPAddr
|
||||
srcs []IP
|
||||
srcs []netip.Addr
|
||||
want []IPAddr
|
||||
reverse bool // also test it starting backwards
|
||||
}{
|
||||
|
|
@ -26,9 +27,9 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
{IP: ParseIP("2001:db8:1::1")},
|
||||
{IP: ParseIP("198.51.100.121")},
|
||||
},
|
||||
srcs: []IP{
|
||||
ParseIP("2001:db8:1::2"),
|
||||
ParseIP("169.254.13.78"),
|
||||
srcs: []netip.Addr{
|
||||
netip.MustParseAddr("2001:db8:1::2"),
|
||||
netip.MustParseAddr("169.254.13.78"),
|
||||
},
|
||||
want: []IPAddr{
|
||||
{IP: ParseIP("2001:db8:1::1")},
|
||||
|
|
@ -43,9 +44,9 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
{IP: ParseIP("2001:db8:1::1")},
|
||||
{IP: ParseIP("198.51.100.121")},
|
||||
},
|
||||
srcs: []IP{
|
||||
ParseIP("fe80::1"),
|
||||
ParseIP("198.51.100.117"),
|
||||
srcs: []netip.Addr{
|
||||
netip.MustParseAddr("fe80::1"),
|
||||
netip.MustParseAddr("198.51.100.117"),
|
||||
},
|
||||
want: []IPAddr{
|
||||
{IP: ParseIP("198.51.100.121")},
|
||||
|
|
@ -60,9 +61,9 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
{IP: ParseIP("2001:db8:1::1")},
|
||||
{IP: ParseIP("10.1.2.3")},
|
||||
},
|
||||
srcs: []IP{
|
||||
ParseIP("2001:db8:1::2"),
|
||||
ParseIP("10.1.2.4"),
|
||||
srcs: []netip.Addr{
|
||||
netip.MustParseAddr("2001:db8:1::2"),
|
||||
netip.MustParseAddr("10.1.2.4"),
|
||||
},
|
||||
want: []IPAddr{
|
||||
{IP: ParseIP("2001:db8:1::1")},
|
||||
|
|
@ -77,9 +78,9 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
{IP: ParseIP("2001:db8:1::1")},
|
||||
{IP: ParseIP("fe80::1")},
|
||||
},
|
||||
srcs: []IP{
|
||||
ParseIP("2001:db8:1::2"),
|
||||
ParseIP("fe80::2"),
|
||||
srcs: []netip.Addr{
|
||||
netip.MustParseAddr("2001:db8:1::2"),
|
||||
netip.MustParseAddr("fe80::2"),
|
||||
},
|
||||
want: []IPAddr{
|
||||
{IP: ParseIP("fe80::1")},
|
||||
|
|
@ -99,13 +100,13 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
{IP: ParseIP("23.23.134.56")},
|
||||
{IP: ParseIP("23.21.50.150")},
|
||||
},
|
||||
srcs: []IP{
|
||||
ParseIP("10.2.3.4"),
|
||||
ParseIP("10.2.3.4"),
|
||||
ParseIP("10.2.3.4"),
|
||||
ParseIP("10.2.3.4"),
|
||||
ParseIP("10.2.3.4"),
|
||||
ParseIP("10.2.3.4"),
|
||||
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")},
|
||||
|
|
@ -121,7 +122,7 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
for i, tt := range tests {
|
||||
inCopy := make([]IPAddr, len(tt.in))
|
||||
copy(inCopy, tt.in)
|
||||
srcCopy := make([]IP, len(tt.in))
|
||||
srcCopy := make([]netip.Addr, len(tt.in))
|
||||
copy(srcCopy, tt.srcs)
|
||||
sortByRFC6724withSrcs(inCopy, srcCopy)
|
||||
if !reflect.DeepEqual(inCopy, tt.want) {
|
||||
|
|
@ -145,39 +146,100 @@ func TestSortByRFC6724(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
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 IP
|
||||
ip netip.Addr
|
||||
want policyTableEntry
|
||||
}{
|
||||
{
|
||||
ip: ParseIP("127.0.0.1"),
|
||||
ip: netip.MustParseAddr("127.0.0.1"),
|
||||
want: policyTableEntry{
|
||||
Prefix: &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)},
|
||||
Prefix: netip.MustParsePrefix("::ffff:0:0/96"),
|
||||
Precedence: 35,
|
||||
Label: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"),
|
||||
ip: netip.MustParseAddr("2601:645:8002:a500:986f:1db8:c836:bd65"),
|
||||
want: policyTableEntry{
|
||||
Prefix: &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)},
|
||||
Prefix: netip.MustParsePrefix("::/0"),
|
||||
Precedence: 40,
|
||||
Label: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
ip: ParseIP("::1"),
|
||||
ip: netip.MustParseAddr("::1"),
|
||||
want: policyTableEntry{
|
||||
Prefix: &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)},
|
||||
Prefix: netip.MustParsePrefix("::1/128"),
|
||||
Precedence: 50,
|
||||
Label: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
ip: ParseIP("2002::ab12"),
|
||||
ip: netip.MustParseAddr("2002::ab12"),
|
||||
want: policyTableEntry{
|
||||
Prefix: &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)},
|
||||
Prefix: netip.MustParsePrefix("2002::/16"),
|
||||
Precedence: 30,
|
||||
Label: 2,
|
||||
},
|
||||
|
|
@ -193,24 +255,24 @@ func TestRFC6724PolicyTableClassify(t *testing.T) {
|
|||
|
||||
func TestRFC6724ClassifyScope(t *testing.T) {
|
||||
tests := []struct {
|
||||
ip IP
|
||||
ip netip.Addr
|
||||
want scope
|
||||
}{
|
||||
{ParseIP("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2
|
||||
{ParseIP("::1"), scopeLinkLocal}, // rfc4007#section-4
|
||||
{ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
|
||||
{ParseIP("fec0::1"), scopeSiteLocal},
|
||||
{ParseIP("8.8.8.8"), scopeGlobal},
|
||||
{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},
|
||||
|
||||
{ParseIP("ff02::"), scopeLinkLocal}, // IPv6 multicast
|
||||
{ParseIP("ff05::"), scopeSiteLocal}, // IPv6 multicast
|
||||
{ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast
|
||||
{ParseIP("ff0e::"), scopeGlobal}, // IPv6 multicast
|
||||
{netip.MustParseAddr("ff02::"), scopeLinkLocal}, // IPv6 multicast
|
||||
{netip.MustParseAddr("ff05::"), scopeSiteLocal}, // IPv6 multicast
|
||||
{netip.MustParseAddr("ff04::"), scopeAdminLocal}, // IPv6 multicast
|
||||
{netip.MustParseAddr("ff0e::"), scopeGlobal}, // IPv6 multicast
|
||||
|
||||
{IPv4(0xe0, 0, 0, 0), scopeGlobal}, // IPv4 link-local multicast as 16 bytes
|
||||
{IPv4(0xe0, 2, 2, 2), scopeGlobal}, // IPv4 global multicast as 16 bytes
|
||||
{IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes
|
||||
{IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes
|
||||
{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)
|
||||
|
|
@ -222,22 +284,23 @@ func TestRFC6724ClassifyScope(t *testing.T) {
|
|||
|
||||
func TestRFC6724CommonPrefixLength(t *testing.T) {
|
||||
tests := []struct {
|
||||
a, b IP
|
||||
a netip.Addr
|
||||
b IP
|
||||
want int
|
||||
}{
|
||||
{ParseIP("fe80::1"), ParseIP("fe80::2"), 64},
|
||||
{ParseIP("fe81::1"), ParseIP("fe80::2"), 15},
|
||||
{ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
|
||||
{IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32},
|
||||
{IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16},
|
||||
{IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17},
|
||||
{IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18},
|
||||
{IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19},
|
||||
{IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20},
|
||||
{IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21},
|
||||
{IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22},
|
||||
{IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23},
|
||||
{IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24},
|
||||
{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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue