From ab30509b25d54dac99294b76ba03fd49c3d2c946 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Mon, 25 Dec 2023 11:00:20 +0100 Subject: ethernet: T5566: disable energy efficient ethernet (EEE) for interfaces VyOS is a routing (packet pushing) platform, thus supporting EEE which potentially causes issues is not a good idea. Some recent Intel drivers enable EEE by default, thus we will disable this for every NIC supporting EEE. --- python/vyos/ethtool.py | 34 +++++++++++++++++++++++++++++----- python/vyos/ifconfig/ethernet.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py index f19632719..ba638b280 100644 --- a/python/vyos/ethtool.py +++ b/python/vyos/ethtool.py @@ -23,6 +23,7 @@ from vyos.utils.process import popen _drivers_without_speed_duplex_flow = ['vmxnet3', 'virtio_net', 'xen_netfront', 'iavf', 'ice', 'i40e', 'hv_netvsc', 'veth', 'ixgbevf', 'tun'] +_drivers_without_eee = ['vmxnet3', 'virtio_net', 'xen_netfront', 'hv_netvsc'] class Ethtool: """ @@ -55,16 +56,18 @@ class Ethtool: _auto_negotiation_supported = None _flow_control = False _flow_control_enabled = None + _eee = False + _eee_enabled = None def __init__(self, ifname): # Get driver used for interface - out, err = popen(f'ethtool --driver {ifname}') + out, _ = popen(f'ethtool --driver {ifname}') driver = re.search(r'driver:\s(\w+)', out) if driver: self._driver_name = driver.group(1) # Build a dictinary of supported link-speed and dupley settings. - out, err = popen(f'ethtool {ifname}') + out, _ = popen(f'ethtool {ifname}') reading = False pattern = re.compile(r'\d+base.*') for line in out.splitlines()[1:]: @@ -95,7 +98,7 @@ class Ethtool: self._auto_negotiation = bool(tmp == 'on') # Now populate features dictionaty - out, err = popen(f'ethtool --show-features {ifname}') + out, _ = popen(f'ethtool --show-features {ifname}') # skip the first line, it only says: "Features for eth0": for line in out.splitlines()[1:]: if ":" in line: @@ -108,7 +111,7 @@ class Ethtool: 'fixed' : fixed } - out, err = popen(f'ethtool --show-ring {ifname}') + out, _ = popen(f'ethtool --show-ring {ifname}') # We are only interested in line 2-5 which contains the device maximum # ringbuffers for line in out.splitlines()[2:6]: @@ -133,13 +136,22 @@ class Ethtool: # Get current flow control settings, but this is not supported by # all NICs (e.g. vmxnet3 does not support is) - out, err = popen(f'ethtool --show-pause {ifname}') + out, _ = popen(f'ethtool --show-pause {ifname}') if len(out.splitlines()) > 1: self._flow_control = True # read current flow control setting, this returns: # ['Autonegotiate:', 'on'] self._flow_control_enabled = out.splitlines()[1].split()[-1] + # Get current Energy Efficient Ethernet (EEE) settings, but this is + # not supported by all NICs (e.g. vmxnet3 does not support is) + out, _ = popen(f'ethtool --show-eee {ifname}') + if len(out.splitlines()) > 1: + self._eee = True + # read current EEE setting, this returns: + # EEE status: disabled || EEE status: enabled - inactive || EEE status: enabled - active + self._eee_enabled = bool('enabled' in out.splitlines()[2]) + def check_auto_negotiation_supported(self): """ Check if the NIC supports changing auto-negotiation """ return self._auto_negotiation_supported @@ -227,3 +239,15 @@ class Ethtool: raise ValueError('Interface does not support changing '\ 'flow-control settings!') return self._flow_control_enabled + + def check_eee(self): + """ Check if the NIC supports eee """ + if self.get_driver_name() in _drivers_without_eee: + return False + return self._eee + + def get_eee(self): + if self._eee_enabled == None: + raise ValueError('Interface does not support changing '\ + 'EEE settings!') + return self._eee_enabled diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index aa1e87744..aaf903acd 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -399,6 +399,34 @@ class EthernetIf(Interface): print(f'could not set "{rx_tx}" ring-buffer for {ifname}') return output + def set_eee(self, enable): + """ + Enable/Disable Energy Efficient Ethernet (EEE) settings + + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_eee(enable=False) + """ + if not isinstance(enable, bool): + raise ValueError('Value out of range') + + if not self.ethtool.check_eee(): + self._debug_msg(f'NIC driver does not support changing EEE settings!') + return False + + current = self.ethtool.get_eee() + if current != enable: + # Assemble command executed on system. Unfortunately there is no way + # to change this setting via sysfs + cmd = f'ethtool --set-eee {self.ifname} eee ' + cmd += 'on' if enable else 'off' + output, code = self._popen(cmd) + if code: + Warning(f'could not change "{self.ifname}" EEE setting!') + return output + return None + def update(self, config): """ General helper function which works on a dictionary retrived by get_config_dict(). It's main intention is to consolidate the scattered @@ -409,6 +437,9 @@ class EthernetIf(Interface): value = 'off' if 'disable_flow_control' in config else 'on' self.set_flow_control(value) + # Always disable Energy Efficient Ethernet + self.set_eee(False) + # GRO (generic receive offload) self.set_gro(dict_search('offload.gro', config) != None) -- cgit v1.2.3