Skip to content

Commit

Permalink
Force disable tx and rx offloading on VXLAN
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aojea committed Apr 13, 2020
1 parent 4ff77dc commit 44dec0e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
5 changes: 5 additions & 0 deletions backend/vxlan/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
67 changes: 67 additions & 0 deletions pkg/ip/iface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down

0 comments on commit 44dec0e

Please sign in to comment.