From ebd1f30695671fda33f4430a5ac36437217dd3ea Mon Sep 17 00:00:00 2001 From: Sven Auhagen Date: Tue, 30 Jul 2019 19:59:34 +0200 Subject: [PATCH 1/4] 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)) From 9e4c83547c06749284e6f3be726a4af8b8fe01ea Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Mon, 23 Dec 2019 14:40:42 +0100 Subject: [PATCH 2/4] argv: add new command line argument --nldebug if --nldebug is provided, netlink debug message will be printed Signed-off-by: Julien Fortin --- ifupdown2/ifupdown/argv.py | 7 +++++++ ifupdown2/ifupdown/ifupdownmain.py | 4 ++-- ifupdown2/ifupdown/main.py | 8 ++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ifupdown2/ifupdown/argv.py b/ifupdown2/ifupdown/argv.py index 4e1da40..e560b40 100644 --- a/ifupdown2/ifupdown/argv.py +++ b/ifupdown2/ifupdown/argv.py @@ -148,6 +148,13 @@ class Parse: help='type of interface entry (iface or vlan). ' 'This option can be used in case of ambiguity between ' 'a vlan interface and an iface interface of the same name') + argparser.add_argument( + "--nldebug", + dest="nldebug", + action="store_true", + default=False, + help="print netlink debug messages" + ) def update_ifupdown_argparser(self, argparser): """ common arg parser for ifup and ifdown """ diff --git a/ifupdown2/ifupdown/ifupdownmain.py b/ifupdown2/ifupdown/ifupdownmain.py index b6afe58..01163e2 100644 --- a/ifupdown2/ifupdown/ifupdownmain.py +++ b/ifupdown2/ifupdown/ifupdownmain.py @@ -219,7 +219,7 @@ class ifupdownMain: def link_exists(self, ifacename): return os.path.exists('/sys/class/net/%s' %ifacename) - def __init__(self, config={}, + def __init__(self, config={}, args=None, daemon=False, force=False, dryrun=False, nowait=False, perfmode=False, withdepends=False, njobs=1, cache=False, addons_enable=True, statemanager_enable=True, @@ -247,7 +247,7 @@ class ifupdownMain: self.reset_ifupdown2() else: # init nlcache with appropriate log level - nlcache.NetlinkListenerWithCache.init(logging.root.level) + nlcache.NetlinkListenerWithCache.init(logging.DEBUG if args.nldebug else logging.WARNING) # start netlink listener and cache link/addr/netconf dumps nlcache.NetlinkListenerWithCache.get_instance().start() diff --git a/ifupdown2/ifupdown/main.py b/ifupdown2/ifupdown/main.py index 7847ba1..f33a0f0 100644 --- a/ifupdown2/ifupdown/main.py +++ b/ifupdown2/ifupdown/main.py @@ -159,7 +159,7 @@ class Ifupdown2: log.debug('creating ifupdown object ..') cachearg = (False if (iflist or args.nocache or args.noact) else True) - ifupdown_handle = ifupdownMain(daemon=self.daemon, + ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, config=configmap_g, force=args.force, withdepends=args.withdepends, @@ -193,7 +193,7 @@ class Ifupdown2: try: iflist = args.iflist log.debug('creating ifupdown object ..') - ifupdown_handle = ifupdownMain(daemon=self.daemon, + ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, config=configmap_g, force=args.force, withdepends=args.withdepends, perfmode=args.perfmode, @@ -239,7 +239,7 @@ class Ifupdown2: iflist = [i for i in os.listdir('/sys/class/net/') if os.path.isdir('/sys/class/net/%s' % i)] log.debug('creating ifupdown object ..') - ifupdown_handle = ifupdownMain(daemon=self.daemon, + ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, config=configmap_g, withdepends=args.withdepends, perfmode=args.perfmode, @@ -263,7 +263,7 @@ class Ifupdown2: try: log.debug('creating ifupdown object ..') - ifupdown_handle = ifupdownMain(daemon=self.daemon, + ifupdown_handle = ifupdownMain(daemon=self.daemon, args=args, config=configmap_g, interfacesfile=self.interfaces_filename, withdepends=args.withdepends, From e65fae4889fa8072a1cfbf7be7cb46f405369abe Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Tue, 31 Dec 2019 15:21:36 +0100 Subject: [PATCH 3/4] debian: changelog: new 2.0.1-1 entry Signed-off-by: Julien Fortin --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index b64932e..a62a32c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +ifupdown2 (2.0.1-1) unstable; urgency=medium + + * New argv option: --nldebug to print netlink debug message + * New: ethtool: nics (GRO, LRO GSO, TSO, UFO, TX and RX) offload attributes + + -- Julien Fortin Tue, 31 Dec 2019 15:21:06 +0100 + ifupdown2 (2.0.0-1) unstable; urgency=medium * Introduction of the live netlink cache From 8e9960454d58f648547fcb086a8b4352a4aa4faa Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Tue, 31 Dec 2019 20:25:44 +0100 Subject: [PATCH 4/4] argv: move --nldebug option to common_argparse to avoid exception in ifreload Signed-off-by: Julien Fortin --- ifupdown2/ifupdown/argv.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ifupdown2/ifupdown/argv.py b/ifupdown2/ifupdown/argv.py index e560b40..a96a390 100644 --- a/ifupdown2/ifupdown/argv.py +++ b/ifupdown2/ifupdown/argv.py @@ -148,13 +148,6 @@ class Parse: help='type of interface entry (iface or vlan). ' 'This option can be used in case of ambiguity between ' 'a vlan interface and an iface interface of the same name') - argparser.add_argument( - "--nldebug", - dest="nldebug", - action="store_true", - default=False, - help="print netlink debug messages" - ) def update_ifupdown_argparser(self, argparser): """ common arg parser for ifup and ifdown """ @@ -248,3 +241,10 @@ class Parse: ''' general parsing rules ''' argparser.add_argument('-V', '--version', action=VersionAction, nargs=0) + argparser.add_argument( + "--nldebug", + dest="nldebug", + action="store_true", + default=False, + help="print netlink debug messages" + )