mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
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: Vladyslav Tarasiuk <vladyslavt@mellanox.com> Reviewed-by: Moshe Shemesh <moshe@mellanox.com> Reviewed-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bd8210055c
commit
f4f5416601
2 changed files with 79 additions and 17 deletions
|
@ -101,6 +101,8 @@ struct devlink_port {
|
|||
u8 attrs_set:1,
|
||||
switch_port:1;
|
||||
struct delayed_work type_warn_dw;
|
||||
struct list_head reporter_list;
|
||||
struct mutex reporters_lock; /* Protects reporter_list */
|
||||
};
|
||||
|
||||
struct devlink_sb_pool_info {
|
||||
|
|
|
@ -386,19 +386,21 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
|
||||
#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
|
||||
#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
|
||||
#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
|
||||
#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
|
||||
#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
|
||||
* operation, yet several commands do not require this. The global
|
||||
* 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,
|
||||
struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
int err;
|
||||
|
||||
|
@ -413,14 +415,17 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
|
|||
if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
|
||||
info->user_ptr[0] = devlink;
|
||||
} else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
|
||||
struct devlink_port *devlink_port;
|
||||
|
||||
devlink_port = devlink_port_get_from_info(devlink, info);
|
||||
if (IS_ERR(devlink_port)) {
|
||||
err = PTR_ERR(devlink_port);
|
||||
goto unlock;
|
||||
}
|
||||
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) {
|
||||
struct devlink_sb *devlink_sb;
|
||||
|
@ -5287,6 +5292,7 @@ struct devlink_health_reporter {
|
|||
void *priv;
|
||||
const struct devlink_health_reporter_ops *ops;
|
||||
struct devlink *devlink;
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink_fmsg *dump_fmsg;
|
||||
struct mutex dump_lock; /* lock parallel read/write from dump buffers */
|
||||
u64 graceful_period;
|
||||
|
@ -5331,6 +5337,15 @@ devlink_health_reporter_find_by_name(struct devlink *devlink,
|
|||
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 *
|
||||
__devlink_health_reporter_create(struct devlink *devlink,
|
||||
const struct devlink_health_reporter_ops *ops,
|
||||
|
@ -5443,6 +5458,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
|
|||
if (devlink_nl_put_handle(msg, devlink))
|
||||
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,
|
||||
DEVLINK_ATTR_HEALTH_REPORTER);
|
||||
if (!reporter_attr)
|
||||
|
@ -5650,17 +5669,28 @@ devlink_health_reporter_get_from_attrs(struct devlink *devlink,
|
|||
struct nlattr **attrs)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
struct devlink_port *devlink_port;
|
||||
char *reporter_name;
|
||||
|
||||
if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
|
||||
return NULL;
|
||||
|
||||
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
|
||||
mutex_lock(&devlink->reporters_lock);
|
||||
reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
|
||||
if (reporter)
|
||||
refcount_inc(&reporter->refcount);
|
||||
mutex_unlock(&devlink->reporters_lock);
|
||||
devlink_port = devlink_port_get_from_attrs(devlink, attrs);
|
||||
if (IS_ERR(devlink_port)) {
|
||||
mutex_lock(&devlink->reporters_lock);
|
||||
reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -5748,6 +5778,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
|
|||
struct netlink_callback *cb)
|
||||
{
|
||||
struct devlink_health_reporter *reporter;
|
||||
struct devlink_port *port;
|
||||
struct devlink *devlink;
|
||||
int start = cb->args[0];
|
||||
int idx = 0;
|
||||
|
@ -5778,6 +5809,31 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
|
|||
}
|
||||
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:
|
||||
mutex_unlock(&devlink_mutex);
|
||||
|
||||
|
@ -7157,7 +7213,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_health_reporter_get_doit,
|
||||
.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,
|
||||
/* can be retrieved by unprivileged users */
|
||||
},
|
||||
|
@ -7166,7 +7222,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_health_reporter_set_doit,
|
||||
.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,
|
||||
},
|
||||
{
|
||||
|
@ -7174,7 +7230,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_health_reporter_recover_doit,
|
||||
.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,
|
||||
},
|
||||
{
|
||||
|
@ -7182,7 +7238,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_health_reporter_diagnose_doit,
|
||||
.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,
|
||||
},
|
||||
{
|
||||
|
@ -7191,7 +7247,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
|
||||
.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,
|
||||
},
|
||||
{
|
||||
|
@ -7199,7 +7255,7 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
|
||||
.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,
|
||||
},
|
||||
{
|
||||
|
@ -7459,6 +7515,8 @@ int devlink_port_register(struct devlink *devlink,
|
|||
list_add_tail(&devlink_port->list, &devlink->port_list);
|
||||
INIT_LIST_HEAD(&devlink_port->param_list);
|
||||
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);
|
||||
devlink_port_type_warn_schedule(devlink_port);
|
||||
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
||||
|
@ -7475,6 +7533,8 @@ void devlink_port_unregister(struct devlink_port *devlink_port)
|
|||
{
|
||||
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_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
|
||||
mutex_lock(&devlink->lock);
|
||||
|
|
Loading…
Reference in a new issue