mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
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)
158 lines
4.9 KiB
Go
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)
|
|
}
|