naccyde / rpms / iproute

Forked from rpms/iproute 8 months ago
Clone

Blame SOURCES/0049-devlink-Add-param-command-support.patch

7e752c
From a126f6cc4f4d8f5f58758d673fbdb80894c5f05d Mon Sep 17 00:00:00 2001
7e752c
From: Andrea Claudi <aclaudi@redhat.com>
7e752c
Date: Wed, 29 May 2019 18:55:33 +0200
7e752c
Subject: [PATCH] devlink: Add param command support
7e752c
7e752c
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1663199
7e752c
Upstream Status: iproute2.git commit 13925ae9eb38b
7e752c
7e752c
commit 13925ae9eb38b99107be1d3fe21a1b73cf40bd97
7e752c
Author: Moshe Shemesh <moshe@mellanox.com>
7e752c
Date:   Wed Jul 4 17:12:06 2018 +0300
7e752c
7e752c
    devlink: Add param command support
7e752c
7e752c
    Add support for configuration parameters set and show.
7e752c
    Each parameter can be either generic or driver-specific.
7e752c
    The user can retrieve data on these configuration parameters by devlink
7e752c
    param show command and can set new value to a configuration parameter
7e752c
    by devlink param set command.
7e752c
    The configuration parameters can be set in different configuration
7e752c
    modes:
7e752c
      runtime - set while driver is running, no reset required.
7e752c
      driverinit - applied while driver initializes, requires restart
7e752c
                   driver by devlink reload command.
7e752c
      permanent - written to device's non-volatile memory, hard reset
7e752c
                  required to apply.
7e752c
7e752c
    New commands added:
7e752c
      devlink dev param show [DEV name PARAMETER]
7e752c
      devlink dev param set DEV name PARAMETER value VALUE
7e752c
                                cmode { permanent | driverinit | runtime }
7e752c
7e752c
    Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
7e752c
    Signed-off-by: Jiri Pirko <jiri@mellanox.com>
7e752c
    Signed-off-by: David Ahern <dsahern@gmail.com>
7e752c
---
7e752c
 devlink/devlink.c      | 454 +++++++++++++++++++++++++++++++++++++++++
7e752c
 man/man8/devlink-dev.8 |  57 ++++++
7e752c
 2 files changed, 511 insertions(+)
7e752c
7e752c
diff --git a/devlink/devlink.c b/devlink/devlink.c
7e752c
index 7a5aef84f25dc..00a514f8ff666 100644
7e752c
--- a/devlink/devlink.c
7e752c
+++ b/devlink/devlink.c
7e752c
@@ -35,6 +35,10 @@
7e752c
 #define ESWITCH_INLINE_MODE_NETWORK "network"
7e752c
 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
7e752c
 
7e752c
+#define PARAM_CMODE_RUNTIME_STR "runtime"
7e752c
+#define PARAM_CMODE_DRIVERINIT_STR "driverinit"
7e752c
+#define PARAM_CMODE_PERMANENT_STR "permanent"
7e752c
+
7e752c
 static int g_new_line_count;
7e752c
 
7e752c
 #define pr_err(args...) fprintf(stderr, ##args)
7e752c
@@ -187,6 +191,9 @@ static void ifname_map_free(struct ifname_map *ifname_map)
7e752c
 #define DL_OPT_ESWITCH_ENCAP_MODE	BIT(15)
7e752c
 #define DL_OPT_RESOURCE_PATH	BIT(16)
7e752c
 #define DL_OPT_RESOURCE_SIZE	BIT(17)
7e752c
+#define DL_OPT_PARAM_NAME	BIT(18)
7e752c
+#define DL_OPT_PARAM_VALUE	BIT(19)
7e752c
+#define DL_OPT_PARAM_CMODE	BIT(20)
7e752c
 
7e752c
 struct dl_opts {
7e752c
 	uint32_t present; /* flags of present items */
7e752c
@@ -211,6 +218,9 @@ struct dl_opts {
7e752c
 	uint32_t resource_size;
7e752c
 	uint32_t resource_id;
7e752c
 	bool resource_id_valid;
7e752c
+	const char *param_name;
7e752c
+	const char *param_value;
7e752c
+	enum devlink_param_cmode cmode;
7e752c
 };
7e752c
 
7e752c
 struct dl {
7e752c
@@ -348,6 +358,12 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
7e752c
 	[DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
7e752c
 	[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
7e752c
 	[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
7e752c
+	[DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
7e752c
+	[DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
7e752c
+	[DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
7e752c
+	[DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
7e752c
+	[DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
7e752c
+	[DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
7e752c
 };
7e752c
 
7e752c
 static int attr_cb(const struct nlattr *attr, void *data)
7e752c
@@ -514,6 +530,34 @@ static int strtouint16_t(const char *str, uint16_t *p_val)
7e752c
 	return 0;
7e752c
 }
7e752c
 
7e752c
+static int strtouint8_t(const char *str, uint8_t *p_val)
7e752c
+{
7e752c
+	char *endptr;
7e752c
+	unsigned long int val;
7e752c
+
7e752c
+	val = strtoul(str, &endptr, 10);
7e752c
+	if (endptr == str || *endptr != '\0')
7e752c
+		return -EINVAL;
7e752c
+	if (val > UCHAR_MAX)
7e752c
+		return -ERANGE;
7e752c
+	*p_val = val;
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
+static int strtobool(const char *str, bool *p_val)
7e752c
+{
7e752c
+	bool val;
7e752c
+
7e752c
+	if (!strcmp(str, "true") || !strcmp(str, "1"))
7e752c
+		val = true;
7e752c
+	else if (!strcmp(str, "false") || !strcmp(str, "0"))
7e752c
+		val = false;
7e752c
+	else
7e752c
+		return -EINVAL;
7e752c
+	*p_val = val;
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
7e752c
 {
7e752c
 	strslashrsplit(str, p_bus_name, p_dev_name);
7e752c
@@ -792,6 +836,22 @@ static int eswitch_encap_mode_get(const char *typestr, bool *p_mode)
7e752c
 	return 0;
7e752c
 }
7e752c
 
7e752c
+static int param_cmode_get(const char *cmodestr,
7e752c
+			   enum devlink_param_cmode *cmode)
7e752c
+{
7e752c
+	if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
7e752c
+		*cmode = DEVLINK_PARAM_CMODE_RUNTIME;
7e752c
+	} else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
7e752c
+		*cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
7e752c
+	} else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
7e752c
+		*cmode = DEVLINK_PARAM_CMODE_PERMANENT;
7e752c
+	} else {
7e752c
+		pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
7e752c
+		return -EINVAL;
7e752c
+	}
7e752c
+	return 0;
7e752c
+}
7e752c
+
7e752c
 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
7e752c
 			 uint32_t o_optional)
7e752c
 {
7e752c
@@ -973,6 +1033,32 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
7e752c
 			if (err)
7e752c
 				return err;
7e752c
 			o_found |= DL_OPT_RESOURCE_SIZE;
7e752c
+		} else if (dl_argv_match(dl, "name") &&
7e752c
+			   (o_all & DL_OPT_PARAM_NAME)) {
7e752c
+			dl_arg_inc(dl);
7e752c
+			err = dl_argv_str(dl, &opts->param_name);
7e752c
+			if (err)
7e752c
+				return err;
7e752c
+			o_found |= DL_OPT_PARAM_NAME;
7e752c
+		} else if (dl_argv_match(dl, "value") &&
7e752c
+			   (o_all & DL_OPT_PARAM_VALUE)) {
7e752c
+			dl_arg_inc(dl);
7e752c
+			err = dl_argv_str(dl, &opts->param_value);
7e752c
+			if (err)
7e752c
+				return err;
7e752c
+			o_found |= DL_OPT_PARAM_VALUE;
7e752c
+		} else if (dl_argv_match(dl, "cmode") &&
7e752c
+			   (o_all & DL_OPT_PARAM_CMODE)) {
7e752c
+			const char *cmodestr;
7e752c
+
7e752c
+			dl_arg_inc(dl);
7e752c
+			err = dl_argv_str(dl, &cmodestr);
7e752c
+			if (err)
7e752c
+				return err;
7e752c
+			err = param_cmode_get(cmodestr, &opts->cmode);
7e752c
+			if (err)
7e752c
+				return err;
7e752c
+			o_found |= DL_OPT_PARAM_CMODE;
7e752c
 		} else {
7e752c
 			pr_err("Unknown option \"%s\"\n", dl_argv(dl));
7e752c
 			return -EINVAL;
7e752c
@@ -1057,6 +1143,24 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
7e752c
 		return -EINVAL;
7e752c
 	}
7e752c
 
7e752c
+	if ((o_required & DL_OPT_PARAM_NAME) &&
7e752c
+	    !(o_found & DL_OPT_PARAM_NAME)) {
7e752c
+		pr_err("Parameter name expected.\n");
7e752c
+		return -EINVAL;
7e752c
+	}
7e752c
+
7e752c
+	if ((o_required & DL_OPT_PARAM_VALUE) &&
7e752c
+	    !(o_found & DL_OPT_PARAM_VALUE)) {
7e752c
+		pr_err("Value to set expected.\n");
7e752c
+		return -EINVAL;
7e752c
+	}
7e752c
+
7e752c
+	if ((o_required & DL_OPT_PARAM_CMODE) &&
7e752c
+	    !(o_found & DL_OPT_PARAM_CMODE)) {
7e752c
+		pr_err("Configuration mode expected.\n");
7e752c
+		return -EINVAL;
7e752c
+	}
7e752c
+
7e752c
 	return 0;
7e752c
 }
7e752c
 
7e752c
@@ -1121,6 +1225,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
7e752c
 	if (opts->present & DL_OPT_RESOURCE_SIZE)
7e752c
 		mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
7e752c
 				 opts->resource_size);
7e752c
+	if (opts->present & DL_OPT_PARAM_NAME)
7e752c
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
7e752c
+				  opts->param_name);
7e752c
+	if (opts->present & DL_OPT_PARAM_CMODE)
7e752c
+		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
7e752c
+				opts->cmode);
7e752c
 }
7e752c
 
7e752c
 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
7e752c
@@ -1179,6 +1289,8 @@ static void cmd_dev_help(void)
7e752c
 	pr_err("                               [ inline-mode { none | link | network | transport } ]\n");
7e752c
 	pr_err("                               [ encap { disable | enable } ]\n");
7e752c
 	pr_err("       devlink dev eswitch show DEV\n");
7e752c
+	pr_err("       devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
7e752c
+	pr_err("       devlink dev param show [DEV name PARAMETER]\n");
7e752c
 	pr_err("       devlink dev reload DEV\n");
7e752c
 }
7e752c
 
7e752c
@@ -1393,6 +1505,14 @@ static void pr_out_str(struct dl *dl, const char *name, const char *val)
7e752c
 	}
7e752c
 }
7e752c
 
7e752c
+static void pr_out_bool(struct dl *dl, const char *name, bool val)
7e752c
+{
7e752c
+	if (val)
7e752c
+		pr_out_str(dl, name, "true");
7e752c
+	else
7e752c
+		pr_out_str(dl, name, "false");
7e752c
+}
7e752c
+
7e752c
 static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
7e752c
 {
7e752c
 	if (dl->json_output) {
7e752c
@@ -1475,6 +1595,19 @@ static void pr_out_entry_end(struct dl *dl)
7e752c
 		__pr_out_newline();
7e752c
 }
7e752c
 
7e752c
+static const char *param_cmode_name(uint8_t cmode)
7e752c
+{
7e752c
+	switch (cmode) {
7e752c
+	case DEVLINK_PARAM_CMODE_RUNTIME:
7e752c
+		return PARAM_CMODE_RUNTIME_STR;
7e752c
+	case DEVLINK_PARAM_CMODE_DRIVERINIT:
7e752c
+		return PARAM_CMODE_DRIVERINIT_STR;
7e752c
+	case DEVLINK_PARAM_CMODE_PERMANENT:
7e752c
+		return PARAM_CMODE_PERMANENT_STR;
7e752c
+	default: return "<unknown type>";
7e752c
+	}
7e752c
+}
7e752c
+
7e752c
 static const char *eswitch_mode_name(uint32_t mode)
7e752c
 {
7e752c
 	switch (mode) {
7e752c
@@ -1593,6 +1726,304 @@ static int cmd_dev_eswitch(struct dl *dl)
7e752c
 	return -ENOENT;
7e752c
 }
7e752c
 
7e752c
+static void pr_out_param_value(struct dl *dl, int nla_type, struct nlattr *nl)
7e752c
+{
7e752c
+	struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+	struct nlattr *val_attr;
7e752c
+	int err;
7e752c
+
7e752c
+	err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
7e752c
+	if (err != MNL_CB_OK)
7e752c
+		return;
7e752c
+
7e752c
+	if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
7e752c
+	    (nla_type != MNL_TYPE_FLAG &&
7e752c
+	     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
7e752c
+		return;
7e752c
+
7e752c
+	pr_out_str(dl, "cmode",
7e752c
+		   param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
7e752c
+	val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
7e752c
+
7e752c
+	switch (nla_type) {
7e752c
+	case MNL_TYPE_U8:
7e752c
+		pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
7e752c
+		break;
7e752c
+	case MNL_TYPE_U16:
7e752c
+		pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
7e752c
+		break;
7e752c
+	case MNL_TYPE_U32:
7e752c
+		pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
7e752c
+		break;
7e752c
+	case MNL_TYPE_STRING:
7e752c
+		pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
7e752c
+		break;
7e752c
+	case MNL_TYPE_FLAG:
7e752c
+		pr_out_bool(dl, "value", val_attr ? true : false);
7e752c
+		break;
7e752c
+	}
7e752c
+}
7e752c
+
7e752c
+static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
7e752c
+{
7e752c
+	struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+	struct nlattr *param_value_attr;
7e752c
+	int nla_type;
7e752c
+	int err;
7e752c
+
7e752c
+	err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
7e752c
+	if (err != MNL_CB_OK)
7e752c
+		return;
7e752c
+	if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
7e752c
+	    !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
7e752c
+	    !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
7e752c
+		return;
7e752c
+
7e752c
+	if (array)
7e752c
+		pr_out_handle_start_arr(dl, tb);
7e752c
+	else
7e752c
+		__pr_out_handle_start(dl, tb, true, false);
7e752c
+
7e752c
+	nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
7e752c
+
7e752c
+	pr_out_str(dl, "name",
7e752c
+		   mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]));
7e752c
+
7e752c
+	if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
7e752c
+		pr_out_str(dl, "type", "driver-specific");
7e752c
+	else
7e752c
+		pr_out_str(dl, "type", "generic");
7e752c
+
7e752c
+	pr_out_array_start(dl, "values");
7e752c
+	mnl_attr_for_each_nested(param_value_attr,
7e752c
+				 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
7e752c
+		pr_out_entry_start(dl);
7e752c
+		pr_out_param_value(dl, nla_type, param_value_attr);
7e752c
+		pr_out_entry_end(dl);
7e752c
+	}
7e752c
+	pr_out_array_end(dl);
7e752c
+	pr_out_handle_end(dl);
7e752c
+}
7e752c
+
7e752c
+static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
7e752c
+{
7e752c
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7e752c
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+	struct dl *dl = data;
7e752c
+
7e752c
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7e752c
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7e752c
+	    !tb[DEVLINK_ATTR_PARAM])
7e752c
+		return MNL_CB_ERROR;
7e752c
+	pr_out_param(dl, tb, true);
7e752c
+	return MNL_CB_OK;
7e752c
+}
7e752c
+
7e752c
+struct param_ctx {
7e752c
+	struct dl *dl;
7e752c
+	int nla_type;
7e752c
+	union {
7e752c
+		uint8_t vu8;
7e752c
+		uint16_t vu16;
7e752c
+		uint32_t vu32;
7e752c
+		const char *vstr;
7e752c
+		bool vbool;
7e752c
+	} value;
7e752c
+};
7e752c
+
7e752c
+static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
7e752c
+{
7e752c
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7e752c
+	struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+	struct nlattr *param_value_attr;
7e752c
+	enum devlink_param_cmode cmode;
7e752c
+	struct param_ctx *ctx = data;
7e752c
+	struct dl *dl = ctx->dl;
7e752c
+	int nla_type;
7e752c
+	int err;
7e752c
+
7e752c
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7e752c
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7e752c
+	    !tb[DEVLINK_ATTR_PARAM])
7e752c
+		return MNL_CB_ERROR;
7e752c
+
7e752c
+	err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
7e752c
+	if (err != MNL_CB_OK)
7e752c
+		return MNL_CB_ERROR;
7e752c
+
7e752c
+	if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
7e752c
+	    !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
7e752c
+		return MNL_CB_ERROR;
7e752c
+
7e752c
+	nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
7e752c
+	mnl_attr_for_each_nested(param_value_attr,
7e752c
+				 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
7e752c
+		struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
7e752c
+		struct nlattr *val_attr;
7e752c
+
7e752c
+		err = mnl_attr_parse_nested(param_value_attr,
7e752c
+					    attr_cb, nla_value);
7e752c
+		if (err != MNL_CB_OK)
7e752c
+			return MNL_CB_ERROR;
7e752c
+
7e752c
+		if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
7e752c
+		    (nla_type != MNL_TYPE_FLAG &&
7e752c
+		     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
7e752c
+			return MNL_CB_ERROR;
7e752c
+
7e752c
+		cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
7e752c
+		if (cmode == dl->opts.cmode) {
7e752c
+			val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
7e752c
+			switch (nla_type) {
7e752c
+			case MNL_TYPE_U8:
7e752c
+				ctx->value.vu8 = mnl_attr_get_u8(val_attr);
7e752c
+				break;
7e752c
+			case MNL_TYPE_U16:
7e752c
+				ctx->value.vu16 = mnl_attr_get_u16(val_attr);
7e752c
+				break;
7e752c
+			case MNL_TYPE_U32:
7e752c
+				ctx->value.vu32 = mnl_attr_get_u32(val_attr);
7e752c
+				break;
7e752c
+			case MNL_TYPE_STRING:
7e752c
+				ctx->value.vstr = mnl_attr_get_str(val_attr);
7e752c
+				break;
7e752c
+			case MNL_TYPE_FLAG:
7e752c
+				ctx->value.vbool = val_attr ? true : false;
7e752c
+				break;
7e752c
+			}
7e752c
+			break;
7e752c
+		}
7e752c
+	}
7e752c
+	ctx->nla_type = nla_type;
7e752c
+	return MNL_CB_OK;
7e752c
+}
7e752c
+
7e752c
+static int cmd_dev_param_set(struct dl *dl)
7e752c
+{
7e752c
+	struct param_ctx ctx = {};
7e752c
+	struct nlmsghdr *nlh;
7e752c
+	uint32_t val_u32;
7e752c
+	uint16_t val_u16;
7e752c
+	uint8_t val_u8;
7e752c
+	bool val_bool;
7e752c
+	int err;
7e752c
+
7e752c
+	err = dl_argv_parse(dl, DL_OPT_HANDLE |
7e752c
+			    DL_OPT_PARAM_NAME |
7e752c
+			    DL_OPT_PARAM_VALUE |
7e752c
+			    DL_OPT_PARAM_CMODE, 0);
7e752c
+	if (err)
7e752c
+		return err;
7e752c
+
7e752c
+	/* Get value type */
7e752c
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
7e752c
+			       NLM_F_REQUEST | NLM_F_ACK);
7e752c
+	dl_opts_put(nlh, dl);
7e752c
+
7e752c
+	ctx.dl = dl;
7e752c
+	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx;;
7e752c
+	if (err)
7e752c
+		return err;
7e752c
+
7e752c
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
7e752c
+			       NLM_F_REQUEST | NLM_F_ACK);
7e752c
+	dl_opts_put(nlh, dl);
7e752c
+
7e752c
+	mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
7e752c
+	switch (ctx.nla_type) {
7e752c
+	case MNL_TYPE_U8:
7e752c
+		err = strtouint8_t(dl->opts.param_value, &val_u8);
7e752c
+		if (err)
7e752c
+			goto err_param_value_parse;
7e752c
+		if (val_u8 == ctx.value.vu8)
7e752c
+			return 0;
7e752c
+		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
7e752c
+		break;
7e752c
+	case MNL_TYPE_U16:
7e752c
+		err = strtouint16_t(dl->opts.param_value, &val_u16);
7e752c
+		if (err)
7e752c
+			goto err_param_value_parse;
7e752c
+		if (val_u16 == ctx.value.vu16)
7e752c
+			return 0;
7e752c
+		mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
7e752c
+		break;
7e752c
+	case MNL_TYPE_U32:
7e752c
+		err = strtouint32_t(dl->opts.param_value, &val_u32);
7e752c
+		if (err)
7e752c
+			goto err_param_value_parse;
7e752c
+		if (val_u32 == ctx.value.vu32)
7e752c
+			return 0;
7e752c
+		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
7e752c
+		break;
7e752c
+	case MNL_TYPE_FLAG:
7e752c
+		err = strtobool(dl->opts.param_value, &val_bool);
7e752c
+		if (err)
7e752c
+			goto err_param_value_parse;
7e752c
+		if (val_bool == ctx.value.vbool)
7e752c
+			return 0;
7e752c
+		if (val_bool)
7e752c
+			mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
7e752c
+				     0, NULL);
7e752c
+		break;
7e752c
+	case MNL_TYPE_STRING:
7e752c
+		mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
7e752c
+				  dl->opts.param_value);
7e752c
+		if (!strcmp(dl->opts.param_value, ctx.value.vstr))
7e752c
+			return 0;
7e752c
+		break;
7e752c
+	default:
7e752c
+		printf("Value type not supported\n");
7e752c
+		return -ENOTSUP;
7e752c
+	}
7e752c
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7e752c
+
7e752c
+err_param_value_parse:
7e752c
+	pr_err("Value \"%s\" is not a number or not within range\n",
7e752c
+	       dl->opts.param_value);
7e752c
+	return err;
7e752c
+}
7e752c
+
7e752c
+static int cmd_dev_param_show(struct dl *dl)
7e752c
+{
7e752c
+	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7e752c
+	struct nlmsghdr *nlh;
7e752c
+	int err;
7e752c
+
7e752c
+	if (dl_argc(dl) == 0)
7e752c
+		flags |= NLM_F_DUMP;
7e752c
+
7e752c
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
7e752c
+
7e752c
+	if (dl_argc(dl) > 0) {
7e752c
+		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
7e752c
+					DL_OPT_PARAM_NAME, 0);
7e752c
+		if (err)
7e752c
+			return err;
7e752c
+	}
7e752c
+
7e752c
+	pr_out_section_start(dl, "param");
7e752c
+	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
7e752c
+	pr_out_section_end(dl);
7e752c
+	return err;
7e752c
+}
7e752c
+
7e752c
+static int cmd_dev_param(struct dl *dl)
7e752c
+{
7e752c
+	if (dl_argv_match(dl, "help")) {
7e752c
+		cmd_dev_help();
7e752c
+		return 0;
7e752c
+	} else if (dl_argv_match(dl, "show") ||
7e752c
+		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7e752c
+		dl_arg_inc(dl);
7e752c
+		return cmd_dev_param_show(dl);
7e752c
+	} else if (dl_argv_match(dl, "set")) {
7e752c
+		dl_arg_inc(dl);
7e752c
+		return cmd_dev_param_set(dl);
7e752c
+	}
7e752c
+	pr_err("Command \"%s\" not found\n", dl_argv(dl));
7e752c
+	return -ENOENT;
7e752c
+}
7e752c
 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
7e752c
 {
7e752c
 	struct dl *dl = data;
7e752c
@@ -1669,6 +2100,9 @@ static int cmd_dev(struct dl *dl)
7e752c
 	} else if (dl_argv_match(dl, "reload")) {
7e752c
 		dl_arg_inc(dl);
7e752c
 		return cmd_dev_reload(dl);
7e752c
+	} else if (dl_argv_match(dl, "param")) {
7e752c
+		dl_arg_inc(dl);
7e752c
+		return cmd_dev_param(dl);
7e752c
 	}
7e752c
 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
7e752c
 	return -ENOENT;
7e752c
@@ -2632,6 +3066,10 @@ static const char *cmd_name(uint8_t cmd)
7e752c
 	case DEVLINK_CMD_PORT_SET: return "set";
7e752c
 	case DEVLINK_CMD_PORT_NEW: return "new";
7e752c
 	case DEVLINK_CMD_PORT_DEL: return "del";
7e752c
+	case DEVLINK_CMD_PARAM_GET: return "get";
7e752c
+	case DEVLINK_CMD_PARAM_SET: return "set";
7e752c
+	case DEVLINK_CMD_PARAM_NEW: return "new";
7e752c
+	case DEVLINK_CMD_PARAM_DEL: return "del";
7e752c
 	default: return "<unknown cmd>";
7e752c
 	}
7e752c
 }
7e752c
@@ -2650,6 +3088,11 @@ static const char *cmd_obj(uint8_t cmd)
7e752c
 	case DEVLINK_CMD_PORT_NEW:
7e752c
 	case DEVLINK_CMD_PORT_DEL:
7e752c
 		return "port";
7e752c
+	case DEVLINK_CMD_PARAM_GET:
7e752c
+	case DEVLINK_CMD_PARAM_SET:
7e752c
+	case DEVLINK_CMD_PARAM_NEW:
7e752c
+	case DEVLINK_CMD_PARAM_DEL:
7e752c
+		return "param";
7e752c
 	default: return "<unknown obj>";
7e752c
 	}
7e752c
 }
7e752c
@@ -2706,6 +3149,17 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
7e752c
 		pr_out_mon_header(genl->cmd);
7e752c
 		pr_out_port(dl, tb);
7e752c
 		break;
7e752c
+	case DEVLINK_CMD_PARAM_GET: /* fall through */
7e752c
+	case DEVLINK_CMD_PARAM_SET: /* fall through */
7e752c
+	case DEVLINK_CMD_PARAM_NEW: /* fall through */
7e752c
+	case DEVLINK_CMD_PARAM_DEL:
7e752c
+		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7e752c
+		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7e752c
+		    !tb[DEVLINK_ATTR_PARAM])
7e752c
+			return MNL_CB_ERROR;
7e752c
+		pr_out_mon_header(genl->cmd);
7e752c
+		pr_out_param(dl, tb, false);
7e752c
+		break;
7e752c
 	}
7e752c
 	return MNL_CB_OK;
7e752c
 }
7e752c
diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8
7e752c
index 7c749ddabaeeb..d985da172aa05 100644
7e752c
--- a/man/man8/devlink-dev.8
7e752c
+++ b/man/man8/devlink-dev.8
7e752c
@@ -42,6 +42,23 @@ devlink-dev \- devlink device configuration
7e752c
 .BR "devlink dev eswitch show"
7e752c
 .IR DEV
7e752c
 
7e752c
+.ti -8
7e752c
+.BR "devlink dev param set"
7e752c
+.IR DEV
7e752c
+.BR name
7e752c
+.IR PARAMETER
7e752c
+.BR value
7e752c
+.IR VALUE
7e752c
+.BR cmode " { " runtime " | " driverinit " | " permanent " } "
7e752c
+
7e752c
+.ti -8
7e752c
+.BR "devlink dev param show"
7e752c
+.RI "[ "
7e752c
+.IR DEV
7e752c
+.BR name
7e752c
+.IR PARAMETER
7e752c
+.RI "]"
7e752c
+
7e752c
 .ti -8
7e752c
 .BR "devlink dev reload"
7e752c
 .IR DEV
7e752c
@@ -98,6 +115,36 @@ Set eswitch encapsulation support
7e752c
 .I enable
7e752c
 - Enable encapsulation support
7e752c
 
7e752c
+.SS devlink dev param set  - set new value to devlink device configuration parameter
7e752c
+
7e752c
+.TP
7e752c
+.BI name " PARAMETER"
7e752c
+Specify parameter name to set.
7e752c
+
7e752c
+.TP
7e752c
+.BI value " VALUE"
7e752c
+New value to set.
7e752c
+
7e752c
+.TP
7e752c
+.BR cmode " { " runtime " | " driverinit " | " permanent " } "
7e752c
+Configuration mode in which the new value is set.
7e752c
+
7e752c
+.I runtime
7e752c
+- Set new value while driver is running. This configuration mode doesn't require any reset to apply the new value.
7e752c
+
7e752c
+.I driverinit
7e752c
+- Set new value which will be applied during driver initialization. This configuration mode requires restart driver by devlink reload command to apply the new value.
7e752c
+
7e752c
+.I permanent
7e752c
+- New value is written to device's non-volatile memory. This configuration mode requires hard reset to apply the new value.
7e752c
+
7e752c
+.SS devlink dev param show - display devlink device supported configuration parameters attributes
7e752c
+
7e752c
+.BR name
7e752c
+.IR PARAMETER
7e752c
+Specify parameter name to show.
7e752c
+If this argument is omitted all parameters supported by devlink devices are listed.
7e752c
+
7e752c
 .SS devlink dev reload - perform hot reload of the driver.
7e752c
 
7e752c
 .PP
7e752c
@@ -126,6 +173,16 @@ devlink dev eswitch set pci/0000:01:00.0 mode switchdev
7e752c
 Sets the eswitch mode of specified devlink device to switchdev.
7e752c
 .RE
7e752c
 .PP
7e752c
+devlink dev param show pci/0000:01:00.0 name max_macs
7e752c
+.RS 4
7e752c
+Shows the parameter max_macs attributes.
7e752c
+.RE
7e752c
+.PP
7e752c
+devlink dev param set pci/0000:01:00.0 name internal_error_reset value true cmode runtime
7e752c
+.RS 4
7e752c
+Sets the parameter internal_error_reset of specified devlink device to true.
7e752c
+.RE
7e752c
+.PP
7e752c
 devlink dev reload pci/0000:01:00.0
7e752c
 .RS 4
7e752c
 Performs hot reload of specified devlink device.
7e752c
-- 
7e752c
2.20.1
7e752c