Re: [PATCH net-next 04/16] devlink: Add reload stats

From: Jakub Kicinski
Date: Thu Oct 01 2020 - 17:25:25 EST


On Thu, 1 Oct 2020 16:59:07 +0300 Moshe Shemesh wrote:
> Add reload stats to hold the history per reload action type and limit.
>
> For example, the number of times fw_activate has been performed on this
> device since the driver module was added or if the firmware activation
> was performed with or without reset.
>
> Add devlink notification on stats update.
>
> Expose devlink reload stats to the user through devlink dev get command.
>
> Examples:
> $ devlink dev show
> pci/0000:82:00.0:
> stats:
> reload_stats:
> driver_reinit 2
> fw_activate 1
> fw_activate_no_reset 0
> pci/0000:82:00.1:
> stats:
> reload_stats:
> driver_reinit 1
> fw_activate 0
> fw_activate_no_reset 0
>
> $ devlink dev show -jp
> {
> "dev": {
> "pci/0000:82:00.0": {
> "stats": {
> "reload_stats": [ {
> "driver_reinit": 2
> },{
> "fw_activate": 1
> },{
> "fw_activate_no_reset": 0
> } ]
> }
> },
> "pci/0000:82:00.1": {
> "stats": {
> "reload_stats": [ {
> "driver_reinit": 1
> },{
> "fw_activate": 0
> },{
> "fw_activate_no_reset": 0
> } ]

This will be a question to the user space part but IDK why every stat
is in a separate object?

Instead of doing an array of objects -> [ {}, {}, {} ]
make "reload_stats" itself an object.

> }
> }
> }
> }
>
> Signed-off-by: Moshe Shemesh <moshe@xxxxxxxxxxxx>

Minor nits, looks good overall:

Reviewed-by: Jakub Kicinski <kuba@xxxxxxxxxx>

> diff --git a/net/core/devlink.c b/net/core/devlink.c
> index 6de7d6aa6ed1..05516f1e4c3e 100644
> --- a/net/core/devlink.c
> +++ b/net/core/devlink.c
> @@ -500,10 +500,68 @@ devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_l
> return test_bit(limit, &devlink->ops->reload_limits);
> }
>
> +static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_action action,
> + enum devlink_reload_limit limit, u32 value)
> +{
> + struct nlattr *reload_stats_entry;
> +
> + reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY);
> + if (!reload_stats_entry)
> + return -EMSGSIZE;
> +
> + if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, action))
> + goto nla_put_failure;
> + if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_LIMIT, limit))
> + goto nla_put_failure;
> + if (nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))
> + goto nla_put_failure;

nit: it's common to combine such expressions into:

if (nla_put...() ||
nla_put...() ||
nla_put...())
goto ...;

> + nla_nest_end(msg, reload_stats_entry);
> + return 0;
> +
> +nla_put_failure:
> + nla_nest_cancel(msg, reload_stats_entry);
> + return -EMSGSIZE;
> +}
> +
> +static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink)
> +{
> + struct nlattr *reload_stats_attr;
> + int i, j, stat_idx;
> + u32 value;
> +
> + reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS);
> +
> + if (!reload_stats_attr)
> + return -EMSGSIZE;
> +
> + for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) {
> + if (j != DEVLINK_RELOAD_LIMIT_UNSPEC &&

Why check this? It can't be supported.

> + !devlink_reload_limit_is_supported(devlink, j))
> + continue;
> + for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) {
> + if (!devlink_reload_action_is_supported(devlink, i) ||
> + devlink_reload_combination_is_invalid(i, j))

Again, devlink instance would not have been registered with invalid
combinations, right?

> + continue;
> +
> + stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i;
> + value = devlink->reload_stats[stat_idx];
> + if (devlink_reload_stat_put(msg, i, j, value))
> + goto nla_put_failure;
> + }
> + }
> + nla_nest_end(msg, reload_stats_attr);
> + return 0;
> +
> +nla_put_failure:
> + nla_nest_cancel(msg, reload_stats_attr);
> + return -EMSGSIZE;
> +}


> @@ -3004,6 +3072,34 @@ bool devlink_is_reload_failed(const struct devlink *devlink)
> }
> EXPORT_SYMBOL_GPL(devlink_is_reload_failed);
>
> +static void
> +__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats,
> + enum devlink_reload_limit limit, unsigned long actions_performed)

> + for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {

nit: for_each_set_bit

> + if (!test_bit(action, &actions_performed))
> + continue;
> + stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action;
> + reload_stats[stat_idx]++;
> + }
> + devlink_notify(devlink, DEVLINK_CMD_NEW);
> +}