[PATCH net-next 03/11] net: core: devlink: add port_params_ops for devlink port parameters altering

Oleksandr Mazur
2021-06-09T15:16:46Z

Current design makes it impossible to distinguish which port's parameter
should get altered (set) or retrieved (get) whenever there's a single
parameter registered within a few ports.

Change this by adding new devlink port parameter ops structure:
- introduce structure port_params_ops that has callbacks for
get/set/validate;
- if devlink has registered port_params_ops, then upon every devlink
port parameter get/set call invoke port parameters callback

Suggested-by: Vadym Kochan <vadym.kochan@plvision.eu>
Signed-off-by: Oleksandr Mazur <oleksandr.mazur@plvision.eu>
---
include/net/devlink.h | 23 ++++++++++++++++++++++
net/core/devlink.c | 44 +++++++++++++++++++++++++++++++++++--------
2 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index b8c6bac067a6..1d687651260c 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1191,6 +1191,28 @@ enum devlink_trap_group_generic_id {
.min_burst = _min_burst, \
}

+/**
+ * struct devlink_port_param_ops - devlink port parameters-specific ops
+ * @get: get port parameter value, used for runtime and permanent
+ * configuration modes
+ * @set: set port parameter value, used for runtime and permanent
+ * configuration modes
+ * @validate: validate input value is applicable (within value range, etc.)
+ *
+ * This struct should be used by the driver register port parameters ops,
+ * that would be used by the devlink subsystem to fetch (get) or alter (set)
+ * devlink port parameter.
+ */
+struct devlink_port_param_ops {
+ int (*get)(struct devlink_port *port, u32 id,
+ struct devlink_param_gset_ctx *ctx);
+ int (*set)(struct devlink_port *port, u32 id,
+ struct devlink_param_gset_ctx *ctx);
+ int (*validate)(struct devlink_port *port, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack);
+};
+
struct devlink_ops {
/**
* @supported_flash_update_params:
@@ -1463,6 +1485,7 @@ struct devlink_ops {
struct devlink_port *port,
enum devlink_port_fn_state state,
struct netlink_ext_ack *extack);
+ const struct devlink_port_param_ops *port_param_ops;
};

static inline void *devlink_priv(struct devlink *devlink)
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 2baf8720bb48..79566a04083b 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3923,6 +3923,7 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
const struct devlink_param *param = param_item->param;
struct devlink_param_gset_ctx ctx;
struct nlattr *param_values_list;
+ struct devlink_port *dl_port;
struct nlattr *param_attr;
int nla_type;
void *hdr;
@@ -3941,7 +3942,20 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
if (!param_item->published)
continue;
ctx.cmode = i;
- err = devlink_param_get(devlink, param, &ctx);
+ if ((cmd == DEVLINK_CMD_PORT_PARAM_GET ||
+ cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
+ cmd == DEVLINK_CMD_PORT_PARAM_DEL) &&
+ devlink->ops->port_param_ops &&
+ devlink->ops->port_param_ops->get) {
+ dl_port = devlink_port_get_by_index(devlink,
+ port_index);
+ err = devlink->ops->port_param_ops->get(dl_port,
+ param->id,
+ &ctx);
+ } else {
+ err = devlink_param_get(devlink, param, &ctx);
+ }
+
if (err)
return err;
param_value[i] = ctx.val;
@@ -4201,6 +4215,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
struct devlink_param_item *param_item;
const struct devlink_param *param;
union devlink_param_value value;
+ struct devlink_port *dl_port;
int err = 0;

param_item = devlink_param_get_from_info(param_list, info);
@@ -4234,13 +4249,28 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
param_item->driverinit_value = value;
param_item->driverinit_value_valid = true;
} else {
- if (!param->set)
- return -EOPNOTSUPP;
ctx.val = value;
ctx.cmode = cmode;
- err = devlink_param_set(devlink, param, &ctx);
- if (err)
- return err;
+
+ if ((cmd == DEVLINK_CMD_PORT_PARAM_SET ||
+ cmd == DEVLINK_CMD_PORT_PARAM_NEW) &&
+ devlink->ops->port_param_ops &&
+ devlink->ops->port_param_ops->set) {
+ dl_port = devlink_port_get_by_index(devlink,
+ port_index);
+ err = devlink->ops->port_param_ops->set(dl_port,
+ param->id,
+ &ctx);
+ if (err)
+ return err;
+ } else {
+ if (!param->set)
+ return -EOPNOTSUPP;
+
+ err = devlink_param_set(devlink, param, &ctx);
+ if (err)
+ return err;
+ }
}

devlink_param_notify(devlink, port_index, param_item, cmd);
@@ -4269,8 +4299,6 @@ static int devlink_param_register_one(struct devlink *devlink,

if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
WARN_ON(param->get || param->set);
- else
- WARN_ON(!param->get || !param->set);

param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
if (!param_item)
--
2.17.1