From 44dec0e65b258b42ecc6399a3d4d7d94c3726e49 Mon Sep 17 00:00:00 2001 From: Antonio Ojea Date: Mon, 13 Apr 2020 17:05:05 +0200 Subject: [PATCH] Force disable tx and rx offloading on VXLAN Seems that some kernel versions have issues with VXLAN checksum offloading, causing that flannel stop to work on some scenarios where the traffic is encapsulated, but the checksum is wrong and is discarded by the receiver. A known workaround that works is disabling offloading on the flannel interface: ethtool --offload flannel.1 rx off tx off Flannel disables tx and rx offloading on VXLAN interfaces. --- backend/vxlan/device.go | 5 +++ pkg/ip/iface.go | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/backend/vxlan/device.go b/backend/vxlan/device.go index c3020b5795..56c762d45d 100644 --- a/backend/vxlan/device.go +++ b/backend/vxlan/device.go @@ -118,6 +118,11 @@ func (dev *vxlanDevice) Configure(ipn ip.IP4Net) error { return fmt.Errorf("failed to set interface %s to UP state: %s", dev.link.Attrs().Name, err) } + // TODO: Workaround to fix #1282 + if err := ip.SetChecksumOffloading(dev.link.Attrs().Name, false, false); err != nil { + return fmt.Errorf("failed to disable interface %s tx and rx offloading: %s", dev.link.Attrs().Name, err) + } + return nil } diff --git a/pkg/ip/iface.go b/pkg/ip/iface.go index c4ade549e3..f116afcd2b 100644 --- a/pkg/ip/iface.go +++ b/pkg/ip/iface.go @@ -22,10 +22,77 @@ import ( "fmt" "net" "syscall" + "unsafe" "github.com/vishvananda/netlink" ) +const ( + siocEthtool = 0x8946 // linux/sockios.h + + // #define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ + ethtoolSRxCsum = 0x00000015 // linux/ethtool.h + // #define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ + ethtoolSTxCsum = 0x00000017 // linux/ethtool.h + + maxIfNameSize = 16 // linux/if.h +) + +// linux/if.h 'struct ifreq' +type ifreq struct { + Name [maxIfNameSize]byte + Data uintptr +} + +// linux/ethtool.h 'struct ethtool_value' +type ethtoolValue struct { + Cmd uint32 + Data uint32 +} + +// ethtool executes Linux ethtool syscall. +func ethtool(iface string, cmd, val uint32) (retval uint32, err error) { + if len(iface)+1 > maxIfNameSize { + return 0, fmt.Errorf("interface name is too long") + } + socket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return 0, err + } + defer syscall.Close(socket) + + // prepare ethtool request + value := ethtoolValue{cmd, val} + request := ifreq{Data: uintptr(unsafe.Pointer(&value))} + copy(request.Name[:], iface) + + // ioctl system call + _, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(socket), uintptr(siocEthtool), + uintptr(unsafe.Pointer(&request))) + if errno != 0 { + return 0, errno + } + return value.Data, nil +} + +// SetChecksumOffloading enables/disables Rx/Tx checksum offloading +// for the given interface. +func SetChecksumOffloading(ifName string, rxOn, txOn bool) error { + var rxVal, txVal uint32 + if rxOn { + rxVal = 1 + } + if txOn { + txVal = 1 + } + _, err := ethtool(ifName, ethtoolSRxCsum, rxVal) + if err != nil { + return err + } + _, err = ethtool(ifName, ethtoolSTxCsum, txVal) + return err +} + func getIfaceAddrs(iface *net.Interface) ([]netlink.Addr, error) { link := &netlink.Device{ netlink.LinkAttrs{