diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_multicast.c | 101 | ||||
-rw-r--r-- | net/bridge/br_private.h | 7 |
2 files changed, 95 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 | ||
792 | static 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 | |||
792 | static void __br_multicast_send_query(struct net_bridge *br, | 804 | static 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 | ||
811 | static void br_multicast_send_query(struct net_bridge *br, | 825 | static 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 | ||
1082 | static 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 | |||
1097 | update: | ||
1098 | br->ip4_querier.addr.u.ip4 = saddr; | ||
1099 | |||
1100 | return true; | ||
1101 | } | ||
1102 | |||
1103 | #if IS_ENABLED(CONFIG_IPV6) | ||
1104 | static 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 | |||
1116 | update: | ||
1117 | br->ip6_querier.addr.u.ip6 = *saddr; | ||
1118 | |||
1119 | return true; | ||
1120 | } | ||
1121 | #endif | ||
1122 | |||
1123 | static 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 | |||
1068 | static void | 1138 | static void |
1069 | br_multicast_update_query_timer(struct net_bridge *br, | 1139 | br_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: | |||
1127 | static void br_multicast_query_received(struct net_bridge *br, | 1197 | static 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) |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2469aeeda1ec..97c5e46dde72 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -78,6 +78,11 @@ struct bridge_mcast_other_query { | |||
78 | struct timer_list timer; | 78 | struct timer_list timer; |
79 | unsigned long delay_time; | 79 | unsigned long delay_time; |
80 | }; | 80 | }; |
81 | |||
82 | /* selected querier */ | ||
83 | struct bridge_mcast_querier { | ||
84 | struct br_ip addr; | ||
85 | }; | ||
81 | #endif | 86 | #endif |
82 | 87 | ||
83 | struct net_port_vlans { | 88 | struct net_port_vlans { |
@@ -284,9 +289,11 @@ struct net_bridge | |||
284 | struct timer_list multicast_router_timer; | 289 | struct timer_list multicast_router_timer; |
285 | struct bridge_mcast_other_query ip4_other_query; | 290 | struct bridge_mcast_other_query ip4_other_query; |
286 | struct bridge_mcast_own_query ip4_own_query; | 291 | struct bridge_mcast_own_query ip4_own_query; |
292 | struct bridge_mcast_querier ip4_querier; | ||
287 | #if IS_ENABLED(CONFIG_IPV6) | 293 | #if IS_ENABLED(CONFIG_IPV6) |
288 | struct bridge_mcast_other_query ip6_other_query; | 294 | struct bridge_mcast_other_query ip6_other_query; |
289 | struct bridge_mcast_own_query ip6_own_query; | 295 | struct bridge_mcast_own_query ip6_own_query; |
296 | struct bridge_mcast_querier ip6_querier; | ||
290 | #endif /* IS_ENABLED(CONFIG_IPV6) */ | 297 | #endif /* IS_ENABLED(CONFIG_IPV6) */ |
291 | #endif | 298 | #endif |
292 | 299 | ||