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