[v2,2/3] batman-adv: mcast: collect softif listeners from IP lists instead
Commit Message
From: Linus Lüssing <linus.luessing@c0d3.blue>
Instead of collecting multicast MAC addresses from the netdev hw mc
list collect a node's multicast listeners from the IP lists and convert
those to MAC addresses.
This allows to exclude addresses of specific scope later. On a
multicast MAC address the IP destination scope is not visible anymore.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/multicast.c | 258 +++++++++++++++++++++++++------------
1 file changed, 173 insertions(+), 85 deletions(-)
Comments
On Tuesday, 7 May 2019 05:48:23 CEST T_X wrote:
[..]
> Instead of collecting multicast MAC addresses from the netdev hw mc
> list collect a node's multicast listeners from the IP lists and convert
> those to MAC addresses.
>
> This allows to exclude addresses of specific scope later. On a
> multicast MAC address the IP destination scope is not visible anymore.
>
> Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
There are various build problems. See attachment.
Kind regards,
Sven
tree: git://git.open-mesh.org/linux-merge batadv/net-next
head: 5e8230d96b966a3691f83e2b053798487725353e
commit: 5e8230d96b966a3691f83e2b053798487725353e [7/7] batman-adv: mcast: avoid redundant multicast TT entries with bridges
config: x86_64-randconfig-x008-201920 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
git checkout 5e8230d96b966a3691f83e2b053798487725353e
# save the attached .config to linux build tree
make ARCH=x86_64
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
net/batman-adv/multicast.c: In function 'batadv_mcast_mla_softif_get':
net/batman-adv/multicast.c:362:42: error: passing argument 1 of 'batadv_mcast_mla_softif_get_ipv6' from incompatible pointer type [-Werror=incompatible-pointer-types]
ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
^~~
net/batman-adv/multicast.c:320:1: note: expected 'struct batadv_priv *' but argument is of type 'struct net_device *'
batadv_mcast_mla_softif_get_ipv6(struct batadv_priv *bat_priv,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
net/batman-adv/multicast.c:362:47: error: passing argument 2 of 'batadv_mcast_mla_softif_get_ipv6' from incompatible pointer type [-Werror=incompatible-pointer-types]
ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
^~~~~~~~~~
net/batman-adv/multicast.c:320:1: note: expected 'struct net_device *' but argument is of type 'struct hlist_head *'
batadv_mcast_mla_softif_get_ipv6(struct batadv_priv *bat_priv,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
net/batman-adv/multicast.c:362:59: error: passing argument 3 of 'batadv_mcast_mla_softif_get_ipv6' from incompatible pointer type [-Werror=incompatible-pointer-types]
ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
^~~~~
net/batman-adv/multicast.c:320:1: note: expected 'struct hlist_head *' but argument is of type 'struct batadv_mcast_mla_flags *'
batadv_mcast_mla_softif_get_ipv6(struct batadv_priv *bat_priv,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
net/batman-adv/multicast.c: In function 'batadv_mcast_mla_bridge_get':
>> net/batman-adv/multicast.c:446:55: error: 'union <anonymous>' has no member named 'ip6'; did you mean 'ip4'?
ipv6_addr_is_ll_all_nodes(&br_ip_entry->addr.u.ip6))
^~~
ip4
cc1: some warnings being treated as errors
vim +446 net/batman-adv/multicast.c
327
328 /**
329 * batadv_mcast_mla_softif_get() - get softif multicast listeners
330 * @dev: the device to collect multicast addresses from
331 * @mcast_list: a list to put found addresses into
332 * @flags: flags indicating the new multicast state
333 *
334 * Collects multicast addresses of multicast listeners residing
335 * on this kernel on the given soft interface, dev, in
336 * the given mcast_list. In general, multicast listeners provided by
337 * your multicast receiving applications run directly on this node.
338 *
339 * If there is a bridge interface on top of dev, collects from that one
340 * instead. Just like with IP addresses and routes, multicast listeners
341 * will(/should) register to the bridge interface instead of an
342 * enslaved bat0.
343 *
344 * Return: -ENOMEM on memory allocation error or the number of
345 * items added to the mcast_list otherwise.
346 */
347 static int
348 batadv_mcast_mla_softif_get(struct net_device *dev,
349 struct hlist_head *mcast_list,
350 struct batadv_mcast_mla_flags *flags)
351 {
352 struct net_device *bridge = batadv_mcast_get_bridge(dev);
353 int ret4, ret6 = 0;
354
355 if (bridge)
356 dev = bridge;
357
358 ret4 = batadv_mcast_mla_softif_get_ipv4(dev, mcast_list, flags);
359 if (ret4 < 0)
360 goto out;
361
> 362 ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
363 if (ret6 < 0) {
364 ret4 = 0;
365 goto out;
366 }
367
368 out:
369 if (bridge)
370 dev_put(bridge);
371
372 return ret4 + ret6;
373 }
374
375 /**
376 * batadv_mcast_mla_br_addr_cpy() - copy a bridge multicast address
377 * @dst: destination to write to - a multicast MAC address
378 * @src: source to read from - a multicast IP address
379 *
380 * Converts a given multicast IPv4/IPv6 address from a bridge
381 * to its matching multicast MAC address and copies it into the given
382 * destination buffer.
383 *
384 * Caller needs to make sure the destination buffer can hold
385 * at least ETH_ALEN bytes.
386 */
387 static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
388 {
389 if (src->proto == htons(ETH_P_IP))
390 ip_eth_mc_map(src->u.ip4, dst);
391 #if IS_ENABLED(CONFIG_IPV6)
392 else if (src->proto == htons(ETH_P_IPV6))
393 ipv6_eth_mc_map(&src->u.ip6, dst);
394 #endif
395 else
396 eth_zero_addr(dst);
397 }
398
399 /**
400 * batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners
401 * @dev: a bridge slave whose bridge to collect multicast addresses from
402 * @mcast_list: a list to put found addresses into
403 * @flags: flags indicating the new multicast state
404 *
405 * Collects multicast addresses of multicast listeners residing
406 * on foreign, non-mesh devices which we gave access to our mesh via
407 * a bridge on top of the given soft interface, dev, in the given
408 * mcast_list.
409 *
410 * Return: -ENOMEM on memory allocation error or the number of
411 * items added to the mcast_list otherwise.
412 */
413 static int batadv_mcast_mla_bridge_get(struct net_device *dev,
414 struct hlist_head *mcast_list,
415 struct batadv_mcast_mla_flags *flags)
416 {
417 struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
418 struct br_ip_list *br_ip_entry, *tmp;
419 u8 tvlv_flags = flags->tvlv_flags;
420 struct batadv_hw_addr *new;
421 u8 mcast_addr[ETH_ALEN];
422 int ret;
423
424 /* we don't need to detect these devices/listeners, the IGMP/MLD
425 * snooping code of the Linux bridge already does that for us
426 */
427 ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
428 if (ret < 0)
429 goto out;
430
431 list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
432 if (br_ip_entry->addr.proto == htons(ETH_P_IP)) {
433 if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
434 continue;
435
436 if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
437 ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
438 continue;
439 }
440
441 if (br_ip_entry->addr.proto == htons(ETH_P_IPV6)) {
442 if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
443 continue;
444
445 if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
> 446 ipv6_addr_is_ll_all_nodes(&br_ip_entry->addr.u.ip6))
447 continue;
448 }
449
450 batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr);
451 if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
452 continue;
453
454 new = kmalloc(sizeof(*new), GFP_ATOMIC);
455 if (!new) {
456 ret = -ENOMEM;
457 break;
458 }
459
460 ether_addr_copy(new->addr, mcast_addr);
461 hlist_add_head(&new->list, mcast_list);
462 }
463
464 out:
465 list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
466 list_del(&br_ip_entry->list);
467 kfree(br_ip_entry);
468 }
469
470 return ret;
471 }
472
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
@@ -20,6 +20,7 @@
#include <linux/igmp.h>
#include <linux/in.h>
#include <linux/in6.h>
+#include <linux/inetdevice.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/jiffies.h>
@@ -171,91 +172,6 @@ static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface)
return upper;
}
-/**
- * batadv_mcast_addr_is_ipv4() - check if multicast MAC is IPv4
- * @addr: the MAC address to check
- *
- * Return: True, if MAC address is one reserved for IPv4 multicast, false
- * otherwise.
- */
-static bool batadv_mcast_addr_is_ipv4(const u8 *addr)
-{
- static const u8 prefix[] = {0x01, 0x00, 0x5E};
-
- return memcmp(prefix, addr, sizeof(prefix)) == 0;
-}
-
-/**
- * batadv_mcast_addr_is_ipv6() - check if multicast MAC is IPv6
- * @addr: the MAC address to check
- *
- * Return: True, if MAC address is one reserved for IPv6 multicast, false
- * otherwise.
- */
-static bool batadv_mcast_addr_is_ipv6(const u8 *addr)
-{
- static const u8 prefix[] = {0x33, 0x33};
-
- return memcmp(prefix, addr, sizeof(prefix)) == 0;
-}
-
-/**
- * batadv_mcast_mla_softif_get() - get softif multicast listeners
- * @dev: the device to collect multicast addresses from
- * @mcast_list: a list to put found addresses into
- * @flags: flags indicating the new multicast state
- *
- * Collects multicast addresses of multicast listeners residing
- * on this kernel on the given soft interface, dev, in
- * the given mcast_list. In general, multicast listeners provided by
- * your multicast receiving applications run directly on this node.
- *
- * If there is a bridge interface on top of dev, collects from that one
- * instead. Just like with IP addresses and routes, multicast listeners
- * will(/should) register to the bridge interface instead of an
- * enslaved bat0.
- *
- * Return: -ENOMEM on memory allocation error or the number of
- * items added to the mcast_list otherwise.
- */
-static int
-batadv_mcast_mla_softif_get(struct net_device *dev,
- struct hlist_head *mcast_list,
- struct batadv_mcast_mla_flags *flags)
-{
- bool all_ipv4 = flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4;
- bool all_ipv6 = flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6;
- struct net_device *bridge = batadv_mcast_get_bridge(dev);
- struct netdev_hw_addr *mc_list_entry;
- struct batadv_hw_addr *new;
- int ret = 0;
-
- netif_addr_lock_bh(bridge ? bridge : dev);
- netdev_for_each_mc_addr(mc_list_entry, bridge ? bridge : dev) {
- if (all_ipv4 && batadv_mcast_addr_is_ipv4(mc_list_entry->addr))
- continue;
-
- if (all_ipv6 && batadv_mcast_addr_is_ipv6(mc_list_entry->addr))
- continue;
-
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new) {
- ret = -ENOMEM;
- break;
- }
-
- ether_addr_copy(new->addr, mc_list_entry->addr);
- hlist_add_head(&new->list, mcast_list);
- ret++;
- }
- netif_addr_unlock_bh(bridge ? bridge : dev);
-
- if (bridge)
- dev_put(bridge);
-
- return ret;
-}
-
/**
* batadv_mcast_mla_is_duplicate() - check whether an address is in a list
* @mcast_addr: the multicast address to check
@@ -276,6 +192,178 @@ static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
return false;
}
+/**
+ * batadv_mcast_mla_softif_get_ipv4() - get softif IPv4 multicast listeners
+ * @dev: the device to collect multicast addresses from
+ * @mcast_list: a list to put found addresses into
+ * @flags: flags indicating the new multicast state
+ *
+ * Collects multicast addresses of IPv4 multicast listeners residing
+ * on this kernel on the given soft interface, dev, in
+ * the given mcast_list. In general, multicast listeners provided by
+ * your multicast receiving applications run directly on this node.
+ *
+ * Return: -ENOMEM on memory allocation error or the number of
+ * items added to the mcast_list otherwise.
+ */
+static int
+batadv_mcast_mla_softif_get_ipv4(struct net_device *dev,
+ struct hlist_head *mcast_list,
+ struct batadv_mcast_mla_flags *flags)
+{
+ struct batadv_hw_addr *new;
+ struct in_device *in_dev;
+ u8 mcast_addr[ETH_ALEN];
+ struct ip_mc_list *pmc;
+ int ret = 0;
+
+ if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
+ return 0;
+
+ in_dev = in_dev_get(dev);
+ if (!in_dev)
+ return 0;
+
+ rcu_read_lock();
+ for (pmc = rcu_dereference(in_dev->mc_list); pmc;
+ pmc = rcu_dereference(pmc->next_rcu)) {
+ ip_eth_mc_map(pmc->multiaddr, mcast_addr);
+
+ if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
+ continue;
+
+ new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ ether_addr_copy(new->addr, mcast_addr);
+ hlist_add_head(&new->list, mcast_list);
+ ret++;
+ }
+ rcu_read_unlock();
+ in_dev_put(in_dev);
+
+ return ret;
+}
+
+/**
+ * batadv_mcast_mla_softif_get_ipv6() - get softif IPv6 multicast listeners
+ * @dev: the device to collect multicast addresses from
+ * @mcast_list: a list to put found addresses into
+ * @flags: flags indicating the new multicast state
+ *
+ * Collects multicast addresses of IPv6 multicast listeners residing
+ * on this kernel on the given soft interface, dev, in
+ * the given mcast_list. In general, multicast listeners provided by
+ * your multicast receiving applications run directly on this node.
+ *
+ * Return: -ENOMEM on memory allocation error or the number of
+ * items added to the mcast_list otherwise.
+ */
+#if IS_ENABLED(CONFIG_IPV6)
+static int
+batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
+ struct hlist_head *mcast_list,
+ struct batadv_mcast_mla_flags *flags)
+{
+ struct batadv_hw_addr *new;
+ struct inet6_dev *in6_dev;
+ u8 mcast_addr[ETH_ALEN];
+ struct ifmcaddr6 *pmc6;
+ int ret = 0;
+
+ if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
+ return 0;
+
+ in6_dev = in6_dev_get(dev);
+ if (!in6_dev)
+ return 0;
+
+ read_lock_bh(&in6_dev->lock);
+ for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
+ if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
+ IPV6_ADDR_SCOPE_LINKLOCAL)
+ continue;
+
+ ipv6_eth_mc_map(&pmc6->mca_addr, mcast_addr);
+
+ if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
+ continue;
+
+ new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ ether_addr_copy(new->addr, mcast_addr);
+ hlist_add_head(&new->list, mcast_list);
+ ret++;
+ }
+ read_unlock_bh(&in6_dev->lock);
+ in6_dev_put(in6_dev);
+
+ return ret;
+}
+#else
+static inline int
+batadv_mcast_mla_softif_get_ipv6(struct batadv_priv *bat_priv,
+ struct net_device *dev,
+ struct hlist_head *mcast_list)
+{
+ return 0;
+}
+#endif
+
+/**
+ * batadv_mcast_mla_softif_get() - get softif multicast listeners
+ * @dev: the device to collect multicast addresses from
+ * @mcast_list: a list to put found addresses into
+ * @flags: flags indicating the new multicast state
+ *
+ * Collects multicast addresses of multicast listeners residing
+ * on this kernel on the given soft interface, dev, in
+ * the given mcast_list. In general, multicast listeners provided by
+ * your multicast receiving applications run directly on this node.
+ *
+ * If there is a bridge interface on top of dev, collects from that one
+ * instead. Just like with IP addresses and routes, multicast listeners
+ * will(/should) register to the bridge interface instead of an
+ * enslaved bat0.
+ *
+ * Return: -ENOMEM on memory allocation error or the number of
+ * items added to the mcast_list otherwise.
+ */
+static int
+batadv_mcast_mla_softif_get(struct net_device *dev,
+ struct hlist_head *mcast_list,
+ struct batadv_mcast_mla_flags *flags)
+{
+ struct net_device *bridge = batadv_mcast_get_bridge(dev);
+ int ret4, ret6 = 0;
+
+ if (bridge)
+ dev = bridge;
+
+ ret4 = batadv_mcast_mla_softif_get_ipv4(dev, mcast_list, flags);
+ if (ret4 < 0)
+ goto out;
+
+ ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
+ if (ret6 < 0) {
+ ret4 = 0;
+ goto out;
+ }
+
+out:
+ if (bridge)
+ dev_put(bridge);
+
+ return ret4 + ret6;
+}
+
/**
* batadv_mcast_mla_br_addr_cpy() - copy a bridge multicast address
* @dst: destination to write to - a multicast MAC address