Skip to content

Commit 78a94d4

Browse files
committed
Refactor routemanager
For a number of reasons: 1. Performance With BGP the number of routes that can be installed on the system scales up. Tests with > 1500 routes causes trouble. The current sync implementation has exponential loops. On each iteration, RouteListFiltered is called which dumps all the routes on the system and then filters client side. netlink API is by value, and this causes high GC crunch. Changed sync implementation to have sequential loops and a single list call to netlink. Changed to avoid listing routes in any other case. sinc is still a heavy operation that keeps a lock and migh require further optimizations. This is a first take. 2. Consistency The used RoutePartiallyEqual had a different criteria than what was used to actually delete a route from netlink, leaving the door open for inconsistencies. This could be thought of as a compromise due to the fact that routes can assume different defaults when installed than those provided. Proposal is to do a bit better and ignore those defaults when comparing against kernel routes as a unified criteria. Should fulfill our use cases but might need further tweaking in the future. Potential problem is that kernel switches bad an incorrect value to default instead of throwing us an error which can cause a route to constantly sync. Much of this is undocumented as far as I could tell but anyway has not been observed with the specific routes that we install. Also, the current implementation was validating and indexing by link index which is actually not a required field of a route. Instead, key routes by priority, prefix and table. Route manager assumes ownership of all the routes with any of the provided keys and will delete unrecognized routes on sync. This is inline to what our previous netlink delete was doing. 3. Other * Reset ticker on each sync iteration to avoid backlogging. * Cleaned up excessive logging Signed-off-by: Jaime Caamaño Ruiz <[email protected]>
1 parent 8777b58 commit 78a94d4

File tree

6 files changed

+395
-309
lines changed

6 files changed

+395
-309
lines changed

go-controller/pkg/node/controllers/egressip/egressip.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ func routeDifference(routesA, routesB []netlink.Route) []netlink.Route {
13321332
for _, routeA := range routesA {
13331333
found = false
13341334
for _, routeB := range routesB {
1335-
if routemanager.RoutePartiallyEqual(routeA, routeB) {
1335+
if util.RouteEqual(&routeA, &routeB) {
13361336
found = true
13371337
break
13381338
}

go-controller/pkg/node/controllers/egressip/egressip_test.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1699,10 +1699,21 @@ func getNetlinkAddr(ip, netmask string) *netlink.Addr {
16991699
// containsRoutes returns true if routes in routes1 are presents in routes routes2
17001700
func containsRoutes(routes1 []netlink.Route, routes2 []netlink.Route) bool {
17011701
var found bool
1702+
eq := func(route1, route2 netlink.Route) bool {
1703+
// normalize fields that we don't set explicitly and just get set once
1704+
// the route is installed
1705+
if route1.Family == netlink.FAMILY_ALL {
1706+
route1.Family = route2.Family
1707+
}
1708+
if route1.Protocol == unix.RTPROT_UNSPEC {
1709+
route1.Protocol = route2.Protocol
1710+
}
1711+
return util.RouteEqual(&route1, &route2)
1712+
}
17021713
for _, route1 := range routes1 {
17031714
found = false
17041715
for _, route2 := range routes2 {
1705-
if routemanager.RoutePartiallyEqual(route1, route2) {
1716+
if eq(route1, route2) {
17061717
found = true
17071718
break
17081719
}

go-controller/pkg/node/gateway_init_linux_test.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,8 +1756,7 @@ var _ = Describe("Gateway unit tests", func() {
17561756
netlinkMock.On("LinkByName", lnkAttr.Name).Return(lnk, nil)
17571757
netlinkMock.On("LinkByIndex", lnkAttr.Index).Return(lnk, nil)
17581758
netlinkMock.On("LinkSetUp", mock.Anything).Return(nil)
1759-
netlinkMock.On("RouteListFiltered", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
1760-
netlinkMock.On("RouteAdd", mock.Anything, mock.Anything, mock.Anything).Return(nil)
1759+
netlinkMock.On("RouteReplace", mock.Anything, mock.Anything, mock.Anything).Return(nil)
17611760
wg := &sync.WaitGroup{}
17621761
rm := routemanager.NewController()
17631762
util.SetNetLinkOpMockInst(netlinkMock)
@@ -1786,29 +1785,20 @@ var _ = Describe("Gateway unit tests", func() {
17861785
Name: "ens1f0",
17871786
Index: 5,
17881787
}
1789-
previousRoute := &netlink.Route{
1790-
Dst: ipnet,
1791-
LinkIndex: 5,
1792-
Scope: netlink.SCOPE_UNIVERSE,
1793-
Gw: gwIPs[0],
1794-
MTU: config.Default.MTU - 100,
1795-
Src: srcIP,
1796-
}
1797-
17981788
expectedRoute := &netlink.Route{
17991789
Dst: ipnet,
18001790
LinkIndex: 5,
18011791
Scope: netlink.SCOPE_UNIVERSE,
18021792
Gw: gwIPs[0],
18031793
MTU: config.Default.MTU,
18041794
Src: srcIP,
1795+
Table: syscall.RT_TABLE_MAIN,
18051796
}
18061797

18071798
lnk.On("Attrs").Return(lnkAttr)
18081799
netlinkMock.On("LinkByName", lnkAttr.Name).Return(lnk, nil)
18091800
netlinkMock.On("LinkByIndex", lnkAttr.Index).Return(lnk, nil)
18101801
netlinkMock.On("LinkSetUp", mock.Anything).Return(nil)
1811-
netlinkMock.On("RouteListFiltered", mock.Anything, mock.Anything, mock.Anything).Return([]netlink.Route{*previousRoute}, nil)
18121802
netlinkMock.On("RouteReplace", expectedRoute).Return(nil)
18131803
wg := &sync.WaitGroup{}
18141804
rm := routemanager.NewController()

0 commit comments

Comments
 (0)