From ebd1f30695671fda33f4430a5ac36437217dd3ea Mon Sep 17 00:00:00 2001 From: Sven Auhagen Date: Tue, 30 Jul 2019 19:59:34 +0200 Subject: [PATCH] This commit adds the feature to change offloads for nics. Currently GRO, LRO GSO, TSO, UFO, TX and RX Offload are supported. One can read the current value with ethtool -k NICNAME. Values are set with ethtool -K NICNAME gro on lro on gso on tso on ufo on tx on rx on An example for the config file is: iface eth0 static gro-offload no The default value will be kept in the statemanager. The default value might differ depending on the NIC and is saved upon the first change. --- ifupdown2/addons/ethtool.py | 131 +++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/ifupdown2/addons/ethtool.py b/ifupdown2/addons/ethtool.py index c4f9aa1..4a20ef5 100644 --- a/ifupdown2/addons/ethtool.py +++ b/ifupdown2/addons/ethtool.py @@ -9,6 +9,7 @@ import os try: import ifupdown2.ifupdown.ifupdownflags as ifupdownflags import ifupdown2.ifupdown.policymanager as policymanager + import ifupdown2.ifupdown.statemanager as statemanager from ifupdown2.ifupdown.iface import * from ifupdown2.ifupdown.utils import utils @@ -20,6 +21,7 @@ try: except ImportError: import ifupdown.ifupdownflags as ifupdownflags import ifupdown.policymanager as policymanager + import ifupdown.statemanager as statemanager from ifupdown.iface import * from ifupdown.utils import utils @@ -61,7 +63,44 @@ class ethtool(moduleBase,utilsBase): {'help': 'set forward error correction mode', 'example' : ['link-fec rs'], 'validvals' : ['rs', 'baser', 'auto', 'off'], - 'default' : 'varies by platform and port'}}} + 'default' : 'varies by platform and port'}, + 'gro-offload' : + {'help': 'Generic Receive Offload', + 'example' : ['gro-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'lro-offload' : + {'help': 'Large Receive Offload', + 'example' : ['lro-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'gso-offload' : + {'help': 'Generic Segmentation Offload', + 'example' : ['tso-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'tso-offload' : + {'help': 'TCP Segmentation Offload', + 'example' : ['tso-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'ufo-offload' : + {'help': 'UDP Fragmentation Offload', + 'example' : ['ufo-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'tx-offload' : + {'help': 'TX Checksum Offload', + 'example' : ['tx-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + 'rx-offload' : + {'help': 'RX Checksum Offload', + 'example' : ['rx-offload on'], + 'validvals' : ['on', 'off'], + 'default' : 'varies by interface'}, + } + } def __init__(self, *args, **kargs): moduleBase.__init__(self, *args, **kargs) @@ -70,6 +109,39 @@ class ethtool(moduleBase,utilsBase): self.ipcmd = None # keep a list of iface objects who have modified link attributes self.ifaceobjs_modified_configs = [] + # Cache for features + self.feature_cache = None + + def do_offload_settings(self, ifaceobj, attr_name, eth_name): + default = 'default_' + eth_name + config_val = ifaceobj.get_attr_value_first(attr_name) + # Default + default_val = None + saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) + if saved_ifaceobjs: + default_val = saved_ifaceobjs[0].get_attr_value_first(default) + if config_val or default_val: + + # get running value + running_val = str(self.get_running_attr(eth_name, ifaceobj)).lower() + # Save default value + # Load state data + if not default_val: + ifaceobj.config[default] = [running_val] + elif config_val: + # resave for state + ifaceobj.config[default] = [default_val] + + if not config_val: + config_val = default_val + + if config_val and config_val != running_val: + try: + cmd = ('%s -K %s %s %s' % + (utils.ethtool_cmd, ifaceobj.name, eth_name, config_val)) + utils.exec_command(cmd) + except Exception, e: + self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj) def do_fec_settings(self, ifaceobj): feccmd = '' @@ -226,6 +298,13 @@ class ethtool(moduleBase,utilsBase): self.do_speed_settings(ifaceobj) self.do_fec_settings(ifaceobj) + self.do_offload_settings(ifaceobj, 'gro-offload', 'gro') + self.do_offload_settings(ifaceobj, 'lro-offload', 'lro') + self.do_offload_settings(ifaceobj, 'gso-offload', 'gso') + self.do_offload_settings(ifaceobj, 'tso-offload', 'tso') + self.do_offload_settings(ifaceobj, 'ufo-offload', 'ufo') + self.do_offload_settings(ifaceobj, 'tx-offload', 'tx') + self.do_offload_settings(ifaceobj, 'rx-offload', 'rx') def _pre_down(self, ifaceobj): pass #self._post_up(ifaceobj,operation="_pre_down") @@ -315,6 +394,21 @@ class ethtool(moduleBase,utilsBase): return(None) + def get_offload_setting(self, ethtool_output, setting): + + value = None + + for line in ethtool_output.splitlines(): + if setting in line: + if 'on' in line: + value = 'on' + elif 'off' in line: + value = 'off' + + break + + return value + def get_running_attr(self,attr='',ifaceobj=None): if not ifaceobj or not attr: return @@ -327,6 +421,41 @@ class ethtool(moduleBase,utilsBase): output = utils.exec_command('%s --show-fec %s'% (utils.ethtool_cmd, ifaceobj.name)) running_attr = self.get_fec_encoding(ethtool_output=output) + elif attr == 'gro': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='generic-receive-offload') + elif attr == 'lro': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='large-receive-offload') + elif attr == 'gso': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='generic-segmentation-offload') + elif attr == 'tso': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='tcp-segmentation-offload') + elif attr == 'ufo': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='udp-fragmentation-offload') + elif attr == 'rx': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='rx-checksumming') + elif attr == 'tx': + if not self.feature_cache: + self.feature_cache = utils.exec_command('%s --show-features %s'% + (utils.ethtool_cmd, ifaceobj.name)) + running_attr = self.get_offload_setting(ethtool_output=self.feature_cache, setting='tx-checksumming') else: running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \ (ifaceobj.name, attr))