All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC net-next 0/9] genetlink: support per-command policy dump
@ 2020-10-01  0:05 Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 1/9] genetlink: add missing kdoc for validation flags Jakub Kicinski
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Hi!

The objective of this series is to dump ethtool policies
to be able to tell which flags are supported by the kernel.
Ethtool policies are per command.

First patch here is included for completeness - it's already
in net, but other patches won't apply cleanly without it.

The series adds new set of "light" ops which don't have all
the callbacks, and won't have the policy. Most of families
are then moved to these ops. This gives us 4096B in savings
on an allyesconfig build (not counting the growth that would
have happened when policy is added):

     text       data       bss        dec       hex
244415581  227958581  78372980  550747142  20d3bc06
244415581  227962677  78372980  550751238  20d3cc06

Next 5 patches deal the dumping per-op policy.

Jakub Kicinski (9):
  genetlink: add missing kdoc for validation flags
  genetlink: reorg struct genl_family
  genetlink: add small version of ops
  genetlink: move to smaller ops wherever possible
  genetlink: add a structure for dump state
  genetlink: use .start callback for dumppolicy
  genetlink: bring back per op policy
  genetlink: use per-op policy for CTRL_CMD_GETPOLICY
  genetlink: allow dumping command-specific policy

 drivers/block/nbd.c                      |   6 +-
 drivers/net/gtp.c                        |   6 +-
 drivers/net/ieee802154/mac802154_hwsim.c |   6 +-
 drivers/net/macsec.c                     |   6 +-
 drivers/net/team/team.c                  |   6 +-
 drivers/net/wireless/mac80211_hwsim.c    |   6 +-
 drivers/target/target_core_user.c        |   6 +-
 drivers/thermal/thermal_netlink.c        |   6 +-
 fs/dlm/netlink.c                         |   6 +-
 include/net/genetlink.h                  |  40 +++-
 include/uapi/linux/genetlink.h           |   1 +
 kernel/taskstats.c                       |   6 +-
 net/batman-adv/netlink.c                 |   6 +-
 net/core/devlink.c                       |   6 +-
 net/core/drop_monitor.c                  |   6 +-
 net/hsr/hsr_netlink.c                    |   6 +-
 net/ieee802154/netlink.c                 |   6 +-
 net/ipv4/fou.c                           |   6 +-
 net/ipv4/tcp_metrics.c                   |   6 +-
 net/l2tp/l2tp_netlink.c                  |   6 +-
 net/mptcp/pm_netlink.c                   |   6 +-
 net/ncsi/ncsi-netlink.c                  |   6 +-
 net/netfilter/ipvs/ip_vs_ctl.c           |   6 +-
 net/netlabel/netlabel_calipso.c          |   6 +-
 net/netlabel/netlabel_cipso_v4.c         |   6 +-
 net/netlabel/netlabel_mgmt.c             |   6 +-
 net/netlabel/netlabel_unlabeled.c        |   6 +-
 net/netlink/genetlink.c                  | 225 ++++++++++++++++-------
 net/openvswitch/conntrack.c              |   6 +-
 net/openvswitch/datapath.c               |  24 +--
 net/openvswitch/meter.c                  |   6 +-
 net/psample/psample.c                    |   6 +-
 net/tipc/netlink_compat.c                |   6 +-
 net/wimax/stack.c                        |   6 +-
 net/wireless/nl80211.c                   |   5 +
 35 files changed, 304 insertions(+), 171 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC net-next 1/9] genetlink: add missing kdoc for validation flags
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 2/9] genetlink: reorg struct genl_family Jakub Kicinski
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Validation flags are missing kdoc, add it.

Fixes: ef6243acb478 ("genetlink: optionally validate strictly/dumps")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/genetlink.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index b9eb92f3fe86..a3484fd736d6 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -130,6 +130,7 @@ genl_dumpit_info(struct netlink_callback *cb)
  * @cmd: command identifier
  * @internal_flags: flags used by the family
  * @flags: flags
+ * @validate: validation flags from enum genl_validate_flags
  * @doit: standard command callback
  * @start: start callback for dumps
  * @dumpit: callback for dumpers
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 2/9] genetlink: reorg struct genl_family
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 1/9] genetlink: add missing kdoc for validation flags Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:34   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 3/9] genetlink: add small version of ops Jakub Kicinski
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

There are holes and oversized members in struct genl_family.

Before: /* size: 104, cachelines: 2, members: 16 */
After:  /* size:  88, cachelines: 2, members: 16 */

The command field in struct genlmsghdr is a u8, so no point
in the operation count being 32 bit. Also operation 0 is
usually undefined, so we only need 255 entries.

netnsok and parallel_ops are only ever initialized to true.

We can grow the fields as needed, compiler should warn us
if someone tries to assign larger constants.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/genetlink.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index a3484fd736d6..0033c76ff094 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -48,8 +48,11 @@ struct genl_family {
 	char			name[GENL_NAMSIZ];
 	unsigned int		version;
 	unsigned int		maxattr;
-	bool			netnsok;
-	bool			parallel_ops;
+	unsigned int		mcgrp_offset;	/* private */
+	u8			netnsok:1;
+	u8			parallel_ops:1;
+	u8			n_ops;
+	u8			n_mcgrps;
 	const struct nla_policy *policy;
 	int			(*pre_doit)(const struct genl_ops *ops,
 					    struct sk_buff *skb,
@@ -59,9 +62,6 @@ struct genl_family {
 					     struct genl_info *info);
 	const struct genl_ops *	ops;
 	const struct genl_multicast_group *mcgrps;
-	unsigned int		n_ops;
-	unsigned int		n_mcgrps;
-	unsigned int		mcgrp_offset;	/* private */
 	struct module		*module;
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 3/9] genetlink: add small version of ops
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 1/9] genetlink: add missing kdoc for validation flags Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 2/9] genetlink: reorg struct genl_family Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:40   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 4/9] genetlink: move to smaller ops wherever possible Jakub Kicinski
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

We want to add maxattr and policy back to genl_ops, to enable
dumping per command policy to user space. This, however, would
cause bloat for all the families with global policies. Introduce
smaller version of ops (half the size of genl_ops). Translate
these smaller ops into a full blown struct before use in the
core.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/genetlink.h |  25 +++++++++
 net/netlink/genetlink.c | 119 ++++++++++++++++++++++++++++++----------
 2 files changed, 116 insertions(+), 28 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 0033c76ff094..d781f2a240b5 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -41,6 +41,8 @@ struct genl_info;
  *	(private)
  * @ops: the operations supported by this family
  * @n_ops: number of operations supported by this family
+ * @small_ops: the small-struct operations supported by this family
+ * @n_small_ops: number of small-struct operations supported by this family
  */
 struct genl_family {
 	int			id;		/* private */
@@ -52,6 +54,7 @@ struct genl_family {
 	u8			netnsok:1;
 	u8			parallel_ops:1;
 	u8			n_ops;
+	u8			n_small_ops;
 	u8			n_mcgrps;
 	const struct nla_policy *policy;
 	int			(*pre_doit)(const struct genl_ops *ops,
@@ -61,6 +64,7 @@ struct genl_family {
 					     struct sk_buff *skb,
 					     struct genl_info *info);
 	const struct genl_ops *	ops;
+	const struct genl_small_ops *small_ops;
 	const struct genl_multicast_group *mcgrps;
 	struct module		*module;
 };
@@ -125,6 +129,27 @@ genl_dumpit_info(struct netlink_callback *cb)
 	return cb->data;
 }
 
+/**
+ * struct genl_small_ops - generic netlink operations (small version)
+ * @cmd: command identifier
+ * @internal_flags: flags used by the family
+ * @flags: flags
+ * @validate: validation flags from enum genl_validate_flags
+ * @doit: standard command callback
+ * @dumpit: callback for dumpers
+ *
+ * This is a cut-down version of struct genl_ops for users who don't need
+ * most of the ancillary infra and want to save space.
+ */
+struct genl_small_ops {
+	int	(*doit)(struct sk_buff *skb, struct genl_info *info);
+	int	(*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
+	u8	cmd;
+	u8	internal_flags;
+	u8	flags;
+	u8	validate;
+};
+
 /**
  * struct genl_ops - generic netlink operations
  * @cmd: command identifier
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 3a718e327515..38d8f353dba1 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -107,16 +107,75 @@ static const struct genl_family *genl_family_find_byname(char *name)
 	return NULL;
 }
 
-static const struct genl_ops *genl_get_cmd(u8 cmd,
-					   const struct genl_family *family)
+static int genl_get_cmd_cnt(const struct genl_family *family)
+{
+	return family->n_ops + family->n_small_ops;
+}
+
+static void genl_op_from_full(const struct genl_family *family,
+			      unsigned int i, struct genl_ops *op)
+{
+	memcpy(op, &family->ops[i], sizeof(*op));
+}
+
+static int genl_get_cmd_full(u8 cmd, const struct genl_family *family,
+			     struct genl_ops *op)
 {
 	int i;
 
 	for (i = 0; i < family->n_ops; i++)
-		if (family->ops[i].cmd == cmd)
-			return &family->ops[i];
+		if (family->ops[i].cmd == cmd) {
+			genl_op_from_full(family, i, op);
+			return 0;
+		}
 
-	return NULL;
+	return -ENOENT;
+}
+
+static void genl_op_from_light(const struct genl_family *family,
+			       unsigned int i, struct genl_ops *op)
+{
+	memset(op, 0, sizeof(*op));
+	op->doit	= family->small_ops[i].doit;
+	op->dumpit	= family->small_ops[i].dumpit;
+	op->cmd		= family->small_ops[i].cmd;
+	op->internal_flags = family->small_ops[i].internal_flags;
+	op->flags	= family->small_ops[i].flags;
+	op->validate	= family->small_ops[i].validate;
+}
+
+static int genl_get_cmd_light(u8 cmd, const struct genl_family *family,
+			      struct genl_ops *op)
+{
+	int i;
+
+	for (i = 0; i < family->n_small_ops; i++)
+		if (family->small_ops[i].cmd == cmd) {
+			genl_op_from_light(family, i, op);
+			return 0;
+		}
+
+	return -ENOENT;
+}
+
+static int genl_get_cmd(u8 cmd, const struct genl_family *family,
+			struct genl_ops *op)
+{
+	if (!genl_get_cmd_full(cmd, family, op))
+		return 0;
+	return genl_get_cmd_light(cmd, family, op);
+}
+
+static void genl_get_cmd_by_index(unsigned int i,
+				  const struct genl_family *family,
+				  struct genl_ops *op)
+{
+	if (i < family->n_ops)
+		genl_op_from_full(family, i, op);
+	else if (i < family->n_ops + family->n_small_ops)
+		genl_op_from_light(family, i - family->n_ops, op);
+	else
+		WARN_ON_ONCE(1);
 }
 
 static int genl_allocate_reserve_groups(int n_groups, int *first_id)
@@ -286,22 +345,25 @@ static void genl_unregister_mc_groups(const struct genl_family *family)
 
 static int genl_validate_ops(const struct genl_family *family)
 {
-	const struct genl_ops *ops = family->ops;
-	unsigned int n_ops = family->n_ops;
 	int i, j;
 
-	if (WARN_ON(n_ops && !ops))
+	if (WARN_ON(family->n_ops && !family->ops) ||
+	    WARN_ON(family->n_small_ops && !family->small_ops))
 		return -EINVAL;
 
-	if (!n_ops)
-		return 0;
+	for (i = 0; i < genl_get_cmd_cnt(family); i++) {
+		struct genl_ops op;
 
-	for (i = 0; i < n_ops; i++) {
-		if (ops[i].dumpit == NULL && ops[i].doit == NULL)
+		genl_get_cmd_by_index(i, family, &op);
+		if (op.dumpit == NULL && op.doit == NULL)
 			return -EINVAL;
-		for (j = i + 1; j < n_ops; j++)
-			if (ops[i].cmd == ops[j].cmd)
+		for (j = i + 1; j < genl_get_cmd_cnt(family); j++) {
+			struct genl_ops op2;
+
+			genl_get_cmd_by_index(j, family, &op2);
+			if (op.cmd == op2.cmd)
 				return -EINVAL;
+		}
 	}
 
 	return 0;
@@ -682,9 +744,9 @@ static int genl_family_rcv_msg(const struct genl_family *family,
 			       struct nlmsghdr *nlh,
 			       struct netlink_ext_ack *extack)
 {
-	const struct genl_ops *ops;
 	struct net *net = sock_net(skb->sk);
 	struct genlmsghdr *hdr = nlmsg_data(nlh);
+	struct genl_ops op;
 	int hdrlen;
 
 	/* this family doesn't exist in this netns */
@@ -695,24 +757,23 @@ static int genl_family_rcv_msg(const struct genl_family *family,
 	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
 		return -EINVAL;
 
-	ops = genl_get_cmd(hdr->cmd, family);
-	if (ops == NULL)
+	if (genl_get_cmd(hdr->cmd, family, &op))
 		return -EOPNOTSUPP;
 
-	if ((ops->flags & GENL_ADMIN_PERM) &&
+	if ((op.flags & GENL_ADMIN_PERM) &&
 	    !netlink_capable(skb, CAP_NET_ADMIN))
 		return -EPERM;
 
-	if ((ops->flags & GENL_UNS_ADMIN_PERM) &&
+	if ((op.flags & GENL_UNS_ADMIN_PERM) &&
 	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
 		return -EPERM;
 
 	if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
 		return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
-						  ops, hdrlen, net);
+						  &op, hdrlen, net);
 	else
 		return genl_family_rcv_msg_doit(family, skb, nlh, extack,
-						ops, hdrlen, net);
+						&op, hdrlen, net);
 }
 
 static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -765,7 +826,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
 	    nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
 		goto nla_put_failure;
 
-	if (family->n_ops) {
+	if (genl_get_cmd_cnt(family)) {
 		struct nlattr *nla_ops;
 		int i;
 
@@ -773,14 +834,16 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
 		if (nla_ops == NULL)
 			goto nla_put_failure;
 
-		for (i = 0; i < family->n_ops; i++) {
+		for (i = 0; i < genl_get_cmd_cnt(family); i++) {
 			struct nlattr *nest;
-			const struct genl_ops *ops = &family->ops[i];
-			u32 op_flags = ops->flags;
+			struct genl_ops op;
+			u32 op_flags;
 
-			if (ops->dumpit)
+			genl_get_cmd_by_index(i, family, &op);
+			op_flags = op.flags;
+			if (op.dumpit)
 				op_flags |= GENL_CMD_CAP_DUMP;
-			if (ops->doit)
+			if (op.doit)
 				op_flags |= GENL_CMD_CAP_DO;
 			if (family->policy)
 				op_flags |= GENL_CMD_CAP_HASPOL;
@@ -789,7 +852,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
 			if (nest == NULL)
 				goto nla_put_failure;
 
-			if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
+			if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) ||
 			    nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
 				goto nla_put_failure;
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 4/9] genetlink: move to smaller ops wherever possible
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (2 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 3/9] genetlink: add small version of ops Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:42   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 5/9] genetlink: add a structure for dump state Jakub Kicinski
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Bulk of the genetlink users can use smaller ops, move them.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/block/nbd.c                      |  6 +++---
 drivers/net/gtp.c                        |  6 +++---
 drivers/net/ieee802154/mac802154_hwsim.c |  6 +++---
 drivers/net/macsec.c                     |  6 +++---
 drivers/net/team/team.c                  |  6 +++---
 drivers/net/wireless/mac80211_hwsim.c    |  6 +++---
 drivers/target/target_core_user.c        |  6 +++---
 drivers/thermal/thermal_netlink.c        |  6 +++---
 fs/dlm/netlink.c                         |  6 +++---
 kernel/taskstats.c                       |  6 +++---
 net/batman-adv/netlink.c                 |  6 +++---
 net/core/devlink.c                       |  6 +++---
 net/core/drop_monitor.c                  |  6 +++---
 net/hsr/hsr_netlink.c                    |  6 +++---
 net/ieee802154/netlink.c                 |  6 +++---
 net/ipv4/fou.c                           |  6 +++---
 net/ipv4/tcp_metrics.c                   |  6 +++---
 net/l2tp/l2tp_netlink.c                  |  6 +++---
 net/mptcp/pm_netlink.c                   |  6 +++---
 net/ncsi/ncsi-netlink.c                  |  6 +++---
 net/netfilter/ipvs/ip_vs_ctl.c           |  6 +++---
 net/netlabel/netlabel_calipso.c          |  6 +++---
 net/netlabel/netlabel_cipso_v4.c         |  6 +++---
 net/netlabel/netlabel_mgmt.c             |  6 +++---
 net/netlabel/netlabel_unlabeled.c        |  6 +++---
 net/openvswitch/conntrack.c              |  6 +++---
 net/openvswitch/datapath.c               | 24 ++++++++++++------------
 net/openvswitch/meter.c                  |  6 +++---
 net/psample/psample.c                    |  6 +++---
 net/tipc/netlink_compat.c                |  6 +++---
 net/wimax/stack.c                        |  6 +++---
 net/wireless/nl80211.c                   |  5 +++++
 32 files changed, 107 insertions(+), 102 deletions(-)

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index edf8b632e3d2..ab2bbe2208ef 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -2183,7 +2183,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
 	return ret;
 }
 
-static const struct genl_ops nbd_connect_genl_ops[] = {
+static const struct genl_small_ops nbd_connect_genl_ops[] = {
 	{
 		.cmd	= NBD_CMD_CONNECT,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -2215,8 +2215,8 @@ static struct genl_family nbd_genl_family __ro_after_init = {
 	.name		= NBD_GENL_FAMILY_NAME,
 	.version	= NBD_GENL_VERSION,
 	.module		= THIS_MODULE,
-	.ops		= nbd_connect_genl_ops,
-	.n_ops		= ARRAY_SIZE(nbd_connect_genl_ops),
+	.small_ops	= nbd_connect_genl_ops,
+	.n_small_ops	= ARRAY_SIZE(nbd_connect_genl_ops),
 	.maxattr	= NBD_ATTR_MAX,
 	.policy = nbd_attr_policy,
 	.mcgrps		= nbd_mcast_grps,
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 611722eafed8..c09fe18c6c52 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1339,7 +1339,7 @@ static const struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
 	[GTPA_O_TEI]		= { .type = NLA_U32, },
 };
 
-static const struct genl_ops gtp_genl_ops[] = {
+static const struct genl_small_ops gtp_genl_ops[] = {
 	{
 		.cmd = GTP_CMD_NEWPDP,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1369,8 +1369,8 @@ static struct genl_family gtp_genl_family __ro_after_init = {
 	.policy = gtp_genl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= gtp_genl_ops,
-	.n_ops		= ARRAY_SIZE(gtp_genl_ops),
+	.small_ops	= gtp_genl_ops,
+	.n_small_ops	= ARRAY_SIZE(gtp_genl_ops),
 	.mcgrps		= gtp_genl_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(gtp_genl_mcgrps),
 };
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index c20e7ef18bc9..c0bf7d78276e 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -583,7 +583,7 @@ static const struct nla_policy hwsim_genl_policy[MAC802154_HWSIM_ATTR_MAX + 1] =
 };
 
 /* Generic Netlink operations array */
-static const struct genl_ops hwsim_nl_ops[] = {
+static const struct genl_small_ops hwsim_nl_ops[] = {
 	{
 		.cmd = MAC802154_HWSIM_CMD_NEW_RADIO,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -628,8 +628,8 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
 	.maxattr = MAC802154_HWSIM_ATTR_MAX,
 	.policy = hwsim_genl_policy,
 	.module = THIS_MODULE,
-	.ops = hwsim_nl_ops,
-	.n_ops = ARRAY_SIZE(hwsim_nl_ops),
+	.small_ops = hwsim_nl_ops,
+	.n_small_ops = ARRAY_SIZE(hwsim_nl_ops),
 	.mcgrps = hwsim_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
 };
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 124045cbcda3..3f4d8c6625de 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -3285,7 +3285,7 @@ static int macsec_dump_txsc(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
-static const struct genl_ops macsec_genl_ops[] = {
+static const struct genl_small_ops macsec_genl_ops[] = {
 	{
 		.cmd = MACSEC_CMD_GET_TXSC,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -3361,8 +3361,8 @@ static struct genl_family macsec_fam __ro_after_init = {
 	.policy = macsec_genl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= macsec_genl_ops,
-	.n_ops		= ARRAY_SIZE(macsec_genl_ops),
+	.small_ops	= macsec_genl_ops,
+	.n_small_ops	= ARRAY_SIZE(macsec_genl_ops),
 };
 
 static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 8c1e02752ff6..a0c8c2fe6c3e 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2795,7 +2795,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
 	return err;
 }
 
-static const struct genl_ops team_nl_ops[] = {
+static const struct genl_small_ops team_nl_ops[] = {
 	{
 		.cmd = TEAM_CMD_NOOP,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -2832,8 +2832,8 @@ static struct genl_family team_nl_family __ro_after_init = {
 	.policy = team_nl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= team_nl_ops,
-	.n_ops		= ARRAY_SIZE(team_nl_ops),
+	.small_ops	= team_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(team_nl_ops),
 	.mcgrps		= team_nl_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(team_nl_mcgrps),
 };
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index dce3bc9c9f84..7a86145b8226 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3886,7 +3886,7 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
 }
 
 /* Generic Netlink operations array */
-static const struct genl_ops hwsim_ops[] = {
+static const struct genl_small_ops hwsim_ops[] = {
 	{
 		.cmd = HWSIM_CMD_REGISTER,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -3930,8 +3930,8 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
 	.policy = hwsim_genl_policy,
 	.netnsok = true,
 	.module = THIS_MODULE,
-	.ops = hwsim_ops,
-	.n_ops = ARRAY_SIZE(hwsim_ops),
+	.small_ops = hwsim_ops,
+	.n_small_ops = ARRAY_SIZE(hwsim_ops),
 	.mcgrps = hwsim_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
 };
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 9b7592350502..1a060a2c98d6 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -436,7 +436,7 @@ static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-static const struct genl_ops tcmu_genl_ops[] = {
+static const struct genl_small_ops tcmu_genl_ops[] = {
 	{
 		.cmd	= TCMU_CMD_SET_FEATURES,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -474,8 +474,8 @@ static struct genl_family tcmu_genl_family __ro_after_init = {
 	.mcgrps = tcmu_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
 	.netnsok = true,
-	.ops = tcmu_genl_ops,
-	.n_ops = ARRAY_SIZE(tcmu_genl_ops),
+	.small_ops = tcmu_genl_ops,
+	.n_small_ops = ARRAY_SIZE(tcmu_genl_ops),
 };
 
 #define tcmu_cmd_set_dbi_cur(cmd, index) ((cmd)->dbi_cur = (index))
diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c
index af7b2383e8f6..585cb3c0d449 100644
--- a/drivers/thermal/thermal_netlink.c
+++ b/drivers/thermal/thermal_netlink.c
@@ -601,7 +601,7 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb,
 	return ret;
 }
 
-static const struct genl_ops thermal_genl_ops[] = {
+static const struct genl_small_ops thermal_genl_ops[] = {
 	{
 		.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -635,8 +635,8 @@ static struct genl_family thermal_gnl_family __ro_after_init = {
 	.version	= THERMAL_GENL_VERSION,
 	.maxattr	= THERMAL_GENL_ATTR_MAX,
 	.policy		= thermal_genl_policy,
-	.ops		= thermal_genl_ops,
-	.n_ops		= ARRAY_SIZE(thermal_genl_ops),
+	.small_ops	= thermal_genl_ops,
+	.n_small_ops	= ARRAY_SIZE(thermal_genl_ops),
 	.mcgrps		= thermal_genl_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(thermal_genl_mcgrps),
 };
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index e338c407cb75..67f68d48d60c 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -62,7 +62,7 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-static const struct genl_ops dlm_nl_ops[] = {
+static const struct genl_small_ops dlm_nl_ops[] = {
 	{
 		.cmd	= DLM_CMD_HELLO,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -73,8 +73,8 @@ static const struct genl_ops dlm_nl_ops[] = {
 static struct genl_family family __ro_after_init = {
 	.name		= DLM_GENL_NAME,
 	.version	= DLM_GENL_VERSION,
-	.ops		= dlm_nl_ops,
-	.n_ops		= ARRAY_SIZE(dlm_nl_ops),
+	.small_ops	= dlm_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(dlm_nl_ops),
 	.module		= THIS_MODULE,
 };
 
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index e2ac0e37c4ae..ef4de29fbe8a 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -644,7 +644,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
 	nlmsg_free(rep_skb);
 }
 
-static const struct genl_ops taskstats_ops[] = {
+static const struct genl_small_ops taskstats_ops[] = {
 	{
 		.cmd		= TASKSTATS_CMD_GET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -687,8 +687,8 @@ static struct genl_family family __ro_after_init = {
 	.version	= TASKSTATS_GENL_VERSION,
 	.maxattr	= TASKSTATS_CMD_ATTR_MAX,
 	.module		= THIS_MODULE,
-	.ops		= taskstats_ops,
-	.n_ops		= ARRAY_SIZE(taskstats_ops),
+	.small_ops	= taskstats_ops,
+	.n_small_ops	= ARRAY_SIZE(taskstats_ops),
 	.pre_doit	= taskstats_pre_doit,
 };
 
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index dc193618a761..c7a55647b520 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1350,7 +1350,7 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
 	}
 }
 
-static const struct genl_ops batadv_netlink_ops[] = {
+static const struct genl_small_ops batadv_netlink_ops[] = {
 	{
 		.cmd = BATADV_CMD_GET_MESH,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1484,8 +1484,8 @@ struct genl_family batadv_netlink_family __ro_after_init = {
 	.pre_doit = batadv_pre_doit,
 	.post_doit = batadv_post_doit,
 	.module = THIS_MODULE,
-	.ops = batadv_netlink_ops,
-	.n_ops = ARRAY_SIZE(batadv_netlink_ops),
+	.small_ops = batadv_netlink_ops,
+	.n_small_ops = ARRAY_SIZE(batadv_netlink_ops),
 	.mcgrps = batadv_netlink_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps),
 };
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 7a38f9e25922..84d7798fac5b 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -7121,7 +7121,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
 	[DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
 };
 
-static const struct genl_ops devlink_nl_ops[] = {
+static const struct genl_small_ops devlink_nl_ops[] = {
 	{
 		.cmd = DEVLINK_CMD_GET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -7446,8 +7446,8 @@ static struct genl_family devlink_nl_family __ro_after_init = {
 	.pre_doit	= devlink_nl_pre_doit,
 	.post_doit	= devlink_nl_post_doit,
 	.module		= THIS_MODULE,
-	.ops		= devlink_nl_ops,
-	.n_ops		= ARRAY_SIZE(devlink_nl_ops),
+	.small_ops	= devlink_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(devlink_nl_ops),
 	.mcgrps		= devlink_nl_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(devlink_nl_mcgrps),
 };
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index 9704522b0872..ef18f325ae6a 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -1548,7 +1548,7 @@ static const struct nla_policy net_dm_nl_policy[NET_DM_ATTR_MAX + 1] = {
 	[NET_DM_ATTR_HW_DROPS]	= {. type = NLA_FLAG },
 };
 
-static const struct genl_ops dropmon_ops[] = {
+static const struct genl_small_ops dropmon_ops[] = {
 	{
 		.cmd = NET_DM_CMD_CONFIG,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1598,8 +1598,8 @@ static struct genl_family net_drop_monitor_family __ro_after_init = {
 	.pre_doit	= net_dm_nl_pre_doit,
 	.post_doit	= net_dm_nl_post_doit,
 	.module		= THIS_MODULE,
-	.ops		= dropmon_ops,
-	.n_ops		= ARRAY_SIZE(dropmon_ops),
+	.small_ops	= dropmon_ops,
+	.n_small_ops	= ARRAY_SIZE(dropmon_ops),
 	.mcgrps		= dropmon_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(dropmon_mcgrps),
 };
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 0e4681cf71db..f3c8f91dbe2c 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -493,7 +493,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
 	return res;
 }
 
-static const struct genl_ops hsr_ops[] = {
+static const struct genl_small_ops hsr_ops[] = {
 	{
 		.cmd = HSR_C_GET_NODE_STATUS,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -518,8 +518,8 @@ static struct genl_family hsr_genl_family __ro_after_init = {
 	.policy = hsr_genl_policy,
 	.netnsok = true,
 	.module = THIS_MODULE,
-	.ops = hsr_ops,
-	.n_ops = ARRAY_SIZE(hsr_ops),
+	.small_ops = hsr_ops,
+	.n_small_ops = ARRAY_SIZE(hsr_ops),
 	.mcgrps = hsr_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(hsr_mcgrps),
 };
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 7fe3b6b6c495..b07abc38b4b3 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -81,7 +81,7 @@ int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
 	return genlmsg_reply(msg, info);
 }
 
-static const struct genl_ops ieee802154_ops[] = {
+static const struct genl_small_ops ieee802154_ops[] = {
 	/* see nl-phy.c */
 	IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
 			ieee802154_dump_phy),
@@ -130,8 +130,8 @@ struct genl_family nl802154_family __ro_after_init = {
 	.maxattr	= IEEE802154_ATTR_MAX,
 	.policy		= ieee802154_policy,
 	.module		= THIS_MODULE,
-	.ops		= ieee802154_ops,
-	.n_ops		= ARRAY_SIZE(ieee802154_ops),
+	.small_ops	= ieee802154_ops,
+	.n_small_ops	= ARRAY_SIZE(ieee802154_ops),
 	.mcgrps		= ieee802154_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(ieee802154_mcgrps),
 };
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 5308cfa3de62..e5f69b0bf3df 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -911,7 +911,7 @@ static int fou_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
-static const struct genl_ops fou_nl_ops[] = {
+static const struct genl_small_ops fou_nl_ops[] = {
 	{
 		.cmd = FOU_CMD_ADD,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -940,8 +940,8 @@ static struct genl_family fou_nl_family __ro_after_init = {
 	.policy = fou_nl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= fou_nl_ops,
-	.n_ops		= ARRAY_SIZE(fou_nl_ops),
+	.small_ops	= fou_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(fou_nl_ops),
 };
 
 size_t fou_encap_hlen(struct ip_tunnel_encap *e)
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 279db8822439..6b27c481fe18 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -943,7 +943,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-static const struct genl_ops tcp_metrics_nl_ops[] = {
+static const struct genl_small_ops tcp_metrics_nl_ops[] = {
 	{
 		.cmd = TCP_METRICS_CMD_GET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -966,8 +966,8 @@ static struct genl_family tcp_metrics_nl_family __ro_after_init = {
 	.policy = tcp_metrics_nl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= tcp_metrics_nl_ops,
-	.n_ops		= ARRAY_SIZE(tcp_metrics_nl_ops),
+	.small_ops	= tcp_metrics_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(tcp_metrics_nl_ops),
 };
 
 static unsigned int tcpmhash_entries;
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 5ca5056e9636..83956c9ee1fc 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -914,7 +914,7 @@ static const struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {
 	},
 };
 
-static const struct genl_ops l2tp_nl_ops[] = {
+static const struct genl_small_ops l2tp_nl_ops[] = {
 	{
 		.cmd = L2TP_CMD_NOOP,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -981,8 +981,8 @@ static struct genl_family l2tp_nl_family __ro_after_init = {
 	.policy = l2tp_nl_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= l2tp_nl_ops,
-	.n_ops		= ARRAY_SIZE(l2tp_nl_ops),
+	.small_ops	= l2tp_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(l2tp_nl_ops),
 	.mcgrps		= l2tp_multicast_group,
 	.n_mcgrps	= ARRAY_SIZE(l2tp_multicast_group),
 };
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 5a0e4d11bcc3..9f9cd41b7733 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -1054,7 +1054,7 @@ mptcp_nl_cmd_get_limits(struct sk_buff *skb, struct genl_info *info)
 	return -EMSGSIZE;
 }
 
-static struct genl_ops mptcp_pm_ops[] = {
+static struct genl_small_ops mptcp_pm_ops[] = {
 	{
 		.cmd    = MPTCP_PM_CMD_ADD_ADDR,
 		.doit   = mptcp_nl_cmd_add_addr,
@@ -1093,8 +1093,8 @@ static struct genl_family mptcp_genl_family __ro_after_init = {
 	.policy		= mptcp_pm_policy,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= mptcp_pm_ops,
-	.n_ops		= ARRAY_SIZE(mptcp_pm_ops),
+	.small_ops	= mptcp_pm_ops,
+	.n_small_ops	= ARRAY_SIZE(mptcp_pm_ops),
 	.mcgrps		= mptcp_pm_mcgrps,
 	.n_mcgrps	= ARRAY_SIZE(mptcp_pm_mcgrps),
 };
diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
index 8b386d766e7d..adddc7707aa4 100644
--- a/net/ncsi/ncsi-netlink.c
+++ b/net/ncsi/ncsi-netlink.c
@@ -716,7 +716,7 @@ static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
 	return 0;
 }
 
-static const struct genl_ops ncsi_ops[] = {
+static const struct genl_small_ops ncsi_ops[] = {
 	{
 		.cmd = NCSI_CMD_PKG_INFO,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -762,8 +762,8 @@ static struct genl_family ncsi_genl_family __ro_after_init = {
 	.maxattr = NCSI_ATTR_MAX,
 	.policy = ncsi_genl_policy,
 	.module = THIS_MODULE,
-	.ops = ncsi_ops,
-	.n_ops = ARRAY_SIZE(ncsi_ops),
+	.small_ops = ncsi_ops,
+	.n_small_ops = ARRAY_SIZE(ncsi_ops),
 };
 
 int ncsi_init_netlink(struct net_device *dev)
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 8dbfd84322a8..e279ded4e306 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3893,7 +3893,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
 }
 
 
-static const struct genl_ops ip_vs_genl_ops[] = {
+static const struct genl_small_ops ip_vs_genl_ops[] = {
 	{
 		.cmd	= IPVS_CMD_NEW_SERVICE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -4001,8 +4001,8 @@ static struct genl_family ip_vs_genl_family __ro_after_init = {
 	.policy = ip_vs_cmd_policy,
 	.netnsok        = true,         /* Make ipvsadm to work on netns */
 	.module		= THIS_MODULE,
-	.ops		= ip_vs_genl_ops,
-	.n_ops		= ARRAY_SIZE(ip_vs_genl_ops),
+	.small_ops	= ip_vs_genl_ops,
+	.n_small_ops	= ARRAY_SIZE(ip_vs_genl_ops),
 };
 
 static int __init ip_vs_genl_register(void)
diff --git a/net/netlabel/netlabel_calipso.c b/net/netlabel/netlabel_calipso.c
index 1a98247ab148..4e62f2ad3575 100644
--- a/net/netlabel/netlabel_calipso.c
+++ b/net/netlabel/netlabel_calipso.c
@@ -304,7 +304,7 @@ static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
 /* NetLabel Generic NETLINK Command Definitions
  */
 
-static const struct genl_ops netlbl_calipso_ops[] = {
+static const struct genl_small_ops netlbl_calipso_ops[] = {
 	{
 	.cmd = NLBL_CALIPSO_C_ADD,
 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -342,8 +342,8 @@ static struct genl_family netlbl_calipso_gnl_family __ro_after_init = {
 	.maxattr = NLBL_CALIPSO_A_MAX,
 	.policy = calipso_genl_policy,
 	.module = THIS_MODULE,
-	.ops = netlbl_calipso_ops,
-	.n_ops = ARRAY_SIZE(netlbl_calipso_ops),
+	.small_ops = netlbl_calipso_ops,
+	.n_small_ops = ARRAY_SIZE(netlbl_calipso_ops),
 };
 
 /* NetLabel Generic NETLINK Protocol Functions
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 0f16080b87cb..726dda95934c 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -724,7 +724,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
  * NetLabel Generic NETLINK Command Definitions
  */
 
-static const struct genl_ops netlbl_cipsov4_ops[] = {
+static const struct genl_small_ops netlbl_cipsov4_ops[] = {
 	{
 	.cmd = NLBL_CIPSOV4_C_ADD,
 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -762,8 +762,8 @@ static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
 	.maxattr = NLBL_CIPSOV4_A_MAX,
 	.policy = netlbl_cipsov4_genl_policy,
 	.module = THIS_MODULE,
-	.ops = netlbl_cipsov4_ops,
-	.n_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
+	.small_ops = netlbl_cipsov4_ops,
+	.n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
 };
 
 /*
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index e7a25fbfaf8b..eb1d66d20afb 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -757,7 +757,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
  * NetLabel Generic NETLINK Command Definitions
  */
 
-static const struct genl_ops netlbl_mgmt_genl_ops[] = {
+static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
 	{
 	.cmd = NLBL_MGMT_C_ADD,
 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -823,8 +823,8 @@ static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
 	.maxattr = NLBL_MGMT_A_MAX,
 	.policy = netlbl_mgmt_genl_policy,
 	.module = THIS_MODULE,
-	.ops = netlbl_mgmt_genl_ops,
-	.n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
+	.small_ops = netlbl_mgmt_genl_ops,
+	.n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
 };
 
 /*
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 77bb1bb22c3b..2e8e3f7b2111 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1301,7 +1301,7 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
  * NetLabel Generic NETLINK Command Definitions
  */
 
-static const struct genl_ops netlbl_unlabel_genl_ops[] = {
+static const struct genl_small_ops netlbl_unlabel_genl_ops[] = {
 	{
 	.cmd = NLBL_UNLABEL_C_STATICADD,
 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1367,8 +1367,8 @@ static struct genl_family netlbl_unlabel_gnl_family __ro_after_init = {
 	.maxattr = NLBL_UNLABEL_A_MAX,
 	.policy = netlbl_unlabel_genl_policy,
 	.module = THIS_MODULE,
-	.ops = netlbl_unlabel_genl_ops,
-	.n_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
+	.small_ops = netlbl_unlabel_genl_ops,
+	.n_small_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
 };
 
 /*
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index e86b9601f5b1..18af10b7ef0e 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -2231,7 +2231,7 @@ static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
-static struct genl_ops ct_limit_genl_ops[] = {
+static struct genl_small_ops ct_limit_genl_ops[] = {
 	{ .cmd = OVS_CT_LIMIT_CMD_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 		.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN
@@ -2263,8 +2263,8 @@ struct genl_family dp_ct_limit_genl_family __ro_after_init = {
 	.policy = ct_limit_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = ct_limit_genl_ops,
-	.n_ops = ARRAY_SIZE(ct_limit_genl_ops),
+	.small_ops = ct_limit_genl_ops,
+	.n_small_ops = ARRAY_SIZE(ct_limit_genl_ops),
 	.mcgrps = &ovs_ct_limit_multicast_group,
 	.n_mcgrps = 1,
 	.module = THIS_MODULE,
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 00df39b736ed..832f898edb6a 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -652,7 +652,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
 	[OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
 };
 
-static const struct genl_ops dp_packet_genl_ops[] = {
+static const struct genl_small_ops dp_packet_genl_ops[] = {
 	{ .cmd = OVS_PACKET_CMD_EXECUTE,
 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -668,8 +668,8 @@ static struct genl_family dp_packet_genl_family __ro_after_init = {
 	.policy = packet_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = dp_packet_genl_ops,
-	.n_ops = ARRAY_SIZE(dp_packet_genl_ops),
+	.small_ops = dp_packet_genl_ops,
+	.n_small_ops = ARRAY_SIZE(dp_packet_genl_ops),
 	.module = THIS_MODULE,
 };
 
@@ -1453,7 +1453,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
 	[OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
 };
 
-static const struct genl_ops dp_flow_genl_ops[] = {
+static const struct genl_small_ops dp_flow_genl_ops[] = {
 	{ .cmd = OVS_FLOW_CMD_NEW,
 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -1485,8 +1485,8 @@ static struct genl_family dp_flow_genl_family __ro_after_init = {
 	.policy = flow_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = dp_flow_genl_ops,
-	.n_ops = ARRAY_SIZE(dp_flow_genl_ops),
+	.small_ops = dp_flow_genl_ops,
+	.n_small_ops = ARRAY_SIZE(dp_flow_genl_ops),
 	.mcgrps = &ovs_dp_flow_multicast_group,
 	.n_mcgrps = 1,
 	.module = THIS_MODULE,
@@ -1918,7 +1918,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
 		PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
 };
 
-static const struct genl_ops dp_datapath_genl_ops[] = {
+static const struct genl_small_ops dp_datapath_genl_ops[] = {
 	{ .cmd = OVS_DP_CMD_NEW,
 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -1950,8 +1950,8 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = {
 	.policy = datapath_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = dp_datapath_genl_ops,
-	.n_ops = ARRAY_SIZE(dp_datapath_genl_ops),
+	.small_ops = dp_datapath_genl_ops,
+	.n_small_ops = ARRAY_SIZE(dp_datapath_genl_ops),
 	.mcgrps = &ovs_dp_datapath_multicast_group,
 	.n_mcgrps = 1,
 	.module = THIS_MODULE,
@@ -2401,7 +2401,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
 	[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
 };
 
-static const struct genl_ops dp_vport_genl_ops[] = {
+static const struct genl_small_ops dp_vport_genl_ops[] = {
 	{ .cmd = OVS_VPORT_CMD_NEW,
 	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 	  .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -2433,8 +2433,8 @@ struct genl_family dp_vport_genl_family __ro_after_init = {
 	.policy = vport_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = dp_vport_genl_ops,
-	.n_ops = ARRAY_SIZE(dp_vport_genl_ops),
+	.small_ops = dp_vport_genl_ops,
+	.n_small_ops = ARRAY_SIZE(dp_vport_genl_ops),
 	.mcgrps = &ovs_dp_vport_multicast_group,
 	.n_mcgrps = 1,
 	.module = THIS_MODULE,
diff --git a/net/openvswitch/meter.c b/net/openvswitch/meter.c
index 3d3d8e094546..50541e874726 100644
--- a/net/openvswitch/meter.c
+++ b/net/openvswitch/meter.c
@@ -672,7 +672,7 @@ bool ovs_meter_execute(struct datapath *dp, struct sk_buff *skb,
 	return false;
 }
 
-static struct genl_ops dp_meter_genl_ops[] = {
+static struct genl_small_ops dp_meter_genl_ops[] = {
 	{ .cmd = OVS_METER_CMD_FEATURES,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 		.flags = 0,		  /* OK for unprivileged users. */
@@ -711,8 +711,8 @@ struct genl_family dp_meter_genl_family __ro_after_init = {
 	.policy = meter_policy,
 	.netnsok = true,
 	.parallel_ops = true,
-	.ops = dp_meter_genl_ops,
-	.n_ops = ARRAY_SIZE(dp_meter_genl_ops),
+	.small_ops = dp_meter_genl_ops,
+	.n_small_ops = ARRAY_SIZE(dp_meter_genl_ops),
 	.mcgrps = &ovs_meter_multicast_group,
 	.n_mcgrps = 1,
 	.module = THIS_MODULE,
diff --git a/net/psample/psample.c b/net/psample/psample.c
index a042261a45c5..33e238c965bd 100644
--- a/net/psample/psample.c
+++ b/net/psample/psample.c
@@ -96,7 +96,7 @@ static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg,
 	return msg->len;
 }
 
-static const struct genl_ops psample_nl_ops[] = {
+static const struct genl_small_ops psample_nl_ops[] = {
 	{
 		.cmd = PSAMPLE_CMD_GET_GROUP,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -112,8 +112,8 @@ static struct genl_family psample_nl_family __ro_after_init = {
 	.netnsok	= true,
 	.module		= THIS_MODULE,
 	.mcgrps		= psample_nl_mcgrps,
-	.ops		= psample_nl_ops,
-	.n_ops		= ARRAY_SIZE(psample_nl_ops),
+	.small_ops	= psample_nl_ops,
+	.n_small_ops	= ARRAY_SIZE(psample_nl_ops),
 	.n_mcgrps	= ARRAY_SIZE(psample_nl_mcgrps),
 };
 
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 90e3c70a91ad..1c7aa51cc2a3 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -1337,7 +1337,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
-static const struct genl_ops tipc_genl_compat_ops[] = {
+static const struct genl_small_ops tipc_genl_compat_ops[] = {
 	{
 		.cmd		= TIPC_GENL_CMD,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1352,8 +1352,8 @@ static struct genl_family tipc_genl_compat_family __ro_after_init = {
 	.maxattr	= 0,
 	.netnsok	= true,
 	.module		= THIS_MODULE,
-	.ops		= tipc_genl_compat_ops,
-	.n_ops		= ARRAY_SIZE(tipc_genl_compat_ops),
+	.small_ops	= tipc_genl_compat_ops,
+	.n_small_ops	= ARRAY_SIZE(tipc_genl_compat_ops),
 };
 
 int __init tipc_netlink_compat_start(void)
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 4b9b1c5e8f3a..b6dd9d956ed8 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -401,7 +401,7 @@ static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = {
 	},
 };
 
-static const struct genl_ops wimax_gnl_ops[] = {
+static const struct genl_small_ops wimax_gnl_ops[] = {
 	{
 		.cmd = WIMAX_GNL_OP_MSG_FROM_USER,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -560,8 +560,8 @@ struct genl_family wimax_gnl_family __ro_after_init = {
 	.maxattr = WIMAX_GNL_ATTR_MAX,
 	.policy = wimax_gnl_policy,
 	.module = THIS_MODULE,
-	.ops = wimax_gnl_ops,
-	.n_ops = ARRAY_SIZE(wimax_gnl_ops),
+	.small_ops = wimax_gnl_ops,
+	.n_small_ops = ARRAY_SIZE(wimax_gnl_ops),
 	.mcgrps = wimax_gnl_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(wimax_gnl_mcgrps),
 };
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a212db7a300..ee852e70ac12 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -14603,6 +14603,9 @@ static const struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+};
+
+static const struct genl_small_ops nl80211_small_ops[] = {
 	{
 		.cmd = NL80211_CMD_SET_WIPHY,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -15464,6 +15467,8 @@ static struct genl_family nl80211_fam __ro_after_init = {
 	.module = THIS_MODULE,
 	.ops = nl80211_ops,
 	.n_ops = ARRAY_SIZE(nl80211_ops),
+	.small_ops = nl80211_small_ops,
+	.n_small_ops = ARRAY_SIZE(nl80211_small_ops),
 	.mcgrps = nl80211_mcgrps,
 	.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
 	.parallel_ops = true,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 5/9] genetlink: add a structure for dump state
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (3 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 4/9] genetlink: move to smaller ops wherever possible Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:48   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 6/9] genetlink: use .start callback for dumppolicy Jakub Kicinski
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Whenever netlink dump uses more than 2 cb->args[] entries
code gets hard to read. We're about to add more state to
ctrl_dumppolicy() so create a structure.

Since the structure is typed and clearly named we can remove
the local fam_id variable and use ctx->fam_id directly.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/netlink/genetlink.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 38d8f353dba1..a8001044d8cd 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1102,13 +1102,18 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
 	return 0;
 }
 
+struct ctrl_dump_policy_ctx {
+	unsigned long state;
+	unsigned int fam_id;
+};
+
 static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
 	const struct genl_family *rt;
-	unsigned int fam_id = cb->args[0];
 	int err;
 
-	if (!fam_id) {
+	if (!ctx->fam_id) {
 		struct nlattr *tb[CTRL_ATTR_MAX + 1];
 
 		err = genlmsg_parse(cb->nlh, &genl_ctrl, tb,
@@ -1121,28 +1126,28 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 			return -EINVAL;
 
 		if (tb[CTRL_ATTR_FAMILY_ID]) {
-			fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+			ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
 		} else {
 			rt = genl_family_find_byname(
 				nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
 			if (!rt)
 				return -ENOENT;
-			fam_id = rt->id;
+			ctx->fam_id = rt->id;
 		}
 	}
 
-	rt = genl_family_find_byid(fam_id);
+	rt = genl_family_find_byid(ctx->fam_id);
 	if (!rt)
 		return -ENOENT;
 
 	if (!rt->policy)
 		return -ENODATA;
 
-	err = netlink_policy_dump_start(rt->policy, rt->maxattr, &cb->args[1]);
+	err = netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
 	if (err)
 		return err;
 
-	while (netlink_policy_dump_loop(&cb->args[1])) {
+	while (netlink_policy_dump_loop(&ctx->state)) {
 		void *hdr;
 		struct nlattr *nest;
 
@@ -1159,7 +1164,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 		if (!nest)
 			goto nla_put_failure;
 
-		if (netlink_policy_dump_write(skb, cb->args[1]))
+		if (netlink_policy_dump_write(skb, ctx->state))
 			goto nla_put_failure;
 
 		nla_nest_end(skb, nest);
@@ -1172,7 +1177,6 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 		break;
 	}
 
-	cb->args[0] = fam_id;
 	return skb->len;
 }
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 6/9] genetlink: use .start callback for dumppolicy
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (4 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 5/9] genetlink: add a structure for dump state Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:49   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 7/9] genetlink: bring back per op policy Jakub Kicinski
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

The structure of ctrl_dumppolicy() is clearly split into
init and dumping. Move the init to a .start callback
for clarity, it's a more idiomatic netlink dump code structure.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/netlink/genetlink.c | 48 ++++++++++++++++++++---------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index a8001044d8cd..dfa8a00640c0 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1107,33 +1107,29 @@ struct ctrl_dump_policy_ctx {
 	unsigned int fam_id;
 };
 
-static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
+static int ctrl_dumppolicy_start(struct netlink_callback *cb)
 {
 	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
+	struct nlattr *tb[CTRL_ATTR_MAX + 1];
 	const struct genl_family *rt;
 	int err;
 
-	if (!ctx->fam_id) {
-		struct nlattr *tb[CTRL_ATTR_MAX + 1];
-
-		err = genlmsg_parse(cb->nlh, &genl_ctrl, tb,
-				    genl_ctrl.maxattr,
-				    genl_ctrl.policy, cb->extack);
-		if (err)
-			return err;
+	err = genlmsg_parse(cb->nlh, &genl_ctrl, tb, genl_ctrl.maxattr,
+			    genl_ctrl.policy, cb->extack);
+	if (err)
+		return err;
 
-		if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
-			return -EINVAL;
+	if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
+		return -EINVAL;
 
-		if (tb[CTRL_ATTR_FAMILY_ID]) {
-			ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
-		} else {
-			rt = genl_family_find_byname(
-				nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
-			if (!rt)
-				return -ENOENT;
-			ctx->fam_id = rt->id;
-		}
+	if (tb[CTRL_ATTR_FAMILY_ID]) {
+		ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+	} else {
+		rt = genl_family_find_byname(
+			nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
+		if (!rt)
+			return -ENOENT;
+		ctx->fam_id = rt->id;
 	}
 
 	rt = genl_family_find_byid(ctx->fam_id);
@@ -1143,9 +1139,12 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 	if (!rt->policy)
 		return -ENODATA;
 
-	err = netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
-	if (err)
-		return err;
+	return netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
+}
+
+static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
 
 	while (netlink_policy_dump_loop(&ctx->state)) {
 		void *hdr;
@@ -1157,7 +1156,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 		if (!hdr)
 			goto nla_put_failure;
 
-		if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, rt->id))
+		if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
 			goto nla_put_failure;
 
 		nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
@@ -1189,6 +1188,7 @@ static const struct genl_ops genl_ctrl_ops[] = {
 	},
 	{
 		.cmd		= CTRL_CMD_GETPOLICY,
+		.start		= ctrl_dumppolicy_start,
 		.dumpit		= ctrl_dumppolicy,
 	},
 };
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 7/9] genetlink: bring back per op policy
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (5 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 6/9] genetlink: use .start callback for dumppolicy Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:53   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY Jakub Kicinski
  2020-10-01  0:05 ` [RFC net-next 9/9] genetlink: allow dumping command-specific policy Jakub Kicinski
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Add policy to the struct genl_ops structure, this time
with maxattr, so it can be used properly.

Propagate .policy and .maxattr from the family
in genl_get_cmd() if needed, this say the rest of the
code does not have to worry if the policy is per op
or global.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/genetlink.h |  4 ++++
 net/netlink/genetlink.c | 18 +++++++++++++-----
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index d781f2a240b5..48bfd8308938 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -156,6 +156,8 @@ struct genl_small_ops {
  * @internal_flags: flags used by the family
  * @flags: flags
  * @validate: validation flags from enum genl_validate_flags
+ * @maxattr: maximum number of attributes supported
+ * @policy: netlink policy (takes precedence over family policy)
  * @doit: standard command callback
  * @start: start callback for dumps
  * @dumpit: callback for dumpers
@@ -168,6 +170,8 @@ struct genl_ops {
 	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;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index dfa8a00640c0..7ceb2dc92a09 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -116,6 +116,11 @@ static void genl_op_from_full(const struct genl_family *family,
 			      unsigned int i, struct genl_ops *op)
 {
 	memcpy(op, &family->ops[i], sizeof(*op));
+
+	if (!op->maxattr)
+		op->maxattr = family->maxattr;
+	if (!op->policy)
+		op->policy = family->policy;
 }
 
 static int genl_get_cmd_full(u8 cmd, const struct genl_family *family,
@@ -142,6 +147,9 @@ static void genl_op_from_light(const struct genl_family *family,
 	op->internal_flags = family->small_ops[i].internal_flags;
 	op->flags	= family->small_ops[i].flags;
 	op->validate	= family->small_ops[i].validate;
+
+	op->maxattr = family->maxattr;
+	op->policy = family->policy;
 }
 
 static int genl_get_cmd_light(u8 cmd, const struct genl_family *family,
@@ -529,16 +537,16 @@ genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
 	struct nlattr **attrbuf;
 	int err;
 
-	if (!family->maxattr)
+	if (!ops->maxattr)
 		return NULL;
 
-	attrbuf = kmalloc_array(family->maxattr + 1,
+	attrbuf = kmalloc_array(ops->maxattr + 1,
 				sizeof(struct nlattr *), GFP_KERNEL);
 	if (!attrbuf)
 		return ERR_PTR(-ENOMEM);
 
-	err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
-			    family->policy, validate, extack);
+	err = __nlmsg_parse(nlh, hdrlen, attrbuf, ops->maxattr, ops->policy,
+			    validate, extack);
 	if (err) {
 		kfree(attrbuf);
 		return ERR_PTR(err);
@@ -845,7 +853,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
 				op_flags |= GENL_CMD_CAP_DUMP;
 			if (op.doit)
 				op_flags |= GENL_CMD_CAP_DO;
-			if (family->policy)
+			if (op.policy)
 				op_flags |= GENL_CMD_CAP_HASPOL;
 
 			nest = nla_nest_start_noflag(skb, i + 1);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (6 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 7/9] genetlink: bring back per op policy Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:56   ` Johannes Berg
  2020-10-01  0:05 ` [RFC net-next 9/9] genetlink: allow dumping command-specific policy Jakub Kicinski
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Wire up per-op policy for CTRL_CMD_GETPOLICY.
This saves us a call to genlmsg_parse() and will soon allow
dumping this policy.

Create a new policy definition, since we don't want to pollute
ctrl_policy with attributes which CTRL_CMD_GETFAMILY does not
support.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/netlink/genetlink.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 7ceb2dc92a09..f2833e9165c7 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1115,17 +1115,18 @@ struct ctrl_dump_policy_ctx {
 	unsigned int fam_id;
 };
 
+static const struct nla_policy ctrl_policy_policy[] = {
+	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
+	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
+				    .len = GENL_NAMSIZ - 1 },
+};
+
 static int ctrl_dumppolicy_start(struct netlink_callback *cb)
 {
+	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
 	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
-	struct nlattr *tb[CTRL_ATTR_MAX + 1];
+	struct nlattr **tb = info->attrs;
 	const struct genl_family *rt;
-	int err;
-
-	err = genlmsg_parse(cb->nlh, &genl_ctrl, tb, genl_ctrl.maxattr,
-			    genl_ctrl.policy, cb->extack);
-	if (err)
-		return err;
 
 	if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
 		return -EINVAL;
@@ -1196,6 +1197,8 @@ static const struct genl_ops genl_ctrl_ops[] = {
 	},
 	{
 		.cmd		= CTRL_CMD_GETPOLICY,
+		.policy		= ctrl_policy_policy,
+		.maxattr	= ARRAY_SIZE(ctrl_policy_policy) - 1,
 		.start		= ctrl_dumppolicy_start,
 		.dumpit		= ctrl_dumppolicy,
 	},
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
                   ` (7 preceding siblings ...)
  2020-10-01  0:05 ` [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY Jakub Kicinski
@ 2020-10-01  0:05 ` Jakub Kicinski
  2020-10-01  7:59   ` Johannes Berg
  8 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01  0:05 UTC (permalink / raw)
  To: netdev; +Cc: andrew, johannes, jiri, mkubecek, dsahern, pablo, Jakub Kicinski

Right now CTRL_CMD_GETPOLICY can only dump the family-wide
policy. Support dumping policy of a specific op.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/uapi/linux/genetlink.h |  1 +
 net/netlink/genetlink.c        | 23 +++++++++++++++++++++--
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
index 9c0636ec2286..7dbe2d5d7d46 100644
--- a/include/uapi/linux/genetlink.h
+++ b/include/uapi/linux/genetlink.h
@@ -64,6 +64,7 @@ enum {
 	CTRL_ATTR_OPS,
 	CTRL_ATTR_MCAST_GROUPS,
 	CTRL_ATTR_POLICY,
+	CTRL_ATTR_OP,
 	__CTRL_ATTR_MAX,
 };
 
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f2833e9165c7..12e9f323af35 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1113,12 +1113,14 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
 struct ctrl_dump_policy_ctx {
 	unsigned long state;
 	unsigned int fam_id;
+	u8 cmd;
 };
 
 static const struct nla_policy ctrl_policy_policy[] = {
 	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
 	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
 				    .len = GENL_NAMSIZ - 1 },
+	[CTRL_ATTR_OP]		= { .type = NLA_U8 },
 };
 
 static int ctrl_dumppolicy_start(struct netlink_callback *cb)
@@ -1127,6 +1129,8 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
 	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
 	struct nlattr **tb = info->attrs;
 	const struct genl_family *rt;
+	struct genl_ops op;
+	int err;
 
 	if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
 		return -EINVAL;
@@ -1145,10 +1149,23 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
 	if (!rt)
 		return -ENOENT;
 
-	if (!rt->policy)
+	if (tb[CTRL_ATTR_OP]) {
+		ctx->cmd = nla_get_u8(tb[CTRL_ATTR_OP]);
+
+		err = genl_get_cmd(ctx->cmd, rt, &op);
+		if (err) {
+			NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
+			return err;
+		}
+	} else {
+		op.policy = rt->policy;
+		op.maxattr = rt->maxattr;
+	}
+
+	if (!op.policy)
 		return -ENODATA;
 
-	return netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
+	return netlink_policy_dump_start(op.policy, op.maxattr, &ctx->state);
 }
 
 static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
@@ -1167,6 +1184,8 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
 
 		if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
 			goto nla_put_failure;
+		if (ctx->cmd && nla_put_u8(skb, CTRL_ATTR_OP, ctx->cmd))
+			goto nla_put_failure;
 
 		nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
 		if (!nest)
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 2/9] genetlink: reorg struct genl_family
  2020-10-01  0:05 ` [RFC net-next 2/9] genetlink: reorg struct genl_family Jakub Kicinski
@ 2020-10-01  7:34   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:34 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> There are holes and oversized members in struct genl_family.
> 
> Before: /* size: 104, cachelines: 2, members: 16 */
> After:  /* size:  88, cachelines: 2, members: 16 */
> 
> The command field in struct genlmsghdr is a u8, so no point
> in the operation count being 32 bit. Also operation 0 is
> usually undefined, so we only need 255 entries.
> 
> netnsok and parallel_ops are only ever initialized to true.

The fundamentally are bools, so that makes sense :)

> We can grow the fields as needed, compiler should warn us
> if someone tries to assign larger constants.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  include/net/genetlink.h | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/include/net/genetlink.h b/include/net/genetlink.h
> index a3484fd736d6..0033c76ff094 100644
> --- a/include/net/genetlink.h
> +++ b/include/net/genetlink.h
> @@ -48,8 +48,11 @@ struct genl_family {
>  	char			name[GENL_NAMSIZ];
>  	unsigned int		version;
>  	unsigned int		maxattr;
> -	bool			netnsok;
> -	bool			parallel_ops;
> +	unsigned int		mcgrp_offset;	/* private */

In practice, we can probably also shrink that to u16, since it just
gives you the offset of the multicast groups this family has in the
whole table - and we'll hopefully never run more than 2**16 multicast
groups across all genetlink families :)

But it also doesn't matter much.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 3/9] genetlink: add small version of ops
  2020-10-01  0:05 ` [RFC net-next 3/9] genetlink: add small version of ops Jakub Kicinski
@ 2020-10-01  7:40   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:40 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> We want to add maxattr and policy back to genl_ops, to enable
> dumping per command policy to user space. This, however, would
> cause bloat for all the families with global policies. Introduce
> smaller version of ops (half the size of genl_ops). Translate
> these smaller ops into a full blown struct before use in the
> core.

LGTM. That part about the WARN_ON was even easier than I thought :)

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 4/9] genetlink: move to smaller ops wherever possible
  2020-10-01  0:05 ` [RFC net-next 4/9] genetlink: move to smaller ops wherever possible Jakub Kicinski
@ 2020-10-01  7:42   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:42 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> Bulk of the genetlink users can use smaller ops, move them.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 5/9] genetlink: add a structure for dump state
  2020-10-01  0:05 ` [RFC net-next 5/9] genetlink: add a structure for dump state Jakub Kicinski
@ 2020-10-01  7:48   ` Johannes Berg
  2020-10-01  8:04     ` Michal Kubecek
  0 siblings, 1 reply; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:48 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> Whenever netlink dump uses more than 2 cb->args[] entries
> code gets hard to read. We're about to add more state to
> ctrl_dumppolicy() so create a structure.
> 
> Since the structure is typed and clearly named we can remove
> the local fam_id variable and use ctx->fam_id directly.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  net/netlink/genetlink.c | 22 +++++++++++++---------
>  1 file changed, 13 insertions(+), 9 deletions(-)
> 
> diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
> index 38d8f353dba1..a8001044d8cd 100644
> --- a/net/netlink/genetlink.c
> +++ b/net/netlink/genetlink.c
> @@ -1102,13 +1102,18 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
>  	return 0;
>  }
>  
> +struct ctrl_dump_policy_ctx {
> +	unsigned long state;

Maybe if we do this, also make a "struct netlink_policy_dump_state" in
include/net/netlink.h for the policy dump to use as a state? Right now
it just uses an "unsigned long *state" there.

I feel that would more clearly show what this "state" actually is.

Alternatively, perhaps just rename it to "policy_dump_state"? Yeah,
that's longer, but at least would be very obvious?

> +	unsigned int fam_id;

You could make this a u16 I guess, but it doesn't really matter.

>  static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
>  {
> +	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;


I'd also prefer if you stuck a

	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->args));

here. It's not likely we'll need so much more state here, but would
still be good to check IMHO.

But in general looks good :)

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 6/9] genetlink: use .start callback for dumppolicy
  2020-10-01  0:05 ` [RFC net-next 6/9] genetlink: use .start callback for dumppolicy Jakub Kicinski
@ 2020-10-01  7:49   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:49 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> The structure of ctrl_dumppolicy() is clearly split into
> init and dumping. Move the init to a .start callback
> for clarity, it's a more idiomatic netlink dump code structure.

Yep, makes sense.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 7/9] genetlink: bring back per op policy
  2020-10-01  0:05 ` [RFC net-next 7/9] genetlink: bring back per op policy Jakub Kicinski
@ 2020-10-01  7:53   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:53 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> Add policy to the struct genl_ops structure, this time
> with maxattr, so it can be used properly.
> 
> Propagate .policy and .maxattr from the family
> in genl_get_cmd() if needed, this say the rest of the

typo: "this way"

> code does not have to worry if the policy is per op
> or global.

Maybe make 'taskstats', which I munged a bit in commit 3b0f31f2b8c9
("genetlink: make policy common to family") go back to using per-command 
policy - properly this time with maxattr?


But the code here looks good to me.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY
  2020-10-01  0:05 ` [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY Jakub Kicinski
@ 2020-10-01  7:56   ` Johannes Berg
  0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:56 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> Wire up per-op policy for CTRL_CMD_GETPOLICY.
> This saves us a call to genlmsg_parse() and will soon allow
> dumping this policy.
> 
> Create a new policy definition, since we don't want to pollute
> ctrl_policy with attributes which CTRL_CMD_GETFAMILY does not
> support.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01  0:05 ` [RFC net-next 9/9] genetlink: allow dumping command-specific policy Jakub Kicinski
@ 2020-10-01  7:59   ` Johannes Berg
  2020-10-01 15:41     ` Jakub Kicinski
  0 siblings, 1 reply; 24+ messages in thread
From: Johannes Berg @ 2020-10-01  7:59 UTC (permalink / raw)
  To: Jakub Kicinski, netdev; +Cc: andrew, jiri, mkubecek, dsahern, pablo

On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> Right now CTRL_CMD_GETPOLICY can only dump the family-wide
> policy. Support dumping policy of a specific op.

So, hmm.

Yeah, I guess this is fine, but you could end up having to do a lot of
dumps, and with e.g. ethtool you'd end up with a lot of duplicate data
too, since it's structured as


common_policy = { ... }

cmd1_policy = {
	[CMD1_COMMON] = NLA_NESTED_POLICY(common_policy),
	...
};

cmd2_policy = {
	[CMD2_COMMON] = NLA_NESTED_POLICY(common_policy),
	...
};

etc.


So you end up dumping per command (and in practice, since they can be
different, you now *have to* unless you know out-of-band that there are
no per-command policies).


Even if I don't have a good idea now on how to avoid the duplication, it
might be nicer to have a (flag) attribute here for "CTRL_ATTR_ALL_OPS"?

johannes

> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  include/uapi/linux/genetlink.h |  1 +
>  net/netlink/genetlink.c        | 23 +++++++++++++++++++++--
>  2 files changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
> index 9c0636ec2286..7dbe2d5d7d46 100644
> --- a/include/uapi/linux/genetlink.h
> +++ b/include/uapi/linux/genetlink.h
> @@ -64,6 +64,7 @@ enum {
>  	CTRL_ATTR_OPS,
>  	CTRL_ATTR_MCAST_GROUPS,
>  	CTRL_ATTR_POLICY,
> +	CTRL_ATTR_OP,
>  	__CTRL_ATTR_MAX,
>  };
>  
> diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
> index f2833e9165c7..12e9f323af35 100644
> --- a/net/netlink/genetlink.c
> +++ b/net/netlink/genetlink.c
> @@ -1113,12 +1113,14 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
>  struct ctrl_dump_policy_ctx {
>  	unsigned long state;
>  	unsigned int fam_id;
> +	u8 cmd;
>  };
>  
>  static const struct nla_policy ctrl_policy_policy[] = {
>  	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
>  	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_NUL_STRING,
>  				    .len = GENL_NAMSIZ - 1 },
> +	[CTRL_ATTR_OP]		= { .type = NLA_U8 },
>  };
>  
>  static int ctrl_dumppolicy_start(struct netlink_callback *cb)
> @@ -1127,6 +1129,8 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
>  	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
>  	struct nlattr **tb = info->attrs;
>  	const struct genl_family *rt;
> +	struct genl_ops op;
> +	int err;
>  
>  	if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
>  		return -EINVAL;
> @@ -1145,10 +1149,23 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
>  	if (!rt)
>  		return -ENOENT;
>  
> -	if (!rt->policy)
> +	if (tb[CTRL_ATTR_OP]) {
> +		ctx->cmd = nla_get_u8(tb[CTRL_ATTR_OP]);
> +
> +		err = genl_get_cmd(ctx->cmd, rt, &op);
> +		if (err) {
> +			NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
> +			return err;
> +		}
> +	} else {
> +		op.policy = rt->policy;
> +		op.maxattr = rt->maxattr;
> +	}
> +
> +	if (!op.policy)
>  		return -ENODATA;
>  
> -	return netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
> +	return netlink_policy_dump_start(op.policy, op.maxattr, &ctx->state);
>  }
>  
>  static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
> @@ -1167,6 +1184,8 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
>  
>  		if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
>  			goto nla_put_failure;
> +		if (ctx->cmd && nla_put_u8(skb, CTRL_ATTR_OP, ctx->cmd))
> +			goto nla_put_failure;
>  
>  		nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
>  		if (!nest)


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 5/9] genetlink: add a structure for dump state
  2020-10-01  7:48   ` Johannes Berg
@ 2020-10-01  8:04     ` Michal Kubecek
  0 siblings, 0 replies; 24+ messages in thread
From: Michal Kubecek @ 2020-10-01  8:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Jakub Kicinski, netdev, andrew, jiri, dsahern, pablo

On Thu, Oct 01, 2020 at 09:48:31AM +0200, Johannes Berg wrote:
> On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> > Whenever netlink dump uses more than 2 cb->args[] entries
> > code gets hard to read. We're about to add more state to
> > ctrl_dumppolicy() so create a structure.
> > 
> > Since the structure is typed and clearly named we can remove
> > the local fam_id variable and use ctx->fam_id directly.
> > 
> > Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> > ---
> >  net/netlink/genetlink.c | 22 +++++++++++++---------
> >  1 file changed, 13 insertions(+), 9 deletions(-)
> > 
> > diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
> > index 38d8f353dba1..a8001044d8cd 100644
> > --- a/net/netlink/genetlink.c
> > +++ b/net/netlink/genetlink.c
> > @@ -1102,13 +1102,18 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
> >  	return 0;
> >  }
> >  
> > +struct ctrl_dump_policy_ctx {
> > +	unsigned long state;
> 
> Maybe if we do this, also make a "struct netlink_policy_dump_state" in
> include/net/netlink.h for the policy dump to use as a state? Right now
> it just uses an "unsigned long *state" there.
> 
> I feel that would more clearly show what this "state" actually is.
> 
> Alternatively, perhaps just rename it to "policy_dump_state"? Yeah,
> that's longer, but at least would be very obvious?
> 
> > +	unsigned int fam_id;
> 
> You could make this a u16 I guess, but it doesn't really matter.
> 
> >  static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
> >  {
> > +	struct ctrl_dump_policy_ctx *ctx = (void *)cb->args;
> 
> 
> I'd also prefer if you stuck a
> 
> 	BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->args));
> 
> here. It's not likely we'll need so much more state here, but would
> still be good to check IMHO.

Definitely. And it should rather be cb->ctx than cb->args as on 32-bit
architectures, cb->args is technically only 24 bytes while cb->ctx is
always 48 bytes long. After all, the comment in the structure definition
says args is deprecated.

Michal

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01  7:59   ` Johannes Berg
@ 2020-10-01 15:41     ` Jakub Kicinski
  2020-10-01 16:00       ` Johannes Berg
  0 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01 15:41 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, andrew, jiri, mkubecek, dsahern, pablo

On Thu, 01 Oct 2020 09:59:47 +0200 Johannes Berg wrote:
> On Wed, 2020-09-30 at 17:05 -0700, Jakub Kicinski wrote:
> > Right now CTRL_CMD_GETPOLICY can only dump the family-wide
> > policy. Support dumping policy of a specific op.  
> 
> So, hmm.
> 
> Yeah, I guess this is fine, but you could end up having to do a lot of
> dumps, and with e.g. ethtool you'd end up with a lot of duplicate data
> too, since it's structured as
> 
> 
> common_policy = { ... }
> 
> cmd1_policy = {
> 	[CMD1_COMMON] = NLA_NESTED_POLICY(common_policy),
> 	...
> };
> 
> cmd2_policy = {
> 	[CMD2_COMMON] = NLA_NESTED_POLICY(common_policy),
> 	...
> };
> 
> etc.
> 
> 
> So you end up dumping per command (and in practice, since they can be
> different, you now *have to* unless you know out-of-band that there are
> no per-command policies).
> 
> 
> Even if I don't have a good idea now on how to avoid the duplication, it
> might be nicer to have a (flag) attribute here for "CTRL_ATTR_ALL_OPS"?

Hm. How would you see the dump structured? We need to annotate the root
policies with the command. Right now I have:

 [ATTR_FAMILY_ID]
 [ATTR_OP]
 [ATTR_POLICY]
   [policy idx]
     [attr idx]
       [bla]
       [bla]
       [bla]

But if we're dumping _all_ the policy to op mapping is actually 1:n,
so we'd need to restructure the dump a lil' bit and have OP only
reported on root of the policy and make it a nested array.

Alternatively we could report OP -> policy mapping in a separate
message?

WDYT?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01 15:41     ` Jakub Kicinski
@ 2020-10-01 16:00       ` Johannes Berg
  2020-10-01 16:24         ` Jakub Kicinski
  0 siblings, 1 reply; 24+ messages in thread
From: Johannes Berg @ 2020-10-01 16:00 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: netdev, andrew, jiri, mkubecek, dsahern, pablo

On Thu, 2020-10-01 at 08:41 -0700, Jakub Kicinski wrote:

> > Even if I don't have a good idea now on how to avoid the duplication, it
> > might be nicer to have a (flag) attribute here for "CTRL_ATTR_ALL_OPS"?
> 
> Hm. How would you see the dump structured? 

Yeah, that's the tricky part ... Hence why I said "I don't have a good
idea now" :)

> We need to annotate the root
> policies with the command. Right now I have:
> 
>  [ATTR_FAMILY_ID]
>  [ATTR_OP]
>  [ATTR_POLICY]
>    [policy idx]
>      [attr idx]
>        [bla]
>        [bla]
>        [bla]
> 
> But if we're dumping _all_ the policy to op mapping is actually 1:n,
> so we'd need to restructure the dump a lil' bit and have OP only
> reported on root of the policy and make it a nested array.

So today you see something like

[ATTR_FAMILY_ID]
[ATTR_POLICY]
  [policy idx, 0 = main policy]
    [bla]
    ...
  ...


I guess the most compact representation, that also preserves the most
data about sharing, would be to do something like

[ATTR_FAMILY_ID]
[ATTR_POLICY]
  [policy idx, 0 = main policy]
    [bla]
    ...
  ...
[ATTR_OP_POLICY]
  [op] = [policy idx]
  ...

This preserves all the information because it tells you which policies
actually are identical (shared), each per-op policy can have nested
policies referring to common ones, like in the ethtool case, etc.


OTOH, it's a lot trickier to implement - I haven't really come up with a
good way of doing it "generically" with the net/netlink/policy.c code.
I'm sure it can be solved, but I haven't really given it enough thought.
Perhaps by passing a "policy iterator" to netlink_policy_dump_start(),
instead of just a single policy (i.e. a function & a data ptr or so),
and then it can walk all the policies using that, assign the idxes etc.,
and dump them out in netlink_policy_dump_write()?

But then we'd still have to get the policy idx for a given policy, and
not clean up all the state when netlink_policy_dump_loop() returns
false, because you still need it for ATTR_OP_POLICY to find the idx from
the pointer?

I guess it's doable. Just seems a bit more complex. OTOH, it may be that
such complexity also completely makes sense for non-generic netlink
families anyway, I haven't looked at them much at all.

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01 16:00       ` Johannes Berg
@ 2020-10-01 16:24         ` Jakub Kicinski
  2020-10-01 16:57           ` Johannes Berg
  0 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01 16:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, andrew, jiri, mkubecek, dsahern, pablo

On Thu, 01 Oct 2020 18:00:58 +0200 Johannes Berg wrote:
> On Thu, 2020-10-01 at 08:41 -0700, Jakub Kicinski wrote:
> 
> > > Even if I don't have a good idea now on how to avoid the duplication, it
> > > might be nicer to have a (flag) attribute here for "CTRL_ATTR_ALL_OPS"?  
> > 
> > Hm. How would you see the dump structured?   
> 
> Yeah, that's the tricky part ... Hence why I said "I don't have a good
> idea now" :)

You say that, yet your idea below seems pretty good :P

> > We need to annotate the root
> > policies with the command. Right now I have:
> > 
> >  [ATTR_FAMILY_ID]
> >  [ATTR_OP]
> >  [ATTR_POLICY]
> >    [policy idx]
> >      [attr idx]
> >        [bla]
> >        [bla]
> >        [bla]
> > 
> > But if we're dumping _all_ the policy to op mapping is actually 1:n,
> > so we'd need to restructure the dump a lil' bit and have OP only
> > reported on root of the policy and make it a nested array.  
> 
> So today you see something like
> 
> [ATTR_FAMILY_ID]
> [ATTR_POLICY]
>   [policy idx, 0 = main policy]
>     [bla]
>     ...
>   ...
> 
> 
> I guess the most compact representation, that also preserves the most
> data about sharing, would be to do something like
> 
> [ATTR_FAMILY_ID]
> [ATTR_POLICY]
>   [policy idx, 0 = main policy]
>     [bla]
>     ...
>   ...
> [ATTR_OP_POLICY]
>   [op] = [policy idx]
>   ...
> 
> This preserves all the information because it tells you which policies
> actually are identical (shared), each per-op policy can have nested
> policies referring to common ones, like in the ethtool case, etc.

Only comment I have is - can we make sure to put the ATTR_OP_POLICY
first? That way user space can parse the stream an pick out the info
it needs rather than recording all the policies only to find out later
which one is which.

> OTOH, it's a lot trickier to implement - I haven't really come up with a
> good way of doing it "generically" with the net/netlink/policy.c code.
> I'm sure it can be solved, but I haven't really given it enough thought.
> Perhaps by passing a "policy iterator" to netlink_policy_dump_start(),
> instead of just a single policy (i.e. a function & a data ptr or so),
> and then it can walk all the policies using that, assign the idxes etc.,
> and dump them out in netlink_policy_dump_write()?
> 
> But then we'd still have to get the policy idx for a given policy, and
> not clean up all the state when netlink_policy_dump_loop() returns
> false, because you still need it for ATTR_OP_POLICY to find the idx from
> the pointer?
> 
> I guess it's doable. Just seems a bit more complex. OTOH, it may be that
> such complexity also completely makes sense for non-generic netlink
> families anyway, I haven't looked at them much at all.

IDK, doesn't seem crazy hard. We can create some iterator or expand the
API with "begin" "add" "end" calls. Then once dumper state is build we
can ask it which ids it assigned.

OTOH I don't think we have a use for this in ethtool, because user
space usually does just one op per execution. So I'm thinking to use
your structure for the dump, but leave the actual implementation of
"dump all" for "later".

How does that sound?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01 16:24         ` Jakub Kicinski
@ 2020-10-01 16:57           ` Johannes Berg
  2020-10-01 17:09             ` Jakub Kicinski
  0 siblings, 1 reply; 24+ messages in thread
From: Johannes Berg @ 2020-10-01 16:57 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: netdev, andrew, jiri, mkubecek, dsahern, pablo

On Thu, 2020-10-01 at 09:24 -0700, Jakub Kicinski wrote:

> > I guess the most compact representation, that also preserves the most
> > data about sharing, would be to do something like
> > 
> > [ATTR_FAMILY_ID]
> > [ATTR_POLICY]
> >   [policy idx, 0 = main policy]
> >     [bla]
> >     ...
> >   ...
> > [ATTR_OP_POLICY]
> >   [op] = [policy idx]
> >   ...

> Only comment I have is - can we make sure to put the ATTR_OP_POLICY
> first? That way user space can parse the stream an pick out the info
> it needs rather than recording all the policies only to find out later
> which one is which.

Hmm. Yes, that makes sense. But I don't see why not - you could go do
the netlink_policy_dump_start() which that assigns the indexes, then
dump out ATTR_OP_POLICY looking up the indexes in the table that it
created, and then dump out all the policies?

> > I guess it's doable. Just seems a bit more complex. OTOH, it may be that
> > such complexity also completely makes sense for non-generic netlink
> > families anyway, I haven't looked at them much at all.
> 
> IDK, doesn't seem crazy hard. We can create some iterator or expand the
> API with "begin" "add" "end" calls. Then once dumper state is build we
> can ask it which ids it assigned.

Yeah. Seems feasible. Maybe I'll take a stab at it (later, when I can).

> OTOH I don't think we have a use for this in ethtool, because user
> space usually does just one op per execution. So I'm thinking to use
> your structure for the dump, but leave the actual implementation of
> "dump all" for "later".
> 
> How does that sound?

I'm not sure you even need that structure if you have the "filter by
op"? I mean, then just stick to what you had?

When I started down this road I more had in mind "sniffer-like" tools
that want to understand the messages better, etc. without really having
any domain-specific "knowledge" encoded in them. And then you'd probably
really want to build the entire policy representation in the tool side
first.

Or perhaps even tools you could run on the latest kernel to generate
code (e.g. python code was discussed) that would be able to build
messages. You'd want to generate the code once on the latest kernel when
you need a new feature, and then actually use it instead of redoing it
at runtime, but still, could be done.

I suppose you have a completely different use case in mind :-)

johannes


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC net-next 9/9] genetlink: allow dumping command-specific policy
  2020-10-01 16:57           ` Johannes Berg
@ 2020-10-01 17:09             ` Jakub Kicinski
  0 siblings, 0 replies; 24+ messages in thread
From: Jakub Kicinski @ 2020-10-01 17:09 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, andrew, jiri, mkubecek, dsahern, pablo

On Thu, 01 Oct 2020 18:57:35 +0200 Johannes Berg wrote:
> On Thu, 2020-10-01 at 09:24 -0700, Jakub Kicinski wrote:
> > > I guess the most compact representation, that also preserves the most
> > > data about sharing, would be to do something like
> > > 
> > > [ATTR_FAMILY_ID]
> > > [ATTR_POLICY]
> > >   [policy idx, 0 = main policy]
> > >     [bla]
> > >     ...
> > >   ...
> > > [ATTR_OP_POLICY]
> > >   [op] = [policy idx]
> > >   ...  
> 
> > Only comment I have is - can we make sure to put the ATTR_OP_POLICY
> > first? That way user space can parse the stream an pick out the info
> > it needs rather than recording all the policies only to find out later
> > which one is which.  
> 
> Hmm. Yes, that makes sense. But I don't see why not - you could go do
> the netlink_policy_dump_start() which that assigns the indexes, then
> dump out ATTR_OP_POLICY looking up the indexes in the table that it
> created, and then dump out all the policies?

Ack.

> > > I guess it's doable. Just seems a bit more complex. OTOH, it may be that
> > > such complexity also completely makes sense for non-generic netlink
> > > families anyway, I haven't looked at them much at all.  
> > 
> > IDK, doesn't seem crazy hard. We can create some iterator or expand the
> > API with "begin" "add" "end" calls. Then once dumper state is build we
> > can ask it which ids it assigned.  
> 
> Yeah. Seems feasible. Maybe I'll take a stab at it (later, when I can).
> 
> > OTOH I don't think we have a use for this in ethtool, because user
> > space usually does just one op per execution. So I'm thinking to use
> > your structure for the dump, but leave the actual implementation of
> > "dump all" for "later".
> > 
> > How does that sound?  
> 
> I'm not sure you even need that structure if you have the "filter by
> op"? I mean, then just stick to what you had?

I was adding OP as an attribute to each message. I will just ditch that
given user space should know what it asked for.

> When I started down this road I more had in mind "sniffer-like" tools
> that want to understand the messages better, etc. without really having
> any domain-specific "knowledge" encoded in them. And then you'd probably
> really want to build the entire policy representation in the tool side
> first.
> 
> Or perhaps even tools you could run on the latest kernel to generate
> code (e.g. python code was discussed) that would be able to build
> messages. You'd want to generate the code once on the latest kernel when
> you need a new feature, and then actually use it instead of redoing it
> at runtime, but still, could be done.
> 
> I suppose you have a completely different use case in mind :-)

I see. Yes, I'm trying to avoid having to probe the kernel for features.
We added new flags to ethtool to include extra info in the output, and
older kernels with return EOPNOTSUPP for the entire operation if those
are set (due to strict checking). While user would probably expect the
information to just not be there if kernel can't provide it. New
kernels can't provide it all the time either (it's extra stats from the
driver).

I'm hoping Michal will accept this as a solution :) Retrying on
EOPNOTSUPP gets a little hairy for my taste.

That should have been in the cover letter, I guess.

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2020-10-01 17:09 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-01  0:05 [RFC net-next 0/9] genetlink: support per-command policy dump Jakub Kicinski
2020-10-01  0:05 ` [RFC net-next 1/9] genetlink: add missing kdoc for validation flags Jakub Kicinski
2020-10-01  0:05 ` [RFC net-next 2/9] genetlink: reorg struct genl_family Jakub Kicinski
2020-10-01  7:34   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 3/9] genetlink: add small version of ops Jakub Kicinski
2020-10-01  7:40   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 4/9] genetlink: move to smaller ops wherever possible Jakub Kicinski
2020-10-01  7:42   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 5/9] genetlink: add a structure for dump state Jakub Kicinski
2020-10-01  7:48   ` Johannes Berg
2020-10-01  8:04     ` Michal Kubecek
2020-10-01  0:05 ` [RFC net-next 6/9] genetlink: use .start callback for dumppolicy Jakub Kicinski
2020-10-01  7:49   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 7/9] genetlink: bring back per op policy Jakub Kicinski
2020-10-01  7:53   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 8/9] genetlink: use per-op policy for CTRL_CMD_GETPOLICY Jakub Kicinski
2020-10-01  7:56   ` Johannes Berg
2020-10-01  0:05 ` [RFC net-next 9/9] genetlink: allow dumping command-specific policy Jakub Kicinski
2020-10-01  7:59   ` Johannes Berg
2020-10-01 15:41     ` Jakub Kicinski
2020-10-01 16:00       ` Johannes Berg
2020-10-01 16:24         ` Jakub Kicinski
2020-10-01 16:57           ` Johannes Berg
2020-10-01 17:09             ` Jakub Kicinski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.