Commit 07f3af66 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

devlink: add by-instance dump infra



Most dumpit implementations walk the devlink instances.
This requires careful lock taking and reference dropping.
Factor the loop out and provide just a callback to handle
a single instance dump.

Convert one user as an example, other users converted
in the next change.

Slightly inspired by ethtool netlink code.

Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e4d5015b
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -122,6 +122,11 @@ struct devlink_nl_dump_state {
	};
};

struct devlink_gen_cmd {
	int (*dump_one)(struct sk_buff *msg, struct devlink *devlink,
			struct netlink_callback *cb);
};

/* Iterate over registered devlink instances for devlink dump.
 * devlink_put() needs to be called for each iterated devlink pointer
 * in loop body in order to release the reference.
@@ -140,6 +145,9 @@ struct devlink *devlink_get_from_attrs(struct net *net, struct nlattr **attrs);
void devlink_notify_unregister(struct devlink *devlink);
void devlink_notify_register(struct devlink *devlink);

int devlink_nl_instance_iter_dump(struct sk_buff *msg,
				  struct netlink_callback *cb);

static inline struct devlink_nl_dump_state *
devlink_dump_state(struct netlink_callback *cb)
{
@@ -175,6 +183,8 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info);
void devlink_linecard_put(struct devlink_linecard *linecard);

/* Rates */
extern const struct devlink_gen_cmd devl_gen_rate_get;

struct devlink_rate *
devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info);
struct devlink_rate *
+24 −31
Original line number Diff line number Diff line
@@ -1219,18 +1219,15 @@ static void devlink_rate_notify(struct devlink_rate *devlink_rate,
				0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
}

static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg,
static int
devlink_nl_cmd_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
				 struct netlink_callback *cb)
{
	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
	struct devlink *devlink;
	int err = 0;

	devlink_dump_for_each_instance_get(msg, state, devlink) {
	struct devlink_rate *devlink_rate;
	int idx = 0;
	int err = 0;

		devl_lock(devlink);
	list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
		enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
		u32 id = NETLINK_CB(cb->skb).portid;
@@ -1243,23 +1240,19 @@ static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg,
					   cb->nlh->nlmsg_seq,
					   NLM_F_MULTI, NULL);
		if (err) {
				devl_unlock(devlink);
				devlink_put(devlink);
			state->idx = idx;
				goto out;
			break;
		}
		idx++;
	}
		devl_unlock(devlink);
		devlink_put(devlink);
	}
out:
	if (err != -EMSGSIZE)
		return err;

	return msg->len;
	return err;
}

const struct devlink_gen_cmd devl_gen_rate_get = {
	.dump_one		= devlink_nl_cmd_rate_get_dump_one,
};

static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,
					struct genl_info *info)
{
@@ -9130,7 +9123,7 @@ const struct genl_small_ops devlink_nl_ops[56] = {
	{
		.cmd = DEVLINK_CMD_RATE_GET,
		.doit = devlink_nl_cmd_rate_get_doit,
		.dumpit = devlink_nl_cmd_rate_get_dumpit,
		.dumpit = devlink_nl_instance_iter_dump,
		.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
		/* can be retrieved by unprivileged users */
	},
+34 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */

#include <net/genetlink.h>
#include <net/sock.h>

#include "devl_internal.h"

@@ -177,6 +178,39 @@ static void devlink_nl_post_doit(const struct genl_split_ops *ops,
	devlink_put(devlink);
}

static const struct devlink_gen_cmd *devl_gen_cmds[] = {
	[DEVLINK_CMD_RATE_GET]		= &devl_gen_rate_get,
};

int devlink_nl_instance_iter_dump(struct sk_buff *msg,
				  struct netlink_callback *cb)
{
	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
	const struct devlink_gen_cmd *cmd;
	struct devlink *devlink;
	int err = 0;

	cmd = devl_gen_cmds[info->op.cmd];

	devlink_dump_for_each_instance_get(msg, state, devlink) {
		devl_lock(devlink);
		err = cmd->dump_one(msg, devlink, cb);
		devl_unlock(devlink);
		devlink_put(devlink);

		if (err)
			break;

		/* restart sub-object walk for the next instance */
		state->idx = 0;
	}

	if (err != -EMSGSIZE)
		return err;
	return msg->len;
}

struct genl_family devlink_nl_family __ro_after_init = {
	.name		= DEVLINK_GENL_NAME,
	.version	= DEVLINK_GENL_VERSION,