Skip to content

Commit 4effd28

Browse files
T-Xdavem330
authored andcommitted
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>
1 parent a2e2ca3 commit 4effd28

File tree

3 files changed

+78
-5
lines changed

3 files changed

+78
-5
lines changed

include/uapi/linux/in.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,11 @@ struct sockaddr_in {
292292
#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
293293

294294
/* Defines for Multicast INADDR */
295-
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
296-
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
297-
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
298-
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
295+
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
296+
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
297+
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
298+
#define INADDR_ALLSNOOPERS_GROUP 0xe000006aU /* 224.0.0.106 */
299+
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
299300
#endif
300301

301302
/* <asm/byteorder.h> contains the htonl type stuff.. */

net/bridge/br_multicast.c

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,68 @@ void br_multicast_init(struct net_bridge *br)
17801780
INIT_HLIST_HEAD(&br->mdb_list);
17811781
}
17821782

1783+
static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
1784+
{
1785+
struct in_device *in_dev = in_dev_get(br->dev);
1786+
1787+
if (!in_dev)
1788+
return;
1789+
1790+
ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
1791+
in_dev_put(in_dev);
1792+
}
1793+
1794+
#if IS_ENABLED(CONFIG_IPV6)
1795+
static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
1796+
{
1797+
struct in6_addr addr;
1798+
1799+
ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
1800+
ipv6_dev_mc_inc(br->dev, &addr);
1801+
}
1802+
#else
1803+
static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
1804+
{
1805+
}
1806+
#endif
1807+
1808+
static void br_multicast_join_snoopers(struct net_bridge *br)
1809+
{
1810+
br_ip4_multicast_join_snoopers(br);
1811+
br_ip6_multicast_join_snoopers(br);
1812+
}
1813+
1814+
static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
1815+
{
1816+
struct in_device *in_dev = in_dev_get(br->dev);
1817+
1818+
if (WARN_ON(!in_dev))
1819+
return;
1820+
1821+
ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
1822+
in_dev_put(in_dev);
1823+
}
1824+
1825+
#if IS_ENABLED(CONFIG_IPV6)
1826+
static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
1827+
{
1828+
struct in6_addr addr;
1829+
1830+
ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
1831+
ipv6_dev_mc_dec(br->dev, &addr);
1832+
}
1833+
#else
1834+
static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
1835+
{
1836+
}
1837+
#endif
1838+
1839+
static void br_multicast_leave_snoopers(struct net_bridge *br)
1840+
{
1841+
br_ip4_multicast_leave_snoopers(br);
1842+
br_ip6_multicast_leave_snoopers(br);
1843+
}
1844+
17831845
static void __br_multicast_open(struct net_bridge *br,
17841846
struct bridge_mcast_own_query *query)
17851847
{
@@ -1793,6 +1855,9 @@ static void __br_multicast_open(struct net_bridge *br,
17931855

17941856
void br_multicast_open(struct net_bridge *br)
17951857
{
1858+
if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
1859+
br_multicast_join_snoopers(br);
1860+
17961861
__br_multicast_open(br, &br->ip4_own_query);
17971862
#if IS_ENABLED(CONFIG_IPV6)
17981863
__br_multicast_open(br, &br->ip6_own_query);
@@ -1808,6 +1873,9 @@ void br_multicast_stop(struct net_bridge *br)
18081873
del_timer_sync(&br->ip6_other_query.timer);
18091874
del_timer_sync(&br->ip6_own_query.timer);
18101875
#endif
1876+
1877+
if (br_opt_get(br, BROPT_MULTICAST_ENABLED))
1878+
br_multicast_leave_snoopers(br);
18111879
}
18121880

18131881
void br_multicast_dev_del(struct net_bridge *br)
@@ -1943,8 +2011,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
19432011

19442012
br_mc_disabled_update(br->dev, val);
19452013
br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
1946-
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
2014+
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
2015+
br_multicast_leave_snoopers(br);
19472016
goto unlock;
2017+
}
19482018

19492019
if (!netif_running(br->dev))
19502020
goto unlock;

net/ipv6/mcast.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
940940
{
941941
return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE);
942942
}
943+
EXPORT_SYMBOL(ipv6_dev_mc_inc);
943944

944945
/*
945946
* device multicast group del
@@ -987,6 +988,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
987988

988989
return err;
989990
}
991+
EXPORT_SYMBOL(ipv6_dev_mc_dec);
990992

991993
/*
992994
* check if the interface/address pair is valid

0 commit comments

Comments
 (0)