mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
573 lines
18 KiB
Go
573 lines
18 KiB
Go
// SPDX-FileCopyrightText: 2022 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package bmp
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand/v2"
|
|
"net/netip"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"akvorado/common/helpers"
|
|
|
|
"github.com/osrg/gobgp/v4/pkg/packet/bgp"
|
|
)
|
|
|
|
func TestLargeCommunitiesAlign(t *testing.T) {
|
|
largeCommunities := []bgp.LargeCommunity{
|
|
{ASN: 1, LocalData1: 2, LocalData2: 3},
|
|
{ASN: 4, LocalData1: 5, LocalData2: 6},
|
|
}
|
|
first := unsafe.Pointer(&largeCommunities[0])
|
|
second := unsafe.Pointer(&largeCommunities[1])
|
|
diff := uintptr(second) - uintptr(first)
|
|
if diff != 12 {
|
|
t.Errorf("Alignment error for large community slices. Got %d, expected 12",
|
|
diff)
|
|
}
|
|
|
|
// Also check other stuff we think are true about "unsafe"
|
|
if unsafe.Sizeof(largeCommunities[0]) != 12 {
|
|
t.Errorf("Large community size: got %d, expected 12", unsafe.Sizeof(largeCommunities[0]))
|
|
}
|
|
const _ = unsafe.Sizeof(largeCommunities[0])
|
|
}
|
|
|
|
func TestRTAEqual(t *testing.T) {
|
|
cases := []struct {
|
|
pos helpers.Pos
|
|
rta1 routeAttributes
|
|
rta2 routeAttributes
|
|
equal bool
|
|
}{
|
|
{helpers.Mark(), routeAttributes{asn: 2038}, routeAttributes{asn: 2038}, true},
|
|
{helpers.Mark(), routeAttributes{asn: 2038}, routeAttributes{asn: 2039}, false},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{}},
|
|
routeAttributes{asn: 2038},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{}},
|
|
routeAttributes{asn: 2039},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, communities: []uint32{}},
|
|
routeAttributes{asn: 2038},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, communities: []uint32{}},
|
|
routeAttributes{asn: 2039},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{}},
|
|
routeAttributes{asn: 2038},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{}},
|
|
routeAttributes{asn: 2039},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3}},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 0}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 4}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4}},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}},
|
|
routeAttributes{asn: 2038, asPath: []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300, 400}},
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300, 400}},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300, 400}},
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300, 402}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300}},
|
|
routeAttributes{asn: 2038, communities: []uint32{100, 200, 300, 400}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
true,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 8}}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 4}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
false,
|
|
},
|
|
{
|
|
helpers.Mark(),
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}}},
|
|
routeAttributes{asn: 2038, largeCommunities: []bgp.LargeCommunity{{ASN: 1, LocalData1: 2, LocalData2: 3}, {ASN: 3, LocalData1: 4, LocalData2: 5}, {ASN: 5, LocalData1: 6, LocalData2: 7}}},
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
equal := tc.rta1.Equal(tc.rta2)
|
|
if equal && !tc.equal {
|
|
t.Errorf("%s%+v == %+v", tc.pos, tc.rta1, tc.rta2)
|
|
} else if !equal && tc.equal {
|
|
t.Errorf("%s%+v != %+v", tc.pos, tc.rta1, tc.rta2)
|
|
} else {
|
|
equal := tc.rta1.Hash() == tc.rta2.Hash()
|
|
if equal && !tc.equal {
|
|
t.Errorf("%s%+v.hash == %+v.hash", tc.pos, tc.rta1, tc.rta2)
|
|
} else if !equal && tc.equal {
|
|
t.Errorf("%s%+v.hash != %+v.hash", tc.pos, tc.rta1, tc.rta2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRemoveRoutes(t *testing.T) {
|
|
nr := func(r *rib, peer uint32) route {
|
|
return route{
|
|
peer: peer,
|
|
nlri: r.nlris.Put(nlri{family: bgp.RF_IPv4_UC, path: 1}),
|
|
nextHop: r.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:198.51.100.8"))),
|
|
attributes: r.rtas.Put(routeAttributes{
|
|
asn: 65300,
|
|
}),
|
|
prefixLen: 96 + 24,
|
|
}
|
|
}
|
|
t.Run("only route", func(t *testing.T) {
|
|
r := newRIB()
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), nr(r, 10))
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(route) bool { return true }, true)
|
|
if !empty {
|
|
t.Error("removeRoutes() should have removed all routes from node")
|
|
}
|
|
if count != 1 {
|
|
t.Error("removeRoutes() should have removed 1 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
|
|
t.Run("first route", func(t *testing.T) {
|
|
r := newRIB()
|
|
r1 := nr(r, 10)
|
|
r2 := nr(r, 11)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r1)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r2)
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(r route) bool { return r.peer == 10 }, true)
|
|
if empty {
|
|
t.Error("removeRoutes() should not have removed all routes from node")
|
|
}
|
|
if count != 1 {
|
|
t.Error("removeRoutes() should have removed 1 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{
|
|
makeRouteKey(idx, 0): r2,
|
|
}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
|
|
t.Run("second route", func(t *testing.T) {
|
|
r := newRIB()
|
|
r1 := nr(r, 10)
|
|
r2 := nr(r, 11)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r1)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r2)
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(r route) bool { return r.peer == 11 }, true)
|
|
if empty {
|
|
t.Error("removeRoutes() should not have removed all routes from node")
|
|
}
|
|
if count != 1 {
|
|
t.Error("removeRoutes() should have removed 1 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{
|
|
makeRouteKey(idx, 0): r1,
|
|
}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
t.Run("middle route", func(t *testing.T) {
|
|
r := newRIB()
|
|
r1 := nr(r, 10)
|
|
r2 := nr(r, 11)
|
|
r3 := nr(r, 12)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r1)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r2)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r3)
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(r route) bool { return r.peer == 11 }, true)
|
|
if empty {
|
|
t.Error("removeRoutes() should not have removed all routes from node")
|
|
}
|
|
if count != 1 {
|
|
t.Error("removeRoutes() should have removed 1 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{
|
|
makeRouteKey(idx, 0): r1,
|
|
makeRouteKey(idx, 1): r3,
|
|
}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
t.Run("one route out of two", func(t *testing.T) {
|
|
r := newRIB()
|
|
r1 := nr(r, 10)
|
|
r2 := nr(r, 11)
|
|
r3 := nr(r, 12)
|
|
r4 := nr(r, 13)
|
|
r5 := nr(r, 14)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r1)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r2)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r3)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r4)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r5)
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(r route) bool { return r.peer%2 == 0 }, false)
|
|
if empty {
|
|
t.Error("removeRoutes() should not have removed all routes from node")
|
|
}
|
|
if count != 3 {
|
|
t.Error("removeRoutes() should have removed 3 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{
|
|
makeRouteKey(idx, 0): r2,
|
|
makeRouteKey(idx, 1): r4,
|
|
}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
|
|
t.Run("all routes", func(t *testing.T) {
|
|
r := newRIB()
|
|
r1 := nr(r, 10)
|
|
r2 := nr(r, 11)
|
|
r3 := nr(r, 12)
|
|
r4 := nr(r, 13)
|
|
r5 := nr(r, 14)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r1)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r2)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r3)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r4)
|
|
r.AddPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/120"), r5)
|
|
idx, _ := r.tree.Lookup(netip.MustParseAddr("192.168.144.10"))
|
|
count, empty := r.removeRoutes(idx, func(route) bool { return true }, false)
|
|
if !empty {
|
|
t.Error("removeRoutes() should have removed all routes from node")
|
|
}
|
|
if count != 5 {
|
|
t.Error("removeRoutes() should have removed 5 route")
|
|
}
|
|
if diff := helpers.Diff(r.routes, map[routeKey]route{}); diff != "" {
|
|
t.Errorf("removeRoutes() (-got, +want):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRIBHarness(t *testing.T) {
|
|
for run := range 5 {
|
|
random := rand.New(rand.NewPCG(uint64(run), 0))
|
|
run++
|
|
|
|
// Ramp up the test
|
|
totalExporters := run
|
|
peerPerExporter := 1 + run/2
|
|
maxInitialRoutePerPeer := 500 * run
|
|
maxRemovedRoutePerPeer := 100 * run
|
|
maxReaddedRoutePerPeer := 50 * run
|
|
t.Logf("Run %d. Exporters=%d, Peers=%d, Initial=max %d, Removed=max %d, Readded=max %d",
|
|
run, totalExporters, peerPerExporter,
|
|
maxInitialRoutePerPeer, maxRemovedRoutePerPeer, maxReaddedRoutePerPeer)
|
|
|
|
r := newRIB()
|
|
type lookup struct {
|
|
peer uint32
|
|
addr netip.Addr
|
|
nextHop netip.Addr
|
|
rd RD
|
|
asn uint32
|
|
removed bool
|
|
comment string
|
|
}
|
|
// We store all lookups that should succeed
|
|
lookups := []lookup{}
|
|
removeLookup := func(lookup lookup, comment string) {
|
|
for idx := range lookups {
|
|
if lookups[idx].peer != lookup.peer {
|
|
continue
|
|
}
|
|
if lookups[idx].addr != lookup.addr || lookups[idx].rd != lookup.rd {
|
|
continue
|
|
}
|
|
if lookups[idx].removed {
|
|
continue
|
|
}
|
|
lookups[idx].removed = true
|
|
lookups[idx].comment = fmt.Sprintf("%s; %s", lookups[idx].comment, comment)
|
|
break
|
|
}
|
|
}
|
|
|
|
peers := []uint32{}
|
|
for i := range totalExporters {
|
|
for j := range peerPerExporter {
|
|
peer := uint32((i << 16) + int(j))
|
|
peers = append(peers, peer)
|
|
toAdd := random.IntN(maxInitialRoutePerPeer)
|
|
added := 0
|
|
for range toAdd {
|
|
lookup := lookup{
|
|
peer: peer,
|
|
addr: netip.MustParseAddr(fmt.Sprintf("2001:db8:f:%x::",
|
|
random.IntN(300))),
|
|
nextHop: netip.MustParseAddr(
|
|
fmt.Sprintf("2001:db8:c::%x", random.IntN(500))),
|
|
rd: RD(random.IntN(3)),
|
|
asn: uint32(random.IntN(1000)),
|
|
comment: "added during first pass",
|
|
}
|
|
added += r.AddPrefix(netip.PrefixFrom(lookup.addr, 64),
|
|
route{
|
|
peer: peer,
|
|
nlri: r.nlris.Put(nlri{rd: lookup.rd}),
|
|
nextHop: r.nextHops.Put(nextHop(lookup.nextHop)),
|
|
attributes: r.rtas.Put(routeAttributes{
|
|
asn: lookup.asn,
|
|
}),
|
|
})
|
|
removeLookup(lookup, fmt.Sprintf("erased by NH: %s, ASN: %d", lookup.nextHop, lookup.asn))
|
|
lookups = append(lookups, lookup)
|
|
}
|
|
t.Logf("Run %d: added = %d/%d", run, added, toAdd)
|
|
|
|
toRemove := random.IntN(maxRemovedRoutePerPeer)
|
|
removed := 0
|
|
for range toRemove {
|
|
prefix := netip.MustParseAddr(fmt.Sprintf("2001:db8:f:%x::",
|
|
random.IntN(300)))
|
|
rd := RD(random.IntN(4))
|
|
if nlriRef, ok := r.nlris.Ref(nlri{
|
|
rd: rd,
|
|
}); ok {
|
|
removed += r.RemovePrefix(netip.PrefixFrom(prefix, 64),
|
|
route{
|
|
peer: peer,
|
|
nlri: nlriRef,
|
|
})
|
|
removeLookup(lookup{
|
|
peer: peer,
|
|
addr: prefix,
|
|
rd: rd,
|
|
}, "removed during second pass")
|
|
}
|
|
}
|
|
t.Logf("Run %d: removed = %d/%d", run, removed, toRemove)
|
|
|
|
toAdd = random.IntN(maxReaddedRoutePerPeer)
|
|
added = 0
|
|
for range toAdd {
|
|
lookup := lookup{
|
|
peer: peer,
|
|
addr: netip.MustParseAddr(fmt.Sprintf("2001:db8:f:%x::",
|
|
random.IntN(300))),
|
|
nextHop: netip.MustParseAddr(
|
|
fmt.Sprintf("2001:db8:c::%x", random.Uint32()%500)),
|
|
asn: uint32(random.IntN(1010)),
|
|
comment: "added during third pass",
|
|
}
|
|
added += r.AddPrefix(netip.PrefixFrom(lookup.addr, 64),
|
|
route{
|
|
peer: peer,
|
|
nlri: r.nlris.Put(nlri{}),
|
|
nextHop: r.nextHops.Put(nextHop(lookup.nextHop)),
|
|
attributes: r.rtas.Put(routeAttributes{
|
|
asn: lookup.asn,
|
|
}),
|
|
})
|
|
removeLookup(lookup, fmt.Sprintf("erased by NH: %s, ASN: %d", lookup.nextHop, lookup.asn))
|
|
lookups = append(lookups, lookup)
|
|
}
|
|
t.Logf("Run %d: readedd = %d/%d", run, added, toAdd)
|
|
}
|
|
}
|
|
|
|
removed := 0
|
|
for _, lookup := range lookups {
|
|
if lookup.removed {
|
|
removed++
|
|
continue
|
|
}
|
|
// Find prefix in tree
|
|
prefixIdx, ok := r.tree.Lookup(lookup.addr)
|
|
if !ok {
|
|
t.Errorf("cannot find %s for %d",
|
|
lookup.addr, lookup.peer)
|
|
continue
|
|
}
|
|
|
|
// Check if routes exist for this prefix
|
|
found := false
|
|
routeFound := false
|
|
|
|
for route := range r.iterateRoutesForPrefixIndex(prefixIdx) {
|
|
routeFound = true // At least one route exists
|
|
if r.nextHops.Get(route.nextHop) != nextHop(lookup.nextHop) || r.nlris.Get(route.nlri).rd != lookup.rd {
|
|
continue
|
|
}
|
|
if r.rtas.Get(route.attributes).asn != lookup.asn {
|
|
continue
|
|
}
|
|
found = true
|
|
break
|
|
}
|
|
|
|
if !routeFound {
|
|
t.Errorf("no routes found for %s for %d",
|
|
lookup.addr, lookup.peer)
|
|
continue
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("cannot find %s for peer %d; NH: %s, RD: %s, ASN: %d, comment: %s",
|
|
lookup.addr, lookup.peer,
|
|
lookup.nextHop, lookup.rd, lookup.asn, lookup.comment)
|
|
t.Logf("> available routes in tree for %s:", lookup.addr)
|
|
for route := range r.iterateRoutesForPrefixIndex(prefixIdx) {
|
|
t.Logf(" peer %d, NH: %s, RD: %s, ASN: %d",
|
|
route.peer,
|
|
netip.Addr(r.nextHops.Get(route.nextHop)),
|
|
r.nlris.Get(route.nlri).rd, r.rtas.Get(route.attributes).asn)
|
|
}
|
|
t.Logf("> route history for prefix %s:", lookup.addr)
|
|
for _, olookup := range lookups {
|
|
if lookup.addr != olookup.addr {
|
|
continue
|
|
}
|
|
t.Logf(" peer: %d, NH: %s, RD: %s, ASN: %d, comment: %s",
|
|
olookup.peer, olookup.nextHop, olookup.rd, olookup.asn, olookup.comment)
|
|
}
|
|
if run == 1 {
|
|
if testing.Verbose() {
|
|
t.Log("> complete history:")
|
|
for _, olookup := range lookups {
|
|
t.Logf(" prefix: %s, peer: %d, NH: %s, RD: %s, ASN: %d comment: %s",
|
|
olookup.addr,
|
|
olookup.peer, olookup.nextHop, olookup.rd, olookup.asn, olookup.comment)
|
|
}
|
|
} else {
|
|
t.Log("> complete history available in verbose mode")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if removed < 5 {
|
|
t.Error("did not remove more than 5 prefixes, suspicious...")
|
|
}
|
|
|
|
// Remove everything
|
|
for _, peer := range peers {
|
|
r.FlushPeer(peer)
|
|
}
|
|
|
|
// Check for leak of interned values
|
|
if r.nlris.Len() > 0 {
|
|
t.Errorf("%d NLRIs have leaked", r.nlris.Len())
|
|
}
|
|
if r.nextHops.Len() > 0 {
|
|
t.Errorf("%d next hops have leaked", r.nextHops.Len())
|
|
}
|
|
if r.rtas.Len() > 0 {
|
|
t.Errorf("%d route attributes have leaked", r.rtas.Len())
|
|
}
|
|
|
|
if t.Failed() {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkRTAHash(b *testing.B) {
|
|
rta := routeAttributes{
|
|
asn: 2038,
|
|
asPath: []uint32{1, 2, 3, 4, 5, 6, 7},
|
|
}
|
|
for b.Loop() {
|
|
rta.Hash()
|
|
}
|
|
}
|
|
|
|
func BenchmarkRTAEqual(b *testing.B) {
|
|
rta := routeAttributes{
|
|
asn: 2038,
|
|
asPath: []uint32{1, 2, 3, 4, 5, 6, 7},
|
|
}
|
|
for b.Loop() {
|
|
rta.Equal(rta)
|
|
}
|
|
}
|