On Fri, 21 Aug 2026 11:26:43 +0530
Gagandeep Singh <[email protected]> wrote:

> @@ -71,7 +72,46 @@ parse_txq_prior(const char *key __rte_unused, const char 
> *value, void *opaque)
>  
>       str = strtok(input_str, "|");
>       while (str != NULL && i < hw->max_tx_queues) {
> -             hw->txq_prior[i++] = (uint32_t)atoi(str);
> +             hw->txq_prior[i++] = atoi(str) & ENETC_TBMR_PRIO_MASK;
> +             str = strtok(NULL, "|");
> +     }
> +
> +     free(input_str);
> +     return 0;
> +}

The arg parsing in this driver has lots of usage of functions that are on
the naughty list like: atoi, atof, and strtok.

Suggest reworking this to use strtok_r and strtoul and strtod.

Not a fan of so many nerd knobs either. These kind of queue configurations 
really
need to be under ethdev but that is more work.

Something like this?

diff --git a/drivers/net/enetc/enetc4_ethdev.c 
b/drivers/net/enetc/enetc4_ethdev.c
index bb579a0b90..3e13542302 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -2,7 +2,9 @@
  * Copyright 2024-2026 NXP
  */
 
+#include <errno.h>
 #include <stdbool.h>
+#include <stdlib.h>
 #include <rte_kvargs.h>
 #include <rte_random.h>
 #include <dpaax_iova_table.h>
@@ -49,85 +51,172 @@ static uint64_t dev_tx_offloads_sup =
 
 #define ENETC4_NC_MEMORY       "nc"
 
+/* Tx ring WRR weight range; ENETC_TBMR_WRR() encodes it as (weight - 1). */
+#define ENETC4_TXQ_WRR_MIN     1
+#define ENETC4_TXQ_WRR_MAX     8
+
+static const char * const enetc4_valid_args[] = {
+       ENETC4_TXQ_PRIORITIES,
+       ENETC4_TXQ_WRR,
+       ENETC4_NC_MEMORY,
+       NULL,
+};
+
+/*
+ * Parse one unsigned decimal value, rejecting empty strings, signs, trailing
+ * garbage and values outside [min, max]. atoi() reports none of these: it
+ * returns 0 for any non-numeric string and is undefined on overflow.
+ */
 static int
-parse_txq_prior(const char *key __rte_unused, const char *value, void *opaque)
+enetc4_parse_uint(const char *str, uint32_t min, uint32_t max, uint32_t *val)
 {
-       struct rte_eth_dev *dev = (struct rte_eth_dev *)opaque;
-       struct enetc_eth_hw *hw =
-                               ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       char *input_str;
-       char *str;
-       uint32_t i = 0;
+       unsigned long res;
+       char *endptr;
+
+       if (str == NULL || *str == '\0')
+               return -EINVAL;
+
+       /* strtoul() silently wraps a leading '-', so reject signs up front. */
+       if (*str == '-' || *str == '+')
+               return -EINVAL;
+
+       errno = 0;
+       res = strtoul(str, &endptr, 10);
+       if (errno != 0 || endptr == str || *endptr != '\0')
+               return -EINVAL;
+
+       if (res < min || res > max)
+               return -ERANGE;
+
+       *val = (uint32_t)res;
+       return 0;
+}
+
+/*
+ * Parse a "v0|v1|..." list into vals[], validating every field against
+ * [min, max]. Returns the number of values parsed, or a negative errno.
+ */
+static int
+enetc4_parse_uint_list(const char *key, const char *value, uint32_t min,
+                      uint32_t max, uint32_t *vals, uint32_t max_vals)
+{
+       char *input_str, *str, *saveptr;
+       uint32_t n = 0;
+       int ret;
+
+       if (value == NULL) {
+               ENETC_PMD_ERR("%s: missing value", key);
+               return -EINVAL;
+       }
 
        input_str = strdup(value);
-       if (!input_str)
+       if (input_str == NULL)
                return -ENOMEM;
 
-       rte_free(hw->txq_prior);
-       hw->txq_prior = rte_zmalloc(NULL, hw->max_tx_queues * sizeof(uint32_t), 
0);
-       if (!hw->txq_prior) {
-               free(input_str);
-               return -ENOMEM;
+       for (str = strtok_r(input_str, "|", &saveptr); str != NULL;
+            str = strtok_r(NULL, "|", &saveptr)) {
+               if (n == max_vals) {
+                       ENETC_PMD_ERR("%s: too many values, at most %u 
supported",
+                                     key, max_vals);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = enetc4_parse_uint(str, min, max, &vals[n]);
+               if (ret != 0) {
+                       ENETC_PMD_ERR("%s: invalid value '%s' at index %u, 
expected %u..%u",
+                                     key, str, n, min, max);
+                       goto out;
+               }
+               n++;
        }
 
-       str = strtok(input_str, "|");
-       while (str != NULL && i < hw->max_tx_queues) {
-               hw->txq_prior[i++] = atoi(str) & ENETC_TBMR_PRIO_MASK;
-               str = strtok(NULL, "|");
+       if (n == 0) {
+               ENETC_PMD_ERR("%s: empty value list", key);
+               ret = -EINVAL;
+               goto out;
        }
 
+       ret = n;
+out:
        free(input_str);
+       return ret;
+}
+
+/* Parse enetc4_txq_prior="p0|p1|..." devarg; priority 0..7 per ring. */
+static int
+parse_txq_prior(const char *key, const char *value, void *opaque)
+{
+       struct rte_eth_dev *dev = opaque;
+       struct enetc_eth_hw *hw =
+                               ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t *prior;
+       int ret;
+
+       prior = rte_zmalloc(NULL, hw->max_tx_queues * sizeof(uint32_t), 0);
+       if (prior == NULL)
+               return -ENOMEM;
+
+       ret = enetc4_parse_uint_list(key, value, 0, ENETC_TBMR_PRIO_MASK,
+                                    prior, hw->max_tx_queues);
+       if (ret < 0) {
+               rte_free(prior);
+               return ret;
+       }
+
+       /* Only swap in the new table once the whole list is known good. */
+       rte_free(hw->txq_prior);
+       hw->txq_prior = prior;
+
        return 0;
 }
 
 /* Parse enetc4_txq_wrr="w0|w1|..." devarg; weight 1..8 per ring. */
-static int parse_txq_wrr(const char *key __rte_unused, const char *value,
-                         void *opaque)
+static int
+parse_txq_wrr(const char *key, const char *value, void *opaque)
 {
-       struct rte_eth_dev *dev = (struct rte_eth_dev *)opaque;
+       struct rte_eth_dev *dev = opaque;
        struct enetc_eth_hw *hw =
                        ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       char *input_str;
-       char *str;
-       uint32_t i = 0;
-       int w;
+       uint32_t *wrr;
+       int n, i;
 
-       input_str = strdup(value);
-       if (!input_str)
+       wrr = rte_zmalloc(NULL, hw->max_tx_queues * sizeof(uint32_t), 0);
+       if (wrr == NULL)
                return -ENOMEM;
 
-       rte_free(hw->txq_wrr);
-       hw->txq_wrr = rte_zmalloc(NULL,
-                       hw->max_tx_queues * sizeof(uint32_t), 0);
-       if (!hw->txq_wrr) {
-               free(input_str);
-               return -ENOMEM;
+       n = enetc4_parse_uint_list(key, value, ENETC4_TXQ_WRR_MIN,
+                                  ENETC4_TXQ_WRR_MAX, wrr, hw->max_tx_queues);
+       if (n < 0) {
+               rte_free(wrr);
+               return n;
        }
 
-       str = strtok(input_str, "|");
-       while (str != NULL && i < hw->max_tx_queues) {
-               w = atoi(str);
-               if (w < 1)
-                       w = 1;
-               if (w > 8)
-                       w = 8;
-               hw->txq_wrr[i++] = ENETC_TBMR_WRR(w);
-               str = strtok(NULL, "|");
-       }
+       for (i = 0; i < n; i++)
+               wrr[i] = ENETC_TBMR_WRR(wrr[i]);
+
+       /* Only swap in the new table once the whole list is known good. */
+       rte_free(hw->txq_wrr);
+       hw->txq_wrr = wrr;
 
-       free(input_str);
        return 0;
 }
 
 static int
-parse_nc(const char *key __rte_unused, const char *value, void *extra_args)
+parse_nc(const char *key, const char *value, void *extra_args)
 {
        struct rte_eth_dev *dev = extra_args;
        struct enetc_eth_hw *hw =
                ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t val;
+
+       if (enetc4_parse_uint(value, 0, 1, &val) != 0) {
+               ENETC_PMD_ERR("%s: invalid value '%s', expected 0 or 1",
+                             key, value ? value : "(null)");
+               return -EINVAL;
+       }
 
-       if (value && atoi(value) == 1)
-               hw->nc_mode = 1;
+       hw->nc_mode = val;
 
        return 0;
 }
@@ -135,45 +224,41 @@ parse_nc(const char *key __rte_unused, const char *value, 
void *extra_args)
 static int
 enetc4_get_devargs(struct rte_eth_dev *dev, const char *key)
 {
+       static const struct {
+               const char *key;
+               arg_handler_t handler;
+       } handlers[] = {
+               { ENETC4_TXQ_PRIORITIES, parse_txq_prior },
+               { ENETC4_TXQ_WRR,        parse_txq_wrr   },
+               { ENETC4_NC_MEMORY,      parse_nc        },
+       };
        struct rte_devargs *devargs = dev->device->devargs;
        struct rte_kvargs *kvlist;
+       unsigned int i;
+       int ret = 0;
 
-       if (!devargs)
+       if (devargs == NULL)
                return 0;
 
-       kvlist = rte_kvargs_parse(devargs->args, NULL);
-       if (!kvlist)
-               return 0;
-
-       if (!rte_kvargs_count(kvlist, key)) {
-               rte_kvargs_free(kvlist);
-               return 0;
+       /* Passing the key list makes a mistyped devarg an error, not a no-op. 
*/
+       kvlist = rte_kvargs_parse(devargs->args, enetc4_valid_args);
+       if (kvlist == NULL) {
+               ENETC_PMD_ERR("Invalid device arguments '%s'", devargs->args);
+               return -EINVAL;
        }
 
-       if (!strcmp(key, ENETC4_TXQ_PRIORITIES)) {
-               if (rte_kvargs_process(kvlist, key,
-                                      parse_txq_prior, (void *)dev) < 0) {
-                       rte_kvargs_free(kvlist);
-                       return 0;
-               }
-       }
-       if (!strcmp(key, ENETC4_TXQ_WRR)) {
-               if (rte_kvargs_process(kvlist, key,
-                                      parse_txq_wrr, (void *)dev) < 0) {
-                       rte_kvargs_free(kvlist);
-                       return 0;
-               }
-       }
-       if (!strcmp(key, ENETC4_NC_MEMORY)) {
-               if (rte_kvargs_process(kvlist, key,
-                                      parse_nc, (void *)dev) < 0) {
-                       rte_kvargs_free(kvlist);
-                       return 0;
-               }
-       }
+       if (rte_kvargs_count(kvlist, key) == 0)
+               goto out;
 
+       for (i = 0; i < RTE_DIM(handlers); i++) {
+               if (strcmp(key, handlers[i].key) != 0)
+                       continue;
+               ret = rte_kvargs_process(kvlist, key, handlers[i].handler, dev);
+               break;
+       }
+out:
        rte_kvargs_free(kvlist);
-       return 0;
+       return ret;
 }
 
 static int
@@ -1129,9 +1214,13 @@ enetc4_dev_configure(struct rte_eth_dev *dev)
                enetc4_txbdr_wr(enetc_hw, i, ENETC_TBMR, ENETC_BMR_RESET);
 
        hw->nc_mode = 0;
-       enetc4_get_devargs(dev, ENETC4_TXQ_PRIORITIES);
-       enetc4_get_devargs(dev, ENETC4_TXQ_WRR);
-       enetc4_get_devargs(dev, ENETC4_NC_MEMORY);
+       ret = enetc4_get_devargs(dev, ENETC4_TXQ_PRIORITIES);
+       if (ret == 0)
+               ret = enetc4_get_devargs(dev, ENETC4_TXQ_WRR);
+       if (ret == 0)
+               ret = enetc4_get_devargs(dev, ENETC4_NC_MEMORY);
+       if (ret != 0)
+               return ret;
 
        if (dev->data->nb_rx_queues <= 1)
                return 0;
@@ -1538,8 +1627,13 @@ enetc4_dev_init(struct rte_eth_dev *eth_dev)
        hw->max_rx_queues = (si_cap >> 16) & ENETC_SICAPR0_BDR_MASK;
 
        hw->nc_mode = 0;
-       enetc4_get_devargs(eth_dev, ENETC4_TXQ_PRIORITIES);
-       enetc4_get_devargs(eth_dev, ENETC4_NC_MEMORY);
+       error = enetc4_get_devargs(eth_dev, ENETC4_TXQ_PRIORITIES);
+       if (error == 0)
+               error = enetc4_get_devargs(eth_dev, ENETC4_NC_MEMORY);
+       if (error != 0) {
+               ENETC_PMD_ERR("Invalid device arguments");
+               return error;
+       }
        if (hw->nc_mode) {
                eth_dev->rx_pkt_burst = &enetc_recv_pkts_nc;
                eth_dev->tx_pkt_burst = &enetc_xmit_pkts_nc;

Reply via email to