From: Saeed Mahameed Param value attribute DEVLINK_ATTR_PARAM_VALUE_DATA can be passed to/from kernel as type DEVLINK_VAR_ATTR_TYPE_U32_ARRAY with encoded data of U32 list of values. Handle this case by outputting the value as comma separated list or json list objects for get/dump requests. example: $ devlink dev param show name foo name foo type driver-specific values: cmode permanent value: 1,2,3,4,5,6,7,8 Signed-off-by: Saeed Mahameed --- devlink/devlink.c | 77 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/devlink.h | 1 + 2 files changed, 78 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index 8195cb2b..2abf8ff7 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -556,6 +556,30 @@ static void pr_out_array_end(struct dl *dl) } } +static void pr_out_val_array_start(struct dl *dl, const char *name, + const char *delimeter) +{ + if (dl->json_output) { + open_json_array(PRINT_JSON, name); + } else { + __pr_out_indent_inc(); + pr_out(" %s:", name); + if (delimeter) + pr_out("%s", delimeter); + __pr_out_indent_inc(); + } +} + +static void pr_out_val_array_end(struct dl *dl) +{ + if (dl->json_output) { + close_json_array(PRINT_JSON, NULL); + } else { + __pr_out_indent_dec(); + __pr_out_indent_dec(); + } +} + static void pr_out_object_start(struct dl *dl, const char *name) { if (dl->json_output) { @@ -3396,6 +3420,41 @@ static const struct param_val_conv param_val_conv[] = { }, }; +struct dl_param_val_list { + size_t len; + uint32_t vu32[]; +}; + +/* 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] + * @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, + struct dl_param_val_list **list) +{ + struct dl_param_val_list *new_list; + struct nlattr *val_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; + + 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); + + new_list->len = i; + *list = new_list; + return 0; +} + #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv) static void pr_out_param_value(struct dl *dl, const char *nla_name, @@ -3479,6 +3538,24 @@ static void pr_out_param_value(struct dl *dl, const char *nla_name, case DEVLINK_VAR_ATTR_TYPE_FLAG: print_bool(PRINT_ANY, "value", " value %s", val_attr); break; + case DEVLINK_VAR_ATTR_TYPE_U32_ARRAY: { + struct dl_param_val_list *list = NULL; + int err; + int i; + + err = dl_mnl_parse_param_val_nested(val_attr, &list); + if (err) + return; + + pr_out_val_array_start(dl, "value", " "); + + for (i = 0; i < list->len - 1; i++) + print_uint(PRINT_ANY, NULL, "%u,", list->vu32[i]); + print_uint(PRINT_ANY, NULL, "%u", list->vu32[i]); + pr_out_val_array_end(dl); + free(list); + break; + } default: break; } diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 9a1bdc94..a22fc073 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -398,6 +398,7 @@ enum devlink_var_attr_type { DEVLINK_VAR_ATTR_TYPE_BINARY, __DEVLINK_VAR_ATTR_TYPE_CUSTOM_BASE = 0x80, /* Any possible custom types, unrelated to NLA_* values go below */ + DEVLINK_VAR_ATTR_TYPE_U32_ARRAY, }; enum devlink_attr { -- 2.50.0