Re: [PATCH net-next v2 1/3] devlink: introduce framework for selftests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jiri,

On Tue, Jul 12, 2022 at 11:58 AM Jiri Pirko <jiri@xxxxxxxxxx> wrote:
>
> Tue, Jul 12, 2022 at 08:16:11AM CEST, vikas.gupta@xxxxxxxxxxxx wrote:
> >Hi Jiri,
> >
> >On Mon, Jul 11, 2022 at 6:10 PM Jiri Pirko <jiri@xxxxxxxxxx> wrote:
> >
> >> Thu, Jul 07, 2022 at 08:29:48PM CEST, vikas.gupta@xxxxxxxxxxxx wrote:
> >> >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@xxxxxxxxxxxx>
> >> >Reviewed-by: Michael Chan <michael.chan@xxxxxxxxxxxx>
> >> >Reviewed-by: Andy Gospodarek <andrew.gospodarek@xxxxxxxxxxxx>
> >> >---
> >> > .../networking/devlink/devlink-selftests.rst  |  34 +++++
> >> > include/net/devlink.h                         |  30 ++++
> >> > include/uapi/linux/devlink.h                  |  26 ++++
> >> > net/core/devlink.c                            | 144 ++++++++++++++++++
> >> > 4 files changed, 234 insertions(+)
> >> > create mode 100644 Documentation/networking/devlink/devlink-selftests.rst
> >> >
> >> >diff --git a/Documentation/networking/devlink/devlink-selftests.rst
> >> b/Documentation/networking/devlink/devlink-selftests.rst
> >> >new file mode 100644
> >> >index 000000000000..796d38f77038
> >> >--- /dev/null
> >> >+++ b/Documentation/networking/devlink/devlink-selftests.rst
> >> >@@ -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}
> >> >diff --git a/include/net/devlink.h b/include/net/devlink.h
> >> >index 2a2a2a0c93f7..cb7c378cf720 100644
> >> >--- a/include/net/devlink.h
> >> >+++ b/include/net/devlink.h
> >> >@@ -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)
> >>
> >> I don't understand why this is needed. Better not to expose string to
> >> the user. Just have it as well defined attr.
> >
> >
> > OK. Will remove this function and corresponding attr
> >DEVLINK_ATTR_TEST_NAME added in this patch.
> >
> >
> >
> >
> >>
> >> >+{
> >> >+      switch (test) {
> >> >+      case DEVLINK_SELFTEST_FLASH_BIT:
> >> >+              return DEVLINK_SELFTEST_FLASH_TEST_NAME;
> >> >+      default:
> >> >+              return "unknown";
> >> >+      }
> >> >+}
> >> >+
> >> > struct devlink_ops {
> >> >       /**
> >> >        * @supported_flash_update_params:
> >> >@@ -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);
> >> >diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
> >> >index b3d40a5d72ff..1dba262328b9 100644
> >> >--- a/include/uapi/linux/devlink.h
> >> >+++ b/include/uapi/linux/devlink.h
> >> >@@ -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
> >> >@@ -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
> >> >@@ -576,6 +598,10 @@ enum devlink_attr {
> >> >       DEVLINK_ATTR_LINECARD_TYPE,             /* string */
> >> >       DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES,  /* nested */
> >> >
> >> >+      DEVLINK_ATTR_SELFTESTS_MASK,            /* u32 */
> >>
> >> I don't see why this is u32 bitset. Just have one attr per test
> >> (NLA_FLAG) in a nested attr instead.
> >>
> >
> >As per your suggestion, for an example it should be like as below
> >
> >        DEVLINK_ATTR_SELFTESTS,                 /* nested */
> >
> >        DEVLINK_ATTR_SELFTESTS_SOMETEST1            /* flag */
> >
> >        DEVLINK_ATTR_SELFTESTS_SOMETEST2           /* flag */
>
> Yeah, but have the flags in separate enum, no need to pullute the
> devlink_attr enum by them.
>
>
> >
> >....    <SOME MORE TESTS>
> >
> >.....
> >
> >        DEVLINK_ATTR_SLEFTESTS_RESULT_VAL,      /* u8 */
> >
> >
> >
> > If we have this way then we need to have a mapping (probably a function)
> >for drivers to tell them what tests need to be executed based on the flags
> >that are set.
> > Does this look OK?
> >  The rationale behind choosing a mask is that we could directly pass the
> >mask-value to the drivers.
>
> If you have separate enum, you can use the attrs as bits internally in
> kernel. Add a helper that would help the driver to work with it.
> Pass a struct containing u32 (or u8) not to drivers. Once there are more
> tests than that, this structure can be easily extended and the helpers
> changed. This would make this scalable. No need for UAPI change or even
> internel driver api change.

As per your suggestion, selftest attributes can be declared in separate
enum as below

enum {

        DEVLINK_SELFTEST_SOMETEST,         /* flag */

        DEVLINK_SELFTEST_SOMETEST1,

        DEVLINK_SELFTEST_SOMETEST2,

....

......

        __DEVLINK_SELFTEST_MAX,

        DEVLINK_SELFTEST_MAX = __DEVLINK_SELFTEST_MAX - 1

};
Below  examples could be the flow of parameters/data from user to
kernel and vice-versa


Kernel to user for show command . Users can know what all tests are
supported by the driver. A return from kernel to user.
______
|NEST |
|_____ |TEST1|TEST4|TEST7|...


User to kernel to execute test: If user wants to execute test4, test8, test1...
______
|NEST |
|_____ |TEST4|TEST8|TEST1|...


Result Kernel to user execute test RES(u8)
______
|NEST |
|_____ |RES4|RES8|RES1|...

Results are populated in the same order as the user passed the TESTs
flags. Does the above result format from kernel to user look OK ?
Else we need to have below way to form a result format, a nest should
be made for <test_flag,
result> but since test flags are in different enum other than
devlink_attr and RES being part of devlink_attr, I believe it's not
good practice to make the below structure.
______
|NEST |
|_____ | TEST4, RES4|TEST8,RES8|TEST1,RES1|...

Let me know if my understanding is correct.

Thanks,
Vikas

>
>
> >
> >
> >>
> >>
> >>
> >> >+      DEVLINK_ATTR_TEST_RESULT,               /* nested */
> >> >+      DEVLINK_ATTR_TEST_NAME,                 /* string */
> >> >+      DEVLINK_ATTR_TEST_RESULT_VAL,           /* u8 */
> >>
> >> Could you maintain the same "namespace" for all attrs related to
> >> selftests?
> >>
> >
> >Will fix it.
> >
> >
> >>
> >> >       /* add new attributes above here, update the policy in devlink.c */
> >> >
> >> >       __DEVLINK_ATTR_MAX,
> >> >diff --git a/net/core/devlink.c b/net/core/devlink.c
> >> >index db61f3a341cb..0b7341ab6379 100644
> >> >--- a/net/core/devlink.c
> >> >+++ b/net/core/devlink.c
> >> >@@ -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,
> >>
> >> Why don't you run it 1 by 1 and fill up the NL message 1 by 1 too?
> >>
> >>      I`ll consider it in the next patch set.
>
> Please do. This array of results returned from driver looks sloppy.
>
>
> >
> >
> >>
> >> >+                                  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,
> >> >@@ -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[] = {
> >> >@@ -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,
> >>
> >> Why don't dump?
> >>
> >
> >  I`ll add a dump in the next patchset.
> >
> >Thanks,
> >Vikas
> >
> >
> >>
> >>
> >> >+              .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 = {
> >> >--
> >> >2.31.1
> >> >
> >>
> >>
> >>
>
>

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux