summaryrefslogtreecommitdiff
path: root/src/conf_mode
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2026-08-21 08:00:50 -0500
committerGitHub <noreply@github.com>2026-08-21 08:00:50 -0500
commit0712fac9dddb4dbfede4409867d2973ccbfb5aa2 (patch)
tree54b01fae4c493735918efb5229b613017521fe74 /src/conf_mode
parentac99e72affedc97c62d47d2391ade14fd6c2e884 (diff)
parent7b960007e817b722596b7e388577d73ad7a87ed7 (diff)
downloadvyos-1x-0712fac9dddb4dbfede4409867d2973ccbfb5aa2.tar.gz
vyos-1x-0712fac9dddb4dbfede4409867d2973ccbfb5aa2.zip
Merge pull request #5325 from alexandr-san4ez/T8868-rolling
kdump: T8868: Implement kernel crash dump support
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-xsrc/conf_mode/system_option.py99
1 files changed, 96 insertions, 3 deletions
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index 8951adcff..190db232d 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -26,22 +26,27 @@ from vyos.base import Warning
from vyos.config import Config
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_interface_exists
+from vyos.defaults import KDUMP_DEFAULT_MEMORY_AUTO
+from vyos.system import image
from vyos.system import grub_util
from vyos.template import render
from vyos.utils.boot import boot_configuration_complete
from vyos.utils.convert import range_str_to_list
from vyos.utils.convert import list_to_range_str
+from vyos.utils.convert import human_to_bytes
from vyos.utils.cpu import get_cpus
from vyos.utils.cpu import get_available_cpus
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
-from vyos.utils.file import read_file
from vyos.utils.kernel import check_kmod
+from vyos.utils.kernel import get_kernel_boot_arg
+from vyos.utils.kernel import get_crash_kernel_size
from vyos.utils.process import cmdl
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.utils.system import sysctl_write
+from vyos.utils.memory import get_memory_info
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
from vyos import ConfigError
@@ -73,6 +78,15 @@ tuned_profiles = {
'virtual-host': 'virtual-host',
}
+# Path to the kdump-tools configuration file controlling dump behaviour
+KDUMP_CONFIG_FILE = '/etc/default/kdump-tools'
+
+# initramfs-tools drop-in configuration applied during kdump initrd
+# generation. Named with 'zzzz-' prefix to ensure it is sourced last,
+# overriding any conflicting settings from other drop-ins (including the
+# `MODULES=dep` override written by the kdump-tools kernel postinst hook).
+KDUMP_INITRAMFS_HOOK = '/etc/initramfs-tools/conf.d/zzzz-kdump-vyos-overlay'
+
MANAGED_PARAMS = {
'hugepages1g': {
'parse': r'hugepagesz=1[Gg]\s+hugepages=(?P<hugepages1g>\d+)',
@@ -168,6 +182,11 @@ MANAGED_PARAMS = {
'clean': r'numa_balancing=\S+',
'type': str,
},
+ 'crashkernel': {
+ 'parse': r'crashkernel=(?P<crashkernel>\S+)',
+ 'clean': r'crashkernel=\S+',
+ 'type': str,
+ },
}
# Compiled regex pattern for parsing command line options
@@ -198,9 +217,18 @@ def get_config(config=None):
conf = Config()
base = ['system', 'option']
options = conf.get_config_dict(
- base, key_mangling=('-', '_'), get_first_key=True, with_recursive_defaults=True
+ base,
+ key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True,
+ with_pki=True,
)
+ if 'kdump' not in options:
+ options['kdump'] = {}
+ options['kdump']['is_live_boot'] = image.is_live_boot()
+ options['kdump']['disabled'] = not conf.exists(base + ['kdump'])
+
if 'performance' in options:
# Update IPv4/IPv6 and sysctl options after tuned applied it's settings
set_dependents('ip_ipv6', conf)
@@ -314,6 +342,32 @@ def verify(options):
f'({reserved_gb} GB is reserved for system usage and services)'
)
+ if not options['kdump']['disabled']:
+ kdump = options['kdump']
+
+ if kdump.get('is_live_boot'):
+ raise ConfigError('kdump is not supported on live boot images')
+
+ # Check that the configured crash kernel memory does not exceed the
+ # total system RAM for the applicable range
+ memory = kdump.get('memory')
+ if memory and memory != 'auto':
+ memory_info = get_memory_info()
+ # Convert kilobytes to bytes
+ memory_total = memory_info['MemTotal'] * 1024
+
+ # 'memory_info' doesn't consider crash kernel reservation size
+ memory_total += get_crash_kernel_size()
+
+ # Convert scalar value from megabytes to bytes
+ memory_bytes = human_to_bytes(f'{memory}mb')
+
+ # Ensure that specified memory does not exceed total virtual memory
+ if memory_bytes >= memory_total:
+ raise ConfigError(
+ f'Specified kdump memory {memory!r} exceeds the available system RAM'
+ )
+
return None
@@ -401,6 +455,45 @@ def generate(options):
if count:
cmdline_options.append(f'hugepages={count}')
+ kdump = options['kdump']
+ if not kdump['disabled']:
+ # Crash kernel memory reservation
+ kdump_memory = kdump.get('memory')
+ if kdump_memory:
+ if kdump_memory == 'auto':
+ # Tiered auto-sizing based on total system RAM
+ kdump_memory = KDUMP_DEFAULT_MEMORY_AUTO
+ else:
+ # Append suffix (megabytes) to right format
+ kdump_memory = f'{kdump_memory}M'
+
+ # The `crashkernel=` parameter instructs the boot kernel to reserve a
+ # dedicated memory region for the capture kernel.
+ cmdline_options.append(f'crashkernel={kdump_memory}')
+
+ # Render the kdump-tools configuration file from the Jinja2 template
+ render(KDUMP_CONFIG_FILE, 'system/kdump_tools.conf.j2', kdump)
+
+ # VyOS uses an OverlayFS root filesystem. When mkinitramfs runs with
+ # `MODULES=dep`, it attempts to determine which kernel modules are needed
+ # by walking up the device tree from /. On a real block device
+ # this works correctly, but OverlayFS has no backing block device to walk from,
+ # causing mkinitramfs to fail with:
+ # mkinitramfs: failed to determine device for /
+ write_file(KDUMP_INITRAMFS_HOOK, 'MODULES=most')
+ else:
+ # kdump has been disabled - render the
+ # kdump-tools configuration with the disabled flag so the service
+ # starts in a no-op state rather than attempting to load a capture
+ # kernel with stale or missing parameters.
+ render(KDUMP_CONFIG_FILE, 'system/kdump_tools.conf.j2', kdump)
+
+ # Remove ephemeral files after the feature is disabled
+ kdump_delete_files = (KDUMP_INITRAMFS_HOOK,)
+ for delete_file in kdump_delete_files:
+ if os.path.exists(delete_file):
+ os.unlink(delete_file)
+
cmdline_options_str = ' '.join(cmdline_options)
grub_util.update_kernel_cmdline_options(cmdline_options_str)
@@ -464,7 +557,7 @@ def generate_cmdline_for_kexec(options):
- new_cmdline (str): The updated kernel command line string.
"""
# Read current cmdline and parse it
- current_cmdline = read_file('/proc/cmdline').strip()
+ current_cmdline = get_kernel_boot_arg().strip()
current_parsed = parse_cmdline(current_cmdline)
# Parse desired options from options['cmdline_options']