From 3686ec5e84977eddc796903177e7e0a122585c11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:43 +0100 Subject: genetlink: remove genl_register_ops/genl_unregister_ops genl_register_ops() is still needed for internal registration, but is no longer available to users of the API. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 9b787b6..617d718 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -141,8 +141,6 @@ static inline int genl_register_family_with_ops(struct genl_family *family, } int genl_unregister_family(struct genl_family *family); -int genl_register_ops(struct genl_family *, struct genl_ops *ops); -int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); void genl_unregister_mc_group(struct genl_family *family, -- cgit v1.1 From d91824c08fbcb265ec930d863fa905e8daa836a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:44 +0100 Subject: genetlink: register family ops as array Instead of using a linked list, use an array. This reduces the data size needed by the users of genetlink, for example in wireless (net/wireless/nl80211.c) on 64-bit it frees up over 1K of data space. Remove the attempted sending of CTRL_CMD_NEWOPS ctrl event since genl_ctrl_event(CTRL_CMD_NEWOPS, ...) only returns -EINVAL anyway, therefore no such event could ever be sent. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 617d718..d4802af 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -39,9 +39,10 @@ struct genl_info; * @post_doit: called after an operation's doit callback, it may * undo operations done by pre_doit, for example release locks * @attrbuf: buffer to store parsed attributes - * @ops_list: list of all assigned operations * @family_list: family list * @mcast_groups: multicast groups list + * @ops: the operations supported by this family (private) + * @n_ops: number of operations supported by this family (private) */ struct genl_family { unsigned int id; @@ -58,7 +59,8 @@ struct genl_family { struct sk_buff *skb, struct genl_info *info); struct nlattr ** attrbuf; /* private */ - struct list_head ops_list; /* private */ + struct genl_ops * ops; /* private */ + unsigned int n_ops; /* private */ struct list_head family_list; /* private */ struct list_head mcast_groups; /* private */ struct module *module; @@ -119,7 +121,6 @@ struct genl_ops { int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); - struct list_head ops_list; }; int __genl_register_family(struct genl_family *family); -- cgit v1.1 From f84f771d942182e39a56ec2989d6a67d3ca33a13 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:45 +0100 Subject: genetlink: allow making ops const Allow making the ops array const by not modifying the ops flags on registration but rather only when ops are sent out in the family information. No users are updated yet except for the pre_doit/post_doit calls in wireless (the only ones that exist now.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d4802af..d87486a 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -52,14 +52,14 @@ struct genl_family { unsigned int maxattr; bool netnsok; bool parallel_ops; - int (*pre_doit)(struct genl_ops *ops, + int (*pre_doit)(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); - void (*post_doit)(struct genl_ops *ops, + void (*post_doit)(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); struct nlattr ** attrbuf; /* private */ - struct genl_ops * ops; /* private */ + const struct genl_ops * ops; /* private */ unsigned int n_ops; /* private */ struct list_head family_list; /* private */ struct list_head mcast_groups; /* private */ @@ -132,10 +132,10 @@ static inline int genl_register_family(struct genl_family *family) } int __genl_register_family_with_ops(struct genl_family *family, - struct genl_ops *ops, size_t n_ops); + const struct genl_ops *ops, size_t n_ops); static inline int genl_register_family_with_ops(struct genl_family *family, - struct genl_ops *ops, size_t n_ops) + const struct genl_ops *ops, size_t n_ops) { family->module = THIS_MODULE; return __genl_register_family_with_ops(family, ops, n_ops); -- cgit v1.1 From 3f5ccd06aecd0eb1651dd451439d5cb365170854 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:47 +0100 Subject: genetlink: make genl_ops flags a u8 and move to end To save some space in the struct on 32-bit systems, make the flags a u8 (only 4 bits are used) and also move them to the end of the struct. This has no impact on 64-bit systems as alignment of the struct in an array uses up the space anyway. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d87486a..0b6a144 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -112,15 +112,15 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net) * @ops_list: operations list */ struct genl_ops { - u8 cmd; - u8 internal_flags; - unsigned int flags; const struct nla_policy *policy; int (*doit)(struct sk_buff *skb, struct genl_info *info); int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); + u8 cmd; + u8 internal_flags; + u8 flags; }; int __genl_register_family(struct genl_family *family); -- cgit v1.1 From 568508aa0724cc39bcf7d3d8001bd27a45609800 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2013 14:19:08 +0100 Subject: genetlink: unify registration functions Now that the ops assignment is just two variables rather than a long list iteration etc., there's no reason to separately export __genl_register_family() and __genl_register_family_with_ops(). Unify the two functions into __genl_register_family() and make genl_register_family_with_ops() call it after assigning the ops. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 0b6a144..e96385d 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -131,14 +131,34 @@ static inline int genl_register_family(struct genl_family *family) return __genl_register_family(family); } -int __genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, size_t n_ops); - +/** + * genl_register_family_with_ops - register a generic netlink family with ops + * @family: generic netlink family + * @ops: operations to be registered + * @n_ops: number of elements to register + * + * Registers the specified family and operations from the specified table. + * Only one family may be registered with the same family name or identifier. + * + * The family id may equal GENL_ID_GENERATE causing an unique id to + * be automatically generated and assigned. + * + * Either a doit or dumpit callback must be specified for every registered + * operation or the function will fail. Only one operation structure per + * command identifier may be registered. + * + * See include/net/genetlink.h for more documenation on the operations + * structure. + * + * Return 0 on success or a negative error code. + */ static inline int genl_register_family_with_ops(struct genl_family *family, const struct genl_ops *ops, size_t n_ops) { family->module = THIS_MODULE; - return __genl_register_family_with_ops(family, ops, n_ops); + family->ops = ops; + family->n_ops = n_ops; + return __genl_register_family(family); } int genl_unregister_family(struct genl_family *family); -- cgit v1.1 From c53ed7423619b4e8108914a9f31b426dd58ad591 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:31 +0100 Subject: genetlink: only pass array to genl_register_family_with_ops() As suggested by David Miller, make genl_register_family_with_ops() a macro and pass only the array, evaluating ARRAY_SIZE() in the macro, this is a little safer. The openvswitch has some indirection, assing ops/n_ops directly in that code. This might ultimately just assign the pointers in the family initializations, saving the struct genl_family_and_ops and code (once mcast groups are handled differently.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index e96385d..9bd52a4 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -152,8 +152,9 @@ static inline int genl_register_family(struct genl_family *family) * * Return 0 on success or a negative error code. */ -static inline int genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, size_t n_ops) +static inline int _genl_register_family_with_ops(struct genl_family *family, + const struct genl_ops *ops, + size_t n_ops) { family->module = THIS_MODULE; family->ops = ops; @@ -161,6 +162,9 @@ static inline int genl_register_family_with_ops(struct genl_family *family, return __genl_register_family(family); } +#define genl_register_family_with_ops(family, ops) \ + _genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops)) + int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -- cgit v1.1 From 06fb555a273dc8ef0d876f4e864ad11cfcea63e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:35 +0100 Subject: genetlink: remove genl_unregister_mc_group() There are no users of this API remaining, and we'll soon change group registration to be static (like ops are now) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 9bd52a4..067569d 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -168,8 +168,6 @@ static inline int _genl_register_family_with_ops(struct genl_family *family, int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -void genl_unregister_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); -- cgit v1.1 From c2ebb908469d507ff400dad94efc755e6c799672 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:36 +0100 Subject: genetlink: remove family pointer from genl_multicast_group There's no reason to have the family pointer there since it can just be passed internally where needed, so remove it. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 067569d..d8a8b1f 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -13,10 +13,8 @@ * @id: multicast group ID, assigned by the core, to use with * genlmsg_multicast(). * @list: list entry for linking - * @family: pointer to family, need not be set before registering */ struct genl_multicast_group { - struct genl_family *family; /* private */ struct list_head list; /* private */ char name[GENL_NAMSIZ]; u32 id; -- cgit v1.1 From 62b68e99faa802352e9cb2ae91adecd8dfddf1b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:37 +0100 Subject: genetlink: add and use genl_set_err() Add a static inline to generic netlink to wrap netlink_set_err() to make it easier to use here - use it in openvswitch (the only generic netlink user of netlink_set_err()). Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d8a8b1f..11ac77f 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -351,5 +351,19 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) return nlmsg_new(genlmsg_total_size(payload), flags); } +/** + * genl_set_err - report error to genetlink broadcast listeners + * @net: the network namespace to report the error to + * @portid: the PORTID of a process that we want to skip (if any) + * @group: the broadcast group that will notice the error + * @code: error code, must be negative (as usual in kernelspace) + * + * This function returns the number of broadcast listeners that have set the + * NETLINK_RECV_NO_ENOBUFS socket option. + */ +static inline int genl_set_err(struct net *net, u32 portid, u32 group, int code) +{ + return netlink_set_err(net->genl_sock, portid, group, code); +} #endif /* __NET_GENERIC_NETLINK_H */ -- cgit v1.1 From 68eb55031da7c967d954e5f9415cd05f4abdb692 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:38 +0100 Subject: genetlink: pass family to functions using groups This doesn't really change anything, but prepares for the next patch that will change the APIs to pass the group ID within the family, rather than the global group ID. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 11ac77f..60aef0d 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -166,7 +166,8 @@ static inline int _genl_register_family_with_ops(struct genl_family *family, int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, +void genl_notify(struct genl_family *family, + struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, @@ -246,13 +247,15 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) /** * genlmsg_multicast_netns - multicast a netlink message to a specific netns + * @family: the generic netlink family * @net: the net namespace * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself * @group: multicast group id * @flags: allocation flags */ -static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, +static inline int genlmsg_multicast_netns(struct genl_family *family, + struct net *net, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); @@ -260,19 +263,23 @@ static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, /** * genlmsg_multicast - multicast a netlink message to the default netns + * @family: the generic netlink family * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself * @group: multicast group id * @flags: allocation flags */ -static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid, +static inline int genlmsg_multicast(struct genl_family *family, + struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { - return genlmsg_multicast_netns(&init_net, skb, portid, group, flags); + return genlmsg_multicast_netns(family, &init_net, skb, + portid, group, flags); } /** * genlmsg_multicast_allns - multicast a netlink message to all net namespaces + * @family: the generic netlink family * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself * @group: multicast group id @@ -280,7 +287,8 @@ static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid, * * This function must hold the RTNL or rcu_read_lock(). */ -int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid, +int genlmsg_multicast_allns(struct genl_family *family, + struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags); /** @@ -353,6 +361,7 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) /** * genl_set_err - report error to genetlink broadcast listeners + * @family: the generic netlink family * @net: the network namespace to report the error to * @portid: the PORTID of a process that we want to skip (if any) * @group: the broadcast group that will notice the error @@ -361,7 +370,8 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) * This function returns the number of broadcast listeners that have set the * NETLINK_RECV_NO_ENOBUFS socket option. */ -static inline int genl_set_err(struct net *net, u32 portid, u32 group, int code) +static inline int genl_set_err(struct genl_family *family, struct net *net, + u32 portid, u32 group, int code) { return netlink_set_err(net->genl_sock, portid, group, code); } -- cgit v1.1 From 2a94fe48f32ccf7321450a2cc07f2b724a444e5b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:39 +0100 Subject: genetlink: make multicast groups const, prevent abuse Register generic netlink multicast groups as an array with the family and give them contiguous group IDs. Then instead of passing the global group ID to the various functions that send messages, pass the ID relative to the family - for most families that's just 0 because the only have one group. This avoids the list_head and ID in each group, adding a new field for the mcast group ID offset to the family. At the same time, this allows us to prevent abusing groups again like the quota and dropmon code did, since we can now check that a family only uses a group it owns. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'include/net') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 60aef0d..ace4abf 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -10,14 +10,9 @@ /** * struct genl_multicast_group - generic netlink multicast group * @name: name of the multicast group, names are per-family - * @id: multicast group ID, assigned by the core, to use with - * genlmsg_multicast(). - * @list: list entry for linking */ struct genl_multicast_group { - struct list_head list; /* private */ char name[GENL_NAMSIZ]; - u32 id; }; struct genl_ops; @@ -38,7 +33,9 @@ struct genl_info; * undo operations done by pre_doit, for example release locks * @attrbuf: buffer to store parsed attributes * @family_list: family list - * @mcast_groups: multicast groups list + * @mcgrps: multicast groups used by this family (private) + * @n_mcgrps: number of multicast groups (private) + * @mcgrp_offset: starting number of multicast group IDs in this family * @ops: the operations supported by this family (private) * @n_ops: number of operations supported by this family (private) */ @@ -58,9 +55,11 @@ struct genl_family { struct genl_info *info); struct nlattr ** attrbuf; /* private */ const struct genl_ops * ops; /* private */ + const struct genl_multicast_group *mcgrps; /* private */ unsigned int n_ops; /* private */ + unsigned int n_mcgrps; /* private */ + unsigned int mcgrp_offset; /* private */ struct list_head family_list; /* private */ - struct list_head mcast_groups; /* private */ struct module *module; }; @@ -150,22 +149,30 @@ static inline int genl_register_family(struct genl_family *family) * * Return 0 on success or a negative error code. */ -static inline int _genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, - size_t n_ops) +static inline int +_genl_register_family_with_ops_grps(struct genl_family *family, + const struct genl_ops *ops, size_t n_ops, + const struct genl_multicast_group *mcgrps, + size_t n_mcgrps) { family->module = THIS_MODULE; family->ops = ops; family->n_ops = n_ops; + family->mcgrps = mcgrps; + family->n_mcgrps = n_mcgrps; return __genl_register_family(family); } -#define genl_register_family_with_ops(family, ops) \ - _genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops)) +#define genl_register_family_with_ops(family, ops) \ + _genl_register_family_with_ops_grps((family), \ + (ops), ARRAY_SIZE(ops), \ + NULL, 0) +#define genl_register_family_with_ops_groups(family, ops, grps) \ + _genl_register_family_with_ops_grps((family), \ + (ops), ARRAY_SIZE(ops), \ + (grps), ARRAY_SIZE(grps)) int genl_unregister_family(struct genl_family *family); -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); void genl_notify(struct genl_family *family, struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); @@ -251,13 +258,16 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) * @net: the net namespace * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array * @flags: allocation flags */ static inline int genlmsg_multicast_netns(struct genl_family *family, struct net *net, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); } @@ -266,13 +276,16 @@ static inline int genlmsg_multicast_netns(struct genl_family *family, * @family: the generic netlink family * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array * @flags: allocation flags */ static inline int genlmsg_multicast(struct genl_family *family, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return genlmsg_multicast_netns(family, &init_net, skb, portid, group, flags); } @@ -282,7 +295,7 @@ static inline int genlmsg_multicast(struct genl_family *family, * @family: the generic netlink family * @skb: netlink message as socket buffer * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array * @flags: allocation flags * * This function must hold the RTNL or rcu_read_lock(). @@ -365,6 +378,7 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) * @net: the network namespace to report the error to * @portid: the PORTID of a process that we want to skip (if any) * @group: the broadcast group that will notice the error + * (this is the offset of the multicast group in the groups array) * @code: error code, must be negative (as usual in kernelspace) * * This function returns the number of broadcast listeners that have set the -- cgit v1.1