aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_multicast.c
diff options
context:
space:
mode:
authorLinus Lüssing <linus.luessing@web.de>2014-06-07 12:26:29 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-11 02:50:47 -0400
commit2cd4143192e8c60f66cb32c3a30c76d0470a372d (patch)
treee9690ec1d858835250edaa4cb5943bdd8e04d19e /net/bridge/br_multicast.c
parent07f8ac4a1e26e8283542cdaf658a6e2a12fd6980 (diff)
bridge: memorize and export selected IGMP/MLD querier port
Adding bridge support to the batman-adv multicast optimization requires batman-adv knowing about the existence of bridged-in IGMP/MLD queriers to be able to reliably serve any multicast listener behind this same bridge. Signed-off-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r--net/bridge/br_multicast.c72
1 files changed, 66 insertions, 6 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 772476b7c4b7..cd3cf394c477 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1081,6 +1081,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
1081#endif 1081#endif
1082 1082
1083static bool br_ip4_multicast_select_querier(struct net_bridge *br, 1083static bool br_ip4_multicast_select_querier(struct net_bridge *br,
1084 struct net_bridge_port *port,
1084 __be32 saddr) 1085 __be32 saddr)
1085{ 1086{
1086 if (!timer_pending(&br->ip4_own_query.timer) && 1087 if (!timer_pending(&br->ip4_own_query.timer) &&
@@ -1098,11 +1099,15 @@ static bool br_ip4_multicast_select_querier(struct net_bridge *br,
1098update: 1099update:
1099 br->ip4_querier.addr.u.ip4 = saddr; 1100 br->ip4_querier.addr.u.ip4 = saddr;
1100 1101
1102 /* update protected by general multicast_lock by caller */
1103 rcu_assign_pointer(br->ip4_querier.port, port);
1104
1101 return true; 1105 return true;
1102} 1106}
1103 1107
1104#if IS_ENABLED(CONFIG_IPV6) 1108#if IS_ENABLED(CONFIG_IPV6)
1105static bool br_ip6_multicast_select_querier(struct net_bridge *br, 1109static bool br_ip6_multicast_select_querier(struct net_bridge *br,
1110 struct net_bridge_port *port,
1106 struct in6_addr *saddr) 1111 struct in6_addr *saddr)
1107{ 1112{
1108 if (!timer_pending(&br->ip6_own_query.timer) && 1113 if (!timer_pending(&br->ip6_own_query.timer) &&
@@ -1117,19 +1122,23 @@ static bool br_ip6_multicast_select_querier(struct net_bridge *br,
1117update: 1122update:
1118 br->ip6_querier.addr.u.ip6 = *saddr; 1123 br->ip6_querier.addr.u.ip6 = *saddr;
1119 1124
1125 /* update protected by general multicast_lock by caller */
1126 rcu_assign_pointer(br->ip6_querier.port, port);
1127
1120 return true; 1128 return true;
1121} 1129}
1122#endif 1130#endif
1123 1131
1124static bool br_multicast_select_querier(struct net_bridge *br, 1132static bool br_multicast_select_querier(struct net_bridge *br,
1133 struct net_bridge_port *port,
1125 struct br_ip *saddr) 1134 struct br_ip *saddr)
1126{ 1135{
1127 switch (saddr->proto) { 1136 switch (saddr->proto) {
1128 case htons(ETH_P_IP): 1137 case htons(ETH_P_IP):
1129 return br_ip4_multicast_select_querier(br, saddr->u.ip4); 1138 return br_ip4_multicast_select_querier(br, port, saddr->u.ip4);
1130#if IS_ENABLED(CONFIG_IPV6) 1139#if IS_ENABLED(CONFIG_IPV6)
1131 case htons(ETH_P_IPV6): 1140 case htons(ETH_P_IPV6):
1132 return br_ip6_multicast_select_querier(br, &saddr->u.ip6); 1141 return br_ip6_multicast_select_querier(br, port, &saddr->u.ip6);
1133#endif 1142#endif
1134 } 1143 }
1135 1144
@@ -1201,7 +1210,7 @@ static void br_multicast_query_received(struct net_bridge *br,
1201 struct br_ip *saddr, 1210 struct br_ip *saddr,
1202 unsigned long max_delay) 1211 unsigned long max_delay)
1203{ 1212{
1204 if (!br_multicast_select_querier(br, saddr)) 1213 if (!br_multicast_select_querier(br, port, saddr))
1205 return; 1214 return;
1206 1215
1207 br_multicast_update_query_timer(br, query, max_delay); 1216 br_multicast_update_query_timer(br, query, max_delay);
@@ -1804,12 +1813,14 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
1804} 1813}
1805 1814
1806static void br_multicast_query_expired(struct net_bridge *br, 1815static void br_multicast_query_expired(struct net_bridge *br,
1807 struct bridge_mcast_own_query *query) 1816 struct bridge_mcast_own_query *query,
1817 struct bridge_mcast_querier *querier)
1808{ 1818{
1809 spin_lock(&br->multicast_lock); 1819 spin_lock(&br->multicast_lock);
1810 if (query->startup_sent < br->multicast_startup_query_count) 1820 if (query->startup_sent < br->multicast_startup_query_count)
1811 query->startup_sent++; 1821 query->startup_sent++;
1812 1822
1823 rcu_assign_pointer(querier, NULL);
1813 br_multicast_send_query(br, NULL, query); 1824 br_multicast_send_query(br, NULL, query);
1814 spin_unlock(&br->multicast_lock); 1825 spin_unlock(&br->multicast_lock);
1815} 1826}
@@ -1818,7 +1829,7 @@ static void br_ip4_multicast_query_expired(unsigned long data)
1818{ 1829{
1819 struct net_bridge *br = (void *)data; 1830 struct net_bridge *br = (void *)data;
1820 1831
1821 br_multicast_query_expired(br, &br->ip4_own_query); 1832 br_multicast_query_expired(br, &br->ip4_own_query, &br->ip4_querier);
1822} 1833}
1823 1834
1824#if IS_ENABLED(CONFIG_IPV6) 1835#if IS_ENABLED(CONFIG_IPV6)
@@ -1826,7 +1837,7 @@ static void br_ip6_multicast_query_expired(unsigned long data)
1826{ 1837{
1827 struct net_bridge *br = (void *)data; 1838 struct net_bridge *br = (void *)data;
1828 1839
1829 br_multicast_query_expired(br, &br->ip6_own_query); 1840 br_multicast_query_expired(br, &br->ip6_own_query, &br->ip6_querier);
1830} 1841}
1831#endif 1842#endif
1832 1843
@@ -1849,8 +1860,10 @@ void br_multicast_init(struct net_bridge *br)
1849 br->multicast_membership_interval = 260 * HZ; 1860 br->multicast_membership_interval = 260 * HZ;
1850 1861
1851 br->ip4_other_query.delay_time = 0; 1862 br->ip4_other_query.delay_time = 0;
1863 br->ip4_querier.port = NULL;
1852#if IS_ENABLED(CONFIG_IPV6) 1864#if IS_ENABLED(CONFIG_IPV6)
1853 br->ip6_other_query.delay_time = 0; 1865 br->ip6_other_query.delay_time = 0;
1866 br->ip6_querier.port = NULL;
1854#endif 1867#endif
1855 1868
1856 spin_lock_init(&br->multicast_lock); 1869 spin_lock_init(&br->multicast_lock);
@@ -2199,3 +2212,50 @@ unlock:
2199 return count; 2212 return count;
2200} 2213}
2201EXPORT_SYMBOL_GPL(br_multicast_list_adjacent); 2214EXPORT_SYMBOL_GPL(br_multicast_list_adjacent);
2215
2216/**
2217 * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port
2218 * @dev: The bridge port adjacent to which to check for a querier
2219 * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6
2220 *
2221 * Checks whether the given interface has a bridge on top and if so returns
2222 * true if a selected querier is behind one of the other ports of this
2223 * bridge. Otherwise returns false.
2224 */
2225bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
2226{
2227 struct net_bridge *br;
2228 struct net_bridge_port *port;
2229 bool ret = false;
2230
2231 rcu_read_lock();
2232 if (!br_port_exists(dev))
2233 goto unlock;
2234
2235 port = br_port_get_rcu(dev);
2236 if (!port || !port->br)
2237 goto unlock;
2238
2239 br = port->br;
2240
2241 switch (proto) {
2242 case ETH_P_IP:
2243 if (!timer_pending(&br->ip4_other_query.timer) ||
2244 rcu_dereference(br->ip4_querier.port) == port)
2245 goto unlock;
2246 break;
2247 case ETH_P_IPV6:
2248 if (!timer_pending(&br->ip6_other_query.timer) ||
2249 rcu_dereference(br->ip6_querier.port) == port)
2250 goto unlock;
2251 break;
2252 default:
2253 goto unlock;
2254 }
2255
2256 ret = true;
2257unlock:
2258 rcu_read_unlock();
2259 return ret;
2260}
2261EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);