aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/mcast.c
diff options
context:
space:
mode:
authorDaniel Lezcano <dlezcano@fr.ibm.com>2008-03-07 14:16:55 -0500
committerDavid S. Miller <davem@davemloft.net>2008-03-07 14:16:55 -0500
commitb8ad0cbc58f703972e9e37c4e2a8081dd7e6a551 (patch)
treef4f576d4be94ea792bf075260586ab25c6507716 /net/ipv6/mcast.c
parente504799276e53045a9b597f24c1b456552482f63 (diff)
[NETNS][IPV6] mcast - handle several network namespace
This patch make use of the network namespace information at the right places to handle the multicast for several network namespaces. It makes the socket control to be per namespace too. Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com> Signed-off-by: Benjamin Thery <benjamin.thery@bull.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r--net/ipv6/mcast.c116
1 files changed, 78 insertions, 38 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 197ca390a15d..f2879056fab0 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -126,8 +126,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
126/* Big mc list lock for all the sockets */ 126/* Big mc list lock for all the sockets */
127static DEFINE_RWLOCK(ipv6_sk_mc_lock); 127static DEFINE_RWLOCK(ipv6_sk_mc_lock);
128 128
129static struct socket *igmp6_socket;
130
131int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); 129int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr);
132 130
133static void igmp6_join_group(struct ifmcaddr6 *ma); 131static void igmp6_join_group(struct ifmcaddr6 *ma);
@@ -183,6 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
183 struct net_device *dev = NULL; 181 struct net_device *dev = NULL;
184 struct ipv6_mc_socklist *mc_lst; 182 struct ipv6_mc_socklist *mc_lst;
185 struct ipv6_pinfo *np = inet6_sk(sk); 183 struct ipv6_pinfo *np = inet6_sk(sk);
184 struct net *net = sk->sk_net;
186 int err; 185 int err;
187 186
188 if (!ipv6_addr_is_multicast(addr)) 187 if (!ipv6_addr_is_multicast(addr))
@@ -208,14 +207,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
208 207
209 if (ifindex == 0) { 208 if (ifindex == 0) {
210 struct rt6_info *rt; 209 struct rt6_info *rt;
211 rt = rt6_lookup(&init_net, addr, NULL, 0, 0); 210 rt = rt6_lookup(net, addr, NULL, 0, 0);
212 if (rt) { 211 if (rt) {
213 dev = rt->rt6i_dev; 212 dev = rt->rt6i_dev;
214 dev_hold(dev); 213 dev_hold(dev);
215 dst_release(&rt->u.dst); 214 dst_release(&rt->u.dst);
216 } 215 }
217 } else 216 } else
218 dev = dev_get_by_index(&init_net, ifindex); 217 dev = dev_get_by_index(net, ifindex);
219 218
220 if (dev == NULL) { 219 if (dev == NULL) {
221 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 220 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
@@ -256,6 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
256{ 255{
257 struct ipv6_pinfo *np = inet6_sk(sk); 256 struct ipv6_pinfo *np = inet6_sk(sk);
258 struct ipv6_mc_socklist *mc_lst, **lnk; 257 struct ipv6_mc_socklist *mc_lst, **lnk;
258 struct net *net = sk->sk_net;
259 259
260 write_lock_bh(&ipv6_sk_mc_lock); 260 write_lock_bh(&ipv6_sk_mc_lock);
261 for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { 261 for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
@@ -266,7 +266,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
266 *lnk = mc_lst->next; 266 *lnk = mc_lst->next;
267 write_unlock_bh(&ipv6_sk_mc_lock); 267 write_unlock_bh(&ipv6_sk_mc_lock);
268 268
269 if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { 269 dev = dev_get_by_index(net, mc_lst->ifindex);
270 if (dev != NULL) {
270 struct inet6_dev *idev = in6_dev_get(dev); 271 struct inet6_dev *idev = in6_dev_get(dev);
271 272
272 (void) ip6_mc_leave_src(sk, mc_lst, idev); 273 (void) ip6_mc_leave_src(sk, mc_lst, idev);
@@ -286,7 +287,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
286 return -EADDRNOTAVAIL; 287 return -EADDRNOTAVAIL;
287} 288}
288 289
289static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) 290static struct inet6_dev *ip6_mc_find_dev(struct net *net,
291 struct in6_addr *group,
292 int ifindex)
290{ 293{
291 struct net_device *dev = NULL; 294 struct net_device *dev = NULL;
292 struct inet6_dev *idev = NULL; 295 struct inet6_dev *idev = NULL;
@@ -294,14 +297,14 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
294 if (ifindex == 0) { 297 if (ifindex == 0) {
295 struct rt6_info *rt; 298 struct rt6_info *rt;
296 299
297 rt = rt6_lookup(&init_net, group, NULL, 0, 0); 300 rt = rt6_lookup(net, group, NULL, 0, 0);
298 if (rt) { 301 if (rt) {
299 dev = rt->rt6i_dev; 302 dev = rt->rt6i_dev;
300 dev_hold(dev); 303 dev_hold(dev);
301 dst_release(&rt->u.dst); 304 dst_release(&rt->u.dst);
302 } 305 }
303 } else 306 } else
304 dev = dev_get_by_index(&init_net, ifindex); 307 dev = dev_get_by_index(net, ifindex);
305 308
306 if (!dev) 309 if (!dev)
307 return NULL; 310 return NULL;
@@ -324,6 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk)
324{ 327{
325 struct ipv6_pinfo *np = inet6_sk(sk); 328 struct ipv6_pinfo *np = inet6_sk(sk);
326 struct ipv6_mc_socklist *mc_lst; 329 struct ipv6_mc_socklist *mc_lst;
330 struct net *net = sk->sk_net;
327 331
328 write_lock_bh(&ipv6_sk_mc_lock); 332 write_lock_bh(&ipv6_sk_mc_lock);
329 while ((mc_lst = np->ipv6_mc_list) != NULL) { 333 while ((mc_lst = np->ipv6_mc_list) != NULL) {
@@ -332,7 +336,7 @@ void ipv6_sock_mc_close(struct sock *sk)
332 np->ipv6_mc_list = mc_lst->next; 336 np->ipv6_mc_list = mc_lst->next;
333 write_unlock_bh(&ipv6_sk_mc_lock); 337 write_unlock_bh(&ipv6_sk_mc_lock);
334 338
335 dev = dev_get_by_index(&init_net, mc_lst->ifindex); 339 dev = dev_get_by_index(net, mc_lst->ifindex);
336 if (dev) { 340 if (dev) {
337 struct inet6_dev *idev = in6_dev_get(dev); 341 struct inet6_dev *idev = in6_dev_get(dev);
338 342
@@ -361,6 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
361 struct inet6_dev *idev; 365 struct inet6_dev *idev;
362 struct ipv6_pinfo *inet6 = inet6_sk(sk); 366 struct ipv6_pinfo *inet6 = inet6_sk(sk);
363 struct ip6_sf_socklist *psl; 367 struct ip6_sf_socklist *psl;
368 struct net *net = sk->sk_net;
364 int i, j, rv; 369 int i, j, rv;
365 int leavegroup = 0; 370 int leavegroup = 0;
366 int pmclocked = 0; 371 int pmclocked = 0;
@@ -376,7 +381,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
376 if (!ipv6_addr_is_multicast(group)) 381 if (!ipv6_addr_is_multicast(group))
377 return -EINVAL; 382 return -EINVAL;
378 383
379 idev = ip6_mc_find_dev(group, pgsr->gsr_interface); 384 idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
380 if (!idev) 385 if (!idev)
381 return -ENODEV; 386 return -ENODEV;
382 dev = idev->dev; 387 dev = idev->dev;
@@ -500,6 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
500 struct inet6_dev *idev; 505 struct inet6_dev *idev;
501 struct ipv6_pinfo *inet6 = inet6_sk(sk); 506 struct ipv6_pinfo *inet6 = inet6_sk(sk);
502 struct ip6_sf_socklist *newpsl, *psl; 507 struct ip6_sf_socklist *newpsl, *psl;
508 struct net *net = sk->sk_net;
503 int leavegroup = 0; 509 int leavegroup = 0;
504 int i, err; 510 int i, err;
505 511
@@ -511,7 +517,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
511 gsf->gf_fmode != MCAST_EXCLUDE) 517 gsf->gf_fmode != MCAST_EXCLUDE)
512 return -EINVAL; 518 return -EINVAL;
513 519
514 idev = ip6_mc_find_dev(group, gsf->gf_interface); 520 idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
515 521
516 if (!idev) 522 if (!idev)
517 return -ENODEV; 523 return -ENODEV;
@@ -592,13 +598,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
592 struct net_device *dev; 598 struct net_device *dev;
593 struct ipv6_pinfo *inet6 = inet6_sk(sk); 599 struct ipv6_pinfo *inet6 = inet6_sk(sk);
594 struct ip6_sf_socklist *psl; 600 struct ip6_sf_socklist *psl;
601 struct net *net = sk->sk_net;
595 602
596 group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; 603 group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
597 604
598 if (!ipv6_addr_is_multicast(group)) 605 if (!ipv6_addr_is_multicast(group))
599 return -EINVAL; 606 return -EINVAL;
600 607
601 idev = ip6_mc_find_dev(group, gsf->gf_interface); 608 idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
602 609
603 if (!idev) 610 if (!idev)
604 return -ENODEV; 611 return -ENODEV;
@@ -1393,7 +1400,8 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
1393 1400
1394static struct sk_buff *mld_newpack(struct net_device *dev, int size) 1401static struct sk_buff *mld_newpack(struct net_device *dev, int size)
1395{ 1402{
1396 struct sock *sk = igmp6_socket->sk; 1403 struct net *net = dev->nd_net;
1404 struct sock *sk = net->ipv6.igmp_sk;
1397 struct sk_buff *skb; 1405 struct sk_buff *skb;
1398 struct mld2_report *pmr; 1406 struct mld2_report *pmr;
1399 struct in6_addr addr_buf; 1407 struct in6_addr addr_buf;
@@ -1440,6 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb)
1440 (struct mld2_report *)skb_transport_header(skb); 1448 (struct mld2_report *)skb_transport_header(skb);
1441 int payload_len, mldlen; 1449 int payload_len, mldlen;
1442 struct inet6_dev *idev = in6_dev_get(skb->dev); 1450 struct inet6_dev *idev = in6_dev_get(skb->dev);
1451 struct net *net = skb->dev->nd_net;
1443 int err; 1452 int err;
1444 struct flowi fl; 1453 struct flowi fl;
1445 1454
@@ -1459,7 +1468,7 @@ static void mld_sendpack(struct sk_buff *skb)
1459 goto err_out; 1468 goto err_out;
1460 } 1469 }
1461 1470
1462 icmpv6_flow_init(igmp6_socket->sk, &fl, ICMPV6_MLD2_REPORT, 1471 icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT,
1463 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 1472 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
1464 skb->dev->ifindex); 1473 skb->dev->ifindex);
1465 1474
@@ -1753,7 +1762,8 @@ static void mld_send_cr(struct inet6_dev *idev)
1753 1762
1754static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) 1763static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1755{ 1764{
1756 struct sock *sk = igmp6_socket->sk; 1765 struct net *net = dev->nd_net;
1766 struct sock *sk = net->ipv6.igmp_sk;
1757 struct inet6_dev *idev; 1767 struct inet6_dev *idev;
1758 struct sk_buff *skb; 1768 struct sk_buff *skb;
1759 struct icmp6hdr *hdr; 1769 struct icmp6hdr *hdr;
@@ -1824,7 +1834,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1824 goto err_out; 1834 goto err_out;
1825 } 1835 }
1826 1836
1827 icmpv6_flow_init(igmp6_socket->sk, &fl, type, 1837 icmpv6_flow_init(sk, &fl, type,
1828 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 1838 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
1829 skb->dev->ifindex); 1839 skb->dev->ifindex);
1830 1840
@@ -2334,6 +2344,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
2334 2344
2335#ifdef CONFIG_PROC_FS 2345#ifdef CONFIG_PROC_FS
2336struct igmp6_mc_iter_state { 2346struct igmp6_mc_iter_state {
2347 struct seq_net_private p;
2337 struct net_device *dev; 2348 struct net_device *dev;
2338 struct inet6_dev *idev; 2349 struct inet6_dev *idev;
2339}; 2350};
@@ -2344,9 +2355,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
2344{ 2355{
2345 struct ifmcaddr6 *im = NULL; 2356 struct ifmcaddr6 *im = NULL;
2346 struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); 2357 struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
2358 struct net *net = state->p.net;
2347 2359
2348 state->idev = NULL; 2360 state->idev = NULL;
2349 for_each_netdev(&init_net, state->dev) { 2361 for_each_netdev(net, state->dev) {
2350 struct inet6_dev *idev; 2362 struct inet6_dev *idev;
2351 idev = in6_dev_get(state->dev); 2363 idev = in6_dev_get(state->dev);
2352 if (!idev) 2364 if (!idev)
@@ -2448,8 +2460,8 @@ static const struct seq_operations igmp6_mc_seq_ops = {
2448 2460
2449static int igmp6_mc_seq_open(struct inode *inode, struct file *file) 2461static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
2450{ 2462{
2451 return seq_open_private(file, &igmp6_mc_seq_ops, 2463 return seq_open_net(inode, file, &igmp6_mc_seq_ops,
2452 sizeof(struct igmp6_mc_iter_state)); 2464 sizeof(struct igmp6_mc_iter_state));
2453} 2465}
2454 2466
2455static const struct file_operations igmp6_mc_seq_fops = { 2467static const struct file_operations igmp6_mc_seq_fops = {
@@ -2457,10 +2469,11 @@ static const struct file_operations igmp6_mc_seq_fops = {
2457 .open = igmp6_mc_seq_open, 2469 .open = igmp6_mc_seq_open,
2458 .read = seq_read, 2470 .read = seq_read,
2459 .llseek = seq_lseek, 2471 .llseek = seq_lseek,
2460 .release = seq_release_private, 2472 .release = seq_release_net,
2461}; 2473};
2462 2474
2463struct igmp6_mcf_iter_state { 2475struct igmp6_mcf_iter_state {
2476 struct seq_net_private p;
2464 struct net_device *dev; 2477 struct net_device *dev;
2465 struct inet6_dev *idev; 2478 struct inet6_dev *idev;
2466 struct ifmcaddr6 *im; 2479 struct ifmcaddr6 *im;
@@ -2473,10 +2486,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
2473 struct ip6_sf_list *psf = NULL; 2486 struct ip6_sf_list *psf = NULL;
2474 struct ifmcaddr6 *im = NULL; 2487 struct ifmcaddr6 *im = NULL;
2475 struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); 2488 struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
2489 struct net *net = state->p.net;
2476 2490
2477 state->idev = NULL; 2491 state->idev = NULL;
2478 state->im = NULL; 2492 state->im = NULL;
2479 for_each_netdev(&init_net, state->dev) { 2493 for_each_netdev(net, state->dev) {
2480 struct inet6_dev *idev; 2494 struct inet6_dev *idev;
2481 idev = in6_dev_get(state->dev); 2495 idev = in6_dev_get(state->dev);
2482 if (unlikely(idev == NULL)) 2496 if (unlikely(idev == NULL))
@@ -2608,8 +2622,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = {
2608 2622
2609static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) 2623static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
2610{ 2624{
2611 return seq_open_private(file, &igmp6_mcf_seq_ops, 2625 return seq_open_net(inode, file, &igmp6_mcf_seq_ops,
2612 sizeof(struct igmp6_mcf_iter_state)); 2626 sizeof(struct igmp6_mcf_iter_state));
2613} 2627}
2614 2628
2615static const struct file_operations igmp6_mcf_seq_fops = { 2629static const struct file_operations igmp6_mcf_seq_fops = {
@@ -2617,26 +2631,27 @@ static const struct file_operations igmp6_mcf_seq_fops = {
2617 .open = igmp6_mcf_seq_open, 2631 .open = igmp6_mcf_seq_open,
2618 .read = seq_read, 2632 .read = seq_read,
2619 .llseek = seq_lseek, 2633 .llseek = seq_lseek,
2620 .release = seq_release_private, 2634 .release = seq_release_net,
2621}; 2635};
2622#endif 2636#endif
2623 2637
2624int __init igmp6_init(void) 2638static int igmp6_net_init(struct net *net)
2625{ 2639{
2626 struct ipv6_pinfo *np; 2640 struct ipv6_pinfo *np;
2641 struct socket *sock;
2627 struct sock *sk; 2642 struct sock *sk;
2628 int err; 2643 int err;
2629 2644
2630 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); 2645 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
2631 if (err < 0) { 2646 if (err < 0) {
2632 printk(KERN_ERR 2647 printk(KERN_ERR
2633 "Failed to initialize the IGMP6 control socket (err %d).\n", 2648 "Failed to initialize the IGMP6 control socket (err %d).\n",
2634 err); 2649 err);
2635 igmp6_socket = NULL; /* For safety. */ 2650 goto out;
2636 return err;
2637 } 2651 }
2638 2652
2639 sk = igmp6_socket->sk; 2653 net->ipv6.igmp_sk = sk = sock->sk;
2654 sk_change_net(sk, net);
2640 sk->sk_allocation = GFP_ATOMIC; 2655 sk->sk_allocation = GFP_ATOMIC;
2641 sk->sk_prot->unhash(sk); 2656 sk->sk_prot->unhash(sk);
2642 2657
@@ -2644,20 +2659,45 @@ int __init igmp6_init(void)
2644 np->hop_limit = 1; 2659 np->hop_limit = 1;
2645 2660
2646#ifdef CONFIG_PROC_FS 2661#ifdef CONFIG_PROC_FS
2647 proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); 2662 err = -ENOMEM;
2648 proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); 2663 if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops))
2664 goto out_sock_create;
2665 if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO,
2666 &igmp6_mcf_seq_fops)) {
2667 proc_net_remove(net, "igmp6");
2668 goto out_sock_create;
2669 }
2649#endif 2670#endif
2650 2671
2651 return 0; 2672 err = 0;
2673out:
2674 return err;
2675
2676out_sock_create:
2677 sk_release_kernel(net->ipv6.igmp_sk);
2678 goto out;
2652} 2679}
2653 2680
2654void igmp6_cleanup(void) 2681static void igmp6_net_exit(struct net *net)
2655{ 2682{
2656 sock_release(igmp6_socket); 2683 sk_release_kernel(net->ipv6.igmp_sk);
2657 igmp6_socket = NULL; /* for safety */
2658
2659#ifdef CONFIG_PROC_FS 2684#ifdef CONFIG_PROC_FS
2660 proc_net_remove(&init_net, "mcfilter6"); 2685 proc_net_remove(net, "mcfilter6");
2661 proc_net_remove(&init_net, "igmp6"); 2686 proc_net_remove(net, "igmp6");
2662#endif 2687#endif
2663} 2688}
2689
2690static struct pernet_operations igmp6_net_ops = {
2691 .init = igmp6_net_init,
2692 .exit = igmp6_net_exit,
2693};
2694
2695int __init igmp6_init(void)
2696{
2697 return register_pernet_subsys(&igmp6_net_ops);
2698}
2699
2700void igmp6_cleanup(void)
2701{
2702 unregister_pernet_subsys(&igmp6_net_ops);
2703}