igmp v6: add __ipv6_sock_mc_join and __ipv6_sock_mc_drop
Based on the igmp v4 changes from Eric Dumazet. 959d10f6bbf6("igmp: add __ip_mc_{join|leave}_group()") These changes are needed to perform igmp v6 join/leave while RTNL is held. Make ipv6_sock_mc_join and ipv6_sock_mc_drop wrappers around __ipv6_sock_mc_join and __ipv6_sock_mc_drop to avoid proliferation of work queues. Signed-off-by: Madhu Challa <challa@noironetworks.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
723b8e460d
commit
46a4dee074
|
@ -940,4 +940,12 @@ int ipv6_sysctl_register(void);
|
||||||
void ipv6_sysctl_unregister(void);
|
void ipv6_sysctl_unregister(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int ipv6_sock_mc_join(struct sock *sk, int ifindex,
|
||||||
|
const struct in6_addr *addr);
|
||||||
|
int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
|
||||||
|
const struct in6_addr *addr);
|
||||||
|
int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
|
||||||
|
const struct in6_addr *addr);
|
||||||
|
int __ipv6_sock_mc_drop(struct sock *sk, int ifindex,
|
||||||
|
const struct in6_addr *addr);
|
||||||
#endif /* _NET_IPV6_H */
|
#endif /* _NET_IPV6_H */
|
||||||
|
|
|
@ -132,7 +132,7 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
|
||||||
return iv > 0 ? iv : 1;
|
return iv > 0 ? iv : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
int __ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct net_device *dev = NULL;
|
struct net_device *dev = NULL;
|
||||||
struct ipv6_mc_socklist *mc_lst;
|
struct ipv6_mc_socklist *mc_lst;
|
||||||
|
@ -140,6 +140,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
if (!ipv6_addr_is_multicast(addr))
|
if (!ipv6_addr_is_multicast(addr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -161,7 +163,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
mc_lst->next = NULL;
|
mc_lst->next = NULL;
|
||||||
mc_lst->addr = *addr;
|
mc_lst->addr = *addr;
|
||||||
|
|
||||||
rtnl_lock();
|
|
||||||
if (ifindex == 0) {
|
if (ifindex == 0) {
|
||||||
struct rt6_info *rt;
|
struct rt6_info *rt;
|
||||||
rt = rt6_lookup(net, addr, NULL, 0, 0);
|
rt = rt6_lookup(net, addr, NULL, 0, 0);
|
||||||
|
@ -173,7 +174,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
dev = __dev_get_by_index(net, ifindex);
|
dev = __dev_get_by_index(net, ifindex);
|
||||||
|
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
rtnl_unlock();
|
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
err = ipv6_dev_mc_inc(dev, addr);
|
err = ipv6_dev_mc_inc(dev, addr);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
rtnl_unlock();
|
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -198,25 +197,37 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
mc_lst->next = np->ipv6_mc_list;
|
mc_lst->next = np->ipv6_mc_list;
|
||||||
rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
|
rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
|
||||||
|
|
||||||
rtnl_unlock();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(__ipv6_sock_mc_join);
|
||||||
|
|
||||||
|
int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
ret = __ipv6_sock_mc_join(sk, ifindex, addr);
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ipv6_sock_mc_join);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* socket leave on multicast group
|
* socket leave on multicast group
|
||||||
*/
|
*/
|
||||||
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
int __ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||||
struct ipv6_mc_socklist *mc_lst;
|
struct ipv6_mc_socklist *mc_lst;
|
||||||
struct ipv6_mc_socklist __rcu **lnk;
|
struct ipv6_mc_socklist __rcu **lnk;
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
|
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
if (!ipv6_addr_is_multicast(addr))
|
if (!ipv6_addr_is_multicast(addr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rtnl_lock();
|
|
||||||
for (lnk = &np->ipv6_mc_list;
|
for (lnk = &np->ipv6_mc_list;
|
||||||
(mc_lst = rtnl_dereference(*lnk)) != NULL;
|
(mc_lst = rtnl_dereference(*lnk)) != NULL;
|
||||||
lnk = &mc_lst->next) {
|
lnk = &mc_lst->next) {
|
||||||
|
@ -235,17 +246,28 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
||||||
} else
|
} else
|
||||||
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
||||||
rtnl_unlock();
|
|
||||||
|
|
||||||
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
|
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
|
||||||
kfree_rcu(mc_lst, rcu);
|
kfree_rcu(mc_lst, rcu);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
|
||||||
|
|
||||||
return -EADDRNOTAVAIL;
|
return -EADDRNOTAVAIL;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(__ipv6_sock_mc_drop);
|
||||||
|
|
||||||
|
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ipv6_sock_mc_drop);
|
||||||
|
|
||||||
/* called with rcu_read_lock() */
|
/* called with rcu_read_lock() */
|
||||||
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
|
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
|
||||||
|
|
Loading…
Reference in New Issue