Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] net: Allow any address multicast join for IP sockets
@ 2021-07-06  1:15 Callum Sinclair
  2021-07-06  1:15 ` Callum Sinclair
  2021-07-06 13:28 ` Andrew Lunn
  0 siblings, 2 replies; 7+ messages in thread
From: Callum Sinclair @ 2021-07-06  1:15 UTC (permalink / raw)
  To: dsahern, nikolay; +Cc: netdev, linux-kernel, linus.luessing, Callum Sinclair

For an application to receive all multicast packets in a range such as
224.0.0.1 - 239.255.255.255 each multicast IP address has to be joined
explicitly one at a time.

Allow the any address to be passed to the IP_ADD_MEMBERSHIP and
IPV6_ADD_MEMBERSHIP socket option per interface. By joining the any
address the socket will receive all multicast packets that are received
on the interface. 

This allows any IP socket to be used for IGMP or MLD snooping.

Callum Sinclair (1):
  net: Allow any address multicast join for IP sockets

 net/ipv4/igmp.c  | 40 ++++++++++++++++++++++++++++++++--------
 net/ipv6/mcast.c | 20 ++++++++++++++------
 2 files changed, 46 insertions(+), 14 deletions(-)

-- 
2.32.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-06  1:15 [PATCH] net: Allow any address multicast join for IP sockets Callum Sinclair
@ 2021-07-06  1:15 ` Callum Sinclair
  2021-07-06  5:18   ` kernel test robot
  2021-07-07  7:26   ` [kbuild] " Dan Carpenter
  2021-07-06 13:28 ` Andrew Lunn
  1 sibling, 2 replies; 7+ messages in thread
From: Callum Sinclair @ 2021-07-06  1:15 UTC (permalink / raw)
  To: dsahern, nikolay; +Cc: netdev, linux-kernel, linus.luessing, Callum Sinclair

For an application to receive all multicast packets in a range such as
224.0.0.1 - 239.255.255.255 each multicast IP address has to be joined
explicitly one at a time.

Allow the any address to be passed to the IP_ADD_MEMBERSHIP and
IPV6_ADD_MEMBERSHIP socket option per interface. By joining the any
address the socket will receive all multicast packets that are received
on the interface. This allows any IP socket to be used for IGMP or MLD
snooping.

Signed-off-by: Callum Sinclair <callum.sinclair@alliedtelesis.co.nz>
---
 net/ipv4/igmp.c  | 40 ++++++++++++++++++++++++++++++++--------
 net/ipv6/mcast.c | 20 ++++++++++++++------
 2 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 6b3c558a4f23..3978c9f2d1c5 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1413,6 +1413,25 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
 	*mc_hash = im->next_hash;
 }
 
+static struct ip_mc_list *ip_mc_hash_lookup(struct ip_mc_list __rcu **mc_hash,
+					    __be32 mc_addr)
+{
+	struct ip_mc_list *im;
+	u32 hash;
+
+	if (mc_hash) {
+		hash = hash_32((__force u32)mc_addr, MC_HASH_SZ_LOG);
+		for (im = rcu_dereference(mc_hash[hash]);
+		     im != NULL;
+		     im = rcu_dereference(im->next_hash)) {
+			if (im->multiaddr == mc_addr)
+				break;
+			}
+	}
+
+	return im;
+}
+
 
 /*
  *	A socket has joined a multicast group on device dev.
@@ -2166,7 +2185,7 @@ static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
 
 	ASSERT_RTNL();
 
-	if (!ipv4_is_multicast(addr))
+	if (!ipv4_is_multicast(addr) && addr != htonl(INADDR_ANY))
 		return -EINVAL;
 
 	in_dev = ip_mc_find_dev(net, imr);
@@ -2627,6 +2646,11 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr,
 
 	rcu_read_lock();
 	for_each_pmc_rcu(inet, pmc) {
+		if (pmc->multi.imr_multiaddr.s_addr == htonl(INADDR_ANY) &&
+		    pmc->multi.imr_ifindex == dif) {
+			ret = 1;
+			goto unlock;
+		}
 		if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
 		    (pmc->multi.imr_ifindex == dif ||
 		     (sdif && pmc->multi.imr_ifindex == sdif)))
@@ -2695,18 +2719,18 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u
 
 	mc_hash = rcu_dereference(in_dev->mc_hash);
 	if (mc_hash) {
-		u32 hash = hash_32((__force u32)mc_addr, MC_HASH_SZ_LOG);
-
-		for (im = rcu_dereference(mc_hash[hash]);
-		     im != NULL;
-		     im = rcu_dereference(im->next_hash)) {
-			if (im->multiaddr == mc_addr)
-				break;
+		im = ip_mc_hash_lookup(mc_hash, mc_addr);
+		if (!im) {
+			if (ip_mc_hash_lookup(mc_hash, htonl(INADDR_ANY)))
+				return 1;
 		}
+
 	} else {
 		for_each_pmc_rcu(in_dev, im) {
 			if (im->multiaddr == mc_addr)
 				break;
+			if (im->multiaddr == htonl(INADDR_ANY))
+				return 1;
 		}
 	}
 	if (im && proto == IPPROTO_IGMP) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 54ec163fbafa..7acf5b3cb435 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -177,7 +177,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
 
 	ASSERT_RTNL();
 
-	if (!ipv6_addr_is_multicast(addr))
+	if (!ipv6_addr_is_multicast(addr) && !ipv6_addr_any(addr))
 		return -EINVAL;
 
 	for_each_pmc_socklock(np, sk, mc_lst) {
@@ -254,7 +254,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
 
 	ASSERT_RTNL();
 
-	if (!ipv6_addr_is_multicast(addr))
+	if (!ipv6_addr_is_multicast(addr) && !ipv6_addr_any(addr))
 		return -EINVAL;
 
 	for (lnk = &np->ipv6_mc_list;
@@ -374,7 +374,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 	source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;
 	group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr;
 
-	if (!ipv6_addr_is_multicast(group))
+	if (!ipv6_addr_is_multicast(group) && !ipv6_addr_any(group))
 		return -EINVAL;
 
 	idev = ip6_mc_find_dev_rtnl(net, group, pgsr->gsr_interface);
@@ -497,7 +497,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
 
 	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
 
-	if (!ipv6_addr_is_multicast(group))
+	if (!ipv6_addr_is_multicast(group) && !ipv6_addr_any(group))
 		return -EINVAL;
 	if (gsf->gf_fmode != MCAST_INCLUDE &&
 	    gsf->gf_fmode != MCAST_EXCLUDE)
@@ -585,7 +585,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 
 	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
 
-	if (!ipv6_addr_is_multicast(group))
+	if (!ipv6_addr_is_multicast(group) && !ipv6_addr_any(group))
 		return -EINVAL;
 
 	/* changes to the ipv6_mc_list require the socket lock and
@@ -634,6 +634,10 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
 	for_each_pmc_rcu(np, mc) {
 		if (ipv6_addr_equal(&mc->addr, mc_addr))
 			break;
+		if (ipv6_addr_any(&mc->addr)) {
+			rcu_read_unlock();
+			return rv;
+		}
 	}
 	if (!mc) {
 		rcu_read_unlock();
@@ -1019,8 +1023,12 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
 		for_each_mc_rcu(idev, mc) {
 			if (ipv6_addr_equal(&mc->mca_addr, group))
 				break;
+			if (ipv6_addr_any(&mc->mca_addr)) {
+				rv = true;
+				break;
+			}
 		}
-		if (mc) {
+		if (mc && !ipv6_addr_any(&mc->mca_addr)) {
 			if (src_addr && !ipv6_addr_any(src_addr)) {
 				struct ip6_sf_list *psf;
 
-- 
2.32.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-06  1:15 ` Callum Sinclair
@ 2021-07-06  5:18   ` kernel test robot
  2021-07-07  7:26   ` [kbuild] " Dan Carpenter
  1 sibling, 0 replies; 7+ messages in thread
From: kernel test robot @ 2021-07-06  5:18 UTC (permalink / raw)
  To: Callum Sinclair, dsahern, nikolay
  Cc: clang-built-linux, kbuild-all, netdev, linux-kernel,
	linus.luessing, Callum Sinclair

[-- Attachment #1: Type: text/plain, Size: 3162 bytes --]

Hi Callum,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.13 next-20210701]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Callum-Sinclair/net-Allow-any-address-multicast-join-for-IP-sockets/20210706-091734
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79160a603bdb51916226caf4a6616cc4e1c58a58
config: x86_64-randconfig-b001-20210705 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 873e8b96b1226d64e4f95083147d8592ba7bd5d8)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/b05967ad8bde7d374f6cf6f2b8bebe12828c480c
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Callum-Sinclair/net-Allow-any-address-multicast-join-for-IP-sockets/20210706-091734
        git checkout b05967ad8bde7d374f6cf6f2b8bebe12828c480c
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> net/ipv4/igmp.c:1422:6: warning: variable 'im' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
           if (mc_hash) {
               ^~~~~~~
   net/ipv4/igmp.c:1432:9: note: uninitialized use occurs here
           return im;
                  ^~
   net/ipv4/igmp.c:1422:2: note: remove the 'if' if its condition is always true
           if (mc_hash) {
           ^~~~~~~~~~~~~
   net/ipv4/igmp.c:1419:23: note: initialize the variable 'im' to silence this warning
           struct ip_mc_list *im;
                                ^
                                 = NULL
   net/ipv4/igmp.c:1917:6: warning: variable 'changerec' set but not used [-Wunused-but-set-variable]
           int     changerec = 0;
                   ^
   2 warnings generated.


vim +1422 net/ipv4/igmp.c

  1415	
  1416	static struct ip_mc_list *ip_mc_hash_lookup(struct ip_mc_list __rcu **mc_hash,
  1417						    __be32 mc_addr)
  1418	{
  1419		struct ip_mc_list *im;
  1420		u32 hash;
  1421	
> 1422		if (mc_hash) {
  1423			hash = hash_32((__force u32)mc_addr, MC_HASH_SZ_LOG);
  1424			for (im = rcu_dereference(mc_hash[hash]);
  1425			     im != NULL;
  1426			     im = rcu_dereference(im->next_hash)) {
  1427				if (im->multiaddr == mc_addr)
  1428					break;
  1429				}
  1430		}
  1431	
  1432		return im;
  1433	}
  1434	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 39682 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-06  1:15 [PATCH] net: Allow any address multicast join for IP sockets Callum Sinclair
  2021-07-06  1:15 ` Callum Sinclair
@ 2021-07-06 13:28 ` Andrew Lunn
  2021-07-07  2:00   ` Callum Sinclair
  1 sibling, 1 reply; 7+ messages in thread
From: Andrew Lunn @ 2021-07-06 13:28 UTC (permalink / raw)
  To: Callum Sinclair; +Cc: dsahern, nikolay, netdev, linux-kernel, linus.luessing

On Tue, Jul 06, 2021 at 01:15:47PM +1200, Callum Sinclair wrote:
> For an application to receive all multicast packets in a range such as
> 224.0.0.1 - 239.255.255.255 each multicast IP address has to be joined
> explicitly one at a time.
> 
> Allow the any address to be passed to the IP_ADD_MEMBERSHIP and
> IPV6_ADD_MEMBERSHIP socket option per interface. By joining the any
> address the socket will receive all multicast packets that are received
> on the interface. 
> 
> This allows any IP socket to be used for IGMP or MLD snooping.

Do you really want all multicast frames, or just IGMP and MLD
messages?

What is the advantage of this solution over using pcap with a filter
which matches on multicast?

      Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-06 13:28 ` Andrew Lunn
@ 2021-07-07  2:00   ` Callum Sinclair
  2021-07-07 14:56     ` Andrew Lunn
  0 siblings, 1 reply; 7+ messages in thread
From: Callum Sinclair @ 2021-07-07  2:00 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: dsahern, nikolay, netdev, linux-kernel, linus.luessing

Hi Andrew

Yes I want to receive all multicast frames.This is to configure
a userspace switch driver to prevent unknown multicast
routes being flooded unexpectedly to all switch ports.

The advantage of using IP sockets over a pcap on raw sockets
is I can still use the Linux routing stack for sending and receiving
packets.

Cheers
Callum
________________________________________
From: Andrew Lunn <andrew@lunn.ch>
Sent: Wednesday, July 7, 2021 1:28 AM
To: Callum Sinclair
Cc: dsahern@kernel.org; nikolay@nvidia.com; netdev@vger.kernel.org; linux-kernel@vger.kernel.org; linus.luessing@c0d3.blue
Subject: Re: [PATCH] net: Allow any address multicast join for IP sockets

On Tue, Jul 06, 2021 at 01:15:47PM +1200, Callum Sinclair wrote:
> For an application to receive all multicast packets in a range such as
> 224.0.0.1 - 239.255.255.255 each multicast IP address has to be joined
> explicitly one at a time.
>
> Allow the any address to be passed to the IP_ADD_MEMBERSHIP and
> IPV6_ADD_MEMBERSHIP socket option per interface. By joining the any
> address the socket will receive all multicast packets that are received
> on the interface.
>
> This allows any IP socket to be used for IGMP or MLD snooping.

Do you really want all multicast frames, or just IGMP and MLD
messages?

What is the advantage of this solution over using pcap with a filter
which matches on multicast?

      Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [kbuild] Re: [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-06  1:15 ` Callum Sinclair
  2021-07-06  5:18   ` kernel test robot
@ 2021-07-07  7:26   ` Dan Carpenter
  1 sibling, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2021-07-07  7:26 UTC (permalink / raw)
  To: kbuild, Callum Sinclair, dsahern, nikolay
  Cc: lkp, kbuild-all, netdev, linux-kernel, linus.luessing, Callum Sinclair

Hi Callum,

url:    https://github.com/0day-ci/linux/commits/Callum-Sinclair/net-Allow-any-address-multicast-join-for-IP-sockets/20210706-091734 
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git  79160a603bdb51916226caf4a6616cc4e1c58a58
compiler: m68k-linux-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

cppcheck possible warnings: (new ones prefixed by >>, may not real problems)

>> net/ipv4/igmp.c:1432:9: warning: Uninitialized variable: im [uninitvar]
    return im;
           ^

vim +1432 net/ipv4/igmp.c

b05967ad8bde7d Callum Sinclair 2021-07-06  1416  static struct ip_mc_list *ip_mc_hash_lookup(struct ip_mc_list __rcu **mc_hash,
b05967ad8bde7d Callum Sinclair 2021-07-06  1417  					    __be32 mc_addr)
b05967ad8bde7d Callum Sinclair 2021-07-06  1418  {
b05967ad8bde7d Callum Sinclair 2021-07-06  1419  	struct ip_mc_list *im;
b05967ad8bde7d Callum Sinclair 2021-07-06  1420  	u32 hash;
b05967ad8bde7d Callum Sinclair 2021-07-06  1421  
b05967ad8bde7d Callum Sinclair 2021-07-06  1422  	if (mc_hash) {
b05967ad8bde7d Callum Sinclair 2021-07-06  1423  		hash = hash_32((__force u32)mc_addr, MC_HASH_SZ_LOG);
b05967ad8bde7d Callum Sinclair 2021-07-06  1424  		for (im = rcu_dereference(mc_hash[hash]);
b05967ad8bde7d Callum Sinclair 2021-07-06  1425  		     im != NULL;
b05967ad8bde7d Callum Sinclair 2021-07-06  1426  		     im = rcu_dereference(im->next_hash)) {
b05967ad8bde7d Callum Sinclair 2021-07-06  1427  			if (im->multiaddr == mc_addr)
b05967ad8bde7d Callum Sinclair 2021-07-06  1428  				break;
b05967ad8bde7d Callum Sinclair 2021-07-06  1429  			}
b05967ad8bde7d Callum Sinclair 2021-07-06  1430  	}

"im" not intialized on else path.

b05967ad8bde7d Callum Sinclair 2021-07-06  1431  
b05967ad8bde7d Callum Sinclair 2021-07-06 @1432  	return im;
b05967ad8bde7d Callum Sinclair 2021-07-06  1433  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org 
_______________________________________________
kbuild mailing list -- kbuild@lists.01.org
To unsubscribe send an email to kbuild-leave@lists.01.org


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] net: Allow any address multicast join for IP sockets
  2021-07-07  2:00   ` Callum Sinclair
@ 2021-07-07 14:56     ` Andrew Lunn
  0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2021-07-07 14:56 UTC (permalink / raw)
  To: Callum Sinclair; +Cc: dsahern, nikolay, netdev, linux-kernel, linus.luessing

On Wed, Jul 07, 2021 at 02:00:29AM +0000, Callum Sinclair wrote:
> Hi Andrew
> 
> Yes I want to receive all multicast frames.This is to configure
> a userspace switch driver to prevent unknown multicast
> routes being flooded unexpectedly to all switch ports.

Don't you just need the signalling, not the data?

Also, netdev is not friendly to user space switch drivers. You should
be using an in kernel switch driver. So we are unlikely to add an API
which is only going to be used by a user space switch driver. If you
provide patches to mrouted, or frr pim routing daemon which makes use
of this new API, it might get accepted, and then you can also use it
in your user space switch driver as well. Otherwise, i would suggest
you keep to the existing APIs, BPF and pcap for example.

   Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-07-07 14:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-06  1:15 [PATCH] net: Allow any address multicast join for IP sockets Callum Sinclair
2021-07-06  1:15 ` Callum Sinclair
2021-07-06  5:18   ` kernel test robot
2021-07-07  7:26   ` [kbuild] " Dan Carpenter
2021-07-06 13:28 ` Andrew Lunn
2021-07-07  2:00   ` Callum Sinclair
2021-07-07 14:56     ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).