Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7705f730 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ip_level_multicast_join_leave'



Madhu Challa says:

====================
Multicast group join/leave at ip level

This series enables configuring multicast group join/leave at ip level
by extending the "ip address" command.

It adds a new control socket mc_autojoin_sock and ifa_flag IFA_F_MCAUTOJOIN
to invoke the corresponding igmp group join/leave api.

Since the igmp group join/leave api takes the rtnl_lock the code had to
be refactored by adding a shim layer prefixed by __ that can be invoked
by code that already has the rtnl_lock. This way we avoid proliferation of
work queues.

The first patch in this series does the refactoring for igmp v6.
Its based on igmp v4 changes that were added by Eric Dumazet.

The second patch in this series does the group join/leave based on the
setting of the IFA_F_MCAUTOJOIN flag.

v5:
- addressed comments from Daniel Borkmann.
 - removed blank line in patch 1/2
 - removed unused variable, const arg in patch 2/2
v4:
- addressed comments from Yoshifuji Hideaki.
 - Remove WARN_ON not needed because we return a value from v2.
- addressed comments from Daniel Borkmann.
 - rename sock to mc_autojoin_sk
 - ip_mc_config() pass ifa so it needs one less argument.
 - igmp_net_{init|destroy}() use inet_ctl_sock_{create|destroy}
 - inet_rtm_newaddr() change scope of ret.
 - igmp_net_init() no need to initialize sock to NULL.
v3:
- addressed comments from David Miller.
 - fixed indentation and local variable order.
v2:
- addressed comments from Eric Dumazet.
 - removed workqueue and call __ip_mc_{join|leave}_group or
   __ipv6_sock_mc_{join|drop}
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 723b8e46 93a714d6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -940,4 +940,12 @@ int ipv6_sysctl_register(void);
void ipv6_sysctl_unregister(void);
#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 */
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ struct netns_ipv4 {
	struct sock		*fibnl;

	struct sock  * __percpu	*icmp_sk;
	struct sock		*mc_autojoin_sk;

	struct inet_peer_base	*peers;
	struct tcpm_hash_bucket	*tcp_metrics_hash;
+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct netns_ipv6 {
	struct sock             *ndisc_sk;
	struct sock             *tcp_sk;
	struct sock             *igmp_sk;
	struct sock		*mc_autojoin_sk;
#ifdef CONFIG_IPV6_MROUTE
#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
	struct mr6_table	*mrt6;
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ enum {
#define IFA_F_PERMANENT		0x80
#define IFA_F_MANAGETEMPADDR	0x100
#define IFA_F_NOPREFIXROUTE	0x200
#define IFA_F_MCAUTOJOIN	0x400

struct ifa_cacheinfo {
	__u32	ifa_prefered;
+31 −0
Original line number Diff line number Diff line
@@ -548,6 +548,26 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
	return NULL;
}

static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
{
	struct ip_mreqn mreq = {
		.imr_multiaddr.s_addr = ifa->ifa_address,
		.imr_ifindex = ifa->ifa_dev->dev->ifindex,
	};
	int ret;

	ASSERT_RTNL();

	lock_sock(sk);
	if (join)
		ret = __ip_mc_join_group(sk, &mreq);
	else
		ret = __ip_mc_leave_group(sk, &mreq);
	release_sock(sk);

	return ret;
}

static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	struct net *net = sock_net(skb->sk);
@@ -584,6 +604,8 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
		    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
			continue;

		if (ipv4_is_multicast(ifa->ifa_address))
			ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
		return 0;
	}
@@ -838,6 +860,15 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
		 * userspace already relies on not having to provide this.
		 */
		set_ifa_lifetime(ifa, valid_lft, prefered_lft);
		if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
			int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
					       true, ifa);

			if (ret < 0) {
				inet_free_ifa(ifa);
				return ret;
			}
		}
		return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
	} else {
		inet_free_ifa(ifa);
Loading