Skip to content

Commit 08f588f

Browse files
vikasbrcmkuba-moo
authored andcommitted
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>
1 parent 68be7b8 commit 08f588f

File tree

4 files changed

+304
-0
lines changed

4 files changed

+304
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
3+
=================
4+
Devlink Selftests
5+
=================
6+
7+
The ``devlink-selftests`` API allows executing selftests on the device.
8+
9+
Tests Mask
10+
==========
11+
The ``devlink-selftests`` command should be run with a mask indicating
12+
the tests to be executed.
13+
14+
Tests Description
15+
=================
16+
The following is a list of tests that drivers may execute.
17+
18+
.. list-table:: List of tests
19+
:widths: 5 90
20+
21+
* - Name
22+
- Description
23+
* - ``DEVLINK_SELFTEST_FLASH``
24+
- Devices may have the firmware on non-volatile memory on the board, e.g.
25+
flash. This particular test helps to run a flash selftest on the device.
26+
Implementation of the test is left to the driver/firmware.
27+
28+
example usage
29+
-------------
30+
31+
.. code:: shell
32+
33+
# Query selftests supported on the devlink device
34+
$ devlink dev selftests show DEV
35+
# Query selftests supported on all devlink devices
36+
$ devlink dev selftests show
37+
# Executes selftests on the device
38+
$ devlink dev selftests run DEV id flash

include/net/devlink.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,27 @@ struct devlink_ops {
15091509
struct devlink_rate *parent,
15101510
void *priv_child, void *priv_parent,
15111511
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);
15121533
};
15131534

15141535
void *devlink_priv(struct devlink *devlink);

include/uapi/linux/devlink.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ enum devlink_command {
136136
DEVLINK_CMD_LINECARD_NEW,
137137
DEVLINK_CMD_LINECARD_DEL,
138138

139+
DEVLINK_CMD_SELFTESTS_GET, /* can dump */
140+
DEVLINK_CMD_SELFTESTS_RUN,
141+
139142
/* add new commands above here */
140143
__DEVLINK_CMD_MAX,
141144
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -276,6 +279,30 @@ enum {
276279
#define DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS \
277280
(_BITUL(__DEVLINK_FLASH_OVERWRITE_MAX_BIT) - 1)
278281

282+
enum devlink_attr_selftest_id {
283+
DEVLINK_ATTR_SELFTEST_ID_UNSPEC,
284+
DEVLINK_ATTR_SELFTEST_ID_FLASH, /* flag */
285+
286+
__DEVLINK_ATTR_SELFTEST_ID_MAX,
287+
DEVLINK_ATTR_SELFTEST_ID_MAX = __DEVLINK_ATTR_SELFTEST_ID_MAX - 1
288+
};
289+
290+
enum devlink_selftest_status {
291+
DEVLINK_SELFTEST_STATUS_SKIP,
292+
DEVLINK_SELFTEST_STATUS_PASS,
293+
DEVLINK_SELFTEST_STATUS_FAIL
294+
};
295+
296+
enum devlink_attr_selftest_result {
297+
DEVLINK_ATTR_SELFTEST_RESULT_UNSPEC,
298+
DEVLINK_ATTR_SELFTEST_RESULT, /* nested */
299+
DEVLINK_ATTR_SELFTEST_RESULT_ID, /* u32, enum devlink_attr_selftest_id */
300+
DEVLINK_ATTR_SELFTEST_RESULT_STATUS, /* u8, enum devlink_selftest_status */
301+
302+
__DEVLINK_ATTR_SELFTEST_RESULT_MAX,
303+
DEVLINK_ATTR_SELFTEST_RESULT_MAX = __DEVLINK_ATTR_SELFTEST_RESULT_MAX - 1
304+
};
305+
279306
/**
280307
* enum devlink_trap_action - Packet trap action.
281308
* @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not
@@ -578,6 +605,8 @@ enum devlink_attr {
578605

579606
DEVLINK_ATTR_NESTED_DEVLINK, /* nested */
580607

608+
DEVLINK_ATTR_SELFTESTS, /* nested */
609+
581610
/* add new attributes above here, update the policy in devlink.c */
582611

583612
__DEVLINK_ATTR_MAX,

net/core/devlink.c

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_
201201
DEVLINK_PORT_FN_STATE_ACTIVE),
202202
};
203203

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+
204208
static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC);
205209
#define DEVLINK_REGISTERED XA_MARK_1
206210

@@ -4826,6 +4830,206 @@ static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
48264830
return ret;
48274831
}
48284832

4833+
static int
4834+
devlink_nl_selftests_fill(struct sk_buff *msg, struct devlink *devlink,
4835+
u32 portid, u32 seq, int flags,
4836+
struct netlink_ext_ack *extack)
4837+
{
4838+
struct nlattr *selftests;
4839+
void *hdr;
4840+
int err;
4841+
int i;
4842+
4843+
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags,
4844+
DEVLINK_CMD_SELFTESTS_GET);
4845+
if (!hdr)
4846+
return -EMSGSIZE;
4847+
4848+
err = -EMSGSIZE;
4849+
if (devlink_nl_put_handle(msg, devlink))
4850+
goto err_cancel_msg;
4851+
4852+
selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS);
4853+
if (!selftests)
4854+
goto err_cancel_msg;
4855+
4856+
for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1;
4857+
i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) {
4858+
if (devlink->ops->selftest_check(devlink, i, extack)) {
4859+
err = nla_put_flag(msg, i);
4860+
if (err)
4861+
goto err_cancel_msg;
4862+
}
4863+
}
4864+
4865+
nla_nest_end(msg, selftests);
4866+
genlmsg_end(msg, hdr);
4867+
return 0;
4868+
4869+
err_cancel_msg:
4870+
genlmsg_cancel(msg, hdr);
4871+
return err;
4872+
}
4873+
4874+
static int devlink_nl_cmd_selftests_get_doit(struct sk_buff *skb,
4875+
struct genl_info *info)
4876+
{
4877+
struct devlink *devlink = info->user_ptr[0];
4878+
struct sk_buff *msg;
4879+
int err;
4880+
4881+
if (!devlink->ops->selftest_check)
4882+
return -EOPNOTSUPP;
4883+
4884+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4885+
if (!msg)
4886+
return -ENOMEM;
4887+
4888+
err = devlink_nl_selftests_fill(msg, devlink, info->snd_portid,
4889+
info->snd_seq, 0, info->extack);
4890+
if (err) {
4891+
nlmsg_free(msg);
4892+
return err;
4893+
}
4894+
4895+
return genlmsg_reply(msg, info);
4896+
}
4897+
4898+
static int devlink_nl_cmd_selftests_get_dumpit(struct sk_buff *msg,
4899+
struct netlink_callback *cb)
4900+
{
4901+
struct devlink *devlink;
4902+
int start = cb->args[0];
4903+
unsigned long index;
4904+
int idx = 0;
4905+
int err = 0;
4906+
4907+
mutex_lock(&devlink_mutex);
4908+
devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) {
4909+
if (idx < start || !devlink->ops->selftest_check)
4910+
goto inc;
4911+
4912+
devl_lock(devlink);
4913+
err = devlink_nl_selftests_fill(msg, devlink,
4914+
NETLINK_CB(cb->skb).portid,
4915+
cb->nlh->nlmsg_seq, NLM_F_MULTI,
4916+
cb->extack);
4917+
devl_unlock(devlink);
4918+
if (err) {
4919+
devlink_put(devlink);
4920+
break;
4921+
}
4922+
inc:
4923+
idx++;
4924+
devlink_put(devlink);
4925+
}
4926+
mutex_unlock(&devlink_mutex);
4927+
4928+
if (err != -EMSGSIZE)
4929+
return err;
4930+
4931+
cb->args[0] = idx;
4932+
return msg->len;
4933+
}
4934+
4935+
static int devlink_selftest_result_put(struct sk_buff *skb, unsigned int id,
4936+
enum devlink_selftest_status test_status)
4937+
{
4938+
struct nlattr *result_attr;
4939+
4940+
result_attr = nla_nest_start(skb, DEVLINK_ATTR_SELFTEST_RESULT);
4941+
if (!result_attr)
4942+
return -EMSGSIZE;
4943+
4944+
if (nla_put_u32(skb, DEVLINK_ATTR_SELFTEST_RESULT_ID, id) ||
4945+
nla_put_u8(skb, DEVLINK_ATTR_SELFTEST_RESULT_STATUS,
4946+
test_status))
4947+
goto nla_put_failure;
4948+
4949+
nla_nest_end(skb, result_attr);
4950+
return 0;
4951+
4952+
nla_put_failure:
4953+
nla_nest_cancel(skb, result_attr);
4954+
return -EMSGSIZE;
4955+
}
4956+
4957+
static int devlink_nl_cmd_selftests_run(struct sk_buff *skb,
4958+
struct genl_info *info)
4959+
{
4960+
struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1];
4961+
struct devlink *devlink = info->user_ptr[0];
4962+
struct nlattr *attrs, *selftests;
4963+
struct sk_buff *msg;
4964+
void *hdr;
4965+
int err;
4966+
int i;
4967+
4968+
if (!devlink->ops->selftest_run || !devlink->ops->selftest_check)
4969+
return -EOPNOTSUPP;
4970+
4971+
if (!info->attrs[DEVLINK_ATTR_SELFTESTS]) {
4972+
NL_SET_ERR_MSG_MOD(info->extack, "selftest required");
4973+
return -EINVAL;
4974+
}
4975+
4976+
attrs = info->attrs[DEVLINK_ATTR_SELFTESTS];
4977+
4978+
err = nla_parse_nested(tb, DEVLINK_ATTR_SELFTEST_ID_MAX, attrs,
4979+
devlink_selftest_nl_policy, info->extack);
4980+
if (err < 0)
4981+
return err;
4982+
4983+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4984+
if (!msg)
4985+
return -ENOMEM;
4986+
4987+
err = -EMSGSIZE;
4988+
hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
4989+
&devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN);
4990+
if (!hdr)
4991+
goto free_msg;
4992+
4993+
if (devlink_nl_put_handle(msg, devlink))
4994+
goto genlmsg_cancel;
4995+
4996+
selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS);
4997+
if (!selftests)
4998+
goto genlmsg_cancel;
4999+
5000+
for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1;
5001+
i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) {
5002+
enum devlink_selftest_status test_status;
5003+
5004+
if (nla_get_flag(tb[i])) {
5005+
if (!devlink->ops->selftest_check(devlink, i,
5006+
info->extack)) {
5007+
if (devlink_selftest_result_put(msg, i,
5008+
DEVLINK_SELFTEST_STATUS_SKIP))
5009+
goto selftests_nest_cancel;
5010+
continue;
5011+
}
5012+
5013+
test_status = devlink->ops->selftest_run(devlink, i,
5014+
info->extack);
5015+
if (devlink_selftest_result_put(msg, i, test_status))
5016+
goto selftests_nest_cancel;
5017+
}
5018+
}
5019+
5020+
nla_nest_end(msg, selftests);
5021+
genlmsg_end(msg, hdr);
5022+
return genlmsg_reply(msg, info);
5023+
5024+
selftests_nest_cancel:
5025+
nla_nest_cancel(msg, selftests);
5026+
genlmsg_cancel:
5027+
genlmsg_cancel(msg, hdr);
5028+
free_msg:
5029+
nlmsg_free(msg);
5030+
return err;
5031+
}
5032+
48295033
static const struct devlink_param devlink_param_generic[] = {
48305034
{
48315035
.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
@@ -8969,6 +9173,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
89699173
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
89709174
[DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
89719175
[DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
9176+
[DEVLINK_ATTR_SELFTESTS] = { .type = NLA_NESTED },
89729177
};
89739178

89749179
static const struct genl_small_ops devlink_nl_ops[] = {
@@ -9328,6 +9533,17 @@ static const struct genl_small_ops devlink_nl_ops[] = {
93289533
.doit = devlink_nl_cmd_trap_policer_set_doit,
93299534
.flags = GENL_ADMIN_PERM,
93309535
},
9536+
{
9537+
.cmd = DEVLINK_CMD_SELFTESTS_GET,
9538+
.doit = devlink_nl_cmd_selftests_get_doit,
9539+
.dumpit = devlink_nl_cmd_selftests_get_dumpit
9540+
/* can be retrieved by unprivileged users */
9541+
},
9542+
{
9543+
.cmd = DEVLINK_CMD_SELFTESTS_RUN,
9544+
.doit = devlink_nl_cmd_selftests_run,
9545+
.flags = GENL_ADMIN_PERM,
9546+
},
93319547
};
93329548

93339549
static struct genl_family devlink_nl_family __ro_after_init = {

0 commit comments

Comments
 (0)