From: Saeed Mahameed 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 name foo value 1,2,3,4,5,6,7,8 cmode ... Signed-off-by: Saeed Mahameed --- 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