Skip to content

Commit 93d197c

Browse files
LionelJouinsqueed
authored andcommitted
VRF: Wait for the local/host routes to be added
Without waiting for the local/host routes to be added by the kernel after the IP address is being added to an interface. The routes requiring the local/host routes may failed. This caused flaky e2e tests, but could also happen during the execution of the VRF plugin when the IPv6 addresses were being re-added to the interface and when the route were being moved to the VRF table. Signed-off-by: Lionel Jouin <[email protected]>
1 parent c52e02b commit 93d197c

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

plugins/meta/vrf/vrf.go

+34-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package main
1717
import (
1818
"fmt"
1919
"math"
20+
"net"
21+
"time"
2022

2123
"github.com/vishvananda/netlink"
2224
)
@@ -124,7 +126,7 @@ func addInterface(vrf *netlink.Vrf, intf string) error {
124126

125127
afterAddresses, err := netlink.AddrList(i, netlink.FAMILY_V6)
126128
if err != nil {
127-
return fmt.Errorf("failed getting ipv6 new addresses for %s", intf)
129+
return fmt.Errorf("failed getting ipv6 new addresses for %s: %v", intf, err)
128130
}
129131

130132
// Since keeping the ipv6 address depends on net.ipv6.conf.all.keep_addr_on_down ,
@@ -141,6 +143,37 @@ CONTINUE:
141143
if err != nil {
142144
return fmt.Errorf("could not restore address %s to %s @ %s: %v", toFind, intf, vrf.Name, err)
143145
}
146+
147+
// Waits for local/host routes to be added by the kernel.
148+
maxRetry := 10
149+
for {
150+
routesVRFTable, err := netlink.RouteListFiltered(
151+
netlink.FAMILY_ALL,
152+
&netlink.Route{
153+
Dst: &net.IPNet{
154+
IP: toFind.IP,
155+
Mask: net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
156+
},
157+
Table: int(vrf.Table),
158+
LinkIndex: i.Attrs().Index,
159+
},
160+
netlink.RT_FILTER_OIF|netlink.RT_FILTER_TABLE|netlink.RT_FILTER_DST,
161+
)
162+
if err != nil {
163+
return fmt.Errorf("failed getting routes for %s table %d for dst %s: %v", intf, vrf.Table, toFind.IPNet.String(), err)
164+
}
165+
166+
if len(routesVRFTable) >= 1 {
167+
break
168+
}
169+
170+
maxRetry--
171+
if maxRetry <= 0 {
172+
return fmt.Errorf("failed getting local/host addresses for %s in table %d with dst %s", intf, vrf.Table, toFind.IPNet.String())
173+
}
174+
175+
time.Sleep(10 * time.Millisecond)
176+
}
144177
}
145178

146179
// Apply all saved routes for the interface that was moved to the VRF

plugins/meta/vrf/vrf_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"net"
2121
"strings"
22+
"time"
2223

2324
. "github.com/onsi/ginkgo/v2"
2425
. "github.com/onsi/gomega"
@@ -207,6 +208,18 @@ var _ = Describe("vrf plugin", func() {
207208
// Add IP addresses for network reachability
208209
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
209210
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
211+
// Wait for the corresponding route to be addeded
212+
Eventually(func() bool {
213+
ipv6RouteDst := &net.IPNet{
214+
IP: ipv6.IP,
215+
Mask: net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
216+
}
217+
routes, _ := netlink.RouteListFiltered(netlink.FAMILY_ALL, &netlink.Route{
218+
Dst: ipv6RouteDst,
219+
Table: 0,
220+
}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
221+
return err == nil && len(routes) >= 1
222+
}, time.Second, 500*time.Millisecond).Should(BeTrue())
210223

211224
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
212225
Expect(err).NotTo(HaveOccurred())
@@ -304,6 +317,18 @@ var _ = Describe("vrf plugin", func() {
304317
// Add IP addresses for network reachability
305318
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
306319
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
320+
// Wait for the corresponding route to be addeded
321+
Eventually(func() bool {
322+
ipv6RouteDst := &net.IPNet{
323+
IP: ipv6.IP,
324+
Mask: net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
325+
}
326+
routes, _ := netlink.RouteListFiltered(netlink.FAMILY_ALL, &netlink.Route{
327+
Dst: ipv6RouteDst,
328+
Table: 0,
329+
}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
330+
return err == nil && len(routes) >= 1
331+
}, time.Second, 500*time.Millisecond).Should(BeTrue())
307332

308333
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
309334
Expect(err).NotTo(HaveOccurred())
@@ -362,6 +387,18 @@ var _ = Describe("vrf plugin", func() {
362387
// Add IP addresses for network reachability
363388
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
364389
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
390+
// Wait for the corresponding route to be addeded
391+
Eventually(func() bool {
392+
ipv6RouteDst := &net.IPNet{
393+
IP: ipv6.IP,
394+
Mask: net.IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
395+
}
396+
routes, _ := netlink.RouteListFiltered(netlink.FAMILY_ALL, &netlink.Route{
397+
Dst: ipv6RouteDst,
398+
Table: 0,
399+
}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
400+
return err == nil && len(routes) >= 1
401+
}, time.Second, 500*time.Millisecond).Should(BeTrue())
365402

366403
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
367404
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)