diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2025-10-03 12:53:32 +0300 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2025-10-06 13:28:07 +0300 |
| commit | c5cac68ba5a135f80f971e78b97cb9b1c3a0b932 (patch) | |
| tree | 6a1a10a53abd839c03b4454052e5e8ab3889f61a | |
| parent | 5248f1cebd4ac9cd8bebb62aa08ecc042a082f30 (diff) | |
| download | vyos-1x-c5cac68ba5a135f80f971e78b97cb9b1c3a0b932.tar.gz vyos-1x-c5cac68ba5a135f80f971e78b97cb9b1c3a0b932.zip | |
T7887: system_option: Add validation for memory hugepage-count
Move smoke test for hugepages to test_vpp.py
| -rw-r--r-- | smoketest/config-tests/vpp | 2 | ||||
| -rw-r--r-- | smoketest/configs/vpp | 2 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_system_option.py | 11 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_vpp.py | 34 | ||||
| -rwxr-xr-x | src/conf_mode/system_option.py | 65 |
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 69f053a7f..1296fcf26 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 eb14fb2df..c6a67beb7 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' @@ -1478,6 +1479,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) 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 |
