History

devlink: support default values for param-get and param-set

Support querying and resetting to default param values. Introduce two new devlink netlink attrs: DEVLINK_ATTR_PARAM_VALUE_DEFAULT and DEVLINK_ATTR_PARAM_RESET_DEFAULT. The former is used to contain an optional parameter value inside of the param_value nested attribute. The latter is used in param-set requests from userspace to indicate that the driver should reset the param to its default value. To implement this, two new functions are added to the devlink driver api: devlink_param::get_default() and devlink_param::reset_default(). These callbacks allow drivers to implement default param actions for runtime and permanent cmodes. For driverinit params, the core latches the last value set by a driver via devl_param_driverinit_value_set(), and uses that as the default value for a param. Because default parameter values are optional, it would be impossible to discern whether or not a param of type bool has default value of false or not provided if the default value is encoded using a netlink flag type. For this reason, when a DEVLINK_PARAM_TYPE_BOOL has an associated default value, the default value is encoded using a u8 type.

Daniel Zahka committed 12 months ago

Commit 2a367001 parent 17a42aa6 files · +160 −14Browse files

Unified · Split

6 files
  1. Documentation/netlink/specs/devlink.yaml +9 −0
  2. Documentation/networking/devlink/devlink-params.rst +10 −0
  3. include/net/devlink.h +42 −0
  4. include/uapi/linux/devlink.h +3 −0
  5. net/devlink/netlink_gen.c +3 −2
  6. net/devlink/param.c +93 −12
Documentation/netlink/specs/devlink.yaml+9−0
@@ -859,6 +859,14 @@ attribute-sets: · 858 unmodified lines
859 name: health-reporter-burst-period859 name: health-reporter-burst-period
860 type: u64860 type: u64
861 doc: Time (in msec) for recoveries before starting the grace period.861 doc: Time (in msec) for recoveries before starting the grace period.
862
863 # TODO: fill in the attributes in between
864
865 -
866 name: param-reset-default
867 type: flag
868 doc: Request restoring parameter to its default value.
869 value: 183
862 -870 -
863 name: dl-dev-stats871 name: dl-dev-stats
864 subset-of: devlink872 subset-of: devlink
@@ -1793,6 +1801,7 @@ operations: · 928 unmodified lines
1793 - param-type1801 - param-type
1794 # param-value-data is missing here as the type is variable1802 # param-value-data is missing here as the type is variable
1795 - param-value-cmode1803 - param-value-cmode
1804 - param-reset-default
1796 1805
1797 -1806 -
1798 name: region-get1807 name: region-get
Documentation/networking/devlink/devlink-params.rst+10−0
@@ -41,6 +41,16 @@ In order for ``driverinit`` parameters to take effect, the driver must · 40 unmodified lines
41support reloading via the ``devlink-reload`` command. This command will41support reloading via the ``devlink-reload`` command. This command will
42request a reload of the device driver.42request a reload of the device driver.
43 43
44Default parameter values
45=========================
46
47Drivers may optionally export default values for parameters of cmode
48``runtime`` and ``permanent``. For ``driverinit`` parameters, the last
49value set by the driver will be used as the default value. Drivers can
50also support resetting params with cmode ``runtime`` and ``permanent``
51to their default values. Resetting ``driverinit`` params is supported
52by devlink core without additional driver support needed.
53
44.. _devlink_params_generic:54.. _devlink_params_generic:
45 55
46Generic configuration parameters56Generic configuration parameters
include/net/devlink.h+42−0
@@ -479,6 +479,10 @@ struct devlink_flash_notify { · 478 unmodified lines
479 * @set: set parameter value, used for runtime and permanent479 * @set: set parameter value, used for runtime and permanent
480 * configuration modes480 * configuration modes
481 * @validate: validate input value is applicable (within value range, etc.)481 * @validate: validate input value is applicable (within value range, etc.)
482 * @get_default: get parameter default value, used for runtime and permanent
483 * configuration modes
484 * @reset_default: reset parameter to default value, used for runtime and permanent
485 * configuration modes
482 *486 *
483 * This struct should be used by the driver to fill the data for487 * This struct should be used by the driver to fill the data for
484 * a parameter it registers.488 * a parameter it registers.
@@ -498,6 +502,12 @@ struct devlink_param { · 13 unmodified lines
498 int (*validate)(struct devlink *devlink, u32 id,502 int (*validate)(struct devlink *devlink, u32 id,
499 union devlink_param_value val,503 union devlink_param_value val,
500 struct netlink_ext_ack *extack);504 struct netlink_ext_ack *extack);
505 int (*get_default)(struct devlink *devlink, u32 id,
506 struct devlink_param_gset_ctx *ctx,
507 struct netlink_ext_ack *extack);
508 int (*reset_default)(struct devlink *devlink, u32 id,
509 enum devlink_param_cmode cmode,
510 struct netlink_ext_ack *extack);
501};511};
502 512
503struct devlink_param_item {513struct devlink_param_item {
@@ -509,6 +519,7 @@ struct devlink_param_item { · 5 unmodified lines
509 * until reload.519 * until reload.
510 */520 */
511 bool driverinit_value_new_valid;521 bool driverinit_value_new_valid;
522 union devlink_param_value driverinit_default;
512};523};
513 524
514enum devlink_param_generic_id {525enum devlink_param_generic_id {
@@ -630,6 +641,37 @@ enum devlink_param_generic_id { · 115 unmodified lines
630 .validate = _validate, \641 .validate = _validate, \
631}642}
632 643
644#define DEVLINK_PARAM_GENERIC_WITH_DEFAULTS(_id, _cmodes, _get, _set, \
645 _validate, _get_default, \
646 _reset_default) \
647{ \
648 .id = DEVLINK_PARAM_GENERIC_ID_##_id, \
649 .name = DEVLINK_PARAM_GENERIC_##_id##_NAME, \
650 .type = DEVLINK_PARAM_GENERIC_##_id##_TYPE, \
651 .generic = true, \
652 .supported_cmodes = _cmodes, \
653 .get = _get, \
654 .set = _set, \
655 .validate = _validate, \
656 .get_default = _get_default, \
657 .reset_default = _reset_default, \
658}
659
660#define DEVLINK_PARAM_DRIVER_WITH_DEFAULTS(_id, _name, _type, _cmodes, \
661 _get, _set, _validate, \
662 _get_default, _reset_default) \
663{ \
664 .id = _id, \
665 .name = _name, \
666 .type = _type, \
667 .supported_cmodes = _cmodes, \
668 .get = _get, \
669 .set = _set, \
670 .validate = _validate, \
671 .get_default = _get_default, \
672 .reset_default = _reset_default, \
673}
674
633/* Identifier of board design */675/* Identifier of board design */
634#define DEVLINK_INFO_VERSION_GENERIC_BOARD_ID "board.id"676#define DEVLINK_INFO_VERSION_GENERIC_BOARD_ID "board.id"
635/* Revision of board design */677/* Revision of board design */
include/uapi/linux/devlink.h+3−0
@@ -639,6 +639,9 @@ enum devlink_attr { · 638 unmodified lines
639 639
640 DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD, /* u64 */640 DEVLINK_ATTR_HEALTH_REPORTER_BURST_PERIOD, /* u64 */
641 641
642 DEVLINK_ATTR_PARAM_VALUE_DEFAULT, /* dynamic */
643 DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */
644
642 /* Add new attributes above here, update the spec in645 /* Add new attributes above here, update the spec in
643 * Documentation/netlink/specs/devlink.yaml and re-generate646 * Documentation/netlink/specs/devlink.yaml and re-generate
644 * net/devlink/netlink_gen.c.647 * net/devlink/netlink_gen.c.
net/devlink/netlink_gen.c+3−2
@@ -301,12 +301,13 @@ static const struct nla_policy devlink_param_get_dump_nl_policy[DEVLINK_ATTR_DEV · 300 unmodified lines
301};301};
302 302
303/* DEVLINK_CMD_PARAM_SET - do */303/* DEVLINK_CMD_PARAM_SET - do */
304static const struct nla_policy devlink_param_set_nl_policy[DEVLINK_ATTR_PARAM_VALUE_CMODE + 1] = {304static const struct nla_policy devlink_param_set_nl_policy[DEVLINK_ATTR_PARAM_RESET_DEFAULT + 1] = {
305 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },305 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
306 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },306 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
307 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING, },307 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING, },
308 [DEVLINK_ATTR_PARAM_TYPE] = NLA_POLICY_VALIDATE_FN(NLA_U8, &devlink_attr_param_type_validate),308 [DEVLINK_ATTR_PARAM_TYPE] = NLA_POLICY_VALIDATE_FN(NLA_U8, &devlink_attr_param_type_validate),
309 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = NLA_POLICY_MAX(NLA_U8, 2),309 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = NLA_POLICY_MAX(NLA_U8, 2),
310 [DEVLINK_ATTR_PARAM_RESET_DEFAULT] = { .type = NLA_FLAG, },
310};311};
311 312
312/* DEVLINK_CMD_REGION_GET - do */313/* DEVLINK_CMD_REGION_GET - do */
@@ -919,7 +920,7 @@ const struct genl_split_ops devlink_nl_ops[74] = { · 606 unmodified lines
919 .doit = devlink_nl_param_set_doit,920 .doit = devlink_nl_param_set_doit,
920 .post_doit = devlink_nl_post_doit,921 .post_doit = devlink_nl_post_doit,
921 .policy = devlink_param_set_nl_policy,922 .policy = devlink_param_set_nl_policy,
922 .maxattr = DEVLINK_ATTR_PARAM_VALUE_CMODE,923 .maxattr = DEVLINK_ATTR_PARAM_RESET_DEFAULT,
923 .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,924 .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
924 },925 },
925 {926 {
net/devlink/param.c+93−12
@@ -192,9 +192,32 @@ static int devlink_param_set(struct devlink *devlink, · 191 unmodified lines
192 return param->set(devlink, param->id, ctx, extack);192 return param->set(devlink, param->id, ctx, extack);
193}193}
194 194
195static int devlink_param_get_default(struct devlink *devlink,
196 const struct devlink_param *param,
197 struct devlink_param_gset_ctx *ctx,
198 struct netlink_ext_ack *extack)
199{
200 if (!param->get_default)
201 return -EOPNOTSUPP;
202
203 return param->get_default(devlink, param->id, ctx, extack);
204}
205
206static int devlink_param_reset_default(struct devlink *devlink,
207 const struct devlink_param *param,
208 enum devlink_param_cmode cmode,
209 struct netlink_ext_ack *extack)
210{
211 if (!param->reset_default)
212 return -EOPNOTSUPP;
213
214 return param->reset_default(devlink, param->id, cmode, extack);
215}
216
195static int217static int
196devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,218devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
197 int nla_type, union devlink_param_value val)219 int nla_type, union devlink_param_value val,
220 bool flag_as_u8)
198{221{
199 switch (type) {222 switch (type) {
200 case DEVLINK_PARAM_TYPE_U8:223 case DEVLINK_PARAM_TYPE_U8:
@@ -218,8 +241,16 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type, · 17 unmodified lines
218 return -EMSGSIZE;241 return -EMSGSIZE;
219 break;242 break;
220 case DEVLINK_PARAM_TYPE_BOOL:243 case DEVLINK_PARAM_TYPE_BOOL:
221 if (val.vbool && nla_put_flag(msg, nla_type))244 /* default values of type bool are encoded with u8, so that
222 return -EMSGSIZE;245 * false can be distinguished from not present
246 */
247 if (flag_as_u8) {
248 if (nla_put_u8(msg, nla_type, val.vbool))
249 return -EMSGSIZE;
250 } else {
251 if (val.vbool && nla_put_flag(msg, nla_type))
252 return -EMSGSIZE;
253 }
223 break;254 break;
224 }255 }
225 return 0;256 return 0;
@@ -229,7 +260,9 @@ static int · 3 unmodified lines
229devlink_nl_param_value_fill_one(struct sk_buff *msg,260devlink_nl_param_value_fill_one(struct sk_buff *msg,
230 enum devlink_param_type type,261 enum devlink_param_type type,
231 enum devlink_param_cmode cmode,262 enum devlink_param_cmode cmode,
232 union devlink_param_value val)263 union devlink_param_value val,
264 union devlink_param_value default_val,
265 bool has_default)
233{266{
234 struct nlattr *param_value_attr;267 struct nlattr *param_value_attr;
235 int err = -EMSGSIZE;268 int err = -EMSGSIZE;
@@ -243,10 +276,19 @@ devlink_nl_param_value_fill_one(struct sk_buff *msg, · 7 unmodified lines
243 goto value_nest_cancel;276 goto value_nest_cancel;
244 277
245 err = devlink_nl_param_value_put(msg, type,278 err = devlink_nl_param_value_put(msg, type,
246 DEVLINK_ATTR_PARAM_VALUE_DATA, val);279 DEVLINK_ATTR_PARAM_VALUE_DATA,
280 val, false);
247 if (err)281 if (err)
248 goto value_nest_cancel;282 goto value_nest_cancel;
249 283
284 if (has_default) {
285 err = devlink_nl_param_value_put(msg, type,
286 DEVLINK_ATTR_PARAM_VALUE_DEFAULT,
287 default_val, true);
288 if (err)
289 goto value_nest_cancel;
290 }
291
250 nla_nest_end(msg, param_value_attr);292 nla_nest_end(msg, param_value_attr);
251 return 0;293 return 0;
252 294
@@ -262,7 +304,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, · 9 unmodified lines
262 u32 portid, u32 seq, int flags,304 u32 portid, u32 seq, int flags,
263 struct netlink_ext_ack *extack)305 struct netlink_ext_ack *extack)
264{306{
307 union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
265 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];308 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
309 bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
266 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};310 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
267 const struct devlink_param *param = param_item->param;311 const struct devlink_param *param = param_item->param;
268 struct devlink_param_gset_ctx ctx;312 struct devlink_param_gset_ctx ctx;
@@ -283,12 +327,26 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, · 14 unmodified lines
283 param_value[i] = param_item->driverinit_value;327 param_value[i] = param_item->driverinit_value;
284 else328 else
285 return -EOPNOTSUPP;329 return -EOPNOTSUPP;
330
331 if (param_item->driverinit_value_valid) {
332 default_value[i] = param_item->driverinit_default;
333 default_value_set[i] = true;
334 }
286 } else {335 } else {
287 ctx.cmode = i;336 ctx.cmode = i;
288 err = devlink_param_get(devlink, param, &ctx, extack);337 err = devlink_param_get(devlink, param, &ctx, extack);
289 if (err)338 if (err)
290 return err;339 return err;
291 param_value[i] = ctx.val;340 param_value[i] = ctx.val;
341
342 err = devlink_param_get_default(devlink, param, &ctx,
343 extack);
344 if (!err) {
345 default_value[i] = ctx.val;
346 default_value_set[i] = true;
347 } else if (err != -EOPNOTSUPP) {
348 return err;
349 }
292 }350 }
293 param_value_set[i] = true;351 param_value_set[i] = true;
294 }352 }
@@ -325,7 +383,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink, · 30 unmodified lines
325 if (!param_value_set[i])383 if (!param_value_set[i])
326 continue;384 continue;
327 err = devlink_nl_param_value_fill_one(msg, param->type,385 err = devlink_nl_param_value_fill_one(msg, param->type,
328 i, param_value[i]);386 i, param_value[i],
387 default_value[i],
388 default_value_set[i]);
329 if (err)389 if (err)
330 goto values_list_nest_cancel;390 goto values_list_nest_cancel;
331 }391 }
@@ -542,6 +602,7 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, · 210 unmodified lines
542 struct devlink_param_item *param_item;602 struct devlink_param_item *param_item;
543 const struct devlink_param *param;603 const struct devlink_param *param;
544 union devlink_param_value value;604 union devlink_param_value value;
605 bool reset_default;
545 int err = 0;606 int err = 0;
546 607
547 param_item = devlink_param_get_from_info(params, info);608 param_item = devlink_param_get_from_info(params, info);
@@ -553,13 +614,18 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, · 5 unmodified lines
553 return err;614 return err;
554 if (param_type != param->type)615 if (param_type != param->type)
555 return -EINVAL;616 return -EINVAL;
556 err = devlink_param_value_get_from_info(param, info, &value);617
557 if (err)618 reset_default = info->attrs[DEVLINK_ATTR_PARAM_RESET_DEFAULT];
558 return err;619 if (!reset_default) {
559 if (param->validate) {620 err = devlink_param_value_get_from_info(param, info, &value);
560 err = param->validate(devlink, param->id, value, info->extack);
561 if (err)621 if (err)
562 return err;622 return err;
623 if (param->validate) {
624 err = param->validate(devlink, param->id, value,
625 info->extack);
626 if (err)
627 return err;
628 }
563 }629 }
564 630
565 if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))631 if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
@@ -569,6 +635,15 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, · 3 unmodified lines
569 return -EOPNOTSUPP;635 return -EOPNOTSUPP;
570 636
571 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {637 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
638 if (reset_default) {
639 if (!param_item->driverinit_value_valid) {
640 NL_SET_ERR_MSG(info->extack,
641 "Default value not available");
642 return -EOPNOTSUPP;
643 }
644 value = param_item->driverinit_default;
645 }
646
572 param_item->driverinit_value_new = value;647 param_item->driverinit_value_new = value;
573 param_item->driverinit_value_new_valid = true;648 param_item->driverinit_value_new_valid = true;
574 } else {649 } else {
@@ -576,7 +651,12 @@ static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink, · 1 unmodified line
576 return -EOPNOTSUPP;651 return -EOPNOTSUPP;
577 ctx.val = value;652 ctx.val = value;
578 ctx.cmode = cmode;653 ctx.cmode = cmode;
579 err = devlink_param_set(devlink, param, &ctx, info->extack);654 if (reset_default)
655 err = devlink_param_reset_default(devlink, param, cmode,
656 info->extack);
657 else
658 err = devlink_param_set(devlink, param, &ctx,
659 info->extack);
580 if (err)660 if (err)
581 return err;661 return err;
582 }662 }
@@ -824,6 +904,7 @@ void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id, · 241 unmodified lines
824 904
825 param_item->driverinit_value = init_val;905 param_item->driverinit_value = init_val;
826 param_item->driverinit_value_valid = true;906 param_item->driverinit_value_valid = true;
907 param_item->driverinit_default = init_val;
827 908
828 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);909 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
829}910}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t