Skip to content

Commit

Permalink
Add banchmarks for RouteListFiltered variants.
Browse files Browse the repository at this point in the history
  • Loading branch information
fasaxc committed Jan 3, 2024
1 parent 15f24e5 commit 59ee150
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 2 deletions.
4 changes: 2 additions & 2 deletions netlink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import (

type tearDownNetlinkTest func()

func skipUnlessRoot(t *testing.T) {
func skipUnlessRoot(t testing.TB) {
t.Helper()

if os.Getuid() != 0 {
t.Skip("Test requires root privileges.")
}
}

func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
func setUpNetlinkTest(t testing.TB) tearDownNetlinkTest {
skipUnlessRoot(t)

// new temporary namespace so we don't pollute the host
Expand Down
171 changes: 171 additions & 0 deletions route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package netlink
import (
"net"
"os"
"runtime"
"strconv"
"testing"
"time"
Expand Down Expand Up @@ -875,6 +876,176 @@ func TestRouteFilterIterCanStop(t *testing.T) {
}
}

func BenchmarkRouteListFilteredOld(b *testing.B) {
tearDown := setUpNetlinkTest(b)
defer tearDown()

link, err := setUpRoutesBench(b)

b.ResetTimer()
b.ReportAllocs()
var routes []Route
for i := 0; i < b.N; i++ {
routes, err = pkgHandle.RouteListFilteredOld(FAMILY_V4, &Route{
LinkIndex: link.Attrs().Index,
}, RT_FILTER_OIF)
if err != nil {
b.Fatal(err)
}
if len(routes) != 65535 {
b.Fatal("Incorrect number of routes.", len(routes))
}
}
runtime.KeepAlive(routes)
}

func BenchmarkRouteListFilteredNew(b *testing.B) {
tearDown := setUpNetlinkTest(b)
defer tearDown()

link, err := setUpRoutesBench(b)

b.ResetTimer()
b.ReportAllocs()
var routes []Route
for i := 0; i < b.N; i++ {
routes, err = pkgHandle.RouteListFiltered(FAMILY_V4, &Route{
LinkIndex: link.Attrs().Index,
}, RT_FILTER_OIF)
if err != nil {
b.Fatal(err)
}
if len(routes) != 65535 {
b.Fatal("Incorrect number of routes.", len(routes))
}
}
runtime.KeepAlive(routes)
}

// RouteListFiltered gets a list of routes in the system filtered with specified rules.
// All rules must be defined in RouteFilter struct
func (h *Handle) RouteListFilteredOld(family int, filter *Route, filterMask uint64) ([]Route, error) {
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
rtmsg := &nl.RtMsg{}
rtmsg.Family = uint8(family)
msgs, err := h.routeHandle(filter, req, rtmsg)
if err != nil {
return nil, err
}

var res []Route
for _, m := range msgs {
msg := nl.DeserializeRtMsg(m)
if msg.Flags&unix.RTM_F_CLONED != 0 {
// Ignore cloned routes
continue
}
if msg.Table != unix.RT_TABLE_MAIN {
if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
// Ignore non-main tables
continue
}
}
route, err := deserializeRoute(m)
if err != nil {
return nil, err
}
if filter != nil {
switch {
case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
continue
case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
continue
case filterMask&RT_FILTER_SCOPE != 0 && route.Scope != filter.Scope:
continue
case filterMask&RT_FILTER_TYPE != 0 && route.Type != filter.Type:
continue
case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos:
continue
case filterMask&RT_FILTER_REALM != 0 && route.Realm != filter.Realm:
continue
case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex:
continue
case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex:
continue
case filterMask&RT_FILTER_GW != 0 && !route.Gw.Equal(filter.Gw):
continue
case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src):
continue
case filterMask&RT_FILTER_DST != 0:
if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) {
if filter.Dst == nil {
filter.Dst = genZeroIPNet(family)
}
if !ipNetEqual(route.Dst, filter.Dst) {
continue
}
}
case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit:
continue
}
}
res = append(res, route)
}
return res, nil
}

func BenchmarkRouteListIter(b *testing.B) {
tearDown := setUpNetlinkTest(b)
defer tearDown()

link, err := setUpRoutesBench(b)

b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var routes int
err = RouteListFilteredIter(FAMILY_V4, &Route{
LinkIndex: link.Attrs().Index,
}, RT_FILTER_OIF, func(route Route) (cont bool) {
routes++
return true
})
if err != nil {
b.Fatal(err)
}
if routes != 65535 {
b.Fatal("Incorrect number of routes.", routes)
}
}
}

func setUpRoutesBench(b *testing.B) (Link, error) {
// get loopback interface
link, err := LinkByName("lo")
if err != nil {
b.Fatal(err)
}
// bring the interface up
if err = LinkSetUp(link); err != nil {
b.Fatal(err)
}

// add a gateway route
for i := 0; i < 65535; i++ {
dst := &net.IPNet{
IP: net.IPv4(1, 1, byte(i>>8), byte(i&0xff)),
Mask: net.CIDRMask(32, 32),
}
route := Route{
LinkIndex: link.Attrs().Index,
Dst: dst,
Scope: unix.RT_SCOPE_LINK,
Priority: 10,
Type: unix.RTN_UNICAST,
}
if err := RouteAdd(&route); err != nil {
b.Fatal(err)
}
}
return link, err
}

func tableIDIn(ids []int, id int) bool {
for _, v := range ids {
if v == id {
Expand Down

0 comments on commit 59ee150

Please sign in to comment.