Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119064367
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json
index ca4ceb58f..9cfbffd96 100644
--- a/data/config-mode-dependencies/vyos-1x.json
+++ b/data/config-mode-dependencies/vyos-1x.json
@@ -1,67 +1,73 @@
{
"system_conntrack": {
"conntrack_sync": ["service_conntrack-sync"],
"vrf": ["vrf"]
},
"firewall": {
"conntrack": ["system_conntrack"],
"group_resync": ["system_conntrack", "nat", "policy_route"]
},
"interfaces_bonding": {
"ethernet": ["interfaces_ethernet"]
},
"interfaces_bridge": {
"vxlan": ["interfaces_vxlan"],
"wlan": ["interfaces_wireless"]
},
"load_balancing_wan": {
"conntrack": ["system_conntrack"]
},
"nat": {
"conntrack": ["system_conntrack"]
},
"nat66": {
"conntrack": ["system_conntrack"]
},
"pki": {
"ethernet": ["interfaces_ethernet"],
"openvpn": ["interfaces_openvpn"],
"https": ["service_https"],
"ipsec": ["vpn_ipsec"],
"openconnect": ["vpn_openconnect"],
"reverse_proxy": ["load-balancing_reverse-proxy"],
"rpki": ["protocols_rpki"],
"sstp": ["vpn_sstp"],
"sstpc": ["interfaces_sstpc"]
},
"vpn_ipsec": {
"nhrp": ["protocols_nhrp"]
},
"vpn_l2tp": {
"ipsec": ["vpn_ipsec"]
},
"qos": {
"bonding": ["interfaces_bonding"],
"bridge": ["interfaces_bridge"],
"dummy": ["interfaces_dummy"],
"ethernet": ["interfaces_ethernet"],
"geneve": ["interfaces_geneve"],
"input": ["interfaces_input"],
"l2tpv3": ["interfaces_l2tpv3"],
"loopback": ["interfaces_loopback"],
"macsec": ["interfaces_macsec"],
"openvpn": ["interfaces_openvpn"],
"pppoe": ["interfaces_pppoe"],
"pseudo-ethernet": ["interfaces_pseudo-ethernet"],
"tunnel": ["interfaces_tunnel"],
"vti": ["interfaces_vti"],
"vxlan": ["interfaces_vxlan"],
"wireguard": ["interfaces_wireguard"],
"wireless": ["interfaces_wireless"],
"wwan": ["interfaces_wwan"]
},
+ "system_ip": {
+ "sysctl": ["system_sysctl"]
+ },
+ "system_ipv6": {
+ "sysctl": ["system_sysctl"]
+ },
"system_option": {
- "ip": ["system_ip"],
- "ipv6": ["system_ipv6"]
+ "ip_ipv6": ["system_ip", "system_ipv6"],
+ "sysctl": ["system_sysctl"]
}
}
diff --git a/smoketest/scripts/cli/test_system_option.py b/smoketest/scripts/cli/test_system_option.py
new file mode 100755
index 000000000..c6f48bfc6
--- /dev/null
+++ b/smoketest/scripts/cli/test_system_option.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# 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/>.
+
+import os
+import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.utils.file import read_file
+from vyos.utils.process import is_systemd_service_active
+from vyos.utils.system import sysctl_read
+
+base_path = ['system', 'option']
+
+class TestSystemOption(VyOSUnitTestSHIM.TestCase):
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_ctrl_alt_delete(self):
+ self.cli_set(base_path + ['ctrl-alt-delete', 'reboot'])
+ self.cli_commit()
+
+ tmp = os.readlink('/lib/systemd/system/ctrl-alt-del.target')
+ self.assertEqual(tmp, '/lib/systemd/system/reboot.target')
+
+ self.cli_set(base_path + ['ctrl-alt-delete', 'poweroff'])
+ self.cli_commit()
+
+ tmp = os.readlink('/lib/systemd/system/ctrl-alt-del.target')
+ self.assertEqual(tmp, '/lib/systemd/system/poweroff.target')
+
+ self.cli_delete(base_path + ['ctrl-alt-delete', 'poweroff'])
+ self.cli_commit()
+ self.assertFalse(os.path.exists('/lib/systemd/system/ctrl-alt-del.target'))
+
+ def test_reboot_on_panic(self):
+ panic_file = '/proc/sys/kernel/panic'
+
+ tmp = read_file(panic_file)
+ self.assertEqual(tmp, '0')
+
+ self.cli_set(base_path + ['reboot-on-panic'])
+ self.cli_commit()
+
+ tmp = read_file(panic_file)
+ self.assertEqual(tmp, '60')
+
+ def test_performance(self):
+ tuned_service = 'tuned.service'
+
+ self.assertFalse(is_systemd_service_active(tuned_service))
+
+ # T3204 sysctl options must not be overwritten by tuned
+ gc_thresh1 = '131072'
+ gc_thresh2 = '262000'
+ gc_thresh3 = '524000'
+
+ self.cli_set(['system', 'sysctl', 'parameter', 'net.ipv4.neigh.default.gc_thresh1', 'value', gc_thresh1])
+ self.cli_set(['system', 'sysctl', 'parameter', 'net.ipv4.neigh.default.gc_thresh2', 'value', gc_thresh2])
+ self.cli_set(['system', 'sysctl', 'parameter', 'net.ipv4.neigh.default.gc_thresh3', 'value', gc_thresh3])
+
+ self.cli_set(base_path + ['performance', 'throughput'])
+ self.cli_commit()
+
+ self.assertTrue(is_systemd_service_active(tuned_service))
+
+ self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh1'), gc_thresh1)
+ self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh2'), gc_thresh2)
+ self.assertEqual(sysctl_read('net.ipv4.neigh.default.gc_thresh3'), gc_thresh3)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, failfast=True)
diff --git a/src/conf_mode/system_ip.py b/src/conf_mode/system_ip.py
index 2a0bda91a..c8a91fd2f 100755
--- a/src/conf_mode/system_ip.py
+++ b/src/conf_mode/system_ip.py
@@ -1,138 +1,146 @@
#!/usr/bin/env python3
#
# 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
# 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/>.
from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_route_map
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
from vyos.utils.process import is_systemd_service_active
from vyos.utils.system import sysctl_write
-
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos import ConfigError
from vyos import frr
from vyos import airbag
airbag.enable()
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['system', 'ip']
opt = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True,
with_recursive_defaults=True)
# When working with FRR we need to know the corresponding address-family
opt['afi'] = 'ip'
# We also need the route-map information from the config
#
# XXX: one MUST always call this without the key_mangling() option! See
# vyos.configverify.verify_common_route_maps() for more information.
tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
get_first_key=True)}}
# Merge policy dict into "regular" config dict
opt = dict_merge(tmp, opt)
+
+ # If IPv4 ARP table size is set here and also manually in sysctl, the more
+ # fine grained value from sysctl must win
+ set_dependents('sysctl', conf)
+
return opt
def verify(opt):
if 'protocol' in opt:
for protocol, protocol_options in opt['protocol'].items():
if 'route_map' in protocol_options:
verify_route_map(protocol_options['route_map'], opt)
return
def generate(opt):
opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt)
return
def apply(opt):
# Apply ARP threshold values
# 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_write('net.ipv4.neigh.default.gc_thresh3', size)
# Amount after which the records begin to be cleaned after 5 seconds
sysctl_write('net.ipv4.neigh.default.gc_thresh2', size // 2)
# Minimum number of stored records is indicated which is not cleared
sysctl_write('net.ipv4.neigh.default.gc_thresh1', size // 8)
# enable/disable IPv4 forwarding
tmp = dict_search('disable_forwarding', opt)
value = '0' if (tmp != None) else '1'
write_file('/proc/sys/net/ipv4/conf/all/forwarding', value)
# configure multipath
tmp = dict_search('multipath.ignore_unreachable_nexthops', opt)
value = '1' if (tmp != None) else '0'
sysctl_write('net.ipv4.fib_multipath_use_neigh', value)
tmp = dict_search('multipath.layer4_hashing', opt)
value = '1' if (tmp != None) else '0'
sysctl_write('net.ipv4.fib_multipath_hash_policy', value)
# configure TCP options (defaults as of Linux 6.4)
tmp = dict_search('tcp.mss.probing', opt)
if tmp is None:
value = 0
elif tmp == 'on-icmp-black-hole':
value = 1
elif tmp == 'force':
value = 2
else:
# Shouldn't happen
raise ValueError("TCP MSS probing is neither 'on-icmp-black-hole' nor 'force'!")
sysctl_write('net.ipv4.tcp_mtu_probing', value)
tmp = dict_search('tcp.mss.base', opt)
value = '1024' if (tmp is None) else tmp
sysctl_write('net.ipv4.tcp_base_mss', value)
tmp = dict_search('tcp.mss.floor', opt)
value = '48' if (tmp is None) else tmp
sysctl_write('net.ipv4.tcp_mtu_probe_floor', value)
# During startup of vyos-router that brings up FRR, the service is not yet
# running when this script is called first. Skip this part and wait for initial
# commit of the configuration to trigger this statement
if is_systemd_service_active('frr.service'):
zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
# The route-map used for the FIB (zebra) is part of the zebra daemon
frr_cfg.load_configuration(zebra_daemon)
frr_cfg.modify_section(r'no ip nht resolve-via-default')
frr_cfg.modify_section(r'ip protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
if 'frr_zebra_config' in opt:
frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
frr_cfg.commit_configuration(zebra_daemon)
+ call_dependents()
+
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
diff --git a/src/conf_mode/system_ipv6.py b/src/conf_mode/system_ipv6.py
index 00d440e35..a2442d009 100755
--- a/src/conf_mode/system_ipv6.py
+++ b/src/conf_mode/system_ipv6.py
@@ -1,121 +1,130 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019-2023 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/>.
import os
from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_route_map
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
from vyos.utils.process import is_systemd_service_active
from vyos.utils.system import sysctl_write
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos import ConfigError
from vyos import frr
from vyos import airbag
airbag.enable()
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['system', 'ipv6']
opt = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True,
with_recursive_defaults=True)
# When working with FRR we need to know the corresponding address-family
opt['afi'] = 'ipv6'
# We also need the route-map information from the config
#
# XXX: one MUST always call this without the key_mangling() option! See
# vyos.configverify.verify_common_route_maps() for more information.
tmp = {'policy' : {'route-map' : conf.get_config_dict(['policy', 'route-map'],
get_first_key=True)}}
# Merge policy dict into "regular" config dict
opt = dict_merge(tmp, opt)
+
+ # If IPv6 neighbor table size is set here and also manually in sysctl, the more
+ # fine grained value from sysctl must win
+ set_dependents('sysctl', conf)
+
return opt
def verify(opt):
if 'protocol' in opt:
for protocol, protocol_options in opt['protocol'].items():
if 'route_map' in protocol_options:
verify_route_map(protocol_options['route_map'], opt)
return
def generate(opt):
opt['frr_zebra_config'] = render_to_string('frr/zebra.route-map.frr.j2', opt)
return
def apply(opt):
# configure multipath
tmp = dict_search('multipath.layer4_hashing', opt)
value = '1' if (tmp != None) else '0'
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_write('net.ipv6.neigh.default.gc_thresh3', size)
# Amount after which the records begin to be cleaned after 5 seconds
sysctl_write('net.ipv6.neigh.default.gc_thresh2', size // 2)
# Minimum number of stored records is indicated which is not cleared
sysctl_write('net.ipv6.neigh.default.gc_thresh1', size // 8)
# enable/disable IPv6 forwarding
tmp = dict_search('disable_forwarding', opt)
value = '0' if (tmp != None) else '1'
write_file('/proc/sys/net/ipv6/conf/all/forwarding', value)
# configure IPv6 strict-dad
tmp = dict_search('strict_dad', opt)
value = '2' if (tmp != None) else '1'
for root, dirs, files in os.walk('/proc/sys/net/ipv6/conf'):
for name in files:
if name == 'accept_dad':
write_file(os.path.join(root, name), value)
# During startup of vyos-router that brings up FRR, the service is not yet
# running when this script is called first. Skip this part and wait for initial
# commit of the configuration to trigger this statement
if is_systemd_service_active('frr.service'):
zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
# The route-map used for the FIB (zebra) is part of the zebra daemon
frr_cfg.load_configuration(zebra_daemon)
frr_cfg.modify_section(r'no ipv6 nht resolve-via-default')
frr_cfg.modify_section(r'ipv6 protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
if 'frr_zebra_config' in opt:
frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
frr_cfg.commit_configuration(zebra_daemon)
+ call_dependents()
+
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index 9fd7a3195..d1647e3a1 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -1,194 +1,195 @@
#!/usr/bin/env python3
#
# 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
# 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/>.
import os
from sys import exit
from time import sleep
from vyos.config import Config
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_interface_exists
from vyos.system import grub_util
from vyos.template import render
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
from vyos.utils.kernel import check_kmod
from vyos.utils.process import cmd
from vyos.utils.process import is_systemd_service_running
from vyos.utils.network import is_addr_assigned
from vyos.utils.network import is_intf_addr_assigned
-from vyos.configdep import set_dependents, call_dependents
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos import ConfigError
from vyos import airbag
airbag.enable()
curlrc_config = r'/etc/curlrc'
ssh_config = r'/etc/ssh/ssh_config.d/91-vyos-ssh-client-options.conf'
systemd_action_file = '/lib/systemd/system/ctrl-alt-del.target'
usb_autosuspend = r'/etc/udev/rules.d/40-usb-autosuspend.rules'
kernel_dynamic_debug = r'/sys/kernel/debug/dynamic_debug/control'
time_format_to_locale = {
'12-hour': 'en_US.UTF-8',
'24-hour': 'en_GB.UTF-8'
}
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['system', 'option']
options = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True,
with_recursive_defaults=True)
if 'performance' in options:
- # Update IPv4 and IPv6 options after TuneD reapplies
- # sysctl from config files
- for protocol in ['ip', 'ipv6']:
- set_dependents(protocol, conf)
+ # Update IPv4/IPv6 and sysctl options after tuned applied it's settings
+ set_dependents('ip_ipv6', conf)
+ set_dependents('sysctl', conf)
return options
def verify(options):
if 'http_client' in options:
config = options['http_client']
if 'source_interface' in config:
verify_interface_exists(options, config['source_interface'])
if {'source_address', 'source_interface'} <= set(config):
raise ConfigError('Can not define both HTTP source-interface and source-address')
if 'source_address' in config:
if not is_addr_assigned(config['source_address']):
raise ConfigError('No interface with give address specified!')
if 'ssh_client' in options:
config = options['ssh_client']
if 'source_address' in config:
address = config['source_address']
if not is_addr_assigned(config['source_address']):
raise ConfigError('No interface with address "{address}" configured!')
if 'source_interface' in config:
verify_source_interface(config)
if 'source_address' in config:
address = config['source_address']
interface = config['source_interface']
if not is_intf_addr_assigned(interface, address):
raise ConfigError(f'Address "{address}" not assigned on interface "{interface}"!')
return None
def generate(options):
render(curlrc_config, 'system/curlrc.j2', options)
render(ssh_config, 'system/ssh_config.j2', options)
render(usb_autosuspend, 'system/40_usb_autosuspend.j2', options)
cmdline_options = []
if 'kernel' in options:
if 'disable_mitigations' in options['kernel']:
cmdline_options.append('mitigations=off')
if 'disable_power_saving' in options['kernel']:
cmdline_options.append('intel_idle.max_cstate=0 processor.max_cstate=1')
grub_util.update_kernel_cmdline_options(' '.join(cmdline_options))
return None
def apply(options):
# System bootup beep
+ beep_service = 'vyos-beep.service'
if 'startup_beep' in options:
- cmd('systemctl enable vyos-beep.service')
+ cmd(f'systemctl enable {beep_service}')
else:
- cmd('systemctl disable vyos-beep.service')
+ cmd(f'systemctl disable {beep_service}')
# Ctrl-Alt-Delete action
if os.path.exists(systemd_action_file):
os.unlink(systemd_action_file)
if 'ctrl_alt_delete' in options:
if options['ctrl_alt_delete'] == 'reboot':
os.symlink('/lib/systemd/system/reboot.target', systemd_action_file)
elif options['ctrl_alt_delete'] == 'poweroff':
os.symlink('/lib/systemd/system/poweroff.target', systemd_action_file)
# Configure HTTP client
if 'http_client' not in options:
if os.path.exists(curlrc_config):
os.unlink(curlrc_config)
# Configure SSH client
if 'ssh_client' not in options:
if os.path.exists(ssh_config):
os.unlink(ssh_config)
# Reboot system on kernel panic
timeout = '0'
if 'reboot_on_panic' in options:
timeout = '60'
with open('/proc/sys/kernel/panic', 'w') as f:
f.write(timeout)
# tuned - performance tuning
if 'performance' in options:
cmd('systemctl restart tuned.service')
# wait until daemon has started before sending configuration
while (not is_systemd_service_running('tuned.service')):
sleep(0.250)
cmd('tuned-adm profile network-{performance}'.format(**options))
else:
cmd('systemctl stop tuned.service')
call_dependents()
# Keyboard layout - there will be always the default key inside the dict
# but we check for key existence anyway
if 'keyboard_layout' in options:
cmd('loadkeys {keyboard_layout}'.format(**options))
# Enable/diable root-partition-auto-resize SystemD service
if 'root_partition_auto_resize' in options:
cmd('systemctl enable root-partition-auto-resize.service')
else:
cmd('systemctl disable root-partition-auto-resize.service')
# Time format 12|24-hour
if 'time_format' in options:
time_format = time_format_to_locale.get(options['time_format'])
cmd(f'localectl set-locale LC_TIME={time_format}')
# Reload UDEV, required for USB auto suspend
cmd('udevadm control --reload-rules')
# Enable/disable dynamic debugging for kernel modules
modules = ['wireguard']
modules_enabled = dict_search('kernel.debug', options) or []
for module in modules:
if module in modules_enabled:
check_kmod(module)
write_file(kernel_dynamic_debug, f'module {module} +p')
else:
write_file(kernel_dynamic_debug, f'module {module} -p')
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:55 AM (7 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4654092
Default Alt Text
(24 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment