[LEDE-DEV] [PATCH] Bridge: Fix ipv6 mc snooping if bridge has no ipv6 address

John Crispin john at phrozen.org
Thu Jun 30 12:33:53 PDT 2016


On 30/06/2016 17:05, Daniel Danzberger wrote:
> This patch is a backport for current LEDE 4.4 Kernels.
> It is already upstream, for linux-next and stable.
> The initial commit message is below:
> 
> The bridge is falsly dropping ipv6 mulitcast packets if there is:
>  1. No ipv6 address assigned on the brigde.
>  2. No external mld querier present.
>  3. The internal querier enabled.
> 
> When the bridge fails to build mld queries, because it has no
> ipv6 address, it slilently returns, but keeps the local querier enabled.
> This specific case causes confusing packet loss.
> 
> Ipv6 multicast snooping can only work if:
>  a) An external querier is present
>  OR
>  b) The bridge has an ipv6 address an is capable of sending own queries
> 
> Otherwise it has to forward/flood the ipv6 multicast traffic,
> because snooping cannot work.
> 
> This patch fixes the issue by adding a flag to the bridge struct that
> indicates that there is currently no ipv6 address assinged to the bridge
> and returns a false state for the local querier in
> __br_multicast_querier_exists().
> 
> Special thanks to Linus Lüssing.
> 
> Signed-off-by: Daniel Danzberger <daniel at dd-wrt.com>


Hi Daniel,

can you please use the full annotated upstream patch ? it would be best
if 646-bridge_fix_ipv6_mc_snooping_if_bridge_has_no_ipv6_address.patch
contained the original description and SoB line
	John


> ---
>  ...mc_snooping_if_bridge_has_no_ipv6_address.patch | 76 ++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
>  create mode 100644 target/linux/generic/patches-4.4/646-bridge_fix_ipv6_mc_snooping_if_bridge_has_no_ipv6_address.patch
> 
> diff --git a/target/linux/generic/patches-4.4/646-bridge_fix_ipv6_mc_snooping_if_bridge_has_no_ipv6_address.patch b/target/linux/generic/patches-4.4/646-bridge_fix_ipv6_mc_snooping_if_bridge_has_no_ipv6_address.patch
> new file mode 100644
> index 0000000..e0bdbae
> --- /dev/null
> +++ b/target/linux/generic/patches-4.4/646-bridge_fix_ipv6_mc_snooping_if_bridge_has_no_ipv6_address.patch
> @@ -0,0 +1,76 @@
> +diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
> +index c8c2a8a..d063a10 100644
> +--- a/net/bridge/br_multicast.c
> ++++ b/net/bridge/br_multicast.c
> +@@ -465,8 +465,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
> + 	if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
> + 			       &ip6h->saddr)) {
> + 		kfree_skb(skb);
> ++		br->has_ipv6_addr = 0;
> + 		return NULL;
> + 	}
> ++
> ++	br->has_ipv6_addr = 1;
> + 	ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
> + 
> + 	hopopt = (u8 *)(ip6h + 1);
> +@@ -1768,6 +1771,7 @@ void br_multicast_init(struct net_bridge *br)
> + 	br->ip6_other_query.delay_time = 0;
> + 	br->ip6_querier.port = NULL;
> + #endif
> ++	br->has_ipv6_addr = 1;
> + 
> + 	spin_lock_init(&br->multicast_lock);
> + 	setup_timer(&br->multicast_router_timer,
> +diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> +index e24abfd..3dd7e2c 100644
> +--- a/net/bridge/br_private.h
> ++++ b/net/bridge/br_private.h
> +@@ -303,6 +303,7 @@ struct net_bridge
> + 	u8				multicast_disabled:1;
> + 	u8				multicast_querier:1;
> + 	u8				multicast_query_use_ifaddr:1;
> ++	u8				has_ipv6_addr:1;
> + 
> + 	u32				hash_elasticity;
> + 	u32				hash_max;
> +@@ -577,10 +578,22 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
> + 
> + static inline bool
> + __br_multicast_querier_exists(struct net_bridge *br,
> +-			      struct bridge_mcast_other_query *querier)
> ++				struct bridge_mcast_other_query *querier,
> ++				const bool is_ipv6)
> + {
> ++	bool own_querier_enabled;
> ++
> ++	if (br->multicast_querier) {
> ++		if (is_ipv6 && !br->has_ipv6_addr)
> ++			own_querier_enabled = false;
> ++		else
> ++			own_querier_enabled = true;
> ++	} else {
> ++		own_querier_enabled = false;
> ++	}
> ++
> + 	return time_is_before_jiffies(querier->delay_time) &&
> +-	       (br->multicast_querier || timer_pending(&querier->timer));
> ++	       (own_querier_enabled || timer_pending(&querier->timer));
> + }
> + 
> + static inline bool br_multicast_querier_exists(struct net_bridge *br,
> +@@ -588,10 +601,12 @@ static inline bool br_multicast_querier_exists(struct net_bridge *br,
> + {
> + 	switch (eth->h_proto) {
> + 	case (htons(ETH_P_IP)):
> +-		return __br_multicast_querier_exists(br, &br->ip4_other_query);
> ++		return __br_multicast_querier_exists(br,
> ++			&br->ip4_other_query, false);
> + #if IS_ENABLED(CONFIG_IPV6)
> + 	case (htons(ETH_P_IPV6)):
> +-		return __br_multicast_querier_exists(br, &br->ip6_other_query);
> ++		return __br_multicast_querier_exists(br,
> ++			&br->ip6_other_query, true);
> + #endif
> + 	default:
> + 		return false;
> 



More information about the Lede-dev mailing list