Commit c65dffc6 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'genetlink-provide-struct-genl_info-to-dumps'

Jakub Kicinski says:

====================
genetlink: provide struct genl_info to dumps

One of the biggest (which is not to say only) annoyances with genetlink
handling today is that doit and dumpit need some of the same information,
but it is passed to them in completely different structs.

The implementations commonly end up writing a _fill() method which
populates a message and have to pass at least 6 parameters. 3 of which
are extracted manually from request info.

After a lot of umming and ahing I decided to populate struct genl_info
for dumps, without trying to factor out only the common parts.
This makes the adoption easiest.

In the future we may add a new version of dump which takes
struct genl_info *info as the second argument, instead of
struct netlink_callback *cb. For now developers have to call
genl_info_dump(cb) to get the info.

Typical genetlink families no longer get exposed to netlink protocol
internals like pid and seq numbers.

v3:
 - correct the condition in ethtool code (patch 10)
v2: https://lore.kernel.org/all/20230810233845.2318049-1-kuba@kernel.org/
 - replace the GENL_INFO_NTF() macro with init helper
 - fix the commit messages
v1: https://lore.kernel.org/all/20230809182648.1816537-1-kuba@kernel.org/
====================

Link: https://lore.kernel.org/r/20230814214723.2924989-1-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 479b322e f946270d
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ static int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...)
static int drbd_adm_prepare(struct drbd_config_context *adm_ctx,
	struct sk_buff *skb, struct genl_info *info, unsigned flags)
{
	struct drbd_genlmsghdr *d_in = info->userhdr;
	struct drbd_genlmsghdr *d_in = genl_info_userhdr(info);
	const u8 cmd = info->genlhdr->cmd;
	int err;

@@ -1396,8 +1396,9 @@ static void drbd_suspend_al(struct drbd_device *device)

static bool should_set_defaults(struct genl_info *info)
{
	unsigned flags = ((struct drbd_genlmsghdr*)info->userhdr)->flags;
	return 0 != (flags & DRBD_GENL_F_SET_DEFAULTS);
	struct drbd_genlmsghdr *dh = genl_info_userhdr(info);

	return 0 != (dh->flags & DRBD_GENL_F_SET_DEFAULTS);
}

static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
@@ -4276,7 +4277,7 @@ static void device_to_info(struct device_info *info,
int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
{
	struct drbd_config_context adm_ctx;
	struct drbd_genlmsghdr *dh = info->userhdr;
	struct drbd_genlmsghdr *dh = genl_info_userhdr(info);
	enum drbd_ret_code retcode;

	retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
+1 −1
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ static int wg_get_device_start(struct netlink_callback *cb)
{
	struct wg_device *wg;

	wg = lookup_interface(genl_dumpit_info(cb)->attrs, cb->skb);
	wg = lookup_interface(genl_info_dump(cb)->attrs, cb->skb);
	if (IS_ERR(wg))
		return PTR_ERR(wg);
	DUMP_CTX(cb)->wg = wg;
+69 −7
Original line number Diff line number Diff line
@@ -93,9 +93,9 @@ struct genl_family {
 * struct genl_info - receiving information
 * @snd_seq: sending sequence number
 * @snd_portid: netlink portid of sender
 * @family: generic netlink family
 * @nlhdr: netlink message header
 * @genlhdr: generic netlink message header
 * @userhdr: user specific header
 * @attrs: netlink attributes
 * @_net: network namespace
 * @user_ptr: user pointers
@@ -104,16 +104,16 @@ struct genl_family {
struct genl_info {
	u32			snd_seq;
	u32			snd_portid;
	struct nlmsghdr *	nlhdr;
	const struct genl_family *family;
	const struct nlmsghdr *	nlhdr;
	struct genlmsghdr *	genlhdr;
	void *			userhdr;
	struct nlattr **	attrs;
	possible_net_t		_net;
	void *			user_ptr[2];
	struct netlink_ext_ack *extack;
};

static inline struct net *genl_info_net(struct genl_info *info)
static inline struct net *genl_info_net(const struct genl_info *info)
{
	return read_pnet(&info->_net);
}
@@ -123,6 +123,11 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
	write_pnet(&info->_net, net);
}

static inline void *genl_info_userhdr(const struct genl_info *info)
{
	return (u8 *)info->genlhdr + GENL_HDRLEN;
}

#define GENL_SET_ERR_MSG(info, msg) NL_SET_ERR_MSG((info)->extack, msg)

#define GENL_SET_ERR_MSG_FMT(info, msg, args...) \
@@ -244,14 +249,13 @@ struct genl_split_ops {

/**
 * struct genl_dumpit_info - info that is available during dumpit op call
 * @family: generic netlink family - for internal genl code usage
 * @op: generic netlink ops - for internal genl code usage
 * @attrs: netlink attributes
 * @info: struct genl_info describing the request
 */
struct genl_dumpit_info {
	const struct genl_family *family;
	struct genl_split_ops op;
	struct nlattr **attrs;
	struct genl_info info;
};

static inline const struct genl_dumpit_info *
@@ -260,6 +264,38 @@ genl_dumpit_info(struct netlink_callback *cb)
	return cb->data;
}

static inline const struct genl_info *
genl_info_dump(struct netlink_callback *cb)
{
	return &genl_dumpit_info(cb)->info;
}

/**
 * genl_info_init_ntf() - initialize genl_info for notifications
 * @info:   genl_info struct to set up
 * @family: pointer to the genetlink family
 * @cmd:    command to be used in the notification
 *
 * Initialize a locally declared struct genl_info to pass to various APIs.
 * Intended to be used when creating notifications.
 */
static inline void
genl_info_init_ntf(struct genl_info *info, const struct genl_family *family,
		   u8 cmd)
{
	struct genlmsghdr *hdr = (void *) &info->user_ptr[0];

	memset(info, 0, sizeof(*info));
	info->family = family;
	info->genlhdr = hdr;
	hdr->cmd = cmd;
}

static inline bool genl_info_is_ntf(const struct genl_info *info)
{
	return !info->nlhdr;
}

int genl_register_family(struct genl_family *family);
int genl_unregister_family(const struct genl_family *family);
void genl_notify(const struct genl_family *family, struct sk_buff *skb,
@@ -268,6 +304,32 @@ void genl_notify(const struct genl_family *family, struct sk_buff *skb,
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
		  const struct genl_family *family, int flags, u8 cmd);

static inline void *
__genlmsg_iput(struct sk_buff *skb, const struct genl_info *info, int flags)
{
	return genlmsg_put(skb, info->snd_portid, info->snd_seq, info->family,
			   flags, info->genlhdr->cmd);
}

/**
 * genlmsg_iput - start genetlink message based on genl_info
 * @skb: skb in which message header will be placed
 * @info: genl_info as provided to do/dump handlers
 *
 * Convenience wrapper which starts a genetlink message based on
 * information in user request. @info should be either the struct passed
 * by genetlink core to do/dump handlers (when constructing replies to
 * such requests) or a struct initialized by genl_info_init_ntf()
 * when constructing notifications.
 *
 * Returns pointer to new genetlink header.
 */
static inline void *
genlmsg_iput(struct sk_buff *skb, const struct genl_info *info)
{
	return __genlmsg_iput(skb, info, 0);
}

/**
 * genlmsg_nlhdr - Obtain netlink header from user specified header
 * @user_hdr: user header as returned from genlmsg_put()
+8 −9
Original line number Diff line number Diff line
@@ -10,11 +10,11 @@

static int
netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp,
		   u32 portid, u32 seq, int flags, u32 cmd)
		   const struct genl_info *info)
{
	void *hdr;

	hdr = genlmsg_put(rsp, portid, seq, &netdev_nl_family, flags, cmd);
	hdr = genlmsg_iput(rsp, info);
	if (!hdr)
		return -EMSGSIZE;

@@ -41,17 +41,20 @@ netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp,
static void
netdev_genl_dev_notify(struct net_device *netdev, int cmd)
{
	struct genl_info info;
	struct sk_buff *ntf;

	if (!genl_has_listeners(&netdev_nl_family, dev_net(netdev),
				NETDEV_NLGRP_MGMT))
		return;

	genl_info_init_ntf(&info, &netdev_nl_family, cmd);

	ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!ntf)
		return;

	if (netdev_nl_dev_fill(netdev, ntf, 0, 0, 0, cmd)) {
	if (netdev_nl_dev_fill(netdev, ntf, &info)) {
		nlmsg_free(ntf);
		return;
	}
@@ -80,8 +83,7 @@ int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info)

	netdev = __dev_get_by_index(genl_info_net(info), ifindex);
	if (netdev)
		err = netdev_nl_dev_fill(netdev, rsp, info->snd_portid,
					 info->snd_seq, 0, info->genlhdr->cmd);
		err = netdev_nl_dev_fill(netdev, rsp, info);
	else
		err = -ENODEV;

@@ -105,10 +107,7 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)

	rtnl_lock();
	for_each_netdev_dump(net, netdev, cb->args[0]) {
		err = netdev_nl_dev_fill(netdev, skb,
					 NETLINK_CB(cb->skb).portid,
					 cb->nlh->nlmsg_seq, 0,
					 NETDEV_CMD_DEV_GET);
		err = netdev_nl_dev_fill(netdev, skb, genl_info_dump(cb));
		if (err < 0)
			break;
	}
+2 −2
Original line number Diff line number Diff line
@@ -390,7 +390,7 @@ static int devlink_nl_health_reporter_get_dump_one(struct sk_buff *msg,
						   int flags)
{
	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
	const struct genl_info *info = genl_info_dump(cb);
	struct devlink_health_reporter *reporter;
	unsigned long port_index_end = ULONG_MAX;
	struct nlattr **attrs = info->attrs;
@@ -1264,7 +1264,7 @@ int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
static struct devlink_health_reporter *
devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
{
	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
	const struct genl_info *info = genl_info_dump(cb);
	struct devlink_health_reporter *reporter;
	struct nlattr **attrs = info->attrs;
	struct devlink *devlink;
Loading