diff options
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-x | src/conf_mode/container.py | 14 | ||||
-rwxr-xr-x | src/conf_mode/nat.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/policy_route.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/protocols_bfd.py | 3 | ||||
-rwxr-xr-x | src/conf_mode/protocols_bgp.py | 10 | ||||
-rwxr-xr-x | src/conf_mode/qos.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/service_dhcp-server.py | 28 | ||||
-rwxr-xr-x | src/conf_mode/service_dns_dynamic.py | 49 | ||||
-rwxr-xr-x | src/conf_mode/service_dns_forwarding.py | 36 | ||||
-rwxr-xr-x | src/conf_mode/service_ntp.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/system_option.py | 11 | ||||
-rwxr-xr-x | src/conf_mode/system_sflow.py | 11 | ||||
-rwxr-xr-x | src/conf_mode/vpn_l2tp.py | 5 | ||||
-rwxr-xr-x | src/conf_mode/vpn_pptp.py | 30 | ||||
-rwxr-xr-x | src/conf_mode/vpn_sstp.py | 1 | ||||
-rwxr-xr-x | src/conf_mode/vrf.py | 47 |
16 files changed, 140 insertions, 121 deletions
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 59d11c5a3..321d00abf 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -214,6 +214,10 @@ def verify(container): if {'allow_host_networks', 'network'} <= set(container_config): raise ConfigError(f'"allow-host-networks" and "network" for "{name}" cannot be both configured at the same time!') + # gid cannot be set without uid + if 'gid' in container_config and 'uid' not in container_config: + raise ConfigError(f'Cannot set "gid" without "uid" for container') + # Add new network if 'network' in container: for network, network_config in container['network'].items(): @@ -308,6 +312,14 @@ def generate_run_arguments(name, container_config): # If listen_addresses is empty, just include the standard publish command port += f' --publish {sport}:{dport}/{protocol}' + # Set uid and gid + uid = '' + if 'uid' in container_config: + uid = container_config['uid'] + if 'gid' in container_config: + uid += ':' + container_config['gid'] + uid = f'--user {uid}' + # Bind volume volume = '' if 'volume' in container_config: @@ -320,7 +332,7 @@ def generate_run_arguments(name, container_config): container_base_cmd = f'--detach --interactive --tty --replace {cap_add} ' \ f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \ - f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label}' + f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid}' entrypoint = '' if 'entrypoint' in container_config: diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index bd9b5162c..26822b755 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -69,6 +69,10 @@ def get_config(config=None): nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + # Remove dynamic firewall groups if present: + if 'dynamic_group' in nat['firewall_group']: + del nat['firewall_group']['dynamic_group'] + return nat def verify_rule(config, err_msg, groups_dict): diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py index adad012de..6d7a06714 100755 --- a/src/conf_mode/policy_route.py +++ b/src/conf_mode/policy_route.py @@ -53,6 +53,10 @@ def get_config(config=None): policy['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + # Remove dynamic firewall groups if present: + if 'dynamic_group' in policy['firewall_group']: + del policy['firewall_group']['dynamic_group'] + return policy def verify_rule(policy, name, rule_conf, ipv6, rule_id): diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index dab784662..37421efb4 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -72,6 +72,9 @@ def verify(bfd): if 'source' in peer_config and 'interface' in peer_config['source']: raise ConfigError('BFD multihop and source interface cannot be used together') + if 'minimum_ttl' in peer_config and 'multihop' not in peer_config: + raise ConfigError('Minimum TTL is only available for multihop BFD sessions!') + if 'profile' in peer_config: profile_name = peer_config['profile'] if 'profile' not in bfd or profile_name not in bfd['profile']: diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index f6f3370c3..d90dfe45b 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# Copyright (C) 2020-2024 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 @@ -509,6 +509,14 @@ def verify(bgp): if verify_vrf_as_import(vrf_name, afi, bgp['dependent_vrfs']): raise ConfigError( 'Command "import vrf" conflicts with "route-target vpn both" command!') + if dict_search('route_target.vpn.export', afi_config): + raise ConfigError( + 'Command "route-target vpn export" conflicts '\ + 'with "route-target vpn both" command!') + if dict_search('route_target.vpn.import', afi_config): + raise ConfigError( + 'Command "route-target vpn import" conflicts '\ + 'with "route-target vpn both" command!') if dict_search('route_target.vpn.import', afi_config): if verify_vrf_as_import(vrf_name, afi, bgp['dependent_vrfs']): diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py index ad4121a49..40d7a6c16 100755 --- a/src/conf_mode/qos.py +++ b/src/conf_mode/qos.py @@ -149,7 +149,7 @@ def verify(qos): if 'class' in policy_config: for cls, cls_config in policy_config['class'].items(): # bandwidth is not mandatory for priority-queue - that is why this is on the exception list - if 'bandwidth' not in cls_config and policy_type not in ['priority_queue', 'round_robin']: + if 'bandwidth' not in cls_config and policy_type not in ['priority_queue', 'round_robin', 'shaper_hfsc']: raise ConfigError(f'Bandwidth must be defined for policy "{policy}" class "{cls}"!') if 'match' in cls_config: for match, match_config in cls_config['match'].items(): @@ -173,7 +173,7 @@ def verify(qos): if 'default' not in policy_config: raise ConfigError(f'Policy {policy} misses "default" class!') if 'default' in policy_config: - if 'bandwidth' not in policy_config['default'] and policy_type not in ['priority_queue', 'round_robin']: + if 'bandwidth' not in policy_config['default'] and policy_type not in ['priority_queue', 'round_robin', 'shaper_hfsc']: raise ConfigError('Bandwidth not defined for default traffic!') # we should check interface ingress/egress configuration after verifying that diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py index 9632b91fc..91ea354b6 100755 --- a/src/conf_mode/service_dhcp-server.py +++ b/src/conf_mode/service_dhcp-server.py @@ -246,19 +246,21 @@ def verify(dhcp): raise ConfigError(f'Either MAC address or Client identifier (DUID) is required for ' f'static mapping "{mapping}" within shared-network "{network}, {subnet}"!') - if mapping_config['ip_address'] in used_ips: - raise ConfigError(f'Configured IP address for static mapping "{mapping}" already exists on another static mapping') - used_ips.append(mapping_config['ip_address']) - - if 'mac' in mapping_config: - if mapping_config['mac'] in used_mac: - raise ConfigError(f'Configured MAC address for static mapping "{mapping}" already exists on another static mapping') - used_mac.append(mapping_config['mac']) - - if 'duid' in mapping_config: - if mapping_config['duid'] in used_duid: - raise ConfigError(f'Configured DUID for static mapping "{mapping}" already exists on another static mapping') - used_duid.append(mapping_config['duid']) + if 'disable' not in mapping_config: + if mapping_config['ip_address'] in used_ips: + raise ConfigError(f'Configured IP address for static mapping "{mapping}" already exists on another static mapping') + used_ips.append(mapping_config['ip_address']) + + if 'disable' not in mapping_config: + if 'mac' in mapping_config: + if mapping_config['mac'] in used_mac: + raise ConfigError(f'Configured MAC address for static mapping "{mapping}" already exists on another static mapping') + used_mac.append(mapping_config['mac']) + + if 'duid' in mapping_config: + if mapping_config['duid'] in used_duid: + raise ConfigError(f'Configured DUID for static mapping "{mapping}" already exists on another static mapping') + used_duid.append(mapping_config['duid']) # There must be one subnet connected to a listen interface. # This only counts if the network itself is not disabled! diff --git a/src/conf_mode/service_dns_dynamic.py b/src/conf_mode/service_dns_dynamic.py index 845aaa1b5..a551a9891 100755 --- a/src/conf_mode/service_dns_dynamic.py +++ b/src/conf_mode/service_dns_dynamic.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2023 VyOS maintainers and contributors +# Copyright (C) 2018-2024 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 @@ -87,31 +87,36 @@ def verify(dyndns): if field not in config: raise ConfigError(f'"{field.replace("_", "-")}" {error_msg_req}') - # If dyndns address is an interface, ensure - # that the interface exists (or just warn if dynamic interface) - # and that web-options are not set - if config['address'] != 'web': + if not any(x in config['address'] for x in ['interface', 'web']): + raise ConfigError(f'Either "interface" or "web" {error_msg_req} ' + f'with protocol "{config["protocol"]}"') + if all(x in config['address'] for x in ['interface', 'web']): + raise ConfigError(f'Both "interface" and "web" at the same time {error_msg_uns} ' + f'with protocol "{config["protocol"]}"') + + # If dyndns address is an interface, ensure that the interface exists + # and warn if a non-active dynamic interface is used + if 'interface' in config['address']: tmp = re.compile(dynamic_interface_pattern) # exclude check interface for dynamic interfaces - if tmp.match(config["address"]): - if not interface_exists(config["address"]): - Warning(f'Interface "{config["address"]}" does not exist yet and cannot ' - f'be used for Dynamic DNS service "{service}" until it is up!') + if tmp.match(config['address']['interface']): + if not interface_exists(config['address']['interface']): + Warning(f'Interface "{config["address"]["interface"]}" does not exist yet and ' + f'cannot be used for Dynamic DNS service "{service}" until it is up!') else: - verify_interface_exists(config['address']) - if 'web_options' in config: - raise ConfigError(f'"web-options" is applicable only when using HTTP(S) ' - f'web request to obtain the IP address') - - # Warn if using checkip.dyndns.org, as it does not support HTTPS - # See: https://github.com/ddclient/ddclient/issues/597 - if 'web_options' in config: - if 'url' not in config['web_options']: - raise ConfigError(f'"url" in "web-options" {error_msg_req} ' + verify_interface_exists(config['address']['interface']) + + if 'web' in config['address']: + # If 'skip' is specified, 'url' is required as well + if 'skip' in config['address']['web'] and 'url' not in config['address']['web']: + raise ConfigError(f'"url" along with "skip" {error_msg_req} ' f'with protocol "{config["protocol"]}"') - elif re.search("^(https?://)?checkip\.dyndns\.org", config['web_options']['url']): - Warning(f'"checkip.dyndns.org" does not support HTTPS requests for IP address ' - f'lookup. Please use a different IP address lookup service.') + if 'url' in config['address']['web']: + # Warn if using checkip.dyndns.org, as it does not support HTTPS + # See: https://github.com/ddclient/ddclient/issues/597 + if re.search("^(https?://)?checkip\.dyndns\.org", config['address']['web']['url']): + Warning(f'"checkip.dyndns.org" does not support HTTPS requests for IP address ' + f'lookup. Please use a different IP address lookup service.') # RFC2136 uses 'key' instead of 'password' if config['protocol'] != 'nsupdate' and 'password' not in config: diff --git a/src/conf_mode/service_dns_forwarding.py b/src/conf_mode/service_dns_forwarding.py index c186f47af..ecad765f4 100755 --- a/src/conf_mode/service_dns_forwarding.py +++ b/src/conf_mode/service_dns_forwarding.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2022 VyOS maintainers and contributors +# Copyright (C) 2018-2024 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 @@ -26,18 +26,18 @@ from vyos.template import render from vyos.template import bracketize_ipv6 from vyos.utils.process import call from vyos.utils.permission import chown -from vyos.utils.dict import dict_search from vyos import ConfigError from vyos import airbag airbag.enable() -pdns_rec_user = pdns_rec_group = 'pdns' -pdns_rec_run_dir = '/run/powerdns' +pdns_rec_user_group = 'pdns' +pdns_rec_run_dir = '/run/pdns-recursor' pdns_rec_lua_conf_file = f'{pdns_rec_run_dir}/recursor.conf.lua' pdns_rec_hostsd_lua_conf_file = f'{pdns_rec_run_dir}/recursor.vyos-hostsd.conf.lua' pdns_rec_hostsd_zones_file = f'{pdns_rec_run_dir}/recursor.forward-zones.conf' pdns_rec_config_file = f'{pdns_rec_run_dir}/recursor.conf' +pdns_rec_systemd_override = '/run/systemd/system/pdns-recursor.service.d/override.conf' hostsd_tag = 'static' @@ -55,6 +55,9 @@ def get_config(config=None): get_first_key=True, with_recursive_defaults=True) + dns['config_file'] = pdns_rec_config_file + dns['config_dir'] = os.path.dirname(pdns_rec_config_file) + # some additions to the default dictionary if 'system' in dns: base_nameservers = ['system', 'name-server'] @@ -251,11 +254,16 @@ def generate(dns): if not dns: return None - render(pdns_rec_config_file, 'dns-forwarding/recursor.conf.j2', - dns, user=pdns_rec_user, group=pdns_rec_group) + render(pdns_rec_systemd_override, 'dns-forwarding/override.conf.j2', dns) + + render(pdns_rec_config_file, 'dns-forwarding/recursor.conf.j2', dns, + user=pdns_rec_user_group, group=pdns_rec_user_group) - render(pdns_rec_lua_conf_file, 'dns-forwarding/recursor.conf.lua.j2', - dns, user=pdns_rec_user, group=pdns_rec_group) + render(pdns_rec_config_file, 'dns-forwarding/recursor.conf.j2', dns, + user=pdns_rec_user_group, group=pdns_rec_user_group) + + render(pdns_rec_lua_conf_file, 'dns-forwarding/recursor.conf.lua.j2', dns, + user=pdns_rec_user_group, group=pdns_rec_user_group) for zone_filename in glob(f'{pdns_rec_run_dir}/zone.*.conf'): os.unlink(zone_filename) @@ -263,21 +271,25 @@ def generate(dns): if 'authoritative_zones' in dns: for zone in dns['authoritative_zones']: render(zone['file'], 'dns-forwarding/recursor.zone.conf.j2', - zone, user=pdns_rec_user, group=pdns_rec_group) + zone, user=pdns_rec_user_group, group=pdns_rec_user_group) # if vyos-hostsd didn't create its files yet, create them (empty) for file in [pdns_rec_hostsd_lua_conf_file, pdns_rec_hostsd_zones_file]: with open(file, 'a'): pass - chown(file, user=pdns_rec_user, group=pdns_rec_group) + chown(file, user=pdns_rec_user_group, group=pdns_rec_user_group) return None def apply(dns): + systemd_service = 'pdns-recursor.service' + # Reload systemd manager configuration + call('systemctl daemon-reload') + if not dns: # DNS forwarding is removed in the commit - call('systemctl stop pdns-recursor.service') + call(f'systemctl stop {systemd_service}') if os.path.isfile(pdns_rec_config_file): os.unlink(pdns_rec_config_file) @@ -345,7 +357,7 @@ def apply(dns): hc.apply() ### finally (re)start pdns-recursor - call('systemctl restart pdns-recursor.service') + call(f'systemctl reload-or-restart {systemd_service}') if __name__ == '__main__': try: diff --git a/src/conf_mode/service_ntp.py b/src/conf_mode/service_ntp.py index 1cc23a7df..f11690ee6 100755 --- a/src/conf_mode/service_ntp.py +++ b/src/conf_mode/service_ntp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2023 VyOS maintainers and contributors +# Copyright (C) 2018-2024 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 @@ -42,7 +42,7 @@ def get_config(config=None): if not conf.exists(base): return None - ntp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + ntp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, with_defaults=True) ntp['config_file'] = config_file ntp['user'] = user_group diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py index d92121b3d..3b5b67437 100755 --- a/src/conf_mode/system_option.py +++ b/src/conf_mode/system_option.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2023 VyOS maintainers and contributors +# Copyright (C) 2019-2024 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 @@ -22,6 +22,7 @@ from time import sleep from vyos.config import Config from vyos.configverify import verify_source_interface +from vyos.system import grub_util from vyos.template import render from vyos.utils.process import cmd from vyos.utils.process import is_systemd_service_running @@ -39,7 +40,6 @@ time_format_to_locale = { '24-hour': 'en_GB.UTF-8' } - def get_config(config=None): if config: conf = config @@ -87,6 +87,13 @@ def verify(options): def generate(options): render(curlrc_config, 'system/curlrc.j2', options) render(ssh_config, 'system/ssh_config.j2', options) + + cmdline_options = [] + if 'kernel' in options: + if 'disable_mitigations' in options['kernel']: + cmdline_options.append('mitigations=off') + grub_util.update_kernel_cmdline_options(' '.join(cmdline_options)) + return None def apply(options): diff --git a/src/conf_mode/system_sflow.py b/src/conf_mode/system_sflow.py index 2df1bbb7a..41119b494 100755 --- a/src/conf_mode/system_sflow.py +++ b/src/conf_mode/system_sflow.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright (C) 2023-2024 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 @@ -19,6 +19,7 @@ import os from sys import exit from vyos.config import Config +from vyos.configverify import verify_vrf from vyos.template import render from vyos.utils.process import call from vyos.utils.network import is_addr_assigned @@ -46,7 +47,6 @@ def get_config(config=None): return sflow - def verify(sflow): if not sflow: return None @@ -68,9 +68,8 @@ def verify(sflow): if 'server' not in sflow: raise ConfigError('You need to configure at least one sFlow server!') - # return True if all checks were passed - return True - + verify_vrf(sflow) + return None def generate(sflow): if not sflow: @@ -81,7 +80,6 @@ def generate(sflow): # Reload systemd manager configuration call('systemctl daemon-reload') - def apply(sflow): if not sflow: # Stop flow-accounting daemon and remove configuration file @@ -93,7 +91,6 @@ def apply(sflow): # Start/reload flow-accounting daemon call(f'systemctl restart {systemd_service}') - if __name__ == '__main__': try: config = get_config() diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py index b569ca140..36b3d2a30 100755 --- a/src/conf_mode/vpn_l2tp.py +++ b/src/conf_mode/vpn_l2tp.py @@ -51,11 +51,6 @@ def get_config(config=None): # Multiple named pools require ordered values T5099 l2tp['ordered_named_pools'] = get_pools_in_order( dict_search('client_ip_pool', l2tp)) - l2tp['ip6_column'] = [] - if dict_search('client_ipv6_pool.prefix', l2tp): - l2tp['ip6_column'].append('ipv6') - if dict_search('client_ipv6_pool.delegate', l2tp): - l2tp['ip6_column'].append('ip6-db') l2tp['server_type'] = 'l2tp' return l2tp diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py index 0629625bf..b1d5067d5 100755 --- a/src/conf_mode/vpn_pptp.py +++ b/src/conf_mode/vpn_pptp.py @@ -22,6 +22,7 @@ from vyos.config import Config from vyos.template import render from vyos.utils.process import call from vyos.utils.dict import dict_search +from vyos.accel_ppp_util import verify_accel_ppp_base_service from vyos.accel_ppp_util import verify_accel_ppp_ip_pool from vyos.accel_ppp_util import get_pools_in_order from vyos import ConfigError @@ -58,36 +59,10 @@ def get_config(config=None): def verify(pptp): if not pptp: return None - auth_mode = dict_search('authentication.mode', pptp) - if auth_mode == 'local': - if not dict_search('authentication.local_users', pptp): - raise ConfigError( - 'PPTP local auth mode requires local users to be configured!') - - for user in dict_search('authentication.local_users.username', pptp): - user_config = pptp['authentication']['local_users']['username'][ - user] - if 'password' not in user_config: - raise ConfigError(f'Password required for local user "{user}"') - - elif auth_mode == 'radius': - if not dict_search('authentication.radius.server', pptp): - raise ConfigError( - 'RADIUS authentication requires at least one server') - for server in dict_search('authentication.radius.server', pptp): - radius_config = pptp['authentication']['radius']['server'][server] - if 'key' not in radius_config: - raise ConfigError( - f'Missing RADIUS secret key for server "{server}"') + verify_accel_ppp_base_service(pptp) verify_accel_ppp_ip_pool(pptp) - if 'name_server' in pptp: - if len(pptp['name_server']) > 2: - raise ConfigError( - 'Not more then two IPv4 DNS name-servers can be configured' - ) - if 'wins_server' in pptp and len(pptp['wins_server']) > 2: raise ConfigError( 'Not more then two WINS name-servers can be configured') @@ -105,6 +80,7 @@ def generate(pptp): return None + def apply(pptp): if not pptp: call('systemctl stop accel-ppp@pptp.service') diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py index a84513a0f..5c229fe62 100755 --- a/src/conf_mode/vpn_sstp.py +++ b/src/conf_mode/vpn_sstp.py @@ -20,7 +20,6 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_accel_dict -from vyos.configdict import dict_merge from vyos.pki import wrap_certificate from vyos.pki import wrap_private_key from vyos.template import render diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index 9b1b6355f..f2c544aa6 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# Copyright (C) 2020-2024 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 @@ -27,13 +27,12 @@ from vyos.ifconfig import Interface from vyos.template import render from vyos.template import render_to_string from vyos.utils.dict import dict_search +from vyos.utils.kernel import check_kmod from vyos.utils.network import get_interface_config from vyos.utils.network import get_vrf_members from vyos.utils.network import interface_exists from vyos.utils.process import call from vyos.utils.process import cmd -from vyos.utils.process import popen -from vyos.utils.process import run from vyos.utils.system import sysctl_write from vyos import ConfigError from vyos import frr @@ -41,17 +40,29 @@ from vyos import airbag airbag.enable() config_file = '/etc/iproute2/rt_tables.d/vyos-vrf.conf' -nft_vrf_config = '/tmp/nftables-vrf-zones' - -def has_rule(af : str, priority : int, table : str): - """ Check if a given ip rule exists """ +k_mod = ['vrf'] + +def has_rule(af : str, priority : int, table : str=None): + """ + Check if a given ip rule exists + $ ip --json -4 rule show + [{'l3mdev': None, 'priority': 1000, 'src': 'all'}, + {'action': 'unreachable', 'l3mdev': None, 'priority': 2000, 'src': 'all'}, + {'priority': 32765, 'src': 'all', 'table': 'local'}, + {'priority': 32766, 'src': 'all', 'table': 'main'}, + {'priority': 32767, 'src': 'all', 'table': 'default'}] + """ if af not in ['-4', '-6']: raise ValueError() - command = f'ip -j {af} rule show' + command = f'ip --detail --json {af} rule show' for tmp in loads(cmd(command)): - if {'priority', 'table'} <= set(tmp): + if 'priority' in tmp and 'table' in tmp: if tmp['priority'] == priority and tmp['table'] == table: return True + elif 'priority' in tmp and table in tmp: + # l3mdev table has a different layout + if tmp['priority'] == priority: + return True return False def vrf_interfaces(c, match): @@ -173,8 +184,6 @@ def verify(vrf): def generate(vrf): # Render iproute2 VR helper names render(config_file, 'iproute2/vrf.conf.j2', vrf) - # Render nftables zones config - render(nft_vrf_config, 'firewall/nftables-vrf-zones.j2', vrf) # Render VRF Kernel/Zebra route-map filters vrf['frr_zebra_config'] = render_to_string('frr/zebra.vrf.route-map.frr.j2', vrf) @@ -227,14 +236,6 @@ def apply(vrf): sysctl_write('net.vrf.strict_mode', strict_mode) if 'name' in vrf: - # Separate VRFs in conntrack table - # check if table already exists - _, err = popen('nft list table inet vrf_zones') - # If not, create a table - 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. @@ -318,17 +319,11 @@ def apply(vrf): frr_cfg.add_before(frr.default_add_before, vrf['frr_zebra_config']) frr_cfg.commit_configuration(zebra_daemon) - # return to default lookup preference when no VRF is configured - if 'name' not in vrf: - # Remove VRF zones table from nftables - tmp = run('nft list table inet vrf_zones') - if tmp == 0: - cmd('nft delete table inet vrf_zones') - return None if __name__ == '__main__': try: + check_kmod(k_mod) c = get_config() verify(c) generate(c) |