From df0fbfeedce0f163e9d10be21d58ad4dc797a28a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 30 Mar 2022 19:18:09 +0200 Subject: vyos.util: T4319: add is_ipv6_enabled() helper function --- python/vyos/ifconfig/interface.py | 4 ++-- python/vyos/ifconfig/loopback.py | 13 +++++-------- python/vyos/util.py | 4 ++++ src/tests/test_util.py | 15 ++++++++++++++- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 4fda1c0a9..22265cc3c 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -39,7 +39,7 @@ from vyos.util import read_file from vyos.util import get_interface_config from vyos.util import get_interface_namespace from vyos.util import is_systemd_service_active -from vyos.util import sysctl_read +from vyos.util import is_ipv6_enabled from vyos.template import is_ipv4 from vyos.template import is_ipv6 from vyos.validate import is_intf_addr_assigned @@ -1498,7 +1498,7 @@ class Interface(Control): self.set_ipv4_source_validation(value) # Only change IPv6 parameters if IPv6 was not explicitly disabled - if sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0': + if is_ipv6_enabled(): # Configure MSS value for IPv6 TCP connections tmp = dict_search('ipv6.adjust_mss', config) value = tmp if (tmp != None) else '0' diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py index de554ef44..30c890fdf 100644 --- a/python/vyos/ifconfig/loopback.py +++ b/python/vyos/ifconfig/loopback.py @@ -13,9 +13,8 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see . -import vyos.util - from vyos.ifconfig.interface import Interface +from vyos.util import is_ipv6_enabled @Interface.register class LoopbackIf(Interface): @@ -34,8 +33,6 @@ class LoopbackIf(Interface): } } - name = 'loopback' - def remove(self): """ Loopback interface can not be deleted from operating system. We can @@ -62,11 +59,11 @@ class LoopbackIf(Interface): on any interface. """ addr = config.get('address', []) - # We must ensure that the loopback addresses are never deleted from the system - addr += ['127.0.0.1/8'] - if (vyos.util.sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0'): - addr += ['::1/128'] + # We must ensure that the loopback addresses are never deleted from the system + addr.append('127.0.0.1/8') + if is_ipv6_enabled(): + addr.append('::1/128') # Update IP address entry in our dictionary config.update({'address' : addr}) diff --git a/python/vyos/util.py b/python/vyos/util.py index f46775490..f3f323c34 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -1019,3 +1019,7 @@ def sysctl_write(name, value): call(f'sysctl -wq {name}={value}') return True return False + +def is_ipv6_enabled() -> bool: + """ Check if IPv6 support on the system is enabled or not """ + return (sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0') diff --git a/src/tests/test_util.py b/src/tests/test_util.py index 9bd27adc0..91890262c 100644 --- a/src/tests/test_util.py +++ b/src/tests/test_util.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -23,3 +23,16 @@ class TestVyOSUtil(TestCase): expected_data = {"foo_bar": {"baz_quux": None}} new_data = mangle_dict_keys(data, '-', '_') self.assertEqual(new_data, expected_data) + + def test_sysctl_read(self): + self.assertEqual(sysctl_read('net.ipv4.conf.lo.forwarding'), '1') + + def test_ipv6_enabled(self): + tmp = sysctl_read('net.ipv6.conf.all.disable_ipv6') + # We need to test for both variants as this depends on how the + # Docker container is started (with or without IPv6 support) - so we + # will simply check both cases to not make the users life miserable. + if tmp == '0': + self.assertTrue(is_ipv6_enabled()) + else: + self.assertFalse(is_ipv6_enabled()) -- cgit v1.2.3 From c33a96f6f0f0259808992b246b1a550fcf9a454a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 30 Mar 2022 19:19:24 +0200 Subject: vrf: T4319: do not add IPv6 localhost address if IPv6 is disabled --- src/conf_mode/vrf.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index 6a521a0dd..c3e2d8efd 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -30,6 +30,7 @@ from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run from vyos.util import sysctl_write +from vyos.util import is_ipv6_enabled from vyos import ConfigError from vyos import frr from vyos import airbag @@ -215,10 +216,11 @@ def apply(vrf): # set VRF description for e.g. SNMP monitoring vrf_if = Interface(name) - # We also should add proper loopback IP addresses to the newly - # created VRFs for services bound to the loopback address (SNMP, NTP) + # We also should add proper loopback IP addresses to the newly added + # VRF for services bound to the loopback address (SNMP, NTP) vrf_if.add_addr('127.0.0.1/8') - vrf_if.add_addr('::1/128') + if is_ipv6_enabled(): + vrf_if.add_addr('::1/128') # add VRF description if available vrf_if.set_alias(config.get('description', '')) -- cgit v1.2.3 From 60f009defadb9d36bf84def1e839cb11a0b3d619 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 30 Mar 2022 19:19:54 +0200 Subject: vyos.ifconfig: T4319: add_addr() should not add IPv6 address if it's disabled --- python/vyos/ifconfig/interface.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 22265cc3c..6b9a4d03e 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1083,6 +1083,10 @@ class Interface(Control): addr_is_v4 = is_ipv4(addr) + # Failsave - do not add IPv6 address if IPv6 is disabled + if is_ipv6(addr) and not is_ipv6_enabled(): + return False + # add to interface if addr == 'dhcp': self.set_dhcp(True) -- cgit v1.2.3 From a33b737b753843501c86eee744aef75137d2b64e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 30 Mar 2022 21:57:13 +0200 Subject: smoketest: T4319: verify correct assignment of loopback IP addresses --- smoketest/scripts/cli/test_system_ipv6.py | 19 +++++++++++ smoketest/scripts/cli/test_vrf.py | 54 +++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index 3112d2e46..6fe58701b 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -17,7 +17,11 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM + +from vyos.template import is_ipv4 from vyos.util import read_file +from vyos.util import is_ipv6_enabled +from vyos.validate import is_intf_addr_assigned base_path = ['system', 'ipv6'] @@ -42,6 +46,14 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): self.assertEqual(read_file(file_forwarding), '0') def test_system_ipv6_disable(self): + # Verify previous "enable" state + self.assertEqual(read_file(file_disable), '0') + self.assertTrue(is_ipv6_enabled()) + + loopbacks = ['127.0.0.1', '::1'] + for addr in loopbacks: + self.assertTrue(is_intf_addr_assigned('lo', addr)) + # Do not assign any IPv6 address on interfaces, this requires a reboot # which can not be tested, but we can read the config file :) self.cli_set(base_path + ['disable']) @@ -49,6 +61,13 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): # Verify configuration file self.assertEqual(read_file(file_disable), '1') + self.assertFalse(is_ipv6_enabled()) + + for addr in loopbacks: + if is_ipv4(addr): + self.assertTrue(is_intf_addr_assigned('lo', addr)) + else: + self.assertFalse(is_intf_addr_assigned('lo', addr)) def test_system_ipv6_strict_dad(self): # This defaults to 1 diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 5ffa9c086..5daea589c 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -25,9 +25,10 @@ from base_vyostest_shim import VyOSUnitTestSHIM from vyos.configsession import ConfigSessionError from vyos.ifconfig import Interface from vyos.ifconfig import Section -from vyos.template import is_ipv6 +from vyos.template import is_ipv4 from vyos.util import cmd from vyos.util import read_file +from vyos.util import get_interface_config from vyos.validate import is_intf_addr_assigned base_path = ['vrf'] @@ -105,10 +106,13 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig(f'vrf {vrf}') self.assertIn(f' vni {table}', frrconfig) + tmp = get_interface_config(vrf) + self.assertEqual(int(table), tmp['linkinfo']['info_data']['table']) + # Increment table ID for the next run table = str(int(table) + 1) - def test_vrf_loopback_ips(self): + def test_vrf_loopbacks_ips(self): table = '2000' for vrf in vrfs: base = base_path + ['name', vrf] @@ -119,10 +123,48 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify VRF configuration + loopbacks = ['127.0.0.1', '::1'] for vrf in vrfs: - self.assertTrue(vrf in interfaces()) - self.assertTrue(is_intf_addr_assigned(vrf, '127.0.0.1')) - self.assertTrue(is_intf_addr_assigned(vrf, '::1')) + # Ensure VRF was created + self.assertIn(vrf, interfaces()) + # Test for proper loopback IP assignment + for addr in loopbacks: + self.assertTrue(is_intf_addr_assigned(vrf, addr)) + + def test_vrf_loopbacks_no_ipv6(self): + table = '2002' + for vrf in vrfs: + base = base_path + ['name', vrf] + self.cli_set(base + ['table', str(table)]) + table = str(int(table) + 1) + + # Globally disable IPv6 - this will remove all IPv6 interface addresses + self.cli_set(['system', 'ipv6', 'disable']) + + # commit changes + self.cli_commit() + + # Verify VRF configuration + table = '2002' + loopbacks = ['127.0.0.1', '::1'] + for vrf in vrfs: + # Ensure VRF was created + self.assertIn(vrf, interfaces()) + + # Verify VRF table ID + tmp = get_interface_config(vrf) + self.assertEqual(int(table), tmp['linkinfo']['info_data']['table']) + + # Test for proper loopback IP assignment + for addr in loopbacks: + if is_ipv4(addr): + self.assertTrue(is_intf_addr_assigned(vrf, addr)) + else: + self.assertFalse(is_intf_addr_assigned(vrf, addr)) + + table = str(int(table) + 1) + + self.cli_delete(['system', 'ipv6']) def test_vrf_bind_all(self): table = '2000' -- cgit v1.2.3 From 7d4160f5e2ef1b0c7d5443850fa5b694b940547a Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Thu, 31 Mar 2022 13:08:05 +0000 Subject: bgp: T4326: Add bgp parameter no-suppress-duplicates Add new bgp parameter 'no-suppress-duplicates' set protocols bgp parameters no-suppress-duplicates --- data/templates/frr/bgpd.frr.tmpl | 3 +++ interface-definitions/include/bgp/protocol-common-config.xml.i | 6 ++++++ smoketest/scripts/cli/test_protocols_bgp.py | 2 ++ 3 files changed, 11 insertions(+) diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 45e0544b7..0bc0fd36e 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -545,6 +545,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if parameters.no_fast_external_failover is defined %} no bgp fast-external-failover {% endif %} +{% if parameters.no_suppress_duplicates is defined %} + no bgp suppress-duplicates +{% endif %} {% if parameters.reject_as_sets is defined %} bgp reject-as-sets {% endif %} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 38337b032..b59ff0287 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -1430,6 +1430,12 @@ + + + Disable suppress duplicate updates if the route actually not changed + + + Reject routes with AS_SET or AS_CONFED_SET flag diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index d7230baf4..db1587ba7 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -274,6 +274,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['parameters', 'conditional-advertisement', 'timer', cond_adv_timer]) self.cli_set(base_path + ['parameters', 'fast-convergence']) self.cli_set(base_path + ['parameters', 'minimum-holdtime', min_hold_time]) + self.cli_set(base_path + ['parameters', 'no-suppress-duplicates']) self.cli_set(base_path + ['parameters', 'reject-as-sets']) self.cli_set(base_path + ['parameters', 'shutdown']) self.cli_set(base_path + ['parameters', 'suppress-fib-pending']) @@ -305,6 +306,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' bgp shutdown', frrconfig) self.assertIn(f' bgp suppress-fib-pending', frrconfig) self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig) + self.assertIn(f' no bgp suppress-duplicates', frrconfig) afiv4_config = self.getFRRconfig(' address-family ipv4 unicast') self.assertIn(f' maximum-paths {max_path_v4}', afiv4_config) -- cgit v1.2.3 From d14102856387fb74de16f6305de7482443d561d0 Mon Sep 17 00:00:00 2001 From: srividya0208 Date: Mon, 28 Mar 2022 13:42:11 -0400 Subject: logging: T4308: log options for routing protocol It will be more convenient if there is a seperate option to debug the protocol --- op-mode-definitions/show-log.xml.in | 73 +++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index 4c0a7913b..2d75f119d 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -212,6 +212,79 @@ + + + Show log for Routing Protocols + + + + + Show log for OSPF + + journalctl -b /usr/lib/frr/ospfd + + + + Show log for OSPF for IPv6 + + journalctl -b /usr/lib/frr/ospf6d + + + + Show log for BGP + + journalctl -b /usr/lib/frr/bgpd + + + + Show log for RIP + + journalctl -b /usr/lib/frr/ripd + + + + Show log for RIPng + + journalctl -b /usr/lib/frr/ripngd + + + + Show log for static route + + journalctl -b /usr/lib/frr/staticd + + + + Show log for Multicast protocol + + journalctl -b /usr/lib/frr/pimd + + + + Show log for ISIS + + journalctl -b /usr/lib/frr/isisd + + + + Show log for NHRP + + journalctl -b /usr/lib/frr/nhrpd + + + + Show log for BFD + + journalctl -b /usr/lib/frr/bfdd + + + + Show log for MPLS + + journalctl -b /usr/lib/frr/ldpd + + + Show log for Simple Network Monitoring Protocol (SNMP) -- cgit v1.2.3 From 53e20097d227ebf4bdb4dc6c85427ec9c5ec3982 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 31 Mar 2022 21:38:17 +0200 Subject: vyos.ifconfig: T4330: bugfix changing MTU when IPv6 is disabled Commit f8b3d8999c ("ipv6: T4319: do not configure IPv6 related settings if it's disabled") moved the MTU configuration part under the code path which is only run if IPv6 is enabled on the system. This prevented MTU changes on IPv6 disabled systems. --- python/vyos/ifconfig/interface.py | 8 ++++---- smoketest/scripts/cli/test_system_ipv6.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 6b9a4d03e..f39da90e4 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1530,10 +1530,6 @@ class Interface(Control): value = tmp if (tmp != None) else '1' self.set_ipv6_dad_messages(value) - # MTU - Maximum Transfer Unit - if 'mtu' in config: - self.set_mtu(config.get('mtu')) - # Delete old IPv6 EUI64 addresses before changing MAC for addr in (dict_search('ipv6.address.eui64_old', config) or []): self.del_ipv6_eui64_address(addr) @@ -1550,6 +1546,10 @@ class Interface(Control): for addr in tmp: self.add_ipv6_eui64_address(addr) + # MTU - Maximum Transfer Unit + if 'mtu' in config: + self.set_mtu(config.get('mtu')) + # re-add ourselves to any bridge we might have fallen out of if 'is_bridge_member' in config: bridge_dict = config.get('is_bridge_member') diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index 6fe58701b..837d1dc12 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -21,6 +21,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM from vyos.template import is_ipv4 from vyos.util import read_file from vyos.util import is_ipv6_enabled +from vyos.util import get_interface_config from vyos.validate import is_intf_addr_assigned base_path = ['system', 'ipv6'] @@ -69,6 +70,17 @@ class TestSystemIPv6(VyOSUnitTestSHIM.TestCase): else: self.assertFalse(is_intf_addr_assigned('lo', addr)) + # T4330: Verify MTU can be changed with IPv6 disabled + mtu = '1600' + eth_if = 'eth0' + self.cli_set(['interfaces', 'ethernet', eth_if, 'mtu', mtu]) + self.cli_commit() + + tmp = get_interface_config(eth_if) + self.assertEqual(tmp['mtu'], int(mtu)) + + self.cli_delete(['interfaces', 'ethernet', eth_if, 'mtu']) + def test_system_ipv6_strict_dad(self): # This defaults to 1 self.assertEqual(read_file(file_dad), '1') -- cgit v1.2.3