diff options
-rw-r--r-- | data/templates/lldp/lldpd.j2 | 2 | ||||
-rw-r--r-- | interface-definitions/include/version/lldp-version.xml.i | 2 | ||||
-rw-r--r-- | interface-definitions/lldp.xml.in | 15 | ||||
-rw-r--r-- | python/vyos/ethtool.py | 34 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 31 | ||||
-rw-r--r-- | smoketest/configs/ospf-small | 3 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_lldp.py | 16 | ||||
-rwxr-xr-x | src/conf_mode/lldp.py | 5 | ||||
-rwxr-xr-x | src/conf_mode/snmp.py | 2 | ||||
-rwxr-xr-x | src/migration-scripts/lldp/0-to-1 | 14 | ||||
-rwxr-xr-x | src/migration-scripts/lldp/1-to-2 | 48 |
11 files changed, 149 insertions, 23 deletions
diff --git a/data/templates/lldp/lldpd.j2 b/data/templates/lldp/lldpd.j2 index 3c499197d..6ae063c4b 100644 --- a/data/templates/lldp/lldpd.j2 +++ b/data/templates/lldp/lldpd.j2 @@ -1,2 +1,2 @@ ### Autogenerated by lldp.py ### -DAEMON_ARGS="-M 4 {{ '-x' if snmp.enable is vyos_defined }} {{ '-c' if legacy_protocols.cdp is vyos_defined }} {{ '-e' if legacy_protocols.edp is vyos_defined }} {{ '-f' if legacy_protocols.fdp is vyos_defined }} {{ '-s' if legacy_protocols.sonmp is vyos_defined }}" +DAEMON_ARGS="-M 4 {{ '-x' if snmp is vyos_defined }} {{ '-c' if legacy_protocols.cdp is vyos_defined }} {{ '-e' if legacy_protocols.edp is vyos_defined }} {{ '-f' if legacy_protocols.fdp is vyos_defined }} {{ '-s' if legacy_protocols.sonmp is vyos_defined }}" diff --git a/interface-definitions/include/version/lldp-version.xml.i b/interface-definitions/include/version/lldp-version.xml.i index 0deb73279..b41d80451 100644 --- a/interface-definitions/include/version/lldp-version.xml.i +++ b/interface-definitions/include/version/lldp-version.xml.i @@ -1,3 +1,3 @@ <!-- include start from include/version/lldp-version.xml.i --> -<syntaxVersion component='lldp' version='1'></syntaxVersion> +<syntaxVersion component='lldp' version='2'></syntaxVersion> <!-- include end --> diff --git a/interface-definitions/lldp.xml.in b/interface-definitions/lldp.xml.in index 738bb11c1..25fb575b6 100644 --- a/interface-definitions/lldp.xml.in +++ b/interface-definitions/lldp.xml.in @@ -175,19 +175,12 @@ <multi/> </properties> </leafNode> - <node name="snmp"> + <leafNode name="snmp"> <properties> - <help>SNMP parameters for LLDP</help> + <help>Enable SNMP queries of the LLDP database</help> + <valueless/> </properties> - <children> - <leafNode name="enable"> - <properties> - <help>Enable SNMP queries of the LLDP database</help> - <valueless/> - </properties> - </leafNode> - </children> - </node> + </leafNode> </children> </node> </children> 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) diff --git a/smoketest/configs/ospf-small b/smoketest/configs/ospf-small index 767f4e21f..b3002b1af 100644 --- a/smoketest/configs/ospf-small +++ b/smoketest/configs/ospf-small @@ -81,6 +81,9 @@ service { lldp { interface all { } + snmp { + enable + } } snmp { community public { diff --git a/smoketest/scripts/cli/test_service_lldp.py b/smoketest/scripts/cli/test_service_lldp.py index ee26844ab..7e30b43f5 100755 --- a/smoketest/scripts/cli/test_service_lldp.py +++ b/smoketest/scripts/cli/test_service_lldp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2022 VyOS maintainers and contributors +# Copyright (C) 2022-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -122,6 +122,20 @@ class TestServiceLLDP(VyOSUnitTestSHIM.TestCase): self.assertIn(f'configure ports {interface} med location elin "{elin}"', config) self.assertIn(f'configure system interface pattern "{interface}"', config) + def test_06_lldp_snmp(self): + self.cli_set(base_path + ['snmp']) + + # verify - can not start lldp snmp without snmp beeing configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(['service', 'snmp']) + self.cli_commit() + + # SNMP required process to be started with -x option + tmp = read_file('/etc/default/lldpd') + self.assertIn('-x', tmp) + + self.cli_delete(['service', 'snmp']) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/lldp.py b/src/conf_mode/lldp.py index c2e87d171..3c647a0e8 100755 --- a/src/conf_mode/lldp.py +++ b/src/conf_mode/lldp.py @@ -86,9 +86,9 @@ def verify(lldp): raise ConfigError(f'Must define both longitude and latitude for "{interface}" location!') # check options - if 'snmp' in lldp and 'enable' in lldp['snmp']: + if 'snmp' in lldp: if 'system_snmp_enabled' not in lldp: - raise ConfigError('SNMP must be configured to enable LLDP SNMP') + raise ConfigError('SNMP must be configured to enable LLDP SNMP!') def generate(lldp): @@ -121,4 +121,3 @@ if __name__ == '__main__': except ConfigError as e: print(e) exit(1) - diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py index f1d41f23d..6565ffd60 100755 --- a/src/conf_mode/snmp.py +++ b/src/conf_mode/snmp.py @@ -54,7 +54,7 @@ def get_config(config=None): if not conf.exists(base): snmp.update({'deleted' : ''}) - if conf.exists(['service', 'lldp', 'snmp', 'enable']): + if conf.exists(['service', 'lldp', 'snmp']): snmp.update({'lldp_snmp' : ''}) if 'deleted' in snmp: diff --git a/src/migration-scripts/lldp/0-to-1 b/src/migration-scripts/lldp/0-to-1 index a936cbdfc..a99356062 100755 --- a/src/migration-scripts/lldp/0-to-1 +++ b/src/migration-scripts/lldp/0-to-1 @@ -1,4 +1,18 @@ #!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. # Delete "set service lldp interface <interface> location civic-based" option # as it was broken most of the time anyways diff --git a/src/migration-scripts/lldp/1-to-2 b/src/migration-scripts/lldp/1-to-2 new file mode 100755 index 000000000..35efb25db --- /dev/null +++ b/src/migration-scripts/lldp/1-to-2 @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# T5855: migrate "set service lldp snmp enable" -> `set service lldp snmp" + +import sys + +from vyos.configtree import ConfigTree + +if len(sys.argv) < 2: + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) +base = ['service', 'lldp'] +if not config.exists(base): + # Nothing to do + sys.exit(0) + +if config.exists(base + ['snmp']): + enabled = config.exists(base + ['snmp', 'enable']) + config.delete(base + ['snmp']) + if enabled: config.set(base + ['snmp']) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) |