lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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,
+						 &param->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

Powered by Openwall GNU/*/Linux Powered by OpenVZ