Commit f4f54166 authored by Vladyslav Tarasiuk's avatar Vladyslav Tarasiuk Committed by David S. Miller

devlink: Implement devlink health reporters on per-port basis

Add devlink-health reporter support on per-port basis.
The main difference existing devlink-health is that port reporters are
stored in per-devlink_port lists. Upon creation of such health reporter the
reference to a port it belongs to is stored in reporter struct.

Fill the port index attribute in devlink-health response to
allow devlink userspace utility to distinguish between device and port
reporters.
Signed-off-by: default avatarVladyslav Tarasiuk <vladyslavt@mellanox.com>
Reviewed-by: default avatarMoshe Shemesh <moshe@mellanox.com>
Reviewed-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bd821005
...@@ -101,6 +101,8 @@ struct devlink_port { ...@@ -101,6 +101,8 @@ struct devlink_port {
u8 attrs_set:1, u8 attrs_set:1,
switch_port:1; switch_port:1;
struct delayed_work type_warn_dw; struct delayed_work type_warn_dw;
struct list_head reporter_list;
struct mutex reporters_lock; /* Protects reporter_list */
}; };
struct devlink_sb_pool_info { struct devlink_sb_pool_info {
......
...@@ -386,19 +386,21 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id) ...@@ -386,19 +386,21 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
return NULL; return NULL;
} }
#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
#define DEVLINK_NL_FLAG_NEED_PORT BIT(1) #define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
#define DEVLINK_NL_FLAG_NEED_SB BIT(2) #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(2)
#define DEVLINK_NL_FLAG_NEED_SB BIT(3)
/* The per devlink instance lock is taken by default in the pre-doit /* The per devlink instance lock is taken by default in the pre-doit
* operation, yet several commands do not require this. The global * operation, yet several commands do not require this. The global
* devlink lock is taken and protects from disruption by user-calls. * devlink lock is taken and protects from disruption by user-calls.
*/ */
#define DEVLINK_NL_FLAG_NO_LOCK BIT(3) #define DEVLINK_NL_FLAG_NO_LOCK BIT(4)
static int devlink_nl_pre_doit(const struct genl_ops *ops, static int devlink_nl_pre_doit(const struct genl_ops *ops,
struct sk_buff *skb, struct genl_info *info) struct sk_buff *skb, struct genl_info *info)
{ {
struct devlink_port *devlink_port;
struct devlink *devlink; struct devlink *devlink;
int err; int err;
...@@ -413,14 +415,17 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, ...@@ -413,14 +415,17 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) { if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
info->user_ptr[0] = devlink; info->user_ptr[0] = devlink;
} else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) { } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
struct devlink_port *devlink_port;
devlink_port = devlink_port_get_from_info(devlink, info); devlink_port = devlink_port_get_from_info(devlink, info);
if (IS_ERR(devlink_port)) { if (IS_ERR(devlink_port)) {
err = PTR_ERR(devlink_port); err = PTR_ERR(devlink_port);
goto unlock; goto unlock;
} }
info->user_ptr[0] = devlink_port; info->user_ptr[0] = devlink_port;
} else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
info->user_ptr[0] = devlink;
devlink_port = devlink_port_get_from_info(devlink, info);
if (!IS_ERR(devlink_port))
info->user_ptr[1] = devlink_port;
} }
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
struct devlink_sb *devlink_sb; struct devlink_sb *devlink_sb;
...@@ -5287,6 +5292,7 @@ struct devlink_health_reporter { ...@@ -5287,6 +5292,7 @@ struct devlink_health_reporter {
void *priv; void *priv;
const struct devlink_health_reporter_ops *ops; const struct devlink_health_reporter_ops *ops;
struct devlink *devlink; struct devlink *devlink;
struct devlink_port *devlink_port;
struct devlink_fmsg *dump_fmsg; struct devlink_fmsg *dump_fmsg;
struct mutex dump_lock; /* lock parallel read/write from dump buffers */ struct mutex dump_lock; /* lock parallel read/write from dump buffers */
u64 graceful_period; u64 graceful_period;
...@@ -5331,6 +5337,15 @@ devlink_health_reporter_find_by_name(struct devlink *devlink, ...@@ -5331,6 +5337,15 @@ devlink_health_reporter_find_by_name(struct devlink *devlink,
reporter_name); reporter_name);
} }
static struct devlink_health_reporter *
devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
const char *reporter_name)
{
return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
&devlink_port->reporters_lock,
reporter_name);
}
static struct devlink_health_reporter * static struct devlink_health_reporter *
__devlink_health_reporter_create(struct devlink *devlink, __devlink_health_reporter_create(struct devlink *devlink,
const struct devlink_health_reporter_ops *ops, const struct devlink_health_reporter_ops *ops,
...@@ -5443,6 +5458,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg, ...@@ -5443,6 +5458,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
if (devlink_nl_put_handle(msg, devlink)) if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel; goto genlmsg_cancel;
if (reporter->devlink_port) {
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
goto genlmsg_cancel;
}
reporter_attr = nla_nest_start_noflag(msg, reporter_attr = nla_nest_start_noflag(msg,
DEVLINK_ATTR_HEALTH_REPORTER); DEVLINK_ATTR_HEALTH_REPORTER);
if (!reporter_attr) if (!reporter_attr)
...@@ -5650,17 +5669,28 @@ devlink_health_reporter_get_from_attrs(struct devlink *devlink, ...@@ -5650,17 +5669,28 @@ devlink_health_reporter_get_from_attrs(struct devlink *devlink,
struct nlattr **attrs) struct nlattr **attrs)
{ {
struct devlink_health_reporter *reporter; struct devlink_health_reporter *reporter;
struct devlink_port *devlink_port;
char *reporter_name; char *reporter_name;
if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]) if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
return NULL; return NULL;
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]); reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
mutex_lock(&devlink->reporters_lock); devlink_port = devlink_port_get_from_attrs(devlink, attrs);
reporter = devlink_health_reporter_find_by_name(devlink, reporter_name); if (IS_ERR(devlink_port)) {
if (reporter) mutex_lock(&devlink->reporters_lock);
refcount_inc(&reporter->refcount); reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
mutex_unlock(&devlink->reporters_lock); if (reporter)
refcount_inc(&reporter->refcount);
mutex_unlock(&devlink->reporters_lock);
} else {
mutex_lock(&devlink_port->reporters_lock);
reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
if (reporter)
refcount_inc(&reporter->refcount);
mutex_unlock(&devlink_port->reporters_lock);
}
return reporter; return reporter;
} }
...@@ -5748,6 +5778,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg, ...@@ -5748,6 +5778,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
struct netlink_callback *cb) struct netlink_callback *cb)
{ {
struct devlink_health_reporter *reporter; struct devlink_health_reporter *reporter;
struct devlink_port *port;
struct devlink *devlink; struct devlink *devlink;
int start = cb->args[0]; int start = cb->args[0];
int idx = 0; int idx = 0;
...@@ -5778,6 +5809,31 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg, ...@@ -5778,6 +5809,31 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
} }
mutex_unlock(&devlink->reporters_lock); mutex_unlock(&devlink->reporters_lock);
} }
list_for_each_entry(devlink, &devlink_list, list) {
if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
continue;
list_for_each_entry(port, &devlink->port_list, list) {
mutex_lock(&port->reporters_lock);
list_for_each_entry(reporter, &port->reporter_list, list) {
if (idx < start) {
idx++;
continue;
}
err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
DEVLINK_CMD_HEALTH_REPORTER_GET,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
NLM_F_MULTI);
if (err) {
mutex_unlock(&port->reporters_lock);
goto out;
}
idx++;
}
mutex_unlock(&port->reporters_lock);
}
}
out: out:
mutex_unlock(&devlink_mutex); mutex_unlock(&devlink_mutex);
...@@ -7157,7 +7213,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7157,7 +7213,7 @@ static const struct genl_ops devlink_nl_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_get_doit, .doit = devlink_nl_cmd_health_reporter_get_doit,
.dumpit = devlink_nl_cmd_health_reporter_get_dumpit, .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
}, },
...@@ -7166,7 +7222,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7166,7 +7222,7 @@ static const struct genl_ops devlink_nl_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_set_doit, .doit = devlink_nl_cmd_health_reporter_set_doit,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
}, },
{ {
...@@ -7174,7 +7230,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7174,7 +7230,7 @@ static const struct genl_ops devlink_nl_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_recover_doit, .doit = devlink_nl_cmd_health_reporter_recover_doit,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
}, },
{ {
...@@ -7182,7 +7238,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7182,7 +7238,7 @@ static const struct genl_ops devlink_nl_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_diagnose_doit, .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
}, },
{ {
...@@ -7191,7 +7247,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7191,7 +7247,7 @@ static const struct genl_ops devlink_nl_ops[] = {
GENL_DONT_VALIDATE_DUMP_STRICT, GENL_DONT_VALIDATE_DUMP_STRICT,
.dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit, .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
}, },
{ {
...@@ -7199,7 +7255,7 @@ static const struct genl_ops devlink_nl_ops[] = { ...@@ -7199,7 +7255,7 @@ static const struct genl_ops devlink_nl_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = devlink_nl_cmd_health_reporter_dump_clear_doit, .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
DEVLINK_NL_FLAG_NO_LOCK, DEVLINK_NL_FLAG_NO_LOCK,
}, },
{ {
...@@ -7459,6 +7515,8 @@ int devlink_port_register(struct devlink *devlink, ...@@ -7459,6 +7515,8 @@ int devlink_port_register(struct devlink *devlink,
list_add_tail(&devlink_port->list, &devlink->port_list); list_add_tail(&devlink_port->list, &devlink->port_list);
INIT_LIST_HEAD(&devlink_port->param_list); INIT_LIST_HEAD(&devlink_port->param_list);
mutex_unlock(&devlink->lock); mutex_unlock(&devlink->lock);
INIT_LIST_HEAD(&devlink_port->reporter_list);
mutex_init(&devlink_port->reporters_lock);
INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn); INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
devlink_port_type_warn_schedule(devlink_port); devlink_port_type_warn_schedule(devlink_port);
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
...@@ -7475,6 +7533,8 @@ void devlink_port_unregister(struct devlink_port *devlink_port) ...@@ -7475,6 +7533,8 @@ void devlink_port_unregister(struct devlink_port *devlink_port)
{ {
struct devlink *devlink = devlink_port->devlink; struct devlink *devlink = devlink_port->devlink;
WARN_ON(!list_empty(&devlink_port->reporter_list));
mutex_destroy(&devlink_port->reporters_lock);
devlink_port_type_warn_cancel(devlink_port); devlink_port_type_warn_cancel(devlink_port);
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL); devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
mutex_lock(&devlink->lock); mutex_lock(&devlink->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment