Files
akvorado/outlet/routing/provider/bmp/tests.go
Vincent Bernat 92ee2e05b7 outlet/routing: use gaissmai/bart instead of kentik/patricia
For each prefix, list of routes is stored into a map (like what is done
with kentik/patricia). The benchmark shows an improvement, both in
insertion time and in memory.

Before:

```
goos: linux
goarch: amd64
pkg: akvorado/outlet/routing/provider/bmp
cpu: AMD Ryzen 5 5600X 6-Core Processor
BenchmarkRandomRealWorldRoutes4-12         10000               106.4 ns/route
BenchmarkRIBInsertion/1000_routes,_1_peers-12               2504               100.0 %ins              361.4 bytes/route               515.6 ns/route
BenchmarkRIBInsertion/1000_routes,_2_peers-12               1234               100.0 %ins              337.5 bytes/route               545.7 ns/route
BenchmarkRIBInsertion/1000_routes,_5_peers-12                412               100.0 %ins              377.6 bytes/route               646.9 ns/route
BenchmarkRIBInsertion/10000_routes,_1_peers-12               170                99.98 %ins             373.0 bytes/route               780.7 ns/route
BenchmarkRIBInsertion/10000_routes,_2_peers-12                52                99.99 %ins             373.2 bytes/route              1136 ns/route
BenchmarkRIBInsertion/10000_routes,_5_peers-12                13                99.99 %ins             299.8 bytes/route              1877 ns/route
BenchmarkRIBInsertion/100000_routes,_1_peers-12                4                99.84 %ins             300.0 bytes/route              2918 ns/route
BenchmarkRIBInsertion/100000_routes,_2_peers-12                2                99.83 %ins             300.2 bytes/route              5220 ns/route
BenchmarkRIBInsertion/100000_routes,_5_peers-12                1                99.81 %ins             340.4 bytes/route             22259 ns/route
BenchmarkRIBLookup/1000_routes,_1_peers-12                 56382               214.2 ns/op
BenchmarkRIBLookup/1000_routes,_2_peers-12                 52376               227.3 ns/op
BenchmarkRIBLookup/1000_routes,_5_peers-12                 46570               257.8 ns/op
BenchmarkRIBLookup/10000_routes,_1_peers-12                 4084               277.2 ns/op
BenchmarkRIBLookup/10000_routes,_2_peers-12                 3552               295.2 ns/op
BenchmarkRIBLookup/10000_routes,_5_peers-12                 3586               340.0 ns/op
BenchmarkRIBLookup/100000_routes,_1_peers-12                 300               382.2 ns/op
BenchmarkRIBLookup/100000_routes,_2_peers-12                 240               474.1 ns/op
BenchmarkRIBLookup/100000_routes,_5_peers-12                 156               752.9 ns/op
BenchmarkRIBFlush/1000_routes,_1_peers-12                   8642                 0.1422 ms/op
BenchmarkRIBFlush/1000_routes,_2_peers-12                   4234                 0.2829 ms/op
BenchmarkRIBFlush/1000_routes,_5_peers-12                   1995                 0.5927 ms/op
BenchmarkRIBFlush/10000_routes,_1_peers-12                   807                 1.411 ms/op
BenchmarkRIBFlush/10000_routes,_2_peers-12                   360                 3.341 ms/op
BenchmarkRIBFlush/10000_routes,_5_peers-12                   166                 7.186 ms/op
BenchmarkRIBFlush/100000_routes,_1_peers-12                   58                20.85 ms/op
BenchmarkRIBFlush/100000_routes,_2_peers-12                   22                51.13 ms/op
BenchmarkRIBFlush/100000_routes,_5_peers-12                    8               135.5 ms/op
```

After:

```
goos: linux
goarch: amd64
pkg: akvorado/outlet/routing/provider/bmp
cpu: AMD Ryzen 5 5600X 6-Core Processor
BenchmarkRandomRealWorldRoutes4-12         10000               110.2 ns/route
BenchmarkRIBInsertion/1000_routes,_1_peers-12               2299               100.0 %ins              348.7 bytes/route               578.4 ns/route
BenchmarkRIBInsertion/1000_routes,_2_peers-12               1112               100.0 %ins              328.7 bytes/route               579.0 ns/route
BenchmarkRIBInsertion/1000_routes,_5_peers-12                432               100.0 %ins              279.7 bytes/route               615.6 ns/route
BenchmarkRIBInsertion/10000_routes,_1_peers-12               182                99.98 %ins             278.1 bytes/route               722.5 ns/route
BenchmarkRIBInsertion/10000_routes,_2_peers-12                61                99.99 %ins             273.0 bytes/route              1013 ns/route
BenchmarkRIBInsertion/10000_routes,_5_peers-12                14                99.99 %ins             232.4 bytes/route              1717 ns/route
BenchmarkRIBInsertion/100000_routes,_1_peers-12                4                99.84 %ins             228.3 bytes/route              2857 ns/route
BenchmarkRIBInsertion/100000_routes,_2_peers-12                2                99.83 %ins             214.3 bytes/route              4944 ns/route
BenchmarkRIBInsertion/100000_routes,_5_peers-12                1                99.81 %ins             265.4 bytes/route             22098 ns/route
BenchmarkRIBLookup/1000_routes,_1_peers-12                 61369               190.1 ns/op
BenchmarkRIBLookup/1000_routes,_2_peers-12                 64584               186.5 ns/op
BenchmarkRIBLookup/1000_routes,_5_peers-12                 63253               190.2 ns/op
BenchmarkRIBLookup/10000_routes,_1_peers-12                 5934               188.7 ns/op
BenchmarkRIBLookup/10000_routes,_2_peers-12                 5386               207.7 ns/op
BenchmarkRIBLookup/10000_routes,_5_peers-12                 5348               220.3 ns/op
BenchmarkRIBLookup/100000_routes,_1_peers-12                 516               227.1 ns/op
BenchmarkRIBLookup/100000_routes,_2_peers-12                 477               241.7 ns/op
BenchmarkRIBLookup/100000_routes,_5_peers-12                 428               264.2 ns/op
BenchmarkRIBFlush/1000_routes,_1_peers-12                   5246                 0.2294 ms/op
BenchmarkRIBFlush/1000_routes,_2_peers-12                   2984                 0.3965 ms/op
BenchmarkRIBFlush/1000_routes,_5_peers-12                   1406                 0.8498 ms/op
BenchmarkRIBFlush/10000_routes,_1_peers-12                   578                 2.084 ms/op
BenchmarkRIBFlush/10000_routes,_2_peers-12                   295                 3.988 ms/op
BenchmarkRIBFlush/10000_routes,_5_peers-12                   100                10.15 ms/op
BenchmarkRIBFlush/100000_routes,_1_peers-12                   33                30.82 ms/op
BenchmarkRIBFlush/100000_routes,_2_peers-12                   18                61.41 ms/op
BenchmarkRIBFlush/100000_routes,_5_peers-12                    7               158.4 ms/op
```

This is a 20% improvement on insertion, 30% on lookups, but 36%
degradation for flushing.

Fix #253

Next steps:
- test lockless updates (with *Persist functions)
2025-08-16 17:06:36 +02:00

158 lines
4.9 KiB
Go

// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only
//go:build !release
package bmp
import (
"fmt"
"net"
"net/netip"
"reflect"
"testing"
"akvorado/common/daemon"
"akvorado/common/helpers"
"akvorado/common/reporter"
"akvorado/outlet/routing/provider"
"github.com/benbjohnson/clock"
"github.com/osrg/gobgp/v3/pkg/packet/bgp"
"github.com/osrg/gobgp/v3/pkg/packet/bmp"
)
// NewMock creates a new mock provider for BMP (it's a real one
// listening to a random port).
func NewMock(t *testing.T, r *reporter.Reporter, conf provider.Configuration) (*Provider, *clock.Mock) {
t.Helper()
mockClock := clock.NewMock()
confP := conf.(Configuration)
confP.Listen = "127.0.0.1:0"
p, err := confP.New(r, Dependencies{
Daemon: daemon.NewMock(t),
Clock: mockClock,
})
if err != nil {
t.Fatalf("New() error:\n%+v", err)
}
return p.(*Provider), mockClock
}
// PopulateRIB populates the RIB with a few entries.
func (p *Provider) PopulateRIB(t *testing.T) {
t.Helper()
p.active.Store(true)
pinfo := p.addPeer(peerKey{
exporter: netip.MustParseAddrPort("[::ffff:127.0.0.1]:47389"),
ip: netip.MustParseAddr("::ffff:203.0.113.4"),
ptype: bmp.BMP_PEER_TYPE_GLOBAL,
asn: 64500,
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.0.2.0/123"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{family: bgp.RF_IPv4_UC, path: 1}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:198.51.100.4"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 174,
asPath: []uint32{64200, 1299, 174},
communities: []uint32{100, 200, 400},
largeCommunities: []bgp.LargeCommunity{{ASN: 64200, LocalData1: 2, LocalData2: 3}},
plen: 96 + 27,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.0.2.0/123"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{family: bgp.RF_IPv4_UC, path: 2}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:198.51.100.8"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 174,
asPath: []uint32{64200, 174, 174, 174},
communities: []uint32{100},
plen: 96 + 27,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.0.2.128/123"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{family: bgp.RF_IPv4_UC}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:198.51.100.8"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 1299,
asPath: []uint32{64200, 1299},
communities: []uint32{500},
plen: 96 + 27,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:1.0.0.0/120"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{family: bgp.RF_IPv4_UC}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:198.51.100.8"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 65300,
plen: 96 + 24,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/117"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{rd: 10, family: bgp.RF_IPv4_UC, path: 0}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:203.0.113.14"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 1234,
asPath: []uint32{54321, 1234},
plen: 96 + 21,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.168.144.0/118"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{rd: 10, family: bgp.RF_IPv4_UC, path: 0}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:203.0.113.15"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 1234,
asPath: []uint32{1234},
plen: 96 + 22,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.168.148.0/118"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{rd: 10, family: bgp.RF_IPv4_UC, path: 0}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:203.0.113.15"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 1234,
asPath: []uint32{1234},
plen: 96 + 22,
}),
})
p.rib.addPrefix(netip.MustParsePrefix("::ffff:192.168.148.1/128"), route{
peer: pinfo.reference,
nlri: p.rib.nlris.Put(nlri{rd: 10, family: bgp.RF_IPv4_UC, path: 0}),
nextHop: p.rib.nextHops.Put(nextHop(netip.MustParseAddr("::ffff:203.0.113.14"))),
attributes: p.rib.rtas.Put(routeAttributes{
asn: 1234,
asPath: []uint32{1234},
plen: 96 + 32,
}),
})
}
// LocalAddr returns the address the BMP collector is listening to.
func (p *Provider) LocalAddr() net.Addr {
return p.address
}
// Reduce hash mask to generate collisions during tests (this should
// be optimized out by the compiler)
const rtaHashMask = 0xff
// MustParseRD parse a route distinguisher and panic on error.
func MustParseRD(input string) RD {
var output RD
if err := output.UnmarshalText([]byte(input)); err != nil {
panic(err)
}
return output
}
func init() {
helpers.AddPrettyFormatter(reflect.TypeOf(route{}), fmt.Sprint)
}