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

devlink: introduce framework for selftests

Add a framework for running selftests.
Framework exposes devlink commands and test suite(s) to the user
to execute and query the supported tests by the driver.

Below are new entries in devlink_nl_ops
devlink_nl_cmd_selftests_show_doit/dumpit: To query the supported
selftests by the drivers.
devlink_nl_cmd_selftests_run: To execute selftests. Users can
provide a test mask for executing group tests or standalone tests.

Documentation/networking/devlink/ path is already part of MAINTAINERS &
the new files come under this path. Hence no update needed to the
MAINTAINERS

Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Andy Gospodarek <gospo@broadcom.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vikas Gupta and committed by
Jakub Kicinski
08f588fa 68be7b82

+304
+21
include/net/devlink.h
··· 1509 1509 struct devlink_rate *parent, 1510 1510 void *priv_child, void *priv_parent, 1511 1511 struct netlink_ext_ack *extack); 1512 + /** 1513 + * selftests_check() - queries if selftest is supported 1514 + * @devlink: devlink instance 1515 + * @id: test index 1516 + * @extack: extack for reporting error messages 1517 + * 1518 + * Return: true if test is supported by the driver 1519 + */ 1520 + bool (*selftest_check)(struct devlink *devlink, unsigned int id, 1521 + struct netlink_ext_ack *extack); 1522 + /** 1523 + * selftest_run() - Runs a selftest 1524 + * @devlink: devlink instance 1525 + * @id: test index 1526 + * @extack: extack for reporting error messages 1527 + * 1528 + * Return: status of the test 1529 + */ 1530 + enum devlink_selftest_status 1531 + (*selftest_run)(struct devlink *devlink, unsigned int id, 1532 + struct netlink_ext_ack *extack); 1512 1533 }; 1513 1534 1514 1535 void *devlink_priv(struct devlink *devlink);
+29
include/uapi/linux/devlink.h
··· 136 136 DEVLINK_CMD_LINECARD_NEW, 137 137 DEVLINK_CMD_LINECARD_DEL, 138 138 139 + DEVLINK_CMD_SELFTESTS_GET, /* can dump */ 140 + DEVLINK_CMD_SELFTESTS_RUN, 141 + 139 142 /* add new commands above here */ 140 143 __DEVLINK_CMD_MAX, 141 144 DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 ··· 278 275 279 276 #define DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS \ 280 277 (_BITUL(__DEVLINK_FLASH_OVERWRITE_MAX_BIT) - 1) 278 + 279 + enum devlink_attr_selftest_id { 280 + DEVLINK_ATTR_SELFTEST_ID_UNSPEC, 281 + DEVLINK_ATTR_SELFTEST_ID_FLASH, /* flag */ 282 + 283 + __DEVLINK_ATTR_SELFTEST_ID_MAX, 284 + DEVLINK_ATTR_SELFTEST_ID_MAX = __DEVLINK_ATTR_SELFTEST_ID_MAX - 1 285 + }; 286 + 287 + enum devlink_selftest_status { 288 + DEVLINK_SELFTEST_STATUS_SKIP, 289 + DEVLINK_SELFTEST_STATUS_PASS, 290 + DEVLINK_SELFTEST_STATUS_FAIL 291 + }; 292 + 293 + enum devlink_attr_selftest_result { 294 + DEVLINK_ATTR_SELFTEST_RESULT_UNSPEC, 295 + DEVLINK_ATTR_SELFTEST_RESULT, /* nested */ 296 + DEVLINK_ATTR_SELFTEST_RESULT_ID, /* u32, enum devlink_attr_selftest_id */ 297 + DEVLINK_ATTR_SELFTEST_RESULT_STATUS, /* u8, enum devlink_selftest_status */ 298 + 299 + __DEVLINK_ATTR_SELFTEST_RESULT_MAX, 300 + DEVLINK_ATTR_SELFTEST_RESULT_MAX = __DEVLINK_ATTR_SELFTEST_RESULT_MAX - 1 301 + }; 281 302 282 303 /** 283 304 * enum devlink_trap_action - Packet trap action. ··· 604 577 DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ 605 578 606 579 DEVLINK_ATTR_NESTED_DEVLINK, /* nested */ 580 + 581 + DEVLINK_ATTR_SELFTESTS, /* nested */ 607 582 608 583 /* add new attributes above here, update the policy in devlink.c */ 609 584
+216
net/core/devlink.c
··· 201 201 DEVLINK_PORT_FN_STATE_ACTIVE), 202 202 }; 203 203 204 + static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { 205 + [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG }, 206 + }; 207 + 204 208 static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); 205 209 #define DEVLINK_REGISTERED XA_MARK_1 206 210 ··· 4830 4826 return ret; 4831 4827 } 4832 4828 4829 + static int 4830 + devlink_nl_selftests_fill(struct sk_buff *msg, struct devlink *devlink, 4831 + u32 portid, u32 seq, int flags, 4832 + struct netlink_ext_ack *extack) 4833 + { 4834 + struct nlattr *selftests; 4835 + void *hdr; 4836 + int err; 4837 + int i; 4838 + 4839 + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, 4840 + DEVLINK_CMD_SELFTESTS_GET); 4841 + if (!hdr) 4842 + return -EMSGSIZE; 4843 + 4844 + err = -EMSGSIZE; 4845 + if (devlink_nl_put_handle(msg, devlink)) 4846 + goto err_cancel_msg; 4847 + 4848 + selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); 4849 + if (!selftests) 4850 + goto err_cancel_msg; 4851 + 4852 + for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; 4853 + i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { 4854 + if (devlink->ops->selftest_check(devlink, i, extack)) { 4855 + err = nla_put_flag(msg, i); 4856 + if (err) 4857 + goto err_cancel_msg; 4858 + } 4859 + } 4860 + 4861 + nla_nest_end(msg, selftests); 4862 + genlmsg_end(msg, hdr); 4863 + return 0; 4864 + 4865 + err_cancel_msg: 4866 + genlmsg_cancel(msg, hdr); 4867 + return err; 4868 + } 4869 + 4870 + static int devlink_nl_cmd_selftests_get_doit(struct sk_buff *skb, 4871 + struct genl_info *info) 4872 + { 4873 + struct devlink *devlink = info->user_ptr[0]; 4874 + struct sk_buff *msg; 4875 + int err; 4876 + 4877 + if (!devlink->ops->selftest_check) 4878 + return -EOPNOTSUPP; 4879 + 4880 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 4881 + if (!msg) 4882 + return -ENOMEM; 4883 + 4884 + err = devlink_nl_selftests_fill(msg, devlink, info->snd_portid, 4885 + info->snd_seq, 0, info->extack); 4886 + if (err) { 4887 + nlmsg_free(msg); 4888 + return err; 4889 + } 4890 + 4891 + return genlmsg_reply(msg, info); 4892 + } 4893 + 4894 + static int devlink_nl_cmd_selftests_get_dumpit(struct sk_buff *msg, 4895 + struct netlink_callback *cb) 4896 + { 4897 + struct devlink *devlink; 4898 + int start = cb->args[0]; 4899 + unsigned long index; 4900 + int idx = 0; 4901 + int err = 0; 4902 + 4903 + mutex_lock(&devlink_mutex); 4904 + devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) { 4905 + if (idx < start || !devlink->ops->selftest_check) 4906 + goto inc; 4907 + 4908 + devl_lock(devlink); 4909 + err = devlink_nl_selftests_fill(msg, devlink, 4910 + NETLINK_CB(cb->skb).portid, 4911 + cb->nlh->nlmsg_seq, NLM_F_MULTI, 4912 + cb->extack); 4913 + devl_unlock(devlink); 4914 + if (err) { 4915 + devlink_put(devlink); 4916 + break; 4917 + } 4918 + inc: 4919 + idx++; 4920 + devlink_put(devlink); 4921 + } 4922 + mutex_unlock(&devlink_mutex); 4923 + 4924 + if (err != -EMSGSIZE) 4925 + return err; 4926 + 4927 + cb->args[0] = idx; 4928 + return msg->len; 4929 + } 4930 + 4931 + static int devlink_selftest_result_put(struct sk_buff *skb, unsigned int id, 4932 + enum devlink_selftest_status test_status) 4933 + { 4934 + struct nlattr *result_attr; 4935 + 4936 + result_attr = nla_nest_start(skb, DEVLINK_ATTR_SELFTEST_RESULT); 4937 + if (!result_attr) 4938 + return -EMSGSIZE; 4939 + 4940 + if (nla_put_u32(skb, DEVLINK_ATTR_SELFTEST_RESULT_ID, id) || 4941 + nla_put_u8(skb, DEVLINK_ATTR_SELFTEST_RESULT_STATUS, 4942 + test_status)) 4943 + goto nla_put_failure; 4944 + 4945 + nla_nest_end(skb, result_attr); 4946 + return 0; 4947 + 4948 + nla_put_failure: 4949 + nla_nest_cancel(skb, result_attr); 4950 + return -EMSGSIZE; 4951 + } 4952 + 4953 + static int devlink_nl_cmd_selftests_run(struct sk_buff *skb, 4954 + struct genl_info *info) 4955 + { 4956 + struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1]; 4957 + struct devlink *devlink = info->user_ptr[0]; 4958 + struct nlattr *attrs, *selftests; 4959 + struct sk_buff *msg; 4960 + void *hdr; 4961 + int err; 4962 + int i; 4963 + 4964 + if (!devlink->ops->selftest_run || !devlink->ops->selftest_check) 4965 + return -EOPNOTSUPP; 4966 + 4967 + if (!info->attrs[DEVLINK_ATTR_SELFTESTS]) { 4968 + NL_SET_ERR_MSG_MOD(info->extack, "selftest required"); 4969 + return -EINVAL; 4970 + } 4971 + 4972 + attrs = info->attrs[DEVLINK_ATTR_SELFTESTS]; 4973 + 4974 + err = nla_parse_nested(tb, DEVLINK_ATTR_SELFTEST_ID_MAX, attrs, 4975 + devlink_selftest_nl_policy, info->extack); 4976 + if (err < 0) 4977 + return err; 4978 + 4979 + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 4980 + if (!msg) 4981 + return -ENOMEM; 4982 + 4983 + err = -EMSGSIZE; 4984 + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, 4985 + &devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN); 4986 + if (!hdr) 4987 + goto free_msg; 4988 + 4989 + if (devlink_nl_put_handle(msg, devlink)) 4990 + goto genlmsg_cancel; 4991 + 4992 + selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); 4993 + if (!selftests) 4994 + goto genlmsg_cancel; 4995 + 4996 + for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; 4997 + i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { 4998 + enum devlink_selftest_status test_status; 4999 + 5000 + if (nla_get_flag(tb[i])) { 5001 + if (!devlink->ops->selftest_check(devlink, i, 5002 + info->extack)) { 5003 + if (devlink_selftest_result_put(msg, i, 5004 + DEVLINK_SELFTEST_STATUS_SKIP)) 5005 + goto selftests_nest_cancel; 5006 + continue; 5007 + } 5008 + 5009 + test_status = devlink->ops->selftest_run(devlink, i, 5010 + info->extack); 5011 + if (devlink_selftest_result_put(msg, i, test_status)) 5012 + goto selftests_nest_cancel; 5013 + } 5014 + } 5015 + 5016 + nla_nest_end(msg, selftests); 5017 + genlmsg_end(msg, hdr); 5018 + return genlmsg_reply(msg, info); 5019 + 5020 + selftests_nest_cancel: 5021 + nla_nest_cancel(msg, selftests); 5022 + genlmsg_cancel: 5023 + genlmsg_cancel(msg, hdr); 5024 + free_msg: 5025 + nlmsg_free(msg); 5026 + return err; 5027 + } 5028 + 4833 5029 static const struct devlink_param devlink_param_generic[] = { 4834 5030 { 4835 5031 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET, ··· 9173 8969 [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, 9174 8970 [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, 9175 8971 [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING }, 8972 + [DEVLINK_ATTR_SELFTESTS] = { .type = NLA_NESTED }, 9176 8973 }; 9177 8974 9178 8975 static const struct genl_small_ops devlink_nl_ops[] = { ··· 9531 9326 { 9532 9327 .cmd = DEVLINK_CMD_TRAP_POLICER_SET, 9533 9328 .doit = devlink_nl_cmd_trap_policer_set_doit, 9329 + .flags = GENL_ADMIN_PERM, 9330 + }, 9331 + { 9332 + .cmd = DEVLINK_CMD_SELFTESTS_GET, 9333 + .doit = devlink_nl_cmd_selftests_get_doit, 9334 + .dumpit = devlink_nl_cmd_selftests_get_dumpit 9335 + /* can be retrieved by unprivileged users */ 9336 + }, 9337 + { 9338 + .cmd = DEVLINK_CMD_SELFTESTS_RUN, 9339 + .doit = devlink_nl_cmd_selftests_run, 9534 9340 .flags = GENL_ADMIN_PERM, 9535 9341 }, 9536 9342 };