From 3a1a7c40a13ee9f5561823a79876d88d3f5bf053 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 20 Feb 2022 10:36:33 +0100 Subject: interface: T4203: prevent DHCP client restart if not necessary In the past whenever a change happened to any interface and it was configured as a DHCP client, VyOS always had a breif outage as DHCP released the old lease and re-aquired a new one - bad! This commit changes the behavior that DHCP client is only restarted if any one of the possible options one can set for DHCP client under the "dhcp-options" node is altered. --- python/vyos/ifconfig/interface.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 91c7f0c33..cf1887bf6 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1228,12 +1228,11 @@ class Interface(Control): options_file = f'{config_base}_{ifname}.options' pid_file = f'{config_base}_{ifname}.pid' lease_file = f'{config_base}_{ifname}.leases' - - # Stop client with old config files to get the right IF_METRIC. systemd_service = f'dhclient@{ifname}.service' - if is_systemd_service_active(systemd_service): - self._cmd(f'systemctl stop {systemd_service}') + # 'up' check is mandatory b/c even if the interface is A/D, as soon as + # the DHCP client is started the interface will be placed in u/u state. + # This is not what we intended to do when disabling an interface. if enable and 'disable' not in self._config: if dict_search('dhcp_options.host_name', self._config) == None: # read configured system hostname. @@ -1244,16 +1243,19 @@ class Interface(Control): tmp = {'dhcp_options' : { 'host_name' : hostname}} self._config = dict_merge(tmp, self._config) - render(options_file, 'dhcp-client/daemon-options.tmpl', - self._config) - render(config_file, 'dhcp-client/ipv4.tmpl', - self._config) + render(options_file, 'dhcp-client/daemon-options.tmpl', self._config) + render(config_file, 'dhcp-client/ipv4.tmpl', self._config) - # 'up' check is mandatory b/c even if the interface is A/D, as soon as - # the DHCP client is started the interface will be placed in u/u state. - # This is not what we intended to do when disabling an interface. - return self._cmd(f'systemctl restart {systemd_service}') + # When the DHCP client is restarted a brief outage will occur, as + # the old lease is released a new one is acquired (T4203). We will + # only restart DHCP client if it's option changed, or if it's not + # running, but it should be running (e.g. on system startup) + if 'dhcp_options_old' in self._config or not is_systemd_service_active(systemd_service): + return self._cmd(f'systemctl restart {systemd_service}') + return None else: + if is_systemd_service_active(systemd_service): + self._cmd(f'systemctl stop {systemd_service}') # cleanup old config files for file in [config_file, options_file, pid_file, lease_file]: if os.path.isfile(file): -- cgit v1.2.3 From 0e23fc10581cde7b31101990566f59eded826233 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 3 Mar 2022 18:15:32 +0100 Subject: interface: T4203: switch to new recursive node_changed() implementation --- python/vyos/configdict.py | 42 ++++++++++----------------------------- python/vyos/ifconfig/interface.py | 4 ++-- 2 files changed, 13 insertions(+), 33 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index aea22c0c9..b8f428c1c 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -136,7 +136,7 @@ def leaf_node_changed(conf, path): return None -def node_changed(conf, path, key_mangling=None): +def node_changed(conf, path, key_mangling=None, recursive=False): """ Check if a leaf node was altered. If it has been altered - values has been changed, or it was added/removed, we will return the old value. If nothing @@ -146,7 +146,7 @@ def node_changed(conf, path, key_mangling=None): D = get_config_diff(conf, key_mangling) D.set_level(conf.get_level()) # get_child_nodes() will return dict_keys(), mangle this into a list with PEP448 - keys = D.get_child_nodes_diff(path, expand_nodes=Diff.DELETE)['delete'].keys() + keys = D.get_child_nodes_diff(path, expand_nodes=Diff.DELETE, recursive=recursive)['delete'].keys() return list(keys) def get_removed_vlans(conf, dict): @@ -444,13 +444,8 @@ def get_interface_dict(config, base, ifname=''): if bond: dict.update({'is_bond_member' : bond}) # Check if any DHCP options changed which require a client restat - for leaf_node in ['client-id', 'default-route-distance', 'host-name', - 'no-default-route', 'vendor-class-id']: - dhcp = leaf_node_changed(config, ['dhcp-options', leaf_node]) - if dhcp: - dict.update({'dhcp_options_old' : dhcp}) - # one option is suffiecient to set 'dhcp_options_old' key - break + dhcp = node_changed(config, ['dhcp-options'], recursive=True) + if dhcp: dict.update({'dhcp_options_changed' : ''}) # Some interfaces come with a source_interface which must also not be part # of any other bond or bridge interface as it is exclusivly assigned as the @@ -506,13 +501,8 @@ def get_interface_dict(config, base, ifname=''): if bridge: dict['vif'][vif].update({'is_bridge_member' : bridge}) # Check if any DHCP options changed which require a client restat - for leaf_node in ['client-id', 'default-route-distance', 'host-name', - 'no-default-route', 'vendor-class-id']: - dhcp = leaf_node_changed(config, ['vif', vif, 'dhcp-options', leaf_node]) - if dhcp: - dict['vif'][vif].update({'dhcp_options_old' : dhcp}) - # one option is suffiecient to set 'dhcp_options_old' key - break + dhcp = node_changed(config, ['vif', vif, 'dhcp-options'], recursive=True) + if dhcp: dict['vif'][vif].update({'dhcp_options_changed' : ''}) for vif_s, vif_s_config in dict.get('vif_s', {}).items(): default_vif_s_values = defaults(base + ['vif-s']) @@ -547,13 +537,8 @@ def get_interface_dict(config, base, ifname=''): if bridge: dict['vif_s'][vif_s].update({'is_bridge_member' : bridge}) # Check if any DHCP options changed which require a client restat - for leaf_node in ['client-id', 'default-route-distance', 'host-name', - 'no-default-route', 'vendor-class-id']: - dhcp = leaf_node_changed(config, ['vif-s', vif_s, 'dhcp-options', leaf_node]) - if dhcp: - dict['vif_s'][vif_s].update({'dhcp_options_old' : dhcp}) - # one option is suffiecient to set 'dhcp_options_old' key - break + dhcp = node_changed(config, ['vif-s', vif_s, 'dhcp-options'], recursive=True) + if dhcp: dict['vif_s'][vif_s].update({'dhcp_options_changed' : ''}) for vif_c, vif_c_config in vif_s_config.get('vif_c', {}).items(): default_vif_c_values = defaults(base + ['vif-s', 'vif-c']) @@ -589,14 +574,9 @@ def get_interface_dict(config, base, ifname=''): {'is_bridge_member' : bridge}) # Check if any DHCP options changed which require a client restat - for leaf_node in ['client-id', 'default-route-distance', 'host-name', - 'no-default-route', 'vendor-class-id']: - dhcp = leaf_node_changed(config, ['vif-s', vif_s, 'vif-c', vif_c, - 'dhcp-options', leaf_node]) - if dhcp: - dict['vif_s'][vif_s]['vif_c'][vif_c].update({'dhcp_options_old' : dhcp}) - # one option is suffiecient to set 'dhcp_options_old' key - break + dhcp = leaf_node_changed(config, ['vif-s', vif_s, 'vif-c', vif_c, + 'dhcp-options'], recursive=True) + if dhcp: dict['vif_s'][vif_s]['vif_c'][vif_c].update({'dhcp_options_changed' : ''}) # Check vif, vif-s/vif-c VLAN interfaces for removal dict = get_removed_vlans(config, dict) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index cf1887bf6..8c5ff576e 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1,4 +1,4 @@ -# Copyright 2019-2021 VyOS maintainers and contributors +# Copyright 2019-2022 VyOS maintainers and contributors # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -1250,7 +1250,7 @@ class Interface(Control): # the old lease is released a new one is acquired (T4203). We will # only restart DHCP client if it's option changed, or if it's not # running, but it should be running (e.g. on system startup) - if 'dhcp_options_old' in self._config or not is_systemd_service_active(systemd_service): + if 'dhcp_options_changed' in self._config or not is_systemd_service_active(systemd_service): return self._cmd(f'systemctl restart {systemd_service}') return None else: -- cgit v1.2.3 From f8b3d8999cbea988ce8e7d303957558308ddc1bc Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 25 Mar 2022 18:56:06 +0100 Subject: ipv6: T4319: do not configure IPv6 related settings if it's disabled --- python/vyos/ifconfig/interface.py | 93 ++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 45 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 8c5ff576e..8ce851cdb 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -39,6 +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.template import is_ipv4 from vyos.template import is_ipv6 from vyos.validate import is_intf_addr_assigned @@ -1448,11 +1449,6 @@ class Interface(Control): value = tmp if (tmp != None) else '0' self.set_tcp_ipv4_mss(value) - # Configure MSS value for IPv6 TCP connections - tmp = dict_search('ipv6.adjust_mss', config) - value = tmp if (tmp != None) else '0' - self.set_tcp_ipv6_mss(value) - # Configure ARP cache timeout in milliseconds - has default value tmp = dict_search('ip.arp_cache_timeout', config) value = tmp if (tmp != None) else '30' @@ -1498,47 +1494,54 @@ class Interface(Control): value = tmp if (tmp != None) else '0' self.set_ipv4_source_validation(value) - # IPv6 forwarding - tmp = dict_search('ipv6.disable_forwarding', config) - value = '0' if (tmp != None) else '1' - self.set_ipv6_forwarding(value) - - # IPv6 router advertisements - tmp = dict_search('ipv6.address.autoconf', config) - value = '2' if (tmp != None) else '1' - if 'dhcpv6' in new_addr: - value = '2' - self.set_ipv6_accept_ra(value) - - # IPv6 address autoconfiguration - tmp = dict_search('ipv6.address.autoconf', config) - value = '1' if (tmp != None) else '0' - self.set_ipv6_autoconf(value) - - # IPv6 Duplicate Address Detection (DAD) tries - tmp = dict_search('ipv6.dup_addr_detect_transmits', config) - 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) - - # Manage IPv6 link-local addresses - if dict_search('ipv6.address.no_default_link_local', config) != None: - self.del_ipv6_eui64_address('fe80::/64') - else: - self.add_ipv6_eui64_address('fe80::/64') + # Only change IPv6 parameters if IPv6 was not explicitly disabled + if sysctl_read('net.ipv6.conf.all.disable_ipv6') == '0': + # Configure MSS value for IPv6 TCP connections + tmp = dict_search('ipv6.adjust_mss', config) + value = tmp if (tmp != None) else '0' + self.set_tcp_ipv6_mss(value) + + # IPv6 forwarding + tmp = dict_search('ipv6.disable_forwarding', config) + value = '0' if (tmp != None) else '1' + self.set_ipv6_forwarding(value) + + # IPv6 router advertisements + tmp = dict_search('ipv6.address.autoconf', config) + value = '2' if (tmp != None) else '1' + if 'dhcpv6' in new_addr: + value = '2' + self.set_ipv6_accept_ra(value) + + # IPv6 address autoconfiguration + tmp = dict_search('ipv6.address.autoconf', config) + value = '1' if (tmp != None) else '0' + self.set_ipv6_autoconf(value) + + # IPv6 Duplicate Address Detection (DAD) tries + tmp = dict_search('ipv6.dup_addr_detect_transmits', config) + 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) + + # Manage IPv6 link-local addresses + if dict_search('ipv6.address.no_default_link_local', config) != None: + self.del_ipv6_eui64_address('fe80::/64') + else: + self.add_ipv6_eui64_address('fe80::/64') - # Add IPv6 EUI-based addresses - tmp = dict_search('ipv6.address.eui64', config) - if tmp: - for addr in tmp: - self.add_ipv6_eui64_address(addr) + # Add IPv6 EUI-based addresses + tmp = dict_search('ipv6.address.eui64', config) + if tmp: + for addr in tmp: + self.add_ipv6_eui64_address(addr) # re-add ourselves to any bridge we might have fallen out of if 'is_bridge_member' in config: -- cgit v1.2.3 From bafb1973d906707cb571385e994a949d0d90b645 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 30 Mar 2022 19:16:52 +0200 Subject: vyos.ifconfig: make add_addr() method more reader firendly --- python/vyos/ifconfig/interface.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 8ce851cdb..4fda1c0a9 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1089,8 +1089,11 @@ class Interface(Control): elif addr == 'dhcpv6': self.set_dhcpv6(True) elif not is_intf_addr_assigned(self.ifname, addr): - self._cmd(f'ip addr add "{addr}" ' - f'{"brd + " if addr_is_v4 else ""}dev "{self.ifname}"') + tmp = f'ip addr add {addr} dev {self.ifname}' + # Add broadcast address for IPv4 + if is_ipv4(addr): tmp += ' brd +' + + self._cmd(tmp) else: return False -- cgit v1.2.3 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(-) (limited to 'python/vyos/ifconfig/interface.py') 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 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(+) (limited to 'python/vyos/ifconfig/interface.py') 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 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(-) (limited to 'python/vyos/ifconfig/interface.py') 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 From 601ab19fd8c81a998b3c966cc83b85ed60ac5ae0 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 31 Mar 2022 21:38:17 +0200 Subject: vyos.ifconfig: T4330: MTU must be configured prior to any IPv6 option change This extends the fix from 53e20097 ("vyos.ifconfig: T4330: bugfix changing MTU when IPv6 is disabled") by ordering the execution in a way the Kernel does not complain. --- python/vyos/ifconfig/interface.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index f39da90e4..d6906a061 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1501,6 +1501,13 @@ class Interface(Control): value = tmp if (tmp != None) else '0' self.set_ipv4_source_validation(value) + # MTU - Maximum Transfer Unit has a default value. It must ALWAYS be set + # before mangling any IPv6 option. If MTU is less then 1280 IPv6 will be + # automatically disabled by the kernel. Also MTU must be increased before + # configuring any IPv6 address on the interface. + if 'mtu' in config: + self.set_mtu(config.get('mtu')) + # Only change IPv6 parameters if IPv6 was not explicitly disabled if is_ipv6_enabled(): # Configure MSS value for IPv6 TCP connections @@ -1546,10 +1553,6 @@ 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') -- cgit v1.2.3 From d6e22b28887c7a3f7d2f8b955c2e90bcadaeeeba Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Tue, 5 Apr 2022 11:20:54 +0000 Subject: interfaces: T4331: Fix assign link-local static IPv6 addr to vrf If we have link-local static address and vrf, for example: set interfaces ethernet eth2 address 'fe80::5200:ff:fe55:222/64' set interfaces ethernet eth2 vrf 'foo' This IPv6 address was assigned before vrf, as result after attaching the intreface to vrf we lose this static linklocal address DEBUG/IFCONFIG cmd 'ip addr add fe80::5200:ff:fe55:222/64 dev eth2' DEBUG/IFCONFIG cmd 'ip link set dev eth2 master foo' DEBUG/IFCONFIG cmd 'ip addr add fe80::5208:ff:fe13:2/64 dev eth2' This commit fixes this, the address is assigned after vrf assign --- python/vyos/ifconfig/interface.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index d6906a061..585a605e4 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1434,9 +1434,6 @@ class Interface(Control): else: self.del_addr(addr) - for addr in new_addr: - self.add_addr(addr) - # start DHCPv6 client when only PD was configured if dhcpv6pd: self.set_dhcpv6(True) @@ -1451,6 +1448,10 @@ class Interface(Control): # checked before self.set_vrf(config.get('vrf', '')) + # Add this section after vrf T4331 + for addr in new_addr: + self.add_addr(addr) + # Configure MSS value for IPv4 TCP connections tmp = dict_search('ip.adjust_mss', config) value = tmp if (tmp != None) else '0' -- cgit v1.2.3 From 37c6d9fae5172b0342f94212e6483b3aa8fcd673 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 23 Mar 2022 10:07:41 +0100 Subject: qos: T4284: support mirror and redirect on all interface types --- interface-definitions/interfaces-dummy.xml.in | 1 + interface-definitions/interfaces-geneve.xml.in | 1 + interface-definitions/interfaces-l2tpv3.xml.in | 1 + interface-definitions/interfaces-loopback.xml.in | 1 + interface-definitions/interfaces-macsec.xml.in | 1 + interface-definitions/interfaces-openvpn.xml.in | 1 + interface-definitions/interfaces-pppoe.xml.in | 1 + .../interfaces-pseudo-ethernet.xml.in | 1 + interface-definitions/interfaces-tunnel.xml.in | 1 + interface-definitions/interfaces-vti.xml.in | 1 + interface-definitions/interfaces-vxlan.xml.in | 1 + interface-definitions/interfaces-wireguard.xml.in | 1 + interface-definitions/interfaces-wireless.xml.in | 1 + interface-definitions/interfaces-wwan.xml.in | 1 + python/vyos/configverify.py | 27 +++---- python/vyos/ifconfig/interface.py | 84 ++++++++++++---------- src/conf_mode/interfaces-bonding.py | 6 +- src/conf_mode/interfaces-bridge.py | 6 +- src/conf_mode/interfaces-dummy.py | 4 +- src/conf_mode/interfaces-ethernet.py | 6 +- src/conf_mode/interfaces-geneve.py | 4 +- src/conf_mode/interfaces-l2tpv3.py | 4 +- src/conf_mode/interfaces-loopback.py | 4 +- src/conf_mode/interfaces-macsec.py | 4 +- src/conf_mode/interfaces-openvpn.py | 2 + src/conf_mode/interfaces-pppoe.py | 4 +- src/conf_mode/interfaces-pseudo-ethernet.py | 4 +- src/conf_mode/interfaces-tunnel.py | 4 +- src/conf_mode/interfaces-vti.py | 4 +- src/conf_mode/interfaces-vxlan.py | 4 +- src/conf_mode/interfaces-wireguard.py | 4 +- src/conf_mode/interfaces-wireless.py | 4 +- src/conf_mode/interfaces-wwan.py | 4 +- 33 files changed, 107 insertions(+), 90 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/interface-definitions/interfaces-dummy.xml.in b/interface-definitions/interfaces-dummy.xml.in index 109ed1b50..988d87502 100644 --- a/interface-definitions/interfaces-dummy.xml.in +++ b/interface-definitions/interfaces-dummy.xml.in @@ -29,6 +29,7 @@ #include + #include #include #include #include diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in index aa5809e60..5f2c6bc05 100644 --- a/interface-definitions/interfaces-geneve.xml.in +++ b/interface-definitions/interfaces-geneve.xml.in @@ -50,6 +50,7 @@ + #include #include #include #include diff --git a/interface-definitions/interfaces-l2tpv3.xml.in b/interface-definitions/interfaces-l2tpv3.xml.in index 680170b0f..0dcabf7a0 100644 --- a/interface-definitions/interfaces-l2tpv3.xml.in +++ b/interface-definitions/interfaces-l2tpv3.xml.in @@ -58,6 +58,7 @@ #include #include #include + #include #include 1488 diff --git a/interface-definitions/interfaces-loopback.xml.in b/interface-definitions/interfaces-loopback.xml.in index ffffc0220..1e093d95b 100644 --- a/interface-definitions/interfaces-loopback.xml.in +++ b/interface-definitions/interfaces-loopback.xml.in @@ -26,6 +26,7 @@ #include + #include #include #include diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in index 311e95c2f..fbdd1562a 100644 --- a/interface-definitions/interfaces-macsec.xml.in +++ b/interface-definitions/interfaces-macsec.xml.in @@ -23,6 +23,7 @@ #include #include #include + #include Security/Encryption Settings diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in index 73e30e590..761f8bcad 100644 --- a/interface-definitions/interfaces-openvpn.xml.in +++ b/interface-definitions/interfaces-openvpn.xml.in @@ -168,6 +168,7 @@ #include + #include Hashing Algorithm diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in index 1d888236e..adf5f4040 100644 --- a/interface-definitions/interfaces-pppoe.xml.in +++ b/interface-definitions/interfaces-pppoe.xml.in @@ -102,6 +102,7 @@ + #include #include 1492 diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in index 7baeac537..aed2052f5 100644 --- a/interface-definitions/interfaces-pseudo-ethernet.xml.in +++ b/interface-definitions/interfaces-pseudo-ethernet.xml.in @@ -27,6 +27,7 @@ #include #include #include + #include #include #include diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in index bc9297c86..b31f22552 100644 --- a/interface-definitions/interfaces-tunnel.xml.in +++ b/interface-definitions/interfaces-tunnel.xml.in @@ -107,6 +107,7 @@ Invalid encapsulation, must be one of: erspan, gre, gretap, ip6erspan, ip6gre, ip6gretap, ipip, sit, ipip6 or ip6ip6 + #include Multicast operation over tunnel diff --git a/interface-definitions/interfaces-vti.xml.in b/interface-definitions/interfaces-vti.xml.in index 538194c2b..d66fc952e 100644 --- a/interface-definitions/interfaces-vti.xml.in +++ b/interface-definitions/interfaces-vti.xml.in @@ -34,6 +34,7 @@ #include #include #include + #include #include #include #include diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index 18abf9f20..b1a2dfaec 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -53,6 +53,7 @@ #include #include #include + #include #include #include diff --git a/interface-definitions/interfaces-wireguard.xml.in b/interface-definitions/interfaces-wireguard.xml.in index 2f130c6f2..51565cfe6 100644 --- a/interface-definitions/interfaces-wireguard.xml.in +++ b/interface-definitions/interfaces-wireguard.xml.in @@ -23,6 +23,7 @@ #include #include #include + #include 1420 diff --git a/interface-definitions/interfaces-wireless.xml.in b/interface-definitions/interfaces-wireless.xml.in index ef56c208a..a16a7841e 100644 --- a/interface-definitions/interfaces-wireless.xml.in +++ b/interface-definitions/interfaces-wireless.xml.in @@ -566,6 +566,7 @@ g + #include Wireless physical device diff --git a/interface-definitions/interfaces-wwan.xml.in b/interface-definitions/interfaces-wwan.xml.in index c46bc58a7..33bc0cb3d 100644 --- a/interface-definitions/interfaces-wwan.xml.in +++ b/interface-definitions/interfaces-wwan.xml.in @@ -31,6 +31,7 @@ #include #include #include + #include #include 1430 diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index 7f1258575..df2c5775a 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -178,31 +178,26 @@ def verify_eapol(config): if 'certificate' not in ca_cert: raise ConfigError('Invalid CA certificate specified for EAPoL') -def verify_mirror(config): +def verify_mirror_redirect(config): """ Common helper function used by interface implementations to perform - recurring validation of mirror interface configuration. + recurring validation of mirror and redirect interface configuration via tc(8) It makes no sense to mirror traffic back at yourself! """ + if {'mirror', 'redirect'} <= set(config): + raise ConfigError('Mirror and redirect can not be enabled at the same time!') + if 'mirror' in config: for direction, mirror_interface in config['mirror'].items(): if mirror_interface == config['ifname']: raise ConfigError(f'Can not mirror "{direction}" traffic back ' \ 'the originating interface!') -def verify_redirect(config): - """ - Common helper function used by interface implementations to perform - recurring validation of the redirect interface configuration. - - It makes no sense to mirror and redirect traffic at the same time! - """ - if {'mirror', 'redirect'} <= set(config): - raise ConfigError('Can not do both redirect and mirror') - if dict_search('traffic_policy.in', config) != None: - raise ConfigError('Can not use ingress policy and redirect') + # XXX: support combination of limiting and redirect/mirror - this is an + # artificial limitation + raise ConfigError('Can not use ingress policy tigether with mirror or redirect!') def verify_authentication(config): """ @@ -328,7 +323,7 @@ def verify_vlan_config(config): verify_dhcpv6(vlan) verify_address(vlan) verify_vrf(vlan) - verify_redirect(vlan) + verify_mirror_redirect(vlan) verify_mtu_parent(vlan, config) # 802.1ad (Q-in-Q) VLANs @@ -337,7 +332,7 @@ def verify_vlan_config(config): verify_dhcpv6(s_vlan) verify_address(s_vlan) verify_vrf(s_vlan) - verify_redirect(s_vlan) + verify_mirror_redirect(s_vlan) verify_mtu_parent(s_vlan, config) for c_vlan in s_vlan.get('vif_c', {}): @@ -345,7 +340,7 @@ def verify_vlan_config(config): verify_dhcpv6(c_vlan) verify_address(c_vlan) verify_vrf(c_vlan) - verify_redirect(c_vlan) + verify_mirror_redirect(c_vlan) verify_mtu_parent(c_vlan, config) verify_mtu_parent(c_vlan, s_vlan) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 585a605e4..76164ca32 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1294,48 +1294,60 @@ class Interface(Control): if os.path.isfile(config_file): os.remove(config_file) - def set_mirror(self): + def set_mirror_redirect(self): # Please refer to the document for details # - https://man7.org/linux/man-pages/man8/tc.8.html # - https://man7.org/linux/man-pages/man8/tc-mirred.8.html # Depening if we are the source or the target interface of the port # mirror we need to setup some variables. source_if = self._config['ifname'] - config = self._config.get('mirror', None) + mirror_config = None + if 'mirror' in self._config: + mirror_config = self._config['mirror'] if 'is_mirror_intf' in self._config: source_if = next(iter(self._config['is_mirror_intf'])) - config = self._config['is_mirror_intf'][source_if].get('mirror', None) - - # Check configuration stored by old perl code before delete T3782/T4056 - if not 'redirect' in self._config and not 'traffic_policy' in self._config: - # Please do not clear the 'set $? = 0 '. It's meant to force a return of 0 - # Remove existing mirroring rules - delete_tc_cmd = f'tc qdisc del dev {source_if} handle ffff: ingress 2> /dev/null;' - delete_tc_cmd += f'tc qdisc del dev {source_if} handle 1: root prio 2> /dev/null;' - delete_tc_cmd += 'set $?=0' - self._popen(delete_tc_cmd) - - # Bail out early if nothing needs to be configured - if not config: - return - - for direction, mirror_if in config.items(): - if mirror_if not in interfaces(): - continue - - if direction == 'ingress': - handle = 'ffff: ingress' - parent = 'ffff:' - elif direction == 'egress': - handle = '1: root prio' - parent = '1:' - - # Mirror egress traffic - mirror_cmd = f'tc qdisc add dev {source_if} handle {handle}; ' - # Export the mirrored traffic to the interface - mirror_cmd += f'tc filter add dev {source_if} parent {parent} protocol all prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress mirror dev {mirror_if}' - self._popen(mirror_cmd) + mirror_config = self._config['is_mirror_intf'][source_if].get('mirror', None) + + redirect_config = None + + # clear existing ingess - ignore errors (e.g. "Error: Cannot find specified + # qdisc on specified device") - we simply cleanup all stuff here + self._popen(f'tc qdisc del dev {source_if} parent ffff: 2>/dev/null'); + self._popen(f'tc qdisc del dev {source_if} parent 1: 2>/dev/null'); + + # Apply interface mirror policy + if mirror_config: + for direction, target_if in mirror_config.items(): + if target_if not in interfaces(): + continue + + if direction == 'ingress': + handle = 'ffff: ingress' + parent = 'ffff:' + elif direction == 'egress': + handle = '1: root prio' + parent = '1:' + + # Mirror egress traffic + mirror_cmd = f'tc qdisc add dev {source_if} handle {handle}; ' + # Export the mirrored traffic to the interface + mirror_cmd += f'tc filter add dev {source_if} parent {parent} protocol '\ + f'all prio 10 u32 match u32 0 0 flowid 1:1 action mirred '\ + f'egress mirror dev {target_if}' + _, err = self._popen(mirror_cmd) + if err: print('tc qdisc(filter for mirror port failed') + + # Apply interface traffic redirection policy + elif 'redirect' in self._config: + _, err = self._popen(f'tc qdisc add dev {source_if} handle ffff: ingress') + if err: print(f'tc qdisc add for redirect failed!') + + target_if = self._config['redirect'] + _, err = self._popen(f'tc filter add dev {source_if} parent ffff: protocol '\ + f'all prio 10 u32 match u32 0 0 flowid 1:1 action mirred '\ + f'egress redirect dev {target_if}') + if err: print('tc filter add for redirect failed') def set_xdp(self, state): """ @@ -1562,8 +1574,8 @@ class Interface(Control): # eXpress Data Path - highly experimental self.set_xdp('xdp' in config) - # configure port mirror - self.set_mirror() + # configure interface mirror or redirection target + self.set_mirror_redirect() # Enable/Disable of an interface must always be done at the end of the # derived class to make use of the ref-counting set_admin_state() @@ -1723,5 +1735,5 @@ class VLANIf(Interface): return super().set_admin_state(state) - def set_mirror(self): + def set_mirror_redirect(self): return diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 661dc2298..ad5a0f499 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -27,9 +27,8 @@ from vyos.configdict import is_source_interface from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_dhcpv6 -from vyos.configverify import verify_mirror +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect from vyos.configverify import verify_source_interface from vyos.configverify import verify_vlan_config from vyos.configverify import verify_vrf @@ -151,8 +150,7 @@ def verify(bond): verify_address(bond) verify_dhcpv6(bond) verify_vrf(bond) - verify_mirror(bond) - verify_redirect(bond) + verify_mirror_redirect(bond) # use common function to verify VLAN configuration verify_vlan_config(bond) diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index e16c0e9f4..b1f7e6d7c 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -27,8 +27,7 @@ from vyos.configdict import is_source_interface from vyos.configdict import has_vlan_subinterface_configured from vyos.configdict import dict_merge from vyos.configverify import verify_dhcpv6 -from vyos.configverify import verify_mirror -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_vrf from vyos.ifconfig import BridgeIf from vyos.validate import has_address_configured @@ -107,8 +106,7 @@ def verify(bridge): verify_dhcpv6(bridge) verify_vrf(bridge) - verify_mirror(bridge) - verify_redirect(bridge) + verify_mirror_redirect(bridge) ifname = bridge['ifname'] diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 4072c4452..4a1eb7b93 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -21,7 +21,7 @@ from vyos.configdict import get_interface_dict from vyos.configverify import verify_vrf from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import DummyIf from vyos import ConfigError from vyos import airbag @@ -47,7 +47,7 @@ def verify(dummy): verify_vrf(dummy) verify_address(dummy) - verify_redirect(dummy) + verify_mirror_redirect(dummy) return None diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 3eeddf190..6aea7a80e 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -25,10 +25,9 @@ from vyos.configverify import verify_address from vyos.configverify import verify_dhcpv6 from vyos.configverify import verify_eapol from vyos.configverify import verify_interface_exists -from vyos.configverify import verify_mirror +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_mtu from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect from vyos.configverify import verify_vlan_config from vyos.configverify import verify_vrf from vyos.ethtool import Ethtool @@ -84,8 +83,7 @@ def verify(ethernet): verify_address(ethernet) verify_vrf(ethernet) verify_eapol(ethernet) - verify_mirror(ethernet) - verify_redirect(ethernet) + verify_mirror_redirect(ethernet) ethtool = Ethtool(ifname) # No need to check speed and duplex keys as both have default values. diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index a94b5e1f7..3a668226b 100755 --- a/src/conf_mode/interfaces-geneve.py +++ b/src/conf_mode/interfaces-geneve.py @@ -24,7 +24,7 @@ from vyos.configdict import get_interface_dict from vyos.configverify import verify_address from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_bridge_delete -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import GeneveIf from vyos import ConfigError @@ -51,7 +51,7 @@ def verify(geneve): verify_mtu_ipv6(geneve) verify_address(geneve) - verify_redirect(geneve) + verify_mirror_redirect(geneve) if 'remote' not in geneve: raise ConfigError('Remote side must be configured') diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 5ea7159dc..22256bf4f 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -25,7 +25,7 @@ from vyos.configdict import leaf_node_changed from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import L2TPv3If from vyos.util import check_kmod from vyos.validate import is_addr_assigned @@ -77,7 +77,7 @@ def verify(l2tpv3): verify_mtu_ipv6(l2tpv3) verify_address(l2tpv3) - verify_redirect(l2tpv3) + verify_mirror_redirect(l2tpv3) return None def generate(l2tpv3): diff --git a/src/conf_mode/interfaces-loopback.py b/src/conf_mode/interfaces-loopback.py index e6a851113..e4bc15bb5 100755 --- a/src/conf_mode/interfaces-loopback.py +++ b/src/conf_mode/interfaces-loopback.py @@ -20,7 +20,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_interface_dict -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import LoopbackIf from vyos import ConfigError from vyos import airbag @@ -40,7 +40,7 @@ def get_config(config=None): return loopback def verify(loopback): - verify_redirect(loopback) + verify_mirror_redirect(loopback) return None def generate(loopback): diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py index 6a29fdb11..96fc1c41c 100755 --- a/src/conf_mode/interfaces-macsec.py +++ b/src/conf_mode/interfaces-macsec.py @@ -29,7 +29,7 @@ from vyos.configverify import verify_vrf from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_source_interface from vyos import ConfigError from vyos import airbag @@ -67,7 +67,7 @@ def verify(macsec): verify_vrf(macsec) verify_mtu_ipv6(macsec) verify_address(macsec) - verify_redirect(macsec) + verify_mirror_redirect(macsec) if not (('security' in macsec) and ('cipher' in macsec['security'])): diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 8f9c0b3f1..83d1c6d9b 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -35,6 +35,7 @@ from vyos.configdict import get_interface_dict from vyos.configdict import leaf_node_changed from vyos.configverify import verify_vrf from vyos.configverify import verify_bridge_delete +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import VTunIf from vyos.pki import load_dh_parameters from vyos.pki import load_private_key @@ -495,6 +496,7 @@ def verify(openvpn): raise ConfigError('Username for authentication is missing') verify_vrf(openvpn) + verify_mirror_redirect(openvpn) return None diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index 9962e0a08..bfb1fadd5 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -28,7 +28,7 @@ from vyos.configverify import verify_source_interface from vyos.configverify import verify_interface_exists from vyos.configverify import verify_vrf from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import PPPoEIf from vyos.template import render from vyos.util import call @@ -86,7 +86,7 @@ def verify(pppoe): verify_authentication(pppoe) verify_vrf(pppoe) verify_mtu_ipv6(pppoe) - verify_redirect(pppoe) + verify_mirror_redirect(pppoe) if {'connect_on_demand', 'vrf'} <= set(pppoe): raise ConfigError('On-demand dialing and VRF can not be used at the same time') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index f57e41cc4..f2c85554f 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -25,7 +25,7 @@ from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_source_interface from vyos.configverify import verify_vlan_config from vyos.configverify import verify_mtu_parent -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import MACVLANIf from vyos import ConfigError @@ -61,7 +61,7 @@ def verify(peth): verify_vrf(peth) verify_address(peth) verify_mtu_parent(peth, peth['parent']) - verify_redirect(peth) + verify_mirror_redirect(peth) # use common function to verify VLAN configuration verify_vlan_config(peth) diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 005fae5eb..f4668d976 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -26,7 +26,7 @@ from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_interface_exists from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_vrf from vyos.configverify import verify_tunnel from vyos.ifconfig import Interface @@ -158,7 +158,7 @@ def verify(tunnel): verify_mtu_ipv6(tunnel) verify_address(tunnel) verify_vrf(tunnel) - verify_redirect(tunnel) + verify_mirror_redirect(tunnel) if 'source_interface' in tunnel: verify_interface_exists(tunnel['source_interface']) diff --git a/src/conf_mode/interfaces-vti.py b/src/conf_mode/interfaces-vti.py index 30e13536f..f06fdff1b 100755 --- a/src/conf_mode/interfaces-vti.py +++ b/src/conf_mode/interfaces-vti.py @@ -19,7 +19,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_interface_dict -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import VTIIf from vyos.util import dict_search from vyos import ConfigError @@ -40,7 +40,7 @@ def get_config(config=None): return vti def verify(vti): - verify_redirect(vti) + verify_mirror_redirect(vti) return None def generate(vti): diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index a29836efd..0a9b51cac 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -25,7 +25,7 @@ from vyos.configdict import leaf_node_changed from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_source_interface from vyos.ifconfig import Interface from vyos.ifconfig import VXLANIf @@ -141,7 +141,7 @@ def verify(vxlan): verify_mtu_ipv6(vxlan) verify_address(vxlan) - verify_redirect(vxlan) + verify_mirror_redirect(vxlan) return None def generate(vxlan): diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index dc0fe7b9c..b404375d6 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -28,7 +28,7 @@ from vyos.configverify import verify_vrf from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_mtu_ipv6 -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.ifconfig import WireGuardIf from vyos.util import check_kmod from vyos.util import check_port_availability @@ -71,7 +71,7 @@ def verify(wireguard): verify_mtu_ipv6(wireguard) verify_address(wireguard) verify_vrf(wireguard) - verify_redirect(wireguard) + verify_mirror_redirect(wireguard) if 'private_key' not in wireguard: raise ConfigError('Wireguard private-key not defined') diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index fdf9e3988..500952df1 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -27,7 +27,7 @@ from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_dhcpv6 from vyos.configverify import verify_source_interface -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_vlan_config from vyos.configverify import verify_vrf from vyos.ifconfig import WiFiIf @@ -190,7 +190,7 @@ def verify(wifi): verify_address(wifi) verify_vrf(wifi) - verify_redirect(wifi) + verify_mirror_redirect(wifi) # use common function to verify VLAN configuration verify_vlan_config(wifi) diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py index d5e259c74..9a33039a3 100755 --- a/src/conf_mode/interfaces-wwan.py +++ b/src/conf_mode/interfaces-wwan.py @@ -24,7 +24,7 @@ from vyos.configdict import get_interface_dict from vyos.configdict import leaf_node_changed from vyos.configverify import verify_authentication from vyos.configverify import verify_interface_exists -from vyos.configverify import verify_redirect +from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_vrf from vyos.ifconfig import WWANIf from vyos.util import cmd @@ -105,7 +105,7 @@ def verify(wwan): verify_interface_exists(ifname) verify_authentication(wwan) verify_vrf(wwan) - verify_redirect(wwan) + verify_mirror_redirect(wwan) return None -- cgit v1.2.3 From 4ecf558f53d1740b5ddb0de1f7effbaf0f44ff5f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 23 Mar 2022 10:40:06 +0100 Subject: qos: T4284: support mirror and redirect on vlan subinterfaces --- interface-definitions/include/interface/vif-s.xml.i | 2 ++ interface-definitions/include/interface/vif.xml.i | 1 + python/vyos/configverify.py | 19 +++++++++++++------ python/vyos/ifconfig/interface.py | 3 --- 4 files changed, 16 insertions(+), 9 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/interface-definitions/include/interface/vif-s.xml.i b/interface-definitions/include/interface/vif-s.xml.i index 59a47b5ff..40a87e3d3 100644 --- a/interface-definitions/include/interface/vif-s.xml.i +++ b/interface-definitions/include/interface/vif-s.xml.i @@ -44,6 +44,7 @@ #include #include #include + #include #include @@ -63,6 +64,7 @@ #include #include #include + #include #include #include #include diff --git a/interface-definitions/include/interface/vif.xml.i b/interface-definitions/include/interface/vif.xml.i index 8a1475711..615101664 100644 --- a/interface-definitions/include/interface/vif.xml.i +++ b/interface-definitions/include/interface/vif.xml.i @@ -49,6 +49,7 @@ #include #include #include + #include #include #include #include diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index df2c5775a..9f2771854 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -317,9 +317,12 @@ def verify_vlan_config(config): if duplicate: raise ConfigError(f'Duplicate VLAN id "{duplicate[0]}" used for vif and vif-s interfaces!') + parent_ifname = config['ifname'] # 802.1q VLANs - for vlan in config.get('vif', {}): - vlan = config['vif'][vlan] + for vlan_id in config.get('vif', {}): + vlan = config['vif'][vlan_id] + vlan['ifname'] = f'{parent_ifname}.{vlan_id}' + verify_dhcpv6(vlan) verify_address(vlan) verify_vrf(vlan) @@ -327,16 +330,20 @@ def verify_vlan_config(config): verify_mtu_parent(vlan, config) # 802.1ad (Q-in-Q) VLANs - for s_vlan in config.get('vif_s', {}): - s_vlan = config['vif_s'][s_vlan] + for s_vlan_id in config.get('vif_s', {}): + s_vlan = config['vif_s'][s_vlan_id] + s_vlan['ifname'] = f'{parent_ifname}.{s_vlan_id}' + verify_dhcpv6(s_vlan) verify_address(s_vlan) verify_vrf(s_vlan) verify_mirror_redirect(s_vlan) verify_mtu_parent(s_vlan, config) - for c_vlan in s_vlan.get('vif_c', {}): - c_vlan = s_vlan['vif_c'][c_vlan] + for c_vlan_id in s_vlan.get('vif_c', {}): + c_vlan = s_vlan['vif_c'][c_vlan_id] + c_vlan['ifname'] = f'{parent_ifname}.{s_vlan_id}.{c_vlan_id}' + verify_dhcpv6(c_vlan) verify_address(c_vlan) verify_vrf(c_vlan) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 76164ca32..1464b2969 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1734,6 +1734,3 @@ class VLANIf(Interface): return None return super().set_admin_state(state) - - def set_mirror_redirect(self): - return -- cgit v1.2.3 From 7581a5c6cbbc3f0e38ac69028b814252805d5c98 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 23 Mar 2022 10:58:02 +0100 Subject: qos: T4284: verify mirror/redirect target interface exists --- python/vyos/configverify.py | 13 ++++++++++++- python/vyos/ifconfig/interface.py | 4 ---- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py index 9f2771854..1062d51ee 100644 --- a/python/vyos/configverify.py +++ b/python/vyos/configverify.py @@ -185,15 +185,26 @@ def verify_mirror_redirect(config): It makes no sense to mirror traffic back at yourself! """ + import os if {'mirror', 'redirect'} <= set(config): raise ConfigError('Mirror and redirect can not be enabled at the same time!') if 'mirror' in config: for direction, mirror_interface in config['mirror'].items(): + if not os.path.exists(f'/sys/class/net/{mirror_interface}'): + raise ConfigError(f'Requested mirror interface "{mirror_interface}" '\ + 'does not exist!') + if mirror_interface == config['ifname']: - raise ConfigError(f'Can not mirror "{direction}" traffic back ' \ + raise ConfigError(f'Can not mirror "{direction}" traffic back '\ 'the originating interface!') + if 'redirect' in config: + redirect_ifname = config['redirect'] + if not os.path.exists(f'/sys/class/net/{redirect_ifname}'): + raise ConfigError(f'Requested redirect interface "{redirect_ifname}" '\ + 'does not exist!') + if dict_search('traffic_policy.in', config) != None: # XXX: support combination of limiting and redirect/mirror - this is an # artificial limitation diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 1464b2969..5b2760386 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see . -from netifaces import interfaces import os import re import json @@ -1319,9 +1318,6 @@ class Interface(Control): # Apply interface mirror policy if mirror_config: for direction, target_if in mirror_config.items(): - if target_if not in interfaces(): - continue - if direction == 'ingress': handle = 'ffff: ingress' parent = 'ffff:' -- cgit v1.2.3 From 440a7a1c965be39ca0b13b4ea5985dd9c95fabef Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 7 Apr 2022 19:07:52 +0200 Subject: ipv6: T4346: delete (migrate) CLI command to disable IPv6 address family --- .../include/version/system-version.xml.i | 2 +- interface-definitions/system-ipv6.xml.in | 6 -- python/vyos/ifconfig/interface.py | 91 ++++++++++------------ python/vyos/ifconfig/loopback.py | 12 ++- python/vyos/util.py | 4 - smoketest/configs/ipv6-disable | 83 ++++++++++++++++++++ smoketest/scripts/cli/test_system_ipv6.py | 36 --------- src/conf_mode/system-ipv6.py | 18 ----- src/conf_mode/vrf.py | 4 +- src/migration-scripts/system/22-to-23 | 50 ++++++++++++ src/tests/test_util.py | 10 --- 11 files changed, 181 insertions(+), 135 deletions(-) create mode 100644 smoketest/configs/ipv6-disable create mode 100755 src/migration-scripts/system/22-to-23 (limited to 'python/vyos/ifconfig/interface.py') diff --git a/interface-definitions/include/version/system-version.xml.i b/interface-definitions/include/version/system-version.xml.i index fb4629bf1..19591256d 100644 --- a/interface-definitions/include/version/system-version.xml.i +++ b/interface-definitions/include/version/system-version.xml.i @@ -1,3 +1,3 @@ - + diff --git a/interface-definitions/system-ipv6.xml.in b/interface-definitions/system-ipv6.xml.in index af4dcdb0f..63260d00c 100644 --- a/interface-definitions/system-ipv6.xml.in +++ b/interface-definitions/system-ipv6.xml.in @@ -15,12 +15,6 @@ - - - Disable assignment of IPv6 addresses on all interfaces - - - IPv6 multipath settings diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 5b2760386..6b0f08fd4 100755 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -38,7 +38,6 @@ 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 is_ipv6_enabled from vyos.template import is_ipv4 from vyos.template import is_ipv6 from vyos.validate import is_intf_addr_assigned @@ -1080,12 +1079,6 @@ class Interface(Control): if addr in self._addr: return False - 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) @@ -1517,50 +1510,48 @@ class Interface(Control): if 'mtu' in config: self.set_mtu(config.get('mtu')) - # Only change IPv6 parameters if IPv6 was not explicitly disabled - 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' - self.set_tcp_ipv6_mss(value) - - # IPv6 forwarding - tmp = dict_search('ipv6.disable_forwarding', config) - value = '0' if (tmp != None) else '1' - self.set_ipv6_forwarding(value) - - # IPv6 router advertisements - tmp = dict_search('ipv6.address.autoconf', config) - value = '2' if (tmp != None) else '1' - if 'dhcpv6' in new_addr: - value = '2' - self.set_ipv6_accept_ra(value) - - # IPv6 address autoconfiguration - tmp = dict_search('ipv6.address.autoconf', config) - value = '1' if (tmp != None) else '0' - self.set_ipv6_autoconf(value) - - # IPv6 Duplicate Address Detection (DAD) tries - tmp = dict_search('ipv6.dup_addr_detect_transmits', config) - value = tmp if (tmp != None) else '1' - self.set_ipv6_dad_messages(value) - - # 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) - - # Manage IPv6 link-local addresses - if dict_search('ipv6.address.no_default_link_local', config) != None: - self.del_ipv6_eui64_address('fe80::/64') - else: - self.add_ipv6_eui64_address('fe80::/64') + # Configure MSS value for IPv6 TCP connections + tmp = dict_search('ipv6.adjust_mss', config) + value = tmp if (tmp != None) else '0' + self.set_tcp_ipv6_mss(value) + + # IPv6 forwarding + tmp = dict_search('ipv6.disable_forwarding', config) + value = '0' if (tmp != None) else '1' + self.set_ipv6_forwarding(value) + + # IPv6 router advertisements + tmp = dict_search('ipv6.address.autoconf', config) + value = '2' if (tmp != None) else '1' + if 'dhcpv6' in new_addr: + value = '2' + self.set_ipv6_accept_ra(value) + + # IPv6 address autoconfiguration + tmp = dict_search('ipv6.address.autoconf', config) + value = '1' if (tmp != None) else '0' + self.set_ipv6_autoconf(value) + + # IPv6 Duplicate Address Detection (DAD) tries + tmp = dict_search('ipv6.dup_addr_detect_transmits', config) + value = tmp if (tmp != None) else '1' + self.set_ipv6_dad_messages(value) + + # 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) + + # Manage IPv6 link-local addresses + if dict_search('ipv6.address.no_default_link_local', config) != None: + self.del_ipv6_eui64_address('fe80::/64') + else: + self.add_ipv6_eui64_address('fe80::/64') - # Add IPv6 EUI-based addresses - tmp = dict_search('ipv6.address.eui64', config) - if tmp: - for addr in tmp: - self.add_ipv6_eui64_address(addr) + # Add IPv6 EUI-based addresses + tmp = dict_search('ipv6.address.eui64', config) + if tmp: + for addr in tmp: + self.add_ipv6_eui64_address(addr) # re-add ourselves to any bridge we might have fallen out of if 'is_bridge_member' in config: diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py index 30c890fdf..b3babfadc 100644 --- a/python/vyos/ifconfig/loopback.py +++ b/python/vyos/ifconfig/loopback.py @@ -14,7 +14,6 @@ # License along with this library. If not, see . from vyos.ifconfig.interface import Interface -from vyos.util import is_ipv6_enabled @Interface.register class LoopbackIf(Interface): @@ -58,15 +57,14 @@ class LoopbackIf(Interface): interface setup code and provide a single point of entry when workin on any interface. """ - addr = config.get('address', []) - + address = config.get('address', []) # 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') + for tmp in self._persistent_addresses: + if tmp not in address: + address.append(tmp) # Update IP address entry in our dictionary - config.update({'address' : addr}) + config.update({'address' : address}) # call base class super().update(config) diff --git a/python/vyos/util.py b/python/vyos/util.py index 0bf6b699e..de55e108b 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -1024,7 +1024,3 @@ 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/smoketest/configs/ipv6-disable b/smoketest/configs/ipv6-disable new file mode 100644 index 000000000..da41e9020 --- /dev/null +++ b/smoketest/configs/ipv6-disable @@ -0,0 +1,83 @@ +interfaces { + ethernet eth0 { + duplex auto + smp-affinity auto + speed auto + vif 201 { + address 172.18.201.10/24 + } + vif 202 { + address 172.18.202.10/24 + } + vif 203 { + address 172.18.203.10/24 + } + vif 204 { + address 172.18.204.10/24 + } + } +} +protocols { + static { + route 0.0.0.0/0 { + next-hop 172.18.201.254 { + distance 10 + } + next-hop 172.18.202.254 { + distance 20 + } + next-hop 172.18.203.254 { + distance 30 + } + next-hop 172.18.204.254 { + distance 40 + } + } + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + domain-name vyos.net + host-name vyos + ipv6 { + disable + } + login { + user vyos { + authentication { + encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ + plaintext-password "" + } + level admin + } + } + name-server 172.16.254.20 + name-server 172.16.254.30 + ntp { + server 172.16.254.20 { + } + server 172.16.254.30 { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6 */ diff --git a/smoketest/scripts/cli/test_system_ipv6.py b/smoketest/scripts/cli/test_system_ipv6.py index 837d1dc12..c8aea9100 100755 --- a/smoketest/scripts/cli/test_system_ipv6.py +++ b/smoketest/scripts/cli/test_system_ipv6.py @@ -20,7 +20,6 @@ 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 @@ -46,41 +45,6 @@ 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']) - self.cli_commit() - - # 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)) - - # 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') diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py index e6bcc12ad..26aacf46b 100755 --- a/src/conf_mode/system-ipv6.py +++ b/src/conf_mode/system-ipv6.py @@ -17,11 +17,8 @@ import os from sys import exit -from vyos.base import DeprecationWarning from vyos.config import Config from vyos.configdict import dict_merge -from vyos.configdict import leaf_node_changed -from vyos.util import call from vyos.util import dict_search from vyos.util import sysctl_write from vyos.util import write_file @@ -39,9 +36,6 @@ def get_config(config=None): opt = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) - tmp = leaf_node_changed(conf, base + ['disable']) - if tmp: opt['reboot_required'] = {} - # We have gathered the dict representation of the CLI, but there are default # options which we need to update into the dictionary retrived. default_values = defaults(base) @@ -50,24 +44,12 @@ def get_config(config=None): return opt def verify(opt): - if 'disable' in opt: - DeprecationWarning('VyOS 1.4 (sagitta) will remove the CLI command to '\ - 'disable IPv6 address family in the Linux Kernel!') pass def generate(opt): pass def apply(opt): - # disable IPv6 globally - tmp = dict_search('disable', opt) - value = '1' if (tmp != None) else '0' - sysctl_write('net.ipv6.conf.all.disable_ipv6', value) - - if 'reboot_required' in opt: - print('Changing IPv6 disable parameter will only take affect\n' \ - 'when the system is rebooted.') - # configure multipath tmp = dict_search('multipath.layer4_hashing', opt) value = '1' if (tmp != None) else '0' diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index c3e2d8efd..f79c8a21e 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -30,7 +30,6 @@ 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 @@ -219,8 +218,7 @@ def apply(vrf): # 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') - if is_ipv6_enabled(): - vrf_if.add_addr('::1/128') + vrf_if.add_addr('::1/128') # add VRF description if available vrf_if.set_alias(config.get('description', '')) diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23 new file mode 100755 index 000000000..7f832e48a --- /dev/null +++ b/src/migration-scripts/system/22-to-23 @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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 . + +import os + +from sys import exit, argv +from vyos.configtree import ConfigTree + +if (len(argv) < 1): + print("Must specify file name!") + exit(1) + +file_name = argv[1] +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['system', 'ipv6'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +# T4346: drop support to disbale IPv6 address family within the OS Kernel +if config.exists(base + ['disable']): + config.delete(base + ['disable']) + # IPv6 address family disable was the only CLI option set - we can cleanup + # the entire tree + if len(config.list_nodes(base)) == 0: + config.delete(base) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + exit(1) diff --git a/src/tests/test_util.py b/src/tests/test_util.py index 91890262c..8ac9a500a 100644 --- a/src/tests/test_util.py +++ b/src/tests/test_util.py @@ -26,13 +26,3 @@ class TestVyOSUtil(TestCase): 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