.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Bridge multicast support. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License as published by the Free |
---|
8 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
9 | | - * any later version. |
---|
10 | | - * |
---|
11 | 6 | */ |
---|
12 | 7 | |
---|
13 | 8 | #include <linux/err.h> |
---|
14 | 9 | #include <linux/export.h> |
---|
15 | 10 | #include <linux/if_ether.h> |
---|
16 | 11 | #include <linux/igmp.h> |
---|
| 12 | +#include <linux/in.h> |
---|
17 | 13 | #include <linux/jhash.h> |
---|
18 | 14 | #include <linux/kernel.h> |
---|
19 | 15 | #include <linux/log2.h> |
---|
.. | .. |
---|
29 | 25 | #include <net/ip.h> |
---|
30 | 26 | #include <net/switchdev.h> |
---|
31 | 27 | #if IS_ENABLED(CONFIG_IPV6) |
---|
| 28 | +#include <linux/icmpv6.h> |
---|
32 | 29 | #include <net/ipv6.h> |
---|
33 | 30 | #include <net/mld.h> |
---|
34 | 31 | #include <net/ip6_checksum.h> |
---|
.. | .. |
---|
36 | 33 | #endif |
---|
37 | 34 | |
---|
38 | 35 | #include "br_private.h" |
---|
| 36 | + |
---|
| 37 | +static const struct rhashtable_params br_mdb_rht_params = { |
---|
| 38 | + .head_offset = offsetof(struct net_bridge_mdb_entry, rhnode), |
---|
| 39 | + .key_offset = offsetof(struct net_bridge_mdb_entry, addr), |
---|
| 40 | + .key_len = sizeof(struct br_ip), |
---|
| 41 | + .automatic_shrinking = true, |
---|
| 42 | +}; |
---|
| 43 | + |
---|
| 44 | +static const struct rhashtable_params br_sg_port_rht_params = { |
---|
| 45 | + .head_offset = offsetof(struct net_bridge_port_group, rhnode), |
---|
| 46 | + .key_offset = offsetof(struct net_bridge_port_group, key), |
---|
| 47 | + .key_len = sizeof(struct net_bridge_port_group_sg_key), |
---|
| 48 | + .automatic_shrinking = true, |
---|
| 49 | +}; |
---|
39 | 50 | |
---|
40 | 51 | static void br_multicast_start_querier(struct net_bridge *br, |
---|
41 | 52 | struct bridge_mcast_own_query *query); |
---|
.. | .. |
---|
46 | 57 | __be32 group, |
---|
47 | 58 | __u16 vid, |
---|
48 | 59 | const unsigned char *src); |
---|
| 60 | +static void br_multicast_port_group_rexmit(struct timer_list *t); |
---|
49 | 61 | |
---|
50 | 62 | static void __del_port_router(struct net_bridge_port *p); |
---|
51 | 63 | #if IS_ENABLED(CONFIG_IPV6) |
---|
.. | .. |
---|
54 | 66 | const struct in6_addr *group, |
---|
55 | 67 | __u16 vid, const unsigned char *src); |
---|
56 | 68 | #endif |
---|
57 | | -unsigned int br_mdb_rehash_seq; |
---|
| 69 | +static struct net_bridge_port_group * |
---|
| 70 | +__br_multicast_add_group(struct net_bridge *br, |
---|
| 71 | + struct net_bridge_port *port, |
---|
| 72 | + struct br_ip *group, |
---|
| 73 | + const unsigned char *src, |
---|
| 74 | + u8 filter_mode, |
---|
| 75 | + bool igmpv2_mldv1, |
---|
| 76 | + bool blocked); |
---|
| 77 | +static void br_multicast_find_del_pg(struct net_bridge *br, |
---|
| 78 | + struct net_bridge_port_group *pg); |
---|
58 | 79 | |
---|
59 | | -static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b) |
---|
| 80 | +static struct net_bridge_port_group * |
---|
| 81 | +br_sg_port_find(struct net_bridge *br, |
---|
| 82 | + struct net_bridge_port_group_sg_key *sg_p) |
---|
60 | 83 | { |
---|
61 | | - if (a->proto != b->proto) |
---|
62 | | - return 0; |
---|
63 | | - if (a->vid != b->vid) |
---|
64 | | - return 0; |
---|
65 | | - switch (a->proto) { |
---|
66 | | - case htons(ETH_P_IP): |
---|
67 | | - return a->u.ip4 == b->u.ip4; |
---|
68 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
69 | | - case htons(ETH_P_IPV6): |
---|
70 | | - return ipv6_addr_equal(&a->u.ip6, &b->u.ip6); |
---|
71 | | -#endif |
---|
72 | | - } |
---|
73 | | - return 0; |
---|
| 84 | + lockdep_assert_held_once(&br->multicast_lock); |
---|
| 85 | + |
---|
| 86 | + return rhashtable_lookup_fast(&br->sg_port_tbl, sg_p, |
---|
| 87 | + br_sg_port_rht_params); |
---|
74 | 88 | } |
---|
75 | 89 | |
---|
76 | | -static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip, |
---|
77 | | - __u16 vid) |
---|
| 90 | +static struct net_bridge_mdb_entry *br_mdb_ip_get_rcu(struct net_bridge *br, |
---|
| 91 | + struct br_ip *dst) |
---|
78 | 92 | { |
---|
79 | | - return jhash_2words((__force u32)ip, vid, mdb->secret) & (mdb->max - 1); |
---|
| 93 | + return rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params); |
---|
80 | 94 | } |
---|
81 | 95 | |
---|
82 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
83 | | -static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb, |
---|
84 | | - const struct in6_addr *ip, |
---|
85 | | - __u16 vid) |
---|
86 | | -{ |
---|
87 | | - return jhash_2words(ipv6_addr_hash(ip), vid, |
---|
88 | | - mdb->secret) & (mdb->max - 1); |
---|
89 | | -} |
---|
90 | | -#endif |
---|
91 | | - |
---|
92 | | -static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb, |
---|
93 | | - struct br_ip *ip) |
---|
94 | | -{ |
---|
95 | | - switch (ip->proto) { |
---|
96 | | - case htons(ETH_P_IP): |
---|
97 | | - return __br_ip4_hash(mdb, ip->u.ip4, ip->vid); |
---|
98 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
99 | | - case htons(ETH_P_IPV6): |
---|
100 | | - return __br_ip6_hash(mdb, &ip->u.ip6, ip->vid); |
---|
101 | | -#endif |
---|
102 | | - } |
---|
103 | | - return 0; |
---|
104 | | -} |
---|
105 | | - |
---|
106 | | -static struct net_bridge_mdb_entry *__br_mdb_ip_get( |
---|
107 | | - struct net_bridge_mdb_htable *mdb, struct br_ip *dst, int hash) |
---|
108 | | -{ |
---|
109 | | - struct net_bridge_mdb_entry *mp; |
---|
110 | | - |
---|
111 | | - hlist_for_each_entry_rcu(mp, &mdb->mhash[hash], hlist[mdb->ver]) { |
---|
112 | | - if (br_ip_equal(&mp->addr, dst)) |
---|
113 | | - return mp; |
---|
114 | | - } |
---|
115 | | - |
---|
116 | | - return NULL; |
---|
117 | | -} |
---|
118 | | - |
---|
119 | | -struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge_mdb_htable *mdb, |
---|
| 96 | +struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge *br, |
---|
120 | 97 | struct br_ip *dst) |
---|
121 | 98 | { |
---|
122 | | - if (!mdb) |
---|
123 | | - return NULL; |
---|
| 99 | + struct net_bridge_mdb_entry *ent; |
---|
124 | 100 | |
---|
125 | | - return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst)); |
---|
| 101 | + lockdep_assert_held_once(&br->multicast_lock); |
---|
| 102 | + |
---|
| 103 | + rcu_read_lock(); |
---|
| 104 | + ent = rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params); |
---|
| 105 | + rcu_read_unlock(); |
---|
| 106 | + |
---|
| 107 | + return ent; |
---|
126 | 108 | } |
---|
127 | 109 | |
---|
128 | | -static struct net_bridge_mdb_entry *br_mdb_ip4_get( |
---|
129 | | - struct net_bridge_mdb_htable *mdb, __be32 dst, __u16 vid) |
---|
| 110 | +static struct net_bridge_mdb_entry *br_mdb_ip4_get(struct net_bridge *br, |
---|
| 111 | + __be32 dst, __u16 vid) |
---|
130 | 112 | { |
---|
131 | 113 | struct br_ip br_dst; |
---|
132 | 114 | |
---|
133 | | - br_dst.u.ip4 = dst; |
---|
| 115 | + memset(&br_dst, 0, sizeof(br_dst)); |
---|
| 116 | + br_dst.dst.ip4 = dst; |
---|
134 | 117 | br_dst.proto = htons(ETH_P_IP); |
---|
135 | 118 | br_dst.vid = vid; |
---|
136 | 119 | |
---|
137 | | - return br_mdb_ip_get(mdb, &br_dst); |
---|
| 120 | + return br_mdb_ip_get(br, &br_dst); |
---|
138 | 121 | } |
---|
139 | 122 | |
---|
140 | 123 | #if IS_ENABLED(CONFIG_IPV6) |
---|
141 | | -static struct net_bridge_mdb_entry *br_mdb_ip6_get( |
---|
142 | | - struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst, |
---|
143 | | - __u16 vid) |
---|
| 124 | +static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br, |
---|
| 125 | + const struct in6_addr *dst, |
---|
| 126 | + __u16 vid) |
---|
144 | 127 | { |
---|
145 | 128 | struct br_ip br_dst; |
---|
146 | 129 | |
---|
147 | | - br_dst.u.ip6 = *dst; |
---|
| 130 | + memset(&br_dst, 0, sizeof(br_dst)); |
---|
| 131 | + br_dst.dst.ip6 = *dst; |
---|
148 | 132 | br_dst.proto = htons(ETH_P_IPV6); |
---|
149 | 133 | br_dst.vid = vid; |
---|
150 | 134 | |
---|
151 | | - return br_mdb_ip_get(mdb, &br_dst); |
---|
| 135 | + return br_mdb_ip_get(br, &br_dst); |
---|
152 | 136 | } |
---|
153 | 137 | #endif |
---|
154 | 138 | |
---|
155 | 139 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, |
---|
156 | 140 | struct sk_buff *skb, u16 vid) |
---|
157 | 141 | { |
---|
158 | | - struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb); |
---|
159 | 142 | struct br_ip ip; |
---|
160 | 143 | |
---|
161 | | - if (br->multicast_disabled) |
---|
| 144 | + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
162 | 145 | return NULL; |
---|
163 | 146 | |
---|
164 | 147 | if (BR_INPUT_SKB_CB(skb)->igmp) |
---|
165 | 148 | return NULL; |
---|
166 | 149 | |
---|
| 150 | + memset(&ip, 0, sizeof(ip)); |
---|
167 | 151 | ip.proto = skb->protocol; |
---|
168 | 152 | ip.vid = vid; |
---|
169 | 153 | |
---|
170 | 154 | switch (skb->protocol) { |
---|
171 | 155 | case htons(ETH_P_IP): |
---|
172 | | - ip.u.ip4 = ip_hdr(skb)->daddr; |
---|
| 156 | + ip.dst.ip4 = ip_hdr(skb)->daddr; |
---|
| 157 | + if (br->multicast_igmp_version == 3) { |
---|
| 158 | + struct net_bridge_mdb_entry *mdb; |
---|
| 159 | + |
---|
| 160 | + ip.src.ip4 = ip_hdr(skb)->saddr; |
---|
| 161 | + mdb = br_mdb_ip_get_rcu(br, &ip); |
---|
| 162 | + if (mdb) |
---|
| 163 | + return mdb; |
---|
| 164 | + ip.src.ip4 = 0; |
---|
| 165 | + } |
---|
173 | 166 | break; |
---|
174 | 167 | #if IS_ENABLED(CONFIG_IPV6) |
---|
175 | 168 | case htons(ETH_P_IPV6): |
---|
176 | | - ip.u.ip6 = ipv6_hdr(skb)->daddr; |
---|
| 169 | + ip.dst.ip6 = ipv6_hdr(skb)->daddr; |
---|
| 170 | + if (br->multicast_mld_version == 2) { |
---|
| 171 | + struct net_bridge_mdb_entry *mdb; |
---|
| 172 | + |
---|
| 173 | + ip.src.ip6 = ipv6_hdr(skb)->saddr; |
---|
| 174 | + mdb = br_mdb_ip_get_rcu(br, &ip); |
---|
| 175 | + if (mdb) |
---|
| 176 | + return mdb; |
---|
| 177 | + memset(&ip.src.ip6, 0, sizeof(ip.src.ip6)); |
---|
| 178 | + } |
---|
177 | 179 | break; |
---|
178 | 180 | #endif |
---|
179 | 181 | default: |
---|
180 | 182 | return NULL; |
---|
181 | 183 | } |
---|
182 | 184 | |
---|
183 | | - return br_mdb_ip_get(mdb, &ip); |
---|
| 185 | + return br_mdb_ip_get_rcu(br, &ip); |
---|
184 | 186 | } |
---|
185 | 187 | |
---|
186 | | -static void br_mdb_free(struct rcu_head *head) |
---|
| 188 | +static bool br_port_group_equal(struct net_bridge_port_group *p, |
---|
| 189 | + struct net_bridge_port *port, |
---|
| 190 | + const unsigned char *src) |
---|
187 | 191 | { |
---|
188 | | - struct net_bridge_mdb_htable *mdb = |
---|
189 | | - container_of(head, struct net_bridge_mdb_htable, rcu); |
---|
190 | | - struct net_bridge_mdb_htable *old = mdb->old; |
---|
| 192 | + if (p->key.port != port) |
---|
| 193 | + return false; |
---|
191 | 194 | |
---|
192 | | - mdb->old = NULL; |
---|
193 | | - kfree(old->mhash); |
---|
194 | | - kfree(old); |
---|
| 195 | + if (!(port->flags & BR_MULTICAST_TO_UNICAST)) |
---|
| 196 | + return true; |
---|
| 197 | + |
---|
| 198 | + return ether_addr_equal(src, p->eth_addr); |
---|
195 | 199 | } |
---|
196 | 200 | |
---|
197 | | -static int br_mdb_copy(struct net_bridge_mdb_htable *new, |
---|
198 | | - struct net_bridge_mdb_htable *old, |
---|
199 | | - int elasticity) |
---|
| 201 | +static void __fwd_add_star_excl(struct net_bridge_port_group *pg, |
---|
| 202 | + struct br_ip *sg_ip) |
---|
| 203 | +{ |
---|
| 204 | + struct net_bridge_port_group_sg_key sg_key; |
---|
| 205 | + struct net_bridge *br = pg->key.port->br; |
---|
| 206 | + struct net_bridge_port_group *src_pg; |
---|
| 207 | + |
---|
| 208 | + memset(&sg_key, 0, sizeof(sg_key)); |
---|
| 209 | + sg_key.port = pg->key.port; |
---|
| 210 | + sg_key.addr = *sg_ip; |
---|
| 211 | + if (br_sg_port_find(br, &sg_key)) |
---|
| 212 | + return; |
---|
| 213 | + |
---|
| 214 | + src_pg = __br_multicast_add_group(br, pg->key.port, sg_ip, pg->eth_addr, |
---|
| 215 | + MCAST_INCLUDE, false, false); |
---|
| 216 | + if (IS_ERR_OR_NULL(src_pg) || |
---|
| 217 | + src_pg->rt_protocol != RTPROT_KERNEL) |
---|
| 218 | + return; |
---|
| 219 | + |
---|
| 220 | + src_pg->flags |= MDB_PG_FLAGS_STAR_EXCL; |
---|
| 221 | +} |
---|
| 222 | + |
---|
| 223 | +static void __fwd_del_star_excl(struct net_bridge_port_group *pg, |
---|
| 224 | + struct br_ip *sg_ip) |
---|
| 225 | +{ |
---|
| 226 | + struct net_bridge_port_group_sg_key sg_key; |
---|
| 227 | + struct net_bridge *br = pg->key.port->br; |
---|
| 228 | + struct net_bridge_port_group *src_pg; |
---|
| 229 | + |
---|
| 230 | + memset(&sg_key, 0, sizeof(sg_key)); |
---|
| 231 | + sg_key.port = pg->key.port; |
---|
| 232 | + sg_key.addr = *sg_ip; |
---|
| 233 | + src_pg = br_sg_port_find(br, &sg_key); |
---|
| 234 | + if (!src_pg || !(src_pg->flags & MDB_PG_FLAGS_STAR_EXCL) || |
---|
| 235 | + src_pg->rt_protocol != RTPROT_KERNEL) |
---|
| 236 | + return; |
---|
| 237 | + |
---|
| 238 | + br_multicast_find_del_pg(br, src_pg); |
---|
| 239 | +} |
---|
| 240 | + |
---|
| 241 | +/* When a port group transitions to (or is added as) EXCLUDE we need to add it |
---|
| 242 | + * to all other ports' S,G entries which are not blocked by the current group |
---|
| 243 | + * for proper replication, the assumption is that any S,G blocked entries |
---|
| 244 | + * are already added so the S,G,port lookup should skip them. |
---|
| 245 | + * When a port group transitions from EXCLUDE -> INCLUDE mode or is being |
---|
| 246 | + * deleted we need to remove it from all ports' S,G entries where it was |
---|
| 247 | + * automatically installed before (i.e. where it's MDB_PG_FLAGS_STAR_EXCL). |
---|
| 248 | + */ |
---|
| 249 | +void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg, |
---|
| 250 | + u8 filter_mode) |
---|
| 251 | +{ |
---|
| 252 | + struct net_bridge *br = pg->key.port->br; |
---|
| 253 | + struct net_bridge_port_group *pg_lst; |
---|
| 254 | + struct net_bridge_mdb_entry *mp; |
---|
| 255 | + struct br_ip sg_ip; |
---|
| 256 | + |
---|
| 257 | + if (WARN_ON(!br_multicast_is_star_g(&pg->key.addr))) |
---|
| 258 | + return; |
---|
| 259 | + |
---|
| 260 | + mp = br_mdb_ip_get(br, &pg->key.addr); |
---|
| 261 | + if (!mp) |
---|
| 262 | + return; |
---|
| 263 | + |
---|
| 264 | + memset(&sg_ip, 0, sizeof(sg_ip)); |
---|
| 265 | + sg_ip = pg->key.addr; |
---|
| 266 | + for (pg_lst = mlock_dereference(mp->ports, br); |
---|
| 267 | + pg_lst; |
---|
| 268 | + pg_lst = mlock_dereference(pg_lst->next, br)) { |
---|
| 269 | + struct net_bridge_group_src *src_ent; |
---|
| 270 | + |
---|
| 271 | + if (pg_lst == pg) |
---|
| 272 | + continue; |
---|
| 273 | + hlist_for_each_entry(src_ent, &pg_lst->src_list, node) { |
---|
| 274 | + if (!(src_ent->flags & BR_SGRP_F_INSTALLED)) |
---|
| 275 | + continue; |
---|
| 276 | + sg_ip.src = src_ent->addr.src; |
---|
| 277 | + switch (filter_mode) { |
---|
| 278 | + case MCAST_INCLUDE: |
---|
| 279 | + __fwd_del_star_excl(pg, &sg_ip); |
---|
| 280 | + break; |
---|
| 281 | + case MCAST_EXCLUDE: |
---|
| 282 | + __fwd_add_star_excl(pg, &sg_ip); |
---|
| 283 | + break; |
---|
| 284 | + } |
---|
| 285 | + } |
---|
| 286 | + } |
---|
| 287 | +} |
---|
| 288 | + |
---|
| 289 | +/* called when adding a new S,G with host_joined == false by default */ |
---|
| 290 | +static void br_multicast_sg_host_state(struct net_bridge_mdb_entry *star_mp, |
---|
| 291 | + struct net_bridge_port_group *sg) |
---|
| 292 | +{ |
---|
| 293 | + struct net_bridge_mdb_entry *sg_mp; |
---|
| 294 | + |
---|
| 295 | + if (WARN_ON(!br_multicast_is_star_g(&star_mp->addr))) |
---|
| 296 | + return; |
---|
| 297 | + if (!star_mp->host_joined) |
---|
| 298 | + return; |
---|
| 299 | + |
---|
| 300 | + sg_mp = br_mdb_ip_get(star_mp->br, &sg->key.addr); |
---|
| 301 | + if (!sg_mp) |
---|
| 302 | + return; |
---|
| 303 | + sg_mp->host_joined = true; |
---|
| 304 | +} |
---|
| 305 | + |
---|
| 306 | +/* set the host_joined state of all of *,G's S,G entries */ |
---|
| 307 | +static void br_multicast_star_g_host_state(struct net_bridge_mdb_entry *star_mp) |
---|
| 308 | +{ |
---|
| 309 | + struct net_bridge *br = star_mp->br; |
---|
| 310 | + struct net_bridge_mdb_entry *sg_mp; |
---|
| 311 | + struct net_bridge_port_group *pg; |
---|
| 312 | + struct br_ip sg_ip; |
---|
| 313 | + |
---|
| 314 | + if (WARN_ON(!br_multicast_is_star_g(&star_mp->addr))) |
---|
| 315 | + return; |
---|
| 316 | + |
---|
| 317 | + memset(&sg_ip, 0, sizeof(sg_ip)); |
---|
| 318 | + sg_ip = star_mp->addr; |
---|
| 319 | + for (pg = mlock_dereference(star_mp->ports, br); |
---|
| 320 | + pg; |
---|
| 321 | + pg = mlock_dereference(pg->next, br)) { |
---|
| 322 | + struct net_bridge_group_src *src_ent; |
---|
| 323 | + |
---|
| 324 | + hlist_for_each_entry(src_ent, &pg->src_list, node) { |
---|
| 325 | + if (!(src_ent->flags & BR_SGRP_F_INSTALLED)) |
---|
| 326 | + continue; |
---|
| 327 | + sg_ip.src = src_ent->addr.src; |
---|
| 328 | + sg_mp = br_mdb_ip_get(br, &sg_ip); |
---|
| 329 | + if (!sg_mp) |
---|
| 330 | + continue; |
---|
| 331 | + sg_mp->host_joined = star_mp->host_joined; |
---|
| 332 | + } |
---|
| 333 | + } |
---|
| 334 | +} |
---|
| 335 | + |
---|
| 336 | +static void br_multicast_sg_del_exclude_ports(struct net_bridge_mdb_entry *sgmp) |
---|
| 337 | +{ |
---|
| 338 | + struct net_bridge_port_group __rcu **pp; |
---|
| 339 | + struct net_bridge_port_group *p; |
---|
| 340 | + |
---|
| 341 | + /* *,G exclude ports are only added to S,G entries */ |
---|
| 342 | + if (WARN_ON(br_multicast_is_star_g(&sgmp->addr))) |
---|
| 343 | + return; |
---|
| 344 | + |
---|
| 345 | + /* we need the STAR_EXCLUDE ports if there are non-STAR_EXCLUDE ports |
---|
| 346 | + * we should ignore perm entries since they're managed by user-space |
---|
| 347 | + */ |
---|
| 348 | + for (pp = &sgmp->ports; |
---|
| 349 | + (p = mlock_dereference(*pp, sgmp->br)) != NULL; |
---|
| 350 | + pp = &p->next) |
---|
| 351 | + if (!(p->flags & (MDB_PG_FLAGS_STAR_EXCL | |
---|
| 352 | + MDB_PG_FLAGS_PERMANENT))) |
---|
| 353 | + return; |
---|
| 354 | + |
---|
| 355 | + /* currently the host can only have joined the *,G which means |
---|
| 356 | + * we treat it as EXCLUDE {}, so for an S,G it's considered a |
---|
| 357 | + * STAR_EXCLUDE entry and we can safely leave it |
---|
| 358 | + */ |
---|
| 359 | + sgmp->host_joined = false; |
---|
| 360 | + |
---|
| 361 | + for (pp = &sgmp->ports; |
---|
| 362 | + (p = mlock_dereference(*pp, sgmp->br)) != NULL;) { |
---|
| 363 | + if (!(p->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 364 | + br_multicast_del_pg(sgmp, p, pp); |
---|
| 365 | + else |
---|
| 366 | + pp = &p->next; |
---|
| 367 | + } |
---|
| 368 | +} |
---|
| 369 | + |
---|
| 370 | +void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, |
---|
| 371 | + struct net_bridge_port_group *sg) |
---|
| 372 | +{ |
---|
| 373 | + struct net_bridge_port_group_sg_key sg_key; |
---|
| 374 | + struct net_bridge *br = star_mp->br; |
---|
| 375 | + struct net_bridge_port_group *pg; |
---|
| 376 | + |
---|
| 377 | + if (WARN_ON(br_multicast_is_star_g(&sg->key.addr))) |
---|
| 378 | + return; |
---|
| 379 | + if (WARN_ON(!br_multicast_is_star_g(&star_mp->addr))) |
---|
| 380 | + return; |
---|
| 381 | + |
---|
| 382 | + br_multicast_sg_host_state(star_mp, sg); |
---|
| 383 | + memset(&sg_key, 0, sizeof(sg_key)); |
---|
| 384 | + sg_key.addr = sg->key.addr; |
---|
| 385 | + /* we need to add all exclude ports to the S,G */ |
---|
| 386 | + for (pg = mlock_dereference(star_mp->ports, br); |
---|
| 387 | + pg; |
---|
| 388 | + pg = mlock_dereference(pg->next, br)) { |
---|
| 389 | + struct net_bridge_port_group *src_pg; |
---|
| 390 | + |
---|
| 391 | + if (pg == sg || pg->filter_mode == MCAST_INCLUDE) |
---|
| 392 | + continue; |
---|
| 393 | + |
---|
| 394 | + sg_key.port = pg->key.port; |
---|
| 395 | + if (br_sg_port_find(br, &sg_key)) |
---|
| 396 | + continue; |
---|
| 397 | + |
---|
| 398 | + src_pg = __br_multicast_add_group(br, pg->key.port, |
---|
| 399 | + &sg->key.addr, |
---|
| 400 | + sg->eth_addr, |
---|
| 401 | + MCAST_INCLUDE, false, false); |
---|
| 402 | + if (IS_ERR_OR_NULL(src_pg) || |
---|
| 403 | + src_pg->rt_protocol != RTPROT_KERNEL) |
---|
| 404 | + continue; |
---|
| 405 | + src_pg->flags |= MDB_PG_FLAGS_STAR_EXCL; |
---|
| 406 | + } |
---|
| 407 | +} |
---|
| 408 | + |
---|
| 409 | +static void br_multicast_fwd_src_add(struct net_bridge_group_src *src) |
---|
| 410 | +{ |
---|
| 411 | + struct net_bridge_mdb_entry *star_mp; |
---|
| 412 | + struct net_bridge_port_group *sg; |
---|
| 413 | + struct br_ip sg_ip; |
---|
| 414 | + |
---|
| 415 | + if (src->flags & BR_SGRP_F_INSTALLED) |
---|
| 416 | + return; |
---|
| 417 | + |
---|
| 418 | + memset(&sg_ip, 0, sizeof(sg_ip)); |
---|
| 419 | + sg_ip = src->pg->key.addr; |
---|
| 420 | + sg_ip.src = src->addr.src; |
---|
| 421 | + sg = __br_multicast_add_group(src->br, src->pg->key.port, &sg_ip, |
---|
| 422 | + src->pg->eth_addr, MCAST_INCLUDE, false, |
---|
| 423 | + !timer_pending(&src->timer)); |
---|
| 424 | + if (IS_ERR_OR_NULL(sg)) |
---|
| 425 | + return; |
---|
| 426 | + src->flags |= BR_SGRP_F_INSTALLED; |
---|
| 427 | + sg->flags &= ~MDB_PG_FLAGS_STAR_EXCL; |
---|
| 428 | + |
---|
| 429 | + /* if it was added by user-space as perm we can skip next steps */ |
---|
| 430 | + if (sg->rt_protocol != RTPROT_KERNEL && |
---|
| 431 | + (sg->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 432 | + return; |
---|
| 433 | + |
---|
| 434 | + /* the kernel is now responsible for removing this S,G */ |
---|
| 435 | + del_timer(&sg->timer); |
---|
| 436 | + star_mp = br_mdb_ip_get(src->br, &src->pg->key.addr); |
---|
| 437 | + if (!star_mp) |
---|
| 438 | + return; |
---|
| 439 | + |
---|
| 440 | + br_multicast_sg_add_exclude_ports(star_mp, sg); |
---|
| 441 | +} |
---|
| 442 | + |
---|
| 443 | +static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src) |
---|
| 444 | +{ |
---|
| 445 | + struct net_bridge_port_group *p, *pg = src->pg; |
---|
| 446 | + struct net_bridge_port_group __rcu **pp; |
---|
| 447 | + struct net_bridge_mdb_entry *mp; |
---|
| 448 | + struct br_ip sg_ip; |
---|
| 449 | + |
---|
| 450 | + memset(&sg_ip, 0, sizeof(sg_ip)); |
---|
| 451 | + sg_ip = pg->key.addr; |
---|
| 452 | + sg_ip.src = src->addr.src; |
---|
| 453 | + |
---|
| 454 | + mp = br_mdb_ip_get(src->br, &sg_ip); |
---|
| 455 | + if (!mp) |
---|
| 456 | + return; |
---|
| 457 | + |
---|
| 458 | + for (pp = &mp->ports; |
---|
| 459 | + (p = mlock_dereference(*pp, src->br)) != NULL; |
---|
| 460 | + pp = &p->next) { |
---|
| 461 | + if (!br_port_group_equal(p, pg->key.port, pg->eth_addr)) |
---|
| 462 | + continue; |
---|
| 463 | + |
---|
| 464 | + if (p->rt_protocol != RTPROT_KERNEL && |
---|
| 465 | + (p->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 466 | + break; |
---|
| 467 | + |
---|
| 468 | + br_multicast_del_pg(mp, p, pp); |
---|
| 469 | + break; |
---|
| 470 | + } |
---|
| 471 | + src->flags &= ~BR_SGRP_F_INSTALLED; |
---|
| 472 | +} |
---|
| 473 | + |
---|
| 474 | +/* install S,G and based on src's timer enable or disable forwarding */ |
---|
| 475 | +static void br_multicast_fwd_src_handle(struct net_bridge_group_src *src) |
---|
| 476 | +{ |
---|
| 477 | + struct net_bridge_port_group_sg_key sg_key; |
---|
| 478 | + struct net_bridge_port_group *sg; |
---|
| 479 | + u8 old_flags; |
---|
| 480 | + |
---|
| 481 | + br_multicast_fwd_src_add(src); |
---|
| 482 | + |
---|
| 483 | + memset(&sg_key, 0, sizeof(sg_key)); |
---|
| 484 | + sg_key.addr = src->pg->key.addr; |
---|
| 485 | + sg_key.addr.src = src->addr.src; |
---|
| 486 | + sg_key.port = src->pg->key.port; |
---|
| 487 | + |
---|
| 488 | + sg = br_sg_port_find(src->br, &sg_key); |
---|
| 489 | + if (!sg || (sg->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 490 | + return; |
---|
| 491 | + |
---|
| 492 | + old_flags = sg->flags; |
---|
| 493 | + if (timer_pending(&src->timer)) |
---|
| 494 | + sg->flags &= ~MDB_PG_FLAGS_BLOCKED; |
---|
| 495 | + else |
---|
| 496 | + sg->flags |= MDB_PG_FLAGS_BLOCKED; |
---|
| 497 | + |
---|
| 498 | + if (old_flags != sg->flags) { |
---|
| 499 | + struct net_bridge_mdb_entry *sg_mp; |
---|
| 500 | + |
---|
| 501 | + sg_mp = br_mdb_ip_get(src->br, &sg_key.addr); |
---|
| 502 | + if (!sg_mp) |
---|
| 503 | + return; |
---|
| 504 | + br_mdb_notify(src->br->dev, sg_mp, sg, RTM_NEWMDB); |
---|
| 505 | + } |
---|
| 506 | +} |
---|
| 507 | + |
---|
| 508 | +static void br_multicast_destroy_mdb_entry(struct net_bridge_mcast_gc *gc) |
---|
200 | 509 | { |
---|
201 | 510 | struct net_bridge_mdb_entry *mp; |
---|
202 | | - int maxlen; |
---|
203 | | - int len; |
---|
204 | | - int i; |
---|
205 | 511 | |
---|
206 | | - for (i = 0; i < old->max; i++) |
---|
207 | | - hlist_for_each_entry(mp, &old->mhash[i], hlist[old->ver]) |
---|
208 | | - hlist_add_head(&mp->hlist[new->ver], |
---|
209 | | - &new->mhash[br_ip_hash(new, &mp->addr)]); |
---|
| 512 | + mp = container_of(gc, struct net_bridge_mdb_entry, mcast_gc); |
---|
| 513 | + WARN_ON(!hlist_unhashed(&mp->mdb_node)); |
---|
| 514 | + WARN_ON(mp->ports); |
---|
210 | 515 | |
---|
211 | | - if (!elasticity) |
---|
212 | | - return 0; |
---|
213 | | - |
---|
214 | | - maxlen = 0; |
---|
215 | | - for (i = 0; i < new->max; i++) { |
---|
216 | | - len = 0; |
---|
217 | | - hlist_for_each_entry(mp, &new->mhash[i], hlist[new->ver]) |
---|
218 | | - len++; |
---|
219 | | - if (len > maxlen) |
---|
220 | | - maxlen = len; |
---|
221 | | - } |
---|
222 | | - |
---|
223 | | - return maxlen > elasticity ? -EINVAL : 0; |
---|
| 516 | + del_timer_sync(&mp->timer); |
---|
| 517 | + kfree_rcu(mp, rcu); |
---|
224 | 518 | } |
---|
225 | 519 | |
---|
226 | | -void br_multicast_free_pg(struct rcu_head *head) |
---|
| 520 | +static void br_multicast_del_mdb_entry(struct net_bridge_mdb_entry *mp) |
---|
227 | 521 | { |
---|
228 | | - struct net_bridge_port_group *p = |
---|
229 | | - container_of(head, struct net_bridge_port_group, rcu); |
---|
| 522 | + struct net_bridge *br = mp->br; |
---|
230 | 523 | |
---|
231 | | - kfree(p); |
---|
232 | | -} |
---|
233 | | - |
---|
234 | | -static void br_multicast_free_group(struct rcu_head *head) |
---|
235 | | -{ |
---|
236 | | - struct net_bridge_mdb_entry *mp = |
---|
237 | | - container_of(head, struct net_bridge_mdb_entry, rcu); |
---|
238 | | - |
---|
239 | | - kfree(mp); |
---|
| 524 | + rhashtable_remove_fast(&br->mdb_hash_tbl, &mp->rhnode, |
---|
| 525 | + br_mdb_rht_params); |
---|
| 526 | + hlist_del_init_rcu(&mp->mdb_node); |
---|
| 527 | + hlist_add_head(&mp->mcast_gc.gc_node, &br->mcast_gc_list); |
---|
| 528 | + queue_work(system_long_wq, &br->mcast_gc_work); |
---|
240 | 529 | } |
---|
241 | 530 | |
---|
242 | 531 | static void br_multicast_group_expired(struct timer_list *t) |
---|
243 | 532 | { |
---|
244 | 533 | struct net_bridge_mdb_entry *mp = from_timer(mp, t, timer); |
---|
245 | 534 | struct net_bridge *br = mp->br; |
---|
246 | | - struct net_bridge_mdb_htable *mdb; |
---|
247 | 535 | |
---|
248 | 536 | spin_lock(&br->multicast_lock); |
---|
249 | | - if (!netif_running(br->dev) || timer_pending(&mp->timer)) |
---|
| 537 | + if (hlist_unhashed(&mp->mdb_node) || !netif_running(br->dev) || |
---|
| 538 | + timer_pending(&mp->timer)) |
---|
250 | 539 | goto out; |
---|
251 | 540 | |
---|
252 | | - mp->host_joined = false; |
---|
253 | | - br_mdb_notify(br->dev, NULL, &mp->addr, RTM_DELMDB, 0); |
---|
| 541 | + br_multicast_host_leave(mp, true); |
---|
254 | 542 | |
---|
255 | 543 | if (mp->ports) |
---|
256 | 544 | goto out; |
---|
257 | | - |
---|
258 | | - mdb = mlock_dereference(br->mdb, br); |
---|
259 | | - |
---|
260 | | - hlist_del_rcu(&mp->hlist[mdb->ver]); |
---|
261 | | - mdb->size--; |
---|
262 | | - |
---|
263 | | - call_rcu_bh(&mp->rcu, br_multicast_free_group); |
---|
264 | | - |
---|
| 545 | + br_multicast_del_mdb_entry(mp); |
---|
265 | 546 | out: |
---|
266 | 547 | spin_unlock(&br->multicast_lock); |
---|
267 | 548 | } |
---|
268 | 549 | |
---|
269 | | -static void br_multicast_del_pg(struct net_bridge *br, |
---|
270 | | - struct net_bridge_port_group *pg) |
---|
| 550 | +static void br_multicast_destroy_group_src(struct net_bridge_mcast_gc *gc) |
---|
271 | 551 | { |
---|
272 | | - struct net_bridge_mdb_htable *mdb; |
---|
| 552 | + struct net_bridge_group_src *src; |
---|
| 553 | + |
---|
| 554 | + src = container_of(gc, struct net_bridge_group_src, mcast_gc); |
---|
| 555 | + WARN_ON(!hlist_unhashed(&src->node)); |
---|
| 556 | + |
---|
| 557 | + del_timer_sync(&src->timer); |
---|
| 558 | + kfree_rcu(src, rcu); |
---|
| 559 | +} |
---|
| 560 | + |
---|
| 561 | +static void br_multicast_del_group_src(struct net_bridge_group_src *src) |
---|
| 562 | +{ |
---|
| 563 | + struct net_bridge *br = src->pg->key.port->br; |
---|
| 564 | + |
---|
| 565 | + br_multicast_fwd_src_remove(src); |
---|
| 566 | + hlist_del_init_rcu(&src->node); |
---|
| 567 | + src->pg->src_ents--; |
---|
| 568 | + hlist_add_head(&src->mcast_gc.gc_node, &br->mcast_gc_list); |
---|
| 569 | + queue_work(system_long_wq, &br->mcast_gc_work); |
---|
| 570 | +} |
---|
| 571 | + |
---|
| 572 | +static void br_multicast_destroy_port_group(struct net_bridge_mcast_gc *gc) |
---|
| 573 | +{ |
---|
| 574 | + struct net_bridge_port_group *pg; |
---|
| 575 | + |
---|
| 576 | + pg = container_of(gc, struct net_bridge_port_group, mcast_gc); |
---|
| 577 | + WARN_ON(!hlist_unhashed(&pg->mglist)); |
---|
| 578 | + WARN_ON(!hlist_empty(&pg->src_list)); |
---|
| 579 | + |
---|
| 580 | + del_timer_sync(&pg->rexmit_timer); |
---|
| 581 | + del_timer_sync(&pg->timer); |
---|
| 582 | + kfree_rcu(pg, rcu); |
---|
| 583 | +} |
---|
| 584 | + |
---|
| 585 | +void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, |
---|
| 586 | + struct net_bridge_port_group *pg, |
---|
| 587 | + struct net_bridge_port_group __rcu **pp) |
---|
| 588 | +{ |
---|
| 589 | + struct net_bridge *br = pg->key.port->br; |
---|
| 590 | + struct net_bridge_group_src *ent; |
---|
| 591 | + struct hlist_node *tmp; |
---|
| 592 | + |
---|
| 593 | + rcu_assign_pointer(*pp, pg->next); |
---|
| 594 | + hlist_del_init(&pg->mglist); |
---|
| 595 | + hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node) |
---|
| 596 | + br_multicast_del_group_src(ent); |
---|
| 597 | + br_mdb_notify(br->dev, mp, pg, RTM_DELMDB); |
---|
| 598 | + if (!br_multicast_is_star_g(&mp->addr)) { |
---|
| 599 | + rhashtable_remove_fast(&br->sg_port_tbl, &pg->rhnode, |
---|
| 600 | + br_sg_port_rht_params); |
---|
| 601 | + br_multicast_sg_del_exclude_ports(mp); |
---|
| 602 | + } else { |
---|
| 603 | + br_multicast_star_g_handle_mode(pg, MCAST_INCLUDE); |
---|
| 604 | + } |
---|
| 605 | + hlist_add_head(&pg->mcast_gc.gc_node, &br->mcast_gc_list); |
---|
| 606 | + queue_work(system_long_wq, &br->mcast_gc_work); |
---|
| 607 | + |
---|
| 608 | + if (!mp->ports && !mp->host_joined && netif_running(br->dev)) |
---|
| 609 | + mod_timer(&mp->timer, jiffies); |
---|
| 610 | +} |
---|
| 611 | + |
---|
| 612 | +static void br_multicast_find_del_pg(struct net_bridge *br, |
---|
| 613 | + struct net_bridge_port_group *pg) |
---|
| 614 | +{ |
---|
| 615 | + struct net_bridge_port_group __rcu **pp; |
---|
273 | 616 | struct net_bridge_mdb_entry *mp; |
---|
274 | 617 | struct net_bridge_port_group *p; |
---|
275 | | - struct net_bridge_port_group __rcu **pp; |
---|
276 | 618 | |
---|
277 | | - mdb = mlock_dereference(br->mdb, br); |
---|
278 | | - |
---|
279 | | - mp = br_mdb_ip_get(mdb, &pg->addr); |
---|
| 619 | + mp = br_mdb_ip_get(br, &pg->key.addr); |
---|
280 | 620 | if (WARN_ON(!mp)) |
---|
281 | 621 | return; |
---|
282 | 622 | |
---|
.. | .. |
---|
286 | 626 | if (p != pg) |
---|
287 | 627 | continue; |
---|
288 | 628 | |
---|
289 | | - rcu_assign_pointer(*pp, p->next); |
---|
290 | | - hlist_del_init(&p->mglist); |
---|
291 | | - del_timer(&p->timer); |
---|
292 | | - br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB, |
---|
293 | | - p->flags); |
---|
294 | | - call_rcu_bh(&p->rcu, br_multicast_free_pg); |
---|
295 | | - |
---|
296 | | - if (!mp->ports && !mp->host_joined && |
---|
297 | | - netif_running(br->dev)) |
---|
298 | | - mod_timer(&mp->timer, jiffies); |
---|
299 | | - |
---|
| 629 | + br_multicast_del_pg(mp, pg, pp); |
---|
300 | 630 | return; |
---|
301 | 631 | } |
---|
302 | 632 | |
---|
.. | .. |
---|
306 | 636 | static void br_multicast_port_group_expired(struct timer_list *t) |
---|
307 | 637 | { |
---|
308 | 638 | struct net_bridge_port_group *pg = from_timer(pg, t, timer); |
---|
309 | | - struct net_bridge *br = pg->port->br; |
---|
| 639 | + struct net_bridge_group_src *src_ent; |
---|
| 640 | + struct net_bridge *br = pg->key.port->br; |
---|
| 641 | + struct hlist_node *tmp; |
---|
| 642 | + bool changed; |
---|
310 | 643 | |
---|
311 | 644 | spin_lock(&br->multicast_lock); |
---|
312 | 645 | if (!netif_running(br->dev) || timer_pending(&pg->timer) || |
---|
313 | 646 | hlist_unhashed(&pg->mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT) |
---|
314 | 647 | goto out; |
---|
315 | 648 | |
---|
316 | | - br_multicast_del_pg(br, pg); |
---|
| 649 | + changed = !!(pg->filter_mode == MCAST_EXCLUDE); |
---|
| 650 | + pg->filter_mode = MCAST_INCLUDE; |
---|
| 651 | + hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) { |
---|
| 652 | + if (!timer_pending(&src_ent->timer)) { |
---|
| 653 | + br_multicast_del_group_src(src_ent); |
---|
| 654 | + changed = true; |
---|
| 655 | + } |
---|
| 656 | + } |
---|
317 | 657 | |
---|
| 658 | + if (hlist_empty(&pg->src_list)) { |
---|
| 659 | + br_multicast_find_del_pg(br, pg); |
---|
| 660 | + } else if (changed) { |
---|
| 661 | + struct net_bridge_mdb_entry *mp = br_mdb_ip_get(br, &pg->key.addr); |
---|
| 662 | + |
---|
| 663 | + if (changed && br_multicast_is_star_g(&pg->key.addr)) |
---|
| 664 | + br_multicast_star_g_handle_mode(pg, MCAST_INCLUDE); |
---|
| 665 | + |
---|
| 666 | + if (WARN_ON(!mp)) |
---|
| 667 | + goto out; |
---|
| 668 | + br_mdb_notify(br->dev, mp, pg, RTM_NEWMDB); |
---|
| 669 | + } |
---|
318 | 670 | out: |
---|
319 | 671 | spin_unlock(&br->multicast_lock); |
---|
320 | 672 | } |
---|
321 | 673 | |
---|
322 | | -static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max, |
---|
323 | | - int elasticity) |
---|
| 674 | +static void br_multicast_gc(struct hlist_head *head) |
---|
324 | 675 | { |
---|
325 | | - struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1); |
---|
326 | | - struct net_bridge_mdb_htable *mdb; |
---|
327 | | - int err; |
---|
| 676 | + struct net_bridge_mcast_gc *gcent; |
---|
| 677 | + struct hlist_node *tmp; |
---|
328 | 678 | |
---|
329 | | - mdb = kmalloc(sizeof(*mdb), GFP_ATOMIC); |
---|
330 | | - if (!mdb) |
---|
331 | | - return -ENOMEM; |
---|
332 | | - |
---|
333 | | - mdb->max = max; |
---|
334 | | - mdb->old = old; |
---|
335 | | - |
---|
336 | | - mdb->mhash = kcalloc(max, sizeof(*mdb->mhash), GFP_ATOMIC); |
---|
337 | | - if (!mdb->mhash) { |
---|
338 | | - kfree(mdb); |
---|
339 | | - return -ENOMEM; |
---|
| 679 | + hlist_for_each_entry_safe(gcent, tmp, head, gc_node) { |
---|
| 680 | + hlist_del_init(&gcent->gc_node); |
---|
| 681 | + gcent->destroy(gcent); |
---|
340 | 682 | } |
---|
341 | | - |
---|
342 | | - mdb->size = old ? old->size : 0; |
---|
343 | | - mdb->ver = old ? old->ver ^ 1 : 0; |
---|
344 | | - |
---|
345 | | - if (!old || elasticity) |
---|
346 | | - get_random_bytes(&mdb->secret, sizeof(mdb->secret)); |
---|
347 | | - else |
---|
348 | | - mdb->secret = old->secret; |
---|
349 | | - |
---|
350 | | - if (!old) |
---|
351 | | - goto out; |
---|
352 | | - |
---|
353 | | - err = br_mdb_copy(mdb, old, elasticity); |
---|
354 | | - if (err) { |
---|
355 | | - kfree(mdb->mhash); |
---|
356 | | - kfree(mdb); |
---|
357 | | - return err; |
---|
358 | | - } |
---|
359 | | - |
---|
360 | | - br_mdb_rehash_seq++; |
---|
361 | | - call_rcu_bh(&mdb->rcu, br_mdb_free); |
---|
362 | | - |
---|
363 | | -out: |
---|
364 | | - rcu_assign_pointer(*mdbp, mdb); |
---|
365 | | - |
---|
366 | | - return 0; |
---|
367 | 683 | } |
---|
368 | 684 | |
---|
369 | 685 | static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, |
---|
370 | | - __be32 group, |
---|
371 | | - u8 *igmp_type) |
---|
| 686 | + struct net_bridge_port_group *pg, |
---|
| 687 | + __be32 ip_dst, __be32 group, |
---|
| 688 | + bool with_srcs, bool over_lmqt, |
---|
| 689 | + u8 sflag, u8 *igmp_type, |
---|
| 690 | + bool *need_rexmit) |
---|
372 | 691 | { |
---|
| 692 | + struct net_bridge_port *p = pg ? pg->key.port : NULL; |
---|
| 693 | + struct net_bridge_group_src *ent; |
---|
| 694 | + size_t pkt_size, igmp_hdr_size; |
---|
| 695 | + unsigned long now = jiffies; |
---|
373 | 696 | struct igmpv3_query *ihv3; |
---|
374 | | - size_t igmp_hdr_size; |
---|
| 697 | + void *csum_start = NULL; |
---|
| 698 | + __sum16 *csum = NULL; |
---|
375 | 699 | struct sk_buff *skb; |
---|
376 | 700 | struct igmphdr *ih; |
---|
377 | 701 | struct ethhdr *eth; |
---|
| 702 | + unsigned long lmqt; |
---|
378 | 703 | struct iphdr *iph; |
---|
| 704 | + u16 lmqt_srcs = 0; |
---|
379 | 705 | |
---|
380 | 706 | igmp_hdr_size = sizeof(*ih); |
---|
381 | | - if (br->multicast_igmp_version == 3) |
---|
| 707 | + if (br->multicast_igmp_version == 3) { |
---|
382 | 708 | igmp_hdr_size = sizeof(*ihv3); |
---|
383 | | - skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*iph) + |
---|
384 | | - igmp_hdr_size + 4); |
---|
| 709 | + if (pg && with_srcs) { |
---|
| 710 | + lmqt = now + (br->multicast_last_member_interval * |
---|
| 711 | + br->multicast_last_member_count); |
---|
| 712 | + hlist_for_each_entry(ent, &pg->src_list, node) { |
---|
| 713 | + if (over_lmqt == time_after(ent->timer.expires, |
---|
| 714 | + lmqt) && |
---|
| 715 | + ent->src_query_rexmit_cnt > 0) |
---|
| 716 | + lmqt_srcs++; |
---|
| 717 | + } |
---|
| 718 | + |
---|
| 719 | + if (!lmqt_srcs) |
---|
| 720 | + return NULL; |
---|
| 721 | + igmp_hdr_size += lmqt_srcs * sizeof(__be32); |
---|
| 722 | + } |
---|
| 723 | + } |
---|
| 724 | + |
---|
| 725 | + pkt_size = sizeof(*eth) + sizeof(*iph) + 4 + igmp_hdr_size; |
---|
| 726 | + if ((p && pkt_size > p->dev->mtu) || |
---|
| 727 | + pkt_size > br->dev->mtu) |
---|
| 728 | + return NULL; |
---|
| 729 | + |
---|
| 730 | + skb = netdev_alloc_skb_ip_align(br->dev, pkt_size); |
---|
385 | 731 | if (!skb) |
---|
386 | 732 | goto out; |
---|
387 | 733 | |
---|
.. | .. |
---|
391 | 737 | eth = eth_hdr(skb); |
---|
392 | 738 | |
---|
393 | 739 | ether_addr_copy(eth->h_source, br->dev->dev_addr); |
---|
394 | | - eth->h_dest[0] = 1; |
---|
395 | | - eth->h_dest[1] = 0; |
---|
396 | | - eth->h_dest[2] = 0x5e; |
---|
397 | | - eth->h_dest[3] = 0; |
---|
398 | | - eth->h_dest[4] = 0; |
---|
399 | | - eth->h_dest[5] = 1; |
---|
| 740 | + ip_eth_mc_map(ip_dst, eth->h_dest); |
---|
400 | 741 | eth->h_proto = htons(ETH_P_IP); |
---|
401 | 742 | skb_put(skb, sizeof(*eth)); |
---|
402 | 743 | |
---|
403 | 744 | skb_set_network_header(skb, skb->len); |
---|
404 | 745 | iph = ip_hdr(skb); |
---|
| 746 | + iph->tot_len = htons(pkt_size - sizeof(*eth)); |
---|
405 | 747 | |
---|
406 | 748 | iph->version = 4; |
---|
407 | 749 | iph->ihl = 6; |
---|
408 | 750 | iph->tos = 0xc0; |
---|
409 | | - iph->tot_len = htons(sizeof(*iph) + igmp_hdr_size + 4); |
---|
410 | 751 | iph->id = 0; |
---|
411 | 752 | iph->frag_off = htons(IP_DF); |
---|
412 | 753 | iph->ttl = 1; |
---|
413 | 754 | iph->protocol = IPPROTO_IGMP; |
---|
414 | | - iph->saddr = br->multicast_query_use_ifaddr ? |
---|
| 755 | + iph->saddr = br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR) ? |
---|
415 | 756 | inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0; |
---|
416 | | - iph->daddr = htonl(INADDR_ALLHOSTS_GROUP); |
---|
| 757 | + iph->daddr = ip_dst; |
---|
417 | 758 | ((u8 *)&iph[1])[0] = IPOPT_RA; |
---|
418 | 759 | ((u8 *)&iph[1])[1] = 4; |
---|
419 | 760 | ((u8 *)&iph[1])[2] = 0; |
---|
.. | .. |
---|
433 | 774 | (HZ / IGMP_TIMER_SCALE); |
---|
434 | 775 | ih->group = group; |
---|
435 | 776 | ih->csum = 0; |
---|
436 | | - ih->csum = ip_compute_csum((void *)ih, sizeof(*ih)); |
---|
| 777 | + csum = &ih->csum; |
---|
| 778 | + csum_start = (void *)ih; |
---|
437 | 779 | break; |
---|
438 | 780 | case 3: |
---|
439 | 781 | ihv3 = igmpv3_query_hdr(skb); |
---|
.. | .. |
---|
443 | 785 | (HZ / IGMP_TIMER_SCALE); |
---|
444 | 786 | ihv3->group = group; |
---|
445 | 787 | ihv3->qqic = br->multicast_query_interval / HZ; |
---|
446 | | - ihv3->nsrcs = 0; |
---|
| 788 | + ihv3->nsrcs = htons(lmqt_srcs); |
---|
447 | 789 | ihv3->resv = 0; |
---|
448 | | - ihv3->suppress = 0; |
---|
| 790 | + ihv3->suppress = sflag; |
---|
449 | 791 | ihv3->qrv = 2; |
---|
450 | 792 | ihv3->csum = 0; |
---|
451 | | - ihv3->csum = ip_compute_csum((void *)ihv3, sizeof(*ihv3)); |
---|
| 793 | + csum = &ihv3->csum; |
---|
| 794 | + csum_start = (void *)ihv3; |
---|
| 795 | + if (!pg || !with_srcs) |
---|
| 796 | + break; |
---|
| 797 | + |
---|
| 798 | + lmqt_srcs = 0; |
---|
| 799 | + hlist_for_each_entry(ent, &pg->src_list, node) { |
---|
| 800 | + if (over_lmqt == time_after(ent->timer.expires, |
---|
| 801 | + lmqt) && |
---|
| 802 | + ent->src_query_rexmit_cnt > 0) { |
---|
| 803 | + ihv3->srcs[lmqt_srcs++] = ent->addr.src.ip4; |
---|
| 804 | + ent->src_query_rexmit_cnt--; |
---|
| 805 | + if (need_rexmit && ent->src_query_rexmit_cnt) |
---|
| 806 | + *need_rexmit = true; |
---|
| 807 | + } |
---|
| 808 | + } |
---|
| 809 | + if (WARN_ON(lmqt_srcs != ntohs(ihv3->nsrcs))) { |
---|
| 810 | + kfree_skb(skb); |
---|
| 811 | + return NULL; |
---|
| 812 | + } |
---|
452 | 813 | break; |
---|
453 | 814 | } |
---|
454 | 815 | |
---|
| 816 | + if (WARN_ON(!csum || !csum_start)) { |
---|
| 817 | + kfree_skb(skb); |
---|
| 818 | + return NULL; |
---|
| 819 | + } |
---|
| 820 | + |
---|
| 821 | + *csum = ip_compute_csum(csum_start, igmp_hdr_size); |
---|
455 | 822 | skb_put(skb, igmp_hdr_size); |
---|
456 | 823 | __skb_pull(skb, sizeof(*eth)); |
---|
457 | 824 | |
---|
.. | .. |
---|
461 | 828 | |
---|
462 | 829 | #if IS_ENABLED(CONFIG_IPV6) |
---|
463 | 830 | static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, |
---|
464 | | - const struct in6_addr *grp, |
---|
465 | | - u8 *igmp_type) |
---|
| 831 | + struct net_bridge_port_group *pg, |
---|
| 832 | + const struct in6_addr *ip6_dst, |
---|
| 833 | + const struct in6_addr *group, |
---|
| 834 | + bool with_srcs, bool over_llqt, |
---|
| 835 | + u8 sflag, u8 *igmp_type, |
---|
| 836 | + bool *need_rexmit) |
---|
466 | 837 | { |
---|
| 838 | + struct net_bridge_port *p = pg ? pg->key.port : NULL; |
---|
| 839 | + struct net_bridge_group_src *ent; |
---|
| 840 | + size_t pkt_size, mld_hdr_size; |
---|
| 841 | + unsigned long now = jiffies; |
---|
467 | 842 | struct mld2_query *mld2q; |
---|
| 843 | + void *csum_start = NULL; |
---|
468 | 844 | unsigned long interval; |
---|
| 845 | + __sum16 *csum = NULL; |
---|
469 | 846 | struct ipv6hdr *ip6h; |
---|
470 | 847 | struct mld_msg *mldq; |
---|
471 | | - size_t mld_hdr_size; |
---|
472 | 848 | struct sk_buff *skb; |
---|
| 849 | + unsigned long llqt; |
---|
473 | 850 | struct ethhdr *eth; |
---|
| 851 | + u16 llqt_srcs = 0; |
---|
474 | 852 | u8 *hopopt; |
---|
475 | 853 | |
---|
476 | 854 | mld_hdr_size = sizeof(*mldq); |
---|
477 | | - if (br->multicast_mld_version == 2) |
---|
| 855 | + if (br->multicast_mld_version == 2) { |
---|
478 | 856 | mld_hdr_size = sizeof(*mld2q); |
---|
479 | | - skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*ip6h) + |
---|
480 | | - 8 + mld_hdr_size); |
---|
| 857 | + if (pg && with_srcs) { |
---|
| 858 | + llqt = now + (br->multicast_last_member_interval * |
---|
| 859 | + br->multicast_last_member_count); |
---|
| 860 | + hlist_for_each_entry(ent, &pg->src_list, node) { |
---|
| 861 | + if (over_llqt == time_after(ent->timer.expires, |
---|
| 862 | + llqt) && |
---|
| 863 | + ent->src_query_rexmit_cnt > 0) |
---|
| 864 | + llqt_srcs++; |
---|
| 865 | + } |
---|
| 866 | + |
---|
| 867 | + if (!llqt_srcs) |
---|
| 868 | + return NULL; |
---|
| 869 | + mld_hdr_size += llqt_srcs * sizeof(struct in6_addr); |
---|
| 870 | + } |
---|
| 871 | + } |
---|
| 872 | + |
---|
| 873 | + pkt_size = sizeof(*eth) + sizeof(*ip6h) + 8 + mld_hdr_size; |
---|
| 874 | + if ((p && pkt_size > p->dev->mtu) || |
---|
| 875 | + pkt_size > br->dev->mtu) |
---|
| 876 | + return NULL; |
---|
| 877 | + |
---|
| 878 | + skb = netdev_alloc_skb_ip_align(br->dev, pkt_size); |
---|
481 | 879 | if (!skb) |
---|
482 | 880 | goto out; |
---|
483 | 881 | |
---|
.. | .. |
---|
499 | 897 | ip6h->payload_len = htons(8 + mld_hdr_size); |
---|
500 | 898 | ip6h->nexthdr = IPPROTO_HOPOPTS; |
---|
501 | 899 | ip6h->hop_limit = 1; |
---|
502 | | - ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1)); |
---|
| 900 | + ip6h->daddr = *ip6_dst; |
---|
503 | 901 | if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, |
---|
504 | 902 | &ip6h->saddr)) { |
---|
505 | 903 | kfree_skb(skb); |
---|
506 | | - br->has_ipv6_addr = 0; |
---|
| 904 | + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, false); |
---|
507 | 905 | return NULL; |
---|
508 | 906 | } |
---|
509 | 907 | |
---|
510 | | - br->has_ipv6_addr = 1; |
---|
| 908 | + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); |
---|
511 | 909 | ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); |
---|
512 | 910 | |
---|
513 | 911 | hopopt = (u8 *)(ip6h + 1); |
---|
.. | .. |
---|
524 | 922 | |
---|
525 | 923 | /* ICMPv6 */ |
---|
526 | 924 | skb_set_transport_header(skb, skb->len); |
---|
527 | | - interval = ipv6_addr_any(grp) ? |
---|
| 925 | + interval = ipv6_addr_any(group) ? |
---|
528 | 926 | br->multicast_query_response_interval : |
---|
529 | 927 | br->multicast_last_member_interval; |
---|
530 | 928 | *igmp_type = ICMPV6_MGM_QUERY; |
---|
.. | .. |
---|
536 | 934 | mldq->mld_cksum = 0; |
---|
537 | 935 | mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval)); |
---|
538 | 936 | mldq->mld_reserved = 0; |
---|
539 | | - mldq->mld_mca = *grp; |
---|
540 | | - mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, |
---|
541 | | - sizeof(*mldq), IPPROTO_ICMPV6, |
---|
542 | | - csum_partial(mldq, |
---|
543 | | - sizeof(*mldq), |
---|
544 | | - 0)); |
---|
| 937 | + mldq->mld_mca = *group; |
---|
| 938 | + csum = &mldq->mld_cksum; |
---|
| 939 | + csum_start = (void *)mldq; |
---|
545 | 940 | break; |
---|
546 | 941 | case 2: |
---|
547 | 942 | mld2q = (struct mld2_query *)icmp6_hdr(skb); |
---|
.. | .. |
---|
551 | 946 | mld2q->mld2q_cksum = 0; |
---|
552 | 947 | mld2q->mld2q_resv1 = 0; |
---|
553 | 948 | mld2q->mld2q_resv2 = 0; |
---|
554 | | - mld2q->mld2q_suppress = 0; |
---|
| 949 | + mld2q->mld2q_suppress = sflag; |
---|
555 | 950 | mld2q->mld2q_qrv = 2; |
---|
556 | | - mld2q->mld2q_nsrcs = 0; |
---|
| 951 | + mld2q->mld2q_nsrcs = htons(llqt_srcs); |
---|
557 | 952 | mld2q->mld2q_qqic = br->multicast_query_interval / HZ; |
---|
558 | | - mld2q->mld2q_mca = *grp; |
---|
559 | | - mld2q->mld2q_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, |
---|
560 | | - sizeof(*mld2q), |
---|
561 | | - IPPROTO_ICMPV6, |
---|
562 | | - csum_partial(mld2q, |
---|
563 | | - sizeof(*mld2q), |
---|
564 | | - 0)); |
---|
| 953 | + mld2q->mld2q_mca = *group; |
---|
| 954 | + csum = &mld2q->mld2q_cksum; |
---|
| 955 | + csum_start = (void *)mld2q; |
---|
| 956 | + if (!pg || !with_srcs) |
---|
| 957 | + break; |
---|
| 958 | + |
---|
| 959 | + llqt_srcs = 0; |
---|
| 960 | + hlist_for_each_entry(ent, &pg->src_list, node) { |
---|
| 961 | + if (over_llqt == time_after(ent->timer.expires, |
---|
| 962 | + llqt) && |
---|
| 963 | + ent->src_query_rexmit_cnt > 0) { |
---|
| 964 | + mld2q->mld2q_srcs[llqt_srcs++] = ent->addr.src.ip6; |
---|
| 965 | + ent->src_query_rexmit_cnt--; |
---|
| 966 | + if (need_rexmit && ent->src_query_rexmit_cnt) |
---|
| 967 | + *need_rexmit = true; |
---|
| 968 | + } |
---|
| 969 | + } |
---|
| 970 | + if (WARN_ON(llqt_srcs != ntohs(mld2q->mld2q_nsrcs))) { |
---|
| 971 | + kfree_skb(skb); |
---|
| 972 | + return NULL; |
---|
| 973 | + } |
---|
565 | 974 | break; |
---|
566 | 975 | } |
---|
567 | | - skb_put(skb, mld_hdr_size); |
---|
568 | 976 | |
---|
| 977 | + if (WARN_ON(!csum || !csum_start)) { |
---|
| 978 | + kfree_skb(skb); |
---|
| 979 | + return NULL; |
---|
| 980 | + } |
---|
| 981 | + |
---|
| 982 | + *csum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, mld_hdr_size, |
---|
| 983 | + IPPROTO_ICMPV6, |
---|
| 984 | + csum_partial(csum_start, mld_hdr_size, 0)); |
---|
| 985 | + skb_put(skb, mld_hdr_size); |
---|
569 | 986 | __skb_pull(skb, sizeof(*eth)); |
---|
570 | 987 | |
---|
571 | 988 | out: |
---|
.. | .. |
---|
574 | 991 | #endif |
---|
575 | 992 | |
---|
576 | 993 | static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, |
---|
577 | | - struct br_ip *addr, |
---|
578 | | - u8 *igmp_type) |
---|
| 994 | + struct net_bridge_port_group *pg, |
---|
| 995 | + struct br_ip *ip_dst, |
---|
| 996 | + struct br_ip *group, |
---|
| 997 | + bool with_srcs, bool over_lmqt, |
---|
| 998 | + u8 sflag, u8 *igmp_type, |
---|
| 999 | + bool *need_rexmit) |
---|
579 | 1000 | { |
---|
580 | | - switch (addr->proto) { |
---|
| 1001 | + __be32 ip4_dst; |
---|
| 1002 | + |
---|
| 1003 | + switch (group->proto) { |
---|
581 | 1004 | case htons(ETH_P_IP): |
---|
582 | | - return br_ip4_multicast_alloc_query(br, addr->u.ip4, igmp_type); |
---|
| 1005 | + ip4_dst = ip_dst ? ip_dst->dst.ip4 : htonl(INADDR_ALLHOSTS_GROUP); |
---|
| 1006 | + return br_ip4_multicast_alloc_query(br, pg, |
---|
| 1007 | + ip4_dst, group->dst.ip4, |
---|
| 1008 | + with_srcs, over_lmqt, |
---|
| 1009 | + sflag, igmp_type, |
---|
| 1010 | + need_rexmit); |
---|
583 | 1011 | #if IS_ENABLED(CONFIG_IPV6) |
---|
584 | | - case htons(ETH_P_IPV6): |
---|
585 | | - return br_ip6_multicast_alloc_query(br, &addr->u.ip6, |
---|
586 | | - igmp_type); |
---|
| 1012 | + case htons(ETH_P_IPV6): { |
---|
| 1013 | + struct in6_addr ip6_dst; |
---|
| 1014 | + |
---|
| 1015 | + if (ip_dst) |
---|
| 1016 | + ip6_dst = ip_dst->dst.ip6; |
---|
| 1017 | + else |
---|
| 1018 | + ipv6_addr_set(&ip6_dst, htonl(0xff020000), 0, 0, |
---|
| 1019 | + htonl(1)); |
---|
| 1020 | + |
---|
| 1021 | + return br_ip6_multicast_alloc_query(br, pg, |
---|
| 1022 | + &ip6_dst, &group->dst.ip6, |
---|
| 1023 | + with_srcs, over_lmqt, |
---|
| 1024 | + sflag, igmp_type, |
---|
| 1025 | + need_rexmit); |
---|
| 1026 | + } |
---|
587 | 1027 | #endif |
---|
588 | 1028 | } |
---|
589 | 1029 | return NULL; |
---|
590 | 1030 | } |
---|
591 | 1031 | |
---|
592 | | -static struct net_bridge_mdb_entry *br_multicast_get_group( |
---|
593 | | - struct net_bridge *br, struct net_bridge_port *port, |
---|
594 | | - struct br_ip *group, int hash) |
---|
595 | | -{ |
---|
596 | | - struct net_bridge_mdb_htable *mdb; |
---|
597 | | - struct net_bridge_mdb_entry *mp; |
---|
598 | | - unsigned int count = 0; |
---|
599 | | - unsigned int max; |
---|
600 | | - int elasticity; |
---|
601 | | - int err; |
---|
602 | | - |
---|
603 | | - mdb = rcu_dereference_protected(br->mdb, 1); |
---|
604 | | - hlist_for_each_entry(mp, &mdb->mhash[hash], hlist[mdb->ver]) { |
---|
605 | | - count++; |
---|
606 | | - if (unlikely(br_ip_equal(group, &mp->addr))) |
---|
607 | | - return mp; |
---|
608 | | - } |
---|
609 | | - |
---|
610 | | - elasticity = 0; |
---|
611 | | - max = mdb->max; |
---|
612 | | - |
---|
613 | | - if (unlikely(count > br->hash_elasticity && count)) { |
---|
614 | | - if (net_ratelimit()) |
---|
615 | | - br_info(br, "Multicast hash table " |
---|
616 | | - "chain limit reached: %s\n", |
---|
617 | | - port ? port->dev->name : br->dev->name); |
---|
618 | | - |
---|
619 | | - elasticity = br->hash_elasticity; |
---|
620 | | - } |
---|
621 | | - |
---|
622 | | - if (mdb->size >= max) { |
---|
623 | | - max *= 2; |
---|
624 | | - if (unlikely(max > br->hash_max)) { |
---|
625 | | - br_warn(br, "Multicast hash table maximum of %d " |
---|
626 | | - "reached, disabling snooping: %s\n", |
---|
627 | | - br->hash_max, |
---|
628 | | - port ? port->dev->name : br->dev->name); |
---|
629 | | - err = -E2BIG; |
---|
630 | | -disable: |
---|
631 | | - br->multicast_disabled = 1; |
---|
632 | | - goto err; |
---|
633 | | - } |
---|
634 | | - } |
---|
635 | | - |
---|
636 | | - if (max > mdb->max || elasticity) { |
---|
637 | | - if (mdb->old) { |
---|
638 | | - if (net_ratelimit()) |
---|
639 | | - br_info(br, "Multicast hash table " |
---|
640 | | - "on fire: %s\n", |
---|
641 | | - port ? port->dev->name : br->dev->name); |
---|
642 | | - err = -EEXIST; |
---|
643 | | - goto err; |
---|
644 | | - } |
---|
645 | | - |
---|
646 | | - err = br_mdb_rehash(&br->mdb, max, elasticity); |
---|
647 | | - if (err) { |
---|
648 | | - br_warn(br, "Cannot rehash multicast " |
---|
649 | | - "hash table, disabling snooping: %s, %d, %d\n", |
---|
650 | | - port ? port->dev->name : br->dev->name, |
---|
651 | | - mdb->size, err); |
---|
652 | | - goto disable; |
---|
653 | | - } |
---|
654 | | - |
---|
655 | | - err = -EAGAIN; |
---|
656 | | - goto err; |
---|
657 | | - } |
---|
658 | | - |
---|
659 | | - return NULL; |
---|
660 | | - |
---|
661 | | -err: |
---|
662 | | - mp = ERR_PTR(err); |
---|
663 | | - return mp; |
---|
664 | | -} |
---|
665 | | - |
---|
666 | 1032 | struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, |
---|
667 | | - struct net_bridge_port *p, |
---|
668 | 1033 | struct br_ip *group) |
---|
669 | 1034 | { |
---|
670 | | - struct net_bridge_mdb_htable *mdb; |
---|
671 | 1035 | struct net_bridge_mdb_entry *mp; |
---|
672 | | - int hash; |
---|
673 | 1036 | int err; |
---|
674 | 1037 | |
---|
675 | | - mdb = rcu_dereference_protected(br->mdb, 1); |
---|
676 | | - if (!mdb) { |
---|
677 | | - err = br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0); |
---|
678 | | - if (err) |
---|
679 | | - return ERR_PTR(err); |
---|
680 | | - goto rehash; |
---|
681 | | - } |
---|
| 1038 | + mp = br_mdb_ip_get(br, group); |
---|
| 1039 | + if (mp) |
---|
| 1040 | + return mp; |
---|
682 | 1041 | |
---|
683 | | - hash = br_ip_hash(mdb, group); |
---|
684 | | - mp = br_multicast_get_group(br, p, group, hash); |
---|
685 | | - switch (PTR_ERR(mp)) { |
---|
686 | | - case 0: |
---|
687 | | - break; |
---|
688 | | - |
---|
689 | | - case -EAGAIN: |
---|
690 | | -rehash: |
---|
691 | | - mdb = rcu_dereference_protected(br->mdb, 1); |
---|
692 | | - hash = br_ip_hash(mdb, group); |
---|
693 | | - break; |
---|
694 | | - |
---|
695 | | - default: |
---|
696 | | - goto out; |
---|
| 1042 | + if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) { |
---|
| 1043 | + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false); |
---|
| 1044 | + return ERR_PTR(-E2BIG); |
---|
697 | 1045 | } |
---|
698 | 1046 | |
---|
699 | 1047 | mp = kzalloc(sizeof(*mp), GFP_ATOMIC); |
---|
.. | .. |
---|
702 | 1050 | |
---|
703 | 1051 | mp->br = br; |
---|
704 | 1052 | mp->addr = *group; |
---|
| 1053 | + mp->mcast_gc.destroy = br_multicast_destroy_mdb_entry; |
---|
705 | 1054 | timer_setup(&mp->timer, br_multicast_group_expired, 0); |
---|
| 1055 | + err = rhashtable_lookup_insert_fast(&br->mdb_hash_tbl, &mp->rhnode, |
---|
| 1056 | + br_mdb_rht_params); |
---|
| 1057 | + if (err) { |
---|
| 1058 | + kfree(mp); |
---|
| 1059 | + mp = ERR_PTR(err); |
---|
| 1060 | + } else { |
---|
| 1061 | + hlist_add_head_rcu(&mp->mdb_node, &br->mdb_list); |
---|
| 1062 | + } |
---|
706 | 1063 | |
---|
707 | | - hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); |
---|
708 | | - mdb->size++; |
---|
| 1064 | + return mp; |
---|
| 1065 | +} |
---|
| 1066 | + |
---|
| 1067 | +static void br_multicast_group_src_expired(struct timer_list *t) |
---|
| 1068 | +{ |
---|
| 1069 | + struct net_bridge_group_src *src = from_timer(src, t, timer); |
---|
| 1070 | + struct net_bridge_port_group *pg; |
---|
| 1071 | + struct net_bridge *br = src->br; |
---|
| 1072 | + |
---|
| 1073 | + spin_lock(&br->multicast_lock); |
---|
| 1074 | + if (hlist_unhashed(&src->node) || !netif_running(br->dev) || |
---|
| 1075 | + timer_pending(&src->timer)) |
---|
| 1076 | + goto out; |
---|
| 1077 | + |
---|
| 1078 | + pg = src->pg; |
---|
| 1079 | + if (pg->filter_mode == MCAST_INCLUDE) { |
---|
| 1080 | + br_multicast_del_group_src(src); |
---|
| 1081 | + if (!hlist_empty(&pg->src_list)) |
---|
| 1082 | + goto out; |
---|
| 1083 | + br_multicast_find_del_pg(br, pg); |
---|
| 1084 | + } else { |
---|
| 1085 | + br_multicast_fwd_src_handle(src); |
---|
| 1086 | + } |
---|
709 | 1087 | |
---|
710 | 1088 | out: |
---|
711 | | - return mp; |
---|
| 1089 | + spin_unlock(&br->multicast_lock); |
---|
| 1090 | +} |
---|
| 1091 | + |
---|
| 1092 | +static struct net_bridge_group_src * |
---|
| 1093 | +br_multicast_find_group_src(struct net_bridge_port_group *pg, struct br_ip *ip) |
---|
| 1094 | +{ |
---|
| 1095 | + struct net_bridge_group_src *ent; |
---|
| 1096 | + |
---|
| 1097 | + switch (ip->proto) { |
---|
| 1098 | + case htons(ETH_P_IP): |
---|
| 1099 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1100 | + if (ip->src.ip4 == ent->addr.src.ip4) |
---|
| 1101 | + return ent; |
---|
| 1102 | + break; |
---|
| 1103 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 1104 | + case htons(ETH_P_IPV6): |
---|
| 1105 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1106 | + if (!ipv6_addr_cmp(&ent->addr.src.ip6, &ip->src.ip6)) |
---|
| 1107 | + return ent; |
---|
| 1108 | + break; |
---|
| 1109 | +#endif |
---|
| 1110 | + } |
---|
| 1111 | + |
---|
| 1112 | + return NULL; |
---|
| 1113 | +} |
---|
| 1114 | + |
---|
| 1115 | +static struct net_bridge_group_src * |
---|
| 1116 | +br_multicast_new_group_src(struct net_bridge_port_group *pg, struct br_ip *src_ip) |
---|
| 1117 | +{ |
---|
| 1118 | + struct net_bridge_group_src *grp_src; |
---|
| 1119 | + |
---|
| 1120 | + if (unlikely(pg->src_ents >= PG_SRC_ENT_LIMIT)) |
---|
| 1121 | + return NULL; |
---|
| 1122 | + |
---|
| 1123 | + switch (src_ip->proto) { |
---|
| 1124 | + case htons(ETH_P_IP): |
---|
| 1125 | + if (ipv4_is_zeronet(src_ip->src.ip4) || |
---|
| 1126 | + ipv4_is_multicast(src_ip->src.ip4)) |
---|
| 1127 | + return NULL; |
---|
| 1128 | + break; |
---|
| 1129 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 1130 | + case htons(ETH_P_IPV6): |
---|
| 1131 | + if (ipv6_addr_any(&src_ip->src.ip6) || |
---|
| 1132 | + ipv6_addr_is_multicast(&src_ip->src.ip6)) |
---|
| 1133 | + return NULL; |
---|
| 1134 | + break; |
---|
| 1135 | +#endif |
---|
| 1136 | + } |
---|
| 1137 | + |
---|
| 1138 | + grp_src = kzalloc(sizeof(*grp_src), GFP_ATOMIC); |
---|
| 1139 | + if (unlikely(!grp_src)) |
---|
| 1140 | + return NULL; |
---|
| 1141 | + |
---|
| 1142 | + grp_src->pg = pg; |
---|
| 1143 | + grp_src->br = pg->key.port->br; |
---|
| 1144 | + grp_src->addr = *src_ip; |
---|
| 1145 | + grp_src->mcast_gc.destroy = br_multicast_destroy_group_src; |
---|
| 1146 | + timer_setup(&grp_src->timer, br_multicast_group_src_expired, 0); |
---|
| 1147 | + |
---|
| 1148 | + hlist_add_head_rcu(&grp_src->node, &pg->src_list); |
---|
| 1149 | + pg->src_ents++; |
---|
| 1150 | + |
---|
| 1151 | + return grp_src; |
---|
712 | 1152 | } |
---|
713 | 1153 | |
---|
714 | 1154 | struct net_bridge_port_group *br_multicast_new_port_group( |
---|
.. | .. |
---|
716 | 1156 | struct br_ip *group, |
---|
717 | 1157 | struct net_bridge_port_group __rcu *next, |
---|
718 | 1158 | unsigned char flags, |
---|
719 | | - const unsigned char *src) |
---|
| 1159 | + const unsigned char *src, |
---|
| 1160 | + u8 filter_mode, |
---|
| 1161 | + u8 rt_protocol) |
---|
720 | 1162 | { |
---|
721 | 1163 | struct net_bridge_port_group *p; |
---|
722 | 1164 | |
---|
.. | .. |
---|
724 | 1166 | if (unlikely(!p)) |
---|
725 | 1167 | return NULL; |
---|
726 | 1168 | |
---|
727 | | - p->addr = *group; |
---|
728 | | - p->port = port; |
---|
| 1169 | + p->key.addr = *group; |
---|
| 1170 | + p->key.port = port; |
---|
729 | 1171 | p->flags = flags; |
---|
| 1172 | + p->filter_mode = filter_mode; |
---|
| 1173 | + p->rt_protocol = rt_protocol; |
---|
| 1174 | + p->mcast_gc.destroy = br_multicast_destroy_port_group; |
---|
| 1175 | + INIT_HLIST_HEAD(&p->src_list); |
---|
| 1176 | + |
---|
| 1177 | + if (!br_multicast_is_star_g(group) && |
---|
| 1178 | + rhashtable_lookup_insert_fast(&port->br->sg_port_tbl, &p->rhnode, |
---|
| 1179 | + br_sg_port_rht_params)) { |
---|
| 1180 | + kfree(p); |
---|
| 1181 | + return NULL; |
---|
| 1182 | + } |
---|
| 1183 | + |
---|
730 | 1184 | rcu_assign_pointer(p->next, next); |
---|
731 | | - hlist_add_head(&p->mglist, &port->mglist); |
---|
732 | 1185 | timer_setup(&p->timer, br_multicast_port_group_expired, 0); |
---|
| 1186 | + timer_setup(&p->rexmit_timer, br_multicast_port_group_rexmit, 0); |
---|
| 1187 | + hlist_add_head(&p->mglist, &port->mglist); |
---|
733 | 1188 | |
---|
734 | 1189 | if (src) |
---|
735 | 1190 | memcpy(p->eth_addr, src, ETH_ALEN); |
---|
736 | 1191 | else |
---|
737 | | - memset(p->eth_addr, 0xff, ETH_ALEN); |
---|
| 1192 | + eth_broadcast_addr(p->eth_addr); |
---|
738 | 1193 | |
---|
739 | 1194 | return p; |
---|
740 | 1195 | } |
---|
741 | 1196 | |
---|
742 | | -static bool br_port_group_equal(struct net_bridge_port_group *p, |
---|
743 | | - struct net_bridge_port *port, |
---|
744 | | - const unsigned char *src) |
---|
| 1197 | +void br_multicast_host_join(struct net_bridge_mdb_entry *mp, bool notify) |
---|
745 | 1198 | { |
---|
746 | | - if (p->port != port) |
---|
747 | | - return false; |
---|
748 | | - |
---|
749 | | - if (!(port->flags & BR_MULTICAST_TO_UNICAST)) |
---|
750 | | - return true; |
---|
751 | | - |
---|
752 | | - return ether_addr_equal(src, p->eth_addr); |
---|
| 1199 | + if (!mp->host_joined) { |
---|
| 1200 | + mp->host_joined = true; |
---|
| 1201 | + if (br_multicast_is_star_g(&mp->addr)) |
---|
| 1202 | + br_multicast_star_g_host_state(mp); |
---|
| 1203 | + if (notify) |
---|
| 1204 | + br_mdb_notify(mp->br->dev, mp, NULL, RTM_NEWMDB); |
---|
| 1205 | + } |
---|
| 1206 | + mod_timer(&mp->timer, jiffies + mp->br->multicast_membership_interval); |
---|
753 | 1207 | } |
---|
754 | 1208 | |
---|
755 | | -static int br_multicast_add_group(struct net_bridge *br, |
---|
756 | | - struct net_bridge_port *port, |
---|
757 | | - struct br_ip *group, |
---|
758 | | - const unsigned char *src) |
---|
| 1209 | +void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify) |
---|
| 1210 | +{ |
---|
| 1211 | + if (!mp->host_joined) |
---|
| 1212 | + return; |
---|
| 1213 | + |
---|
| 1214 | + mp->host_joined = false; |
---|
| 1215 | + if (br_multicast_is_star_g(&mp->addr)) |
---|
| 1216 | + br_multicast_star_g_host_state(mp); |
---|
| 1217 | + if (notify) |
---|
| 1218 | + br_mdb_notify(mp->br->dev, mp, NULL, RTM_DELMDB); |
---|
| 1219 | +} |
---|
| 1220 | + |
---|
| 1221 | +static struct net_bridge_port_group * |
---|
| 1222 | +__br_multicast_add_group(struct net_bridge *br, |
---|
| 1223 | + struct net_bridge_port *port, |
---|
| 1224 | + struct br_ip *group, |
---|
| 1225 | + const unsigned char *src, |
---|
| 1226 | + u8 filter_mode, |
---|
| 1227 | + bool igmpv2_mldv1, |
---|
| 1228 | + bool blocked) |
---|
759 | 1229 | { |
---|
760 | 1230 | struct net_bridge_port_group __rcu **pp; |
---|
761 | | - struct net_bridge_port_group *p; |
---|
| 1231 | + struct net_bridge_port_group *p = NULL; |
---|
762 | 1232 | struct net_bridge_mdb_entry *mp; |
---|
763 | 1233 | unsigned long now = jiffies; |
---|
764 | | - int err; |
---|
765 | 1234 | |
---|
766 | | - spin_lock(&br->multicast_lock); |
---|
767 | 1235 | if (!netif_running(br->dev) || |
---|
768 | 1236 | (port && port->state == BR_STATE_DISABLED)) |
---|
769 | 1237 | goto out; |
---|
770 | 1238 | |
---|
771 | | - mp = br_multicast_new_group(br, port, group); |
---|
772 | | - err = PTR_ERR(mp); |
---|
| 1239 | + mp = br_multicast_new_group(br, group); |
---|
773 | 1240 | if (IS_ERR(mp)) |
---|
774 | | - goto err; |
---|
| 1241 | + return ERR_PTR(PTR_ERR(mp)); |
---|
775 | 1242 | |
---|
776 | 1243 | if (!port) { |
---|
777 | | - if (!mp->host_joined) { |
---|
778 | | - mp->host_joined = true; |
---|
779 | | - br_mdb_notify(br->dev, NULL, &mp->addr, RTM_NEWMDB, 0); |
---|
780 | | - } |
---|
781 | | - mod_timer(&mp->timer, now + br->multicast_membership_interval); |
---|
| 1244 | + br_multicast_host_join(mp, true); |
---|
782 | 1245 | goto out; |
---|
783 | 1246 | } |
---|
784 | 1247 | |
---|
.. | .. |
---|
787 | 1250 | pp = &p->next) { |
---|
788 | 1251 | if (br_port_group_equal(p, port, src)) |
---|
789 | 1252 | goto found; |
---|
790 | | - if ((unsigned long)p->port < (unsigned long)port) |
---|
| 1253 | + if ((unsigned long)p->key.port < (unsigned long)port) |
---|
791 | 1254 | break; |
---|
792 | 1255 | } |
---|
793 | 1256 | |
---|
794 | | - p = br_multicast_new_port_group(port, group, *pp, 0, src); |
---|
795 | | - if (unlikely(!p)) |
---|
796 | | - goto err; |
---|
| 1257 | + p = br_multicast_new_port_group(port, group, *pp, 0, src, filter_mode, |
---|
| 1258 | + RTPROT_KERNEL); |
---|
| 1259 | + if (unlikely(!p)) { |
---|
| 1260 | + p = ERR_PTR(-ENOMEM); |
---|
| 1261 | + goto out; |
---|
| 1262 | + } |
---|
797 | 1263 | rcu_assign_pointer(*pp, p); |
---|
798 | | - br_mdb_notify(br->dev, port, group, RTM_NEWMDB, 0); |
---|
| 1264 | + if (blocked) |
---|
| 1265 | + p->flags |= MDB_PG_FLAGS_BLOCKED; |
---|
| 1266 | + br_mdb_notify(br->dev, mp, p, RTM_NEWMDB); |
---|
799 | 1267 | |
---|
800 | 1268 | found: |
---|
801 | | - mod_timer(&p->timer, now + br->multicast_membership_interval); |
---|
802 | | -out: |
---|
803 | | - err = 0; |
---|
| 1269 | + if (igmpv2_mldv1) |
---|
| 1270 | + mod_timer(&p->timer, now + br->multicast_membership_interval); |
---|
804 | 1271 | |
---|
805 | | -err: |
---|
| 1272 | +out: |
---|
| 1273 | + return p; |
---|
| 1274 | +} |
---|
| 1275 | + |
---|
| 1276 | +static int br_multicast_add_group(struct net_bridge *br, |
---|
| 1277 | + struct net_bridge_port *port, |
---|
| 1278 | + struct br_ip *group, |
---|
| 1279 | + const unsigned char *src, |
---|
| 1280 | + u8 filter_mode, |
---|
| 1281 | + bool igmpv2_mldv1) |
---|
| 1282 | +{ |
---|
| 1283 | + struct net_bridge_port_group *pg; |
---|
| 1284 | + int err; |
---|
| 1285 | + |
---|
| 1286 | + spin_lock(&br->multicast_lock); |
---|
| 1287 | + pg = __br_multicast_add_group(br, port, group, src, filter_mode, |
---|
| 1288 | + igmpv2_mldv1, false); |
---|
| 1289 | + /* NULL is considered valid for host joined groups */ |
---|
| 1290 | + err = IS_ERR(pg) ? PTR_ERR(pg) : 0; |
---|
806 | 1291 | spin_unlock(&br->multicast_lock); |
---|
| 1292 | + |
---|
807 | 1293 | return err; |
---|
808 | 1294 | } |
---|
809 | 1295 | |
---|
.. | .. |
---|
811 | 1297 | struct net_bridge_port *port, |
---|
812 | 1298 | __be32 group, |
---|
813 | 1299 | __u16 vid, |
---|
814 | | - const unsigned char *src) |
---|
| 1300 | + const unsigned char *src, |
---|
| 1301 | + bool igmpv2) |
---|
815 | 1302 | { |
---|
816 | 1303 | struct br_ip br_group; |
---|
| 1304 | + u8 filter_mode; |
---|
817 | 1305 | |
---|
818 | 1306 | if (ipv4_is_local_multicast(group)) |
---|
819 | 1307 | return 0; |
---|
820 | 1308 | |
---|
821 | | - br_group.u.ip4 = group; |
---|
| 1309 | + memset(&br_group, 0, sizeof(br_group)); |
---|
| 1310 | + br_group.dst.ip4 = group; |
---|
822 | 1311 | br_group.proto = htons(ETH_P_IP); |
---|
823 | 1312 | br_group.vid = vid; |
---|
| 1313 | + filter_mode = igmpv2 ? MCAST_EXCLUDE : MCAST_INCLUDE; |
---|
824 | 1314 | |
---|
825 | | - return br_multicast_add_group(br, port, &br_group, src); |
---|
| 1315 | + return br_multicast_add_group(br, port, &br_group, src, filter_mode, |
---|
| 1316 | + igmpv2); |
---|
826 | 1317 | } |
---|
827 | 1318 | |
---|
828 | 1319 | #if IS_ENABLED(CONFIG_IPV6) |
---|
.. | .. |
---|
830 | 1321 | struct net_bridge_port *port, |
---|
831 | 1322 | const struct in6_addr *group, |
---|
832 | 1323 | __u16 vid, |
---|
833 | | - const unsigned char *src) |
---|
| 1324 | + const unsigned char *src, |
---|
| 1325 | + bool mldv1) |
---|
834 | 1326 | { |
---|
835 | 1327 | struct br_ip br_group; |
---|
| 1328 | + u8 filter_mode; |
---|
836 | 1329 | |
---|
837 | 1330 | if (ipv6_addr_is_ll_all_nodes(group)) |
---|
838 | 1331 | return 0; |
---|
839 | 1332 | |
---|
840 | | - br_group.u.ip6 = *group; |
---|
| 1333 | + memset(&br_group, 0, sizeof(br_group)); |
---|
| 1334 | + br_group.dst.ip6 = *group; |
---|
841 | 1335 | br_group.proto = htons(ETH_P_IPV6); |
---|
842 | 1336 | br_group.vid = vid; |
---|
| 1337 | + filter_mode = mldv1 ? MCAST_EXCLUDE : MCAST_INCLUDE; |
---|
843 | 1338 | |
---|
844 | | - return br_multicast_add_group(br, port, &br_group, src); |
---|
| 1339 | + return br_multicast_add_group(br, port, &br_group, src, filter_mode, |
---|
| 1340 | + mldv1); |
---|
845 | 1341 | } |
---|
846 | 1342 | #endif |
---|
847 | 1343 | |
---|
.. | .. |
---|
894 | 1390 | struct bridge_mcast_own_query *query) |
---|
895 | 1391 | { |
---|
896 | 1392 | spin_lock(&br->multicast_lock); |
---|
897 | | - if (!netif_running(br->dev) || br->multicast_disabled) |
---|
| 1393 | + if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
898 | 1394 | goto out; |
---|
899 | 1395 | |
---|
900 | 1396 | br_multicast_start_querier(br, query); |
---|
.. | .. |
---|
924 | 1420 | struct sk_buff *skb) |
---|
925 | 1421 | { |
---|
926 | 1422 | if (ip->proto == htons(ETH_P_IP)) |
---|
927 | | - br->ip4_querier.addr.u.ip4 = ip_hdr(skb)->saddr; |
---|
| 1423 | + br->ip4_querier.addr.src.ip4 = ip_hdr(skb)->saddr; |
---|
928 | 1424 | #if IS_ENABLED(CONFIG_IPV6) |
---|
929 | 1425 | else |
---|
930 | | - br->ip6_querier.addr.u.ip6 = ipv6_hdr(skb)->saddr; |
---|
| 1426 | + br->ip6_querier.addr.src.ip6 = ipv6_hdr(skb)->saddr; |
---|
931 | 1427 | #endif |
---|
932 | 1428 | } |
---|
933 | 1429 | |
---|
934 | 1430 | static void __br_multicast_send_query(struct net_bridge *br, |
---|
935 | 1431 | struct net_bridge_port *port, |
---|
936 | | - struct br_ip *ip) |
---|
| 1432 | + struct net_bridge_port_group *pg, |
---|
| 1433 | + struct br_ip *ip_dst, |
---|
| 1434 | + struct br_ip *group, |
---|
| 1435 | + bool with_srcs, |
---|
| 1436 | + u8 sflag, |
---|
| 1437 | + bool *need_rexmit) |
---|
937 | 1438 | { |
---|
| 1439 | + bool over_lmqt = !!sflag; |
---|
938 | 1440 | struct sk_buff *skb; |
---|
939 | 1441 | u8 igmp_type; |
---|
940 | 1442 | |
---|
941 | | - skb = br_multicast_alloc_query(br, ip, &igmp_type); |
---|
| 1443 | +again_under_lmqt: |
---|
| 1444 | + skb = br_multicast_alloc_query(br, pg, ip_dst, group, with_srcs, |
---|
| 1445 | + over_lmqt, sflag, &igmp_type, |
---|
| 1446 | + need_rexmit); |
---|
942 | 1447 | if (!skb) |
---|
943 | 1448 | return; |
---|
944 | 1449 | |
---|
.. | .. |
---|
949 | 1454 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, |
---|
950 | 1455 | dev_net(port->dev), NULL, skb, NULL, skb->dev, |
---|
951 | 1456 | br_dev_queue_push_xmit); |
---|
| 1457 | + |
---|
| 1458 | + if (over_lmqt && with_srcs && sflag) { |
---|
| 1459 | + over_lmqt = false; |
---|
| 1460 | + goto again_under_lmqt; |
---|
| 1461 | + } |
---|
952 | 1462 | } else { |
---|
953 | | - br_multicast_select_own_querier(br, ip, skb); |
---|
| 1463 | + br_multicast_select_own_querier(br, group, skb); |
---|
954 | 1464 | br_multicast_count(br, port, skb, igmp_type, |
---|
955 | 1465 | BR_MCAST_DIR_RX); |
---|
956 | 1466 | netif_rx(skb); |
---|
.. | .. |
---|
965 | 1475 | struct br_ip br_group; |
---|
966 | 1476 | unsigned long time; |
---|
967 | 1477 | |
---|
968 | | - if (!netif_running(br->dev) || br->multicast_disabled || |
---|
969 | | - !br->multicast_querier) |
---|
| 1478 | + if (!netif_running(br->dev) || |
---|
| 1479 | + !br_opt_get(br, BROPT_MULTICAST_ENABLED) || |
---|
| 1480 | + !br_opt_get(br, BROPT_MULTICAST_QUERIER)) |
---|
970 | 1481 | return; |
---|
971 | 1482 | |
---|
972 | | - memset(&br_group.u, 0, sizeof(br_group.u)); |
---|
| 1483 | + memset(&br_group.dst, 0, sizeof(br_group.dst)); |
---|
973 | 1484 | |
---|
974 | 1485 | if (port ? (own_query == &port->ip4_own_query) : |
---|
975 | 1486 | (own_query == &br->ip4_own_query)) { |
---|
.. | .. |
---|
985 | 1496 | if (!other_query || timer_pending(&other_query->timer)) |
---|
986 | 1497 | return; |
---|
987 | 1498 | |
---|
988 | | - __br_multicast_send_query(br, port, &br_group); |
---|
| 1499 | + __br_multicast_send_query(br, port, NULL, NULL, &br_group, false, 0, |
---|
| 1500 | + NULL); |
---|
989 | 1501 | |
---|
990 | 1502 | time = jiffies; |
---|
991 | 1503 | time += own_query->startup_sent < br->multicast_startup_query_count ? |
---|
.. | .. |
---|
1030 | 1542 | } |
---|
1031 | 1543 | #endif |
---|
1032 | 1544 | |
---|
| 1545 | +static void br_multicast_port_group_rexmit(struct timer_list *t) |
---|
| 1546 | +{ |
---|
| 1547 | + struct net_bridge_port_group *pg = from_timer(pg, t, rexmit_timer); |
---|
| 1548 | + struct bridge_mcast_other_query *other_query = NULL; |
---|
| 1549 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1550 | + bool need_rexmit = false; |
---|
| 1551 | + |
---|
| 1552 | + spin_lock(&br->multicast_lock); |
---|
| 1553 | + if (!netif_running(br->dev) || hlist_unhashed(&pg->mglist) || |
---|
| 1554 | + !br_opt_get(br, BROPT_MULTICAST_ENABLED) || |
---|
| 1555 | + !br_opt_get(br, BROPT_MULTICAST_QUERIER)) |
---|
| 1556 | + goto out; |
---|
| 1557 | + |
---|
| 1558 | + if (pg->key.addr.proto == htons(ETH_P_IP)) |
---|
| 1559 | + other_query = &br->ip4_other_query; |
---|
| 1560 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 1561 | + else |
---|
| 1562 | + other_query = &br->ip6_other_query; |
---|
| 1563 | +#endif |
---|
| 1564 | + |
---|
| 1565 | + if (!other_query || timer_pending(&other_query->timer)) |
---|
| 1566 | + goto out; |
---|
| 1567 | + |
---|
| 1568 | + if (pg->grp_query_rexmit_cnt) { |
---|
| 1569 | + pg->grp_query_rexmit_cnt--; |
---|
| 1570 | + __br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, |
---|
| 1571 | + &pg->key.addr, false, 1, NULL); |
---|
| 1572 | + } |
---|
| 1573 | + __br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, |
---|
| 1574 | + &pg->key.addr, true, 0, &need_rexmit); |
---|
| 1575 | + |
---|
| 1576 | + if (pg->grp_query_rexmit_cnt || need_rexmit) |
---|
| 1577 | + mod_timer(&pg->rexmit_timer, jiffies + |
---|
| 1578 | + br->multicast_last_member_interval); |
---|
| 1579 | +out: |
---|
| 1580 | + spin_unlock(&br->multicast_lock); |
---|
| 1581 | +} |
---|
| 1582 | + |
---|
1033 | 1583 | static void br_mc_disabled_update(struct net_device *dev, bool value) |
---|
1034 | 1584 | { |
---|
1035 | 1585 | struct switchdev_attr attr = { |
---|
1036 | 1586 | .orig_dev = dev, |
---|
1037 | 1587 | .id = SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, |
---|
1038 | 1588 | .flags = SWITCHDEV_F_DEFER, |
---|
1039 | | - .u.mc_disabled = value, |
---|
| 1589 | + .u.mc_disabled = !value, |
---|
1040 | 1590 | }; |
---|
1041 | 1591 | |
---|
1042 | 1592 | switchdev_port_attr_set(dev, &attr); |
---|
.. | .. |
---|
1054 | 1604 | timer_setup(&port->ip6_own_query.timer, |
---|
1055 | 1605 | br_ip6_multicast_port_query_expired, 0); |
---|
1056 | 1606 | #endif |
---|
1057 | | - br_mc_disabled_update(port->dev, port->br->multicast_disabled); |
---|
| 1607 | + br_mc_disabled_update(port->dev, |
---|
| 1608 | + br_opt_get(port->br, BROPT_MULTICAST_ENABLED)); |
---|
1058 | 1609 | |
---|
1059 | 1610 | port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats); |
---|
1060 | 1611 | if (!port->mcast_stats) |
---|
.. | .. |
---|
1067 | 1618 | { |
---|
1068 | 1619 | struct net_bridge *br = port->br; |
---|
1069 | 1620 | struct net_bridge_port_group *pg; |
---|
| 1621 | + HLIST_HEAD(deleted_head); |
---|
1070 | 1622 | struct hlist_node *n; |
---|
1071 | 1623 | |
---|
1072 | 1624 | /* Take care of the remaining groups, only perm ones should be left */ |
---|
1073 | 1625 | spin_lock_bh(&br->multicast_lock); |
---|
1074 | 1626 | hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) |
---|
1075 | | - br_multicast_del_pg(br, pg); |
---|
| 1627 | + br_multicast_find_del_pg(br, pg); |
---|
| 1628 | + hlist_move_list(&br->mcast_gc_list, &deleted_head); |
---|
1076 | 1629 | spin_unlock_bh(&br->multicast_lock); |
---|
| 1630 | + br_multicast_gc(&deleted_head); |
---|
1077 | 1631 | del_timer_sync(&port->multicast_router_timer); |
---|
1078 | 1632 | free_percpu(port->mcast_stats); |
---|
1079 | 1633 | } |
---|
.. | .. |
---|
1091 | 1645 | { |
---|
1092 | 1646 | struct net_bridge *br = port->br; |
---|
1093 | 1647 | |
---|
1094 | | - if (br->multicast_disabled || !netif_running(br->dev)) |
---|
| 1648 | + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev)) |
---|
1095 | 1649 | return; |
---|
1096 | 1650 | |
---|
1097 | 1651 | br_multicast_enable(&port->ip4_own_query); |
---|
.. | .. |
---|
1121 | 1675 | spin_lock(&br->multicast_lock); |
---|
1122 | 1676 | hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) |
---|
1123 | 1677 | if (!(pg->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
1124 | | - br_multicast_del_pg(br, pg); |
---|
| 1678 | + br_multicast_find_del_pg(br, pg); |
---|
1125 | 1679 | |
---|
1126 | 1680 | __del_port_router(port); |
---|
1127 | 1681 | |
---|
.. | .. |
---|
1133 | 1687 | spin_unlock(&br->multicast_lock); |
---|
1134 | 1688 | } |
---|
1135 | 1689 | |
---|
| 1690 | +static int __grp_src_delete_marked(struct net_bridge_port_group *pg) |
---|
| 1691 | +{ |
---|
| 1692 | + struct net_bridge_group_src *ent; |
---|
| 1693 | + struct hlist_node *tmp; |
---|
| 1694 | + int deleted = 0; |
---|
| 1695 | + |
---|
| 1696 | + hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node) |
---|
| 1697 | + if (ent->flags & BR_SGRP_F_DELETE) { |
---|
| 1698 | + br_multicast_del_group_src(ent); |
---|
| 1699 | + deleted++; |
---|
| 1700 | + } |
---|
| 1701 | + |
---|
| 1702 | + return deleted; |
---|
| 1703 | +} |
---|
| 1704 | + |
---|
| 1705 | +static void __grp_src_mod_timer(struct net_bridge_group_src *src, |
---|
| 1706 | + unsigned long expires) |
---|
| 1707 | +{ |
---|
| 1708 | + mod_timer(&src->timer, expires); |
---|
| 1709 | + br_multicast_fwd_src_handle(src); |
---|
| 1710 | +} |
---|
| 1711 | + |
---|
| 1712 | +static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg) |
---|
| 1713 | +{ |
---|
| 1714 | + struct bridge_mcast_other_query *other_query = NULL; |
---|
| 1715 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1716 | + u32 lmqc = br->multicast_last_member_count; |
---|
| 1717 | + unsigned long lmqt, lmi, now = jiffies; |
---|
| 1718 | + struct net_bridge_group_src *ent; |
---|
| 1719 | + |
---|
| 1720 | + if (!netif_running(br->dev) || |
---|
| 1721 | + !br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
| 1722 | + return; |
---|
| 1723 | + |
---|
| 1724 | + if (pg->key.addr.proto == htons(ETH_P_IP)) |
---|
| 1725 | + other_query = &br->ip4_other_query; |
---|
| 1726 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 1727 | + else |
---|
| 1728 | + other_query = &br->ip6_other_query; |
---|
| 1729 | +#endif |
---|
| 1730 | + |
---|
| 1731 | + lmqt = now + br_multicast_lmqt(br); |
---|
| 1732 | + hlist_for_each_entry(ent, &pg->src_list, node) { |
---|
| 1733 | + if (ent->flags & BR_SGRP_F_SEND) { |
---|
| 1734 | + ent->flags &= ~BR_SGRP_F_SEND; |
---|
| 1735 | + if (ent->timer.expires > lmqt) { |
---|
| 1736 | + if (br_opt_get(br, BROPT_MULTICAST_QUERIER) && |
---|
| 1737 | + other_query && |
---|
| 1738 | + !timer_pending(&other_query->timer)) |
---|
| 1739 | + ent->src_query_rexmit_cnt = lmqc; |
---|
| 1740 | + __grp_src_mod_timer(ent, lmqt); |
---|
| 1741 | + } |
---|
| 1742 | + } |
---|
| 1743 | + } |
---|
| 1744 | + |
---|
| 1745 | + if (!br_opt_get(br, BROPT_MULTICAST_QUERIER) || |
---|
| 1746 | + !other_query || timer_pending(&other_query->timer)) |
---|
| 1747 | + return; |
---|
| 1748 | + |
---|
| 1749 | + __br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, |
---|
| 1750 | + &pg->key.addr, true, 1, NULL); |
---|
| 1751 | + |
---|
| 1752 | + lmi = now + br->multicast_last_member_interval; |
---|
| 1753 | + if (!timer_pending(&pg->rexmit_timer) || |
---|
| 1754 | + time_after(pg->rexmit_timer.expires, lmi)) |
---|
| 1755 | + mod_timer(&pg->rexmit_timer, lmi); |
---|
| 1756 | +} |
---|
| 1757 | + |
---|
| 1758 | +static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg) |
---|
| 1759 | +{ |
---|
| 1760 | + struct bridge_mcast_other_query *other_query = NULL; |
---|
| 1761 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1762 | + unsigned long now = jiffies, lmi; |
---|
| 1763 | + |
---|
| 1764 | + if (!netif_running(br->dev) || |
---|
| 1765 | + !br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
| 1766 | + return; |
---|
| 1767 | + |
---|
| 1768 | + if (pg->key.addr.proto == htons(ETH_P_IP)) |
---|
| 1769 | + other_query = &br->ip4_other_query; |
---|
| 1770 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 1771 | + else |
---|
| 1772 | + other_query = &br->ip6_other_query; |
---|
| 1773 | +#endif |
---|
| 1774 | + |
---|
| 1775 | + if (br_opt_get(br, BROPT_MULTICAST_QUERIER) && |
---|
| 1776 | + other_query && !timer_pending(&other_query->timer)) { |
---|
| 1777 | + lmi = now + br->multicast_last_member_interval; |
---|
| 1778 | + pg->grp_query_rexmit_cnt = br->multicast_last_member_count - 1; |
---|
| 1779 | + __br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, |
---|
| 1780 | + &pg->key.addr, false, 0, NULL); |
---|
| 1781 | + if (!timer_pending(&pg->rexmit_timer) || |
---|
| 1782 | + time_after(pg->rexmit_timer.expires, lmi)) |
---|
| 1783 | + mod_timer(&pg->rexmit_timer, lmi); |
---|
| 1784 | + } |
---|
| 1785 | + |
---|
| 1786 | + if (pg->filter_mode == MCAST_EXCLUDE && |
---|
| 1787 | + (!timer_pending(&pg->timer) || |
---|
| 1788 | + time_after(pg->timer.expires, now + br_multicast_lmqt(br)))) |
---|
| 1789 | + mod_timer(&pg->timer, now + br_multicast_lmqt(br)); |
---|
| 1790 | +} |
---|
| 1791 | + |
---|
| 1792 | +/* State Msg type New state Actions |
---|
| 1793 | + * INCLUDE (A) IS_IN (B) INCLUDE (A+B) (B)=GMI |
---|
| 1794 | + * INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI |
---|
| 1795 | + * EXCLUDE (X,Y) ALLOW (A) EXCLUDE (X+A,Y-A) (A)=GMI |
---|
| 1796 | + */ |
---|
| 1797 | +static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, |
---|
| 1798 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1799 | +{ |
---|
| 1800 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1801 | + struct net_bridge_group_src *ent; |
---|
| 1802 | + unsigned long now = jiffies; |
---|
| 1803 | + bool changed = false; |
---|
| 1804 | + struct br_ip src_ip; |
---|
| 1805 | + u32 src_idx; |
---|
| 1806 | + |
---|
| 1807 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 1808 | + src_ip.proto = pg->key.addr.proto; |
---|
| 1809 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 1810 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 1811 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 1812 | + if (!ent) { |
---|
| 1813 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 1814 | + if (ent) |
---|
| 1815 | + changed = true; |
---|
| 1816 | + } |
---|
| 1817 | + |
---|
| 1818 | + if (ent) |
---|
| 1819 | + __grp_src_mod_timer(ent, now + br_multicast_gmi(br)); |
---|
| 1820 | + srcs += src_size; |
---|
| 1821 | + } |
---|
| 1822 | + |
---|
| 1823 | + return changed; |
---|
| 1824 | +} |
---|
| 1825 | + |
---|
| 1826 | +/* State Msg type New state Actions |
---|
| 1827 | + * INCLUDE (A) IS_EX (B) EXCLUDE (A*B,B-A) (B-A)=0 |
---|
| 1828 | + * Delete (A-B) |
---|
| 1829 | + * Group Timer=GMI |
---|
| 1830 | + */ |
---|
| 1831 | +static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, |
---|
| 1832 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1833 | +{ |
---|
| 1834 | + struct net_bridge_group_src *ent; |
---|
| 1835 | + struct br_ip src_ip; |
---|
| 1836 | + u32 src_idx; |
---|
| 1837 | + |
---|
| 1838 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1839 | + ent->flags |= BR_SGRP_F_DELETE; |
---|
| 1840 | + |
---|
| 1841 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 1842 | + src_ip.proto = pg->key.addr.proto; |
---|
| 1843 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 1844 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 1845 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 1846 | + if (ent) |
---|
| 1847 | + ent->flags &= ~BR_SGRP_F_DELETE; |
---|
| 1848 | + else |
---|
| 1849 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 1850 | + if (ent) |
---|
| 1851 | + br_multicast_fwd_src_handle(ent); |
---|
| 1852 | + srcs += src_size; |
---|
| 1853 | + } |
---|
| 1854 | + |
---|
| 1855 | + __grp_src_delete_marked(pg); |
---|
| 1856 | +} |
---|
| 1857 | + |
---|
| 1858 | +/* State Msg type New state Actions |
---|
| 1859 | + * EXCLUDE (X,Y) IS_EX (A) EXCLUDE (A-Y,Y*A) (A-X-Y)=GMI |
---|
| 1860 | + * Delete (X-A) |
---|
| 1861 | + * Delete (Y-A) |
---|
| 1862 | + * Group Timer=GMI |
---|
| 1863 | + */ |
---|
| 1864 | +static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, |
---|
| 1865 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1866 | +{ |
---|
| 1867 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1868 | + struct net_bridge_group_src *ent; |
---|
| 1869 | + unsigned long now = jiffies; |
---|
| 1870 | + bool changed = false; |
---|
| 1871 | + struct br_ip src_ip; |
---|
| 1872 | + u32 src_idx; |
---|
| 1873 | + |
---|
| 1874 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1875 | + ent->flags |= BR_SGRP_F_DELETE; |
---|
| 1876 | + |
---|
| 1877 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 1878 | + src_ip.proto = pg->key.addr.proto; |
---|
| 1879 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 1880 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 1881 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 1882 | + if (ent) { |
---|
| 1883 | + ent->flags &= ~BR_SGRP_F_DELETE; |
---|
| 1884 | + } else { |
---|
| 1885 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 1886 | + if (ent) { |
---|
| 1887 | + __grp_src_mod_timer(ent, |
---|
| 1888 | + now + br_multicast_gmi(br)); |
---|
| 1889 | + changed = true; |
---|
| 1890 | + } |
---|
| 1891 | + } |
---|
| 1892 | + srcs += src_size; |
---|
| 1893 | + } |
---|
| 1894 | + |
---|
| 1895 | + if (__grp_src_delete_marked(pg)) |
---|
| 1896 | + changed = true; |
---|
| 1897 | + |
---|
| 1898 | + return changed; |
---|
| 1899 | +} |
---|
| 1900 | + |
---|
| 1901 | +static bool br_multicast_isexc(struct net_bridge_port_group *pg, |
---|
| 1902 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1903 | +{ |
---|
| 1904 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1905 | + bool changed = false; |
---|
| 1906 | + |
---|
| 1907 | + switch (pg->filter_mode) { |
---|
| 1908 | + case MCAST_INCLUDE: |
---|
| 1909 | + __grp_src_isexc_incl(pg, srcs, nsrcs, src_size); |
---|
| 1910 | + br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE); |
---|
| 1911 | + changed = true; |
---|
| 1912 | + break; |
---|
| 1913 | + case MCAST_EXCLUDE: |
---|
| 1914 | + changed = __grp_src_isexc_excl(pg, srcs, nsrcs, src_size); |
---|
| 1915 | + break; |
---|
| 1916 | + } |
---|
| 1917 | + |
---|
| 1918 | + pg->filter_mode = MCAST_EXCLUDE; |
---|
| 1919 | + mod_timer(&pg->timer, jiffies + br_multicast_gmi(br)); |
---|
| 1920 | + |
---|
| 1921 | + return changed; |
---|
| 1922 | +} |
---|
| 1923 | + |
---|
| 1924 | +/* State Msg type New state Actions |
---|
| 1925 | + * INCLUDE (A) TO_IN (B) INCLUDE (A+B) (B)=GMI |
---|
| 1926 | + * Send Q(G,A-B) |
---|
| 1927 | + */ |
---|
| 1928 | +static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, |
---|
| 1929 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1930 | +{ |
---|
| 1931 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1932 | + u32 src_idx, to_send = pg->src_ents; |
---|
| 1933 | + struct net_bridge_group_src *ent; |
---|
| 1934 | + unsigned long now = jiffies; |
---|
| 1935 | + bool changed = false; |
---|
| 1936 | + struct br_ip src_ip; |
---|
| 1937 | + |
---|
| 1938 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1939 | + ent->flags |= BR_SGRP_F_SEND; |
---|
| 1940 | + |
---|
| 1941 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 1942 | + src_ip.proto = pg->key.addr.proto; |
---|
| 1943 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 1944 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 1945 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 1946 | + if (ent) { |
---|
| 1947 | + ent->flags &= ~BR_SGRP_F_SEND; |
---|
| 1948 | + to_send--; |
---|
| 1949 | + } else { |
---|
| 1950 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 1951 | + if (ent) |
---|
| 1952 | + changed = true; |
---|
| 1953 | + } |
---|
| 1954 | + if (ent) |
---|
| 1955 | + __grp_src_mod_timer(ent, now + br_multicast_gmi(br)); |
---|
| 1956 | + srcs += src_size; |
---|
| 1957 | + } |
---|
| 1958 | + |
---|
| 1959 | + if (to_send) |
---|
| 1960 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 1961 | + |
---|
| 1962 | + return changed; |
---|
| 1963 | +} |
---|
| 1964 | + |
---|
| 1965 | +/* State Msg type New state Actions |
---|
| 1966 | + * EXCLUDE (X,Y) TO_IN (A) EXCLUDE (X+A,Y-A) (A)=GMI |
---|
| 1967 | + * Send Q(G,X-A) |
---|
| 1968 | + * Send Q(G) |
---|
| 1969 | + */ |
---|
| 1970 | +static bool __grp_src_toin_excl(struct net_bridge_port_group *pg, |
---|
| 1971 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 1972 | +{ |
---|
| 1973 | + struct net_bridge *br = pg->key.port->br; |
---|
| 1974 | + u32 src_idx, to_send = pg->src_ents; |
---|
| 1975 | + struct net_bridge_group_src *ent; |
---|
| 1976 | + unsigned long now = jiffies; |
---|
| 1977 | + bool changed = false; |
---|
| 1978 | + struct br_ip src_ip; |
---|
| 1979 | + |
---|
| 1980 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 1981 | + if (timer_pending(&ent->timer)) |
---|
| 1982 | + ent->flags |= BR_SGRP_F_SEND; |
---|
| 1983 | + |
---|
| 1984 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 1985 | + src_ip.proto = pg->key.addr.proto; |
---|
| 1986 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 1987 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 1988 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 1989 | + if (ent) { |
---|
| 1990 | + if (timer_pending(&ent->timer)) { |
---|
| 1991 | + ent->flags &= ~BR_SGRP_F_SEND; |
---|
| 1992 | + to_send--; |
---|
| 1993 | + } |
---|
| 1994 | + } else { |
---|
| 1995 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 1996 | + if (ent) |
---|
| 1997 | + changed = true; |
---|
| 1998 | + } |
---|
| 1999 | + if (ent) |
---|
| 2000 | + __grp_src_mod_timer(ent, now + br_multicast_gmi(br)); |
---|
| 2001 | + srcs += src_size; |
---|
| 2002 | + } |
---|
| 2003 | + |
---|
| 2004 | + if (to_send) |
---|
| 2005 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 2006 | + |
---|
| 2007 | + __grp_send_query_and_rexmit(pg); |
---|
| 2008 | + |
---|
| 2009 | + return changed; |
---|
| 2010 | +} |
---|
| 2011 | + |
---|
| 2012 | +static bool br_multicast_toin(struct net_bridge_port_group *pg, |
---|
| 2013 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2014 | +{ |
---|
| 2015 | + bool changed = false; |
---|
| 2016 | + |
---|
| 2017 | + switch (pg->filter_mode) { |
---|
| 2018 | + case MCAST_INCLUDE: |
---|
| 2019 | + changed = __grp_src_toin_incl(pg, srcs, nsrcs, src_size); |
---|
| 2020 | + break; |
---|
| 2021 | + case MCAST_EXCLUDE: |
---|
| 2022 | + changed = __grp_src_toin_excl(pg, srcs, nsrcs, src_size); |
---|
| 2023 | + break; |
---|
| 2024 | + } |
---|
| 2025 | + |
---|
| 2026 | + return changed; |
---|
| 2027 | +} |
---|
| 2028 | + |
---|
| 2029 | +/* State Msg type New state Actions |
---|
| 2030 | + * INCLUDE (A) TO_EX (B) EXCLUDE (A*B,B-A) (B-A)=0 |
---|
| 2031 | + * Delete (A-B) |
---|
| 2032 | + * Send Q(G,A*B) |
---|
| 2033 | + * Group Timer=GMI |
---|
| 2034 | + */ |
---|
| 2035 | +static void __grp_src_toex_incl(struct net_bridge_port_group *pg, |
---|
| 2036 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2037 | +{ |
---|
| 2038 | + struct net_bridge_group_src *ent; |
---|
| 2039 | + u32 src_idx, to_send = 0; |
---|
| 2040 | + struct br_ip src_ip; |
---|
| 2041 | + |
---|
| 2042 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 2043 | + ent->flags = (ent->flags & ~BR_SGRP_F_SEND) | BR_SGRP_F_DELETE; |
---|
| 2044 | + |
---|
| 2045 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 2046 | + src_ip.proto = pg->key.addr.proto; |
---|
| 2047 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 2048 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 2049 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 2050 | + if (ent) { |
---|
| 2051 | + ent->flags = (ent->flags & ~BR_SGRP_F_DELETE) | |
---|
| 2052 | + BR_SGRP_F_SEND; |
---|
| 2053 | + to_send++; |
---|
| 2054 | + } else { |
---|
| 2055 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 2056 | + } |
---|
| 2057 | + if (ent) |
---|
| 2058 | + br_multicast_fwd_src_handle(ent); |
---|
| 2059 | + srcs += src_size; |
---|
| 2060 | + } |
---|
| 2061 | + |
---|
| 2062 | + __grp_src_delete_marked(pg); |
---|
| 2063 | + if (to_send) |
---|
| 2064 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 2065 | +} |
---|
| 2066 | + |
---|
| 2067 | +/* State Msg type New state Actions |
---|
| 2068 | + * EXCLUDE (X,Y) TO_EX (A) EXCLUDE (A-Y,Y*A) (A-X-Y)=Group Timer |
---|
| 2069 | + * Delete (X-A) |
---|
| 2070 | + * Delete (Y-A) |
---|
| 2071 | + * Send Q(G,A-Y) |
---|
| 2072 | + * Group Timer=GMI |
---|
| 2073 | + */ |
---|
| 2074 | +static bool __grp_src_toex_excl(struct net_bridge_port_group *pg, |
---|
| 2075 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2076 | +{ |
---|
| 2077 | + struct net_bridge_group_src *ent; |
---|
| 2078 | + u32 src_idx, to_send = 0; |
---|
| 2079 | + bool changed = false; |
---|
| 2080 | + struct br_ip src_ip; |
---|
| 2081 | + |
---|
| 2082 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 2083 | + ent->flags = (ent->flags & ~BR_SGRP_F_SEND) | BR_SGRP_F_DELETE; |
---|
| 2084 | + |
---|
| 2085 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 2086 | + src_ip.proto = pg->key.addr.proto; |
---|
| 2087 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 2088 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 2089 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 2090 | + if (ent) { |
---|
| 2091 | + ent->flags &= ~BR_SGRP_F_DELETE; |
---|
| 2092 | + } else { |
---|
| 2093 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 2094 | + if (ent) { |
---|
| 2095 | + __grp_src_mod_timer(ent, pg->timer.expires); |
---|
| 2096 | + changed = true; |
---|
| 2097 | + } |
---|
| 2098 | + } |
---|
| 2099 | + if (ent && timer_pending(&ent->timer)) { |
---|
| 2100 | + ent->flags |= BR_SGRP_F_SEND; |
---|
| 2101 | + to_send++; |
---|
| 2102 | + } |
---|
| 2103 | + srcs += src_size; |
---|
| 2104 | + } |
---|
| 2105 | + |
---|
| 2106 | + if (__grp_src_delete_marked(pg)) |
---|
| 2107 | + changed = true; |
---|
| 2108 | + if (to_send) |
---|
| 2109 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 2110 | + |
---|
| 2111 | + return changed; |
---|
| 2112 | +} |
---|
| 2113 | + |
---|
| 2114 | +static bool br_multicast_toex(struct net_bridge_port_group *pg, |
---|
| 2115 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2116 | +{ |
---|
| 2117 | + struct net_bridge *br = pg->key.port->br; |
---|
| 2118 | + bool changed = false; |
---|
| 2119 | + |
---|
| 2120 | + switch (pg->filter_mode) { |
---|
| 2121 | + case MCAST_INCLUDE: |
---|
| 2122 | + __grp_src_toex_incl(pg, srcs, nsrcs, src_size); |
---|
| 2123 | + br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE); |
---|
| 2124 | + changed = true; |
---|
| 2125 | + break; |
---|
| 2126 | + case MCAST_EXCLUDE: |
---|
| 2127 | + changed = __grp_src_toex_excl(pg, srcs, nsrcs, src_size); |
---|
| 2128 | + break; |
---|
| 2129 | + } |
---|
| 2130 | + |
---|
| 2131 | + pg->filter_mode = MCAST_EXCLUDE; |
---|
| 2132 | + mod_timer(&pg->timer, jiffies + br_multicast_gmi(br)); |
---|
| 2133 | + |
---|
| 2134 | + return changed; |
---|
| 2135 | +} |
---|
| 2136 | + |
---|
| 2137 | +/* State Msg type New state Actions |
---|
| 2138 | + * INCLUDE (A) BLOCK (B) INCLUDE (A) Send Q(G,A*B) |
---|
| 2139 | + */ |
---|
| 2140 | +static void __grp_src_block_incl(struct net_bridge_port_group *pg, |
---|
| 2141 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2142 | +{ |
---|
| 2143 | + struct net_bridge_group_src *ent; |
---|
| 2144 | + u32 src_idx, to_send = 0; |
---|
| 2145 | + struct br_ip src_ip; |
---|
| 2146 | + |
---|
| 2147 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 2148 | + ent->flags &= ~BR_SGRP_F_SEND; |
---|
| 2149 | + |
---|
| 2150 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 2151 | + src_ip.proto = pg->key.addr.proto; |
---|
| 2152 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 2153 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 2154 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 2155 | + if (ent) { |
---|
| 2156 | + ent->flags |= BR_SGRP_F_SEND; |
---|
| 2157 | + to_send++; |
---|
| 2158 | + } |
---|
| 2159 | + srcs += src_size; |
---|
| 2160 | + } |
---|
| 2161 | + |
---|
| 2162 | + if (to_send) |
---|
| 2163 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 2164 | + |
---|
| 2165 | + if (pg->filter_mode == MCAST_INCLUDE && hlist_empty(&pg->src_list)) |
---|
| 2166 | + br_multicast_find_del_pg(pg->key.port->br, pg); |
---|
| 2167 | +} |
---|
| 2168 | + |
---|
| 2169 | +/* State Msg type New state Actions |
---|
| 2170 | + * EXCLUDE (X,Y) BLOCK (A) EXCLUDE (X+(A-Y),Y) (A-X-Y)=Group Timer |
---|
| 2171 | + * Send Q(G,A-Y) |
---|
| 2172 | + */ |
---|
| 2173 | +static bool __grp_src_block_excl(struct net_bridge_port_group *pg, |
---|
| 2174 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2175 | +{ |
---|
| 2176 | + struct net_bridge_group_src *ent; |
---|
| 2177 | + u32 src_idx, to_send = 0; |
---|
| 2178 | + bool changed = false; |
---|
| 2179 | + struct br_ip src_ip; |
---|
| 2180 | + |
---|
| 2181 | + hlist_for_each_entry(ent, &pg->src_list, node) |
---|
| 2182 | + ent->flags &= ~BR_SGRP_F_SEND; |
---|
| 2183 | + |
---|
| 2184 | + memset(&src_ip, 0, sizeof(src_ip)); |
---|
| 2185 | + src_ip.proto = pg->key.addr.proto; |
---|
| 2186 | + for (src_idx = 0; src_idx < nsrcs; src_idx++) { |
---|
| 2187 | + memcpy(&src_ip.src, srcs, src_size); |
---|
| 2188 | + ent = br_multicast_find_group_src(pg, &src_ip); |
---|
| 2189 | + if (!ent) { |
---|
| 2190 | + ent = br_multicast_new_group_src(pg, &src_ip); |
---|
| 2191 | + if (ent) { |
---|
| 2192 | + __grp_src_mod_timer(ent, pg->timer.expires); |
---|
| 2193 | + changed = true; |
---|
| 2194 | + } |
---|
| 2195 | + } |
---|
| 2196 | + if (ent && timer_pending(&ent->timer)) { |
---|
| 2197 | + ent->flags |= BR_SGRP_F_SEND; |
---|
| 2198 | + to_send++; |
---|
| 2199 | + } |
---|
| 2200 | + srcs += src_size; |
---|
| 2201 | + } |
---|
| 2202 | + |
---|
| 2203 | + if (to_send) |
---|
| 2204 | + __grp_src_query_marked_and_rexmit(pg); |
---|
| 2205 | + |
---|
| 2206 | + return changed; |
---|
| 2207 | +} |
---|
| 2208 | + |
---|
| 2209 | +static bool br_multicast_block(struct net_bridge_port_group *pg, |
---|
| 2210 | + void *srcs, u32 nsrcs, size_t src_size) |
---|
| 2211 | +{ |
---|
| 2212 | + bool changed = false; |
---|
| 2213 | + |
---|
| 2214 | + switch (pg->filter_mode) { |
---|
| 2215 | + case MCAST_INCLUDE: |
---|
| 2216 | + __grp_src_block_incl(pg, srcs, nsrcs, src_size); |
---|
| 2217 | + break; |
---|
| 2218 | + case MCAST_EXCLUDE: |
---|
| 2219 | + changed = __grp_src_block_excl(pg, srcs, nsrcs, src_size); |
---|
| 2220 | + break; |
---|
| 2221 | + } |
---|
| 2222 | + |
---|
| 2223 | + return changed; |
---|
| 2224 | +} |
---|
| 2225 | + |
---|
| 2226 | +static struct net_bridge_port_group * |
---|
| 2227 | +br_multicast_find_port(struct net_bridge_mdb_entry *mp, |
---|
| 2228 | + struct net_bridge_port *p, |
---|
| 2229 | + const unsigned char *src) |
---|
| 2230 | +{ |
---|
| 2231 | + struct net_bridge *br __maybe_unused = mp->br; |
---|
| 2232 | + struct net_bridge_port_group *pg; |
---|
| 2233 | + |
---|
| 2234 | + for (pg = mlock_dereference(mp->ports, br); |
---|
| 2235 | + pg; |
---|
| 2236 | + pg = mlock_dereference(pg->next, br)) |
---|
| 2237 | + if (br_port_group_equal(pg, p, src)) |
---|
| 2238 | + return pg; |
---|
| 2239 | + |
---|
| 2240 | + return NULL; |
---|
| 2241 | +} |
---|
| 2242 | + |
---|
1136 | 2243 | static int br_ip4_multicast_igmp3_report(struct net_bridge *br, |
---|
1137 | 2244 | struct net_bridge_port *port, |
---|
1138 | 2245 | struct sk_buff *skb, |
---|
1139 | 2246 | u16 vid) |
---|
1140 | 2247 | { |
---|
| 2248 | + bool igmpv2 = br->multicast_igmp_version == 2; |
---|
| 2249 | + struct net_bridge_mdb_entry *mdst; |
---|
| 2250 | + struct net_bridge_port_group *pg; |
---|
1141 | 2251 | const unsigned char *src; |
---|
1142 | 2252 | struct igmpv3_report *ih; |
---|
1143 | 2253 | struct igmpv3_grec *grec; |
---|
1144 | | - int i; |
---|
1145 | | - int len; |
---|
1146 | | - int num; |
---|
1147 | | - int type; |
---|
1148 | | - int err = 0; |
---|
| 2254 | + int i, len, num, type; |
---|
| 2255 | + bool changed = false; |
---|
1149 | 2256 | __be32 group; |
---|
| 2257 | + int err = 0; |
---|
1150 | 2258 | u16 nsrcs; |
---|
1151 | 2259 | |
---|
1152 | 2260 | ih = igmpv3_report_hdr(skb); |
---|
.. | .. |
---|
1155 | 2263 | |
---|
1156 | 2264 | for (i = 0; i < num; i++) { |
---|
1157 | 2265 | len += sizeof(*grec); |
---|
1158 | | - if (!pskb_may_pull(skb, len)) |
---|
| 2266 | + if (!ip_mc_may_pull(skb, len)) |
---|
1159 | 2267 | return -EINVAL; |
---|
1160 | 2268 | |
---|
1161 | 2269 | grec = (void *)(skb->data + len - sizeof(*grec)); |
---|
.. | .. |
---|
1164 | 2272 | nsrcs = ntohs(grec->grec_nsrcs); |
---|
1165 | 2273 | |
---|
1166 | 2274 | len += nsrcs * 4; |
---|
1167 | | - if (!pskb_may_pull(skb, len)) |
---|
| 2275 | + if (!ip_mc_may_pull(skb, len)) |
---|
1168 | 2276 | return -EINVAL; |
---|
1169 | 2277 | |
---|
1170 | | - /* We treat this as an IGMPv2 report for now. */ |
---|
1171 | 2278 | switch (type) { |
---|
1172 | 2279 | case IGMPV3_MODE_IS_INCLUDE: |
---|
1173 | 2280 | case IGMPV3_MODE_IS_EXCLUDE: |
---|
.. | .. |
---|
1182 | 2289 | } |
---|
1183 | 2290 | |
---|
1184 | 2291 | src = eth_hdr(skb)->h_source; |
---|
1185 | | - if ((type == IGMPV3_CHANGE_TO_INCLUDE || |
---|
1186 | | - type == IGMPV3_MODE_IS_INCLUDE) && |
---|
1187 | | - nsrcs == 0) { |
---|
1188 | | - br_ip4_multicast_leave_group(br, port, group, vid, src); |
---|
| 2292 | + if (nsrcs == 0 && |
---|
| 2293 | + (type == IGMPV3_CHANGE_TO_INCLUDE || |
---|
| 2294 | + type == IGMPV3_MODE_IS_INCLUDE)) { |
---|
| 2295 | + if (!port || igmpv2) { |
---|
| 2296 | + br_ip4_multicast_leave_group(br, port, group, vid, src); |
---|
| 2297 | + continue; |
---|
| 2298 | + } |
---|
1189 | 2299 | } else { |
---|
1190 | 2300 | err = br_ip4_multicast_add_group(br, port, group, vid, |
---|
1191 | | - src); |
---|
| 2301 | + src, igmpv2); |
---|
1192 | 2302 | if (err) |
---|
1193 | 2303 | break; |
---|
1194 | 2304 | } |
---|
| 2305 | + |
---|
| 2306 | + if (!port || igmpv2) |
---|
| 2307 | + continue; |
---|
| 2308 | + |
---|
| 2309 | + spin_lock_bh(&br->multicast_lock); |
---|
| 2310 | + mdst = br_mdb_ip4_get(br, group, vid); |
---|
| 2311 | + if (!mdst) |
---|
| 2312 | + goto unlock_continue; |
---|
| 2313 | + pg = br_multicast_find_port(mdst, port, src); |
---|
| 2314 | + if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 2315 | + goto unlock_continue; |
---|
| 2316 | + /* reload grec */ |
---|
| 2317 | + grec = (void *)(skb->data + len - sizeof(*grec) - (nsrcs * 4)); |
---|
| 2318 | + switch (type) { |
---|
| 2319 | + case IGMPV3_ALLOW_NEW_SOURCES: |
---|
| 2320 | + changed = br_multicast_isinc_allow(pg, grec->grec_src, |
---|
| 2321 | + nsrcs, sizeof(__be32)); |
---|
| 2322 | + break; |
---|
| 2323 | + case IGMPV3_MODE_IS_INCLUDE: |
---|
| 2324 | + changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs, |
---|
| 2325 | + sizeof(__be32)); |
---|
| 2326 | + break; |
---|
| 2327 | + case IGMPV3_MODE_IS_EXCLUDE: |
---|
| 2328 | + changed = br_multicast_isexc(pg, grec->grec_src, nsrcs, |
---|
| 2329 | + sizeof(__be32)); |
---|
| 2330 | + break; |
---|
| 2331 | + case IGMPV3_CHANGE_TO_INCLUDE: |
---|
| 2332 | + changed = br_multicast_toin(pg, grec->grec_src, nsrcs, |
---|
| 2333 | + sizeof(__be32)); |
---|
| 2334 | + break; |
---|
| 2335 | + case IGMPV3_CHANGE_TO_EXCLUDE: |
---|
| 2336 | + changed = br_multicast_toex(pg, grec->grec_src, nsrcs, |
---|
| 2337 | + sizeof(__be32)); |
---|
| 2338 | + break; |
---|
| 2339 | + case IGMPV3_BLOCK_OLD_SOURCES: |
---|
| 2340 | + changed = br_multicast_block(pg, grec->grec_src, nsrcs, |
---|
| 2341 | + sizeof(__be32)); |
---|
| 2342 | + break; |
---|
| 2343 | + } |
---|
| 2344 | + if (changed) |
---|
| 2345 | + br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB); |
---|
| 2346 | +unlock_continue: |
---|
| 2347 | + spin_unlock_bh(&br->multicast_lock); |
---|
1195 | 2348 | } |
---|
1196 | 2349 | |
---|
1197 | 2350 | return err; |
---|
.. | .. |
---|
1203 | 2356 | struct sk_buff *skb, |
---|
1204 | 2357 | u16 vid) |
---|
1205 | 2358 | { |
---|
| 2359 | + bool mldv1 = br->multicast_mld_version == 1; |
---|
| 2360 | + struct net_bridge_mdb_entry *mdst; |
---|
| 2361 | + struct net_bridge_port_group *pg; |
---|
| 2362 | + unsigned int nsrcs_offset; |
---|
1206 | 2363 | const unsigned char *src; |
---|
1207 | 2364 | struct icmp6hdr *icmp6h; |
---|
1208 | 2365 | struct mld2_grec *grec; |
---|
1209 | | - int i; |
---|
1210 | | - int len; |
---|
1211 | | - int num; |
---|
| 2366 | + unsigned int grec_len; |
---|
| 2367 | + bool changed = false; |
---|
| 2368 | + int i, len, num; |
---|
1212 | 2369 | int err = 0; |
---|
1213 | 2370 | |
---|
1214 | | - if (!pskb_may_pull(skb, sizeof(*icmp6h))) |
---|
| 2371 | + if (!ipv6_mc_may_pull(skb, sizeof(*icmp6h))) |
---|
1215 | 2372 | return -EINVAL; |
---|
1216 | 2373 | |
---|
1217 | 2374 | icmp6h = icmp6_hdr(skb); |
---|
.. | .. |
---|
1222 | 2379 | __be16 *_nsrcs, __nsrcs; |
---|
1223 | 2380 | u16 nsrcs; |
---|
1224 | 2381 | |
---|
1225 | | - _nsrcs = skb_header_pointer(skb, |
---|
1226 | | - len + offsetof(struct mld2_grec, |
---|
1227 | | - grec_nsrcs), |
---|
| 2382 | + nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs); |
---|
| 2383 | + |
---|
| 2384 | + if (skb_transport_offset(skb) + ipv6_transport_len(skb) < |
---|
| 2385 | + nsrcs_offset + sizeof(__nsrcs)) |
---|
| 2386 | + return -EINVAL; |
---|
| 2387 | + |
---|
| 2388 | + _nsrcs = skb_header_pointer(skb, nsrcs_offset, |
---|
1228 | 2389 | sizeof(__nsrcs), &__nsrcs); |
---|
1229 | 2390 | if (!_nsrcs) |
---|
1230 | 2391 | return -EINVAL; |
---|
1231 | 2392 | |
---|
1232 | 2393 | nsrcs = ntohs(*_nsrcs); |
---|
| 2394 | + grec_len = struct_size(grec, grec_src, nsrcs); |
---|
1233 | 2395 | |
---|
1234 | | - if (!pskb_may_pull(skb, |
---|
1235 | | - len + sizeof(*grec) + |
---|
1236 | | - sizeof(struct in6_addr) * nsrcs)) |
---|
| 2396 | + if (!ipv6_mc_may_pull(skb, len + grec_len)) |
---|
1237 | 2397 | return -EINVAL; |
---|
1238 | 2398 | |
---|
1239 | 2399 | grec = (struct mld2_grec *)(skb->data + len); |
---|
1240 | | - len += sizeof(*grec) + |
---|
1241 | | - sizeof(struct in6_addr) * nsrcs; |
---|
| 2400 | + len += grec_len; |
---|
1242 | 2401 | |
---|
1243 | | - /* We treat these as MLDv1 reports for now. */ |
---|
1244 | 2402 | switch (grec->grec_type) { |
---|
1245 | 2403 | case MLD2_MODE_IS_INCLUDE: |
---|
1246 | 2404 | case MLD2_MODE_IS_EXCLUDE: |
---|
.. | .. |
---|
1258 | 2416 | if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE || |
---|
1259 | 2417 | grec->grec_type == MLD2_MODE_IS_INCLUDE) && |
---|
1260 | 2418 | nsrcs == 0) { |
---|
1261 | | - br_ip6_multicast_leave_group(br, port, &grec->grec_mca, |
---|
1262 | | - vid, src); |
---|
| 2419 | + if (!port || mldv1) { |
---|
| 2420 | + br_ip6_multicast_leave_group(br, port, |
---|
| 2421 | + &grec->grec_mca, |
---|
| 2422 | + vid, src); |
---|
| 2423 | + continue; |
---|
| 2424 | + } |
---|
1263 | 2425 | } else { |
---|
1264 | 2426 | err = br_ip6_multicast_add_group(br, port, |
---|
1265 | 2427 | &grec->grec_mca, vid, |
---|
1266 | | - src); |
---|
| 2428 | + src, mldv1); |
---|
1267 | 2429 | if (err) |
---|
1268 | 2430 | break; |
---|
1269 | 2431 | } |
---|
| 2432 | + |
---|
| 2433 | + if (!port || mldv1) |
---|
| 2434 | + continue; |
---|
| 2435 | + |
---|
| 2436 | + spin_lock_bh(&br->multicast_lock); |
---|
| 2437 | + mdst = br_mdb_ip6_get(br, &grec->grec_mca, vid); |
---|
| 2438 | + if (!mdst) |
---|
| 2439 | + goto unlock_continue; |
---|
| 2440 | + pg = br_multicast_find_port(mdst, port, src); |
---|
| 2441 | + if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT)) |
---|
| 2442 | + goto unlock_continue; |
---|
| 2443 | + switch (grec->grec_type) { |
---|
| 2444 | + case MLD2_ALLOW_NEW_SOURCES: |
---|
| 2445 | + changed = br_multicast_isinc_allow(pg, grec->grec_src, |
---|
| 2446 | + nsrcs, |
---|
| 2447 | + sizeof(struct in6_addr)); |
---|
| 2448 | + break; |
---|
| 2449 | + case MLD2_MODE_IS_INCLUDE: |
---|
| 2450 | + changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs, |
---|
| 2451 | + sizeof(struct in6_addr)); |
---|
| 2452 | + break; |
---|
| 2453 | + case MLD2_MODE_IS_EXCLUDE: |
---|
| 2454 | + changed = br_multicast_isexc(pg, grec->grec_src, nsrcs, |
---|
| 2455 | + sizeof(struct in6_addr)); |
---|
| 2456 | + break; |
---|
| 2457 | + case MLD2_CHANGE_TO_INCLUDE: |
---|
| 2458 | + changed = br_multicast_toin(pg, grec->grec_src, nsrcs, |
---|
| 2459 | + sizeof(struct in6_addr)); |
---|
| 2460 | + break; |
---|
| 2461 | + case MLD2_CHANGE_TO_EXCLUDE: |
---|
| 2462 | + changed = br_multicast_toex(pg, grec->grec_src, nsrcs, |
---|
| 2463 | + sizeof(struct in6_addr)); |
---|
| 2464 | + break; |
---|
| 2465 | + case MLD2_BLOCK_OLD_SOURCES: |
---|
| 2466 | + changed = br_multicast_block(pg, grec->grec_src, nsrcs, |
---|
| 2467 | + sizeof(struct in6_addr)); |
---|
| 2468 | + break; |
---|
| 2469 | + } |
---|
| 2470 | + if (changed) |
---|
| 2471 | + br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB); |
---|
| 2472 | +unlock_continue: |
---|
| 2473 | + spin_unlock_bh(&br->multicast_lock); |
---|
1270 | 2474 | } |
---|
1271 | 2475 | |
---|
1272 | 2476 | return err; |
---|
.. | .. |
---|
1281 | 2485 | !timer_pending(&br->ip4_other_query.timer)) |
---|
1282 | 2486 | goto update; |
---|
1283 | 2487 | |
---|
1284 | | - if (!br->ip4_querier.addr.u.ip4) |
---|
| 2488 | + if (!br->ip4_querier.addr.src.ip4) |
---|
1285 | 2489 | goto update; |
---|
1286 | 2490 | |
---|
1287 | | - if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.u.ip4)) |
---|
| 2491 | + if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.src.ip4)) |
---|
1288 | 2492 | goto update; |
---|
1289 | 2493 | |
---|
1290 | 2494 | return false; |
---|
1291 | 2495 | |
---|
1292 | 2496 | update: |
---|
1293 | | - br->ip4_querier.addr.u.ip4 = saddr; |
---|
| 2497 | + br->ip4_querier.addr.src.ip4 = saddr; |
---|
1294 | 2498 | |
---|
1295 | 2499 | /* update protected by general multicast_lock by caller */ |
---|
1296 | 2500 | rcu_assign_pointer(br->ip4_querier.port, port); |
---|
.. | .. |
---|
1307 | 2511 | !timer_pending(&br->ip6_other_query.timer)) |
---|
1308 | 2512 | goto update; |
---|
1309 | 2513 | |
---|
1310 | | - if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.u.ip6) <= 0) |
---|
| 2514 | + if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.src.ip6) <= 0) |
---|
1311 | 2515 | goto update; |
---|
1312 | 2516 | |
---|
1313 | 2517 | return false; |
---|
1314 | 2518 | |
---|
1315 | 2519 | update: |
---|
1316 | | - br->ip6_querier.addr.u.ip6 = *saddr; |
---|
| 2520 | + br->ip6_querier.addr.src.ip6 = *saddr; |
---|
1317 | 2521 | |
---|
1318 | 2522 | /* update protected by general multicast_lock by caller */ |
---|
1319 | 2523 | rcu_assign_pointer(br->ip6_querier.port, port); |
---|
.. | .. |
---|
1328 | 2532 | { |
---|
1329 | 2533 | switch (saddr->proto) { |
---|
1330 | 2534 | case htons(ETH_P_IP): |
---|
1331 | | - return br_ip4_multicast_select_querier(br, port, saddr->u.ip4); |
---|
| 2535 | + return br_ip4_multicast_select_querier(br, port, saddr->src.ip4); |
---|
1332 | 2536 | #if IS_ENABLED(CONFIG_IPV6) |
---|
1333 | 2537 | case htons(ETH_P_IPV6): |
---|
1334 | | - return br_ip6_multicast_select_querier(br, port, &saddr->u.ip6); |
---|
| 2538 | + return br_ip6_multicast_select_querier(br, port, &saddr->src.ip6); |
---|
1335 | 2539 | #endif |
---|
1336 | 2540 | } |
---|
1337 | 2541 | |
---|
.. | .. |
---|
1433 | 2637 | struct sk_buff *skb, |
---|
1434 | 2638 | u16 vid) |
---|
1435 | 2639 | { |
---|
| 2640 | + unsigned int transport_len = ip_transport_len(skb); |
---|
1436 | 2641 | const struct iphdr *iph = ip_hdr(skb); |
---|
1437 | 2642 | struct igmphdr *ih = igmp_hdr(skb); |
---|
1438 | 2643 | struct net_bridge_mdb_entry *mp; |
---|
.. | .. |
---|
1442 | 2647 | struct br_ip saddr; |
---|
1443 | 2648 | unsigned long max_delay; |
---|
1444 | 2649 | unsigned long now = jiffies; |
---|
1445 | | - unsigned int offset = skb_transport_offset(skb); |
---|
1446 | 2650 | __be32 group; |
---|
1447 | 2651 | |
---|
1448 | 2652 | spin_lock(&br->multicast_lock); |
---|
.. | .. |
---|
1452 | 2656 | |
---|
1453 | 2657 | group = ih->group; |
---|
1454 | 2658 | |
---|
1455 | | - if (skb->len == offset + sizeof(*ih)) { |
---|
| 2659 | + if (transport_len == sizeof(*ih)) { |
---|
1456 | 2660 | max_delay = ih->code * (HZ / IGMP_TIMER_SCALE); |
---|
1457 | 2661 | |
---|
1458 | 2662 | if (!max_delay) { |
---|
1459 | 2663 | max_delay = 10 * HZ; |
---|
1460 | 2664 | group = 0; |
---|
1461 | 2665 | } |
---|
1462 | | - } else if (skb->len >= offset + sizeof(*ih3)) { |
---|
| 2666 | + } else if (transport_len >= sizeof(*ih3)) { |
---|
1463 | 2667 | ih3 = igmpv3_query_hdr(skb); |
---|
1464 | | - if (ih3->nsrcs) |
---|
| 2668 | + if (ih3->nsrcs || |
---|
| 2669 | + (br->multicast_igmp_version == 3 && group && ih3->suppress)) |
---|
1465 | 2670 | goto out; |
---|
1466 | 2671 | |
---|
1467 | 2672 | max_delay = ih3->code ? |
---|
.. | .. |
---|
1472 | 2677 | |
---|
1473 | 2678 | if (!group) { |
---|
1474 | 2679 | saddr.proto = htons(ETH_P_IP); |
---|
1475 | | - saddr.u.ip4 = iph->saddr; |
---|
| 2680 | + saddr.src.ip4 = iph->saddr; |
---|
1476 | 2681 | |
---|
1477 | 2682 | br_multicast_query_received(br, port, &br->ip4_other_query, |
---|
1478 | 2683 | &saddr, max_delay); |
---|
1479 | 2684 | goto out; |
---|
1480 | 2685 | } |
---|
1481 | 2686 | |
---|
1482 | | - mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group, vid); |
---|
| 2687 | + mp = br_mdb_ip4_get(br, group, vid); |
---|
1483 | 2688 | if (!mp) |
---|
1484 | 2689 | goto out; |
---|
1485 | 2690 | |
---|
.. | .. |
---|
1496 | 2701 | pp = &p->next) { |
---|
1497 | 2702 | if (timer_pending(&p->timer) ? |
---|
1498 | 2703 | time_after(p->timer.expires, now + max_delay) : |
---|
1499 | | - try_to_del_timer_sync(&p->timer) >= 0) |
---|
| 2704 | + try_to_del_timer_sync(&p->timer) >= 0 && |
---|
| 2705 | + (br->multicast_igmp_version == 2 || |
---|
| 2706 | + p->filter_mode == MCAST_EXCLUDE)) |
---|
1500 | 2707 | mod_timer(&p->timer, now + max_delay); |
---|
1501 | 2708 | } |
---|
1502 | 2709 | |
---|
.. | .. |
---|
1510 | 2717 | struct sk_buff *skb, |
---|
1511 | 2718 | u16 vid) |
---|
1512 | 2719 | { |
---|
| 2720 | + unsigned int transport_len = ipv6_transport_len(skb); |
---|
1513 | 2721 | struct mld_msg *mld; |
---|
1514 | 2722 | struct net_bridge_mdb_entry *mp; |
---|
1515 | 2723 | struct mld2_query *mld2q; |
---|
.. | .. |
---|
1528 | 2736 | (port && port->state == BR_STATE_DISABLED)) |
---|
1529 | 2737 | goto out; |
---|
1530 | 2738 | |
---|
1531 | | - if (skb->len == offset + sizeof(*mld)) { |
---|
| 2739 | + if (transport_len == sizeof(*mld)) { |
---|
1532 | 2740 | if (!pskb_may_pull(skb, offset + sizeof(*mld))) { |
---|
1533 | 2741 | err = -EINVAL; |
---|
1534 | 2742 | goto out; |
---|
.. | .. |
---|
1545 | 2753 | mld2q = (struct mld2_query *)icmp6_hdr(skb); |
---|
1546 | 2754 | if (!mld2q->mld2q_nsrcs) |
---|
1547 | 2755 | group = &mld2q->mld2q_mca; |
---|
| 2756 | + if (br->multicast_mld_version == 2 && |
---|
| 2757 | + !ipv6_addr_any(&mld2q->mld2q_mca) && |
---|
| 2758 | + mld2q->mld2q_suppress) |
---|
| 2759 | + goto out; |
---|
1548 | 2760 | |
---|
1549 | 2761 | max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL); |
---|
1550 | 2762 | } |
---|
.. | .. |
---|
1553 | 2765 | |
---|
1554 | 2766 | if (is_general_query) { |
---|
1555 | 2767 | saddr.proto = htons(ETH_P_IPV6); |
---|
1556 | | - saddr.u.ip6 = ipv6_hdr(skb)->saddr; |
---|
| 2768 | + saddr.src.ip6 = ipv6_hdr(skb)->saddr; |
---|
1557 | 2769 | |
---|
1558 | 2770 | br_multicast_query_received(br, port, &br->ip6_other_query, |
---|
1559 | 2771 | &saddr, max_delay); |
---|
.. | .. |
---|
1562 | 2774 | goto out; |
---|
1563 | 2775 | } |
---|
1564 | 2776 | |
---|
1565 | | - mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid); |
---|
| 2777 | + mp = br_mdb_ip6_get(br, group, vid); |
---|
1566 | 2778 | if (!mp) |
---|
1567 | 2779 | goto out; |
---|
1568 | 2780 | |
---|
.. | .. |
---|
1578 | 2790 | pp = &p->next) { |
---|
1579 | 2791 | if (timer_pending(&p->timer) ? |
---|
1580 | 2792 | time_after(p->timer.expires, now + max_delay) : |
---|
1581 | | - try_to_del_timer_sync(&p->timer) >= 0) |
---|
| 2793 | + try_to_del_timer_sync(&p->timer) >= 0 && |
---|
| 2794 | + (br->multicast_mld_version == 1 || |
---|
| 2795 | + p->filter_mode == MCAST_EXCLUDE)) |
---|
1582 | 2796 | mod_timer(&p->timer, now + max_delay); |
---|
1583 | 2797 | } |
---|
1584 | 2798 | |
---|
.. | .. |
---|
1596 | 2810 | struct bridge_mcast_own_query *own_query, |
---|
1597 | 2811 | const unsigned char *src) |
---|
1598 | 2812 | { |
---|
1599 | | - struct net_bridge_mdb_htable *mdb; |
---|
1600 | 2813 | struct net_bridge_mdb_entry *mp; |
---|
1601 | 2814 | struct net_bridge_port_group *p; |
---|
1602 | 2815 | unsigned long now; |
---|
.. | .. |
---|
1607 | 2820 | (port && port->state == BR_STATE_DISABLED)) |
---|
1608 | 2821 | goto out; |
---|
1609 | 2822 | |
---|
1610 | | - mdb = mlock_dereference(br->mdb, br); |
---|
1611 | | - mp = br_mdb_ip_get(mdb, group); |
---|
| 2823 | + mp = br_mdb_ip_get(br, group); |
---|
1612 | 2824 | if (!mp) |
---|
1613 | 2825 | goto out; |
---|
1614 | 2826 | |
---|
.. | .. |
---|
1624 | 2836 | if (p->flags & MDB_PG_FLAGS_PERMANENT) |
---|
1625 | 2837 | break; |
---|
1626 | 2838 | |
---|
1627 | | - rcu_assign_pointer(*pp, p->next); |
---|
1628 | | - hlist_del_init(&p->mglist); |
---|
1629 | | - del_timer(&p->timer); |
---|
1630 | | - call_rcu_bh(&p->rcu, br_multicast_free_pg); |
---|
1631 | | - br_mdb_notify(br->dev, port, group, RTM_DELMDB, |
---|
1632 | | - p->flags); |
---|
1633 | | - |
---|
1634 | | - if (!mp->ports && !mp->host_joined && |
---|
1635 | | - netif_running(br->dev)) |
---|
1636 | | - mod_timer(&mp->timer, jiffies); |
---|
| 2839 | + p->flags |= MDB_PG_FLAGS_FAST_LEAVE; |
---|
| 2840 | + br_multicast_del_pg(mp, p, pp); |
---|
1637 | 2841 | } |
---|
1638 | 2842 | goto out; |
---|
1639 | 2843 | } |
---|
.. | .. |
---|
1641 | 2845 | if (timer_pending(&other_query->timer)) |
---|
1642 | 2846 | goto out; |
---|
1643 | 2847 | |
---|
1644 | | - if (br->multicast_querier) { |
---|
1645 | | - __br_multicast_send_query(br, port, &mp->addr); |
---|
| 2848 | + if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { |
---|
| 2849 | + __br_multicast_send_query(br, port, NULL, NULL, &mp->addr, |
---|
| 2850 | + false, 0, NULL); |
---|
1646 | 2851 | |
---|
1647 | 2852 | time = jiffies + br->multicast_last_member_count * |
---|
1648 | 2853 | br->multicast_last_member_interval; |
---|
.. | .. |
---|
1684 | 2889 | for (p = mlock_dereference(mp->ports, br); |
---|
1685 | 2890 | p != NULL; |
---|
1686 | 2891 | p = mlock_dereference(p->next, br)) { |
---|
1687 | | - if (p->port != port) |
---|
| 2892 | + if (p->key.port != port) |
---|
1688 | 2893 | continue; |
---|
1689 | 2894 | |
---|
1690 | 2895 | if (!hlist_unhashed(&p->mglist) && |
---|
.. | .. |
---|
1714 | 2919 | |
---|
1715 | 2920 | own_query = port ? &port->ip4_own_query : &br->ip4_own_query; |
---|
1716 | 2921 | |
---|
1717 | | - br_group.u.ip4 = group; |
---|
| 2922 | + memset(&br_group, 0, sizeof(br_group)); |
---|
| 2923 | + br_group.dst.ip4 = group; |
---|
1718 | 2924 | br_group.proto = htons(ETH_P_IP); |
---|
1719 | 2925 | br_group.vid = vid; |
---|
1720 | 2926 | |
---|
.. | .. |
---|
1737 | 2943 | |
---|
1738 | 2944 | own_query = port ? &port->ip6_own_query : &br->ip6_own_query; |
---|
1739 | 2945 | |
---|
1740 | | - br_group.u.ip6 = *group; |
---|
| 2946 | + memset(&br_group, 0, sizeof(br_group)); |
---|
| 2947 | + br_group.dst.ip6 = *group; |
---|
1741 | 2948 | br_group.proto = htons(ETH_P_IPV6); |
---|
1742 | 2949 | br_group.vid = vid; |
---|
1743 | 2950 | |
---|
.. | .. |
---|
1753 | 2960 | struct bridge_mcast_stats __percpu *stats; |
---|
1754 | 2961 | struct bridge_mcast_stats *pstats; |
---|
1755 | 2962 | |
---|
1756 | | - if (!br->multicast_stats_enabled) |
---|
| 2963 | + if (!br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) |
---|
1757 | 2964 | return; |
---|
1758 | 2965 | |
---|
1759 | 2966 | if (p) |
---|
.. | .. |
---|
1796 | 3003 | spin_unlock(&br->multicast_lock); |
---|
1797 | 3004 | } |
---|
1798 | 3005 | |
---|
| 3006 | +static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, |
---|
| 3007 | + struct net_bridge_port *port, |
---|
| 3008 | + struct sk_buff *skb) |
---|
| 3009 | +{ |
---|
| 3010 | + if (ip_hdr(skb)->protocol != IPPROTO_IGMP || |
---|
| 3011 | + igmp_hdr(skb)->type != IGMP_MRDISC_ADV) |
---|
| 3012 | + return -ENOMSG; |
---|
| 3013 | + |
---|
| 3014 | + spin_lock(&br->multicast_lock); |
---|
| 3015 | + br_multicast_mark_router(br, port); |
---|
| 3016 | + spin_unlock(&br->multicast_lock); |
---|
| 3017 | + |
---|
| 3018 | + return 0; |
---|
| 3019 | +} |
---|
| 3020 | + |
---|
1799 | 3021 | static int br_multicast_ipv4_rcv(struct net_bridge *br, |
---|
1800 | 3022 | struct net_bridge_port *port, |
---|
1801 | 3023 | struct sk_buff *skb, |
---|
1802 | 3024 | u16 vid) |
---|
1803 | 3025 | { |
---|
1804 | | - struct sk_buff *skb_trimmed = NULL; |
---|
1805 | 3026 | const unsigned char *src; |
---|
1806 | 3027 | struct igmphdr *ih; |
---|
1807 | 3028 | int err; |
---|
1808 | 3029 | |
---|
1809 | | - err = ip_mc_check_igmp(skb, &skb_trimmed); |
---|
| 3030 | + err = ip_mc_check_igmp(skb); |
---|
1810 | 3031 | |
---|
1811 | 3032 | if (err == -ENOMSG) { |
---|
1812 | 3033 | if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) { |
---|
.. | .. |
---|
1814 | 3035 | } else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) { |
---|
1815 | 3036 | if (ip_hdr(skb)->protocol == IPPROTO_PIM) |
---|
1816 | 3037 | br_multicast_pim(br, port, skb); |
---|
| 3038 | + } else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) { |
---|
| 3039 | + br_ip4_multicast_mrd_rcv(br, port, skb); |
---|
1817 | 3040 | } |
---|
| 3041 | + |
---|
1818 | 3042 | return 0; |
---|
1819 | 3043 | } else if (err < 0) { |
---|
1820 | 3044 | br_multicast_err_count(br, port, skb->protocol); |
---|
.. | .. |
---|
1829 | 3053 | case IGMP_HOST_MEMBERSHIP_REPORT: |
---|
1830 | 3054 | case IGMPV2_HOST_MEMBERSHIP_REPORT: |
---|
1831 | 3055 | BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
---|
1832 | | - err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); |
---|
| 3056 | + err = br_ip4_multicast_add_group(br, port, ih->group, vid, src, |
---|
| 3057 | + true); |
---|
1833 | 3058 | break; |
---|
1834 | 3059 | case IGMPV3_HOST_MEMBERSHIP_REPORT: |
---|
1835 | | - err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid); |
---|
| 3060 | + err = br_ip4_multicast_igmp3_report(br, port, skb, vid); |
---|
1836 | 3061 | break; |
---|
1837 | 3062 | case IGMP_HOST_MEMBERSHIP_QUERY: |
---|
1838 | | - br_ip4_multicast_query(br, port, skb_trimmed, vid); |
---|
| 3063 | + br_ip4_multicast_query(br, port, skb, vid); |
---|
1839 | 3064 | break; |
---|
1840 | 3065 | case IGMP_HOST_LEAVE_MESSAGE: |
---|
1841 | 3066 | br_ip4_multicast_leave_group(br, port, ih->group, vid, src); |
---|
1842 | 3067 | break; |
---|
1843 | 3068 | } |
---|
1844 | | - |
---|
1845 | | - if (skb_trimmed && skb_trimmed != skb) |
---|
1846 | | - kfree_skb(skb_trimmed); |
---|
1847 | 3069 | |
---|
1848 | 3070 | br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, |
---|
1849 | 3071 | BR_MCAST_DIR_RX); |
---|
.. | .. |
---|
1852 | 3074 | } |
---|
1853 | 3075 | |
---|
1854 | 3076 | #if IS_ENABLED(CONFIG_IPV6) |
---|
| 3077 | +static void br_ip6_multicast_mrd_rcv(struct net_bridge *br, |
---|
| 3078 | + struct net_bridge_port *port, |
---|
| 3079 | + struct sk_buff *skb) |
---|
| 3080 | +{ |
---|
| 3081 | + if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) |
---|
| 3082 | + return; |
---|
| 3083 | + |
---|
| 3084 | + spin_lock(&br->multicast_lock); |
---|
| 3085 | + br_multicast_mark_router(br, port); |
---|
| 3086 | + spin_unlock(&br->multicast_lock); |
---|
| 3087 | +} |
---|
| 3088 | + |
---|
1855 | 3089 | static int br_multicast_ipv6_rcv(struct net_bridge *br, |
---|
1856 | 3090 | struct net_bridge_port *port, |
---|
1857 | 3091 | struct sk_buff *skb, |
---|
1858 | 3092 | u16 vid) |
---|
1859 | 3093 | { |
---|
1860 | | - struct sk_buff *skb_trimmed = NULL; |
---|
1861 | 3094 | const unsigned char *src; |
---|
1862 | 3095 | struct mld_msg *mld; |
---|
1863 | 3096 | int err; |
---|
1864 | 3097 | |
---|
1865 | | - err = ipv6_mc_check_mld(skb, &skb_trimmed); |
---|
| 3098 | + err = ipv6_mc_check_mld(skb); |
---|
1866 | 3099 | |
---|
1867 | | - if (err == -ENOMSG) { |
---|
| 3100 | + if (err == -ENOMSG || err == -ENODATA) { |
---|
1868 | 3101 | if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) |
---|
1869 | 3102 | BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
---|
| 3103 | + if (err == -ENODATA && |
---|
| 3104 | + ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) |
---|
| 3105 | + br_ip6_multicast_mrd_rcv(br, port, skb); |
---|
| 3106 | + |
---|
1870 | 3107 | return 0; |
---|
1871 | 3108 | } else if (err < 0) { |
---|
1872 | 3109 | br_multicast_err_count(br, port, skb->protocol); |
---|
.. | .. |
---|
1881 | 3118 | src = eth_hdr(skb)->h_source; |
---|
1882 | 3119 | BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
---|
1883 | 3120 | err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, |
---|
1884 | | - src); |
---|
| 3121 | + src, true); |
---|
1885 | 3122 | break; |
---|
1886 | 3123 | case ICMPV6_MLD2_REPORT: |
---|
1887 | | - err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid); |
---|
| 3124 | + err = br_ip6_multicast_mld2_report(br, port, skb, vid); |
---|
1888 | 3125 | break; |
---|
1889 | 3126 | case ICMPV6_MGM_QUERY: |
---|
1890 | | - err = br_ip6_multicast_query(br, port, skb_trimmed, vid); |
---|
| 3127 | + err = br_ip6_multicast_query(br, port, skb, vid); |
---|
1891 | 3128 | break; |
---|
1892 | 3129 | case ICMPV6_MGM_REDUCTION: |
---|
1893 | 3130 | src = eth_hdr(skb)->h_source; |
---|
1894 | 3131 | br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); |
---|
1895 | 3132 | break; |
---|
1896 | 3133 | } |
---|
1897 | | - |
---|
1898 | | - if (skb_trimmed && skb_trimmed != skb) |
---|
1899 | | - kfree_skb(skb_trimmed); |
---|
1900 | 3134 | |
---|
1901 | 3135 | br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, |
---|
1902 | 3136 | BR_MCAST_DIR_RX); |
---|
.. | .. |
---|
1913 | 3147 | BR_INPUT_SKB_CB(skb)->igmp = 0; |
---|
1914 | 3148 | BR_INPUT_SKB_CB(skb)->mrouters_only = 0; |
---|
1915 | 3149 | |
---|
1916 | | - if (br->multicast_disabled) |
---|
| 3150 | + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
1917 | 3151 | return 0; |
---|
1918 | 3152 | |
---|
1919 | 3153 | switch (skb->protocol) { |
---|
.. | .. |
---|
1959 | 3193 | } |
---|
1960 | 3194 | #endif |
---|
1961 | 3195 | |
---|
| 3196 | +static void br_multicast_gc_work(struct work_struct *work) |
---|
| 3197 | +{ |
---|
| 3198 | + struct net_bridge *br = container_of(work, struct net_bridge, |
---|
| 3199 | + mcast_gc_work); |
---|
| 3200 | + HLIST_HEAD(deleted_head); |
---|
| 3201 | + |
---|
| 3202 | + spin_lock_bh(&br->multicast_lock); |
---|
| 3203 | + hlist_move_list(&br->mcast_gc_list, &deleted_head); |
---|
| 3204 | + spin_unlock_bh(&br->multicast_lock); |
---|
| 3205 | + |
---|
| 3206 | + br_multicast_gc(&deleted_head); |
---|
| 3207 | +} |
---|
| 3208 | + |
---|
1962 | 3209 | void br_multicast_init(struct net_bridge *br) |
---|
1963 | 3210 | { |
---|
1964 | | - br->hash_elasticity = 4; |
---|
1965 | | - br->hash_max = 512; |
---|
| 3211 | + br->hash_max = BR_MULTICAST_DEFAULT_HASH_MAX; |
---|
1966 | 3212 | |
---|
1967 | 3213 | br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; |
---|
1968 | | - br->multicast_querier = 0; |
---|
1969 | | - br->multicast_query_use_ifaddr = 0; |
---|
1970 | 3214 | br->multicast_last_member_count = 2; |
---|
1971 | 3215 | br->multicast_startup_query_count = 2; |
---|
1972 | 3216 | |
---|
.. | .. |
---|
1985 | 3229 | br->ip6_other_query.delay_time = 0; |
---|
1986 | 3230 | br->ip6_querier.port = NULL; |
---|
1987 | 3231 | #endif |
---|
1988 | | - br->has_ipv6_addr = 1; |
---|
| 3232 | + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, true); |
---|
| 3233 | + br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); |
---|
1989 | 3234 | |
---|
1990 | 3235 | spin_lock_init(&br->multicast_lock); |
---|
1991 | 3236 | timer_setup(&br->multicast_router_timer, |
---|
.. | .. |
---|
2000 | 3245 | timer_setup(&br->ip6_own_query.timer, |
---|
2001 | 3246 | br_ip6_multicast_query_expired, 0); |
---|
2002 | 3247 | #endif |
---|
| 3248 | + INIT_HLIST_HEAD(&br->mdb_list); |
---|
| 3249 | + INIT_HLIST_HEAD(&br->mcast_gc_list); |
---|
| 3250 | + INIT_WORK(&br->mcast_gc_work, br_multicast_gc_work); |
---|
| 3251 | +} |
---|
| 3252 | + |
---|
| 3253 | +static void br_ip4_multicast_join_snoopers(struct net_bridge *br) |
---|
| 3254 | +{ |
---|
| 3255 | + struct in_device *in_dev = in_dev_get(br->dev); |
---|
| 3256 | + |
---|
| 3257 | + if (!in_dev) |
---|
| 3258 | + return; |
---|
| 3259 | + |
---|
| 3260 | + __ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC); |
---|
| 3261 | + in_dev_put(in_dev); |
---|
| 3262 | +} |
---|
| 3263 | + |
---|
| 3264 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 3265 | +static void br_ip6_multicast_join_snoopers(struct net_bridge *br) |
---|
| 3266 | +{ |
---|
| 3267 | + struct in6_addr addr; |
---|
| 3268 | + |
---|
| 3269 | + ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a)); |
---|
| 3270 | + ipv6_dev_mc_inc(br->dev, &addr); |
---|
| 3271 | +} |
---|
| 3272 | +#else |
---|
| 3273 | +static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br) |
---|
| 3274 | +{ |
---|
| 3275 | +} |
---|
| 3276 | +#endif |
---|
| 3277 | + |
---|
| 3278 | +void br_multicast_join_snoopers(struct net_bridge *br) |
---|
| 3279 | +{ |
---|
| 3280 | + br_ip4_multicast_join_snoopers(br); |
---|
| 3281 | + br_ip6_multicast_join_snoopers(br); |
---|
| 3282 | +} |
---|
| 3283 | + |
---|
| 3284 | +static void br_ip4_multicast_leave_snoopers(struct net_bridge *br) |
---|
| 3285 | +{ |
---|
| 3286 | + struct in_device *in_dev = in_dev_get(br->dev); |
---|
| 3287 | + |
---|
| 3288 | + if (WARN_ON(!in_dev)) |
---|
| 3289 | + return; |
---|
| 3290 | + |
---|
| 3291 | + __ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC); |
---|
| 3292 | + in_dev_put(in_dev); |
---|
| 3293 | +} |
---|
| 3294 | + |
---|
| 3295 | +#if IS_ENABLED(CONFIG_IPV6) |
---|
| 3296 | +static void br_ip6_multicast_leave_snoopers(struct net_bridge *br) |
---|
| 3297 | +{ |
---|
| 3298 | + struct in6_addr addr; |
---|
| 3299 | + |
---|
| 3300 | + ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a)); |
---|
| 3301 | + ipv6_dev_mc_dec(br->dev, &addr); |
---|
| 3302 | +} |
---|
| 3303 | +#else |
---|
| 3304 | +static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br) |
---|
| 3305 | +{ |
---|
| 3306 | +} |
---|
| 3307 | +#endif |
---|
| 3308 | + |
---|
| 3309 | +void br_multicast_leave_snoopers(struct net_bridge *br) |
---|
| 3310 | +{ |
---|
| 3311 | + br_ip4_multicast_leave_snoopers(br); |
---|
| 3312 | + br_ip6_multicast_leave_snoopers(br); |
---|
2003 | 3313 | } |
---|
2004 | 3314 | |
---|
2005 | 3315 | static void __br_multicast_open(struct net_bridge *br, |
---|
.. | .. |
---|
2007 | 3317 | { |
---|
2008 | 3318 | query->startup_sent = 0; |
---|
2009 | 3319 | |
---|
2010 | | - if (br->multicast_disabled) |
---|
| 3320 | + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
2011 | 3321 | return; |
---|
2012 | 3322 | |
---|
2013 | 3323 | mod_timer(&query->timer, jiffies); |
---|
.. | .. |
---|
2034 | 3344 | |
---|
2035 | 3345 | void br_multicast_dev_del(struct net_bridge *br) |
---|
2036 | 3346 | { |
---|
2037 | | - struct net_bridge_mdb_htable *mdb; |
---|
2038 | 3347 | struct net_bridge_mdb_entry *mp; |
---|
2039 | | - struct hlist_node *n; |
---|
2040 | | - u32 ver; |
---|
2041 | | - int i; |
---|
| 3348 | + HLIST_HEAD(deleted_head); |
---|
| 3349 | + struct hlist_node *tmp; |
---|
2042 | 3350 | |
---|
2043 | 3351 | spin_lock_bh(&br->multicast_lock); |
---|
2044 | | - mdb = mlock_dereference(br->mdb, br); |
---|
2045 | | - if (!mdb) |
---|
2046 | | - goto out; |
---|
2047 | | - |
---|
2048 | | - br->mdb = NULL; |
---|
2049 | | - |
---|
2050 | | - ver = mdb->ver; |
---|
2051 | | - for (i = 0; i < mdb->max; i++) { |
---|
2052 | | - hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], |
---|
2053 | | - hlist[ver]) { |
---|
2054 | | - del_timer(&mp->timer); |
---|
2055 | | - call_rcu_bh(&mp->rcu, br_multicast_free_group); |
---|
2056 | | - } |
---|
2057 | | - } |
---|
2058 | | - |
---|
2059 | | - if (mdb->old) { |
---|
2060 | | - spin_unlock_bh(&br->multicast_lock); |
---|
2061 | | - rcu_barrier_bh(); |
---|
2062 | | - spin_lock_bh(&br->multicast_lock); |
---|
2063 | | - WARN_ON(mdb->old); |
---|
2064 | | - } |
---|
2065 | | - |
---|
2066 | | - mdb->old = mdb; |
---|
2067 | | - call_rcu_bh(&mdb->rcu, br_mdb_free); |
---|
2068 | | - |
---|
2069 | | -out: |
---|
| 3352 | + hlist_for_each_entry_safe(mp, tmp, &br->mdb_list, mdb_node) |
---|
| 3353 | + br_multicast_del_mdb_entry(mp); |
---|
| 3354 | + hlist_move_list(&br->mcast_gc_list, &deleted_head); |
---|
2070 | 3355 | spin_unlock_bh(&br->multicast_lock); |
---|
| 3356 | + |
---|
| 3357 | + br_multicast_gc(&deleted_head); |
---|
| 3358 | + cancel_work_sync(&br->mcast_gc_work); |
---|
| 3359 | + |
---|
| 3360 | + rcu_barrier(); |
---|
2071 | 3361 | } |
---|
2072 | 3362 | |
---|
2073 | 3363 | int br_multicast_set_router(struct net_bridge *br, unsigned long val) |
---|
.. | .. |
---|
2179 | 3469 | |
---|
2180 | 3470 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) |
---|
2181 | 3471 | { |
---|
2182 | | - struct net_bridge_mdb_htable *mdb; |
---|
2183 | 3472 | struct net_bridge_port *port; |
---|
2184 | | - int err = 0; |
---|
| 3473 | + bool change_snoopers = false; |
---|
2185 | 3474 | |
---|
2186 | 3475 | spin_lock_bh(&br->multicast_lock); |
---|
2187 | | - if (br->multicast_disabled == !val) |
---|
| 3476 | + if (!!br_opt_get(br, BROPT_MULTICAST_ENABLED) == !!val) |
---|
2188 | 3477 | goto unlock; |
---|
2189 | 3478 | |
---|
2190 | | - br_mc_disabled_update(br->dev, !val); |
---|
2191 | | - br->multicast_disabled = !val; |
---|
2192 | | - if (br->multicast_disabled) |
---|
| 3479 | + br_mc_disabled_update(br->dev, val); |
---|
| 3480 | + br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val); |
---|
| 3481 | + if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) { |
---|
| 3482 | + change_snoopers = true; |
---|
2193 | 3483 | goto unlock; |
---|
| 3484 | + } |
---|
2194 | 3485 | |
---|
2195 | 3486 | if (!netif_running(br->dev)) |
---|
2196 | 3487 | goto unlock; |
---|
2197 | | - |
---|
2198 | | - mdb = mlock_dereference(br->mdb, br); |
---|
2199 | | - if (mdb) { |
---|
2200 | | - if (mdb->old) { |
---|
2201 | | - err = -EEXIST; |
---|
2202 | | -rollback: |
---|
2203 | | - br->multicast_disabled = !!val; |
---|
2204 | | - goto unlock; |
---|
2205 | | - } |
---|
2206 | | - |
---|
2207 | | - err = br_mdb_rehash(&br->mdb, mdb->max, |
---|
2208 | | - br->hash_elasticity); |
---|
2209 | | - if (err) |
---|
2210 | | - goto rollback; |
---|
2211 | | - } |
---|
2212 | 3488 | |
---|
2213 | 3489 | br_multicast_open(br); |
---|
2214 | 3490 | list_for_each_entry(port, &br->port_list, list) |
---|
2215 | 3491 | __br_multicast_enable_port(port); |
---|
2216 | 3492 | |
---|
| 3493 | + change_snoopers = true; |
---|
| 3494 | + |
---|
2217 | 3495 | unlock: |
---|
2218 | 3496 | spin_unlock_bh(&br->multicast_lock); |
---|
2219 | 3497 | |
---|
2220 | | - return err; |
---|
| 3498 | + /* br_multicast_join_snoopers has the potential to cause |
---|
| 3499 | + * an MLD Report/Leave to be delivered to br_multicast_rcv, |
---|
| 3500 | + * which would in turn call br_multicast_add_group, which would |
---|
| 3501 | + * attempt to acquire multicast_lock. This function should be |
---|
| 3502 | + * called after the lock has been released to avoid deadlocks on |
---|
| 3503 | + * multicast_lock. |
---|
| 3504 | + * |
---|
| 3505 | + * br_multicast_leave_snoopers does not have the problem since |
---|
| 3506 | + * br_multicast_rcv first checks BROPT_MULTICAST_ENABLED, and |
---|
| 3507 | + * returns without calling br_multicast_ipv4/6_rcv if it's not |
---|
| 3508 | + * enabled. Moved both functions out just for symmetry. |
---|
| 3509 | + */ |
---|
| 3510 | + if (change_snoopers) { |
---|
| 3511 | + if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
---|
| 3512 | + br_multicast_join_snoopers(br); |
---|
| 3513 | + else |
---|
| 3514 | + br_multicast_leave_snoopers(br); |
---|
| 3515 | + } |
---|
| 3516 | + |
---|
| 3517 | + return 0; |
---|
2221 | 3518 | } |
---|
2222 | 3519 | |
---|
2223 | 3520 | bool br_multicast_enabled(const struct net_device *dev) |
---|
2224 | 3521 | { |
---|
2225 | 3522 | struct net_bridge *br = netdev_priv(dev); |
---|
2226 | 3523 | |
---|
2227 | | - return !br->multicast_disabled; |
---|
| 3524 | + return !!br_opt_get(br, BROPT_MULTICAST_ENABLED); |
---|
2228 | 3525 | } |
---|
2229 | 3526 | EXPORT_SYMBOL_GPL(br_multicast_enabled); |
---|
2230 | 3527 | |
---|
.. | .. |
---|
2247 | 3544 | val = !!val; |
---|
2248 | 3545 | |
---|
2249 | 3546 | spin_lock_bh(&br->multicast_lock); |
---|
2250 | | - if (br->multicast_querier == val) |
---|
| 3547 | + if (br_opt_get(br, BROPT_MULTICAST_QUERIER) == val) |
---|
2251 | 3548 | goto unlock; |
---|
2252 | 3549 | |
---|
2253 | | - br->multicast_querier = val; |
---|
| 3550 | + br_opt_toggle(br, BROPT_MULTICAST_QUERIER, !!val); |
---|
2254 | 3551 | if (!val) |
---|
2255 | 3552 | goto unlock; |
---|
2256 | 3553 | |
---|
.. | .. |
---|
2272 | 3569 | spin_unlock_bh(&br->multicast_lock); |
---|
2273 | 3570 | |
---|
2274 | 3571 | return 0; |
---|
2275 | | -} |
---|
2276 | | - |
---|
2277 | | -int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) |
---|
2278 | | -{ |
---|
2279 | | - int err = -EINVAL; |
---|
2280 | | - u32 old; |
---|
2281 | | - struct net_bridge_mdb_htable *mdb; |
---|
2282 | | - |
---|
2283 | | - spin_lock_bh(&br->multicast_lock); |
---|
2284 | | - if (!is_power_of_2(val)) |
---|
2285 | | - goto unlock; |
---|
2286 | | - |
---|
2287 | | - mdb = mlock_dereference(br->mdb, br); |
---|
2288 | | - if (mdb && val < mdb->size) |
---|
2289 | | - goto unlock; |
---|
2290 | | - |
---|
2291 | | - err = 0; |
---|
2292 | | - |
---|
2293 | | - old = br->hash_max; |
---|
2294 | | - br->hash_max = val; |
---|
2295 | | - |
---|
2296 | | - if (mdb) { |
---|
2297 | | - if (mdb->old) { |
---|
2298 | | - err = -EEXIST; |
---|
2299 | | -rollback: |
---|
2300 | | - br->hash_max = old; |
---|
2301 | | - goto unlock; |
---|
2302 | | - } |
---|
2303 | | - |
---|
2304 | | - err = br_mdb_rehash(&br->mdb, br->hash_max, |
---|
2305 | | - br->hash_elasticity); |
---|
2306 | | - if (err) |
---|
2307 | | - goto rollback; |
---|
2308 | | - } |
---|
2309 | | - |
---|
2310 | | -unlock: |
---|
2311 | | - spin_unlock_bh(&br->multicast_lock); |
---|
2312 | | - |
---|
2313 | | - return err; |
---|
2314 | 3572 | } |
---|
2315 | 3573 | |
---|
2316 | 3574 | int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val) |
---|
.. | .. |
---|
2378 | 3636 | int count = 0; |
---|
2379 | 3637 | |
---|
2380 | 3638 | rcu_read_lock(); |
---|
2381 | | - if (!br_ip_list || !br_port_exists(dev)) |
---|
| 3639 | + if (!br_ip_list || !netif_is_bridge_port(dev)) |
---|
2382 | 3640 | goto unlock; |
---|
2383 | 3641 | |
---|
2384 | 3642 | port = br_port_get_rcu(dev); |
---|
.. | .. |
---|
2396 | 3654 | if (!entry) |
---|
2397 | 3655 | goto unlock; |
---|
2398 | 3656 | |
---|
2399 | | - entry->addr = group->addr; |
---|
| 3657 | + entry->addr = group->key.addr; |
---|
2400 | 3658 | list_add(&entry->list, br_ip_list); |
---|
2401 | 3659 | count++; |
---|
2402 | 3660 | } |
---|
.. | .. |
---|
2425 | 3683 | bool ret = false; |
---|
2426 | 3684 | |
---|
2427 | 3685 | rcu_read_lock(); |
---|
2428 | | - if (!br_port_exists(dev)) |
---|
| 3686 | + if (!netif_is_bridge_port(dev)) |
---|
2429 | 3687 | goto unlock; |
---|
2430 | 3688 | |
---|
2431 | 3689 | port = br_port_get_rcu(dev); |
---|
.. | .. |
---|
2461 | 3719 | bool ret = false; |
---|
2462 | 3720 | |
---|
2463 | 3721 | rcu_read_lock(); |
---|
2464 | | - if (!br_port_exists(dev)) |
---|
| 3722 | + if (!netif_is_bridge_port(dev)) |
---|
2465 | 3723 | goto unlock; |
---|
2466 | 3724 | |
---|
2467 | 3725 | port = br_port_get_rcu(dev); |
---|
.. | .. |
---|
2571 | 3829 | struct bridge_mcast_stats __percpu *stats; |
---|
2572 | 3830 | |
---|
2573 | 3831 | /* if multicast_disabled is true then igmp type can't be set */ |
---|
2574 | | - if (!type || !br->multicast_stats_enabled) |
---|
| 3832 | + if (!type || !br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) |
---|
2575 | 3833 | return; |
---|
2576 | 3834 | |
---|
2577 | 3835 | if (p) |
---|
.. | .. |
---|
2598 | 3856 | free_percpu(br->mcast_stats); |
---|
2599 | 3857 | } |
---|
2600 | 3858 | |
---|
2601 | | -static void mcast_stats_add_dir(u64 *dst, u64 *src) |
---|
| 3859 | +/* noinline for https://bugs.llvm.org/show_bug.cgi?id=45802#c9 */ |
---|
| 3860 | +static noinline_for_stack void mcast_stats_add_dir(u64 *dst, u64 *src) |
---|
2602 | 3861 | { |
---|
2603 | 3862 | dst[BR_MCAST_DIR_RX] += src[BR_MCAST_DIR_RX]; |
---|
2604 | 3863 | dst[BR_MCAST_DIR_TX] += src[BR_MCAST_DIR_TX]; |
---|
.. | .. |
---|
2649 | 3908 | } |
---|
2650 | 3909 | memcpy(dest, &tdst, sizeof(*dest)); |
---|
2651 | 3910 | } |
---|
| 3911 | + |
---|
| 3912 | +int br_mdb_hash_init(struct net_bridge *br) |
---|
| 3913 | +{ |
---|
| 3914 | + int err; |
---|
| 3915 | + |
---|
| 3916 | + err = rhashtable_init(&br->sg_port_tbl, &br_sg_port_rht_params); |
---|
| 3917 | + if (err) |
---|
| 3918 | + return err; |
---|
| 3919 | + |
---|
| 3920 | + err = rhashtable_init(&br->mdb_hash_tbl, &br_mdb_rht_params); |
---|
| 3921 | + if (err) { |
---|
| 3922 | + rhashtable_destroy(&br->sg_port_tbl); |
---|
| 3923 | + return err; |
---|
| 3924 | + } |
---|
| 3925 | + |
---|
| 3926 | + return 0; |
---|
| 3927 | +} |
---|
| 3928 | + |
---|
| 3929 | +void br_mdb_hash_fini(struct net_bridge *br) |
---|
| 3930 | +{ |
---|
| 3931 | + rhashtable_destroy(&br->sg_port_tbl); |
---|
| 3932 | + rhashtable_destroy(&br->mdb_hash_tbl); |
---|
| 3933 | +} |
---|