From 2cec431e5caf9df85640f707cd6dc3077c17c238 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 13 Feb 2022 20:29:25 +0100 Subject: vrf: T4191: bugfix for "ip rule" when VRFs are created We always mangled and worked on the "ip rule" singleton even when nothing needed to be changed. This resulted in a VRF hickup when the same VRF was added and removed multiple times. set interfaces ethernet eth1 vrf foo set vrf name foo table '1000' commit delete interfaces ethernet eth1 vrf delete vrf commit set interfaces ethernet eth1 vrf foo set vrf name foo table '1000' commit broke reachability on eth1 - a reboot was required. This change will now only alter the ip rule tables once when VRF instances are created for the first time and will not touch the Kernel "ip rule" representation afterwards. --- src/conf_mode/vrf.py | 108 ++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 52 deletions(-) (limited to 'src/conf_mode/vrf.py') diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index 38c0c4463..cfe0f4d8e 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/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 @@ -29,6 +29,7 @@ from vyos.util import dict_search from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run +from vyos.util import sysctl from vyos import ConfigError from vyos import frr from vyos import airbag @@ -37,10 +38,16 @@ airbag.enable() config_file = '/etc/iproute2/rt_tables.d/vyos-vrf.conf' nft_vrf_config = '/tmp/nftables-vrf-zones' -def list_rules(): - command = 'ip -j -4 rule show' - answer = loads(cmd(command)) - return [_ for _ in answer if _] +def has_rule(af : str, priority : int, table : str): + """ Check if a given ip rule exists """ + if af not in ['-4', '-6']: + raise ValueError() + command = f'ip -j {af} rule show' + for tmp in loads(cmd(command)): + if {'priority', 'table'} <= set(tmp): + if tmp['priority'] == priority and tmp['table'] == table: + return True + return False def vrf_interfaces(c, match): matched = [] @@ -69,7 +76,6 @@ def vrf_routing(c, match): c.set_level(old_level) return matched - def get_config(config=None): if config: conf = config @@ -148,13 +154,11 @@ def apply(vrf): bind_all = '0' if 'bind-to-all' in vrf: bind_all = '1' - call(f'sysctl -wq net.ipv4.tcp_l3mdev_accept={bind_all}') - call(f'sysctl -wq net.ipv4.udp_l3mdev_accept={bind_all}') + sysctl('net.ipv4.tcp_l3mdev_accept', bind_all) + sysctl('net.ipv4.udp_l3mdev_accept', bind_all) for tmp in (dict_search('vrf_remove', vrf) or []): if os.path.isdir(f'/sys/class/net/{tmp}'): - call(f'ip -4 route del vrf {tmp} unreachable default metric 4278198272') - call(f'ip -6 route del vrf {tmp} unreachable default metric 4278198272') call(f'ip link delete dev {tmp}') # Remove nftables conntrack zone map item nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ "{tmp}" }}' @@ -165,31 +169,59 @@ def apply(vrf): # check if table already exists _, err = popen('nft list table inet vrf_zones') # If not, create a table - if err: - if os.path.exists(nft_vrf_config): - cmd(f'nft -f {nft_vrf_config}') - os.unlink(nft_vrf_config) + if err and os.path.exists(nft_vrf_config): + cmd(f'nft -f {nft_vrf_config}') + os.unlink(nft_vrf_config) + + # Linux routing uses rules to find tables - routing targets are then + # looked up in those tables. If the lookup got a matching route, the + # process ends. + # + # TL;DR; first table with a matching entry wins! + # + # You can see your routing table lookup rules using "ip rule", sadly the + # local lookup is hit before any VRF lookup. Pinging an addresses from the + # VRF will usually find a hit in the local table, and never reach the VRF + # routing table - this is usually not what you want. Thus we will + # re-arrange the tables and move the local lookup further down once VRFs + # are enabled. + # + # Thanks to https://stbuehler.de/blog/article/2020/02/29/using_vrf__virtual_routing_and_forwarding__on_linux.html + + for afi in ['-4', '-6']: + # move lookup local to pref 32765 (from 0) + if not has_rule(afi, 32765, 'local'): + call(f'ip {afi} rule add pref 32765 table local') + if has_rule(afi, 0, 'local'): + call(f'ip {afi} rule del pref 0') + # make sure that in VRFs after failed lookup in the VRF specific table + # nothing else is reached + if not has_rule(afi, 1000, 'l3mdev'): + # this should be added by the kernel when a VRF is created + # add it here for completeness + call(f'ip {afi} rule add pref 1000 l3mdev protocol kernel') + + # add another rule with an unreachable target which only triggers in VRF context + # if a route could not be reached + if not has_rule(afi, 2000, 'l3mdev'): + call(f'ip {afi} rule add pref 2000 l3mdev unreachable') for name, config in vrf['name'].items(): table = config['table'] - if not os.path.isdir(f'/sys/class/net/{name}'): # For each VRF apart from your default context create a VRF # interface with a separate routing table call(f'ip link add {name} type vrf table {table}') - # The kernel Documentation/networking/vrf.txt also recommends - # adding unreachable routes to the VRF routing tables so that routes - # afterwards are taken. - call(f'ip -4 route add vrf {name} unreachable default metric 4278198272') - call(f'ip -6 route add vrf {name} unreachable default metric 4278198272') - # We also should add proper loopback IP addresses to the newly - # created VRFs for services bound to the loopback address (SNMP, NTP) - call(f'ip -4 addr add 127.0.0.1/8 dev {name}') - call(f'ip -6 addr add ::1/128 dev {name}') # 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) + vrf_if.add_addr('127.0.0.1/8') + vrf_if.add_addr('::1/128') + # add VRF description if available vrf_if.set_alias(config.get('description', '')) + # 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() # function. We will only enable the interface if 'up' was called as @@ -203,37 +235,9 @@ def apply(vrf): nft_add_element = f'add element inet vrf_zones ct_iface_map {{ "{name}" : {table} }}' cmd(f'nft {nft_add_element}') - # Linux routing uses rules to find tables - routing targets are then - # looked up in those tables. If the lookup got a matching route, the - # process ends. - # - # TL;DR; first table with a matching entry wins! - # - # You can see your routing table lookup rules using "ip rule", sadly the - # local lookup is hit before any VRF lookup. Pinging an addresses from the - # VRF will usually find a hit in the local table, and never reach the VRF - # routing table - this is usually not what you want. Thus we will - # re-arrange the tables and move the local lookup furhter down once VRFs - # are enabled. - - # get current preference on local table - local_pref = [r.get('priority') for r in list_rules() if r.get('table') == 'local'][0] - - # change preference when VRFs are enabled and local lookup table is default - if not local_pref and 'name' in vrf: - for af in ['-4', '-6']: - call(f'ip {af} rule add pref 32765 table local') - call(f'ip {af} rule del pref 0') # return to default lookup preference when no VRF is configured if 'name' not in vrf: - for af in ['-4', '-6']: - call(f'ip {af} rule add pref 0 table local') - call(f'ip {af} rule del pref 32765') - - # clean out l3mdev-table rule if present - if 1000 in [r.get('priority') for r in list_rules() if r.get('priority') == 1000]: - call(f'ip {af} rule del pref 1000') # Remove VRF zones table from nftables tmp = run('nft list table inet vrf_zones') if tmp == 0: -- cgit v1.2.3 From 364009e4317fb5c6732635726b511613aa2ed519 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 25 Mar 2022 19:00:36 +0100 Subject: vyos.util: T4319: rename sysctl() -> sysctl_write() --- python/vyos/util.py | 2 +- src/conf_mode/system-ip.py | 12 ++++++------ src/conf_mode/system-ipv6.py | 12 ++++++------ src/conf_mode/vrf.py | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/conf_mode/vrf.py') diff --git a/python/vyos/util.py b/python/vyos/util.py index da39ee8d1..f46775490 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -1011,7 +1011,7 @@ def sysctl_read(name): tmp = cmd(f'sysctl {name}') return tmp.split()[-1] -def sysctl(name, value): +def sysctl_write(name, value): """ Change value via sysctl() - return True if changed, False otherwise """ tmp = cmd(f'sysctl {name}') # last list index contains the actual value - only write if value differs diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py index 8b97725ac..05fc3a97a 100755 --- a/src/conf_mode/system-ip.py +++ b/src/conf_mode/system-ip.py @@ -20,7 +20,7 @@ from vyos.config import Config from vyos.configdict import dict_merge from vyos.util import call from vyos.util import dict_search -from vyos.util import sysctl +from vyos.util import sysctl_write from vyos.util import write_file from vyos.xml import defaults from vyos import ConfigError @@ -53,11 +53,11 @@ def apply(opt): # table_size has a default value - thus the key always exists size = int(dict_search('arp.table_size', opt)) # Amount upon reaching which the records begin to be cleared immediately - sysctl('net.ipv4.neigh.default.gc_thresh3', size) + sysctl_write('net.ipv4.neigh.default.gc_thresh3', size) # Amount after which the records begin to be cleaned after 5 seconds - sysctl('net.ipv4.neigh.default.gc_thresh2', size // 2) + sysctl_write('net.ipv4.neigh.default.gc_thresh2', size // 2) # Minimum number of stored records is indicated which is not cleared - sysctl('net.ipv4.neigh.default.gc_thresh1', size // 8) + sysctl_write('net.ipv4.neigh.default.gc_thresh1', size // 8) # enable/disable IPv4 forwarding tmp = dict_search('disable_forwarding', opt) @@ -67,11 +67,11 @@ def apply(opt): # configure multipath tmp = dict_search('multipath.ignore_unreachable_nexthops', opt) value = '1' if (tmp != None) else '0' - sysctl('net.ipv4.fib_multipath_use_neigh', value) + sysctl_write('net.ipv4.fib_multipath_use_neigh', value) tmp = dict_search('multipath.layer4_hashing', opt) value = '1' if (tmp != None) else '0' - sysctl('net.ipv4.fib_multipath_hash_policy', value) + sysctl_write('net.ipv4.fib_multipath_hash_policy', value) if __name__ == '__main__': try: diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py index 8195beaa6..7fb2dd1cf 100755 --- a/src/conf_mode/system-ipv6.py +++ b/src/conf_mode/system-ipv6.py @@ -22,7 +22,7 @@ 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 +from vyos.util import sysctl_write from vyos.util import write_file from vyos.xml import defaults from vyos import ConfigError @@ -58,7 +58,7 @@ def apply(opt): # disable IPv6 globally tmp = dict_search('disable', opt) value = '1' if (tmp != None) else '0' - sysctl('net.ipv6.conf.all.disable_ipv6', value) + sysctl_write('net.ipv6.conf.all.disable_ipv6', value) if 'reboot_required' in opt: print('Changing IPv6 disable parameter will only take affect\n' \ @@ -67,17 +67,17 @@ def apply(opt): # configure multipath tmp = dict_search('multipath.layer4_hashing', opt) value = '1' if (tmp != None) else '0' - sysctl('net.ipv6.fib_multipath_hash_policy', value) + sysctl_write('net.ipv6.fib_multipath_hash_policy', value) # Apply ND threshold values # table_size has a default value - thus the key always exists size = int(dict_search('neighbor.table_size', opt)) # Amount upon reaching which the records begin to be cleared immediately - sysctl('net.ipv6.neigh.default.gc_thresh3', size) + sysctl_write('net.ipv6.neigh.default.gc_thresh3', size) # Amount after which the records begin to be cleaned after 5 seconds - sysctl('net.ipv6.neigh.default.gc_thresh2', size // 2) + sysctl_write('net.ipv6.neigh.default.gc_thresh2', size // 2) # Minimum number of stored records is indicated which is not cleared - sysctl('net.ipv6.neigh.default.gc_thresh1', size // 8) + sysctl_write('net.ipv6.neigh.default.gc_thresh1', size // 8) # enable/disable IPv6 forwarding tmp = dict_search('disable_forwarding', opt) diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index cfe0f4d8e..6a521a0dd 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -29,7 +29,7 @@ from vyos.util import dict_search from vyos.util import get_interface_config from vyos.util import popen from vyos.util import run -from vyos.util import sysctl +from vyos.util import sysctl_write from vyos import ConfigError from vyos import frr from vyos import airbag @@ -154,8 +154,8 @@ def apply(vrf): bind_all = '0' if 'bind-to-all' in vrf: bind_all = '1' - sysctl('net.ipv4.tcp_l3mdev_accept', bind_all) - sysctl('net.ipv4.udp_l3mdev_accept', bind_all) + sysctl_write('net.ipv4.tcp_l3mdev_accept', bind_all) + sysctl_write('net.ipv4.udp_l3mdev_accept', bind_all) for tmp in (dict_search('vrf_remove', vrf) or []): if os.path.isdir(f'/sys/class/net/{tmp}'): -- 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(-) (limited to 'src/conf_mode/vrf.py') 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 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 'src/conf_mode/vrf.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