summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2025-10-10 21:11:35 +0200
committerGitHub <noreply@github.com>2025-10-10 21:11:35 +0200
commita1be2ee22cd058d5e18e6ef4fb3ec6468a38aa37 (patch)
tree5dfecfd6d047b8dd0cfa038cffdd1ef646f0d9fb
parent7c1bbdfade7b447a4e6723ea3ba13fc1942cd0e2 (diff)
parentc5cac68ba5a135f80f971e78b97cb9b1c3a0b932 (diff)
downloadvyos-1x-a1be2ee22cd058d5e18e6ef4fb3ec6468a38aa37.tar.gz
vyos-1x-a1be2ee22cd058d5e18e6ef4fb3ec6468a38aa37.zip
Merge pull request #4772 from natali-rs1985/T7887
T7887: system_option: Add validation for memory hugepage-count
-rw-r--r--smoketest/config-tests/vpp2
-rw-r--r--smoketest/configs/vpp2
-rwxr-xr-xsmoketest/scripts/cli/test_system_option.py11
-rwxr-xr-xsmoketest/scripts/cli/test_vpp.py34
-rwxr-xr-xsrc/conf_mode/system_option.py65
5 files changed, 91 insertions, 23 deletions
diff --git a/smoketest/config-tests/vpp b/smoketest/config-tests/vpp
index e42568965..12ea24884 100644
--- a/smoketest/config-tests/vpp
+++ b/smoketest/config-tests/vpp
@@ -15,7 +15,7 @@ set system console device ttyS0 speed '115200'
set system host-name 'r16'
set system login user vyos authentication encrypted-password '$6$rounds=656000$FZBlGpWsmSrV2Rvq$YPNAPtk4k6u99FAMxR6cw4DUPCgOomwCgRZRSO5rAoJK8RlMSCkVAFVF3ozL/3mZMfxcuCnwvd5HX6f9V5KzO.'
set system name-server '203.0.113.1'
-set system option kernel memory hugepage-size 2M hugepage-count '2048'
+set system option kernel memory hugepage-size 2M hugepage-count '1800'
set system option time-format '24-hour'
set system syslog local facility all level 'info'
set system syslog local facility local7 level 'debug'
diff --git a/smoketest/configs/vpp b/smoketest/configs/vpp
index 472c2919b..7e82d04ee 100644
--- a/smoketest/configs/vpp
+++ b/smoketest/configs/vpp
@@ -45,7 +45,7 @@ system {
kernel {
memory {
hugepage-size 2M {
- hugepage-count "2048"
+ hugepage-count "1800"
}
}
}
diff --git a/smoketest/scripts/cli/test_system_option.py b/smoketest/scripts/cli/test_system_option.py
index 4fb318fd8..48935f555 100755
--- a/smoketest/scripts/cli/test_system_option.py
+++ b/smoketest/scripts/cli/test_system_option.py
@@ -105,11 +105,6 @@ class TestSystemOption(VyOSUnitTestSHIM.TestCase):
isolate_cpus = '1,2,3'
nohz_full = '2'
rcu_no_cbs = '1,2,4-5'
- default_hp_size = '2M'
- hp_size_1g = '1G'
- hp_size_2m = '2M'
- hp_count_1g = '2'
- hp_count_2m = '512'
self.cli_set(['system', 'option', 'kernel', 'cpu', 'disable-nmi-watchdog'])
self.cli_set(['system', 'option', 'kernel', 'cpu', 'isolate-cpus', isolate_cpus])
@@ -121,9 +116,6 @@ class TestSystemOption(VyOSUnitTestSHIM.TestCase):
self.cli_set(['system', 'option', 'kernel', 'disable-power-saving'])
self.cli_set(['system', 'option', 'kernel', 'disable-softlockup'])
self.cli_set(['system', 'option', 'kernel', 'memory', 'disable-numa-balancing'])
- self.cli_set(['system', 'option', 'kernel', 'memory', 'default-hugepage-size', default_hp_size])
- self.cli_set(['system', 'option', 'kernel', 'memory', 'hugepage-size', hp_size_1g, 'hugepage-count', hp_count_1g])
- self.cli_set(['system', 'option', 'kernel', 'memory', 'hugepage-size', hp_size_2m, 'hugepage-count', hp_count_2m])
self.cli_set(['system', 'option', 'kernel', 'quiet'])
self.cli_set(['system', 'option', 'kernel', 'amd-pstate-driver', amd_pstate_mode])
@@ -147,9 +139,6 @@ class TestSystemOption(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' isolcpus={isolate_cpus}', tmp)
self.assertIn(f' nohz_full={nohz_full}', tmp)
self.assertIn(f' rcu_nocbs={rcu_no_cbs}', tmp)
- self.assertIn(f' default_hugepagesz={default_hp_size}', tmp)
- self.assertIn(f' hugepagesz={hp_size_1g} hugepages={hp_count_1g}', tmp)
- self.assertIn(f' hugepagesz={hp_size_2m} hugepages={hp_count_2m}', tmp)
self.assertIn(' numa_balancing=disable', tmp)
if cpu_vendor == 'AuthenticAMD':
diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py
index 8cc2e86e7..4738db485 100755
--- a/smoketest/scripts/cli/test_vpp.py
+++ b/smoketest/scripts/cli/test_vpp.py
@@ -31,6 +31,7 @@ from vyos.utils.process import process_named_running
from vyos.utils.file import read_file
from vyos.utils.process import rc_cmd
from vyos.utils.system import sysctl_read
+from vyos.system import image
PROCESS_NAME = 'vpp_main'
VPP_CONF = '/run/vpp/vpp.conf'
@@ -1477,6 +1478,39 @@ class TestVPP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['interfaces', 'ethernet', interface, 'vif'])
self.cli_commit()
+ def test_20_kernel_options_hugepages(self):
+ default_hp_size = '2M'
+ hp_size_1g = '1G'
+ hp_size_2m = '2M'
+ hp_count_1g = '2'
+ hp_count_2m = '512'
+ memory_path = ['system', 'option', 'kernel', 'memory']
+
+ self.cli_set(memory_path + ['default-hugepage-size', default_hp_size])
+ self.cli_set(
+ memory_path + ['hugepage-size', hp_size_2m, 'hugepage-count', hp_count_2m]
+ )
+ self.cli_set(
+ memory_path + ['hugepage-size', hp_size_1g, 'hugepage-count', '2000']
+ )
+ # very big number of 1G hugepages, not enough memory for configuring them
+ # expect raise ConfigError
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(
+ memory_path + ['hugepage-size', hp_size_1g, 'hugepage-count', hp_count_1g]
+ )
+ self.cli_commit()
+
+ # Read GRUB config file for current running image
+ tmp = read_file(
+ f'{image.grub.GRUB_DIR_VYOS_VERS}/{image.get_running_image()}.cfg'
+ )
+ self.assertIn(f' default_hugepagesz={default_hp_size}', tmp)
+ self.assertIn(f' hugepagesz={hp_size_1g} hugepages={hp_count_1g}', tmp)
+ self.assertIn(f' hugepagesz={hp_size_2m} hugepages={hp_count_2m}', tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index cb3d6ce9b..a0b3dd72c 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import psutil
from sys import exit
from time import sleep
@@ -39,6 +40,8 @@ from vyos.configdep import call_dependents
from vyos import ConfigError
from vyos import airbag
+from vyos.vpp.config_resource_checks import memory as mem_check
+
airbag.enable()
curlrc_config = r'/etc/curlrc'
@@ -56,6 +59,21 @@ tuned_profiles = {
}
+def _get_total_hugepages_and_memory(config):
+ unit_map = {'M': 1 << 20, 'G': 1 << 30}
+
+ total_pages = 0
+ total_bytes = 0
+
+ hp_sizes = config.get('hugepage_size', {})
+ for size_str, hp_config in hp_sizes.items():
+ pages = int(hp_config.get('hugepage_count', 0))
+ total_pages += pages
+ total_bytes += pages * int(size_str[:-1]) * unit_map[size_str[-1]]
+
+ return total_pages, total_bytes
+
+
def get_config(config=None):
if config:
conf = config
@@ -116,6 +134,40 @@ def verify(options):
f'AMD pstate driver cannot be used with "{cpu_vendor}" CPU!'
)
+ _, hp_memory_bytes = _get_total_hugepages_and_memory(
+ options['kernel'].get('memory', {})
+ )
+ if hp_memory_bytes:
+ memory = psutil.virtual_memory()
+ memory_total_bytes = memory.total
+
+ # Exclude hugepage usage from system "used" memory
+ hp_memory_used = sum(
+ p['memory'] for p in mem_check.get_hugepages_info().values()
+ )
+ memory_used_bytes = memory.used - hp_memory_used
+
+ # TODO: need to calculate how much memory is consumed for other services, tmpfs etc.
+ # for now we should leave at least 4 GB for system usage and other processes
+ min_system_reserved_gd = 4
+ memory_margin_gb = 1
+ reserved_bytes = max(
+ min_system_reserved_gd * 1024**3,
+ memory_used_bytes + memory_margin_gb * 1024**3,
+ )
+
+ available_for_hp_bytes = memory_total_bytes - reserved_bytes
+ if available_for_hp_bytes < hp_memory_bytes:
+ # For the error message, convert to GB and round to 1 decimal
+ hp_memory_gb = round(hp_memory_bytes / 1024**3, 1)
+ available_for_hp_gb = max(0, round(available_for_hp_bytes / 1024**3, 1))
+ reserved_gb = round(reserved_bytes / 1024**3, 1)
+ raise ConfigError(
+ f'Configured hugepages require {hp_memory_gb} GB of memory, but only '
+ f'{available_for_hp_gb:.1f} GB is available '
+ f'({reserved_gb} GB is reserved for system usage and services)'
+ )
+
return None
@@ -269,16 +321,9 @@ def apply(options):
write_file(kernel_dynamic_debug, f'module {module} -p')
if 'resource_limits' in options:
- unit_map = {'M': 1 << 20, 'G': 1 << 30}
-
- total_pages = 0
- total_bytes = 0
-
- hp_sizes = options.get('kernel', {}).get('memory', {}).get('hugepage_size', {})
- for size_str, hp_config in hp_sizes.items():
- pages = int(hp_config.get('hugepage_count', 0))
- total_pages += pages
- total_bytes += pages * int(size_str[:-1]) * unit_map[size_str[-1]]
+ total_pages, total_bytes = _get_total_hugepages_and_memory(
+ options.get('kernel', {}).get('memory', {})
+ )
# Minimum recommended system values
max_map_count_min = 65530 # ensures large workload compatibility