Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Link: https://patch.msgid.link/20251119025038.651131-4-daniel.zahka@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Daniel Zahka and committed by
Jakub Kicinski
2a367002 17a42aa4

+160 -14
+9
Documentation/netlink/specs/devlink.yaml
··· 859 859 name: health-reporter-burst-period 860 860 type: u64 861 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 871 name: dl-dev-stats 864 872 subset-of: devlink ··· 1801 1793 - param-type 1802 1794 # param-value-data is missing here as the type is variable 1803 1795 - param-value-cmode 1796 + - param-reset-default 1804 1797 1805 1798 - 1806 1799 name: region-get
+42
include/net/devlink.h
··· 479 479 * @set: set parameter value, used for runtime and permanent 480 480 * configuration modes 481 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 487 * This struct should be used by the driver to fill the data for 484 488 * a parameter it registers. ··· 502 498 int (*validate)(struct devlink *devlink, u32 id, 503 499 union devlink_param_value val, 504 500 struct netlink_ext_ack *extack); 501 + int (*get_default)(struct devlink *devlink, u32 id, 502 + struct devlink_param_gset_ctx *ctx, 503 + struct netlink_ext_ack *extack); 504 + int (*reset_default)(struct devlink *devlink, u32 id, 505 + enum devlink_param_cmode cmode, 506 + struct netlink_ext_ack *extack); 505 507 }; 506 508 507 509 struct devlink_param_item { ··· 519 509 * until reload. 520 510 */ 521 511 bool driverinit_value_new_valid; 512 + union devlink_param_value driverinit_default; 522 513 }; 523 514 524 515 enum devlink_param_generic_id { ··· 639 628 .get = _get, \ 640 629 .set = _set, \ 641 630 .validate = _validate, \ 631 + } 632 + 633 + #define DEVLINK_PARAM_GENERIC_WITH_DEFAULTS(_id, _cmodes, _get, _set, \ 634 + _validate, _get_default, \ 635 + _reset_default) \ 636 + { \ 637 + .id = DEVLINK_PARAM_GENERIC_ID_##_id, \ 638 + .name = DEVLINK_PARAM_GENERIC_##_id##_NAME, \ 639 + .type = DEVLINK_PARAM_GENERIC_##_id##_TYPE, \ 640 + .generic = true, \ 641 + .supported_cmodes = _cmodes, \ 642 + .get = _get, \ 643 + .set = _set, \ 644 + .validate = _validate, \ 645 + .get_default = _get_default, \ 646 + .reset_default = _reset_default, \ 647 + } 648 + 649 + #define DEVLINK_PARAM_DRIVER_WITH_DEFAULTS(_id, _name, _type, _cmodes, \ 650 + _get, _set, _validate, \ 651 + _get_default, _reset_default) \ 652 + { \ 653 + .id = _id, \ 654 + .name = _name, \ 655 + .type = _type, \ 656 + .supported_cmodes = _cmodes, \ 657 + .get = _get, \ 658 + .set = _set, \ 659 + .validate = _validate, \ 660 + .get_default = _get_default, \ 661 + .reset_default = _reset_default, \ 642 662 } 643 663 644 664 /* Identifier of board design */
+3
include/uapi/linux/devlink.h
··· 639 639 640 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 645 /* Add new attributes above here, update the spec in 643 646 * Documentation/netlink/specs/devlink.yaml and re-generate 644 647 * net/devlink/netlink_gen.c.
+93 -12
net/devlink/param.c
··· 192 192 return param->set(devlink, param->id, ctx, extack); 193 193 } 194 194 195 + static 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 + 206 + static 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 + 195 217 static int 196 218 devlink_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 222 switch (type) { 200 223 case DEVLINK_PARAM_TYPE_U8: ··· 241 218 return -EMSGSIZE; 242 219 break; 243 220 case DEVLINK_PARAM_TYPE_BOOL: 244 - if (val.vbool && nla_put_flag(msg, nla_type)) 245 - return -EMSGSIZE; 221 + /* default values of type bool are encoded with u8, so that 222 + * false can be distinguished from not present 223 + */ 224 + if (flag_as_u8) { 225 + if (nla_put_u8(msg, nla_type, val.vbool)) 226 + return -EMSGSIZE; 227 + } else { 228 + if (val.vbool && nla_put_flag(msg, nla_type)) 229 + return -EMSGSIZE; 230 + } 246 231 break; 247 232 } 248 233 return 0; ··· 260 229 devlink_nl_param_value_fill_one(struct sk_buff *msg, 261 230 enum devlink_param_type type, 262 231 enum devlink_param_cmode cmode, 263 - union devlink_param_value val) 232 + union devlink_param_value val, 233 + union devlink_param_value default_val, 234 + bool has_default) 264 235 { 265 236 struct nlattr *param_value_attr; 266 237 int err = -EMSGSIZE; ··· 276 243 goto value_nest_cancel; 277 244 278 245 err = devlink_nl_param_value_put(msg, type, 279 - DEVLINK_ATTR_PARAM_VALUE_DATA, val); 246 + DEVLINK_ATTR_PARAM_VALUE_DATA, 247 + val, false); 280 248 if (err) 281 249 goto value_nest_cancel; 250 + 251 + if (has_default) { 252 + err = devlink_nl_param_value_put(msg, type, 253 + DEVLINK_ATTR_PARAM_VALUE_DEFAULT, 254 + default_val, true); 255 + if (err) 256 + goto value_nest_cancel; 257 + } 282 258 283 259 nla_nest_end(msg, param_value_attr); 284 260 return 0; ··· 304 262 u32 portid, u32 seq, int flags, 305 263 struct netlink_ext_ack *extack) 306 264 { 265 + union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1]; 307 266 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1]; 267 + bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {}; 308 268 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {}; 309 269 const struct devlink_param *param = param_item->param; 310 270 struct devlink_param_gset_ctx ctx; ··· 327 283 param_value[i] = param_item->driverinit_value; 328 284 else 329 285 return -EOPNOTSUPP; 286 + 287 + if (param_item->driverinit_value_valid) { 288 + default_value[i] = param_item->driverinit_default; 289 + default_value_set[i] = true; 290 + } 330 291 } else { 331 292 ctx.cmode = i; 332 293 err = devlink_param_get(devlink, param, &ctx, extack); 333 294 if (err) 334 295 return err; 335 296 param_value[i] = ctx.val; 297 + 298 + err = devlink_param_get_default(devlink, param, &ctx, 299 + extack); 300 + if (!err) { 301 + default_value[i] = ctx.val; 302 + default_value_set[i] = true; 303 + } else if (err != -EOPNOTSUPP) { 304 + return err; 305 + } 336 306 } 337 307 param_value_set[i] = true; 338 308 } ··· 383 325 if (!param_value_set[i]) 384 326 continue; 385 327 err = devlink_nl_param_value_fill_one(msg, param->type, 386 - i, param_value[i]); 328 + i, param_value[i], 329 + default_value[i], 330 + default_value_set[i]); 387 331 if (err) 388 332 goto values_list_nest_cancel; 389 333 } ··· 602 542 struct devlink_param_item *param_item; 603 543 const struct devlink_param *param; 604 544 union devlink_param_value value; 545 + bool reset_default; 605 546 int err = 0; 606 547 607 548 param_item = devlink_param_get_from_info(params, info); ··· 614 553 return err; 615 554 if (param_type != param->type) 616 555 return -EINVAL; 617 - err = devlink_param_value_get_from_info(param, info, &value); 618 - if (err) 619 - return err; 620 - if (param->validate) { 621 - err = param->validate(devlink, param->id, value, info->extack); 556 + 557 + reset_default = info->attrs[DEVLINK_ATTR_PARAM_RESET_DEFAULT]; 558 + if (!reset_default) { 559 + err = devlink_param_value_get_from_info(param, info, &value); 622 560 if (err) 623 561 return err; 562 + if (param->validate) { 563 + err = param->validate(devlink, param->id, value, 564 + info->extack); 565 + if (err) 566 + return err; 567 + } 624 568 } 625 569 626 570 if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE)) ··· 635 569 return -EOPNOTSUPP; 636 570 637 571 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) { 572 + if (reset_default) { 573 + if (!param_item->driverinit_value_valid) { 574 + NL_SET_ERR_MSG(info->extack, 575 + "Default value not available"); 576 + return -EOPNOTSUPP; 577 + } 578 + value = param_item->driverinit_default; 579 + } 580 + 638 581 param_item->driverinit_value_new = value; 639 582 param_item->driverinit_value_new_valid = true; 640 583 } else { ··· 651 576 return -EOPNOTSUPP; 652 577 ctx.val = value; 653 578 ctx.cmode = cmode; 654 - err = devlink_param_set(devlink, param, &ctx, info->extack); 579 + if (reset_default) 580 + err = devlink_param_reset_default(devlink, param, cmode, 581 + info->extack); 582 + else 583 + err = devlink_param_set(devlink, param, &ctx, 584 + info->extack); 655 585 if (err) 656 586 return err; 657 587 } ··· 904 824 905 825 param_item->driverinit_value = init_val; 906 826 param_item->driverinit_value_valid = true; 827 + param_item->driverinit_default = init_val; 907 828 908 829 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW); 909 830 }