Skip to content

Commit

Permalink
Fix Egress not working with kube-proxy IPVS strictARP mode
Browse files Browse the repository at this point in the history
Check the arp_ignore sysctl value of the transport interface
and start a userspace ARP responder if it has a value other
than 0.

Fixes: antrea-io#3804

Signed-off-by: Xu Liu <xliu2@vmware.com>
  • Loading branch information
xliuxu committed May 27, 2022
1 parent 5efac86 commit 41cccc1
Showing 1 changed file with 30 additions and 8 deletions.
38 changes: 30 additions & 8 deletions pkg/agent/ipassigner/ip_assigner_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"antrea.io/antrea/pkg/agent/ipassigner/responder"
"antrea.io/antrea/pkg/agent/util"
"antrea.io/antrea/pkg/agent/util/sysctl"
)

// ipAssigner creates a dummy device and assigns IPs to it.
Expand Down Expand Up @@ -60,11 +61,19 @@ func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (*ipAs
assignedIPs: sets.NewString(),
}
if ipv4 != nil {
arpResonder, err := responder.NewARPResponder(externalInterface)
// Create an ARP responder if the dummy device does not exist or
// arp_ignore of the transport interface has a value other than 0.
arpIgnore, err := getARPIgnoreForInterface(externalInterface.Name)
if err != nil {
return nil, fmt.Errorf("failed to create ARP responder for link %s: %v", externalInterface.Name, err)
return nil, err
}
if dummyDeviceName == "" || arpIgnore > 0 {
arpResonder, err := responder.NewARPResponder(externalInterface)
if err != nil {
return nil, fmt.Errorf("failed to create ARP responder for link %s: %v", externalInterface.Name, err)
}
a.arpResponder = arpResonder
}
a.arpResponder = arpResonder
}
if ipv6 != nil {
ndpResponder, err := responder.NewNDPResponder(externalInterface)
Expand All @@ -86,6 +95,23 @@ func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (*ipAs
return a, nil
}

// getARPIgnoreForInterface gets the max value of conf/{all,interface}/arp_ignore form sysctl.
func getARPIgnoreForInterface(iface string) (int, error) {
arpIgnoreAll, err := sysctl.GetSysctlNet("ipv4/conf/all/arp_ignore")
if err != nil {
return 0, fmt.Errorf("failed to get arp_ignore for all interfaces: %w", err)
}
arpIgnore, err := sysctl.GetSysctlNet(fmt.Sprintf("ipv4/conf/%s/arp_ignore", iface))
if err != nil {
return 0, fmt.Errorf("failed to get arp_ignore for %s: %w", iface, err)
}
if arpIgnore > arpIgnoreAll {
return arpIgnore, nil
}
return arpIgnoreAll, nil

}

// ensureDummyDevice creates the dummy device if it doesn't exist.
func ensureDummyDevice(deviceName string) (netlink.Link, error) {
link, err := netlink.LinkByName(deviceName)
Expand Down Expand Up @@ -210,11 +236,7 @@ func (a *ipAssigner) AssignedIPs() sets.String {

// Run starts the ARP responder and NDP responder.
func (a *ipAssigner) Run(ch <-chan struct{}) {
// Start the ARP responder only when the dummy device is not created. The kernel will handle ARP requests
// for IPs assigned to the dummy devices by default.
// TODO: Check the arp_ignore sysctl parameter of the transport interface to determine whether to start
// the ARP responder or not.
if a.dummyDevice == nil && a.arpResponder != nil {
if a.arpResponder != nil {
go a.arpResponder.Run(ch)
}
if a.ndpResponder != nil {
Expand Down

0 comments on commit 41cccc1

Please sign in to comment.