Commit 0fb6af70 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'genetlink-improvements'



Johannes Berg says:

====================
genetlink improvements

This series contains some generic netlink improvements, making
the API safer to use, and making the function pointers in the
family struct safer by allowing it to be __ro_after_init.

The first patch, introducing genl_family_attrbuf(), just ensures
that the users of family->attrbuf aren't actually racy, but making
them use the indirection function for obtaining a reference and
checking that the context can actually do so.

The second patch removes the more or less broken ability to have
a static family ID, the three IDs that need to be static because
it's simply needed (genl controller), or due to old API misused.
Everything else couldn't be static anyway, or could fail when the
family is registered, if somebody else already got a static ID.

The third patch statically initializes the families, mostly to save
some code. I wrote this initially because I thought I could make
them all const, but that ends up being very inefficient (it would
require always doing some kind of family -> id lookup), so now it's
just here because I had it already and it reduces the code size.

The fourth patch then, finally, lays the groundwork for what I had
really wanted - now with __ro_after_init instead of const; I remove
code there to do the ID->family hash table mapping in genetlink and
use IDR instead to both allocate and map the IDs, which again ends
up saving some code size.

Finally, the fifth patch updates all families, as it turns out, no
families exist that really dynamically register/unregister. This
last patch should perhaps be split up, I could submit it for each
subsystem separately, but it'd depend on the second and third to
go in first, so would take a while. I can do that though, if that
seems better to you.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4fe77d82 56989f6d
......@@ -82,8 +82,8 @@ static const struct genl_multicast_group acpi_event_mcgrps[] = {
{ .name = ACPI_GENL_MCAST_GROUP_NAME, },
};
static struct genl_family acpi_event_genl_family = {
.id = GENL_ID_GENERATE,
static struct genl_family acpi_event_genl_family __ro_after_init = {
.module = THIS_MODULE,
.name = ACPI_GENL_FAMILY_NAME,
.version = ACPI_GENL_VERSION,
.maxattr = ACPI_GENL_ATTR_MAX,
......@@ -144,7 +144,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
static int acpi_event_genetlink_init(void)
static int __init acpi_event_genetlink_init(void)
{
return genl_register_family(&acpi_event_genl_family);
}
......
......@@ -1094,14 +1094,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)
return 0;
}
static struct genl_family gtp_genl_family = {
.id = GENL_ID_GENERATE,
.name = "gtp",
.version = 0,
.hdrsize = 0,
.maxattr = GTPA_MAX,
.netnsok = true,
};
static struct genl_family gtp_genl_family;
static int gtp_genl_fill_info(struct sk_buff *skb, u32 snd_portid, u32 snd_seq,
u32 type, struct pdp_ctx *pctx)
......@@ -1297,6 +1290,17 @@ static const struct genl_ops gtp_genl_ops[] = {
},
};
static struct genl_family gtp_genl_family __ro_after_init = {
.name = "gtp",
.version = 0,
.hdrsize = 0,
.maxattr = GTPA_MAX,
.netnsok = true,
.module = THIS_MODULE,
.ops = gtp_genl_ops,
.n_ops = ARRAY_SIZE(gtp_genl_ops),
};
static int __net_init gtp_net_init(struct net *net)
{
struct gtp_net *gn = net_generic(net, gtp_net_id);
......@@ -1336,7 +1340,7 @@ static int __init gtp_init(void)
if (err < 0)
goto error_out;
err = genl_register_family_with_ops(&gtp_genl_family, gtp_genl_ops);
err = genl_register_family(&gtp_genl_family);
if (err < 0)
goto unreg_rtnl_link;
......
......@@ -1421,14 +1421,7 @@ static void clear_tx_sa(struct macsec_tx_sa *tx_sa)
macsec_txsa_put(tx_sa);
}
static struct genl_family macsec_fam = {
.id = GENL_ID_GENERATE,
.name = MACSEC_GENL_NAME,
.hdrsize = 0,
.version = MACSEC_GENL_VERSION,
.maxattr = MACSEC_ATTR_MAX,
.netnsok = true,
};
static struct genl_family macsec_fam;
static struct net_device *get_dev_from_nl(struct net *net,
struct nlattr **attrs)
......@@ -2655,6 +2648,17 @@ static const struct genl_ops macsec_genl_ops[] = {
},
};
static struct genl_family macsec_fam __ro_after_init = {
.name = MACSEC_GENL_NAME,
.hdrsize = 0,
.version = MACSEC_GENL_VERSION,
.maxattr = MACSEC_ATTR_MAX,
.netnsok = true,
.module = THIS_MODULE,
.ops = macsec_genl_ops,
.n_ops = ARRAY_SIZE(macsec_genl_ops),
};
static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
......@@ -3462,7 +3466,7 @@ static int __init macsec_init(void)
if (err)
goto notifier;
err = genl_register_family_with_ops(&macsec_fam, macsec_genl_ops);
err = genl_register_family(&macsec_fam);
if (err)
goto rtnl;
......
......@@ -2150,13 +2150,7 @@ static struct rtnl_link_ops team_link_ops __read_mostly = {
* Generic netlink custom interface
***********************************/
static struct genl_family team_nl_family = {
.id = GENL_ID_GENERATE,
.name = TEAM_GENL_NAME,
.version = TEAM_GENL_VERSION,
.maxattr = TEAM_ATTR_MAX,
.netnsok = true,
};
static struct genl_family team_nl_family;
static const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
[TEAM_ATTR_UNSPEC] = { .type = NLA_UNSPEC, },
......@@ -2746,6 +2740,18 @@ static const struct genl_multicast_group team_nl_mcgrps[] = {
{ .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, },
};
static struct genl_family team_nl_family __ro_after_init = {
.name = TEAM_GENL_NAME,
.version = TEAM_GENL_VERSION,
.maxattr = TEAM_ATTR_MAX,
.netnsok = true,
.module = THIS_MODULE,
.ops = team_nl_ops,
.n_ops = ARRAY_SIZE(team_nl_ops),
.mcgrps = team_nl_mcgrps,
.n_mcgrps = ARRAY_SIZE(team_nl_mcgrps),
};
static int team_nl_send_multicast(struct sk_buff *skb,
struct team *team, u32 portid)
{
......@@ -2767,10 +2773,9 @@ static int team_nl_send_event_port_get(struct team *team,
port);
}
static int team_nl_init(void)
static int __init team_nl_init(void)
{
return genl_register_family_with_ops_groups(&team_nl_family, team_nl_ops,
team_nl_mcgrps);
return genl_register_family(&team_nl_family);
}
static void team_nl_fini(void)
......
......@@ -587,15 +587,8 @@ struct hwsim_radiotap_ack_hdr {
__le16 rt_chbitmask;
} __packed;
/* MAC80211_HWSIM netlinf family */
static struct genl_family hwsim_genl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "MAC80211_HWSIM",
.version = 1,
.maxattr = HWSIM_ATTR_MAX,
.netnsok = true,
};
/* MAC80211_HWSIM netlink family */
static struct genl_family hwsim_genl_family;
enum hwsim_multicast_groups {
HWSIM_MCGRP_CONFIG,
......@@ -3235,6 +3228,18 @@ static const struct genl_ops hwsim_ops[] = {
},
};
static struct genl_family hwsim_genl_family __ro_after_init = {
.name = "MAC80211_HWSIM",
.version = 1,
.maxattr = HWSIM_ATTR_MAX,
.netnsok = true,
.module = THIS_MODULE,
.ops = hwsim_ops,
.n_ops = ARRAY_SIZE(hwsim_ops),
.mcgrps = hwsim_mcgrps,
.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
};
static void destroy_radio(struct work_struct *work)
{
struct mac80211_hwsim_data *data =
......@@ -3282,15 +3287,13 @@ static struct notifier_block hwsim_netlink_notifier = {
.notifier_call = mac80211_hwsim_netlink_notify,
};
static int hwsim_init_netlink(void)
static int __init hwsim_init_netlink(void)
{
int rc;
printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
rc = genl_register_family_with_ops_groups(&hwsim_genl_family,
hwsim_ops,
hwsim_mcgrps);
rc = genl_register_family(&hwsim_genl_family);
if (rc)
goto failure;
......
......@@ -1368,13 +1368,8 @@ static struct genl_multicast_group pmcraid_mcgrps[] = {
{ .name = "events", /* not really used - see ID discussion below */ },
};
static struct genl_family pmcraid_event_family = {
/*
* Due to prior multicast group abuse (the code having assumed that
* the family ID can be used as a multicast group ID) we need to
* statically allocate a family (and thus group) ID.
*/
.id = GENL_ID_PMCRAID,
static struct genl_family pmcraid_event_family __ro_after_init = {
.module = THIS_MODULE,
.name = "pmcraid",
.version = 1,
.maxattr = PMCRAID_AEN_ATTR_MAX,
......@@ -1389,7 +1384,7 @@ static struct genl_family pmcraid_event_family = {
* 0 if the pmcraid_event_family is successfully registered
* with netlink generic, non-zero otherwise
*/
static int pmcraid_netlink_init(void)
static int __init pmcraid_netlink_init(void)
{
int result;
......
......@@ -147,8 +147,8 @@ static const struct genl_multicast_group tcmu_mcgrps[] = {
};
/* Our generic netlink family */
static struct genl_family tcmu_genl_family = {
.id = GENL_ID_GENERATE,
static struct genl_family tcmu_genl_family __ro_after_init = {
.module = THIS_MODULE,
.hdrsize = 0,
.name = "TCM-USER",
.version = 1,
......
......@@ -2163,8 +2163,8 @@ static const struct genl_multicast_group thermal_event_mcgrps[] = {
{ .name = THERMAL_GENL_MCAST_GROUP_NAME, },
};
static struct genl_family thermal_event_genl_family = {
.id = GENL_ID_GENERATE,
static struct genl_family thermal_event_genl_family __ro_after_init = {
.module = THIS_MODULE,
.name = THERMAL_GENL_FAMILY_NAME,
.version = THERMAL_GENL_VERSION,
.maxattr = THERMAL_GENL_ATTR_MAX,
......@@ -2235,7 +2235,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
static int genetlink_init(void)
static int __init genetlink_init(void)
{
return genl_register_family(&thermal_event_genl_family);
}
......
......@@ -16,11 +16,7 @@
static uint32_t dlm_nl_seqnum;
static uint32_t listener_nlportid;
static struct genl_family family = {
.id = GENL_ID_GENERATE,
.name = DLM_GENL_NAME,
.version = DLM_GENL_VERSION,
};
static struct genl_family family;
static int prepare_data(u8 cmd, struct sk_buff **skbp, size_t size)
{
......@@ -76,9 +72,17 @@ static 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),
.module = THIS_MODULE,
};
int __init dlm_netlink_init(void)
{
return genl_register_family_with_ops(&family, dlm_nl_ops);
return genl_register_family(&family);
}
void dlm_netlink_exit(void)
......
......@@ -12,14 +12,8 @@ static const struct genl_multicast_group quota_mcgrps[] = {
};
/* Netlink family structure for quota */
static struct genl_family quota_genl_family = {
/*
* Needed due to multicast group ID abuse - old code assumed
* the family ID was also a valid multicast group ID (which
* isn't true) and userspace might thus rely on it. Assign a
* static ID for this group to make dealing with that easier.
*/
.id = GENL_ID_VFS_DQUOT,
static struct genl_family quota_genl_family __ro_after_init = {
.module = THIS_MODULE,
.hdrsize = 0,
.name = "VFS_DQUOT",
.version = 1,
......
......@@ -67,7 +67,7 @@
* genl_magic_func.h
* generates an entry in the static genl_ops array,
* and static register/unregister functions to
* genl_register_family_with_ops().
* genl_register_family().
*
* flags and handler:
* GENL_op_init( .doit = x, .dumpit = y, .flags = something)
......
......@@ -259,16 +259,7 @@ static struct genl_ops ZZZ_genl_ops[] __read_mostly = {
* {{{2
*/
#define ZZZ_genl_family CONCAT_(GENL_MAGIC_FAMILY, _genl_family)
static struct genl_family ZZZ_genl_family __read_mostly = {
.id = GENL_ID_GENERATE,
.name = __stringify(GENL_MAGIC_FAMILY),
.version = GENL_MAGIC_VERSION,
#ifdef GENL_MAGIC_FAMILY_HDRSZ
.hdrsize = NLA_ALIGN(GENL_MAGIC_FAMILY_HDRSZ),
#endif
.maxattr = ARRAY_SIZE(drbd_tla_nl_policy)-1,
};
static struct genl_family ZZZ_genl_family;
/*
* Magic: define multicast groups
* Magic: define multicast group registration helper
......@@ -302,11 +293,23 @@ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \
#undef GENL_mc_group
#define GENL_mc_group(group)
static struct genl_family ZZZ_genl_family __ro_after_init = {
.name = __stringify(GENL_MAGIC_FAMILY),
.version = GENL_MAGIC_VERSION,
#ifdef GENL_MAGIC_FAMILY_HDRSZ
.hdrsize = NLA_ALIGN(GENL_MAGIC_FAMILY_HDRSZ),
#endif
.maxattr = ARRAY_SIZE(drbd_tla_nl_policy)-1,
.ops = ZZZ_genl_ops,
.n_ops = ARRAY_SIZE(ZZZ_genl_ops),
.mcgrps = ZZZ_genl_mcgrps,
.n_mcgrps = ARRAY_SIZE(ZZZ_genl_mcgrps),
.module = THIS_MODULE,
};
int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
{
return genl_register_family_with_ops_groups(&ZZZ_genl_family, \
ZZZ_genl_ops, \
ZZZ_genl_mcgrps);
return genl_register_family(&ZZZ_genl_family);
}
void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void)
......
......@@ -20,7 +20,7 @@ struct genl_info;
/**
* struct genl_family - generic netlink family
* @id: protocol family idenfitier
* @id: protocol family identifier (private)
* @hdrsize: length of user specific header in bytes
* @name: name of family
* @version: protocol version
......@@ -39,16 +39,16 @@ struct genl_info;
* Note that unbind() will not be called symmetrically if the
* generic netlink family is removed while there are still open
* sockets.
* @attrbuf: buffer to store parsed attributes
* @family_list: family list
* @mcgrps: multicast groups used by this family (private)
* @n_mcgrps: number of multicast groups (private)
* @attrbuf: buffer to store parsed attributes (private)
* @mcgrps: multicast groups used by this family
* @n_mcgrps: number of multicast groups
* @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)
* (private)
* @ops: the operations supported by this family
* @n_ops: number of operations supported by this family
*/
struct genl_family {
unsigned int id;
unsigned int id; /* private */
unsigned int hdrsize;
char name[GENL_NAMSIZ];
unsigned int version;
......@@ -64,15 +64,16 @@ struct genl_family {
int (*mcast_bind)(struct net *net, int group);
void (*mcast_unbind)(struct net *net, int group);
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 */
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 list_head family_list; /* private */
struct module *module;
};
struct nlattr **genl_family_attrbuf(const struct genl_family *family);
/**
* struct genl_info - receiving information
* @snd_seq: sending sequence number
......@@ -130,64 +131,13 @@ struct genl_ops {
u8 flags;
};
int __genl_register_family(struct genl_family *family);
static inline int genl_register_family(struct genl_family *family)
{
family->module = THIS_MODULE;
return __genl_register_family(family);
}
/**
* 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_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_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);
void genl_notify(struct genl_family *family, struct sk_buff *skb,
int genl_register_family(struct genl_family *family);
int genl_unregister_family(const struct genl_family *family);
void genl_notify(const struct genl_family *family, struct sk_buff *skb,
struct genl_info *info, u32 group, gfp_t flags);
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
struct genl_family *family, int flags, u8 cmd);
const struct genl_family *family, int flags, u8 cmd);
/**
* genlmsg_nlhdr - Obtain netlink header from user specified header
......@@ -196,8 +146,8 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
*
* Returns pointer to netlink header.
*/
static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr,
struct genl_family *family)
static inline struct nlmsghdr *
genlmsg_nlhdr(void *user_hdr, const struct genl_family *family)
{
return (struct nlmsghdr *)((char *)user_hdr -
family->hdrsize -
......@@ -233,7 +183,7 @@ static inline int genlmsg_parse(const struct nlmsghdr *nlh,
*/
static inline void genl_dump_check_consistent(struct netlink_callback *cb,
void *user_hdr,
struct genl_family *family)
const struct genl_family *family)
{
nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family));
}
......@@ -250,7 +200,7 @@ static inline void genl_dump_check_consistent(struct netlink_callback *cb,
*/
static inline void *genlmsg_put_reply(struct sk_buff *skb,
struct genl_info *info,
struct genl_family *family,
const struct genl_family *family,
int flags, u8 cmd)
{
return genlmsg_put(skb, info->snd_portid, info->snd_seq, family,
......@@ -287,7 +237,7 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
* @group: offset of multicast group in groups array
* @flags: allocation flags
*/
static inline int genlmsg_multicast_netns(struct genl_family *family,
static inline int genlmsg_multicast_netns(const struct genl_family *family,
struct net *net, struct sk_buff *skb,
u32 portid, unsigned int group, gfp_t flags)
{
......@@ -305,7 +255,7 @@ static inline int genlmsg_multicast_netns(struct genl_family *family,
* @group: offset of multicast group in groups array
* @flags: allocation flags
*/
static inline int genlmsg_multicast(struct genl_family *family,
static inline int genlmsg_multicast(const struct genl_family *family,
struct sk_buff *skb, u32 portid,
unsigned int group, gfp_t flags)
{
......@@ -323,7 +273,7 @@ static inline int genlmsg_multicast(struct genl_family *family,
*
* This function must hold the RTNL or rcu_read_lock().
*/
int genlmsg_multicast_allns(struct genl_family *family,
int genlmsg_multicast_allns(const struct genl_family *family,
struct sk_buff *skb, u32 portid,
unsigned int group, gfp_t flags);
......@@ -407,8 +357,9 @@ 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 genl_family *family, struct net *net,
u32 portid, u32 group, int code)
static inline int genl_set_err(const struct genl_family *family,
struct net *net, u32 portid,
u32 group, int code)
{
if (WARN_ON_ONCE(group >= family->n_mcgrps))
return -EINVAL;
......@@ -416,7 +367,7 @@ static inline int genl_set_err(struct genl_family *family, struct net *net,
return netlink_set_err(net->genl_sock, portid, group, code);
}
static inline int genl_has_listeners(struct genl_family *family,
static inline int genl_has_listeners(const struct genl_family *family,
struct net *net, unsigned int group)
{
if (WARN_ON_ONCE(group >= family->n_mcgrps))
......
......@@ -26,10 +26,11 @@ struct genlmsghdr {
/*
* List of reserved static generic netlink identifiers:
*/
#define GENL_ID_GENERATE 0
#define GENL_ID_CTRL NLMSG_MIN_TYPE
#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1)
#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2)
/* must be last reserved + 1 */
#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3)
/**************************************************************************
* Controller
......
......@@ -41,12 +41,7 @@ static DEFINE_PER_CPU(__u32, taskstats_seqnum);
static int family_registered;
struct kmem_cache *taskstats_cache;
static struct genl_family family = {
.id = GENL_ID_GENERATE,
.name = TASKSTATS_GENL_NAME,
.version = TASKSTATS_GENL_VERSION,
.maxattr = TASKSTATS_CMD_ATTR_MAX,
};
static struct genl_family family;
static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
[TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
......@@ -651,6 +646,15 @@ static const struct genl_ops taskstats_ops[] = {
},
};
static struct genl_family family __ro_after_init = {
.name = TASKSTATS_GENL_NAME,
.version = TASKSTATS_GENL_VERSION,
.maxattr = TASKSTATS_CMD_ATTR_MAX,
.module = THIS_MODULE,
.ops = taskstats_ops,
.n_ops = ARRAY_SIZE(taskstats_ops),
};
/* Needed early in initialization */
void __init taskstats_init_early(void)
{
......@@ -667,7 +671,7 @@ static int __init taskstats_init(void)
{
int rc;
rc = genl_register_family_with_ops(&family, taskstats_ops);
rc = genl_register_family(&family);
if (rc)
return rc;
...