diff --git a/cmd/stayrtr/stayrtr.go b/cmd/stayrtr/stayrtr.go index f36b502..3d8b4ba 100644 --- a/cmd/stayrtr/stayrtr.go +++ b/cmd/stayrtr/stayrtr.go @@ -12,6 +12,7 @@ import ( "fmt" "net" "net/http" + "net/netip" "os" "os/signal" "sort" @@ -27,6 +28,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" + "go4.org/netipx" "golang.org/x/crypto/ssh" ) @@ -182,9 +184,8 @@ func decodeJSON(data []byte) (*prefixfile.VRPList, error) { return &vrplistjson, err } -func isValidPrefixLength(prefix *net.IPNet, maxLength uint8) bool { - plen, max := net.IPMask.Size(prefix.Mask) - +func isValidPrefixLength(prefix netip.Prefix, maxLength uint8) bool { + plen, max := net.IPMask.Size(netipx.PrefixIPNet(prefix).Mask) if plen == 0 || uint8(plen) > maxLength || maxLength > uint8(max) { log.Errorf("%s Maxlength wrong: %d - %d", prefix, plen, maxLength) return false @@ -201,8 +202,7 @@ func isValidPrefixLength(prefix *net.IPNet, maxLength uint8) bool { func processData(vrplistjson []prefixfile.VRPJson, brklistjson []prefixfile.BgpSecKeyJson, aspajson *prefixfile.ProviderAuthorizationsJson) /*Export*/ ([]rtr.VRP, []rtr.BgpsecKey, []rtr.VAP, int, int, int) { - // - filterDuplicates := make(map[string]bool) + filterDuplicates := make(map[string]struct{}) // It may be tempting to change this to a simple time.Since() but that will // grab the current time every time it's invoked, time calls can be slow on @@ -240,7 +240,7 @@ func processData(vrplistjson []prefixfile.VRPJson, } } - if prefix.IP.To4() != nil { + if prefix.Addr().Is4() { countv4++ } else { countv6++ @@ -251,10 +251,10 @@ func processData(vrplistjson []prefixfile.VRPJson, if exists { continue } - filterDuplicates[key] = true + filterDuplicates[key] = struct{}{} vrp := rtr.VRP{ - Prefix: *prefix, + Prefix: prefix, ASN: asn, MaxLen: v.Length, } @@ -281,15 +281,14 @@ func processData(vrplistjson []prefixfile.VRPJson, P1 is likely to mark a BGP prefix P1 invalid. Therefore, the cache SHOULD announce the sub-prefix P1 before the covering prefix P0. */ - CIDRSizei, _ := vrplist[i].Prefix.Mask.Size() - CIDRSizej, _ := vrplist[j].Prefix.Mask.Size() - if CIDRSizei == CIDRSizej { + + if vrplist[i].Prefix.Bits() == vrplist[j].Prefix.Bits() { if vrplist[i].MaxLen != vrplist[j].MaxLen { return vrplist[i].MaxLen > vrplist[j].MaxLen } - return bytes.Compare(vrplist[i].Prefix.IP, vrplist[j].Prefix.IP) < 1 + return vrplist[i].Prefix.Addr().Compare(vrplist[j].Prefix.Addr()) < 1 } else { - return CIDRSizei > CIDRSizej + return vrplist[i].Prefix.Bits() > vrplist[j].Prefix.Bits() } }) @@ -452,7 +451,7 @@ func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, brks []rtr.BgpsecKey, va vrpsjson []prefixfile.VRPJson, brksjson []prefixfile.BgpSecKeyJson, aspajson *prefixfile.ProviderAuthorizationsJson, countv4 int, countv6 int) error { - SDs := make([]rtr.SendableData, 0) + SDs := make([]rtr.SendableData, 0, len(vrps)+len(brks)+len(vaps)) for _, v := range vrps { SDs = append(SDs, v.Copy()) } @@ -488,9 +487,9 @@ func (s *state) applyUpdateFromNewState(vrps []rtr.VRP, brks []rtr.BgpsecKey, va var countv4_dup int var countv6_dup int for _, vrp := range vrps { - if vrp.Prefix.IP.To4() != nil { + if vrp.Prefix.Addr().Is4() { countv4_dup++ - } else if vrp.Prefix.IP.To16() != nil { + } else if vrp.Prefix.Addr().Is6() { countv6_dup++ } } diff --git a/cmd/stayrtr/stayrtr_test.go b/cmd/stayrtr/stayrtr_test.go index cf67143..047fc3b 100644 --- a/cmd/stayrtr/stayrtr_test.go +++ b/cmd/stayrtr/stayrtr_test.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "net" + "net/netip" "os" "testing" "time" @@ -103,17 +103,17 @@ func TestProcessData(t *testing.T) { got, _, _, count, v4count, v6count := processData(stuff, nil, nil) want := []rtr.VRP{ { - Prefix: mustParseIPNet("2001:db8::/32"), + Prefix: netip.MustParsePrefix("2001:db8::/32"), MaxLen: 33, ASN: 123, }, { - Prefix: mustParseIPNet("192.168.1.0/24"), + Prefix: netip.MustParsePrefix("192.168.1.0/24"), MaxLen: 25, ASN: 123, }, { - Prefix: mustParseIPNet("192.168.0.0/24"), + Prefix: netip.MustParsePrefix("192.168.0.0/24"), MaxLen: 24, ASN: 123, }, @@ -122,20 +122,15 @@ func TestProcessData(t *testing.T) { t.Errorf("Wanted count = 3, v4count = 2, v6count = 1, but got %d, %d, %d", count, v4count, v6count) } - if !cmp.Equal(got, want) { - t.Errorf("Want (%+v), Got (%+v)", want, got) + opts := []cmp.Option{ + cmp.Comparer(func(x, y netip.Prefix) bool { + return x == y + }), } -} -// mustParseIPNet is a test helper function to return a net.IPNet -// This should only be called in test code, and it'll panic on test set up -// if unable to parse. -func mustParseIPNet(prefix string) net.IPNet { - _, ipnet, err := net.ParseCIDR(prefix) - if err != nil { - panic(err) + if !cmp.Equal(got, want, opts...) { + t.Errorf("Want (%+v), Got (%+v)", want, got) } - return *ipnet } func BenchmarkDecodeJSON(b *testing.B) { diff --git a/go.mod b/go.mod index 7a4ae5b..1aaf68d 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ module github.com/bgp/stayrtr -go 1.17 +go 1.21 require ( github.com/google/go-cmp v0.5.6 github.com/prometheus/client_golang v1.11.1 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.4.0 + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba golang.org/x/crypto v0.6.0 golang.org/x/sys v0.15.0 ) diff --git a/go.sum b/go.sum index 6258075..cef8527 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -32,6 +34,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -39,6 +44,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -56,6 +63,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -72,55 +83,63 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -131,28 +150,17 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -164,6 +172,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -174,3 +185,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/server.go b/lib/server.go index 48a8858..86b1be5 100644 --- a/lib/server.go +++ b/lib/server.go @@ -8,6 +8,7 @@ import ( "io" "math/rand" "net" + "net/netip" "sync" "time" @@ -212,15 +213,15 @@ func NewServer(configuration ServerConfiguration, handler RTRServerEventHandler, } } -func ConvertSDListToMap(SDs []SendableData) map[string]SendableData { - sdMap := make(map[string]SendableData, len(SDs)) +func ConvertSDListToMap(SDs []SendableData) map[string]uint8 { + sdMap := make(map[string]uint8, len(SDs)) for _, v := range SDs { - sdMap[v.HashKey()] = v + sdMap[v.HashKey()] = v.GetFlag() } return sdMap } -func ComputeDiff(newSDs, prevSDs []SendableData) (added, removed, unchanged []SendableData) { +func ComputeDiff(newSDs, prevSDs []SendableData, populateUnchanged bool) (added, removed, unchanged []SendableData) { added = make([]SendableData, 0) removed = make([]SendableData, 0) unchanged = make([]SendableData, 0) @@ -242,7 +243,7 @@ func ComputeDiff(newSDs, prevSDs []SendableData) (added, removed, unchanged []Se rcopy := vrp.Copy() rcopy.SetFlag(FLAG_REMOVED) removed = append(removed, rcopy) - } else { + } else if populateUnchanged { rcopy := vrp.Copy() unchanged = append(unchanged, rcopy) } @@ -273,7 +274,7 @@ func ApplyDiff(diff, prevSDs []SendableData) []SendableData { rcopy := vrp.Copy() newSDs = append(newSDs, rcopy) } else { - if cvrp.GetFlag() == FLAG_REMOVED { + if cvrp == FLAG_REMOVED { rcopy := vrp.Copy() newSDs = append(newSDs, rcopy) } @@ -369,16 +370,16 @@ func (s *Server) AddData(vrps []SendableData) { s.sdlock.RLock() // a slight hack for now, until we have BGPsec/ASPA support - vrpsAsSD := make([]SendableData, 0) + vrpsAsSD := make([]SendableData, 0, len(vrps)) for _, v := range vrps { vrpsAsSD = append(vrpsAsSD, v.Copy()) } - added, removed, unchanged := ComputeDiff(vrpsAsSD, s.sdCurrent) + added, removed, _ := ComputeDiff(vrpsAsSD, s.sdCurrent, false) if s.log != nil && s.logverbose { - s.log.Debugf("Computed diff: added (%v), removed (%v), unchanged (%v)", added, removed, unchanged) + s.log.Debugf("Computed diff: added (%v), removed (%v)", added, removed) } else if s.log != nil { - s.log.Debugf("Computed diff: added (%d), removed (%d), unchanged (%d)", len(added), len(removed), len(unchanged)) + s.log.Debugf("Computed diff: added (%d), removed (%d)", len(added), len(removed)) } curDiff := append(added, removed...) s.sdlock.RUnlock() @@ -670,9 +671,7 @@ func (s *Server) StartTLS(bind string, config *tls.Config) error { func (s *Server) GetClientList() []*Client { s.clientlock.RLock() list := make([]*Client, len(s.clients)) - for i, c := range s.clients { - list[i] = c - } + copy(list, s.clients) s.clientlock.RUnlock() return list } @@ -886,9 +885,9 @@ func (c *Client) Notify(sessionId uint16, serialNumber uint32) { } type VRP struct { - Prefix net.IPNet - MaxLen uint8 + Prefix netip.Prefix ASN uint32 + MaxLen uint8 Flags uint8 } @@ -910,18 +909,13 @@ func (r1 *VRP) Equals(r2 SendableData) bool { } r2True := r2.(*VRP) - return r1.MaxLen == r2True.MaxLen && r1.ASN == r2True.ASN && r1.Prefix.IP.Equal(r2True.Prefix.IP) && bytes.Equal(r1.Prefix.Mask, r2True.Prefix.Mask) + + return r1.MaxLen == r2True.MaxLen && r1.ASN == r2True.ASN && r1.Prefix == r2True.Prefix } func (r1 *VRP) Copy() SendableData { - newprefix := net.IPNet{ - IP: make([]byte, len(r1.Prefix.IP)), - Mask: make([]byte, len(r1.Prefix.Mask)), - } - copy(newprefix.IP, r1.Prefix.IP) - copy(newprefix.Mask, r1.Prefix.Mask) return &VRP{ - Prefix: newprefix, + Prefix: r1.Prefix, ASN: r1.ASN, MaxLen: r1.MaxLen, Flags: r1.Flags} @@ -1090,7 +1084,8 @@ func (c *Client) SendWrongVersionError() { func (c *Client) SendData(sd SendableData) { switch t := sd.(type) { case *VRP: - if t.Prefix.IP.To4() == nil && t.Prefix.IP.To16() != nil { + + if t.Prefix.Addr().Is6() { pdu := &PDUIPv6Prefix{ Flags: t.Flags, MaxLen: t.MaxLen, @@ -1098,7 +1093,7 @@ func (c *Client) SendData(sd SendableData) { Prefix: t.Prefix, } c.SendPDU(pdu) - } else if t.Prefix.IP.To4() != nil { + } else if t.Prefix.Addr().Is4() { pdu := &PDUIPv4Prefix{ Flags: t.Flags, MaxLen: t.MaxLen, diff --git a/lib/server_test.go b/lib/server_test.go index ca2f4b8..f0943fb 100644 --- a/lib/server_test.go +++ b/lib/server_test.go @@ -3,9 +3,14 @@ package rtrlib import ( "encoding/binary" "net" + "net/netip" + "runtime" "testing" + "unsafe" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" + "go4.org/netipx" ) func GenerateVrps(size uint32, offset uint32) []SendableData { @@ -14,10 +19,10 @@ func GenerateVrps(size uint32, offset uint32) []SendableData { ipFinal := make([]byte, 4) binary.BigEndian.PutUint32(ipFinal, i+offset) vrps[i] = &VRP{ - Prefix: net.IPNet{ - IP: net.IP(append([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ipFinal...)), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP(append([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ipFinal...)), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 64496, } @@ -30,7 +35,7 @@ func BaseBench(base int, multiplier int) { newVrps := GenerateVrps(uint32(benchSize1), uint32(0)) benchSize2 := base prevVrps := GenerateVrps(uint32(benchSize2), uint32(benchSize1-benchSize2/2)) - ComputeDiff(newVrps, prevVrps) + ComputeDiff(newVrps, prevVrps, false) } func BenchmarkComputeDiff1000x10(b *testing.B) { @@ -48,36 +53,36 @@ func BenchmarkComputeDiff100000x1(b *testing.B) { func TestComputeDiff(t *testing.T) { newVrps := []VRP{ { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65003, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65002, }, } prevVrps := []VRP{ { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65001, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65002, }, @@ -91,7 +96,7 @@ func TestComputeDiff(t *testing.T) { prevVrpsAsSD = append(prevVrpsAsSD, v.Copy()) } - added, removed, unchanged := ComputeDiff(newVrpsSD, prevVrpsAsSD) + added, removed, unchanged := ComputeDiff(newVrpsSD, prevVrpsAsSD, true) assert.Len(t, added, 1) assert.Len(t, removed, 1) assert.Len(t, unchanged, 1) @@ -103,46 +108,46 @@ func TestComputeDiff(t *testing.T) { func TestApplyDiff(t *testing.T) { diff := []VRP{ { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65003, Flags: FLAG_ADDED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65002, Flags: FLAG_REMOVED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65004, Flags: FLAG_REMOVED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65006, Flags: FLAG_REMOVED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65007, Flags: FLAG_ADDED, @@ -150,46 +155,46 @@ func TestApplyDiff(t *testing.T) { } prevVrps := []VRP{ { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65001, Flags: FLAG_ADDED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65002, Flags: FLAG_ADDED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65005, Flags: FLAG_REMOVED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65006, Flags: FLAG_REMOVED, }, { - Prefix: net.IPNet{ - IP: net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}), - Mask: net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), - }, + Prefix: synthIPNetToPrefix( + net.IP([]byte{0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7}), + net.IPMask([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + ), MaxLen: 128, ASN: 65007, Flags: FLAG_REMOVED, @@ -254,7 +259,7 @@ func TestComputeDiffBGPSEC(t *testing.T) { prevVrpsAsSD = append(prevVrpsAsSD, v.Copy()) } - added, removed, unchanged := ComputeDiff(newVrpsSD, prevVrpsAsSD) + added, removed, unchanged := ComputeDiff(newVrpsSD, prevVrpsAsSD, true) assert.Len(t, added, 1) assert.Len(t, removed, 1) assert.Len(t, unchanged, 1) @@ -262,3 +267,57 @@ func TestComputeDiffBGPSEC(t *testing.T) { assert.Equal(t, removed[0].(*BgpsecKey).ASN, uint32(65001)) assert.Equal(t, unchanged[0].(*BgpsecKey).ASN, uint32(65002)) } + +func TestVRPStructSize(t *testing.T) { + if a := runtime.GOARCH; a != "amd64" { + t.Skipf("skipping, running on %s but this test is hard-coded for amd64 architecture", a) + } + + // This test verifies that the size of a VRP and its component structures + // do not change unexpectedly due to other code modifications. + // + // For reference, the tool structlayout can be used to examine struct sizes + // and structlayout-optimize to recommend ordering of members to minimize memory utilization. + // Whenever a constant is changed here, be sure to update the associated + // comment with the output of the tools. + // + // $ go install honnef.co/go/tools/cmd/structlayout@latest + // $ go install honnef.co/go/tools/cmd/structlayout-optimize@latest + + const ( + // $ structlayout -json . VRP + // VRP.Prefix.ip.addr.hi uint64: 0-8 (size 8, align 8) + // VRP.Prefix.ip.addr.lo uint64: 8-16 (size 8, align 8) + // VRP.Prefix.ip.z *internal/intern.Value: 16-24 (size 8, align 8) + // VRP.Prefix.bitsPlusOne uint8: 24-25 (size 1, align 1) + // padding: 25-32 (size 7, align 0) + // VRP.ASN uint32: 32-36 (size 4, align 4) + // VRP.MaxLen uint8: 36-37 (size 1, align 1) + // VRP.Flags uint8: 37-38 (size 1, align 1) + // padding: 38-40 (size 2, align 0) + // + // NOTE: we could actually reduce this to 32 if netip.Prefix + // were properly aligned. Ex: + // $ structlayout -json . VRP | structlayout-optimize + // VRP.Prefix struct: 0-24 (size 24, align 8) + // VRP.ASN uint32: 24-28 (size 4, align 4) + // VRP.MaxLen uint8: 28-29 (size 1, align 1) + // VRP.Flags uint8: 29-30 (size 1, align 1) + // padding: 30-32 (size 2, align 0) + // + vrpSize = 40 + ) + + if diff := cmp.Diff(int(unsafe.Sizeof(VRP{})), vrpSize); diff != "" { + t.Fatalf("unexpected VRPs struct size (-want +got):\n%s", diff) + } +} + +func synthIPNetToPrefix(ip net.IP, mask net.IPMask) netip.Prefix { + n := &net.IPNet{ + IP: ip, + Mask: mask, + } + pfx, _ := netipx.FromStdIPNet(n) + return pfx +} diff --git a/lib/structs.go b/lib/structs.go index ca51b66..1ef2480 100644 --- a/lib/structs.go +++ b/lib/structs.go @@ -7,7 +7,7 @@ import ( "errors" "fmt" "io" - "net" + "net/netip" ) type Logger interface { @@ -249,16 +249,15 @@ func (pdu *PDUCacheResponse) Write(wr io.Writer) { } type PDUIPv4Prefix struct { + Prefix netip.Prefix + ASN uint32 Version uint8 - Prefix net.IPNet MaxLen uint8 - ASN uint32 Flags uint8 } func (pdu *PDUIPv4Prefix) String() string { - mask, _ := pdu.Prefix.Mask.Size() - return fmt.Sprintf("PDU IPv4 Prefix v%d %s/%d(->/%d), origin: AS%d, flags: %d", pdu.Version, pdu.Prefix.IP.String(), mask, pdu.MaxLen, pdu.ASN, pdu.Flags) + return fmt.Sprintf("PDU IPv4 Prefix v%d %s(->/%d), origin: AS%d, flags: %d", pdu.Version, pdu.Prefix.String(), pdu.MaxLen, pdu.ASN, pdu.Flags) } func (pdu *PDUIPv4Prefix) Bytes() []byte { @@ -280,30 +279,28 @@ func (pdu *PDUIPv4Prefix) GetType() uint8 { } func (pdu *PDUIPv4Prefix) Write(wr io.Writer) { - mask, _ := pdu.Prefix.Mask.Size() binary.Write(wr, binary.BigEndian, uint8(pdu.Version)) binary.Write(wr, binary.BigEndian, uint8(PDU_ID_IPV4_PREFIX)) binary.Write(wr, binary.BigEndian, uint16(0)) binary.Write(wr, binary.BigEndian, uint32(20)) binary.Write(wr, binary.BigEndian, pdu.Flags) - binary.Write(wr, binary.BigEndian, uint8(mask)) + binary.Write(wr, binary.BigEndian, uint8(pdu.Prefix.Bits())) binary.Write(wr, binary.BigEndian, pdu.MaxLen) binary.Write(wr, binary.BigEndian, uint8(0)) - binary.Write(wr, binary.BigEndian, pdu.Prefix.IP.To4()) + binary.Write(wr, binary.BigEndian, pdu.Prefix.Addr().As4()) binary.Write(wr, binary.BigEndian, pdu.ASN) } type PDUIPv6Prefix struct { + Prefix netip.Prefix + ASN uint32 Version uint8 - Prefix net.IPNet MaxLen uint8 - ASN uint32 Flags uint8 } func (pdu *PDUIPv6Prefix) String() string { - mask, _ := pdu.Prefix.Mask.Size() - return fmt.Sprintf("PDU IPv6 Prefix v%d %s/%d(->/%d), origin: AS%d, flags: %d", pdu.Version, pdu.Prefix.IP.String(), mask, pdu.MaxLen, pdu.ASN, pdu.Flags) + return fmt.Sprintf("PDU IPv6 Prefix v%d %s(->/%d), origin: AS%d, flags: %d", pdu.Version, pdu.Prefix.String(), pdu.MaxLen, pdu.ASN, pdu.Flags) } func (pdu *PDUIPv6Prefix) Bytes() []byte { @@ -325,16 +322,15 @@ func (pdu *PDUIPv6Prefix) GetType() uint8 { } func (pdu *PDUIPv6Prefix) Write(wr io.Writer) { - mask, _ := pdu.Prefix.Mask.Size() binary.Write(wr, binary.BigEndian, uint8(pdu.Version)) binary.Write(wr, binary.BigEndian, uint8(PDU_ID_IPV6_PREFIX)) binary.Write(wr, binary.BigEndian, uint16(0)) binary.Write(wr, binary.BigEndian, uint32(32)) binary.Write(wr, binary.BigEndian, pdu.Flags) - binary.Write(wr, binary.BigEndian, uint8(mask)) + binary.Write(wr, binary.BigEndian, uint8(pdu.Prefix.Bits())) binary.Write(wr, binary.BigEndian, pdu.MaxLen) binary.Write(wr, binary.BigEndian, uint8(0)) - binary.Write(wr, binary.BigEndian, pdu.Prefix.IP.To16()) + binary.Write(wr, binary.BigEndian, pdu.Prefix.Addr().As16()) binary.Write(wr, binary.BigEndian, pdu.ASN) } @@ -645,9 +641,9 @@ func Decode(rdr io.Reader) (PDU, error) { } prefixLen := int(toread[1]) ip := toread[4:8] - ipnet := net.IPNet{ - IP: ip, - Mask: net.CIDRMask(prefixLen, 32), + addr, ok := netip.AddrFromSlice(ip) + if !ok { + return nil, fmt.Errorf("ip slice length is not 4 or 16: %+v", addr) } asn := binary.BigEndian.Uint32(toread[8:]) return &PDUIPv4Prefix{ @@ -655,7 +651,7 @@ func Decode(rdr io.Reader) (PDU, error) { Flags: uint8(toread[0]), MaxLen: uint8(toread[2]), ASN: asn, - Prefix: ipnet, + Prefix: netip.PrefixFrom(addr, prefixLen), }, nil case PDU_ID_IPV6_PREFIX: if len(toread) != 24 { @@ -663,9 +659,9 @@ func Decode(rdr io.Reader) (PDU, error) { } prefixLen := int(toread[1]) ip := toread[4:20] - ipnet := net.IPNet{ - IP: ip, - Mask: net.CIDRMask(prefixLen, 128), + addr, ok := netip.AddrFromSlice(ip) + if !ok { + return nil, fmt.Errorf("ip slice length is not 4 or 16: %+v", addr) } asn := binary.BigEndian.Uint32(toread[20:]) return &PDUIPv6Prefix{ @@ -673,7 +669,7 @@ func Decode(rdr io.Reader) (PDU, error) { Flags: uint8(toread[0]), MaxLen: uint8(toread[2]), ASN: asn, - Prefix: ipnet, + Prefix: netip.PrefixFrom(addr, prefixLen), }, nil case PDU_ID_END_OF_DATA: if len(toread) != 4 && len(toread) != 16 { diff --git a/lib/structs_test.go b/lib/structs_test.go new file mode 100644 index 0000000..852b6b7 --- /dev/null +++ b/lib/structs_test.go @@ -0,0 +1,61 @@ +package rtrlib + +import ( + "runtime" + "testing" + "unsafe" + + "github.com/google/go-cmp/cmp" +) + +func TestPDUPrefixStructSize(t *testing.T) { + if a := runtime.GOARCH; a != "amd64" { + t.Skipf("skipping, running on %s but this test is hard-coded for amd64 architecture", a) + } + + // This test verifies that the size of PDUIPv{4,6}Prefix and its component structures + // do not change unexpectedly due to other code modifications. + // + // For reference, the tool structlayout can be used to examine struct sizes + // and structlayout-optimize to recommend ordering of members to minimize memory utilization. + // Whenever a constant is changed here, be sure to update the associated + // comment with the output of the tools. + // + // $ go install honnef.co/go/tools/cmd/structlayout@latest + // $ go install honnef.co/go/tools/cmd/structlayout-optimize@latest + + const ( + // $ structlayout . PDUIPv4Prefix + // PDUIPv4Prefix.Prefix.ip.addr.hi uint64: 0-8 (size 8, align 8) + // PDUIPv4Prefix.Prefix.ip.addr.lo uint64: 8-16 (size 8, align 8) + // PDUIPv4Prefix.Prefix.ip.z *internal/intern.Value: 16-24 (size 8, align 8) + // PDUIPv4Prefix.Prefix.bitsPlusOne uint8: 24-25 (size 1, align 1) + // padding: 25-32 (size 7, align 0) + // PDUIPv4Prefix.ASN uint32: 32-36 (size 4, align 4) + // PDUIPv4Prefix.Version uint8: 36-37 (size 1, align 1) + // PDUIPv4Prefix.MaxLen uint8: 37-38 (size 1, align 1) + // PDUIPv4Prefix.Flags uint8: 38-39 (size 1, align 1) + // padding: 39-40 (size 1, align 0) + // + // $ structlayout . PDUIPv6Prefix + // PDUIPv6Prefix.Prefix.ip.addr.hi uint64: 0-8 (size 8, align 8) + // PDUIPv6Prefix.Prefix.ip.addr.lo uint64: 8-16 (size 8, align 8) + // PDUIPv6Prefix.Prefix.ip.z *internal/intern.Value: 16-24 (size 8, align 8) + // PDUIPv6Prefix.Prefix.bitsPlusOne uint8: 24-25 (size 1, align 1) + // padding: 25-32 (size 7, align 0) + // PDUIPv6Prefix.ASN uint32: 32-36 (size 4, align 4) + // PDUIPv6Prefix.Version uint8: 36-37 (size 1, align 1) + // PDUIPv6Prefix.MaxLen uint8: 37-38 (size 1, align 1) + // PDUIPv6Prefix.Flags uint8: 38-39 (size 1, align 1) + // padding: 39-40 (size 1, align 0) + pduIPv4PrefixSize = 40 + pduIPv6PrefixSize = 40 + ) + + if diff := cmp.Diff(int(unsafe.Sizeof(PDUIPv4Prefix{})), pduIPv4PrefixSize); diff != "" { + t.Fatalf("unexpected PDUIPv4Prefix struct size (-want +got):\n%s", diff) + } + if diff := cmp.Diff(int(unsafe.Sizeof(PDUIPv6Prefix{})), pduIPv6PrefixSize); diff != "" { + t.Fatalf("unexpected PDUIPv6Prefix struct size (-want +got):\n%s", diff) + } +} diff --git a/prefixfile/prefixfile.go b/prefixfile/prefixfile.go index 06c7c14..3c2cd2d 100644 --- a/prefixfile/prefixfile.go +++ b/prefixfile/prefixfile.go @@ -2,7 +2,7 @@ package prefixfile import ( "fmt" - "net" + "net/netip" "strconv" "strings" "time" @@ -88,15 +88,18 @@ func (vrp *VRPJson) GetASN() uint32 { return asn } -func (vrp *VRPJson) GetPrefix2() (*net.IPNet, error) { - _, prefix, err := net.ParseCIDR(vrp.Prefix) +func (vrp *VRPJson) GetPrefix2() (netip.Prefix, error) { + prefix, err := netip.ParsePrefix(vrp.Prefix) if err != nil { - return nil, fmt.Errorf("could not decode prefix: %v", vrp.Prefix) + return netip.Prefix{}, fmt.Errorf("could not decode prefix: %v", vrp.Prefix) + } + if !prefix.IsValid() { + return netip.Prefix{}, fmt.Errorf("prefix %s is invalid", prefix) } return prefix, nil } -func (vrp *VRPJson) GetPrefix() *net.IPNet { +func (vrp *VRPJson) GetPrefix() netip.Prefix { prefix, _ := vrp.GetPrefix2() return prefix } @@ -108,11 +111,3 @@ func (vrp *VRPJson) GetMaxLen() int { func (vrp *VRPJson) String() string { return fmt.Sprintf("%v/%v/%v", vrp.Prefix, vrp.Length, vrp.ASN) } - -func GetIPBroadcast(ipnet net.IPNet) net.IP { - br := make([]byte, len(ipnet.IP)) - for i := 0; i < len(ipnet.IP); i++ { - br[i] = ipnet.IP[i] | (^ipnet.Mask[i]) - } - return net.IP(br) -} diff --git a/prefixfile/slurm.go b/prefixfile/slurm.go index bc35bf0..f7da931 100644 --- a/prefixfile/slurm.go +++ b/prefixfile/slurm.go @@ -8,7 +8,10 @@ import ( "encoding/json" "io" "net" + "net/netip" "strings" + + "go4.org/netipx" ) type SlurmPrefixFilter struct { @@ -37,8 +40,8 @@ func (pf *SlurmPrefixFilter) GetASN() (uint32, bool) { } } -func (pf *SlurmPrefixFilter) GetPrefix() *net.IPNet { - _, prefix, _ := net.ParseCIDR(pf.Prefix) +func (pf *SlurmPrefixFilter) GetPrefix() netip.Prefix { + prefix, _ := netip.ParsePrefix(pf.Prefix) return prefix } @@ -113,11 +116,12 @@ func (s *SlurmValidationOutputFilters) FilterOnVRPs(vrps []VRPJson) (added, remo } for _, vrp := range vrps { rPrefix := vrp.GetPrefix() - var rIPStart net.IP - var rIPEnd net.IP - if rPrefix != nil { - rIPStart = rPrefix.IP.To16() - rIPEnd = GetIPBroadcast(*rPrefix).To16() + var rIPStart netip.Addr + var rIPEnd netip.Addr + if rPrefix.IsValid() { + r := netipx.RangeOfPrefix(rPrefix) + rIPStart = r.From() + rIPEnd = r.To() } var wasRemoved bool @@ -125,7 +129,7 @@ func (s *SlurmValidationOutputFilters) FilterOnVRPs(vrps []VRPJson) (added, remo fPrefix := filter.GetPrefix() fASN, fASNEmpty := filter.GetASN() match := true - if match && fPrefix != nil && rPrefix != nil { + if match && fPrefix.IsValid() && rPrefix.IsValid() { if !(fPrefix.Contains(rIPStart) && fPrefix.Contains(rIPEnd)) { match = false