Commit 2dbba6f773d1e1e4c78f03b0dbf19790d9017693

Authored by Johannes Berg
Committed by David S. Miller
1 parent 84659eb529

[GENETLINK]: Dynamic multicast groups.

Introduce API to dynamically register and unregister multicast groups.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Patrick McHardy <kaber@trash.net>
Acked-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 263 additions and 7 deletions Side-by-side Diff

include/linux/genetlink.h
... ... @@ -39,6 +39,9 @@
39 39 CTRL_CMD_NEWOPS,
40 40 CTRL_CMD_DELOPS,
41 41 CTRL_CMD_GETOPS,
  42 + CTRL_CMD_NEWMCAST_GRP,
  43 + CTRL_CMD_DELMCAST_GRP,
  44 + CTRL_CMD_GETMCAST_GRP, /* unused */
42 45 __CTRL_CMD_MAX,
43 46 };
44 47  
... ... @@ -52,6 +55,7 @@
52 55 CTRL_ATTR_HDRSIZE,
53 56 CTRL_ATTR_MAXATTR,
54 57 CTRL_ATTR_OPS,
  58 + CTRL_ATTR_MCAST_GROUPS,
55 59 __CTRL_ATTR_MAX,
56 60 };
57 61  
... ... @@ -65,6 +69,15 @@
65 69 };
66 70  
67 71 #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
  72 +
  73 +enum {
  74 + CTRL_ATTR_MCAST_GRP_UNSPEC,
  75 + CTRL_ATTR_MCAST_GRP_NAME,
  76 + CTRL_ATTR_MCAST_GRP_ID,
  77 + __CTRL_ATTR_MCAST_GRP_MAX,
  78 +};
  79 +
  80 +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
68 81  
69 82 #endif /* __LINUX_GENERIC_NETLINK_H */
include/net/genetlink.h
... ... @@ -5,6 +5,22 @@
5 5 #include <net/netlink.h>
6 6  
7 7 /**
  8 + * struct genl_multicast_group - generic netlink multicast group
  9 + * @name: name of the multicast group, names are per-family
  10 + * @id: multicast group ID, assigned by the core, to use with
  11 + * genlmsg_multicast().
  12 + * @list: list entry for linking
  13 + * @family: pointer to family, need not be set before registering
  14 + */
  15 +struct genl_multicast_group
  16 +{
  17 + struct genl_family *family; /* private */
  18 + struct list_head list; /* private */
  19 + char name[GENL_NAMSIZ];
  20 + u32 id;
  21 +};
  22 +
  23 +/**
8 24 * struct genl_family - generic netlink family
9 25 * @id: protocol family idenfitier
10 26 * @hdrsize: length of user specific header in bytes
... ... @@ -14,6 +30,7 @@
14 30 * @attrbuf: buffer to store parsed attributes
15 31 * @ops_list: list of all assigned operations
16 32 * @family_list: family list
  33 + * @mcast_groups: multicast groups list
17 34 */
18 35 struct genl_family
19 36 {
... ... @@ -25,6 +42,7 @@
25 42 struct nlattr ** attrbuf; /* private */
26 43 struct list_head ops_list; /* private */
27 44 struct list_head family_list; /* private */
  45 + struct list_head mcast_groups; /* private */
28 46 };
29 47  
30 48 /**
... ... @@ -73,6 +91,10 @@
73 91 extern int genl_unregister_family(struct genl_family *family);
74 92 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
75 93 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
  94 +extern int genl_register_mc_group(struct genl_family *family,
  95 + struct genl_multicast_group *grp);
  96 +extern void genl_unregister_mc_group(struct genl_family *family,
  97 + struct genl_multicast_group *grp);
76 98  
77 99 extern struct sock *genl_sock;
78 100  
net/netlink/genetlink.c
... ... @@ -3,6 +3,7 @@
3 3 *
4 4 * Authors: Jamal Hadi Salim
5 5 * Thomas Graf <tgraf@suug.ch>
  6 + * Johannes Berg <johannes@sipsolutions.net>
6 7 */
7 8  
8 9 #include <linux/module.h>
... ... @@ -13,6 +14,7 @@
13 14 #include <linux/string.h>
14 15 #include <linux/skbuff.h>
15 16 #include <linux/mutex.h>
  17 +#include <linux/bitmap.h>
16 18 #include <net/sock.h>
17 19 #include <net/genetlink.h>
18 20  
... ... @@ -42,6 +44,16 @@
42 44 #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1)
43 45  
44 46 static struct list_head family_ht[GENL_FAM_TAB_SIZE];
  47 +/*
  48 + * Bitmap of multicast groups that are currently in use.
  49 + *
  50 + * To avoid an allocation at boot of just one unsigned long,
  51 + * declare it global instead.
  52 + * Bit 0 is marked as already used since group 0 is invalid.
  53 + */
  54 +static unsigned long mc_group_start = 0x1;
  55 +static unsigned long *mc_groups = &mc_group_start;
  56 +static unsigned long mc_groups_longs = 1;
45 57  
46 58 static int genl_ctrl_event(int event, void *data);
47 59  
48 60  
... ... @@ -116,7 +128,115 @@
116 128 return id_gen_idx;
117 129 }
118 130  
  131 +static struct genl_multicast_group notify_grp;
  132 +
119 133 /**
  134 + * genl_register_mc_group - register a multicast group
  135 + *
  136 + * Registers the specified multicast group and notifies userspace
  137 + * about the new group.
  138 + *
  139 + * Returns 0 on success or a negative error code.
  140 + *
  141 + * @family: The generic netlink family the group shall be registered for.
  142 + * @grp: The group to register, must have a name.
  143 + */
  144 +int genl_register_mc_group(struct genl_family *family,
  145 + struct genl_multicast_group *grp)
  146 +{
  147 + int id;
  148 + unsigned long *new_groups;
  149 + int err;
  150 +
  151 + BUG_ON(grp->name[0] == '\0');
  152 +
  153 + genl_lock();
  154 +
  155 + /* special-case our own group */
  156 + if (grp == &notify_grp)
  157 + id = GENL_ID_CTRL;
  158 + else
  159 + id = find_first_zero_bit(mc_groups,
  160 + mc_groups_longs * BITS_PER_LONG);
  161 +
  162 +
  163 + if (id >= mc_groups_longs * BITS_PER_LONG) {
  164 + size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
  165 +
  166 + if (mc_groups == &mc_group_start) {
  167 + new_groups = kzalloc(nlen, GFP_KERNEL);
  168 + if (!new_groups) {
  169 + err = -ENOMEM;
  170 + goto out;
  171 + }
  172 + mc_groups = new_groups;
  173 + *mc_groups = mc_group_start;
  174 + } else {
  175 + new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
  176 + if (!new_groups) {
  177 + err = -ENOMEM;
  178 + goto out;
  179 + }
  180 + mc_groups = new_groups;
  181 + mc_groups[mc_groups_longs] = 0;
  182 + }
  183 + mc_groups_longs++;
  184 + }
  185 +
  186 + err = netlink_change_ngroups(genl_sock,
  187 + sizeof(unsigned long) * NETLINK_GENERIC);
  188 + if (err)
  189 + goto out;
  190 +
  191 + grp->id = id;
  192 + set_bit(id, mc_groups);
  193 + list_add_tail(&grp->list, &family->mcast_groups);
  194 + grp->family = family;
  195 +
  196 + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
  197 + out:
  198 + genl_unlock();
  199 + return 0;
  200 +}
  201 +EXPORT_SYMBOL(genl_register_mc_group);
  202 +
  203 +/**
  204 + * genl_unregister_mc_group - unregister a multicast group
  205 + *
  206 + * Unregisters the specified multicast group and notifies userspace
  207 + * about it. All current listeners on the group are removed.
  208 + *
  209 + * Note: It is not necessary to unregister all multicast groups before
  210 + * unregistering the family, unregistering the family will cause
  211 + * all assigned multicast groups to be unregistered automatically.
  212 + *
  213 + * @family: Generic netlink family the group belongs to.
  214 + * @grp: The group to unregister, must have been registered successfully
  215 + * previously.
  216 + */
  217 +void genl_unregister_mc_group(struct genl_family *family,
  218 + struct genl_multicast_group *grp)
  219 +{
  220 + BUG_ON(grp->family != family);
  221 + genl_lock();
  222 + netlink_clear_multicast_users(genl_sock, grp->id);
  223 + clear_bit(grp->id, mc_groups);
  224 + list_del(&grp->list);
  225 + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
  226 + grp->id = 0;
  227 + grp->family = NULL;
  228 + genl_unlock();
  229 +}
  230 +
  231 +static void genl_unregister_mc_groups(struct genl_family *family)
  232 +{
  233 + struct genl_multicast_group *grp, *tmp;
  234 +
  235 + list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
  236 + genl_unregister_mc_group(family, grp);
  237 +}
  238 +
  239 +/**
120 240 * genl_register_ops - register generic netlink operations
121 241 * @family: generic netlink family
122 242 * @ops: operations to be registered
... ... @@ -216,6 +336,7 @@
216 336 goto errout;
217 337  
218 338 INIT_LIST_HEAD(&family->ops_list);
  339 + INIT_LIST_HEAD(&family->mcast_groups);
219 340  
220 341 genl_lock();
221 342  
... ... @@ -275,6 +396,8 @@
275 396 {
276 397 struct genl_family *rc;
277 398  
  399 + genl_unregister_mc_groups(family);
  400 +
278 401 genl_lock();
279 402  
280 403 list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
281 404  
... ... @@ -410,12 +533,73 @@
410 533 nla_nest_end(skb, nla_ops);
411 534 }
412 535  
  536 + if (!list_empty(&family->mcast_groups)) {
  537 + struct genl_multicast_group *grp;
  538 + struct nlattr *nla_grps;
  539 + int idx = 1;
  540 +
  541 + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
  542 + if (nla_grps == NULL)
  543 + goto nla_put_failure;
  544 +
  545 + list_for_each_entry(grp, &family->mcast_groups, list) {
  546 + struct nlattr *nest;
  547 +
  548 + nest = nla_nest_start(skb, idx++);
  549 + if (nest == NULL)
  550 + goto nla_put_failure;
  551 +
  552 + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
  553 + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
  554 + grp->name);
  555 +
  556 + nla_nest_end(skb, nest);
  557 + }
  558 + nla_nest_end(skb, nla_grps);
  559 + }
  560 +
413 561 return genlmsg_end(skb, hdr);
414 562  
415 563 nla_put_failure:
416 564 return genlmsg_cancel(skb, hdr);
417 565 }
418 566  
  567 +static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
  568 + u32 seq, u32 flags, struct sk_buff *skb,
  569 + u8 cmd)
  570 +{
  571 + void *hdr;
  572 + struct nlattr *nla_grps;
  573 + struct nlattr *nest;
  574 +
  575 + hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
  576 + if (hdr == NULL)
  577 + return -1;
  578 +
  579 + NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
  580 + NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
  581 +
  582 + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
  583 + if (nla_grps == NULL)
  584 + goto nla_put_failure;
  585 +
  586 + nest = nla_nest_start(skb, 1);
  587 + if (nest == NULL)
  588 + goto nla_put_failure;
  589 +
  590 + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
  591 + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
  592 + grp->name);
  593 +
  594 + nla_nest_end(skb, nest);
  595 + nla_nest_end(skb, nla_grps);
  596 +
  597 + return genlmsg_end(skb, hdr);
  598 +
  599 +nla_put_failure:
  600 + return genlmsg_cancel(skb, hdr);
  601 +}
  602 +
419 603 static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
420 604 {
421 605  
... ... @@ -453,8 +637,8 @@
453 637 return skb->len;
454 638 }
455 639  
456   -static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
457   - int seq, u8 cmd)
  640 +static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
  641 + u32 pid, int seq, u8 cmd)
458 642 {
459 643 struct sk_buff *skb;
460 644 int err;
... ... @@ -472,6 +656,25 @@
472 656 return skb;
473 657 }
474 658  
  659 +static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
  660 + u32 pid, int seq, u8 cmd)
  661 +{
  662 + struct sk_buff *skb;
  663 + int err;
  664 +
  665 + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  666 + if (skb == NULL)
  667 + return ERR_PTR(-ENOBUFS);
  668 +
  669 + err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
  670 + if (err < 0) {
  671 + nlmsg_free(skb);
  672 + return ERR_PTR(err);
  673 + }
  674 +
  675 + return skb;
  676 +}
  677 +
475 678 static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
476 679 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
477 680 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
... ... @@ -501,8 +704,8 @@
501 704 goto errout;
502 705 }
503 706  
504   - msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq,
505   - CTRL_CMD_NEWFAMILY);
  707 + msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
  708 + CTRL_CMD_NEWFAMILY);
506 709 if (IS_ERR(msg)) {
507 710 err = PTR_ERR(msg);
508 711 goto errout;
509 712  
... ... @@ -523,12 +726,20 @@
523 726 switch (event) {
524 727 case CTRL_CMD_NEWFAMILY:
525 728 case CTRL_CMD_DELFAMILY:
526   - msg = ctrl_build_msg(data, 0, 0, event);
  729 + msg = ctrl_build_family_msg(data, 0, 0, event);
527 730 if (IS_ERR(msg))
528 731 return PTR_ERR(msg);
529 732  
530 733 genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
531 734 break;
  735 + case CTRL_CMD_NEWMCAST_GRP:
  736 + case CTRL_CMD_DELMCAST_GRP:
  737 + msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
  738 + if (IS_ERR(msg))
  739 + return PTR_ERR(msg);
  740 +
  741 + genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
  742 + break;
532 743 }
533 744  
534 745 return 0;
... ... @@ -541,6 +752,10 @@
541 752 .policy = ctrl_policy,
542 753 };
543 754  
  755 +static struct genl_multicast_group notify_grp = {
  756 + .name = "notify",
  757 +};
  758 +
544 759 static int __init genl_init(void)
545 760 {
546 761 int i, err;
547 762  
... ... @@ -557,10 +772,16 @@
557 772 goto errout_register;
558 773  
559 774 netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
560   - genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
561   - genl_rcv, NULL, THIS_MODULE);
  775 +
  776 + /* we'll bump the group number right afterwards */
  777 + genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv,
  778 + NULL, THIS_MODULE);
562 779 if (genl_sock == NULL)
563 780 panic("GENL: Cannot initialize generic netlink\n");
  781 +
  782 + err = genl_register_mc_group(&genl_ctrl, &notify_grp);
  783 + if (err < 0)
  784 + goto errout_register;
564 785  
565 786 return 0;
566 787