summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2024-01-30 08:29:58 -0600
committerGitHub <noreply@github.com>2024-01-30 08:29:58 -0600
commit8bd6c24b50a34225763058c1daa28c8a8fe59098 (patch)
tree211c13a3df56abe246d556eaf04d8208d12b5af4
parent02f7f91e3937f1622ba055847aa96b207d5ba754 (diff)
parent287c3edbac7f308d3240bdec253f0e5103e8eca1 (diff)
downloadvyos-1x-8bd6c24b50a34225763058c1daa28c8a8fe59098.tar.gz
vyos-1x-8bd6c24b50a34225763058c1daa28c8a8fe59098.zip
Merge pull request #2888 from vyos/mergify/bp/sagitta/pr-2886
system-option: T5979: Add configurable kernel boot options (backport #2886)
-rw-r--r--data/templates/grub/grub_vyos_version.j29
-rw-r--r--interface-definitions/system_option.xml.in13
-rw-r--r--python/vyos/system/compat.py8
-rw-r--r--python/vyos/system/grub.py61
-rw-r--r--python/vyos/system/grub_util.py30
-rw-r--r--python/vyos/system/image.py13
-rwxr-xr-xsrc/conf_mode/system_option.py11
7 files changed, 133 insertions, 12 deletions
diff --git a/data/templates/grub/grub_vyos_version.j2 b/data/templates/grub/grub_vyos_version.j2
index 62688e68b..de85f1419 100644
--- a/data/templates/grub/grub_vyos_version.j2
+++ b/data/templates/grub/grub_vyos_version.j2
@@ -1,5 +1,10 @@
-{% set boot_opts_default = "boot=live rootdelay=5 noautologin net.ifnames=0 biosdevname=0 vyos-union=/boot/" + version_name %}
-{% if boot_opts != '' %}
+{% if boot_opts_config is vyos_defined %}
+{% if boot_opts_config %}
+{% set boot_opts_rendered = boot_opts_default + " " + boot_opts_config %}
+{% else %}
+{% set boot_opts_rendered = boot_opts_default %}
+{% endif %}
+{% elif boot_opts != '' %}
{% set boot_opts_rendered = boot_opts %}
{% else %}
{% set boot_opts_rendered = boot_opts_default %}
diff --git a/interface-definitions/system_option.xml.in b/interface-definitions/system_option.xml.in
index adb45bdcc..602d7d100 100644
--- a/interface-definitions/system_option.xml.in
+++ b/interface-definitions/system_option.xml.in
@@ -32,6 +32,19 @@
<constraintErrorMessage>Must be ignore, reboot, or poweroff</constraintErrorMessage>
</properties>
</leafNode>
+ <node name="kernel">
+ <properties>
+ <help>Kernel boot parameters</help>
+ </properties>
+ <children>
+ <leafNode name="disable-mitigations">
+ <properties>
+ <help>Disable all optional CPU mitigations</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<leafNode name="keyboard-layout">
<properties>
<help>System keyboard layout, type ISO2</help>
diff --git a/python/vyos/system/compat.py b/python/vyos/system/compat.py
index cc0529b91..37b834ad6 100644
--- a/python/vyos/system/compat.py
+++ b/python/vyos/system/compat.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -249,13 +249,17 @@ def update_version_list(root_dir: str = '') -> list[dict]:
menu_entries = list(filter(lambda x: x.get('version') != ver,
menu_entries))
+ # reset boot_opts in case of config update
+ for entry in menu_entries:
+ entry['boot_opts'] = grub.get_boot_opts(entry['version'])
+
add = list(set(current_versions) - set(menu_versions))
for ver in add:
last = menu_entries[0].get('version')
new = deepcopy(list(filter(lambda x: x.get('version') == last,
menu_entries)))
for e in new:
- boot_opts = e.get('boot_opts').replace(last, ver)
+ boot_opts = grub.get_boot_opts(ver)
e.update({'version': ver, 'boot_opts': boot_opts})
menu_entries = new + menu_entries
diff --git a/python/vyos/system/grub.py b/python/vyos/system/grub.py
index 3f5f89103..4e133c5fc 100644
--- a/python/vyos/system/grub.py
+++ b/python/vyos/system/grub.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -43,10 +43,14 @@ TMPL_GRUB_MODULES: str = 'grub/grub_modules.j2'
TMPL_GRUB_OPTS: str = 'grub/grub_options.j2'
TMPL_GRUB_COMMON: str = 'grub/grub_common.j2'
+# default boot options
+BOOT_OPTS_STEM: str = 'boot=live rootdelay=5 noautologin net.ifnames=0 biosdevname=0 vyos-union=/boot/'
+
# prepare regexes
REGEX_GRUB_VARS: str = r'^set (?P<variable_name>.+)=[\'"]?(?P<variable_value>.*)(?<![\'"])[\'"]?$'
REGEX_GRUB_MODULES: str = r'^insmod (?P<module_name>.+)$'
REGEX_KERNEL_CMDLINE: str = r'^BOOT_IMAGE=/(?P<boot_type>boot|live)/((?P<image_version>.+)/)?vmlinuz.*$'
+REGEX_GRUB_BOOT_OPTS: str = r'^\s*set boot_opts="(?P<boot_opts>[^$]+)"$'
def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS') -> None:
@@ -87,7 +91,8 @@ def gen_version_uuid(version_name: str) -> str:
def version_add(version_name: str,
root_dir: str = '',
- boot_opts: str = '') -> None:
+ boot_opts: str = '',
+ boot_opts_config = None) -> None:
"""Add a new VyOS version to GRUB loader configuration
Args:
@@ -104,7 +109,9 @@ def version_add(version_name: str,
version_config, TMPL_VYOS_VERSION, {
'version_name': version_name,
'version_uuid': gen_version_uuid(version_name),
- 'boot_opts': boot_opts
+ 'boot_opts_default': BOOT_OPTS_STEM + version_name,
+ 'boot_opts': boot_opts,
+ 'boot_opts_config': boot_opts_config
})
@@ -286,12 +293,43 @@ def vars_write(grub_cfg: str, grub_vars: dict[str, str]) -> None:
"""
render(grub_cfg, TMPL_GRUB_VARS, {'vars': grub_vars})
+def get_boot_opts(version_name: str, root_dir: str = '') -> str:
+ """Read boot_opts setting from version file; return default setting on
+ any failure.
+
+ Args:
+ version_name (str): version name
+ root_dir (str, optional): an optional path to the root directory.
+ Defaults to empty.
+ """
+ if not root_dir:
+ root_dir = disk.find_persistence()
+
+ boot_opts_default: str = BOOT_OPTS_STEM + version_name
+ boot_opts: str = ''
+ regex_filter = re_compile(REGEX_GRUB_BOOT_OPTS)
+ version_config: str = f'{root_dir}/{GRUB_DIR_VYOS_VERS}/{version_name}.cfg'
+ try:
+ config_text: list[str] = Path(version_config).read_text().splitlines()
+ except FileNotFoundError:
+ return boot_opts_default
+ for line in config_text:
+ search_result = regex_filter.fullmatch(line)
+ if search_result:
+ search_dict = search_result.groupdict()
+ boot_opts = search_dict.get('boot_opts', '')
+ break
+
+ if not boot_opts:
+ boot_opts = boot_opts_default
+
+ return boot_opts
def set_default(version_name: str, root_dir: str = '') -> None:
"""Set version as default boot entry
Args:
- version_name (str): versio name
+ version_name (str): version name
root_dir (str, optional): an optional path to the root directory.
Defaults to empty.
"""
@@ -361,3 +399,18 @@ def set_console_speed(console_speed: str, root_dir: str = '') -> None:
vars_current: dict[str, str] = vars_read(vars_file)
vars_current['console_speed'] = str(console_speed)
vars_write(vars_file, vars_current)
+
+def set_kernel_cmdline_options(cmdline_options: str, version_name: str,
+ root_dir: str = '') -> None:
+ """Write additional cmdline options to GRUB configuration
+
+ Args:
+ cmdline_options (str): cmdline options to add to default boot line
+ version_name (str): image version name
+ root_dir (str, optional): an optional path to the root directory.
+ """
+ if not root_dir:
+ root_dir = disk.find_persistence()
+
+ version_add(version_name=version_name, root_dir=root_dir,
+ boot_opts_config=cmdline_options)
diff --git a/python/vyos/system/grub_util.py b/python/vyos/system/grub_util.py
index 9e79d41d4..4a3d8795e 100644
--- a/python/vyos/system/grub_util.py
+++ b/python/vyos/system/grub_util.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
-from vyos.system import disk, grub, compat
+from vyos.system import disk, grub, image, compat
@compat.grub_cfg_update
def set_console_speed(console_speed: str, root_dir: str = '') -> None:
@@ -29,6 +29,7 @@ def set_console_speed(console_speed: str, root_dir: str = '') -> None:
grub.set_console_speed(console_speed, root_dir)
+@image.if_not_live_boot
def update_console_speed(console_speed: str, root_dir: str = '') -> None:
"""Update console_speed if different from current value"""
@@ -40,3 +41,30 @@ def update_console_speed(console_speed: str, root_dir: str = '') -> None:
console_speed_current = vars_current.get('console_speed', None)
if console_speed != console_speed_current:
set_console_speed(console_speed, root_dir)
+
+@compat.grub_cfg_update
+def set_kernel_cmdline_options(cmdline_options: str, version: str = '',
+ root_dir: str = '') -> None:
+ """Write Kernel CLI cmdline options to GRUB configuration"""
+ if not root_dir:
+ root_dir = disk.find_persistence()
+
+ if not version:
+ version = image.get_running_image()
+
+ grub.set_kernel_cmdline_options(cmdline_options, version, root_dir)
+
+@image.if_not_live_boot
+def update_kernel_cmdline_options(cmdline_options: str,
+ root_dir: str = '') -> None:
+ """Update Kernel custom cmdline options"""
+ if not root_dir:
+ root_dir = disk.find_persistence()
+
+ version = image.get_running_image()
+
+ boot_opts_current = grub.get_boot_opts(version, root_dir)
+ boot_opts_proposed = grub.BOOT_OPTS_STEM + f'{version} {cmdline_options}'
+
+ if boot_opts_proposed != boot_opts_current:
+ set_kernel_cmdline_options(cmdline_options, version, root_dir)
diff --git a/python/vyos/system/image.py b/python/vyos/system/image.py
index 514275654..5460e6a36 100644
--- a/python/vyos/system/image.py
+++ b/python/vyos/system/image.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -15,6 +15,7 @@
from pathlib import Path
from re import compile as re_compile
+from functools import wraps
from tempfile import TemporaryDirectory
from typing import TypedDict
@@ -262,6 +263,16 @@ def is_live_boot() -> bool:
return True
return False
+def if_not_live_boot(func):
+ """Decorator to call function only if not live boot"""
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ if not is_live_boot():
+ ret = func(*args, **kwargs)
+ return ret
+ return None
+ return wrapper
+
def is_running_as_container() -> bool:
if Path('/.dockerenv').exists():
return True
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):