Skip to content

Commit

Permalink
devlink: introduce framework for selftests
Browse files Browse the repository at this point in the history
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: To query the supported selftests
by the driver.
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: Michael Chan <michael.chan@broadcom.com>
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
  • Loading branch information
vikasbrcm authored and intel-lab-lkp committed Jul 7, 2022
1 parent cf21b35 commit 5c0b96e
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 0 deletions.
34 changes: 34 additions & 0 deletions Documentation/networking/devlink/devlink-selftests.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
=================
Devlink Selftests
=================

The ``devlink-selftests`` API allows executing selftests on the device.

Tests Mask
==========
The ``devlink-selftests`` command should be run with a mask indicating
the tests to be executed.

Tests Description
=================
The following is a list of tests that drivers may execute.

.. list-table:: List of tests
:widths: 5 90

* - Name
- Description
* - ``DEVLINK_SELFTEST_FLASH``
- Runs a flash test on the device.

example usage
-------------

.. code:: shell
# Query selftests supported on the device
$ devlink dev selftests show DEV
# Executes selftests on the device
$ devlink dev selftests run DEV test {flash | all}
30 changes: 30 additions & 0 deletions include/net/devlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,18 @@ enum {
DEVLINK_F_RELOAD = 1UL << 0,
};

#define DEVLINK_SELFTEST_FLASH_TEST_NAME "flash"

static inline const char *devlink_selftest_name(int test)
{
switch (test) {
case DEVLINK_SELFTEST_FLASH_BIT:
return DEVLINK_SELFTEST_FLASH_TEST_NAME;
default:
return "unknown";
}
}

struct devlink_ops {
/**
* @supported_flash_update_params:
Expand Down Expand Up @@ -1509,6 +1521,24 @@ struct devlink_ops {
struct devlink_rate *parent,
void *priv_child, void *priv_parent,
struct netlink_ext_ack *extack);
/**
* selftests_show() - Shows selftests supported by device
* @devlink: Devlink instance
* @extack: extack for reporting error messages
*
* Return: test mask supported by driver
*/
u32 (*selftests_show)(struct devlink *devlink,
struct netlink_ext_ack *extack);
/**
* selftests_run() - Runs selftests
* @devlink: Devlink instance
* @tests_mask: tests to be run by driver
* @results: test results by driver
* @extack: extack for reporting error messages
*/
void (*selftests_run)(struct devlink *devlink, u32 tests_mask,
u8 *results, struct netlink_ext_ack *extack);
};

void *devlink_priv(struct devlink *devlink);
Expand Down
26 changes: 26 additions & 0 deletions include/uapi/linux/devlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ enum devlink_command {
DEVLINK_CMD_LINECARD_NEW,
DEVLINK_CMD_LINECARD_DEL,

DEVLINK_CMD_SELFTESTS_SHOW,
DEVLINK_CMD_SELFTESTS_RUN,

/* add new commands above here */
__DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
Expand Down Expand Up @@ -276,6 +279,25 @@ enum {
#define DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS \
(_BITUL(__DEVLINK_FLASH_OVERWRITE_MAX_BIT) - 1)

/* Commonly used test cases */
enum {
DEVLINK_SELFTEST_FLASH_BIT,

__DEVLINK_SELFTEST_MAX_BIT,
DEVLINK_SELFTEST_MAX_BIT = __DEVLINK_SELFTEST_MAX_BIT - 1
};

#define DEVLINK_SELFTEST_FLASH _BITUL(DEVLINK_SELFTEST_FLASH_BIT)

#define DEVLINK_SELFTESTS_MASK \
(_BITUL(__DEVLINK_SELFTEST_MAX_BIT) - 1)

enum {
DEVLINK_SELFTEST_SKIP,
DEVLINK_SELFTEST_PASS,
DEVLINK_SELFTEST_FAIL
};

/**
* enum devlink_trap_action - Packet trap action.
* @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not
Expand Down Expand Up @@ -576,6 +598,10 @@ enum devlink_attr {
DEVLINK_ATTR_LINECARD_TYPE, /* string */
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */

DEVLINK_ATTR_SELFTESTS_MASK, /* u32 */
DEVLINK_ATTR_TEST_RESULT, /* nested */
DEVLINK_ATTR_TEST_NAME, /* string */
DEVLINK_ATTR_TEST_RESULT_VAL, /* u8 */
/* add new attributes above here, update the policy in devlink.c */

__DEVLINK_ATTR_MAX,
Expand Down
144 changes: 144 additions & 0 deletions net/core/devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -4794,6 +4794,136 @@ static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
return ret;
}

static int devlink_selftest_name_put(struct sk_buff *skb, int test)
{
const char *name = devlink_selftest_name(test);
if (nla_put_string(skb, DEVLINK_ATTR_TEST_NAME, name))
return -EMSGSIZE;

return 0;
}

static int devlink_nl_cmd_selftests_show(struct sk_buff *skb,
struct genl_info *info)
{
struct devlink *devlink = info->user_ptr[0];
struct sk_buff *msg;
unsigned long tests;
int err = 0;
void *hdr;
int test;

if (!devlink->ops->selftests_show)
return -EOPNOTSUPP;

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;

hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
&devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_SHOW);
if (!hdr)
goto free_msg;

if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;

tests = devlink->ops->selftests_show(devlink, info->extack);

for_each_set_bit(test, &tests, __DEVLINK_SELFTEST_MAX_BIT) {
err = devlink_selftest_name_put(msg, test);
if (err)
goto genlmsg_cancel;
}

genlmsg_end(msg, hdr);

return genlmsg_reply(msg, info);

genlmsg_cancel:
genlmsg_cancel(msg, hdr);
free_msg:
nlmsg_free(msg);
return err;
}

static int devlink_selftest_result_put(struct sk_buff *skb, int test,
u8 result)
{
const char *name = devlink_selftest_name(test);
struct nlattr *result_attr;

result_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_TEST_RESULT);
if (!result_attr)
return -EMSGSIZE;

if (nla_put_string(skb, DEVLINK_ATTR_TEST_NAME, name) ||
nla_put_u8(skb, DEVLINK_ATTR_TEST_RESULT_VAL, result))
goto nla_put_failure;

nla_nest_end(skb, result_attr);

return 0;

nla_put_failure:
nla_nest_cancel(skb, result_attr);
return -EMSGSIZE;
}

static int devlink_nl_cmd_selftests_run(struct sk_buff *skb,
struct genl_info *info)
{
u8 test_results[DEVLINK_SELFTEST_MAX_BIT + 1] = {};
struct devlink *devlink = info->user_ptr[0];
unsigned long tests;
struct sk_buff *msg;
u32 tests_mask;
void *hdr;
int err = 0;
int test;

if (!devlink->ops->selftests_run)
return -EOPNOTSUPP;

if (!info->attrs[DEVLINK_ATTR_SELFTESTS_MASK])
return -EINVAL;

msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;

hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
&devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN);
if (!hdr)
goto free_msg;

if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;

tests_mask = nla_get_u32(info->attrs[DEVLINK_ATTR_SELFTESTS_MASK]);

devlink->ops->selftests_run(devlink, tests_mask, test_results,
info->extack);
tests = tests_mask;

for_each_set_bit(test, &tests, __DEVLINK_SELFTEST_MAX_BIT) {
err = devlink_selftest_result_put(msg, test,
test_results[test]);
if (err)
goto genlmsg_cancel;
}

genlmsg_end(msg, hdr);

return genlmsg_reply(msg, info);

genlmsg_cancel:
genlmsg_cancel(msg, hdr);
free_msg:
nlmsg_free(msg);
return err;
}

static const struct devlink_param devlink_param_generic[] = {
{
.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
Expand Down Expand Up @@ -9000,6 +9130,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
[DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
[DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
[DEVLINK_ATTR_SELFTESTS_MASK] = NLA_POLICY_MASK(NLA_U32,
DEVLINK_SELFTESTS_MASK),
};

static const struct genl_small_ops devlink_nl_ops[] = {
Expand Down Expand Up @@ -9361,6 +9493,18 @@ static const struct genl_small_ops devlink_nl_ops[] = {
.doit = devlink_nl_cmd_trap_policer_set_doit,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = DEVLINK_CMD_SELFTESTS_SHOW,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_selftests_show,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = DEVLINK_CMD_SELFTESTS_RUN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_selftests_run,
.flags = GENL_ADMIN_PERM,
},
};

static struct genl_family devlink_nl_family __ro_after_init = {
Expand Down

0 comments on commit 5c0b96e

Please sign in to comment.