summaryrefslogtreecommitdiff
path: root/net/devlink/param.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/devlink/param.c')
-rw-r--r--net/devlink/param.c127
1 files changed, 94 insertions, 33 deletions
diff --git a/net/devlink/param.c b/net/devlink/param.c
index cf95268da5b0..3e9d2e5750c2 100644
--- a/net/devlink/param.c
+++ b/net/devlink/param.c
@@ -216,28 +216,28 @@ static int devlink_param_reset_default(struct devlink *devlink,
static int
devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
- int nla_type, union devlink_param_value val,
+ int nla_type, union devlink_param_value *val,
bool flag_as_u8)
{
switch (type) {
case DEVLINK_PARAM_TYPE_U8:
- if (nla_put_u8(msg, nla_type, val.vu8))
+ if (nla_put_u8(msg, nla_type, val->vu8))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U16:
- if (nla_put_u16(msg, nla_type, val.vu16))
+ if (nla_put_u16(msg, nla_type, val->vu16))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U32:
- if (nla_put_u32(msg, nla_type, val.vu32))
+ if (nla_put_u32(msg, nla_type, val->vu32))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_U64:
- if (devlink_nl_put_u64(msg, nla_type, val.vu64))
+ if (devlink_nl_put_u64(msg, nla_type, val->vu64))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_STRING:
- if (nla_put_string(msg, nla_type, val.vstr))
+ if (nla_put_string(msg, nla_type, val->vstr))
return -EMSGSIZE;
break;
case DEVLINK_PARAM_TYPE_BOOL:
@@ -245,10 +245,19 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
* false can be distinguished from not present
*/
if (flag_as_u8) {
- if (nla_put_u8(msg, nla_type, val.vbool))
+ if (nla_put_u8(msg, nla_type, val->vbool))
return -EMSGSIZE;
} else {
- if (val.vbool && nla_put_flag(msg, nla_type))
+ if (val->vbool && nla_put_flag(msg, nla_type))
+ return -EMSGSIZE;
+ }
+ break;
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ if (val->u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ for (int i = 0; i < val->u64arr.size; i++) {
+ if (nla_put_uint(msg, nla_type, val->u64arr.val[i]))
return -EMSGSIZE;
}
break;
@@ -260,8 +269,8 @@ static int
devlink_nl_param_value_fill_one(struct sk_buff *msg,
enum devlink_param_type type,
enum devlink_param_cmode cmode,
- union devlink_param_value val,
- union devlink_param_value default_val,
+ union devlink_param_value *val,
+ union devlink_param_value *default_val,
bool has_default)
{
struct nlattr *param_value_attr;
@@ -304,56 +313,79 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
u32 portid, u32 seq, int flags,
struct netlink_ext_ack *extack)
{
- union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
- union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
const struct devlink_param *param = param_item->param;
- struct devlink_param_gset_ctx ctx;
+ union devlink_param_value *default_value;
+ union devlink_param_value *param_value;
+ struct devlink_param_gset_ctx *ctx;
struct nlattr *param_values_list;
struct nlattr *param_attr;
void *hdr;
int err;
int i;
+ default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*default_value), GFP_KERNEL);
+ if (!default_value)
+ return -ENOMEM;
+
+ param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*param_value), GFP_KERNEL);
+ if (!param_value) {
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
+ ctx = kzalloc_obj(*ctx);
+ if (!ctx) {
+ kfree(param_value);
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
/* Get value from driver part to driverinit configuration mode */
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
if (!devlink_param_cmode_is_supported(param, i))
continue;
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
- if (param_item->driverinit_value_new_valid)
+ if (param_item->driverinit_value_new_valid) {
param_value[i] = param_item->driverinit_value_new;
- else if (param_item->driverinit_value_valid)
+ } else if (param_item->driverinit_value_valid) {
param_value[i] = param_item->driverinit_value;
- else
- return -EOPNOTSUPP;
+ } else {
+ err = -EOPNOTSUPP;
+ goto get_put_fail;
+ }
if (param_item->driverinit_value_valid) {
default_value[i] = param_item->driverinit_default;
default_value_set[i] = true;
}
} else {
- ctx.cmode = i;
- err = devlink_param_get(devlink, param, &ctx, extack);
+ ctx->cmode = i;
+ err = devlink_param_get(devlink, param, ctx, extack);
if (err)
- return err;
- param_value[i] = ctx.val;
+ goto get_put_fail;
- err = devlink_param_get_default(devlink, param, &ctx,
+ param_value[i] = ctx->val;
+
+ err = devlink_param_get_default(devlink, param, ctx,
extack);
if (!err) {
- default_value[i] = ctx.val;
+ default_value[i] = ctx->val;
default_value_set[i] = true;
} else if (err != -EOPNOTSUPP) {
- return err;
+ goto get_put_fail;
}
}
param_value_set[i] = true;
}
+ err = -EMSGSIZE;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
if (!hdr)
- return -EMSGSIZE;
+ goto get_put_fail;
if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;
@@ -383,8 +415,8 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
if (!param_value_set[i])
continue;
err = devlink_nl_param_value_fill_one(msg, param->type,
- i, param_value[i],
- default_value[i],
+ i, &param_value[i],
+ &default_value[i],
default_value_set[i]);
if (err)
goto values_list_nest_cancel;
@@ -393,6 +425,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
nla_nest_end(msg, param_values_list);
nla_nest_end(msg, param_attr);
genlmsg_end(msg, hdr);
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
return 0;
values_list_nest_cancel:
@@ -401,7 +436,11 @@ param_nest_cancel:
nla_nest_cancel(msg, param_attr);
genlmsg_cancel:
genlmsg_cancel(msg, hdr);
- return -EMSGSIZE;
+get_put_fail:
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
+ return err;
}
static void devlink_param_notify(struct devlink *devlink,
@@ -507,7 +546,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
union devlink_param_value *value)
{
struct nlattr *param_data;
- int len;
+ int len, cnt, rem;
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
@@ -547,6 +586,28 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
return -EINVAL;
value->vbool = nla_get_flag(param_data);
break;
+
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ cnt = 0;
+ nla_for_each_attr_type(param_data,
+ DEVLINK_ATTR_PARAM_VALUE_DATA,
+ genlmsg_data(info->genlhdr),
+ genlmsg_len(info->genlhdr), rem) {
+ if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ if ((nla_len(param_data) != sizeof(u64)) &&
+ (nla_len(param_data) != sizeof(u32))) {
+ NL_SET_BAD_ATTR(info->extack, param_data);
+ return -EINVAL;
+ }
+
+ value->u64arr.val[cnt] = nla_get_uint(param_data);
+ cnt++;
+ }
+
+ value->u64arr.size = cnt;
+ break;
}
return 0;
}
@@ -621,7 +682,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
if (err)
return err;
if (param->validate) {
- err = param->validate(devlink, param->id, value,
+ err = param->validate(devlink, param->id, &value,
info->extack);
if (err)
return err;
@@ -888,7 +949,7 @@ EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
* configuration mode default value.
*/
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
- union devlink_param_value init_val)
+ union devlink_param_value *init_val)
{
struct devlink_param_item *param_item;
@@ -902,9 +963,9 @@ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
DEVLINK_PARAM_CMODE_DRIVERINIT)))
return;
- param_item->driverinit_value = init_val;
+ param_item->driverinit_value = *init_val;
param_item->driverinit_value_valid = true;
- param_item->driverinit_default = init_val;
+ param_item->driverinit_default = *init_val;
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
}