Skip to content

Commit b0e5168

Browse files
authored
Periodically sync permanent neighbors to ensure route correctness (#7238) (#7259)
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 493c5d0 commit b0e5168

File tree

4 files changed

+108
-2
lines changed

4 files changed

+108
-2
lines changed

pkg/agent/route/route_linux.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,11 @@ func (c *Client) syncIPInfra() {
278278
if err := c.syncRoute(); err != nil {
279279
klog.ErrorS(err, "Failed to sync route")
280280
}
281-
klog.V(3).Info("Successfully synced iptables, ipset and route")
281+
if err := c.syncNeighbor(); err != nil {
282+
klog.ErrorS(err, "Failed to sync neighbor")
283+
}
284+
285+
klog.V(3).Info("Successfully synced iptables, ipset, route and neighbor")
282286
}
283287

284288
type routeKey struct {
@@ -379,6 +383,56 @@ func (c *Client) syncRoute() error {
379383
return nil
380384
}
381385

386+
type neighborKey struct {
387+
ip string
388+
mac string
389+
}
390+
391+
// syncNeighbor ensures that necessary neighbors exist on the Antrea gateway interface, as some routes managed by Antrea
392+
// depend on these neighbors.
393+
func (c *Client) syncNeighbor() error {
394+
msg := netlink.Ndmsg{
395+
Family: netlink.FAMILY_ALL,
396+
Index: uint32(c.nodeConfig.GatewayConfig.LinkIndex),
397+
State: netlink.NUD_PERMANENT,
398+
}
399+
neighborList, err := c.netlink.NeighListExecute(msg)
400+
if err != nil {
401+
return err
402+
}
403+
neighborKeys := sets.New[neighborKey]()
404+
for i := range neighborList {
405+
n := neighborList[i]
406+
neighborKeys.Insert(neighborKey{
407+
ip: n.IP.String(),
408+
mac: n.HardwareAddr.String(),
409+
})
410+
}
411+
restoreNeighbor := func(neighbor *netlink.Neigh) bool {
412+
if neighborKeys.Has(neighborKey{
413+
ip: neighbor.IP.String(),
414+
mac: neighbor.HardwareAddr.String(),
415+
}) {
416+
return true
417+
}
418+
if err := c.netlink.NeighSet(neighbor); err != nil {
419+
klog.ErrorS(err, "failed to sync neighbor", "Neighbor", neighbor)
420+
return false
421+
}
422+
return true
423+
}
424+
c.nodeNeighbors.Range(func(_, v interface{}) bool {
425+
return restoreNeighbor(v.(*netlink.Neigh))
426+
})
427+
if c.proxyAll {
428+
c.serviceNeighbors.Range(func(_, v interface{}) bool {
429+
return restoreNeighbor(v.(*netlink.Neigh))
430+
})
431+
}
432+
433+
return nil
434+
}
435+
382436
// syncIPSet ensures that the required ipset exists, and it has the initial members.
383437
func (c *Client) syncIPSet() error {
384438
// 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
@@ -114,6 +114,41 @@ func TestSyncRoutes(t *testing.T) {
114114
assert.NoError(t, c.syncRoute())
115115
}
116116

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

0 commit comments

Comments
 (0)