diff --git a/backend/vxlan/device.go b/backend/vxlan/device.go index c3020b579..56c762d45 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 c4ade549e..f116afcd2 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{