mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	bridge: join all-snoopers multicast address
Next to snooping IGMP/MLD queries RFC4541, section 2.1.1.a) recommends to snoop multicast router advertisements to detect multicast routers. Multicast router advertisements are sent to an "all-snoopers" multicast address. To be able to receive them reliably, we need to join this group. Otherwise other snooping switches might refrain from forwarding these advertisements to us. Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									a2e2ca3beb
								
							
						
					
					
						commit
						4effd28c12
					
				
					 3 changed files with 78 additions and 5 deletions
				
			
		| 
						 | 
					@ -292,10 +292,11 @@ struct sockaddr_in {
 | 
				
			||||||
#define	IN_LOOPBACK(a)		((((long int) (a)) & 0xff000000) == 0x7f000000)
 | 
					#define	IN_LOOPBACK(a)		((((long int) (a)) & 0xff000000) == 0x7f000000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Defines for Multicast INADDR */
 | 
					/* Defines for Multicast INADDR */
 | 
				
			||||||
#define INADDR_UNSPEC_GROUP   	0xe0000000U	/* 224.0.0.0   */
 | 
					#define INADDR_UNSPEC_GROUP		0xe0000000U	/* 224.0.0.0   */
 | 
				
			||||||
#define INADDR_ALLHOSTS_GROUP 	0xe0000001U	/* 224.0.0.1   */
 | 
					#define INADDR_ALLHOSTS_GROUP		0xe0000001U	/* 224.0.0.1   */
 | 
				
			||||||
#define INADDR_ALLRTRS_GROUP    0xe0000002U	/* 224.0.0.2 */
 | 
					#define INADDR_ALLRTRS_GROUP		0xe0000002U	/* 224.0.0.2 */
 | 
				
			||||||
#define INADDR_MAX_LOCAL_GROUP  0xe00000ffU	/* 224.0.0.255 */
 | 
					#define INADDR_ALLSNOOPERS_GROUP	0xe000006aU	/* 224.0.0.106 */
 | 
				
			||||||
 | 
					#define INADDR_MAX_LOCAL_GROUP		0xe00000ffU	/* 224.0.0.255 */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
 | 
					/* <asm/byteorder.h> contains the htonl type stuff.. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1780,6 +1780,68 @@ void br_multicast_init(struct net_bridge *br)
 | 
				
			||||||
	INIT_HLIST_HEAD(&br->mdb_list);
 | 
						INIT_HLIST_HEAD(&br->mdb_list);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in_device *in_dev = in_dev_get(br->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!in_dev)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
 | 
				
			||||||
 | 
						in_dev_put(in_dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
 | 
					static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in6_addr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
 | 
				
			||||||
 | 
						ipv6_dev_mc_inc(br->dev, &addr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void br_multicast_join_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						br_ip4_multicast_join_snoopers(br);
 | 
				
			||||||
 | 
						br_ip6_multicast_join_snoopers(br);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in_device *in_dev = in_dev_get(br->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(!in_dev))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
 | 
				
			||||||
 | 
						in_dev_put(in_dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
 | 
					static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in6_addr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
 | 
				
			||||||
 | 
						ipv6_dev_mc_dec(br->dev, &addr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void br_multicast_leave_snoopers(struct net_bridge *br)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						br_ip4_multicast_leave_snoopers(br);
 | 
				
			||||||
 | 
						br_ip6_multicast_leave_snoopers(br);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __br_multicast_open(struct net_bridge *br,
 | 
					static void __br_multicast_open(struct net_bridge *br,
 | 
				
			||||||
				struct bridge_mcast_own_query *query)
 | 
									struct bridge_mcast_own_query *query)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1793,6 +1855,9 @@ static void __br_multicast_open(struct net_bridge *br,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void br_multicast_open(struct net_bridge *br)
 | 
					void br_multicast_open(struct net_bridge *br)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
 | 
				
			||||||
 | 
							br_multicast_join_snoopers(br);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__br_multicast_open(br, &br->ip4_own_query);
 | 
						__br_multicast_open(br, &br->ip4_own_query);
 | 
				
			||||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
	__br_multicast_open(br, &br->ip6_own_query);
 | 
						__br_multicast_open(br, &br->ip6_own_query);
 | 
				
			||||||
| 
						 | 
					@ -1808,6 +1873,9 @@ void br_multicast_stop(struct net_bridge *br)
 | 
				
			||||||
	del_timer_sync(&br->ip6_other_query.timer);
 | 
						del_timer_sync(&br->ip6_other_query.timer);
 | 
				
			||||||
	del_timer_sync(&br->ip6_own_query.timer);
 | 
						del_timer_sync(&br->ip6_own_query.timer);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
 | 
				
			||||||
 | 
							br_multicast_leave_snoopers(br);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void br_multicast_dev_del(struct net_bridge *br)
 | 
					void br_multicast_dev_del(struct net_bridge *br)
 | 
				
			||||||
| 
						 | 
					@ -1943,8 +2011,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	br_mc_disabled_update(br->dev, val);
 | 
						br_mc_disabled_update(br->dev, val);
 | 
				
			||||||
	br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
 | 
						br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
 | 
				
			||||||
	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
 | 
						if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
 | 
				
			||||||
 | 
							br_multicast_leave_snoopers(br);
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!netif_running(br->dev))
 | 
						if (!netif_running(br->dev))
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -940,6 +940,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE);
 | 
						return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ipv6_dev_mc_inc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	device multicast group del
 | 
					 *	device multicast group del
 | 
				
			||||||
| 
						 | 
					@ -987,6 +988,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ipv6_dev_mc_dec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	check if the interface/address pair is valid
 | 
					 *	check if the interface/address pair is valid
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue