go.ligato.io/vpp-agent/v3@v3.5.0/plugins/linux/ifplugin/linuxcalls/ethtool_linuxcalls.go (about)

     1  //  Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  //go:build !windows && !darwin
    16  
    17  package linuxcalls
    18  
    19  import (
    20  	"fmt"
    21  	"syscall"
    22  	"unsafe"
    23  )
    24  
    25  const (
    26  	siocEthtool = 0x8946 // linux/sockios.h
    27  
    28  	ethtoolGRxCsum = 0x00000014 // linux/ethtool.h
    29  	ethtoolSRxCsum = 0x00000015 // linux/ethtool.h
    30  
    31  	ethtoolGTxCsum = 0x00000016 // linux/ethtool.h
    32  	ethtoolSTxCsum = 0x00000017 // linux/ethtool.h
    33  
    34  	maxIfNameSize = 16 // linux/if.h
    35  )
    36  
    37  // linux/if.h 'struct ifreq'
    38  type ifreq struct {
    39  	Name [maxIfNameSize]byte
    40  	Data uintptr
    41  }
    42  
    43  // linux/ethtool.h 'struct ethtool_value'
    44  type ethtoolValue struct {
    45  	Cmd  uint32
    46  	Data uint32
    47  }
    48  
    49  // GetChecksumOffloading returns the state of Rx/Tx checksum offloading
    50  // for the given interface.
    51  func (h *NetLinkHandler) GetChecksumOffloading(ifName string) (rxOn, txOn bool, err error) {
    52  	rxVal, err := ethtool(ifName, ethtoolGRxCsum, 0)
    53  	if err != nil {
    54  		return
    55  	}
    56  	txVal, err := ethtool(ifName, ethtoolGTxCsum, 0)
    57  	if err != nil {
    58  		return
    59  	}
    60  	return rxVal != 0, txVal != 0, nil
    61  }
    62  
    63  // SetChecksumOffloading enables/disables Rx/Tx checksum offloading
    64  // for the given interface.
    65  func (h *NetLinkHandler) SetChecksumOffloading(ifName string, rxOn, txOn bool) error {
    66  	var rxVal, txVal uint32
    67  	if rxOn {
    68  		rxVal = 1
    69  	}
    70  	if txOn {
    71  		txVal = 1
    72  	}
    73  	_, err := ethtool(ifName, ethtoolSRxCsum, rxVal)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	_, err = ethtool(ifName, ethtoolSTxCsum, txVal)
    78  	return err
    79  }
    80  
    81  // ethtool executes Linux ethtool syscall.
    82  func ethtool(iface string, cmd, val uint32) (retval uint32, err error) {
    83  	if len(iface)+1 > maxIfNameSize {
    84  		return 0, fmt.Errorf("interface name is too long")
    85  	}
    86  	socket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    87  	if err != nil {
    88  		return 0, err
    89  	}
    90  	defer syscall.Close(socket)
    91  
    92  	// prepare ethtool request
    93  	value := ethtoolValue{cmd, val}
    94  	request := ifreq{Data: uintptr(unsafe.Pointer(&value))}
    95  	copy(request.Name[:], iface)
    96  
    97  	// ioctl system call
    98  	_, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(socket), uintptr(siocEthtool),
    99  		uintptr(unsafe.Pointer(&request)))
   100  	if errno != 0 {
   101  		return 0, errno
   102  	}
   103  	return value.Data, nil
   104  }