|SUCCESS| [v3,10/10] power: add lcore ID check for PMD mgmt
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Fri May 22 12:33:19 CEST 2026
Test-Label: ai-code-review
Test-Status: SUCCESS
https://dpdk.org/patch/164258
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-05-22
git sha: 20260522041110.2023062-2-lihuisong at huawei.com (patch 01/10)
git sha: 20260522041110.2023062-3-lihuisong at huawei.com (patch 02/10)
git sha: 20260522041110.2023062-4-lihuisong at huawei.com (patch 03/10)
git sha: 20260522041110.2023062-5-lihuisong at huawei.com (patch 04/10)
git sha: 20260522041110.2023062-6-lihuisong at huawei.com (patch 05/10)
git sha: 20260522041110.2023062-7-lihuisong at huawei.com (patch 06/10)
git sha: 20260522041110.2023062-8-lihuisong at huawei.com (patch 07/10)
git sha: 20260522041110.2023062-9-lihuisong at huawei.com (patch 08/10)
git sha: 20260522041110.2023062-10-lihuisong at huawei.com (patch 09/10)
git sha: 20260522041110.2023062-11-lihuisong at huawei.com (patch 10/10)
Author: Huisong Li <lihuisong at huawei.com>
This patch series adds a new helper function to check if an lcore is
EAL-managed (ROLE_RTE or ROLE_SERVICE), then uses it to standardize
lcore validation across power management libraries.
> --- a/lib/eal/common/eal_common_lcore.c
> +++ b/lib/eal/common/eal_common_lcore.c
> @@ -102,6 +102,17 @@ int rte_lcore_is_enabled(unsigned int lcore_id)
> return cfg->lcore_role[lcore_id] == ROLE_RTE;
> }
>
> +RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_lcore_is_eal_managed, 26.07)
> +int rte_lcore_is_eal_managed(unsigned int lcore_id)
> +{
> + struct rte_config *cfg = rte_eal_get_configuration();
> +
> + if (lcore_id >= RTE_MAX_LCORE)
> + return 0;
> + return cfg->lcore_role[lcore_id] == ROLE_RTE ||
> + cfg->lcore_role[lcore_id] == ROLE_SERVICE;
> +}
In the new function rte_lcore_is_eal_managed(), can both conditions in
the return statement be tested using a single array access? Currently,
cfg->lcore_role[lcore_id] is read twice. Would
"(cfg->lcore_role[lcore_id] & (ROLE_RTE | ROLE_SERVICE))" be equivalent
and avoid redundant array lookups, or does the enum definition prevent
this?
[ ... ]
> --- a/lib/power/power_common.h
> +++ b/lib/power/power_common.h
> @@ -23,6 +23,13 @@ extern int rte_power_logtype;
> #define POWER_DEBUG_LOG(...)
> #endif
>
> +#define RTE_POWER_VALID_LCOREID_OR_ERR_RET(lcore_id, retval) do { \
> + if (!rte_lcore_is_eal_managed(lcore_id)) { \
> + POWER_LOG(ERR, "lcore id %u is invalid", lcore_id); \
> + return retval; \
> + } \
> +} while (0)
In RTE_POWER_VALID_LCOREID_OR_ERR_RET, does wrapping the conditional and
return inside a do-while(0) block follow DPDK conventions? The pattern
is common, but can the "do {} while (0)" be omitted if the macro body is
only used where a statement is expected?
[ ... ]
> --- a/lib/power/rte_power_cpufreq.c
> +++ b/lib/power/rte_power_cpufreq.c
> @@ -116,6 +116,7 @@ rte_power_init(unsigned int lcore_id)
> struct rte_power_cpufreq_ops *ops;
> uint8_t env;
>
> + RTE_POWER_VALID_LCOREID_OR_ERR_RET(lcore_id, -1);
> if (global_default_env != PM_ENV_NOT_SET)
> return global_cpufreq_ops->init(lcore_id);
After validating lcore_id with RTE_POWER_VALID_LCOREID_OR_ERR_RET in
rte_power_init(), does the subsequent call chain
global_cpufreq_ops->init(lcore_id) assume lcore_id is validated, or do
driver-specific init functions also perform redundant checks? Some
driver init functions in this series remove lcore checks. Does this
create an inconsistency if global_cpufreq_ops is NULL or points to an
unexpected ops table?
[ ... ]
> @@ -161,6 +163,7 @@ uint32_t
> rte_power_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t n)
> {
> RTE_ASSERT(global_cpufreq_ops != NULL);
> + RTE_POWER_VALID_LCOREID_OR_ERR_RET(lcore_id, 0);
> return global_cpufreq_ops->get_avail_freqs(lcore_id, freqs, n);
> }
In rte_power_freqs(), does adding the lcore_id validation after
RTE_ASSERT(global_cpufreq_ops != NULL) create a situation where the
assert fires before the lcore validation in debug builds? If so, does
this produce less helpful diagnostics?
[ ... ]
> --- a/drivers/power/acpi/acpi_cpufreq.c
> +++ b/drivers/power/acpi/acpi_cpufreq.c
> @@ -242,12 +242,6 @@ power_acpi_cpufreq_init(unsigned int lcore_id)
> return -1;
> }
>
> - if (lcore_id >= RTE_MAX_LCORE) {
> - POWER_LOG(ERR, "Lcore id %u can not exceeds %u",
> - lcore_id, RTE_MAX_LCORE - 1U);
> - return -1;
> - }
> -
> pi = &lcore_power_info[lcore_id];
In power_acpi_cpufreq_init(), after removing the lcore_id >=
RTE_MAX_LCORE check, does the line "pi = &lcore_power_info[lcore_id]"
rely entirely on the framework-level validation via
RTE_POWER_VALID_LCOREID_OR_ERR_RET? If the framework check is somehow
bypassed or not present, does this indexing overflow lcore_power_info?
[ ... ]
> @@ -373,11 +362,6 @@ power_acpi_cpufreq_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t num)
> {
> struct acpi_power_info *pi;
>
> - if (lcore_id >= RTE_MAX_LCORE) {
> - POWER_LOG(ERR, "Invalid lcore ID");
> - return 0;
> - }
> -
> if (freqs == NULL) {
> POWER_LOG(ERR, "NULL buffer supplied");
> return 0;
In power_acpi_cpufreq_freqs(), does removing the lcore_id check and
relying on the framework mean that if freqs is NULL, the function logs
an error and returns 0, but if lcore_id was invalid, the framework
already returned -1? Does this create inconsistent return values for
different error paths?
[ ... ]
> --- a/drivers/power/kvm_vm/guest_channel.c
> +++ b/drivers/power/kvm_vm/guest_channel.c
> @@ -61,11 +61,6 @@ guest_channel_host_connect(const char *path, unsigned int lcore_id)
> char fd_path[PATH_MAX];
> int fd = -1;
>
> - if (lcore_id >= RTE_MAX_LCORE) {
> - GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
> - lcore_id, RTE_MAX_LCORE-1);
> - return -1;
> - }
> /* check if path is already open */
> if (global_fds[lcore_id] != -1) {
In guest_channel_host_connect(), after removing the lcore_id >=
RTE_MAX_LCORE check, does accessing global_fds[lcore_id] assume that
all callers have already validated lcore_id? If guest_channel module
functions are called directly instead of through the power framework,
does this create a bounds-checking gap?
[ ... ]
> @@ -127,12 +122,6 @@ guest_channel_send_msg(struct rte_power_channel_packet *pkt,
> int ret, buffer_len = sizeof(*pkt);
> void *buffer = pkt;
>
> - if (lcore_id >= RTE_MAX_LCORE) {
> - GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
> - lcore_id, RTE_MAX_LCORE-1);
> - return -1;
> - }
> -
> if (global_fds[lcore_id] < 0) {
> GUEST_CHANNEL_LOG(ERR, "Channel is not connected");
> return -1;
In guest_channel_send_msg(), does the check "if (global_fds[lcore_id] <
0)" potentially overflow global_fds if lcore_id is invalid and no prior
validation occurred?
[ ... ]
> --- a/lib/power/rte_power_qos.c
> +++ b/lib/power/rte_power_qos.c
> @@ -27,10 +27,7 @@ rte_power_qos_set_cpu_resume_latency(uint16_t lcore_id, int latency)
> FILE *f;
> int ret;
>
> - if (!rte_lcore_is_enabled(lcore_id)) {
> - POWER_LOG(ERR, "lcore id %u is not enabled", lcore_id);
> - return -EINVAL;
> - }
> + RTE_POWER_VALID_LCOREID_OR_ERR_RET(lcore_id, -EINVAL);
In rte_power_qos_set_cpu_resume_latency(), does changing from
rte_lcore_is_enabled() to RTE_POWER_VALID_LCOREID_OR_ERR_RET (which uses
rte_lcore_is_eal_managed) alter the semantics such that service cores
are now accepted? The commit message says this is intentional, but does
the new macro return -EINVAL or -1 on error, and does this match what
the function previously returned?
[ ... ]
> --- a/lib/power/rte_power_pmd_mgmt.c
> +++ b/lib/power/rte_power_pmd_mgmt.c
> @@ -511,7 +511,8 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id, uint16_t port_id,
>
> RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
>
> - if (queue_id >= RTE_MAX_QUEUES_PER_PORT || lcore_id >= RTE_MAX_LCORE) {
> + if (queue_id >= RTE_MAX_QUEUES_PER_PORT ||
> + !rte_lcore_is_enabled(lcore_id)) {
In rte_power_ethdev_pmgmt_queue_enable(), does changing the lcore_id
check from "lcore_id >= RTE_MAX_LCORE" to "!rte_lcore_is_enabled(lcore_id)"
mean that service cores are now rejected? The commit message says
pmd_mgmt is used with data plane threads (ROLE_RTE only), but does this
create a behavior change if applications previously passed service core
IDs that happened to be < RTE_MAX_LCORE?
[ ... ]
> @@ -729,8 +730,8 @@ RTE_EXPORT_SYMBOL(rte_power_pmd_mgmt_set_scaling_freq_min)
> int
> rte_power_pmd_mgmt_set_scaling_freq_min(unsigned int lcore, unsigned int min)
> {
> - if (lcore >= RTE_MAX_LCORE) {
> - POWER_LOG(ERR, "Invalid lcore ID: %u", lcore);
> + if (!rte_lcore_is_enabled(lcore)) {
> + POWER_LOG(ERR, "lcore id %u is not enabled", lcore);
In rte_power_pmd_mgmt_set_scaling_freq_min(), does the error message
change from "Invalid lcore ID" to "lcore id %u is not enabled" accurately
reflect the new check? If an lcore ID is >= RTE_MAX_LCORE, is it more
accurate to say "not enabled" or "out of range"?
More information about the test-report
mailing list