summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorNataliia Solomko <natalirs1985@gmail.com>2026-02-16 16:53:29 +0200
committerNataliia Solomko <natalirs1985@gmail.com>2026-02-17 11:33:56 +0200
commit2414c156cc21bfe51b65f8726f186c55b533bb97 (patch)
tree815f9d77ce7ade89371695252aeb1d7af5580890 /python
parent82461ce7856aaf91d1b8a85ca45080e26783fc5e (diff)
downloadvyos-1x-2414c156cc21bfe51b65f8726f186c55b533bb97.tar.gz
vyos-1x-2414c156cc21bfe51b65f8726f186c55b533bb97.zip
vpp: T8268: Unify CPU settings into a single 'cpu-cores' node under 'resource-allocation'
Replace legacy VPP CPU settings (main-core, skip-cores, workers, corelist-workers) with a single resource-allocation cpu-cores option. CPU assignment is now handled automatically: two cores are reserved for the system, the VPP main thread is placed on the first available core, and the remaining allocated cores are used as workers. This simplifies configuration and ensures consistent CPU allocation.
Diffstat (limited to 'python')
-rw-r--r--python/vyos/vpp/config_resource_checks/cpu.py76
-rw-r--r--python/vyos/vpp/config_resource_checks/memory.py11
-rw-r--r--python/vyos/vpp/config_verify.py116
3 files changed, 22 insertions, 181 deletions
diff --git a/python/vyos/vpp/config_resource_checks/cpu.py b/python/vyos/vpp/config_resource_checks/cpu.py
deleted file mode 100644
index b319608e4..000000000
--- a/python/vyos/vpp/config_resource_checks/cpu.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Used for validating estimated CPU/physical cores use
-#
-# 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 as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# 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, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-from vyos.utils.cpu import get_available_cpus, get_core_count
-
-from vyos.vpp.config_resource_checks.resource_defaults import default_resource_map
-
-
-# Get default value for reserved cpu cores
-reserved_cpus = default_resource_map.get('reserved_cpu_cores')
-
-
-def available_cores_count(cpu_settings: dict) -> int:
- core_count = get_core_count()
-
- if cpu_settings.get('main_core'):
- core_count -= 1
-
- skip_cores = int(cpu_settings.get('skip_cores', 0))
- # The default settings assume that
- # at least 2 CPU cores should remain reserved for system use
- # (only in case of current runtime is not smoke test)
- if skip_cores < reserved_cpus:
- core_count -= reserved_cpus
- else:
- core_count -= skip_cores
-
- return core_count
-
-
-def available_cores_list(skip_cores: int) -> list:
- # Available cores are all CPU cores without first N skipped cores that will not be used
- # Get all available physical cores - use set to filter out unique values
- cpu_cores = set(map(lambda el: el['cpu'], get_available_cpus()))
- cpu_cores = list(cpu_cores)
-
- return cpu_cores[skip_cores:]
-
-
-def worker_cores_list(iface: str, worker_ranges: list) -> list:
- all_core_numbers = []
- for worker_range in worker_ranges:
- core_numbers = worker_range.split('-')
-
- if int(core_numbers[0]) > int(core_numbers[-1]):
- raise ValueError(
- f'Range for "{iface} workers {worker_range}" is not correct'
- )
-
- all_core_numbers.extend(range(int(core_numbers[0]), int(core_numbers[-1]) + 1))
-
- # Check for duplicates
- duplicates = set(
- [str(x) for n, x in enumerate(all_core_numbers) if x in all_core_numbers[:n]]
- )
- if duplicates:
- raise ValueError(
- f'Some workers in "{iface} workers" are duplicated: #{",".join(list(duplicates))}'
- )
-
- return all_core_numbers
diff --git a/python/vyos/vpp/config_resource_checks/memory.py b/python/vyos/vpp/config_resource_checks/memory.py
index 03fe097e9..f1ae6f7bc 100644
--- a/python/vyos/vpp/config_resource_checks/memory.py
+++ b/python/vyos/vpp/config_resource_checks/memory.py
@@ -174,10 +174,11 @@ def total_memory_required(settings: dict) -> dict:
return memory
-def buffers_required(settings: dict, workers) -> int:
+def buffers_required(settings: dict) -> int:
"""
Calculate total VPP buffer requirements based on interface settings and workers.
"""
+ workers = int(settings['resource_allocation']['cpu_cores'])
buffers_total = 0
for ifname, iface_config in settings.get('interface', {}).items():
# Do not include XDP interfaces in buffer calculations.
@@ -185,14 +186,14 @@ def buffers_required(settings: dict, workers) -> int:
# so buffer requirements cannot be derived from descriptors here.
# Buffers for XDP are handled internally by the kernel/XDP layer,
# not by VPP’s buffer allocator.
- if iface_config.get('driver') == 'xdp':
- continue
+ # if iface_config.get('driver') == 'xdp':
+ # continue
+
dpdk_options = iface_config.get('dpdk_options', {})
rx_queues = int(dpdk_options.get('num_rx_queues', 1))
rx_desc = int(dpdk_options.get('num_rx_desc'))
# default TX queues is equal to number of worker threads
- # plus 1 main thread
- tx_queues = int(dpdk_options.get('num_tx_queues', workers + 1))
+ tx_queues = int(dpdk_options.get('num_tx_queues', workers))
tx_desc = int(dpdk_options.get('num_tx_desc'))
# buffers for RX/TX queues for interface
diff --git a/python/vyos/vpp/config_verify.py b/python/vyos/vpp/config_verify.py
index bcc10257f..f8bfb214a 100644
--- a/python/vyos/vpp/config_verify.py
+++ b/python/vyos/vpp/config_verify.py
@@ -22,7 +22,7 @@ from vyos import ConfigError
from vyos.base import Warning
from vyos.utils.cpu import get_core_count as total_core_count, get_cpus
-from vyos.vpp.config_resource_checks import cpu as cpu_checks, memory as mem_checks
+from vyos.vpp.config_resource_checks import memory as mem_checks
from vyos.vpp.config_resource_checks.resource_defaults import default_resource_map
from vyos.vpp.utils import human_memory_to_bytes, bytes_to_human_memory
@@ -183,17 +183,13 @@ def verify_dev_driver(driver_type: str, driver: str) -> bool:
return False
-def create_cpu_error_message(
- cpus_required: int, cpus_available: int = None, skip_cores: int = 0
-) -> str:
+def create_cpu_error_message(cpus_required: int, cpus_available: int = None) -> str:
cpu_info = get_cpus()
logical_cores = sum(
[int(s.get('siblings')) if 'siblings' in s else 1 for s in cpu_info]
)
reserved_cpus = default_resource_map.get('reserved_cpu_cores')
- if skip_cores > reserved_cpus:
- reserved_cpus = skip_cores
available_str = (
(
@@ -320,100 +316,19 @@ def verify_vpp_memory(config: dict):
)
-def verify_vpp_settings_cpu_skip_cores(skip_cores: int):
- cpu_cores = total_core_count()
-
- # The number of skipped cores must not be greater than
- # available CPU cores in the system - 1 for main thread
- if skip_cores > (cpu_cores - 1):
- raise ConfigError(
- f'The system does not have enough available CPUs to skip '
- f'(reduce "cpu skip-cores" to {cpu_cores} or less)'
- )
-
-
-def verify_vpp_settings_cpu(settings: dict):
- """
- Verify 'cpu main-core' is set if worker-related settings are used.
- `set vpp settings cpu workers` and `set vpp settings cpu corelist-workers`
- are mutually exclusive!
- """
- worker_related = ('corelist_workers', 'workers', 'skip_cores')
-
- if any(key in settings for key in worker_related) and 'main_core' not in settings:
- raise ConfigError('"cpu main-core" is required but not set!')
-
- if 'corelist_workers' in settings and 'workers' in settings:
- raise ConfigError(
- '"cpu corelist-workers" and "cpu workers" cannot be used at the same time!'
- )
-
-
-def verify_vpp_cpu_main_core(cpu_settings: dict) -> None:
- """Check that the main core is available"""
- skip_cores = int(cpu_settings.get('skip_cores', 0))
- available_cores = cpu_checks.available_cores_list(skip_cores)
- main_core = int(cpu_settings['main_core'])
-
- if main_core not in available_cores:
- raise ConfigError(
- 'Cannot set main core for VPP process: '
- f'CPU#{main_core} is not available.'
- )
-
-
-def verify_vpp_settings_cpu_workers(cpu_settings: dict):
+def verify_vpp_cpu_cores(cpu_cores: int):
"""
Verify that the system has enough available CPU cores
to run a given amount of worker processes (1 worker/core)
"""
- workers = int(cpu_settings.get('workers', 0))
- available_cores = cpu_checks.available_cores_count(cpu_settings)
-
- if workers > available_cores:
- raise ConfigError(
- f'Not enough free physical CPU cores for {workers} VPP workers '.ljust(72)
- + create_cpu_error_message(
- workers, available_cores, cpu_settings.get('skip_cores', 0)
- )
- )
-
-
-def verify_vpp_settings_cpu_corelist_workers(cpu_settings: dict):
- """
- Verify that the CPU cores provided to the config are free and can be used by VPP
- """
- workers = cpu_settings.get('corelist_workers')
- main_core = int(cpu_settings.get('main_core'))
- skip_cores = int(cpu_settings.get('skip_cores', 0))
- available_cores = cpu_checks.available_cores_list(skip_cores)
- try:
- all_core_nums = cpu_checks.worker_cores_list(
- iface='cpu corelist', worker_ranges=workers
- )
- except ValueError as e:
- raise ConfigError(str(e))
-
- error_msg = 'Cannot set VPP "cpu corelist-workers": '.ljust(72)
-
- if main_core in all_core_nums:
- raise ConfigError(
- f'CPU#{main_core} is set as main core and should not '
- 'be included to the corelist-workers'
- )
-
- invalid_cores = [str(el) for el in all_core_nums if el not in available_cores]
- if invalid_cores:
- raise ConfigError(error_msg + f'CPU# {",".join(invalid_cores)} not available.')
+ total_cores = total_core_count()
+ reserved_cpus = default_resource_map.get('reserved_cpu_cores')
+ available_cores = total_cores - reserved_cpus
- available_cores_count = cpu_checks.available_cores_count(cpu_settings)
- if len(all_core_nums) > available_cores_count:
+ if cpu_cores > available_cores:
raise ConfigError(
- error_msg
- + 'Not enough free physical CPUs in the system.'.ljust(72)
- + create_cpu_error_message(
- len(all_core_nums), available_cores_count, skip_cores
- )
+ f'Not enough free physical CPU cores for {cpu_cores} "cpu-cores" '.ljust(72)
+ + create_cpu_error_message(cpu_cores, available_cores)
)
@@ -441,12 +356,12 @@ def verify_vpp_interfaces_dpdk_num_queues(qtype: str, num_queues: int, workers:
if num_queues > workers:
raise ConfigError(
- f'The number of {qtype} queues cannot be greater than the number of configured VPP workers: '
- f'workers: {workers}, queues: {num_queues}'
+ f'The number of {qtype} queues cannot be greater than the number of configured VPP "cpu-cores": '
+ f'cpu-cores: {workers}, queues: {num_queues}'
)
-def verify_routes_count(settings: dict, workers: int):
+def verify_routes_count(settings: dict):
"""
Maximum routes count depending on main heap size,
statistics segment size and workers
@@ -454,12 +369,13 @@ def verify_routes_count(settings: dict, workers: int):
counters = 2 # 2 counters for each route
bytes = 16 # each counter consumes 16 bytes
statseg_scale = 2
+ cpu_cores = int(settings['resource_allocation']['cpu_cores'])
statseg_size = settings['statseg']['size']
statseg_size_in_bytes = human_memory_to_bytes(statseg_size)
main_heap = settings['memory']['main_heap_size']
main_heap_in_gb = human_memory_to_bytes(main_heap) >> 30
- formula = (workers + 1) * counters * bytes * statseg_scale
+ formula = cpu_cores * counters * bytes * statseg_scale
routes_count_statseg = statseg_size_in_bytes / formula
routes_count_statseg = round(routes_count_statseg / 1_000_000, 2)
routes_count_mh = main_heap_in_gb * 2
@@ -472,10 +388,10 @@ def verify_routes_count(settings: dict, workers: int):
)
-def verify_vpp_buffers(settings: dict, workers: int):
+def verify_vpp_buffers(settings: dict):
buffers_configured = int(settings['buffers']['buffers_per_numa'])
- buffers_required = mem_checks.buffers_required(settings, workers)
+ buffers_required = mem_checks.buffers_required(settings)
if buffers_required > buffers_configured:
raise ConfigError(