Commit 20b0b53a authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

genetlink: introduce split op representation



We currently have two forms of operations - small ops and "full" ops
(or just ops). The former does not have pointers for some of the less
commonly used features (namely dump start/done and policy).

The "full" ops, however, still don't contain all the necessary
information. In particular the policy is per command ID, while
do and dump often accept different attributes. It's also not
possible to define different pre_doit and post_doit callbacks
for different commands within the family.

At the same time a lot of commands do not support dumping and
therefore all the dump-related information is wasted space.

Create a new command representation which can hold info about
a do implementation or a dump implementation, but not both at
the same time.

Use this new representation on the command execution path
(genl_family_rcv_msg) as we either run a do or a dump and
don't have to create a "full" op there.

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7c3eaa02
Loading
Loading
Loading
Loading
+56 −4
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ struct genl_multicast_group {
	u8			flags;
};

struct genl_ops;
struct genl_split_ops;
struct genl_info;

/**
@@ -66,10 +66,10 @@ struct genl_family {
	u8			n_mcgrps;
	u8			resv_start_op;
	const struct nla_policy *policy;
	int			(*pre_doit)(const struct genl_ops *ops,
	int			(*pre_doit)(const struct genl_split_ops *ops,
					    struct sk_buff *skb,
					    struct genl_info *info);
	void			(*post_doit)(const struct genl_ops *ops,
	void			(*post_doit)(const struct genl_split_ops *ops,
					     struct sk_buff *skb,
					     struct genl_info *info);
	const struct genl_ops *	ops;
@@ -182,6 +182,58 @@ struct genl_ops {
	u8			validate;
};

/**
 * struct genl_split_ops - generic netlink operations (do/dump split version)
 * @cmd: command identifier
 * @internal_flags: flags used by the family
 * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM)
 * @validate: validation flags from enum genl_validate_flags
 * @policy: netlink policy (takes precedence over family policy)
 * @maxattr: maximum number of attributes supported
 *
 * Do callbacks:
 * @pre_doit: called before an operation's @doit callback, it may
 *	do additional, common, filtering and return an error
 * @doit: standard command callback
 * @post_doit: called after an operation's @doit callback, it may
 *	undo operations done by pre_doit, for example release locks
 *
 * Dump callbacks:
 * @start: start callback for dumps
 * @dumpit: callback for dumpers
 * @done: completion callback for dumps
 *
 * Do callbacks can be used if %GENL_CMD_CAP_DO is set in @flags.
 * Dump callbacks can be used if %GENL_CMD_CAP_DUMP is set in @flags.
 * Exactly one of those flags must be set.
 */
struct genl_split_ops {
	union {
		struct {
			int (*pre_doit)(const struct genl_split_ops *ops,
					struct sk_buff *skb,
					struct genl_info *info);
			int (*doit)(struct sk_buff *skb,
				    struct genl_info *info);
			void (*post_doit)(const struct genl_split_ops *ops,
					  struct sk_buff *skb,
					  struct genl_info *info);
		};
		struct {
			int (*start)(struct netlink_callback *cb);
			int (*dumpit)(struct sk_buff *skb,
				      struct netlink_callback *cb);
			int (*done)(struct netlink_callback *cb);
		};
	};
	const struct nla_policy *policy;
	unsigned int		maxattr;
	u8			cmd;
	u8			internal_flags;
	u8			flags;
	u8			validate;
};

/**
 * struct genl_dumpit_info - info that is available during dumpit op call
 * @family: generic netlink family - for internal genl code usage
@@ -190,7 +242,7 @@ struct genl_ops {
 */
struct genl_dumpit_info {
	const struct genl_family *family;
	struct genl_ops op;
	struct genl_split_ops op;
	struct nlattr **attrs;
};

+4 −2
Original line number Diff line number Diff line
@@ -1267,7 +1267,8 @@ batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net,
 *
 * Return: 0 on success or negative error number in case of failure
 */
static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
static int batadv_pre_doit(const struct genl_split_ops *ops,
			   struct sk_buff *skb,
			   struct genl_info *info)
{
	struct net *net = genl_info_net(info);
@@ -1332,7 +1333,8 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
 * @skb: Netlink message with request data
 * @info: receiver information
 */
static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static void batadv_post_doit(const struct genl_split_ops *ops,
			     struct sk_buff *skb,
			     struct genl_info *info)
{
	struct batadv_hard_iface *hard_iface;
+2 −2
Original line number Diff line number Diff line
@@ -770,7 +770,7 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
#define DEVLINK_NL_FLAG_NEED_RATE_NODE		BIT(3)
#define DEVLINK_NL_FLAG_NEED_LINECARD		BIT(4)

static int devlink_nl_pre_doit(const struct genl_ops *ops,
static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
			       struct sk_buff *skb, struct genl_info *info)
{
	struct devlink_linecard *linecard;
@@ -828,7 +828,7 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
	return err;
}

static void devlink_nl_post_doit(const struct genl_ops *ops,
static void devlink_nl_post_doit(const struct genl_split_ops *ops,
				 struct sk_buff *skb, struct genl_info *info)
{
	struct devlink_linecard *linecard;
+2 −2
Original line number Diff line number Diff line
@@ -1620,7 +1620,7 @@ static const struct genl_small_ops dropmon_ops[] = {
	},
};

static int net_dm_nl_pre_doit(const struct genl_ops *ops,
static int net_dm_nl_pre_doit(const struct genl_split_ops *ops,
			      struct sk_buff *skb, struct genl_info *info)
{
	mutex_lock(&net_dm_mutex);
@@ -1628,7 +1628,7 @@ static int net_dm_nl_pre_doit(const struct genl_ops *ops,
	return 0;
}

static void net_dm_nl_post_doit(const struct genl_ops *ops,
static void net_dm_nl_post_doit(const struct genl_split_ops *ops,
				struct sk_buff *skb, struct genl_info *info)
{
	mutex_unlock(&net_dm_mutex);
+4 −2
Original line number Diff line number Diff line
@@ -2157,7 +2157,8 @@ static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
#define NL802154_FLAG_CHECK_NETDEV_UP	0x08
#define NL802154_FLAG_NEED_WPAN_DEV	0x10

static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
static int nl802154_pre_doit(const struct genl_split_ops *ops,
			     struct sk_buff *skb,
			     struct genl_info *info)
{
	struct cfg802154_registered_device *rdev;
@@ -2219,7 +2220,8 @@ static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
	return 0;
}

static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static void nl802154_post_doit(const struct genl_split_ops *ops,
			       struct sk_buff *skb,
			       struct genl_info *info)
{
	if (info->user_ptr[1]) {
Loading