diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/dhcpv6_server.py | 33 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-pppoe.py | 35 | ||||
-rwxr-xr-x | src/conf_mode/protocols_bgp.py | 6 | ||||
-rwxr-xr-x | src/conf_mode/protocols_static.py | 5 | ||||
-rwxr-xr-x | src/etc/ppp/ip-up.d/99-vyos-pppoe-callback | 12 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/25-to-26 | 54 |
6 files changed, 102 insertions, 43 deletions
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py index 9922f2c5c..078ff327c 100755 --- a/src/conf_mode/dhcpv6_server.py +++ b/src/conf_mode/dhcpv6_server.py @@ -41,7 +41,9 @@ def get_config(config=None): if not conf.exists(base): return None - dhcpv6 = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + dhcpv6 = conf.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True) return dhcpv6 def verify(dhcpv6): @@ -51,7 +53,7 @@ def verify(dhcpv6): # If DHCP is enabled we need one share-network if 'shared_network_name' not in dhcpv6: - raise ConfigError('No DHCPv6 shared networks configured. At least\n' \ + raise ConfigError('No DHCPv6 shared networks configured. At least '\ 'one DHCPv6 shared network must be configured.') # Inspect shared-network/subnet @@ -60,8 +62,9 @@ def verify(dhcpv6): for network, network_config in dhcpv6['shared_network_name'].items(): # A shared-network requires a subnet definition if 'subnet' not in network_config: - raise ConfigError(f'No DHCPv6 lease subnets configured for "{network}". At least one\n' \ - 'lease subnet must be configured for each shared network!') + raise ConfigError(f'No DHCPv6 lease subnets configured for "{network}". '\ + 'At least one lease subnet must be configured for '\ + 'each shared network!') for subnet, subnet_config in network_config['subnet'].items(): if 'address_range' in subnet_config: @@ -83,20 +86,20 @@ def verify(dhcpv6): # Stop address must be greater or equal to start address if not ip_address(stop) >= ip_address(start): - raise ConfigError(f'address-range stop address "{stop}" must be greater or equal\n' \ + raise ConfigError(f'address-range stop address "{stop}" must be greater then or equal ' \ f'to the range start address "{start}"!') # DHCPv6 range start address must be unique - two ranges can't # start with the same address - makes no sense if start in range6_start: - raise ConfigError(f'Conflicting DHCPv6 lease range:\n' \ + raise ConfigError(f'Conflicting DHCPv6 lease range: '\ f'Pool start address "{start}" defined multipe times!') range6_start.append(start) # DHCPv6 range stop address must be unique - two ranges can't # end with the same address - makes no sense if stop in range6_stop: - raise ConfigError(f'Conflicting DHCPv6 lease range:\n' \ + raise ConfigError(f'Conflicting DHCPv6 lease range: '\ f'Pool stop address "{stop}" defined multipe times!') range6_stop.append(stop) @@ -112,7 +115,7 @@ def verify(dhcpv6): for prefix, prefix_config in subnet_config['prefix_delegation']['start'].items(): if 'stop' not in prefix_config: - raise ConfigError(f'Stop address of delegated IPv6 prefix range "{prefix}"\n' + raise ConfigError(f'Stop address of delegated IPv6 prefix range "{prefix}" '\ f'must be configured') if 'prefix_length' not in prefix_config: @@ -126,6 +129,10 @@ def verify(dhcpv6): if ip_address(mapping_config['ipv6_address']) not in ip_network(subnet): raise ConfigError(f'static-mapping address for mapping "{mapping}" is not in subnet "{subnet}"!') + if 'vendor_option' in subnet_config: + if len(dict_search('vendor_option.cisco.tftp_server', subnet_config)) > 2: + raise ConfigError(f'No more then two Cisco tftp-servers should be defined for subnet "{subnet}"!') + # Subnets must be unique if subnet in subnets: raise ConfigError(f'DHCPv6 subnets must be unique! Subnet {subnet} defined multiple times!') @@ -149,8 +156,8 @@ def verify(dhcpv6): raise ConfigError('DHCPv6 conflicting subnet ranges: {0} overlaps {1}'.format(net, net2)) if not listen_ok: - raise ConfigError('None of the DHCPv6 subnets are connected to a subnet6 on\n' \ - 'this machine. At least one subnet6 must be connected such that\n' \ + raise ConfigError('None of the DHCPv6 subnets are connected to a subnet6 on '\ + 'this machine. At least one subnet6 must be connected such that '\ 'DHCPv6 listens on an interface!') @@ -166,15 +173,15 @@ def generate(dhcpv6): def apply(dhcpv6): # bail out early - looks like removal from running config + service_name = 'isc-dhcp-server6.service' if not dhcpv6 or 'disable' in dhcpv6: # DHCP server is removed in the commit - call('systemctl stop isc-dhcp-server6.service') + call(f'systemctl stop {service_name}') if os.path.exists(config_file): os.unlink(config_file) - return None - call('systemctl restart isc-dhcp-server6.service') + call(f'systemctl restart {service_name}') return None if __name__ == '__main__': diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py index bfb1fadd5..279369a32 100755 --- a/src/conf_mode/interfaces-pppoe.py +++ b/src/conf_mode/interfaces-pppoe.py @@ -22,7 +22,9 @@ from netifaces import interfaces from vyos.config import Config from vyos.configdict import get_interface_dict +from vyos.configdict import is_node_changed from vyos.configdict import leaf_node_changed +from vyos.configdict import get_pppoe_interfaces from vyos.configverify import verify_authentication from vyos.configverify import verify_source_interface from vyos.configverify import verify_interface_exists @@ -52,28 +54,12 @@ def get_config(config=None): # We should only terminate the PPPoE session if critical parameters change. # All parameters that can be changed on-the-fly (like interface description) # should not lead to a reconnect! - tmp = leaf_node_changed(conf, ['access-concentrator']) - if tmp: pppoe.update({'shutdown_required': {}}) - - tmp = leaf_node_changed(conf, ['connect-on-demand']) - if tmp: pppoe.update({'shutdown_required': {}}) - - tmp = leaf_node_changed(conf, ['service-name']) - if tmp: pppoe.update({'shutdown_required': {}}) - - tmp = leaf_node_changed(conf, ['source-interface']) - if tmp: pppoe.update({'shutdown_required': {}}) - - tmp = leaf_node_changed(conf, ['vrf']) - # leaf_node_changed() returns a list, as VRF is a non-multi node, there - # will be only one list element - if tmp: pppoe.update({'vrf_old': tmp[0]}) - - tmp = leaf_node_changed(conf, ['authentication', 'user']) - if tmp: pppoe.update({'shutdown_required': {}}) - - tmp = leaf_node_changed(conf, ['authentication', 'password']) - if tmp: pppoe.update({'shutdown_required': {}}) + for options in ['access-concentrator', 'connect-on-demand', 'service-name', + 'source-interface', 'vrf', 'no-default-route', 'authentication']: + if is_node_changed(conf, options): + pppoe.update({'shutdown_required': {}}) + # bail out early - no need to further process other nodes + break return pppoe @@ -120,7 +106,7 @@ def apply(pppoe): return None # reconnect should only be necessary when certain config options change, - # like ACS name, authentication, no-peer-dns, source-interface + # like ACS name, authentication ... (see get_config() for details) if ((not is_systemd_service_running(f'ppp@{ifname}.service')) or 'shutdown_required' in pppoe): @@ -130,6 +116,9 @@ def apply(pppoe): p.remove() call(f'systemctl restart ppp@{ifname}.service') + # When interface comes "live" a hook is called: + # /etc/ppp/ip-up.d/99-vyos-pppoe-callback + # which triggers PPPoEIf.update() else: if os.path.isdir(f'/sys/class/net/{ifname}'): p = PPPoEIf(ifname) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 8d9d3e99a..a9173ab87 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -164,6 +164,12 @@ def verify(bgp): if not verify_remote_as(peer_config, bgp): raise ConfigError(f'Neighbor "{peer}" remote-as must be set!') + # Peer-group member cannot override remote-as of peer-group + if 'peer_group' in peer_config: + peer_group = peer_config['peer_group'] + if 'remote_as' in peer_config and 'remote_as' in bgp['peer_group'][peer_group]: + raise ConfigError(f'Peer-group member "{peer}" cannot override remote-as of peer-group "{peer_group}"!') + # Only checks for ipv4 and ipv6 neighbors # Check if neighbor address is assigned as system interface address vrf = None diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 87432bc1c..58e202928 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -22,6 +22,7 @@ from sys import argv from vyos.config import Config from vyos.configdict import dict_merge from vyos.configdict import get_dhcp_interfaces +from vyos.configdict import get_pppoe_interfaces from vyos.configverify import verify_common_route_maps from vyos.configverify import verify_vrf from vyos.template import render_to_string @@ -59,7 +60,9 @@ def get_config(config=None): # T3680 - get a list of all interfaces currently configured to use DHCP tmp = get_dhcp_interfaces(conf, vrf) - if tmp: static['dhcp'] = tmp + if tmp: static.update({'dhcp' : tmp}) + tmp = get_pppoe_interfaces(conf, vrf) + if tmp: static.update({'pppoe' : tmp}) return static diff --git a/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback index bb918a468..78ca09010 100755 --- a/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback +++ b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -28,7 +28,8 @@ from syslog import openlog from syslog import LOG_PID from syslog import LOG_INFO -from vyos.configquery import ConfigTreeQuery +from vyos.configquery import Config +from vyos.configdict import get_interface_dict from vyos.ifconfig import PPPoEIf from vyos.util import read_file @@ -50,10 +51,9 @@ dialer_pid = read_file(f'/var/run/{interface}.pid') openlog(ident=f'pppd[{dialer_pid}]', facility=LOG_INFO) syslog('executing ' + argv[0]) -conf = ConfigTreeQuery() -pppoe = conf.get_config_dict(['interfaces', 'pppoe', argv[6]], - get_first_key=True, key_mangling=('-', '_')) -pppoe['ifname'] = argv[6] +conf = Config() +pppoe = get_interface_dict(conf, ['interfaces', 'pppoe'], argv[6]) +# Update the config p = PPPoEIf(pppoe['ifname']) p.update(pppoe) diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26 new file mode 100755 index 000000000..a8936235e --- /dev/null +++ b/src/migration-scripts/interfaces/25-to-26 @@ -0,0 +1,54 @@ +#!/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 <http://www.gnu.org/licenses/>. + +# T4384: pppoe: replace default-route CLI option with common CLI nodes already +# present for DHCP + +from sys import argv + +from vyos.ethtool import Ethtool +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 = ['interfaces', 'pppoe'] +config = ConfigTree(config_file) + +if not config.exists(base): + exit(0) + +for ifname in config.list_nodes(base): + tmp_config = base + [ifname, 'default-route'] + if config.exists(tmp_config): + # Retrieve current config value + value = config.return_value(tmp_config) + # Delete old Config node + config.delete(tmp_config) + if value == 'none': + config.set(base + [ifname, 'no-default-route']) + +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) |