summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/vyos/defaults.py8
-rw-r--r--python/vyos/system/image.py17
-rw-r--r--python/vyos/utils/boot.py1
-rw-r--r--python/vyos/utils/kernel.py77
-rw-r--r--python/vyos/utils/memory.py28
5 files changed, 121 insertions, 10 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/system/image.py b/python/vyos/system/image.py
index ed8a96fbb..02f2303b2 100644
--- a/python/vyos/system/image.py
+++ b/python/vyos/system/image.py
@@ -22,6 +22,7 @@ from json import loads
from vyos.defaults import directories
from vyos.system import disk, grub
+from vyos.utils.kernel import get_kernel_boot_arg
# Define variables
GRUB_DIR_MAIN: str = '/boot/grub'
@@ -29,8 +30,12 @@ GRUB_DIR_VYOS: str = f'{GRUB_DIR_MAIN}/grub.cfg.d'
CFG_VYOS_VARS: str = f'{GRUB_DIR_VYOS}/20-vyos-defaults-autoload.cfg'
GRUB_DIR_VYOS_VERS: str = f'{GRUB_DIR_VYOS}/vyos-versions'
# prepare regexes
-REGEX_KERNEL_CMDLINE: str = r'^BOOT_IMAGE=/(?P<boot_type>boot|live)/((?P<image_version>.+)/)?vmlinuz.*$'
-REGEX_SYSTEM_CFG_VER: str = r'(\r\n|\r|\n)SYSTEM_CFG_VER\s*=\s*(?P<cfg_ver>\d+)(\r\n|\r|\n)'
+REGEX_KERNEL_CMDLINE: str = (
+ r'^/(?P<boot_type>boot|live)/((?P<image_version>.+)/)?vmlinuz.*$'
+)
+REGEX_SYSTEM_CFG_VER: str = (
+ r'(\r\n|\r|\n)SYSTEM_CFG_VER\s*=\s*(?P<cfg_ver>\d+)(\r\n|\r|\n)'
+)
# structures definitions
@@ -197,8 +202,8 @@ def get_running_image() -> str:
"""
running_image: str = ''
regex_filter = re_compile(REGEX_KERNEL_CMDLINE)
- cmdline: str = Path('/proc/cmdline').read_text()
- running_image_result = regex_filter.match(cmdline)
+ cmdline_arg: str = get_kernel_boot_arg('BOOT_IMAGE') or ''
+ running_image_result = regex_filter.match(cmdline_arg)
if running_image_result:
running_image: str = running_image_result.groupdict().get(
'image_version', '')
@@ -259,8 +264,8 @@ def is_live_boot() -> bool:
bool: True if the system currently booted in live mode
"""
regex_filter = re_compile(REGEX_KERNEL_CMDLINE)
- cmdline: str = Path('/proc/cmdline').read_text()
- running_image_result = regex_filter.match(cmdline)
+ cmdline_arg: str = get_kernel_boot_arg('BOOT_IMAGE') or ''
+ running_image_result = regex_filter.match(cmdline_arg)
if running_image_result:
boot_type: str = running_image_result.groupdict().get('boot_type', '')
if boot_type == 'boot':
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..72c7413cf 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.
@@ -157,14 +165,13 @@ def get_kernel_serial_console() -> Tuple[Optional[str], Optional[str], Optional[
command line which was used during system boot.
"""
import re
- from vyos.utils.file import read_file
cmdline_console_re = re.compile(
- r'(?:^|\s)console=(?P<console_type>tty(?:S|AMA))(?P<console_num>\d+),(?P<console_speed>\d+)(?=\s|$)'
+ r'(?P<console_type>tty(?:S|AMA))(?P<console_num>\d+),(?P<console_speed>\d+)'
)
- kernel_cmdline = read_file('/proc/cmdline')
- if m := cmdline_console_re.search(kernel_cmdline):
+ console_value = get_kernel_boot_arg('console') or ''
+ if m := cmdline_console_re.search(console_value):
return (
m.group('console_type'),
m.group('console_num'),
@@ -172,3 +179,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