Skip to content

Commit

Permalink
Fix Egress not work 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 the userspace ARP responder if it has 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 509cb35
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
34 changes: 28 additions & 6 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 All @@ -43,7 +44,9 @@ type ipAssigner struct {
// assignIPs caches the IPs that are assigned to the dummy device.
// TODO: Add a goroutine to ensure that the cache is in sync with the IPs assigned to the dummy device in case the
// IPs are removed by users accidentally.
assignedIPs sets.String
assignedIPs sets.String
// arpIgnore is the max value of conf/{all,interface}/arp_ignore for transport interface
arpIgnore int
mutex sync.RWMutex
arpResponder responder.Responder
ndpResponder responder.Responder
Expand All @@ -60,6 +63,11 @@ func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (*ipAs
assignedIPs: sets.NewString(),
}
if ipv4 != nil {
arpIgnore, err := getARPIgnoreForInterface(externalInterface.Name)
if err != nil {
return nil, err
}
a.arpIgnore = arpIgnore
arpResonder, err := responder.NewARPResponder(externalInterface)
if err != nil {
return nil, fmt.Errorf("failed to create ARP responder for link %s: %v", externalInterface.Name, err)
Expand All @@ -86,6 +94,22 @@ func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (*ipAs
return a, nil
}

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 +234,9 @@ 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 {
// Start the ARP responder if the dummy device does not exist or
// arp_ignore of the transport interface has value other than 0.
if (a.arpIgnore > 0 || a.dummyDevice == nil) && a.arpResponder != nil {
go a.arpResponder.Run(ch)
}
if a.ndpResponder != nil {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/infra/vagrant/Vagrantfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
VAGRANTFILE_API_VERSION = "2"

NUM_WORKERS = 1
NUM_WORKERS = 2

MODE = ENV['K8S_IP_FAMILY'] || "v4"
if MODE != "v4" && MODE != "v6" && MODE != "dual"
Expand Down

0 comments on commit 509cb35

Please sign in to comment.