2021-07-06 01:17:16

by Callum Sinclair

[permalink] [raw]
Subject: [PATCH] net: Allow any address multicast join for IP sockets

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


2021-07-06 01:20:02

by Callum Sinclair

[permalink] [raw]
Subject: [PATCH] net: Allow any address multicast join for IP sockets

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 <[email protected]>
---
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

2021-07-06 05:20:38

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] net: Allow any address multicast join for IP sockets

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 <[email protected]>

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/[email protected]


Attachments:
(No filename) (3.16 kB)
.config.gz (38.75 kB)
Download all attachments

2021-07-06 13:32:07

by Andrew Lunn

[permalink] [raw]
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

2021-07-07 02:02:16

by Callum Sinclair

[permalink] [raw]
Subject: Re: [PATCH] net: Allow any address multicast join for IP sockets

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 <[email protected]>
Sent: Wednesday, July 7, 2021 1:28 AM
To: Callum Sinclair
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
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

2021-07-07 07:30:07

by Dan Carpenter

[permalink] [raw]
Subject: [kbuild] Re: [PATCH] net: Allow any address multicast join for IP sockets

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 <[email protected]>

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/[email protected]
_______________________________________________
kbuild mailing list -- [email protected]
To unsubscribe send an email to [email protected]

2021-07-07 14:59:24

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH] net: Allow any address multicast join for IP sockets

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