Skip to content

Commit 4e5adaa

Browse files
authored
Periodically sync permanent neighbors to ensure route correctness (#7238) (#7257)
In the current implementation, permanent neighbors are installed only once at startup. However, these neighbors are critical for the functionality of routes managed by antrea-agent. If they are accidentally deleted, the affected routes will break and remain non-functional until antrea-agent is restarted. This commit adds periodic syncing of permanent neighbors to ensure they are reinstalled automatically if missing, improving the robustness and reliability of route management. Signed-off-by: Hongliang Liu <[email protected]>
1 parent d60c370 commit 4e5adaa

File tree

4 files changed

+107
-1
lines changed

4 files changed

+107
-1
lines changed

pkg/agent/route/route_linux.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,11 @@ func (c *Client) syncIPInfra() {
291291
if err := c.syncRoute(); err != nil {
292292
klog.ErrorS(err, "Failed to sync route")
293293
}
294-
klog.V(3).Info("Successfully synced iptables, ipset and route")
294+
if err := c.syncNeighbor(); err != nil {
295+
klog.ErrorS(err, "Failed to sync neighbor")
296+
}
297+
298+
klog.V(3).Info("Successfully synced iptables, ipset, route and neighbor")
295299
}
296300

297301
type routeKey struct {
@@ -392,6 +396,56 @@ func (c *Client) syncRoute() error {
392396
return nil
393397
}
394398

399+
type neighborKey struct {
400+
ip string
401+
mac string
402+
}
403+
404+
// syncNeighbor ensures that necessary neighbors exist on the Antrea gateway interface, as some routes managed by Antrea
405+
// depend on these neighbors.
406+
func (c *Client) syncNeighbor() error {
407+
msg := netlink.Ndmsg{
408+
Family: netlink.FAMILY_ALL,
409+
Index: uint32(c.nodeConfig.GatewayConfig.LinkIndex),
410+
State: netlink.NUD_PERMANENT,
411+
}
412+
neighborList, err := c.netlink.NeighListExecute(msg)
413+
if err != nil {
414+
return err
415+
}
416+
neighborKeys := sets.New[neighborKey]()
417+
for i := range neighborList {
418+
n := neighborList[i]
419+
neighborKeys.Insert(neighborKey{
420+
ip: n.IP.String(),
421+
mac: n.HardwareAddr.String(),
422+
})
423+
}
424+
restoreNeighbor := func(neighbor *netlink.Neigh) bool {
425+
if neighborKeys.Has(neighborKey{
426+
ip: neighbor.IP.String(),
427+
mac: neighbor.HardwareAddr.String(),
428+
}) {
429+
return true
430+
}
431+
if err := c.netlink.NeighSet(neighbor); err != nil {
432+
klog.ErrorS(err, "failed to sync neighbor", "Neighbor", neighbor)
433+
return false
434+
}
435+
return true
436+
}
437+
c.nodeNeighbors.Range(func(_, v interface{}) bool {
438+
return restoreNeighbor(v.(*netlink.Neigh))
439+
})
440+
if c.proxyAll {
441+
c.serviceNeighbors.Range(func(_, v interface{}) bool {
442+
return restoreNeighbor(v.(*netlink.Neigh))
443+
})
444+
}
445+
446+
return nil
447+
}
448+
395449
// syncIPSet ensures that the required ipset exists, and it has the initial members.
396450
func (c *Client) syncIPSet() error {
397451
// Create the ipsets to store all Pod CIDRs for constructing full-mesh routing in encap/noEncap/hybrid modes. In

pkg/agent/route/route_linux_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,41 @@ func TestSyncRoutes(t *testing.T) {
115115
assert.NoError(t, c.syncRoute())
116116
}
117117

118+
func TestSyncNeighbors(t *testing.T) {
119+
ctrl := gomock.NewController(t)
120+
mockNetlink := netlinktest.NewMockInterface(ctrl)
121+
122+
c := &Client{
123+
netlink: mockNetlink,
124+
proxyAll: true,
125+
nodeNeighbors: sync.Map{},
126+
serviceNeighbors: sync.Map{},
127+
nodeConfig: &config.NodeConfig{
128+
GatewayConfig: &config.GatewayConfig{LinkIndex: 10, IPv4: net.ParseIP("192.168.0.1"), IPv6: net.ParseIP("aabb:ccdd::1")},
129+
PodIPv4CIDR: ip.MustParseCIDR("192.168.0.0/24"),
130+
PodIPv6CIDR: ip.MustParseCIDR("aabb:ccdd::/64"),
131+
},
132+
}
133+
134+
tamperedMAC, _ := net.ParseMAC("de:ad:be:ef:12:34")
135+
tamperedNodeNeighbor1 := &netlink.Neigh{LinkIndex: 10, Family: netlink.FAMILY_V6, State: netlink.NUD_PERMANENT, IP: net.ParseIP("aabb:ccee::1"), HardwareAddr: tamperedMAC}
136+
nodeNeighbor1 := &netlink.Neigh{LinkIndex: 10, Family: netlink.FAMILY_V6, State: netlink.NUD_PERMANENT, IP: net.ParseIP("aabb:ccee::1"), HardwareAddr: globalVMAC}
137+
nodeNeighbor2 := &netlink.Neigh{LinkIndex: 10, Family: netlink.FAMILY_V6, State: netlink.NUD_PERMANENT, IP: net.ParseIP("aabb:ccdd::1"), HardwareAddr: globalVMAC}
138+
serviceNeighbor1 := &netlink.Neigh{LinkIndex: 10, Family: netlink.FAMILY_V4, State: netlink.NUD_PERMANENT, IP: config.VirtualServiceIPv4, HardwareAddr: globalVMAC}
139+
serviceNeighbor2 := &netlink.Neigh{LinkIndex: 10, Family: netlink.FAMILY_V6, State: netlink.NUD_PERMANENT, IP: config.VirtualServiceIPv6, HardwareAddr: globalVMAC}
140+
mockNetlink.EXPECT().NeighListExecute(netlink.Ndmsg{Family: netlink.FAMILY_ALL, Index: 10, State: netlink.NUD_PERMANENT}).Return([]netlink.Neigh{*tamperedNodeNeighbor1, *serviceNeighbor1}, nil)
141+
mockNetlink.EXPECT().NeighSet(nodeNeighbor1)
142+
mockNetlink.EXPECT().NeighSet(nodeNeighbor2)
143+
mockNetlink.EXPECT().NeighSet(serviceNeighbor2)
144+
145+
c.nodeNeighbors.Store("aabb:ccee::1", nodeNeighbor1)
146+
c.nodeNeighbors.Store("aabb:ccdd::1", nodeNeighbor2)
147+
c.serviceNeighbors.Store(config.VirtualServiceIPv4.String(), serviceNeighbor1)
148+
c.serviceNeighbors.Store(config.VirtualServiceIPv6.String(), serviceNeighbor2)
149+
150+
assert.NoError(t, c.syncNeighbor())
151+
}
152+
118153
func TestRestoreEgressRoutesAndRules(t *testing.T) {
119154
ctrl := gomock.NewController(t)
120155
mockNetlink := netlinktest.NewMockInterface(ctrl)

pkg/agent/util/netlink/netlink_linux.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ type Interface interface {
4646

4747
NeighList(linkIndex, family int) ([]netlink.Neigh, error)
4848

49+
NeighListExecute(msg netlink.Ndmsg) ([]netlink.Neigh, error)
50+
4951
NeighSet(neigh *netlink.Neigh) error
5052

5153
NeighDel(neigh *netlink.Neigh) error

pkg/agent/util/netlink/testing/mock_netlink_linux.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)