[v2,2/3] batman-adv: mcast: collect softif listeners from IP lists instead

Message ID 20190507034824.3362-3-tux@c0d3.blue (mailing list archive)
State Superseded, archived
Delegated to: Simon Wunderlich
Headers
Series None |

Commit Message

Linus Lüssing May 7, 2019, 3:48 a.m. UTC
  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

Sven Eckelmann May 25, 2019, 11:40 a.m. UTC | #1
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
  

Patch

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index af0e2ce8..2a975bc0 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -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