diff --git a/clab/docker.go b/clab/docker.go index 2ce4eae22..5113fe9e0 100644 --- a/clab/docker.go +++ b/clab/docker.go @@ -7,7 +7,6 @@ import ( "io" "io/ioutil" "os" - "os/exec" "path" "strconv" "strings" @@ -105,13 +104,11 @@ func (c *cLab) CreateBridge(ctx context.Context) (err error) { return fmt.Errorf("failed to enable LLDP on docker bridge: %v", err) } - log.Debug("Disable Checksum Offloading on the docker bridge") - var b []byte - b, err = exec.Command("sudo", "ethtool", "--offload", bridgeName, "rx", "off", "tx", "off").CombinedOutput() + log.Debugf("Disabling TX checksum offloading for the %s bridge interface...", bridgeName) + err = EthtoolTXOff(bridgeName) if err != nil { - return fmt.Errorf("failed to disable Checksum Offloading on docker bridge: %v", err) + return fmt.Errorf("Failed to disable TX checksum offloading for the %s bridge interface: %v", bridgeName, err) } - log.Debugf("%s", string(b)) return nil } diff --git a/clab/ethtool.go b/clab/ethtool.go new file mode 100644 index 000000000..1bdcd9156 --- /dev/null +++ b/clab/ethtool.go @@ -0,0 +1,62 @@ +package clab + +import ( + "fmt" + "syscall" + "unsafe" +) + +const ( + SIOCETHTOOL = 0x8946 // linux/sockios.h + ETHTOOL_GTXCSUM = 0x00000016 // linux/ethtool.h + ETHTOOL_STXCSUM = 0x00000017 // linux/ethtool.h + IFNAMSIZ = 16 // linux/if.h +) + +// linux/if.h 'struct ifreq' +type IFReqData struct { + Name [IFNAMSIZ]byte + Data uintptr +} + +// linux/ethtool.h 'struct ethtool_value' +type EthtoolValue struct { + Cmd uint32 + Data uint32 +} + +func ioctlEthtool(fd int, argp uintptr) error { + _, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), argp) + if errno != 0 { + return errno + } + return nil +} + +// EthtoolTXOff disables TX checksum offload on specified interface +func EthtoolTXOff(name string) error { + if len(name)+1 > IFNAMSIZ { + return fmt.Errorf("name too long") + } + + socket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0) + if err != nil { + return err + } + defer syscall.Close(socket) + + // Request current value + value := EthtoolValue{Cmd: ETHTOOL_GTXCSUM} + request := IFReqData{Data: uintptr(unsafe.Pointer(&value))} + copy(request.Name[:], name) + + if err := ioctlEthtool(socket, uintptr(unsafe.Pointer(&request))); err != nil { + return err + } + if value.Data == 0 { // if already off, don't try to change + return nil + } + + value = EthtoolValue{ETHTOOL_STXCSUM, 0} + return ioctlEthtool(socket, uintptr(unsafe.Pointer(&request))) +} diff --git a/clab/netlink.go b/clab/netlink.go index 033e8fac5..b7af69f69 100644 --- a/clab/netlink.go +++ b/clab/netlink.go @@ -78,7 +78,11 @@ func (c *cLab) createAToBveth(l *Link) error { func (c *cLab) configVeth(dummyInterface, endpointName, ns string) error { var cmd *exec.Cmd - var err error + log.Debugf("Disabling TX checksum offloading for the %s interface...", dummyInterface) + err := EthtoolTXOff(dummyInterface) + if err != nil { + return err + } log.Debugf("map dummy interface '%s' to container %s", dummyInterface, ns) cmd = exec.Command("sudo", "ip", "link", "set", dummyInterface, "netns", ns) err = runCmd(cmd) @@ -97,12 +101,6 @@ func (c *cLab) configVeth(dummyInterface, endpointName, ns string) error { if err != nil { return err } - log.Debugf("set RX, TX offload off for interface '%s' in NS %s", endpointName, ns) - cmd = exec.Command("docker", "exec", ns, "ethtool", "--offload", endpointName, "rx", "off", "tx", "off") - err = runCmd(cmd) - if err != nil { - return err - } return nil } @@ -148,9 +146,8 @@ func (c *cLab) createvethToBridge(l *Link) error { if err != nil { return err } - log.Debug("set RX, TX offload off on veth of the bridge interface") - cmd = exec.Command("sudo", "ethtool", "--offload", bridgeIfname, "rx", "off", "tx", "off") - err = runCmd(cmd) + log.Debugf("Disabling TX checksum offloading for the %s interface...", bridgeIfname) + err = EthtoolTXOff(bridgeIfname) if err != nil { return err }