summaryrefslogtreecommitdiff
path: root/src/conf_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-xsrc/conf_mode/firewall.py11
-rwxr-xr-xsrc/conf_mode/interfaces_wireguard.py28
-rwxr-xr-xsrc/conf_mode/nat.py6
-rwxr-xr-xsrc/conf_mode/nat66.py4
-rwxr-xr-xsrc/conf_mode/policy.py16
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py5
-rwxr-xr-xsrc/conf_mode/system_option.py45
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py2
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py2
9 files changed, 92 insertions, 27 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index 274ca2ce6..348eaeba3 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -17,6 +17,8 @@
import os
import re
+from glob import glob
+
from sys import exit
from vyos.base import Warning
from vyos.config import Config
@@ -30,6 +32,7 @@ from vyos.firewall import geoip_update
from vyos.template import render
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
+from vyos.utils.file import write_file
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
@@ -37,7 +40,6 @@ from vyos.utils.network import get_vrf_members
from vyos.utils.network import get_interface_vrf
from vyos import ConfigError
from vyos import airbag
-from pathlib import Path
from subprocess import run as subp_run
airbag.enable()
@@ -626,10 +628,11 @@ def apply(firewall):
domain_action = 'restart'
if dict_search_args(firewall, 'group', 'remote_group') or dict_search_args(firewall, 'group', 'domain_group') or firewall['ip_fqdn'].items() or firewall['ip6_fqdn'].items():
text = f'# Automatically generated by firewall.py\nThis file indicates that vyos-domain-resolver service is used by the firewall.\n'
- Path(domain_resolver_usage).write_text(text)
+ write_file(domain_resolver_usage, text)
else:
- Path(domain_resolver_usage).unlink(missing_ok=True)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if os.path.exists(domain_resolver_usage):
+ os.unlink(domain_resolver_usage)
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
diff --git a/src/conf_mode/interfaces_wireguard.py b/src/conf_mode/interfaces_wireguard.py
index 3ca6ecdca..770667df1 100755
--- a/src/conf_mode/interfaces_wireguard.py
+++ b/src/conf_mode/interfaces_wireguard.py
@@ -14,6 +14,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
+
+from glob import glob
from sys import exit
from vyos.config import Config
@@ -35,7 +38,6 @@ from vyos.utils.network import is_wireguard_key_pair
from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
-from pathlib import Path
airbag.enable()
@@ -145,19 +147,11 @@ def generate(wireguard):
def apply(wireguard):
check_kmod('wireguard')
- if 'rebuild_required' in wireguard or 'deleted' in wireguard:
- wg = WireGuardIf(**wireguard)
- # WireGuard only supports peer removal based on the configured public-key,
- # by deleting the entire interface this is the shortcut instead of parsing
- # out all peers and removing them one by one.
- #
- # Peer reconfiguration will always come with a short downtime while the
- # WireGuard interface is recreated (see below)
- wg.remove()
+ wg = WireGuardIf(**wireguard)
- # Create the new interface if required
- if 'deleted' not in wireguard:
- wg = WireGuardIf(**wireguard)
+ if 'deleted' in wireguard:
+ wg.remove()
+ else:
wg.update(wireguard)
domain_resolver_usage = '/run/use-vyos-domain-resolver-interfaces-wireguard-' + wireguard['ifname']
@@ -168,12 +162,12 @@ def apply(wireguard):
from vyos.utils.file import write_file
text = f'# Automatically generated by interfaces_wireguard.py\nThis file indicates that vyos-domain-resolver service is used by the interfaces_wireguard.\n'
- text += "intefaces:\n" + "".join([f" - {peer}\n" for peer in wireguard['peers_need_resolve']])
- Path(domain_resolver_usage).write_text(text)
+ text += "interfaces:\n" + "".join([f" - {peer}\n" for peer in wireguard['peers_need_resolve']])
write_file(domain_resolver_usage, text)
else:
- Path(domain_resolver_usage).unlink(missing_ok=True)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if os.path.exists(domain_resolver_usage):
+ os.unlink(domain_resolver_usage)
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index 504b3e82a..6c88e5cfd 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -16,8 +16,8 @@
import os
+from glob import glob
from sys import exit
-from pathlib import Path
from vyos.base import Warning
from vyos.config import Config
@@ -265,9 +265,9 @@ def apply(nat):
text = f'# Automatically generated by nat.py\nThis file indicates that vyos-domain-resolver service is used by nat.\n'
write_file(domain_resolver_usage, text)
elif os.path.exists(domain_resolver_usage):
- Path(domain_resolver_usage).unlink(missing_ok=True)
+ os.unlink(domain_resolver_usage)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 95dfae3a5..c65950c9e 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -92,6 +92,10 @@ def verify(nat):
if prefix != None:
if not is_ipv6(prefix):
raise ConfigError(f'{err_msg} source-prefix not specified')
+
+ if 'destination' in config and 'group' in config['destination']:
+ if len({'address_group', 'network_group', 'domain_group'} & set(config['destination']['group'])) > 1:
+ raise ConfigError('Only one address-group, network-group or domain-group can be specified')
if dict_search('destination.rule', nat):
for rule, config in dict_search('destination.rule', nat).items():
diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py
index a90e33e81..ec9005890 100755
--- a/src/conf_mode/policy.py
+++ b/src/conf_mode/policy.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import re
from sys import exit
from vyos.config import Config
@@ -24,9 +25,20 @@ from vyos.frrender import get_frrender_dict
from vyos.utils.dict import dict_search
from vyos.utils.process import is_systemd_service_running
from vyos import ConfigError
+from vyos.base import Warning
from vyos import airbag
airbag.enable()
+# Sanity checks for large-community-list regex:
+# * Require complete 3-tuples, no blank members. Catch missed & doubled colons.
+# * Permit appropriate community separators (whitespace, underscore)
+# * Permit common regex between tuples while requiring at least one separator
+# (eg, "1:1:1_.*_4:4:4", matching "1:1:1 4:4:4" and "1:1:1 2:2:2 4:4:4",
+# but not "1:1:13 24:4:4")
+# Best practice: stick with basic patterns, mind your wildcards and whitespace.
+# Regex that doesn't match this pattern will be allowed with a warning.
+large_community_regex_pattern = r'([^: _]+):([^: _]+):([^: _]+)([ _]([^:]+):([^: _]+):([^: _]+))*'
+
def community_action_compatibility(actions: dict) -> bool:
"""
Check compatibility of values in community and large community sections
@@ -147,6 +159,10 @@ def verify(config_dict):
if 'regex' not in rule_config:
raise ConfigError(f'A regex {mandatory_error}')
+ if policy_type == 'large_community_list':
+ if not re.fullmatch(large_community_regex_pattern, rule_config['regex']):
+ Warning(f'"policy large-community-list {instance} rule {rule} regex" does not follow expected form and may not match as expected.')
+
if policy_type in ['prefix_list', 'prefix_list6']:
if 'prefix' not in rule_config:
raise ConfigError(f'A prefix {mandatory_error}')
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 99d8eb9d1..e29f3358a 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -527,6 +527,10 @@ def verify(config_dict):
raise ConfigError(
'Please unconfigure import vrf commands before using vpn commands in dependent VRFs!')
+ # Verify if the route-map exists
+ if dict_search('route_map.vrf.import', afi_config) is not None:
+ verify_route_map(afi_config['route_map']['vrf']['import'], bgp)
+
if (dict_search('route_map.vrf.import', afi_config) is not None
or dict_search('import.vrf', afi_config) is not None):
# FRR error: please unconfigure vpn to vrf commands before
@@ -541,7 +545,6 @@ def verify(config_dict):
raise ConfigError('Please unconfigure route-map VPN to VRF commands before '\
'using "import vrf" commands!')
-
# Verify that the export/import route-maps do exist
for export_import in ['export', 'import']:
tmp = dict_search(f'route_map.vpn.{export_import}', afi_config)
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index 3d76a1eaa..5acad6599 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -127,6 +127,9 @@ def generate(options):
# occurance is used for having the appropriate options passed to GRUB
# when re-configuring options on the CLI.
cmdline_options = []
+ kernel_opts = options.get('kernel', {})
+ k_cpu_opts = kernel_opts.get('cpu', {})
+ k_memory_opts = kernel_opts.get('memory', {})
if 'kernel' in options:
if 'disable_mitigations' in options['kernel']:
cmdline_options.append('mitigations=off')
@@ -138,6 +141,48 @@ def generate(options):
f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}')
if 'quiet' in options['kernel']:
cmdline_options.append('quiet')
+
+ if 'disable_hpet' in kernel_opts:
+ cmdline_options.append('hpet=disable')
+
+ if 'disable_mce' in kernel_opts:
+ cmdline_options.append('mce=off')
+
+ if 'disable_softlockup' in kernel_opts:
+ cmdline_options.append('nosoftlockup')
+
+ # CPU options
+ isol_cpus = k_cpu_opts.get('isolate_cpus')
+ if isol_cpus:
+ cmdline_options.append(f'isolcpus={isol_cpus}')
+
+ nohz_full = k_cpu_opts.get('nohz_full')
+ if nohz_full:
+ cmdline_options.append(f'nohz_full={nohz_full}')
+
+ rcu_nocbs = k_cpu_opts.get('rcu_no_cbs')
+ if rcu_nocbs:
+ cmdline_options.append(f'rcu_nocbs={rcu_nocbs}')
+
+ if 'disable_nmi_watchdog' in k_cpu_opts:
+ cmdline_options.append('nmi_watchdog=0')
+
+ # Memory options
+ if 'disable_numa_balancing' in k_memory_opts:
+ cmdline_options.append('numa_balancing=disable')
+
+ default_hp_size = k_memory_opts.get('default_hugepage_size')
+ if default_hp_size:
+ cmdline_options.append(f'default_hugepagesz={default_hp_size}')
+
+ hp_sizes = k_memory_opts.get('hugepage_size')
+ if hp_sizes:
+ for size, settings in hp_sizes.items():
+ cmdline_options.append(f'hugepagesz={size}')
+ count = settings.get('hugepage_count')
+ if count:
+ cmdline_options.append(f'hugepages={count}')
+
grub_util.update_kernel_cmdline_options(' '.join(cmdline_options))
return None
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 2754314f7..ac25cd671 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -727,7 +727,7 @@ def generate(ipsec):
for remote_prefix in remote_prefixes:
local_net = ipaddress.ip_network(local_prefix)
remote_net = ipaddress.ip_network(remote_prefix)
- if local_net.overlaps(remote_net):
+ if local_net.subnet_of(remote_net):
if passthrough is None:
passthrough = []
passthrough.append(local_prefix)
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 42785134f..0346c7819 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -93,7 +93,7 @@ def verify(ocserv):
"radius" in ocserv["authentication"]["mode"]):
raise ConfigError('OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration')
if "radius" in ocserv["authentication"]["mode"]:
- if not ocserv["authentication"]['radius']['server']:
+ if 'server' not in ocserv['authentication']['radius']:
raise ConfigError('OpenConnect authentication mode radius requires at least one RADIUS server')
if "local" in ocserv["authentication"]["mode"]:
if not ocserv.get("authentication", {}).get("local_users"):