Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Linus Lüssing and committed by
David S. Miller
4effd28c a2e2ca3b

+78 -5
+5 -4
include/uapi/linux/in.h
··· 292 292 #define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) 293 293 294 294 /* 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 */ 299 300 #endif 300 301 301 302 /* <asm/byteorder.h> contains the htonl type stuff.. */
+71 -1
net/bridge/br_multicast.c
··· 1780 1780 INIT_HLIST_HEAD(&br->mdb_list); 1781 1781 } 1782 1782 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 + 1783 1845 static void __br_multicast_open(struct net_bridge *br, 1784 1846 struct bridge_mcast_own_query *query) 1785 1847 { ··· 1855 1793 1856 1794 void br_multicast_open(struct net_bridge *br) 1857 1795 { 1796 + if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) 1797 + br_multicast_join_snoopers(br); 1798 + 1858 1799 __br_multicast_open(br, &br->ip4_own_query); 1859 1800 #if IS_ENABLED(CONFIG_IPV6) 1860 1801 __br_multicast_open(br, &br->ip6_own_query); ··· 1873 1808 del_timer_sync(&br->ip6_other_query.timer); 1874 1809 del_timer_sync(&br->ip6_own_query.timer); 1875 1810 #endif 1811 + 1812 + if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) 1813 + br_multicast_leave_snoopers(br); 1876 1814 } 1877 1815 1878 1816 void br_multicast_dev_del(struct net_bridge *br) ··· 2011 1943 2012 1944 br_mc_disabled_update(br->dev, val); 2013 1945 br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val); 2014 - if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) 1946 + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) { 1947 + br_multicast_leave_snoopers(br); 2015 1948 goto unlock; 1949 + } 2016 1950 2017 1951 if (!netif_running(br->dev)) 2018 1952 goto unlock;
+2
net/ipv6/mcast.c
··· 940 940 { 941 941 return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE); 942 942 } 943 + EXPORT_SYMBOL(ipv6_dev_mc_inc); 943 944 944 945 /* 945 946 * device multicast group del ··· 988 987 989 988 return err; 990 989 } 990 + EXPORT_SYMBOL(ipv6_dev_mc_dec); 991 991 992 992 /* 993 993 * check if the interface/address pair is valid