diff options
| author | Oleksandr Kuchmystyi <o.kuchmystyi@vyos.io> | 2026-07-09 11:16:09 +0300 |
|---|---|---|
| committer | Viacheslav Hletenko <v.gletenko@vyos.io> | 2026-08-20 13:35:07 +0000 |
| commit | 2054c3c53f8bc83733c8ef81c2cc57f4e6b27f5a (patch) | |
| tree | dd42f9a7d6d3c60cf3662c1c456c6c17b310fd44 /python | |
| parent | 79e70fbfe0c4b5b33c5c707f0b0fee904fedd79f (diff) | |
| download | vyos-1x-2054c3c53f8bc83733c8ef81c2cc57f4e6b27f5a.tar.gz vyos-1x-2054c3c53f8bc83733c8ef81c2cc57f4e6b27f5a.zip | |
kdump: T8868: Implement kernel crash dump support
Add new CLI subtree 'system option kdump' with memory reservation and
local dump path configuration. Also add 'show system kdump' and
'show system kdump dumps' operation mode commands to get
status of the configuration and list of dumps.
Extend 'show tech-support report' and 'generate tech-support archive' with
kdump service status, active config files and the recently kernel dump file.
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/defaults.py | 8 | ||||
| -rw-r--r-- | python/vyos/utils/boot.py | 1 | ||||
| -rw-r--r-- | python/vyos/utils/kernel.py | 70 | ||||
| -rw-r--r-- | python/vyos/utils/memory.py | 28 |
4 files changed, 107 insertions, 0 deletions
diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index 5829b859f..854f95ff0 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -49,6 +49,7 @@ systemd_services = { 'openconnect': 'ocserv.service', 'syslog' : 'syslog.service', 'snmpd' : 'snmpd.service', + 'kdump': 'kdump-tools.service', } internal_ports = { @@ -115,3 +116,10 @@ config_sync_exclusion_list = os.path.join( # Sits between the l3mdev rule (1000) and the l3mdev unreachable rule (2000), # ensuring fwmark-tagged tunnel packets are routed into the correct VRF table. wireguard_fwmark_pref = '1998' + +# Tiered auto-sizing based on total system RAM, determined by +# empirical testing across representative VyOS deployments: +# 1G - 8G RAM -> reserve 512M +# 8G - 64G RAM -> reserve 768M +# 64G+ RAM -> reserve 1G +KDUMP_DEFAULT_MEMORY_AUTO = '1G-8G:512M,8G-64G:768M,64G-:1G' diff --git a/python/vyos/utils/boot.py b/python/vyos/utils/boot.py index f804cd94e..dc6fcd408 100644 --- a/python/vyos/utils/boot.py +++ b/python/vyos/utils/boot.py @@ -15,6 +15,7 @@ import os + def boot_configuration_complete() -> bool: """ Check if the boot config loader has completed """ diff --git a/python/vyos/utils/kernel.py b/python/vyos/utils/kernel.py index 726025605..69574cefc 100644 --- a/python/vyos/utils/kernel.py +++ b/python/vyos/utils/kernel.py @@ -17,10 +17,18 @@ import os from typing import Tuple from typing import Optional +from vyos.utils.file import read_file + # A list of used Kernel constants # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/net/wireguard/messages.h?h=linux-6.6.y#n45 WIREGUARD_REKEY_AFTER_TIME = 120 +CMDLINE_PATH = '/proc/cmdline' + +# Kernel interface files exposing crash kernel state at runtime +KEXEC_CRASH_LOADED = '/sys/kernel/kexec_crash_loaded' +KEXEC_CRASH_SIZE = '/sys/kernel/kexec_crash_size' + def load_module(name: str, quiet: bool = True, dry_run: bool = False) -> int: """Load a kernel module via modprobe. @@ -172,3 +180,65 @@ def get_kernel_serial_console() -> Tuple[Optional[str], Optional[str], Optional[ ) return (None, None, None) + + +def get_kernel_boot_arg(argument=None) -> str | None: + """Read and parse kernel boot arguments from the kernel command line. + + Args: + argument: The name of a specific boot argument to look up (e.g. + 'crashkernel'). If omitted or None, the full raw command + line string is returned. + + Returns: + If argument is None: the full kernel command line string. + If argument is given: the value of that argument (the part after '='), + or None if the argument is not present on the command line. + + Examples: + >>> get_kernel_boot_arg() + 'ro quiet crashkernel=256M console=tty0' + + >>> get_kernel_boot_arg('crashkernel') + '256M' + + >>> get_kernel_boot_arg('quiet') + '' + + >>> get_kernel_boot_arg('nonexistent') + None + """ + cmdline = read_file(CMDLINE_PATH) + if not argument: + return cmdline + + # Kernel arguments with values are formatted as 'key=value' tokens + # separated by spaces. Build the prefix to match against: + key = f'{argument}=' + + # Kernel parses the command line from left to right. + # A later argument will overwrite an earlier one. + for part in reversed(cmdline.split()): + if part.startswith(key): + # Strip the 'key=' prefix and return only the value portion + return part[len(key) :] + elif part == argument: + # Statement without value portion should be return empty string + return '' + + return None + + +def is_crash_kernel_loaded() -> bool: + """Return True when a capture kernel is currently loaded via kexec""" + return read_file(KEXEC_CRASH_LOADED, defaultonfailure='0') == '1' + + +def get_crash_kernel_size() -> int: + """Return the number of bytes reserved for the capture kernel""" + + if not is_crash_kernel_loaded(): + return 0 + + raw = read_file(KEXEC_CRASH_SIZE, defaultonfailure='0') + return int(raw) if raw.isdigit() else 0 diff --git a/python/vyos/utils/memory.py b/python/vyos/utils/memory.py new file mode 100644 index 000000000..c279168b5 --- /dev/null +++ b/python/vyos/utils/memory.py @@ -0,0 +1,28 @@ +# Copyright (C) VyOS Inc. +# +# 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 re +from vyos.utils.file import read_file + + +def get_memory_info() -> dict: + """Returns system memory information parsed from /proc/meminfo""" + data = read_file('/proc/meminfo') + + result = {} + regex = r'^(?P<key>\S+):\s+(?P<value>[0-9]+)\s+kB\s*$' + for match in re.finditer(regex, data, flags=re.MULTILINE): + result[match['key']] = int(match['value']) + + return result |
