aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorMadhu Challa <challa@noironetworks.com>2015-02-25 12:58:35 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-27 16:25:25 -0500
commit93a714d6b53d87872e552dbb273544bdeaaf6e12 (patch)
tree3cc79521cb6dbcd600384507329ecef93ae618ab /net/ipv6
parent46a4dee074b58c4256dbf6c2dbf199c372f85b04 (diff)
multicast: Extend ip address command to enable multicast group join/leave on
Joining multicast group on ethernet level via "ip maddr" command would not work if we have an Ethernet switch that does igmp snooping since the switch would not replicate multicast packets on ports that did not have IGMP reports for the multicast addresses. Linux vxlan interfaces created via "ip link add vxlan" have the group option that enables then to do the required join. By extending ip address command with option "autojoin" we can get similar functionality for openvswitch vxlan interfaces as well as other tunneling mechanisms that need to receive multicast traffic. The kernel code is structured similar to how the vxlan driver does a group join / leave. example: ip address add 224.1.1.10/24 dev eth5 autojoin ip address del 224.1.1.10/24 dev eth5 Signed-off-by: Madhu Challa <challa@noironetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c38
-rw-r--r--net/ipv6/mcast.c20
2 files changed, 51 insertions, 7 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 98e4a63d72bb..783bccfcc060 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2464,6 +2464,23 @@ err_exit:
2464 return err; 2464 return err;
2465} 2465}
2466 2466
2467static int ipv6_mc_config(struct sock *sk, bool join,
2468 const struct in6_addr *addr, int ifindex)
2469{
2470 int ret;
2471
2472 ASSERT_RTNL();
2473
2474 lock_sock(sk);
2475 if (join)
2476 ret = __ipv6_sock_mc_join(sk, ifindex, addr);
2477 else
2478 ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
2479 release_sock(sk);
2480
2481 return ret;
2482}
2483
2467/* 2484/*
2468 * Manual configuration of address on an interface 2485 * Manual configuration of address on an interface
2469 */ 2486 */
@@ -2476,10 +2493,10 @@ static int inet6_addr_add(struct net *net, int ifindex,
2476 struct inet6_ifaddr *ifp; 2493 struct inet6_ifaddr *ifp;
2477 struct inet6_dev *idev; 2494 struct inet6_dev *idev;
2478 struct net_device *dev; 2495 struct net_device *dev;
2496 unsigned long timeout;
2497 clock_t expires;
2479 int scope; 2498 int scope;
2480 u32 flags; 2499 u32 flags;
2481 clock_t expires;
2482 unsigned long timeout;
2483 2500
2484 ASSERT_RTNL(); 2501 ASSERT_RTNL();
2485 2502
@@ -2501,6 +2518,14 @@ static int inet6_addr_add(struct net *net, int ifindex,
2501 if (IS_ERR(idev)) 2518 if (IS_ERR(idev))
2502 return PTR_ERR(idev); 2519 return PTR_ERR(idev);
2503 2520
2521 if (ifa_flags & IFA_F_MCAUTOJOIN) {
2522 int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk,
2523 true, pfx, ifindex);
2524
2525 if (ret < 0)
2526 return ret;
2527 }
2528
2504 scope = ipv6_addr_scope(pfx); 2529 scope = ipv6_addr_scope(pfx);
2505 2530
2506 timeout = addrconf_timeout_fixup(valid_lft, HZ); 2531 timeout = addrconf_timeout_fixup(valid_lft, HZ);
@@ -2542,6 +2567,9 @@ static int inet6_addr_add(struct net *net, int ifindex,
2542 in6_ifa_put(ifp); 2567 in6_ifa_put(ifp);
2543 addrconf_verify_rtnl(); 2568 addrconf_verify_rtnl();
2544 return 0; 2569 return 0;
2570 } else if (ifa_flags & IFA_F_MCAUTOJOIN) {
2571 ipv6_mc_config(net->ipv6.mc_autojoin_sk,
2572 false, pfx, ifindex);
2545 } 2573 }
2546 2574
2547 return PTR_ERR(ifp); 2575 return PTR_ERR(ifp);
@@ -2578,6 +2606,10 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
2578 jiffies); 2606 jiffies);
2579 ipv6_del_addr(ifp); 2607 ipv6_del_addr(ifp);
2580 addrconf_verify_rtnl(); 2608 addrconf_verify_rtnl();
2609 if (ipv6_addr_is_multicast(pfx)) {
2610 ipv6_mc_config(net->ipv6.mc_autojoin_sk,
2611 false, pfx, dev->ifindex);
2612 }
2581 return 0; 2613 return 0;
2582 } 2614 }
2583 } 2615 }
@@ -3945,7 +3977,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3945 3977
3946 /* We ignore other flags so far. */ 3978 /* We ignore other flags so far. */
3947 ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | 3979 ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
3948 IFA_F_NOPREFIXROUTE; 3980 IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN;
3949 3981
3950 ifa = ipv6_get_ifaddr(net, pfx, dev, 1); 3982 ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
3951 if (ifa == NULL) { 3983 if (ifa == NULL) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index e4955d019734..1dd1fedff9f4 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2929,20 +2929,32 @@ static int __net_init igmp6_net_init(struct net *net)
2929 2929
2930 inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; 2930 inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1;
2931 2931
2932 err = inet_ctl_sock_create(&net->ipv6.mc_autojoin_sk, PF_INET6,
2933 SOCK_RAW, IPPROTO_ICMPV6, net);
2934 if (err < 0) {
2935 pr_err("Failed to initialize the IGMP6 autojoin socket (err %d)\n",
2936 err);
2937 goto out_sock_create;
2938 }
2939
2932 err = igmp6_proc_init(net); 2940 err = igmp6_proc_init(net);
2933 if (err) 2941 if (err)
2934 goto out_sock_create; 2942 goto out_sock_create_autojoin;
2935out: 2943
2936 return err; 2944 return 0;
2937 2945
2946out_sock_create_autojoin:
2947 inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
2938out_sock_create: 2948out_sock_create:
2939 inet_ctl_sock_destroy(net->ipv6.igmp_sk); 2949 inet_ctl_sock_destroy(net->ipv6.igmp_sk);
2940 goto out; 2950out:
2951 return err;
2941} 2952}
2942 2953
2943static void __net_exit igmp6_net_exit(struct net *net) 2954static void __net_exit igmp6_net_exit(struct net *net)
2944{ 2955{
2945 inet_ctl_sock_destroy(net->ipv6.igmp_sk); 2956 inet_ctl_sock_destroy(net->ipv6.igmp_sk);
2957 inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
2946 igmp6_proc_exit(net); 2958 igmp6_proc_exit(net);
2947} 2959}
2948 2960