So far, the recently added multicast optimizations did not support a configuration where a bridge is on top of the soft-interface (e.g. bat0).
Now the Linux bridge code is able to provide us with the missing bits:
Multicast Listeners: The bridge hands us a list of multicast listeners it has detected behind the bridge which we will announce through the mesh via the translation table, allowing other nodes to direct multicast packets to these clients behind the bridge even with enabled multicast optimizations.
Queriers: The bridge informs us whether there is a selected IGMP or MLD querier behind the bridge. In that case we need to all according IPv4 or IPv6 multicast traffic directed to us.
These two parts together allow us to serve all multicast listeners with IPv6 link-local multicast packets even when bridges are involved and our multicast optimizations enabled.
Signed-off-by: Linus Lüssing linus.luessing@web.de --- compat.c | 15 ++++++ compat.h | 30 ++++++++++++ main.h | 1 + multicast.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 179 insertions(+), 18 deletions(-)
diff --git a/compat.c b/compat.c index 3dbf9d2..7187a34 100644 --- a/compat.c +++ b/compat.c @@ -109,3 +109,18 @@ void batadv_free_rcu_tvlv_handler(struct rcu_head *rcu) }
#endif /* < KERNEL_VERSION(3, 0, 0) */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) + +int br_multicast_list_adjacent(struct net_device *dev, + struct list_head *br_ip_list) +{ + return 0; +} + +bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto) +{ + return true; +} + +#endif /* < KERNEL_VERSION(3, 16, 0) */ diff --git a/compat.h b/compat.h index 5eb5fe6..24a86cd 100644 --- a/compat.h +++ b/compat.h @@ -240,6 +240,12 @@ static inline void skb_reset_mac_len(struct sk_buff *skb)
#endif /* < KERNEL_VERSION(3, 0, 0) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) + +#define IS_ENABLED(x) defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#endif /* < KERNEL_VERSION(3, 1, 0) */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
#define batadv_interface_add_vid(x, y, z) \ @@ -438,4 +444,28 @@ static int __batadv_interface_kill_vid(struct net_device *dev, __be16 proto,\
#endif /* < KERNEL_VERSION(3, 14, 0) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) + +int br_multicast_list_adjacent(struct net_device *dev, + struct list_head *br_ip_list); +bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto); + +struct br_ip { + union { + __be32 ip4; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr ip6; +#endif + } u; + __be16 proto; + __u16 vid; +}; + +struct br_ip_list { + struct list_head list; + struct br_ip addr; +}; + +#endif /* < KERNEL_VERSION(3, 16, 0) */ + #endif /* _NET_BATMAN_ADV_COMPAT_H_ */ diff --git a/main.h b/main.h index 87e7196..d34dc5d 100644 --- a/main.h +++ b/main.h @@ -169,6 +169,7 @@ enum batadv_uev_type { #include <linux/netdevice.h> /* netdevice */ #include <linux/etherdevice.h> /* ethernet address classification */ #include <linux/if_ether.h> /* ethernet header */ +#include <linux/if_bridge.h> /* bridge / multicast-snooping communication */ #include <linux/poll.h> /* poll_table */ #include <linux/kthread.h> /* kernel threads */ #include <linux/pkt_sched.h> /* schedule types */ diff --git a/multicast.c b/multicast.c index 96b66fd..e4a8acd 100644 --- a/multicast.c +++ b/multicast.c @@ -23,6 +23,29 @@ #include "multicast.h"
/** + * batadv_mcast_get_bridge - get the bridge on top of the softif if it exists + * @soft_iface: netdev struct of the mesh interface + * + * Returns either a bridge interface on top of our soft interface or + * NULL if no such bridge exists. + */ +static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface) +{ + struct net_device *upper = soft_iface; + + rcu_read_lock(); + do { + upper = netdev_master_upper_dev_get_rcu(upper); + } while (upper && !(upper->priv_flags & IFF_EBRIDGE)); + + if (upper) + dev_hold(upper); + rcu_read_unlock(); + + return upper; +} + +/** * 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 @@ -30,17 +53,21 @@ * Collect multicast addresses of the local multicast listeners * on the given soft interface, dev, in the given mcast_list. * + * If there is a bridge interface on top of dev, collect from that one + * instead. + * * Returns -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 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(dev); + netif_addr_lock_bh(bridge ? bridge : dev); netdev_for_each_mc_addr(mc_list_entry, dev) { new = kmalloc(sizeof(*new), GFP_ATOMIC); if (!new) { @@ -52,7 +79,10 @@ static int batadv_mcast_mla_softif_get(struct net_device *dev, hlist_add_head(&new->list, mcast_list); ret++; } - netif_addr_unlock_bh(dev); + netif_addr_unlock_bh(bridge ? bridge : dev); + + if (bridge) + dev_put(bridge);
return ret; } @@ -78,6 +108,87 @@ static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr, }
/** + * batadv_mcast_mla_br_addr_cpy - copy a bridge multicast address + * @dst: destination to write to - a multicast MAC address + * @src: source to read from - a multicast IP address + * + * Converts a given multicast IPv4/IPv6 address from a bridge + * to its matching multicast MAC address and copies it into the given + * destination buffer. + * + * Caller needs to make sure the destination buffer can hold + * at least ETH_ALEN bytes. + */ +static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src) +{ + if (src->proto == htons(ETH_P_IP)) { + /* RFC 1112 */ + memcpy(dst, "\x01\x00\x5e", 3); + memcpy(dst + 3, ((char *)&src->u.ip4) + 1, ETH_ALEN - 3); + dst[3] &= 0x7F; + } +#if IS_ENABLED(CONFIG_IPV6) + else if (src->proto == htons(ETH_P_IPV6)) { + /* RFC 2464 */ + memcpy(dst, "\x33\x33", 2); + memcpy(dst + 2, &src->u.ip6.s6_addr32[3], + sizeof(src->u.ip6.s6_addr32[3])); + } +#endif + else + memset(dst, 0, ETH_ALEN); +} + +/** + * batadv_mcast_mla_bridge_get - get bridged-in multicast listeners + * @dev: a bridge slave whose bridge to collect multicast addresses from + * @mcast_list: a list to put found addresses into + * + * Collects multicast addresses of the bridged-in multicast listeners + * from the bridge on top of the given soft interface, dev, in the + * given mcast_list. + * + * Returns -ENOMEM on memory allocation error or the number of + * items added to the mcast_list otherwise. + */ +static int batadv_mcast_mla_bridge_get(struct net_device *dev, + struct hlist_head *mcast_list) +{ + struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list); + struct br_ip_list *br_ip_entry, *tmp; + struct batadv_hw_addr *new; + uint8_t mcast_addr[ETH_ALEN]; + int ret; + + ret = br_multicast_list_adjacent(dev, &bridge_mcast_list); + if (ret < 0) + goto out; + + list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) { + batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->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); + } + +out: + list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) { + list_del(&br_ip_entry->list); + kfree(br_ip_entry); + } + + return ret; +} + +/** * batadv_mcast_mla_list_free - free a list of multicast addresses * @mcast_list: the list to free * @@ -185,8 +296,8 @@ static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv) * Updates the own multicast tvlv with our current multicast related settings, * capabilities and inabilities. * - * Returns true if the tvlv container is registered afterwards. Otherwise - * returns false. + * Returns false if we want all IPv4 && IPv6 multicast traffic and true + * otherwise. */ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) { @@ -195,19 +306,18 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) mcast_data.flags = BATADV_NO_FLAGS; memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
- /* Avoid attaching MLAs, if there is a bridge on top of our soft - * interface, we don't support that yet (TODO) - */ - if (batadv_mcast_has_bridge(bat_priv)) { - if (bat_priv->mcast.enabled) { - batadv_tvlv_container_unregister(bat_priv, - BATADV_TVLV_MCAST, 1); - bat_priv->mcast.enabled = false; - } + if (!batadv_mcast_has_bridge(bat_priv)) + goto skip;
- return false; - } + mcast_data.flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES; + + if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IP)) + mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV4;
+ if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IPV6)) + mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV6; + +skip: if (!bat_priv->mcast.enabled || mcast_data.flags != bat_priv->mcast.flags) { batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1, @@ -216,7 +326,8 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) bat_priv->mcast.enabled = true; }
- return true; + return !(mcast_data.flags & + (BATADV_MCAST_WANT_ALL_IPV4 + BATADV_MCAST_WANT_ALL_IPV6)); }
/** @@ -233,13 +344,17 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv) int ret;
if (!batadv_mcast_mla_tvlv_update(bat_priv)) - goto update; + goto skip;
ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); if (ret < 0) goto out;
-update: + ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list); + if (ret < 0) + goto out; + +skip: batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
On Thursday 12 June 2014 02:00:27 Linus Lüssing wrote:
@@ -30,17 +53,21 @@
- Collect multicast addresses of the local multicast listeners
- on the given soft interface, dev, in the given mcast_list.
- If there is a bridge interface on top of dev, collect from that one
- instead.
*/
- Returns -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 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(dev);
- netif_addr_lock_bh(bridge ? bridge : dev); netdev_for_each_mc_addr(mc_list_entry, dev) { new = kmalloc(sizeof(*new), GFP_ATOMIC); if (!new) {
Maybe I am missing something but shouldn't we fetch the entries from the bridge interface instead of dev ?
/**
- batadv_mcast_mla_br_addr_cpy - copy a bridge multicast address
- @dst: destination to write to - a multicast MAC address
- @src: source to read from - a multicast IP address
- Converts a given multicast IPv4/IPv6 address from a bridge
- to its matching multicast MAC address and copies it into the given
- destination buffer.
- Caller needs to make sure the destination buffer can hold
- at least ETH_ALEN bytes.
- */
+static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src) +{
- if (src->proto == htons(ETH_P_IP)) {
/* RFC 1112 */
memcpy(dst, "\x01\x00\x5e", 3);
memcpy(dst + 3, ((char *)&src->u.ip4) + 1, ETH_ALEN - 3);
dst[3] &= 0x7F;
- }
+#if IS_ENABLED(CONFIG_IPV6)
- else if (src->proto == htons(ETH_P_IPV6)) {
/* RFC 2464 */
memcpy(dst, "\x33\x33", 2);
memcpy(dst + 2, &src->u.ip6.s6_addr32[3],
sizeof(src->u.ip6.s6_addr32[3]));
- }
+#endif
- else
memset(dst, 0, ETH_ALEN);
+}
Is there no cleaner way to do this ? "\x01\x00\x5e" and "\x33\x33" looks pretty hackish. Are there no defines for mcast prefixes somewhere ?
+/**
- batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
- @dev: a bridge slave whose bridge to collect multicast addresses from
- @mcast_list: a list to put found addresses into
- Collects multicast addresses of the bridged-in multicast listeners
- from the bridge on top of the given soft interface, dev, in the
- given mcast_list.
- Returns -ENOMEM on memory allocation error or the number of
- items added to the mcast_list otherwise.
- */
+static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct hlist_head *mcast_list)
+{
That is probably where my confusion is coming from. Why do we query the bridge interface again ?
@@ -195,19 +306,18 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) mcast_data.flags = BATADV_NO_FLAGS; memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
- /* Avoid attaching MLAs, if there is a bridge on top of our soft
* interface, we don't support that yet (TODO)
*/
- if (batadv_mcast_has_bridge(bat_priv)) {
if (bat_priv->mcast.enabled) {
batadv_tvlv_container_unregister(bat_priv,
BATADV_TVLV_MCAST, 1);
bat_priv->mcast.enabled = false;
}
- if (!batadv_mcast_has_bridge(bat_priv))
goto skip;
return false;
- }
mcast_data.flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IP))
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV4;
if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IPV6))
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV6;
+skip: if (!bat_priv->mcast.enabled || mcast_data.flags != bat_priv->mcast.flags) { batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
Please find a more intuitive goto label ('skip' is quite generic).
@@ -233,13 +344,17 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv) int ret;
if (!batadv_mcast_mla_tvlv_update(bat_priv))
goto update;
goto skip;
ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); if (ret < 0) goto out;
-update:
- ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list);
- if (ret < 0)
goto out;
+skip: batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
Again, 'skip' isn't very self-explanatory.
Cheers, Marek
On Tue, Jun 17, 2014 at 10:50:34PM +0800, Marek Lindner wrote:
On Thursday 12 June 2014 02:00:27 Linus Lüssing wrote:
- netif_addr_lock_bh(dev);
- netif_addr_lock_bh(bridge ? bridge : dev); netdev_for_each_mc_addr(mc_list_entry, dev) { new = kmalloc(sizeof(*new), GFP_ATOMIC); if (!new) {
Maybe I am missing something but shouldn't we fetch the entries from the bridge interface instead of dev ?
Ups, right, good catch! The 'netdev_for_each...' should be for "bridge", not "dev" if "bridge" exists.
+static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src) +{
- if (src->proto == htons(ETH_P_IP)) {
/* RFC 1112 */
memcpy(dst, "\x01\x00\x5e", 3);
memcpy(dst + 3, ((char *)&src->u.ip4) + 1, ETH_ALEN - 3);
dst[3] &= 0x7F;
- }
+#if IS_ENABLED(CONFIG_IPV6)
- else if (src->proto == htons(ETH_P_IPV6)) {
/* RFC 2464 */
memcpy(dst, "\x33\x33", 2);
memcpy(dst + 2, &src->u.ip6.s6_addr32[3],
sizeof(src->u.ip6.s6_addr32[3]));
- }
+#endif
- else
memset(dst, 0, ETH_ALEN);
+}
Is there no cleaner way to do this ? "\x01\x00\x5e" and "\x33\x33" looks pretty hackish. Are there no defines for mcast prefixes somewhere ?
Oh, indeed there is: The bridge code pointed me to "ip_eth_mc_map()" and "ipv6_eth_mc_map()", making that a one-liner each :).
+/**
- batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
- @dev: a bridge slave whose bridge to collect multicast addresses from
- @mcast_list: a list to put found addresses into
- Collects multicast addresses of the bridged-in multicast listeners
- from the bridge on top of the given soft interface, dev, in the
- given mcast_list.
- Returns -ENOMEM on memory allocation error or the number of
- items added to the mcast_list otherwise.
- */
+static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct hlist_head *mcast_list)
+{
That is probably where my confusion is coming from. Why do we query the bridge interface again ?
A batman-adv node needs to know on/behind which other batman-adv node a multicast listener exists to be able to know where it needs to forward multicast packets to. A multicast listener can either sit on bat0, on a bridge on top of bat0. Or in this case, that's what "mla_bridge_get" is for, behind the bridge.
We usually don't have direct access to the kernel of weird Windows machines behind a bridge. Luckily a protocol, Multicast Listener Discovery, exists to detect such multicast listeners.
The bridge code has multicast snooping already, so it already memorizes what multicast listeners it has behind it's bridge. That's what we are fetching here. To add these to our local TT to announce them through the mesh.
@@ -195,19 +306,18 @@ static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) mcast_data.flags = BATADV_NO_FLAGS; memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
- /* Avoid attaching MLAs, if there is a bridge on top of our soft
* interface, we don't support that yet (TODO)
*/
- if (batadv_mcast_has_bridge(bat_priv)) {
if (bat_priv->mcast.enabled) {
batadv_tvlv_container_unregister(bat_priv,
BATADV_TVLV_MCAST, 1);
bat_priv->mcast.enabled = false;
}
- if (!batadv_mcast_has_bridge(bat_priv))
goto skip;
return false;
- }
mcast_data.flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IP))
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV4;
if (br_multicast_has_querier_adjacent(bat_priv->soft_iface, ETH_P_IPV6))
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV6;
+skip: if (!bat_priv->mcast.enabled || mcast_data.flags != bat_priv->mcast.flags) { batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
Please find a more intuitive goto label ('skip' is quite generic).
Oki doki, good point.
@@ -233,13 +344,17 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv) int ret;
if (!batadv_mcast_mla_tvlv_update(bat_priv))
goto update;
goto skip;
ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); if (ret < 0) goto out;
-update:
- ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list);
- if (ret < 0)
goto out;
+skip: batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
Again, 'skip' isn't very self-explanatory.
K, right!
Cheers, Marek
Cheers, Linus
On Wednesday 18 June 2014 00:24:14 Linus Lüssing wrote:
A batman-adv node needs to know on/behind which other batman-adv node a multicast listener exists to be able to know where it needs to forward multicast packets to. A multicast listener can either sit on bat0, on a bridge on top of bat0. Or in this case, that's what "mla_bridge_get" is for, behind the bridge.
We usually don't have direct access to the kernel of weird Windows machines behind a bridge. Luckily a protocol, Multicast Listener Discovery, exists to detect such multicast listeners.
The bridge code has multicast snooping already, so it already memorizes what multicast listeners it has behind it's bridge. That's what we are fetching here. To add these to our local TT to announce them through the mesh.
Thanks for the clarifications but that does not address my question. To be more precise: In batadv_mcast_mla_update() your code is calling batadv_mcast_mla_softif_get() which queries the bridge interface (if bridged). A couple of lines later batadv_mcast_mla_bridge_get() is called (if bridged). It looks to me the code queries the bridge twice ?
Then, I am comparing the kernel doc to get the difference but I see none:
* 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 * * Collect multicast addresses of the local multicast listeners * on the given soft interface, dev, in the given mcast_list. * * If there is a bridge interface on top of dev, collect from that one * instead.
===============================================================
* batadv_mcast_mla_bridge_get - get bridged-in multicast listeners * @dev: a bridge slave whose bridge to collect multicast addresses from * @mcast_list: a list to put found addresses into * * Collects multicast addresses of the bridged-in multicast listeners * from the bridge on top of the given soft interface, dev, in the * given mcast_list.
What is the difference between these calls and why doesn't the code explain that difference ?
Cheers, Marek
On Wed, Jun 18, 2014 at 12:53:20PM +0800, Marek Lindner wrote:
Thanks for the clarifications but that does not address my question. To be more precise: In batadv_mcast_mla_update() your code is calling batadv_mcast_mla_softif_get() which queries the bridge interface (if bridged). A couple of lines later batadv_mcast_mla_bridge_get() is called (if bridged). It looks to me the code queries the bridge twice ?
Then, I am comparing the kernel doc to get the difference but I see none:
- 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
- Collect multicast addresses of the local multicast listeners
- on the given soft interface, dev, in the given mcast_list.
- If there is a bridge interface on top of dev, collect from that one
- instead.
===============================================================
- batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
- @dev: a bridge slave whose bridge to collect multicast addresses from
- @mcast_list: a list to put found addresses into
- Collects multicast addresses of the bridged-in multicast listeners
- from the bridge on top of the given soft interface, dev, in the
- given mcast_list.
What is the difference between these calls and why doesn't the code explain that difference ?
Okay, another try, now with pictures :) :
So far we are doing this:
https://metameute.de/~tux/batman-adv/multicast-listener-fetching-no-bridge.p...
So we are able to fetch local listeners (with "local" I mean listeners which are present on the same kernel) from bat0 via batadv_mcast_mla_softif_get(). And are announcing them in the mesh cloud so that multicast senders know which nodes they need to send their data to.
This box with the local listener could be an embedded router running batman-adv receiving music via multicast and playing it directly over its USB sound card.
---
With this patch batadv_mla_bridge_get() is being added:
https://metameute.de/~tux/batman-adv/multicast-listener-fetching-with-bridge...
Now we are able to detect bridged-in listeners (with "bridged-in" I mean listeners behind the bridge of a batman-adv node, some alien device). For instance this could be a non-Linux laptop wanting to receive the same or a different multicast music stream.
Also note, that in the bridge-case batadv_mcast_mla_softif_get() gets its local listener information from a different device now, marked in orange: Just like you wouldn't use IP addresses+routes on bat0 anymore but br0 instead, also the local multicast listeners will be registering to br0 instead of bat0 now. That's where the "bridge ? bridge : dev" code changes in this patch for batadv_mcast_mla_softif_get() come from.
---
tl;dr: batadv_mla_softif_get() is for multicast listeners *on* a batman-adv node, batadv_mla_bridge_get() for multicast listeners *behind* the bridge of a batman-adv node.
If the pictures are somehow helpful and if others feel this is worth a new wiki page in the batadv-multicast-docs, I can create one. (Also, I hope especially the second one isn't too overloaded, if someone has ideas how to simplify it, I'd be glad to hear about it.)
Cheers, Linus
On Friday 20 June 2014 17:57:12 Linus Lüssing wrote:
tl;dr: batadv_mla_softif_get() is for multicast listeners *on* a batman-adv node, batadv_mla_bridge_get() for multicast listeners *behind* the bridge of a batman-adv node.
Ok, I get it now. The diagrams certainly helped. Please highlight the difference between these functions in the kernel doc.
Thanks, Marek
On Wed, Jun 18, 2014 at 12:53:20PM +0800, Marek Lindner wrote:
Thanks for the clarifications but that does not address my question. To be more precise: In batadv_mcast_mla_update() your code is calling batadv_mcast_mla_softif_get() which queries the bridge interface (if bridged). A couple of lines later batadv_mcast_mla_bridge_get() is called (if bridged). It looks to me the code queries the bridge twice ?
Then, I am comparing the kernel doc to get the difference but I see none:
- 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
- Collect multicast addresses of the local multicast listeners
- on the given soft interface, dev, in the given mcast_list.
- If there is a bridge interface on top of dev, collect from that one
- instead.
===============================================================
- batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
- @dev: a bridge slave whose bridge to collect multicast addresses from
- @mcast_list: a list to put found addresses into
- Collects multicast addresses of the bridged-in multicast listeners
- from the bridge on top of the given soft interface, dev, in the
- given mcast_list.
What is the difference between these calls and why doesn't the code explain that difference ?
Okay, another try, now with pictures :) :
So far we are doing this:
https://metameute.de/~tux/batman-adv/multicast-listener-fetching-no-bridge. png
So we are able to fetch local listeners (with "local" I mean listeners which are present on the same kernel) from bat0 via batadv_mcast_mla_softif_get(). And are announcing them in the mesh cloud so that multicast senders know which nodes they need to send their data to.
This box with the local listener could be an embedded router running batman-adv receiving music via multicast and playing it directly over its USB sound card.
With this patch batadv_mla_bridge_get() is being added:
https://metameute.de/~tux/batman-adv/multicast-listener-fetching-with-bridg e.png
Now we are able to detect bridged-in listeners (with "bridged-in" I mean listeners behind the bridge of a batman-adv node, some alien device). For instance this could be a non-Linux laptop wanting to receive the same or a different multicast music stream.
Also note, that in the bridge-case batadv_mcast_mla_softif_get() gets its local listener information from a different device now, marked in orange: Just like you wouldn't use IP addresses+routes on bat0 anymore but br0 instead, also the local multicast listeners will be registering to br0 instead of bat0 now. That's where the "bridge ? bridge : dev" code changes in this patch for batadv_mcast_mla_softif_get() come from.
tl;dr: batadv_mla_softif_get() is for multicast listeners *on* a batman-adv node, batadv_mla_bridge_get() for multicast listeners *behind* the bridge of a batman-adv node.
If the pictures are somehow helpful and if others feel this is worth a new wiki page in the batadv-multicast-docs, I can create one. (Also, I hope especially the second one isn't too overloaded, if someone has ideas how to simplify it, I'd be glad to hear about it.)
Thanks for the pictures! I think it would be great to have them in the wiki in any case, so please add them (maybe as a subpage for now). :)
I'm still preparing to get this patch tested, I can't test it in my usual kvm/OpenWRT environment as it depends on the latest kernel ... but I'm preparing that now. :)
Cheers, Simon
b.a.t.m.a.n@lists.open-mesh.org