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:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-11 02:50:47 -0400
commitdc4eb53a996a78bfb8ea07b47423ff5a3aadc362 (patch)
treeb8e20e21f06afd05489ff5fba727c8c01717db70 /net/bridge/br_multicast.c
parent90010b36ebbedc6c3b7f09d384fecc5f18d77031 (diff)
bridge: adhere to querier election mechanism specified by RFCs
MLDv1 (RFC2710 section 6), MLDv2 (RFC3810 section 7.6.2), IGMPv2 (RFC2236 section 3) and IGMPv3 (RFC3376 section 6.6.2) specify that the querier with lowest source address shall become the selected querier. So far the bridge stopped its querier as soon as it heard another querier regardless of its source address. This results in the "wrong" querier potentially becoming the active querier or a potential, unnecessary querying delay. With this patch the bridge memorizes the source address of the currently selected querier and ignores queries from queriers with a higher source address than the currently selected one. This slight optimization is supposed to make it more RFC compliant (but is rather uncritical and therefore probably not necessary to be queued for stable kernels). 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.c101
1 files changed, 88 insertions, 13 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 5ccac62b4005..b3f17c9b4d06 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -789,6 +789,18 @@ static void br_ip6_multicast_querier_expired(unsigned long data)
789} 789}
790#endif 790#endif
791 791
792static void br_multicast_select_own_querier(struct net_bridge *br,
793 struct br_ip *ip,
794 struct sk_buff *skb)
795{
796 if (ip->proto == htons(ETH_P_IP))
797 br->ip4_querier.addr.u.ip4 = ip_hdr(skb)->saddr;
798#if IS_ENABLED(CONFIG_IPV6)
799 else
800 br->ip6_querier.addr.u.ip6 = ipv6_hdr(skb)->saddr;
801#endif
802}
803
792static void __br_multicast_send_query(struct net_bridge *br, 804static void __br_multicast_send_query(struct net_bridge *br,
793 struct net_bridge_port *port, 805 struct net_bridge_port *port,
794 struct br_ip *ip) 806 struct br_ip *ip)
@@ -804,8 +816,10 @@ static void __br_multicast_send_query(struct net_bridge *br,
804 skb->dev = port->dev; 816 skb->dev = port->dev;
805 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, 817 NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
806 dev_queue_xmit); 818 dev_queue_xmit);
807 } else 819 } else {
820 br_multicast_select_own_querier(br, ip, skb);
808 netif_rx(skb); 821 netif_rx(skb);
822 }
809} 823}
810 824
811static void br_multicast_send_query(struct net_bridge *br, 825static void br_multicast_send_query(struct net_bridge *br,
@@ -1065,6 +1079,62 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
1065} 1079}
1066#endif 1080#endif
1067 1081
1082static bool br_ip4_multicast_select_querier(struct net_bridge *br,
1083 __be32 saddr)
1084{
1085 if (!timer_pending(&br->ip4_own_query.timer) &&
1086 !timer_pending(&br->ip4_other_query.timer))
1087 goto update;
1088
1089 if (!br->ip4_querier.addr.u.ip4)
1090 goto update;
1091
1092 if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.u.ip4))
1093 goto update;
1094
1095 return false;
1096
1097update:
1098 br->ip4_querier.addr.u.ip4 = saddr;
1099
1100 return true;
1101}
1102
1103#if IS_ENABLED(CONFIG_IPV6)
1104static bool br_ip6_multicast_select_querier(struct net_bridge *br,
1105 struct in6_addr *saddr)
1106{
1107 if (!timer_pending(&br->ip6_own_query.timer) &&
1108 !timer_pending(&br->ip6_other_query.timer))
1109 goto update;
1110
1111 if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.u.ip6) <= 0)
1112 goto update;
1113
1114 return false;
1115
1116update:
1117 br->ip6_querier.addr.u.ip6 = *saddr;
1118
1119 return true;
1120}
1121#endif
1122
1123static bool br_multicast_select_querier(struct net_bridge *br,
1124 struct br_ip *saddr)
1125{
1126 switch (saddr->proto) {
1127 case htons(ETH_P_IP):
1128 return br_ip4_multicast_select_querier(br, saddr->u.ip4);
1129#if IS_ENABLED(CONFIG_IPV6)
1130 case htons(ETH_P_IPV6):
1131 return br_ip6_multicast_select_querier(br, &saddr->u.ip6);
1132#endif
1133 }
1134
1135 return false;
1136}
1137
1068static void 1138static void
1069br_multicast_update_query_timer(struct net_bridge *br, 1139br_multicast_update_query_timer(struct net_bridge *br,
1070 struct bridge_mcast_other_query *query, 1140 struct bridge_mcast_other_query *query,
@@ -1127,15 +1197,13 @@ timer:
1127static void br_multicast_query_received(struct net_bridge *br, 1197static void br_multicast_query_received(struct net_bridge *br,
1128 struct net_bridge_port *port, 1198 struct net_bridge_port *port,
1129 struct bridge_mcast_other_query *query, 1199 struct bridge_mcast_other_query *query,
1130 int saddr, 1200 struct br_ip *saddr,
1131 bool is_general_query,
1132 unsigned long max_delay) 1201 unsigned long max_delay)
1133{ 1202{
1134 if (saddr && is_general_query) 1203 if (!br_multicast_select_querier(br, saddr))
1135 br_multicast_update_query_timer(br, query, max_delay);
1136 else if (timer_pending(&query->timer))
1137 return; 1204 return;
1138 1205
1206 br_multicast_update_query_timer(br, query, max_delay);
1139 br_multicast_mark_router(br, port); 1207 br_multicast_mark_router(br, port);
1140} 1208}
1141 1209
@@ -1150,6 +1218,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1150 struct igmpv3_query *ih3; 1218 struct igmpv3_query *ih3;
1151 struct net_bridge_port_group *p; 1219 struct net_bridge_port_group *p;
1152 struct net_bridge_port_group __rcu **pp; 1220 struct net_bridge_port_group __rcu **pp;
1221 struct br_ip saddr;
1153 unsigned long max_delay; 1222 unsigned long max_delay;
1154 unsigned long now = jiffies; 1223 unsigned long now = jiffies;
1155 __be32 group; 1224 __be32 group;
@@ -1191,11 +1260,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1191 goto out; 1260 goto out;
1192 } 1261 }
1193 1262
1194 br_multicast_query_received(br, port, &br->ip4_other_query, 1263 if (!group) {
1195 !!iph->saddr, !group, max_delay); 1264 saddr.proto = htons(ETH_P_IP);
1265 saddr.u.ip4 = iph->saddr;
1196 1266
1197 if (!group) 1267 br_multicast_query_received(br, port, &br->ip4_other_query,
1268 &saddr, max_delay);
1198 goto out; 1269 goto out;
1270 }
1199 1271
1200 mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group, vid); 1272 mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group, vid);
1201 if (!mp) 1273 if (!mp)
@@ -1235,6 +1307,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1235 struct mld2_query *mld2q; 1307 struct mld2_query *mld2q;
1236 struct net_bridge_port_group *p; 1308 struct net_bridge_port_group *p;
1237 struct net_bridge_port_group __rcu **pp; 1309 struct net_bridge_port_group __rcu **pp;
1310 struct br_ip saddr;
1238 unsigned long max_delay; 1311 unsigned long max_delay;
1239 unsigned long now = jiffies; 1312 unsigned long now = jiffies;
1240 const struct in6_addr *group = NULL; 1313 const struct in6_addr *group = NULL;
@@ -1283,12 +1356,14 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1283 goto out; 1356 goto out;
1284 } 1357 }
1285 1358
1286 br_multicast_query_received(br, port, &br->ip6_other_query, 1359 if (is_general_query) {
1287 !ipv6_addr_any(&ip6h->saddr), 1360 saddr.proto = htons(ETH_P_IPV6);
1288 is_general_query, max_delay); 1361 saddr.u.ip6 = ip6h->saddr;
1289 1362
1290 if (!group) 1363 br_multicast_query_received(br, port, &br->ip6_other_query,
1364 &saddr, max_delay);
1291 goto out; 1365 goto out;
1366 }
1292 1367
1293 mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid); 1368 mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid);
1294 if (!mp) 1369 if (!mp)