Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Johannes Berg and committed by
David S. Miller
2dbba6f7 84659eb5

+263 -7
+13
include/linux/genetlink.h
··· 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 ··· 55 52 CTRL_ATTR_HDRSIZE, 56 53 CTRL_ATTR_MAXATTR, 57 54 CTRL_ATTR_OPS, 55 + CTRL_ATTR_MCAST_GROUPS, 58 56 __CTRL_ATTR_MAX, 59 57 }; 60 58 ··· 69 65 }; 70 66 71 67 #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) 68 + 69 + enum { 70 + CTRL_ATTR_MCAST_GRP_UNSPEC, 71 + CTRL_ATTR_MCAST_GRP_NAME, 72 + CTRL_ATTR_MCAST_GRP_ID, 73 + __CTRL_ATTR_MCAST_GRP_MAX, 74 + }; 75 + 76 + #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) 72 77 73 78 #endif /* __LINUX_GENERIC_NETLINK_H */
+22
include/net/genetlink.h
··· 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 ··· 30 14 * @attrbuf: buffer to store parsed attributes 31 15 * @ops_list: list of all assigned operations 32 16 * @family_list: family list 17 + * @mcast_groups: multicast groups list 33 18 */ 34 19 struct genl_family 35 20 { ··· 42 25 struct nlattr ** attrbuf; /* private */ 43 26 struct list_head ops_list; /* private */ 44 27 struct list_head family_list; /* private */ 28 + struct list_head mcast_groups; /* private */ 45 29 }; 46 30 47 31 /** ··· 91 73 extern int genl_unregister_family(struct genl_family *family); 92 74 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); 93 75 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); 76 + extern int genl_register_mc_group(struct genl_family *family, 77 + struct genl_multicast_group *grp); 78 + extern void genl_unregister_mc_group(struct genl_family *family, 79 + struct genl_multicast_group *grp); 94 80 95 81 extern struct sock *genl_sock; 96 82
+228 -7
net/netlink/genetlink.c
··· 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> ··· 14 13 #include <linux/string.h> 15 14 #include <linux/skbuff.h> 16 15 #include <linux/mutex.h> 16 + #include <linux/bitmap.h> 17 17 #include <net/sock.h> 18 18 #include <net/genetlink.h> 19 19 ··· 44 42 #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) 45 43 46 44 static struct list_head family_ht[GENL_FAM_TAB_SIZE]; 45 + /* 46 + * Bitmap of multicast groups that are currently in use. 47 + * 48 + * To avoid an allocation at boot of just one unsigned long, 49 + * declare it global instead. 50 + * Bit 0 is marked as already used since group 0 is invalid. 51 + */ 52 + static unsigned long mc_group_start = 0x1; 53 + static unsigned long *mc_groups = &mc_group_start; 54 + static unsigned long mc_groups_longs = 1; 47 55 48 56 static int genl_ctrl_event(int event, void *data); 49 57 ··· 126 114 } while (genl_family_find_byid(id_gen_idx)); 127 115 128 116 return id_gen_idx; 117 + } 118 + 119 + static struct genl_multicast_group notify_grp; 120 + 121 + /** 122 + * genl_register_mc_group - register a multicast group 123 + * 124 + * Registers the specified multicast group and notifies userspace 125 + * about the new group. 126 + * 127 + * Returns 0 on success or a negative error code. 128 + * 129 + * @family: The generic netlink family the group shall be registered for. 130 + * @grp: The group to register, must have a name. 131 + */ 132 + int genl_register_mc_group(struct genl_family *family, 133 + struct genl_multicast_group *grp) 134 + { 135 + int id; 136 + unsigned long *new_groups; 137 + int err; 138 + 139 + BUG_ON(grp->name[0] == '\0'); 140 + 141 + genl_lock(); 142 + 143 + /* special-case our own group */ 144 + if (grp == &notify_grp) 145 + id = GENL_ID_CTRL; 146 + else 147 + id = find_first_zero_bit(mc_groups, 148 + mc_groups_longs * BITS_PER_LONG); 149 + 150 + 151 + if (id >= mc_groups_longs * BITS_PER_LONG) { 152 + size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long); 153 + 154 + if (mc_groups == &mc_group_start) { 155 + new_groups = kzalloc(nlen, GFP_KERNEL); 156 + if (!new_groups) { 157 + err = -ENOMEM; 158 + goto out; 159 + } 160 + mc_groups = new_groups; 161 + *mc_groups = mc_group_start; 162 + } else { 163 + new_groups = krealloc(mc_groups, nlen, GFP_KERNEL); 164 + if (!new_groups) { 165 + err = -ENOMEM; 166 + goto out; 167 + } 168 + mc_groups = new_groups; 169 + mc_groups[mc_groups_longs] = 0; 170 + } 171 + mc_groups_longs++; 172 + } 173 + 174 + err = netlink_change_ngroups(genl_sock, 175 + sizeof(unsigned long) * NETLINK_GENERIC); 176 + if (err) 177 + goto out; 178 + 179 + grp->id = id; 180 + set_bit(id, mc_groups); 181 + list_add_tail(&grp->list, &family->mcast_groups); 182 + grp->family = family; 183 + 184 + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp); 185 + out: 186 + genl_unlock(); 187 + return 0; 188 + } 189 + EXPORT_SYMBOL(genl_register_mc_group); 190 + 191 + /** 192 + * genl_unregister_mc_group - unregister a multicast group 193 + * 194 + * Unregisters the specified multicast group and notifies userspace 195 + * about it. All current listeners on the group are removed. 196 + * 197 + * Note: It is not necessary to unregister all multicast groups before 198 + * unregistering the family, unregistering the family will cause 199 + * all assigned multicast groups to be unregistered automatically. 200 + * 201 + * @family: Generic netlink family the group belongs to. 202 + * @grp: The group to unregister, must have been registered successfully 203 + * previously. 204 + */ 205 + void genl_unregister_mc_group(struct genl_family *family, 206 + struct genl_multicast_group *grp) 207 + { 208 + BUG_ON(grp->family != family); 209 + genl_lock(); 210 + netlink_clear_multicast_users(genl_sock, grp->id); 211 + clear_bit(grp->id, mc_groups); 212 + list_del(&grp->list); 213 + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); 214 + grp->id = 0; 215 + grp->family = NULL; 216 + genl_unlock(); 217 + } 218 + 219 + static void genl_unregister_mc_groups(struct genl_family *family) 220 + { 221 + struct genl_multicast_group *grp, *tmp; 222 + 223 + list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) 224 + genl_unregister_mc_group(family, grp); 129 225 } 130 226 131 227 /** ··· 336 216 goto errout; 337 217 338 218 INIT_LIST_HEAD(&family->ops_list); 219 + INIT_LIST_HEAD(&family->mcast_groups); 339 220 340 221 genl_lock(); 341 222 ··· 395 274 int genl_unregister_family(struct genl_family *family) 396 275 { 397 276 struct genl_family *rc; 277 + 278 + genl_unregister_mc_groups(family); 398 279 399 280 genl_lock(); 400 281 ··· 533 410 nla_nest_end(skb, nla_ops); 534 411 } 535 412 413 + if (!list_empty(&family->mcast_groups)) { 414 + struct genl_multicast_group *grp; 415 + struct nlattr *nla_grps; 416 + int idx = 1; 417 + 418 + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); 419 + if (nla_grps == NULL) 420 + goto nla_put_failure; 421 + 422 + list_for_each_entry(grp, &family->mcast_groups, list) { 423 + struct nlattr *nest; 424 + 425 + nest = nla_nest_start(skb, idx++); 426 + if (nest == NULL) 427 + goto nla_put_failure; 428 + 429 + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id); 430 + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME, 431 + grp->name); 432 + 433 + nla_nest_end(skb, nest); 434 + } 435 + nla_nest_end(skb, nla_grps); 436 + } 437 + 438 + return genlmsg_end(skb, hdr); 439 + 440 + nla_put_failure: 441 + return genlmsg_cancel(skb, hdr); 442 + } 443 + 444 + static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid, 445 + u32 seq, u32 flags, struct sk_buff *skb, 446 + u8 cmd) 447 + { 448 + void *hdr; 449 + struct nlattr *nla_grps; 450 + struct nlattr *nest; 451 + 452 + hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd); 453 + if (hdr == NULL) 454 + return -1; 455 + 456 + NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name); 457 + NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id); 458 + 459 + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); 460 + if (nla_grps == NULL) 461 + goto nla_put_failure; 462 + 463 + nest = nla_nest_start(skb, 1); 464 + if (nest == NULL) 465 + goto nla_put_failure; 466 + 467 + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id); 468 + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME, 469 + grp->name); 470 + 471 + nla_nest_end(skb, nest); 472 + nla_nest_end(skb, nla_grps); 473 + 536 474 return genlmsg_end(skb, hdr); 537 475 538 476 nla_put_failure: ··· 637 453 return skb->len; 638 454 } 639 455 640 - static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, 641 - int seq, u8 cmd) 456 + static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, 457 + u32 pid, int seq, u8 cmd) 642 458 { 643 459 struct sk_buff *skb; 644 460 int err; ··· 648 464 return ERR_PTR(-ENOBUFS); 649 465 650 466 err = ctrl_fill_info(family, pid, seq, 0, skb, cmd); 467 + if (err < 0) { 468 + nlmsg_free(skb); 469 + return ERR_PTR(err); 470 + } 471 + 472 + return skb; 473 + } 474 + 475 + static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, 476 + u32 pid, int seq, u8 cmd) 477 + { 478 + struct sk_buff *skb; 479 + int err; 480 + 481 + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 482 + if (skb == NULL) 483 + return ERR_PTR(-ENOBUFS); 484 + 485 + err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd); 651 486 if (err < 0) { 652 487 nlmsg_free(skb); 653 488 return ERR_PTR(err); ··· 704 501 goto errout; 705 502 } 706 503 707 - msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq, 708 - CTRL_CMD_NEWFAMILY); 504 + msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq, 505 + CTRL_CMD_NEWFAMILY); 709 506 if (IS_ERR(msg)) { 710 507 err = PTR_ERR(msg); 711 508 goto errout; ··· 726 523 switch (event) { 727 524 case CTRL_CMD_NEWFAMILY: 728 525 case CTRL_CMD_DELFAMILY: 729 - msg = ctrl_build_msg(data, 0, 0, event); 526 + msg = ctrl_build_family_msg(data, 0, 0, event); 527 + if (IS_ERR(msg)) 528 + return PTR_ERR(msg); 529 + 530 + genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); 531 + break; 532 + case CTRL_CMD_NEWMCAST_GRP: 533 + case CTRL_CMD_DELMCAST_GRP: 534 + msg = ctrl_build_mcgrp_msg(data, 0, 0, event); 730 535 if (IS_ERR(msg)) 731 536 return PTR_ERR(msg); 732 537 ··· 750 539 .doit = ctrl_getfamily, 751 540 .dumpit = ctrl_dumpfamily, 752 541 .policy = ctrl_policy, 542 + }; 543 + 544 + static struct genl_multicast_group notify_grp = { 545 + .name = "notify", 753 546 }; 754 547 755 548 static int __init genl_init(void) ··· 772 557 goto errout_register; 773 558 774 559 netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); 775 - genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID, 776 - genl_rcv, NULL, THIS_MODULE); 560 + 561 + /* we'll bump the group number right afterwards */ 562 + genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv, 563 + NULL, THIS_MODULE); 777 564 if (genl_sock == NULL) 778 565 panic("GENL: Cannot initialize generic netlink\n"); 566 + 567 + err = genl_register_mc_group(&genl_ctrl, &notify_grp); 568 + if (err < 0) 569 + goto errout_register; 779 570 780 571 return 0; 781 572