[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250704045427.1558605-10-saeed@kernel.org>
Date: Thu, 3 Jul 2025 21:54:27 -0700
From: Saeed Mahameed <saeed@...nel.org>
To: stephen@...workplumber.org,
dsahern@...il.com,
Jiri Pirko <jiri@...dia.com>
Cc: netdev@...r.kernel.org,
Saeed Mahameed <saeedm@...dia.com>
Subject: [PATCH iproute2 V2 9/9] devlink: params set: add support for nested attributes values
From: Saeed Mahameed <saeedm@...dia.com>
Update the dl_params helper functions to process nested value
attributes, currently the kernel supports variably sized arrays
of u32 via param enum type DEVLINK_VAR_ATTR_TYPE_U32_ARRAY.
Add command line parsing to parse comma separated u32 user inputs and
fill the nlmsg accordingly, check for size mismatch between
current kernel value and user input.
example:
$ devlink dev param set <dev> name foo value 1,2,3,4,5,6,7,8 cmode ...
Signed-off-by: Saeed Mahameed <saeedm@...dia.com>
---
devlink/devlink.c | 102 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 90 insertions(+), 12 deletions(-)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index fe64f2dc..15f2a80b 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -3426,29 +3426,29 @@ struct dl_param_val_list {
};
/* Parse nested param value list
- * @val_list_attr: nested attribute containing the list of values
- * usually : val_list_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]
+ * @val_nest_attr: nested attribute containing the list of values
+ * val_nest_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE]
* @list: pointer to the list of values, reallocated to the new size
* Returns: 0 on success, -errno on failure
*/
static int
-dl_mnl_parse_param_val_nested(struct nlattr *val_list_attr,
+dl_mnl_parse_param_val_nested(struct nlattr *val_nest_attr,
struct dl_param_val_list **list)
{
struct dl_param_val_list *new_list;
- struct nlattr *val_attr;
+ struct nlattr *val_data_attr;
int i = 0, len = 0;
- len = mnl_attr_get_payload_len(val_list_attr)/(MNL_ATTR_HDRLEN + sizeof(uint32_t));
- if (!len)
- return -EINVAL;
-
+ mnl_attr_for_each_nested(val_data_attr, val_nest_attr)
+ if (mnl_attr_get_type(val_data_attr) == DEVLINK_ATTR_PARAM_VALUE_DATA)
+ len++;
new_list = realloc(*list, sizeof(new_list) + len * sizeof(uint32_t));
if (!new_list)
return -ENOMEM;
- mnl_attr_for_each_nested(val_attr, val_list_attr)
- new_list->vu32[i++] = mnl_attr_get_u32(val_attr);
+ mnl_attr_for_each_nested(val_data_attr, val_nest_attr)
+ if (mnl_attr_get_type(val_data_attr) == DEVLINK_ATTR_PARAM_VALUE_DATA)
+ new_list->vu32[i++] = mnl_attr_get_u32(val_data_attr);
new_list->len = i;
*list = new_list;
@@ -3543,7 +3543,7 @@ static void pr_out_param_value(struct dl *dl, const char *nla_name,
int err;
int i;
- err = dl_mnl_parse_param_val_nested(val_attr, &list);
+ err = dl_mnl_parse_param_val_nested(nl, &list);
if (err)
return;
@@ -3637,9 +3637,53 @@ struct dl_param {
uint32_t vu32;
const char *vstr;
bool vbool;
+ struct dl_param_val_list *vlist;
} value;
};
+/* Get the parameter value from the options and fill the param struct
+ * @dl: dl struct
+ * @nla_type: type of the parameter value
+ * @param: parameter struct to store the value
+ *
+ * Note:
+ * param->value.vlist reallocated to the new size
+ *
+ * Returns: 0 on success, -errno on failure
+ */
+static int dl_param_opts_get_arr(struct dl *dl, struct dl_param *param)
+{
+ char *tmp = strdup(dl->opts.param_value);
+ struct dl_param_val_list *list;
+ const char *p = NULL;
+ int err = 0, i = 1;
+
+ if (!tmp) {
+ pr_err("Memory allocation failed\n");
+ return -ENOMEM;
+ }
+ for (p = tmp; *p; p++)
+ i += (*p == ',');
+
+ list = realloc(param->value.vlist, sizeof(*list) + i * sizeof(uint32_t));
+ if (!list) {
+ pr_err("Memory allocation failed\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ param->value.vlist = list; /* update vlist to new size */
+ i = list->len = 0; /* reset len */
+ for (p = strtok(tmp, ","); p; p = strtok(NULL, ",")) {
+ err = get_u32(&list->vu32[i++], p, 10);
+ if (err)
+ goto out;
+ }
+ /* update len only when all values are filled */
+ list->len = i;
+out:
+ free(tmp);
+ return err;
+}
/* Get the parameter value from the options and convert it to the
* appropriate type.
* @dl: dl struct
@@ -3678,6 +3722,9 @@ static int dl_param_opts_get(struct dl *dl, enum devlink_var_attr_type type,
param->value.vstr = dl->opts.param_value;
err = 0;
break;
+ case DEVLINK_VAR_ATTR_TYPE_U32_ARRAY:
+ err = dl_param_opts_get_arr(dl, param);
+ break;
default:
err = -ENOTSUP;
}
@@ -3735,6 +3782,18 @@ static int dl_param_cmp(struct dl_param *p1, struct dl_param *p2)
if (strcmp(p1->value.vstr, p2->value.vstr))
return 1;
break;
+ case DEVLINK_VAR_ATTR_TYPE_U32_ARRAY:
+ if (!p1->value.vlist || !p2->value.vlist)
+ return -EINVAL;
+ if (p1->value.vlist->len != p2->value.vlist->len) {
+ pr_err("Error: expecting value list of legnth %ld\n",
+ p2->value.vlist->len);
+ return -EINVAL; /* different lengths is not expected */
+ }
+ if (memcmp(p1->value.vlist->vu32, p2->value.vlist->vu32,
+ p1->value.vlist->len * sizeof(uint32_t)))
+ return 1;
+ break;
default:
return -EINVAL;
}
@@ -3766,6 +3825,18 @@ static int dl_param_mnl_put(struct nlmsghdr *nlh, struct dl_param *param)
case DEVLINK_VAR_ATTR_TYPE_STRING:
mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, param->value.vstr);
break;
+ case DEVLINK_VAR_ATTR_TYPE_U32_ARRAY: {
+ struct dl_param_val_list *list = param->value.vlist;
+ int i;
+
+ if (!list)
+ return -EINVAL;
+
+ for (i = 0; i < list->len; i++)
+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, list->vu32[i]);
+
+ break;
+ }
default:
pr_err("Value type(%d) not supported\n", param->type);
return -ENOTSUP;
@@ -3776,11 +3847,13 @@ static int dl_param_mnl_put(struct nlmsghdr *nlh, struct dl_param *param)
/* dl_param_val_attr_parse: parse the value attribute and store the value
* in the dl_param struct
* @data_attr: value data attribute
+ * @val_nest_attr: parent attribute containing the values
* @nla_type: type of the value attribute
* @param: dl_param struct to store the value
*/
static int
dl_param_val_attr_parse(struct nlattr *data_attr,
+ struct nlattr *val_nest_attr,
enum devlink_var_attr_type type,
struct dl_param *param)
{
@@ -3800,6 +3873,11 @@ dl_param_val_attr_parse(struct nlattr *data_attr,
case DEVLINK_VAR_ATTR_TYPE_FLAG:
param->value.vbool = data_attr ? true : false;
break;
+ case DEVLINK_VAR_ATTR_TYPE_U32_ARRAY:
+ if(dl_mnl_parse_param_val_nested(val_nest_attr,
+ ¶m->value.vlist))
+ return -ENOMEM;
+ break;
default:
pr_err("Value type(%d) not supported\n", type);
return -ENOTSUP;
@@ -3857,7 +3935,7 @@ static int cmd_param_set_cb(const struct nlmsghdr *nlh, void *data)
param->cmode_found = true;
data_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
- if (dl_param_val_attr_parse(data_attr, type, param))
+ if (dl_param_val_attr_parse(data_attr, param_value_attr, type, param))
return MNL_CB_ERROR;
break;
}
--
2.50.0
Powered by blists - more mailing lists