Blame view
net/bridge/br_multicast.c
59.6 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
eb1d16414 bridge: Add core ... |
2 3 4 5 |
/* * Bridge multicast support. * * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> |
eb1d16414 bridge: Add core ... |
6 7 8 |
*/ #include <linux/err.h> |
07f8ac4a1 bridge: add expor... |
9 |
#include <linux/export.h> |
eb1d16414 bridge: Add core ... |
10 11 |
#include <linux/if_ether.h> #include <linux/igmp.h> |
4b3087c7e bridge: Snoop Mul... |
12 |
#include <linux/in.h> |
eb1d16414 bridge: Add core ... |
13 14 |
#include <linux/jhash.h> #include <linux/kernel.h> |
b195167fc bridge: Add hash ... |
15 |
#include <linux/log2.h> |
eb1d16414 bridge: Add core ... |
16 17 18 19 20 21 22 |
#include <linux/netdevice.h> #include <linux/netfilter_bridge.h> #include <linux/random.h> #include <linux/rculist.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/timer.h> |
1c8ad5bfa bridge: use the b... |
23 |
#include <linux/inetdevice.h> |
91b02d3d1 bridge: mcast: ad... |
24 |
#include <linux/mroute.h> |
eb1d16414 bridge: Add core ... |
25 |
#include <net/ip.h> |
147c1e9b9 switchdev: bridge... |
26 |
#include <net/switchdev.h> |
dfd56b8b3 net: use IS_ENABL... |
27 |
#if IS_ENABLED(CONFIG_IPV6) |
4b3087c7e bridge: Snoop Mul... |
28 |
#include <linux/icmpv6.h> |
08b202b67 bridge br_multica... |
29 30 |
#include <net/ipv6.h> #include <net/mld.h> |
d4c4f07df bridge: Fix build... |
31 |
#include <net/ip6_checksum.h> |
3c3769e63 bridge: apply mul... |
32 |
#include <net/addrconf.h> |
08b202b67 bridge br_multica... |
33 |
#endif |
eb1d16414 bridge: Add core ... |
34 35 |
#include "br_private.h" |
19e3a9c90 net: bridge: conv... |
36 37 38 39 40 |
static const struct rhashtable_params br_mdb_rht_params = { .head_offset = offsetof(struct net_bridge_mdb_entry, rhnode), .key_offset = offsetof(struct net_bridge_mdb_entry, addr), .key_len = sizeof(struct br_ip), .automatic_shrinking = true, |
19e3a9c90 net: bridge: conv... |
41 |
}; |
cc0fdd802 bridge: separate ... |
42 |
static void br_multicast_start_querier(struct net_bridge *br, |
90010b36e bridge: rename st... |
43 |
struct bridge_mcast_own_query *query); |
754bc547f bridge: multicast... |
44 45 |
static void br_multicast_add_router(struct net_bridge *br, struct net_bridge_port *port); |
bc8c20aca bridge: multicast... |
46 47 48 |
static void br_ip4_multicast_leave_group(struct net_bridge *br, struct net_bridge_port *port, __be32 group, |
6db6f0eae bridge: multicast... |
49 50 |
__u16 vid, const unsigned char *src); |
f12e7d95d bridge: mcast: Me... |
51 |
static void __del_port_router(struct net_bridge_port *p); |
bc8c20aca bridge: multicast... |
52 53 54 55 |
#if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_leave_group(struct net_bridge *br, struct net_bridge_port *port, const struct in6_addr *group, |
6db6f0eae bridge: multicast... |
56 |
__u16 vid, const unsigned char *src); |
bc8c20aca bridge: multicast... |
57 |
#endif |
c83b8fab0 bridge: Restart q... |
58 |
|
19e3a9c90 net: bridge: conv... |
59 60 |
static struct net_bridge_mdb_entry *br_mdb_ip_get_rcu(struct net_bridge *br, struct br_ip *dst) |
08b202b67 bridge br_multica... |
61 |
{ |
19e3a9c90 net: bridge: conv... |
62 |
return rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params); |
08b202b67 bridge br_multica... |
63 |
} |
08b202b67 bridge br_multica... |
64 |
|
19e3a9c90 net: bridge: conv... |
65 66 |
struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge *br, struct br_ip *dst) |
eb1d16414 bridge: Add core ... |
67 |
{ |
19e3a9c90 net: bridge: conv... |
68 |
struct net_bridge_mdb_entry *ent; |
eb1d16414 bridge: Add core ... |
69 |
|
19e3a9c90 net: bridge: conv... |
70 |
lockdep_assert_held_once(&br->multicast_lock); |
eb1d16414 bridge: Add core ... |
71 |
|
19e3a9c90 net: bridge: conv... |
72 73 74 |
rcu_read_lock(); ent = rhashtable_lookup(&br->mdb_hash_tbl, dst, br_mdb_rht_params); rcu_read_unlock(); |
7f285fa78 bridge br_multica... |
75 |
|
19e3a9c90 net: bridge: conv... |
76 |
return ent; |
7f285fa78 bridge br_multica... |
77 |
} |
19e3a9c90 net: bridge: conv... |
78 79 |
static struct net_bridge_mdb_entry *br_mdb_ip4_get(struct net_bridge *br, __be32 dst, __u16 vid) |
eb1d16414 bridge: Add core ... |
80 |
{ |
8ef2a9a59 bridge br_multica... |
81 |
struct br_ip br_dst; |
19e3a9c90 net: bridge: conv... |
82 |
memset(&br_dst, 0, sizeof(br_dst)); |
8ef2a9a59 bridge br_multica... |
83 84 |
br_dst.u.ip4 = dst; br_dst.proto = htons(ETH_P_IP); |
b0e9a30dd bridge: Add vlan ... |
85 |
br_dst.vid = vid; |
0821ec55b bridge: Move NULL... |
86 |
|
19e3a9c90 net: bridge: conv... |
87 |
return br_mdb_ip_get(br, &br_dst); |
8ef2a9a59 bridge br_multica... |
88 |
} |
dfd56b8b3 net: use IS_ENABL... |
89 |
#if IS_ENABLED(CONFIG_IPV6) |
19e3a9c90 net: bridge: conv... |
90 91 92 |
static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br, const struct in6_addr *dst, __u16 vid) |
08b202b67 bridge br_multica... |
93 94 |
{ struct br_ip br_dst; |
0821ec55b bridge: Move NULL... |
95 |
|
19e3a9c90 net: bridge: conv... |
96 |
memset(&br_dst, 0, sizeof(br_dst)); |
4e3fd7a06 net: remove ipv6_... |
97 |
br_dst.u.ip6 = *dst; |
08b202b67 bridge br_multica... |
98 |
br_dst.proto = htons(ETH_P_IPV6); |
b0e9a30dd bridge: Add vlan ... |
99 |
br_dst.vid = vid; |
08b202b67 bridge br_multica... |
100 |
|
19e3a9c90 net: bridge: conv... |
101 |
return br_mdb_ip_get(br, &br_dst); |
08b202b67 bridge br_multica... |
102 103 |
} #endif |
eb1d16414 bridge: Add core ... |
104 |
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, |
fbca58a22 bridge: add missi... |
105 |
struct sk_buff *skb, u16 vid) |
eb1d16414 bridge: Add core ... |
106 |
{ |
8ef2a9a59 bridge br_multica... |
107 |
struct br_ip ip; |
13cefad2f net: bridge: conv... |
108 |
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
eb1d16414 bridge: Add core ... |
109 |
return NULL; |
8ef2a9a59 bridge br_multica... |
110 |
if (BR_INPUT_SKB_CB(skb)->igmp) |
eb1d16414 bridge: Add core ... |
111 |
return NULL; |
19e3a9c90 net: bridge: conv... |
112 |
memset(&ip, 0, sizeof(ip)); |
8ef2a9a59 bridge br_multica... |
113 |
ip.proto = skb->protocol; |
fbca58a22 bridge: add missi... |
114 |
ip.vid = vid; |
8ef2a9a59 bridge br_multica... |
115 |
|
eb1d16414 bridge: Add core ... |
116 117 |
switch (skb->protocol) { case htons(ETH_P_IP): |
8ef2a9a59 bridge br_multica... |
118 119 |
ip.u.ip4 = ip_hdr(skb)->daddr; break; |
dfd56b8b3 net: use IS_ENABL... |
120 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
121 |
case htons(ETH_P_IPV6): |
4e3fd7a06 net: remove ipv6_... |
122 |
ip.u.ip6 = ipv6_hdr(skb)->daddr; |
08b202b67 bridge br_multica... |
123 124 |
break; #endif |
8ef2a9a59 bridge br_multica... |
125 126 |
default: return NULL; |
eb1d16414 bridge: Add core ... |
127 |
} |
19e3a9c90 net: bridge: conv... |
128 |
return br_mdb_ip_get_rcu(br, &ip); |
eb1d16414 bridge: Add core ... |
129 |
} |
88c1f37f0 net: bridge: Conv... |
130 |
static void br_multicast_group_expired(struct timer_list *t) |
eb1d16414 bridge: Add core ... |
131 |
{ |
88c1f37f0 net: bridge: Conv... |
132 |
struct net_bridge_mdb_entry *mp = from_timer(mp, t, timer); |
eb1d16414 bridge: Add core ... |
133 |
struct net_bridge *br = mp->br; |
eb1d16414 bridge: Add core ... |
134 135 136 137 |
spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || timer_pending(&mp->timer)) goto out; |
1bc844ee0 net: bridge: mdb:... |
138 |
br_multicast_host_leave(mp, true); |
eb1d16414 bridge: Add core ... |
139 140 141 |
if (mp->ports) goto out; |
19e3a9c90 net: bridge: conv... |
142 143 144 |
rhashtable_remove_fast(&br->mdb_hash_tbl, &mp->rhnode, br_mdb_rht_params); hlist_del_rcu(&mp->mdb_node); |
eb1d16414 bridge: Add core ... |
145 |
|
4329596cb net: bridge: mult... |
146 |
kfree_rcu(mp, rcu); |
eb1d16414 bridge: Add core ... |
147 148 149 150 151 152 153 154 |
out: spin_unlock(&br->multicast_lock); } static void br_multicast_del_pg(struct net_bridge *br, struct net_bridge_port_group *pg) { |
eb1d16414 bridge: Add core ... |
155 156 |
struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; |
e80516880 bridge: add RCU a... |
157 |
struct net_bridge_port_group __rcu **pp; |
19e3a9c90 net: bridge: conv... |
158 |
mp = br_mdb_ip_get(br, &pg->addr); |
eb1d16414 bridge: Add core ... |
159 160 |
if (WARN_ON(!mp)) return; |
e80516880 bridge: add RCU a... |
161 162 163 |
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { |
eb1d16414 bridge: Add core ... |
164 165 |
if (p != pg) continue; |
83f6a740b bridge: multicast... |
166 |
rcu_assign_pointer(*pp, p->next); |
eb1d16414 bridge: Add core ... |
167 168 |
hlist_del_init(&p->mglist); del_timer(&p->timer); |
45ebcce56 bridge: mdb: Mark... |
169 170 |
br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB, p->flags); |
4329596cb net: bridge: mult... |
171 |
kfree_rcu(p, rcu); |
eb1d16414 bridge: Add core ... |
172 |
|
ff0fd34ea net: bridge: Rena... |
173 |
if (!mp->ports && !mp->host_joined && |
eb1d16414 bridge: Add core ... |
174 175 176 177 178 179 180 181 |
netif_running(br->dev)) mod_timer(&mp->timer, jiffies); return; } WARN_ON(1); } |
88c1f37f0 net: bridge: Conv... |
182 |
static void br_multicast_port_group_expired(struct timer_list *t) |
eb1d16414 bridge: Add core ... |
183 |
{ |
88c1f37f0 net: bridge: Conv... |
184 |
struct net_bridge_port_group *pg = from_timer(pg, t, timer); |
eb1d16414 bridge: Add core ... |
185 186 187 188 |
struct net_bridge *br = pg->port->br; spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || timer_pending(&pg->timer) || |
9d06b6d8a bridge: mdb: Sepa... |
189 |
hlist_unhashed(&pg->mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT) |
eb1d16414 bridge: Add core ... |
190 191 192 193 194 195 196 |
goto out; br_multicast_del_pg(br, pg); out: spin_unlock(&br->multicast_lock); } |
8ef2a9a59 bridge br_multica... |
197 |
static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, |
1080ab95e net: bridge: add ... |
198 199 |
__be32 group, u8 *igmp_type) |
eb1d16414 bridge: Add core ... |
200 |
{ |
5e9235853 bridge: mcast: ad... |
201 202 |
struct igmpv3_query *ihv3; size_t igmp_hdr_size; |
eb1d16414 bridge: Add core ... |
203 204 205 206 |
struct sk_buff *skb; struct igmphdr *ih; struct ethhdr *eth; struct iphdr *iph; |
5e9235853 bridge: mcast: ad... |
207 208 209 |
igmp_hdr_size = sizeof(*ih); if (br->multicast_igmp_version == 3) igmp_hdr_size = sizeof(*ihv3); |
eb1d16414 bridge: Add core ... |
210 |
skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*iph) + |
5e9235853 bridge: mcast: ad... |
211 |
igmp_hdr_size + 4); |
eb1d16414 bridge: Add core ... |
212 213 214 215 216 217 218 |
if (!skb) goto out; skb->protocol = htons(ETH_P_IP); skb_reset_mac_header(skb); eth = eth_hdr(skb); |
e5a727f66 bridge: Use ether... |
219 |
ether_addr_copy(eth->h_source, br->dev->dev_addr); |
eb1d16414 bridge: Add core ... |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
eth->h_dest[0] = 1; eth->h_dest[1] = 0; eth->h_dest[2] = 0x5e; eth->h_dest[3] = 0; eth->h_dest[4] = 0; eth->h_dest[5] = 1; eth->h_proto = htons(ETH_P_IP); skb_put(skb, sizeof(*eth)); skb_set_network_header(skb, skb->len); iph = ip_hdr(skb); iph->version = 4; iph->ihl = 6; iph->tos = 0xc0; |
5e9235853 bridge: mcast: ad... |
235 |
iph->tot_len = htons(sizeof(*iph) + igmp_hdr_size + 4); |
eb1d16414 bridge: Add core ... |
236 237 238 239 |
iph->id = 0; iph->frag_off = htons(IP_DF); iph->ttl = 1; iph->protocol = IPPROTO_IGMP; |
675779adb net: bridge: conv... |
240 |
iph->saddr = br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR) ? |
1c8ad5bfa bridge: use the b... |
241 |
inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0; |
eb1d16414 bridge: Add core ... |
242 243 244 245 246 247 248 249 250 |
iph->daddr = htonl(INADDR_ALLHOSTS_GROUP); ((u8 *)&iph[1])[0] = IPOPT_RA; ((u8 *)&iph[1])[1] = 4; ((u8 *)&iph[1])[2] = 0; ((u8 *)&iph[1])[3] = 0; ip_send_check(iph); skb_put(skb, 24); skb_set_transport_header(skb, skb->len); |
1080ab95e net: bridge: add ... |
251 |
*igmp_type = IGMP_HOST_MEMBERSHIP_QUERY; |
eb1d16414 bridge: Add core ... |
252 |
|
5e9235853 bridge: mcast: ad... |
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
switch (br->multicast_igmp_version) { case 2: ih = igmp_hdr(skb); ih->type = IGMP_HOST_MEMBERSHIP_QUERY; ih->code = (group ? br->multicast_last_member_interval : br->multicast_query_response_interval) / (HZ / IGMP_TIMER_SCALE); ih->group = group; ih->csum = 0; ih->csum = ip_compute_csum((void *)ih, sizeof(*ih)); break; case 3: ihv3 = igmpv3_query_hdr(skb); ihv3->type = IGMP_HOST_MEMBERSHIP_QUERY; ihv3->code = (group ? br->multicast_last_member_interval : br->multicast_query_response_interval) / (HZ / IGMP_TIMER_SCALE); ihv3->group = group; ihv3->qqic = br->multicast_query_interval / HZ; ihv3->nsrcs = 0; ihv3->resv = 0; ihv3->suppress = 0; ihv3->qrv = 2; ihv3->csum = 0; ihv3->csum = ip_compute_csum((void *)ihv3, sizeof(*ihv3)); break; } skb_put(skb, igmp_hdr_size); |
eb1d16414 bridge: Add core ... |
282 283 284 285 286 |
__skb_pull(skb, sizeof(*eth)); out: return skb; } |
dfd56b8b3 net: use IS_ENABL... |
287 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
288 |
static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, |
1080ab95e net: bridge: add ... |
289 290 |
const struct in6_addr *grp, u8 *igmp_type) |
08b202b67 bridge br_multica... |
291 |
{ |
aa2ae3e71 bridge: mcast: ad... |
292 293 |
struct mld2_query *mld2q; unsigned long interval; |
08b202b67 bridge br_multica... |
294 295 |
struct ipv6hdr *ip6h; struct mld_msg *mldq; |
aa2ae3e71 bridge: mcast: ad... |
296 297 |
size_t mld_hdr_size; struct sk_buff *skb; |
08b202b67 bridge br_multica... |
298 299 |
struct ethhdr *eth; u8 *hopopt; |
08b202b67 bridge br_multica... |
300 |
|
aa2ae3e71 bridge: mcast: ad... |
301 302 303 |
mld_hdr_size = sizeof(*mldq); if (br->multicast_mld_version == 2) mld_hdr_size = sizeof(*mld2q); |
08b202b67 bridge br_multica... |
304 |
skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*ip6h) + |
aa2ae3e71 bridge: mcast: ad... |
305 |
8 + mld_hdr_size); |
08b202b67 bridge br_multica... |
306 307 308 309 310 311 312 313 |
if (!skb) goto out; skb->protocol = htons(ETH_P_IPV6); /* Ethernet header */ skb_reset_mac_header(skb); eth = eth_hdr(skb); |
e5a727f66 bridge: Use ether... |
314 |
ether_addr_copy(eth->h_source, br->dev->dev_addr); |
08b202b67 bridge br_multica... |
315 316 317 318 319 320 321 322 |
eth->h_proto = htons(ETH_P_IPV6); skb_put(skb, sizeof(*eth)); /* IPv6 header + HbH option */ skb_set_network_header(skb, skb->len); ip6h = ipv6_hdr(skb); *(__force __be32 *)ip6h = htonl(0x60000000); |
aa2ae3e71 bridge: mcast: ad... |
323 |
ip6h->payload_len = htons(8 + mld_hdr_size); |
08b202b67 bridge br_multica... |
324 325 |
ip6h->nexthdr = IPPROTO_HOPOPTS; ip6h->hop_limit = 1; |
a7bff75b0 bridge: Fix possi... |
326 |
ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1)); |
d1d81d4c3 bridge: check ret... |
327 328 329 |
if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, &ip6h->saddr)) { kfree_skb(skb); |
675779adb net: bridge: conv... |
330 |
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, false); |
d1d81d4c3 bridge: check ret... |
331 332 |
return NULL; } |
0888d5f3c Bridge: Fix ipv6 ... |
333 |
|
675779adb net: bridge: conv... |
334 |
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); |
36cff5a10 bridge: Fix MLD q... |
335 |
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); |
08b202b67 bridge br_multica... |
336 337 338 339 340 341 342 343 |
hopopt = (u8 *)(ip6h + 1); hopopt[0] = IPPROTO_ICMPV6; /* next hdr */ hopopt[1] = 0; /* length of HbH */ hopopt[2] = IPV6_TLV_ROUTERALERT; /* Router Alert */ hopopt[3] = 2; /* Length of RA Option */ hopopt[4] = 0; /* Type = 0x0000 (MLD) */ hopopt[5] = 0; |
1de5a71c3 ipv6: correct the... |
344 345 |
hopopt[6] = IPV6_TLV_PAD1; /* Pad1 */ hopopt[7] = IPV6_TLV_PAD1; /* Pad1 */ |
08b202b67 bridge br_multica... |
346 347 348 349 350 |
skb_put(skb, sizeof(*ip6h) + 8); /* ICMPv6 */ skb_set_transport_header(skb, skb->len); |
1080ab95e net: bridge: add ... |
351 |
interval = ipv6_addr_any(grp) ? |
32de868cb bridge: fix switc... |
352 353 |
br->multicast_query_response_interval : br->multicast_last_member_interval; |
1080ab95e net: bridge: add ... |
354 |
*igmp_type = ICMPV6_MGM_QUERY; |
aa2ae3e71 bridge: mcast: ad... |
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
switch (br->multicast_mld_version) { case 1: mldq = (struct mld_msg *)icmp6_hdr(skb); mldq->mld_type = ICMPV6_MGM_QUERY; mldq->mld_code = 0; mldq->mld_cksum = 0; mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval)); mldq->mld_reserved = 0; mldq->mld_mca = *grp; mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, sizeof(*mldq), IPPROTO_ICMPV6, csum_partial(mldq, sizeof(*mldq), 0)); break; case 2: mld2q = (struct mld2_query *)icmp6_hdr(skb); |
53631a5f9 bridge: sparse fi... |
372 |
mld2q->mld2q_mrc = htons((u16)jiffies_to_msecs(interval)); |
aa2ae3e71 bridge: mcast: ad... |
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
mld2q->mld2q_type = ICMPV6_MGM_QUERY; mld2q->mld2q_code = 0; mld2q->mld2q_cksum = 0; mld2q->mld2q_resv1 = 0; mld2q->mld2q_resv2 = 0; mld2q->mld2q_suppress = 0; mld2q->mld2q_qrv = 2; mld2q->mld2q_nsrcs = 0; mld2q->mld2q_qqic = br->multicast_query_interval / HZ; mld2q->mld2q_mca = *grp; mld2q->mld2q_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, sizeof(*mld2q), IPPROTO_ICMPV6, csum_partial(mld2q, sizeof(*mld2q), 0)); break; } skb_put(skb, mld_hdr_size); |
08b202b67 bridge br_multica... |
392 393 394 395 396 397 398 |
__skb_pull(skb, sizeof(*eth)); out: return skb; } #endif |
8ef2a9a59 bridge br_multica... |
399 |
static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, |
1080ab95e net: bridge: add ... |
400 401 |
struct br_ip *addr, u8 *igmp_type) |
8ef2a9a59 bridge br_multica... |
402 403 404 |
{ switch (addr->proto) { case htons(ETH_P_IP): |
1080ab95e net: bridge: add ... |
405 |
return br_ip4_multicast_alloc_query(br, addr->u.ip4, igmp_type); |
dfd56b8b3 net: use IS_ENABL... |
406 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
407 |
case htons(ETH_P_IPV6): |
1080ab95e net: bridge: add ... |
408 409 |
return br_ip6_multicast_alloc_query(br, &addr->u.ip6, igmp_type); |
08b202b67 bridge br_multica... |
410 |
#endif |
8ef2a9a59 bridge br_multica... |
411 412 413 |
} return NULL; } |
cfd567543 bridge: add suppo... |
414 |
struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br, |
5e9235853 bridge: mcast: ad... |
415 |
struct br_ip *group) |
eb1d16414 bridge: Add core ... |
416 |
{ |
eb1d16414 bridge: Add core ... |
417 |
struct net_bridge_mdb_entry *mp; |
4c0833bcd bridge: Fix retur... |
418 |
int err; |
eb1d16414 bridge: Add core ... |
419 |
|
19e3a9c90 net: bridge: conv... |
420 421 422 |
mp = br_mdb_ip_get(br, group); if (mp) return mp; |
eb1d16414 bridge: Add core ... |
423 |
|
19e3a9c90 net: bridge: conv... |
424 425 426 |
if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) { br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false); return ERR_PTR(-E2BIG); |
eb1d16414 bridge: Add core ... |
427 428 429 430 |
} mp = kzalloc(sizeof(*mp), GFP_ATOMIC); if (unlikely(!mp)) |
4c0833bcd bridge: Fix retur... |
431 |
return ERR_PTR(-ENOMEM); |
eb1d16414 bridge: Add core ... |
432 433 |
mp->br = br; |
8ef2a9a59 bridge br_multica... |
434 |
mp->addr = *group; |
88c1f37f0 net: bridge: Conv... |
435 |
timer_setup(&mp->timer, br_multicast_group_expired, 0); |
19e3a9c90 net: bridge: conv... |
436 437 438 439 440 441 442 443 |
err = rhashtable_lookup_insert_fast(&br->mdb_hash_tbl, &mp->rhnode, br_mdb_rht_params); if (err) { kfree(mp); mp = ERR_PTR(err); } else { hlist_add_head_rcu(&mp->mdb_node, &br->mdb_list); } |
1faabf2aa bridge: do not ca... |
444 |
|
eb1d16414 bridge: Add core ... |
445 446 |
return mp; } |
cfd567543 bridge: add suppo... |
447 448 449 |
struct net_bridge_port_group *br_multicast_new_port_group( struct net_bridge_port *port, struct br_ip *group, |
ccb1c31a7 bridge: add flags... |
450 |
struct net_bridge_port_group __rcu *next, |
6db6f0eae bridge: multicast... |
451 452 |
unsigned char flags, const unsigned char *src) |
cfd567543 bridge: add suppo... |
453 454 455 456 457 458 459 460 461 |
{ struct net_bridge_port_group *p; p = kzalloc(sizeof(*p), GFP_ATOMIC); if (unlikely(!p)) return NULL; p->addr = *group; p->port = port; |
9d06b6d8a bridge: mdb: Sepa... |
462 |
p->flags = flags; |
eca2a43bb bridge: fix icmpv... |
463 |
rcu_assign_pointer(p->next, next); |
cfd567543 bridge: add suppo... |
464 |
hlist_add_head(&p->mglist, &port->mglist); |
88c1f37f0 net: bridge: Conv... |
465 |
timer_setup(&p->timer, br_multicast_port_group_expired, 0); |
6db6f0eae bridge: multicast... |
466 467 468 469 |
if (src) memcpy(p->eth_addr, src, ETH_ALEN); else |
1bfe45f4a net: bridge: use ... |
470 |
eth_broadcast_addr(p->eth_addr); |
6db6f0eae bridge: multicast... |
471 |
|
cfd567543 bridge: add suppo... |
472 473 |
return p; } |
6db6f0eae bridge: multicast... |
474 475 476 477 478 479 480 481 482 483 484 485 |
static bool br_port_group_equal(struct net_bridge_port_group *p, struct net_bridge_port *port, const unsigned char *src) { if (p->port != port) return false; if (!(port->flags & BR_MULTICAST_TO_UNICAST)) return true; return ether_addr_equal(src, p->eth_addr); } |
1bc844ee0 net: bridge: mdb:... |
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
void br_multicast_host_join(struct net_bridge_mdb_entry *mp, bool notify) { if (!mp->host_joined) { mp->host_joined = true; if (notify) br_mdb_notify(mp->br->dev, NULL, &mp->addr, RTM_NEWMDB, 0); } mod_timer(&mp->timer, jiffies + mp->br->multicast_membership_interval); } void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify) { if (!mp->host_joined) return; mp->host_joined = false; if (notify) br_mdb_notify(mp->br->dev, NULL, &mp->addr, RTM_DELMDB, 0); } |
eb1d16414 bridge: Add core ... |
506 |
static int br_multicast_add_group(struct net_bridge *br, |
8ef2a9a59 bridge br_multica... |
507 |
struct net_bridge_port *port, |
6db6f0eae bridge: multicast... |
508 509 |
struct br_ip *group, const unsigned char *src) |
eb1d16414 bridge: Add core ... |
510 |
{ |
e80516880 bridge: add RCU a... |
511 |
struct net_bridge_port_group __rcu **pp; |
5e9235853 bridge: mcast: ad... |
512 513 |
struct net_bridge_port_group *p; struct net_bridge_mdb_entry *mp; |
454594f3b Revert "bridge: o... |
514 |
unsigned long now = jiffies; |
eb1d16414 bridge: Add core ... |
515 |
int err; |
eb1d16414 bridge: Add core ... |
516 517 518 519 |
spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || (port && port->state == BR_STATE_DISABLED)) goto out; |
19e3a9c90 net: bridge: conv... |
520 |
mp = br_multicast_new_group(br, group); |
eb1d16414 bridge: Add core ... |
521 |
err = PTR_ERR(mp); |
4c0833bcd bridge: Fix retur... |
522 |
if (IS_ERR(mp)) |
eb1d16414 bridge: Add core ... |
523 524 525 |
goto err; if (!port) { |
1bc844ee0 net: bridge: mdb:... |
526 |
br_multicast_host_join(mp, true); |
eb1d16414 bridge: Add core ... |
527 528 |
goto out; } |
e80516880 bridge: add RCU a... |
529 530 531 |
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { |
6db6f0eae bridge: multicast... |
532 |
if (br_port_group_equal(p, port, src)) |
454594f3b Revert "bridge: o... |
533 |
goto found; |
eb1d16414 bridge: Add core ... |
534 535 536 |
if ((unsigned long)p->port < (unsigned long)port) break; } |
6db6f0eae bridge: multicast... |
537 |
p = br_multicast_new_port_group(port, group, *pp, 0, src); |
eb1d16414 bridge: Add core ... |
538 539 |
if (unlikely(!p)) goto err; |
eb1d16414 bridge: Add core ... |
540 |
rcu_assign_pointer(*pp, p); |
45ebcce56 bridge: mdb: Mark... |
541 |
br_mdb_notify(br->dev, port, group, RTM_NEWMDB, 0); |
eb1d16414 bridge: Add core ... |
542 |
|
454594f3b Revert "bridge: o... |
543 544 |
found: mod_timer(&p->timer, now + br->multicast_membership_interval); |
eb1d16414 bridge: Add core ... |
545 546 547 548 549 550 551 |
out: err = 0; err: spin_unlock(&br->multicast_lock); return err; } |
8ef2a9a59 bridge br_multica... |
552 553 |
static int br_ip4_multicast_add_group(struct net_bridge *br, struct net_bridge_port *port, |
b0e9a30dd bridge: Add vlan ... |
554 |
__be32 group, |
6db6f0eae bridge: multicast... |
555 556 |
__u16 vid, const unsigned char *src) |
8ef2a9a59 bridge br_multica... |
557 558 559 560 561 |
{ struct br_ip br_group; if (ipv4_is_local_multicast(group)) return 0; |
1515a63fc net: bridge: alwa... |
562 |
memset(&br_group, 0, sizeof(br_group)); |
8ef2a9a59 bridge br_multica... |
563 564 |
br_group.u.ip4 = group; br_group.proto = htons(ETH_P_IP); |
b0e9a30dd bridge: Add vlan ... |
565 |
br_group.vid = vid; |
8ef2a9a59 bridge br_multica... |
566 |
|
6db6f0eae bridge: multicast... |
567 |
return br_multicast_add_group(br, port, &br_group, src); |
8ef2a9a59 bridge br_multica... |
568 |
} |
dfd56b8b3 net: use IS_ENABL... |
569 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
570 571 |
static int br_ip6_multicast_add_group(struct net_bridge *br, struct net_bridge_port *port, |
b0e9a30dd bridge: Add vlan ... |
572 |
const struct in6_addr *group, |
6db6f0eae bridge: multicast... |
573 574 |
__u16 vid, const unsigned char *src) |
08b202b67 bridge br_multica... |
575 576 |
{ struct br_ip br_group; |
3c3769e63 bridge: apply mul... |
577 |
if (ipv6_addr_is_ll_all_nodes(group)) |
08b202b67 bridge br_multica... |
578 |
return 0; |
19e3a9c90 net: bridge: conv... |
579 |
memset(&br_group, 0, sizeof(br_group)); |
4e3fd7a06 net: remove ipv6_... |
580 |
br_group.u.ip6 = *group; |
9cc6e0c4c bridge: Fix IPv6 ... |
581 |
br_group.proto = htons(ETH_P_IPV6); |
b0e9a30dd bridge: Add vlan ... |
582 |
br_group.vid = vid; |
08b202b67 bridge br_multica... |
583 |
|
6db6f0eae bridge: multicast... |
584 |
return br_multicast_add_group(br, port, &br_group, src); |
08b202b67 bridge br_multica... |
585 586 |
} #endif |
88c1f37f0 net: bridge: Conv... |
587 |
static void br_multicast_router_expired(struct timer_list *t) |
eb1d16414 bridge: Add core ... |
588 |
{ |
88c1f37f0 net: bridge: Conv... |
589 590 |
struct net_bridge_port *port = from_timer(port, t, multicast_router_timer); |
eb1d16414 bridge: Add core ... |
591 592 593 |
struct net_bridge *br = port->br; spin_lock(&br->multicast_lock); |
a55d8246a bridge: mcast: ad... |
594 595 |
if (port->multicast_router == MDB_RTR_TYPE_DISABLED || port->multicast_router == MDB_RTR_TYPE_PERM || |
f12e7d95d bridge: mcast: Me... |
596 |
timer_pending(&port->multicast_router_timer)) |
eb1d16414 bridge: Add core ... |
597 |
goto out; |
f12e7d95d bridge: mcast: Me... |
598 |
__del_port_router(port); |
eb1d16414 bridge: Add core ... |
599 600 601 |
out: spin_unlock(&br->multicast_lock); } |
770414207 net: bridge: Noti... |
602 603 604 605 606 607 608 609 610 611 612 613 |
static void br_mc_router_state_change(struct net_bridge *p, bool is_mc_router) { struct switchdev_attr attr = { .orig_dev = p->dev, .id = SWITCHDEV_ATTR_ID_BRIDGE_MROUTER, .flags = SWITCHDEV_F_DEFER, .u.mrouter = is_mc_router, }; switchdev_port_attr_set(p->dev, &attr); } |
88c1f37f0 net: bridge: Conv... |
614 |
static void br_multicast_local_router_expired(struct timer_list *t) |
eb1d16414 bridge: Add core ... |
615 |
{ |
88c1f37f0 net: bridge: Conv... |
616 |
struct net_bridge *br = from_timer(br, t, multicast_router_timer); |
770414207 net: bridge: Noti... |
617 618 619 620 621 622 623 624 625 626 |
spin_lock(&br->multicast_lock); if (br->multicast_router == MDB_RTR_TYPE_DISABLED || br->multicast_router == MDB_RTR_TYPE_PERM || timer_pending(&br->multicast_router_timer)) goto out; br_mc_router_state_change(br, false); out: spin_unlock(&br->multicast_lock); |
eb1d16414 bridge: Add core ... |
627 |
} |
cc0fdd802 bridge: separate ... |
628 |
static void br_multicast_querier_expired(struct net_bridge *br, |
90010b36e bridge: rename st... |
629 |
struct bridge_mcast_own_query *query) |
c83b8fab0 bridge: Restart q... |
630 |
{ |
c83b8fab0 bridge: Restart q... |
631 |
spin_lock(&br->multicast_lock); |
13cefad2f net: bridge: conv... |
632 |
if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
c83b8fab0 bridge: Restart q... |
633 |
goto out; |
cc0fdd802 bridge: separate ... |
634 |
br_multicast_start_querier(br, query); |
c83b8fab0 bridge: Restart q... |
635 636 637 638 |
out: spin_unlock(&br->multicast_lock); } |
88c1f37f0 net: bridge: Conv... |
639 |
static void br_ip4_multicast_querier_expired(struct timer_list *t) |
cc0fdd802 bridge: separate ... |
640 |
{ |
88c1f37f0 net: bridge: Conv... |
641 |
struct net_bridge *br = from_timer(br, t, ip4_other_query.timer); |
cc0fdd802 bridge: separate ... |
642 |
|
90010b36e bridge: rename st... |
643 |
br_multicast_querier_expired(br, &br->ip4_own_query); |
cc0fdd802 bridge: separate ... |
644 645 646 |
} #if IS_ENABLED(CONFIG_IPV6) |
88c1f37f0 net: bridge: Conv... |
647 |
static void br_ip6_multicast_querier_expired(struct timer_list *t) |
cc0fdd802 bridge: separate ... |
648 |
{ |
88c1f37f0 net: bridge: Conv... |
649 |
struct net_bridge *br = from_timer(br, t, ip6_other_query.timer); |
cc0fdd802 bridge: separate ... |
650 |
|
90010b36e bridge: rename st... |
651 |
br_multicast_querier_expired(br, &br->ip6_own_query); |
cc0fdd802 bridge: separate ... |
652 653 |
} #endif |
dc4eb53a9 bridge: adhere to... |
654 655 656 657 658 659 660 661 662 663 664 |
static void br_multicast_select_own_querier(struct net_bridge *br, struct br_ip *ip, struct sk_buff *skb) { if (ip->proto == htons(ETH_P_IP)) br->ip4_querier.addr.u.ip4 = ip_hdr(skb)->saddr; #if IS_ENABLED(CONFIG_IPV6) else br->ip6_querier.addr.u.ip6 = ipv6_hdr(skb)->saddr; #endif } |
8ef2a9a59 bridge br_multica... |
665 666 667 |
static void __br_multicast_send_query(struct net_bridge *br, struct net_bridge_port *port, struct br_ip *ip) |
eb1d16414 bridge: Add core ... |
668 |
{ |
eb1d16414 bridge: Add core ... |
669 |
struct sk_buff *skb; |
1080ab95e net: bridge: add ... |
670 |
u8 igmp_type; |
eb1d16414 bridge: Add core ... |
671 |
|
1080ab95e net: bridge: add ... |
672 |
skb = br_multicast_alloc_query(br, ip, &igmp_type); |
eb1d16414 bridge: Add core ... |
673 |
if (!skb) |
8ef2a9a59 bridge br_multica... |
674 |
return; |
eb1d16414 bridge: Add core ... |
675 676 |
if (port) { |
eb1d16414 bridge: Add core ... |
677 |
skb->dev = port->dev; |
a65056ecf net: bridge: exte... |
678 |
br_multicast_count(br, port, skb, igmp_type, |
1080ab95e net: bridge: add ... |
679 |
BR_MCAST_DIR_TX); |
29a26a568 netfilter: Pass s... |
680 681 |
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, dev_net(port->dev), NULL, skb, NULL, skb->dev, |
f0b4eeced bridge: fix netfi... |
682 |
br_dev_queue_push_xmit); |
dc4eb53a9 bridge: adhere to... |
683 684 |
} else { br_multicast_select_own_querier(br, ip, skb); |
a65056ecf net: bridge: exte... |
685 |
br_multicast_count(br, port, skb, igmp_type, |
1080ab95e net: bridge: add ... |
686 |
BR_MCAST_DIR_RX); |
eb1d16414 bridge: Add core ... |
687 |
netif_rx(skb); |
dc4eb53a9 bridge: adhere to... |
688 |
} |
8ef2a9a59 bridge br_multica... |
689 690 691 |
} static void br_multicast_send_query(struct net_bridge *br, |
cc0fdd802 bridge: separate ... |
692 |
struct net_bridge_port *port, |
90010b36e bridge: rename st... |
693 |
struct bridge_mcast_own_query *own_query) |
8ef2a9a59 bridge br_multica... |
694 |
{ |
90010b36e bridge: rename st... |
695 |
struct bridge_mcast_other_query *other_query = NULL; |
5e9235853 bridge: mcast: ad... |
696 697 |
struct br_ip br_group; unsigned long time; |
8ef2a9a59 bridge br_multica... |
698 |
|
13cefad2f net: bridge: conv... |
699 700 |
if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED) || |
675779adb net: bridge: conv... |
701 |
!br_opt_get(br, BROPT_MULTICAST_QUERIER)) |
8ef2a9a59 bridge br_multica... |
702 |
return; |
08b202b67 bridge br_multica... |
703 |
memset(&br_group.u, 0, sizeof(br_group.u)); |
90010b36e bridge: rename st... |
704 705 706 |
if (port ? (own_query == &port->ip4_own_query) : (own_query == &br->ip4_own_query)) { other_query = &br->ip4_other_query; |
cc0fdd802 bridge: separate ... |
707 |
br_group.proto = htons(ETH_P_IP); |
dfd56b8b3 net: use IS_ENABL... |
708 |
#if IS_ENABLED(CONFIG_IPV6) |
cc0fdd802 bridge: separate ... |
709 |
} else { |
90010b36e bridge: rename st... |
710 |
other_query = &br->ip6_other_query; |
cc0fdd802 bridge: separate ... |
711 |
br_group.proto = htons(ETH_P_IPV6); |
08b202b67 bridge br_multica... |
712 |
#endif |
cc0fdd802 bridge: separate ... |
713 |
} |
90010b36e bridge: rename st... |
714 |
if (!other_query || timer_pending(&other_query->timer)) |
cc0fdd802 bridge: separate ... |
715 716 717 |
return; __br_multicast_send_query(br, port, &br_group); |
eb1d16414 bridge: Add core ... |
718 |
|
eb1d16414 bridge: Add core ... |
719 |
time = jiffies; |
90010b36e bridge: rename st... |
720 |
time += own_query->startup_sent < br->multicast_startup_query_count ? |
eb1d16414 bridge: Add core ... |
721 722 |
br->multicast_startup_query_interval : br->multicast_query_interval; |
90010b36e bridge: rename st... |
723 |
mod_timer(&own_query->timer, time); |
eb1d16414 bridge: Add core ... |
724 |
} |
90010b36e bridge: rename st... |
725 726 727 |
static void br_multicast_port_query_expired(struct net_bridge_port *port, struct bridge_mcast_own_query *query) |
eb1d16414 bridge: Add core ... |
728 |
{ |
eb1d16414 bridge: Add core ... |
729 730 731 |
struct net_bridge *br = port->br; spin_lock(&br->multicast_lock); |
02a780c01 bridge: cleanup: ... |
732 733 |
if (port->state == BR_STATE_DISABLED || port->state == BR_STATE_BLOCKING) |
eb1d16414 bridge: Add core ... |
734 |
goto out; |
cc0fdd802 bridge: separate ... |
735 736 |
if (query->startup_sent < br->multicast_startup_query_count) query->startup_sent++; |
eb1d16414 bridge: Add core ... |
737 |
|
cc0fdd802 bridge: separate ... |
738 |
br_multicast_send_query(port->br, port, query); |
eb1d16414 bridge: Add core ... |
739 740 741 742 |
out: spin_unlock(&br->multicast_lock); } |
88c1f37f0 net: bridge: Conv... |
743 |
static void br_ip4_multicast_port_query_expired(struct timer_list *t) |
cc0fdd802 bridge: separate ... |
744 |
{ |
88c1f37f0 net: bridge: Conv... |
745 |
struct net_bridge_port *port = from_timer(port, t, ip4_own_query.timer); |
cc0fdd802 bridge: separate ... |
746 |
|
90010b36e bridge: rename st... |
747 |
br_multicast_port_query_expired(port, &port->ip4_own_query); |
cc0fdd802 bridge: separate ... |
748 749 750 |
} #if IS_ENABLED(CONFIG_IPV6) |
88c1f37f0 net: bridge: Conv... |
751 |
static void br_ip6_multicast_port_query_expired(struct timer_list *t) |
cc0fdd802 bridge: separate ... |
752 |
{ |
88c1f37f0 net: bridge: Conv... |
753 |
struct net_bridge_port *port = from_timer(port, t, ip6_own_query.timer); |
cc0fdd802 bridge: separate ... |
754 |
|
90010b36e bridge: rename st... |
755 |
br_multicast_port_query_expired(port, &port->ip6_own_query); |
cc0fdd802 bridge: separate ... |
756 757 |
} #endif |
147c1e9b9 switchdev: bridge... |
758 759 760 761 762 763 |
static void br_mc_disabled_update(struct net_device *dev, bool value) { struct switchdev_attr attr = { .orig_dev = dev, .id = SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, .flags = SWITCHDEV_F_DEFER, |
13cefad2f net: bridge: conv... |
764 |
.u.mc_disabled = !value, |
147c1e9b9 switchdev: bridge... |
765 766 767 768 |
}; switchdev_port_attr_set(dev, &attr); } |
1080ab95e net: bridge: add ... |
769 |
int br_multicast_add_port(struct net_bridge_port *port) |
eb1d16414 bridge: Add core ... |
770 |
{ |
7f0aec7a6 bridge: mcast: us... |
771 |
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; |
eb1d16414 bridge: Add core ... |
772 |
|
88c1f37f0 net: bridge: Conv... |
773 774 775 776 |
timer_setup(&port->multicast_router_timer, br_multicast_router_expired, 0); timer_setup(&port->ip4_own_query.timer, br_ip4_multicast_port_query_expired, 0); |
cc0fdd802 bridge: separate ... |
777 |
#if IS_ENABLED(CONFIG_IPV6) |
88c1f37f0 net: bridge: Conv... |
778 779 |
timer_setup(&port->ip6_own_query.timer, br_ip6_multicast_port_query_expired, 0); |
cc0fdd802 bridge: separate ... |
780 |
#endif |
13cefad2f net: bridge: conv... |
781 782 |
br_mc_disabled_update(port->dev, br_opt_get(port->br, BROPT_MULTICAST_ENABLED)); |
147c1e9b9 switchdev: bridge... |
783 |
|
1080ab95e net: bridge: add ... |
784 785 786 787 788 |
port->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats); if (!port->mcast_stats) return -ENOMEM; return 0; |
eb1d16414 bridge: Add core ... |
789 790 791 792 |
} void br_multicast_del_port(struct net_bridge_port *port) { |
e10177abf bridge: multicast... |
793 794 795 796 797 798 799 800 801 |
struct net_bridge *br = port->br; struct net_bridge_port_group *pg; struct hlist_node *n; /* Take care of the remaining groups, only perm ones should be left */ spin_lock_bh(&br->multicast_lock); hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) br_multicast_del_pg(br, pg); spin_unlock_bh(&br->multicast_lock); |
eb1d16414 bridge: Add core ... |
802 |
del_timer_sync(&port->multicast_router_timer); |
1080ab95e net: bridge: add ... |
803 |
free_percpu(port->mcast_stats); |
eb1d16414 bridge: Add core ... |
804 |
} |
90010b36e bridge: rename st... |
805 |
static void br_multicast_enable(struct bridge_mcast_own_query *query) |
561f1103a bridge: Add multi... |
806 |
{ |
cc0fdd802 bridge: separate ... |
807 |
query->startup_sent = 0; |
561f1103a bridge: Add multi... |
808 |
|
cc0fdd802 bridge: separate ... |
809 810 811 |
if (try_to_del_timer_sync(&query->timer) >= 0 || del_timer(&query->timer)) mod_timer(&query->timer, jiffies); |
561f1103a bridge: Add multi... |
812 |
} |
7cb3f9214 bridge: multicast... |
813 |
static void __br_multicast_enable_port(struct net_bridge_port *port) |
eb1d16414 bridge: Add core ... |
814 815 |
{ struct net_bridge *br = port->br; |
13cefad2f net: bridge: conv... |
816 |
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev)) |
7cb3f9214 bridge: multicast... |
817 |
return; |
eb1d16414 bridge: Add core ... |
818 |
|
90010b36e bridge: rename st... |
819 |
br_multicast_enable(&port->ip4_own_query); |
cc0fdd802 bridge: separate ... |
820 |
#if IS_ENABLED(CONFIG_IPV6) |
90010b36e bridge: rename st... |
821 |
br_multicast_enable(&port->ip6_own_query); |
cc0fdd802 bridge: separate ... |
822 |
#endif |
7f0aec7a6 bridge: mcast: us... |
823 824 |
if (port->multicast_router == MDB_RTR_TYPE_PERM && hlist_unhashed(&port->rlist)) |
754bc547f bridge: multicast... |
825 |
br_multicast_add_router(br, port); |
7cb3f9214 bridge: multicast... |
826 |
} |
eb1d16414 bridge: Add core ... |
827 |
|
7cb3f9214 bridge: multicast... |
828 829 830 831 832 833 |
void br_multicast_enable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; spin_lock(&br->multicast_lock); __br_multicast_enable_port(port); |
eb1d16414 bridge: Add core ... |
834 835 836 837 838 839 840 |
spin_unlock(&br->multicast_lock); } void br_multicast_disable_port(struct net_bridge_port *port) { struct net_bridge *br = port->br; struct net_bridge_port_group *pg; |
b67bfe0d4 hlist: drop the n... |
841 |
struct hlist_node *n; |
eb1d16414 bridge: Add core ... |
842 843 |
spin_lock(&br->multicast_lock); |
b67bfe0d4 hlist: drop the n... |
844 |
hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) |
9d06b6d8a bridge: mdb: Sepa... |
845 |
if (!(pg->flags & MDB_PG_FLAGS_PERMANENT)) |
e10177abf bridge: multicast... |
846 |
br_multicast_del_pg(br, pg); |
eb1d16414 bridge: Add core ... |
847 |
|
f12e7d95d bridge: mcast: Me... |
848 |
__del_port_router(port); |
eb1d16414 bridge: Add core ... |
849 |
del_timer(&port->multicast_router_timer); |
90010b36e bridge: rename st... |
850 |
del_timer(&port->ip4_own_query.timer); |
cc0fdd802 bridge: separate ... |
851 |
#if IS_ENABLED(CONFIG_IPV6) |
90010b36e bridge: rename st... |
852 |
del_timer(&port->ip6_own_query.timer); |
cc0fdd802 bridge: separate ... |
853 |
#endif |
eb1d16414 bridge: Add core ... |
854 855 |
spin_unlock(&br->multicast_lock); } |
8ef2a9a59 bridge br_multica... |
856 857 |
static int br_ip4_multicast_igmp3_report(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
858 859 |
struct sk_buff *skb, u16 vid) |
eb1d16414 bridge: Add core ... |
860 |
{ |
6db6f0eae bridge: multicast... |
861 |
const unsigned char *src; |
eb1d16414 bridge: Add core ... |
862 863 864 865 866 867 868 869 |
struct igmpv3_report *ih; struct igmpv3_grec *grec; int i; int len; int num; int type; int err = 0; __be32 group; |
e57f61858 net: bridge: mcas... |
870 |
u16 nsrcs; |
eb1d16414 bridge: Add core ... |
871 |
|
eb1d16414 bridge: Add core ... |
872 873 |
ih = igmpv3_report_hdr(skb); num = ntohs(ih->ngrec); |
c2d4fbd21 bridge: fix igmpv... |
874 |
len = skb_transport_offset(skb) + sizeof(*ih); |
eb1d16414 bridge: Add core ... |
875 876 877 |
for (i = 0; i < num; i++) { len += sizeof(*grec); |
ba5ea6146 bridge: simplify ... |
878 |
if (!ip_mc_may_pull(skb, len)) |
eb1d16414 bridge: Add core ... |
879 |
return -EINVAL; |
fd218cf95 bridge: Fix IGMP3... |
880 |
grec = (void *)(skb->data + len - sizeof(*grec)); |
eb1d16414 bridge: Add core ... |
881 882 |
group = grec->grec_mca; type = grec->grec_type; |
e57f61858 net: bridge: mcas... |
883 |
nsrcs = ntohs(grec->grec_nsrcs); |
eb1d16414 bridge: Add core ... |
884 |
|
e57f61858 net: bridge: mcas... |
885 |
len += nsrcs * 4; |
ba5ea6146 bridge: simplify ... |
886 |
if (!ip_mc_may_pull(skb, len)) |
eb1d16414 bridge: Add core ... |
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
return -EINVAL; /* We treat this as an IGMPv2 report for now. */ switch (type) { case IGMPV3_MODE_IS_INCLUDE: case IGMPV3_MODE_IS_EXCLUDE: case IGMPV3_CHANGE_TO_INCLUDE: case IGMPV3_CHANGE_TO_EXCLUDE: case IGMPV3_ALLOW_NEW_SOURCES: case IGMPV3_BLOCK_OLD_SOURCES: break; default: continue; } |
6db6f0eae bridge: multicast... |
902 |
src = eth_hdr(skb)->h_source; |
bc8c20aca bridge: multicast... |
903 904 |
if ((type == IGMPV3_CHANGE_TO_INCLUDE || type == IGMPV3_MODE_IS_INCLUDE) && |
e57f61858 net: bridge: mcas... |
905 |
nsrcs == 0) { |
6db6f0eae bridge: multicast... |
906 |
br_ip4_multicast_leave_group(br, port, group, vid, src); |
bc8c20aca bridge: multicast... |
907 |
} else { |
6db6f0eae bridge: multicast... |
908 909 |
err = br_ip4_multicast_add_group(br, port, group, vid, src); |
bc8c20aca bridge: multicast... |
910 911 912 |
if (err) break; } |
eb1d16414 bridge: Add core ... |
913 914 915 916 |
} return err; } |
dfd56b8b3 net: use IS_ENABL... |
917 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
918 919 |
static int br_ip6_multicast_mld2_report(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
920 921 |
struct sk_buff *skb, u16 vid) |
08b202b67 bridge br_multica... |
922 |
{ |
ba5ea6146 bridge: simplify ... |
923 |
unsigned int nsrcs_offset; |
6db6f0eae bridge: multicast... |
924 |
const unsigned char *src; |
08b202b67 bridge br_multica... |
925 926 |
struct icmp6hdr *icmp6h; struct mld2_grec *grec; |
ba5ea6146 bridge: simplify ... |
927 |
unsigned int grec_len; |
08b202b67 bridge br_multica... |
928 929 930 931 |
int i; int len; int num; int err = 0; |
ba5ea6146 bridge: simplify ... |
932 |
if (!ipv6_mc_may_pull(skb, sizeof(*icmp6h))) |
08b202b67 bridge br_multica... |
933 934 935 936 |
return -EINVAL; icmp6h = icmp6_hdr(skb); num = ntohs(icmp6h->icmp6_dataun.un_data16[1]); |
c2d4fbd21 bridge: fix igmpv... |
937 |
len = skb_transport_offset(skb) + sizeof(*icmp6h); |
08b202b67 bridge br_multica... |
938 939 |
for (i = 0; i < num; i++) { |
e57f61858 net: bridge: mcas... |
940 941 |
__be16 *_nsrcs, __nsrcs; u16 nsrcs; |
08b202b67 bridge br_multica... |
942 |
|
ba5ea6146 bridge: simplify ... |
943 944 945 |
nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs); if (skb_transport_offset(skb) + ipv6_transport_len(skb) < |
5fc6266af bridge: mcast: Fi... |
946 |
nsrcs_offset + sizeof(__nsrcs)) |
ba5ea6146 bridge: simplify ... |
947 |
return -EINVAL; |
e57f61858 net: bridge: mcas... |
948 949 950 |
_nsrcs = skb_header_pointer(skb, nsrcs_offset, sizeof(__nsrcs), &__nsrcs); if (!_nsrcs) |
08b202b67 bridge br_multica... |
951 |
return -EINVAL; |
e57f61858 net: bridge: mcas... |
952 953 |
nsrcs = ntohs(*_nsrcs); grec_len = struct_size(grec, grec_src, nsrcs); |
ba5ea6146 bridge: simplify ... |
954 955 |
if (!ipv6_mc_may_pull(skb, len + grec_len)) |
08b202b67 bridge br_multica... |
956 957 958 |
return -EINVAL; grec = (struct mld2_grec *)(skb->data + len); |
ba5ea6146 bridge: simplify ... |
959 |
len += grec_len; |
08b202b67 bridge br_multica... |
960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
/* We treat these as MLDv1 reports for now. */ switch (grec->grec_type) { case MLD2_MODE_IS_INCLUDE: case MLD2_MODE_IS_EXCLUDE: case MLD2_CHANGE_TO_INCLUDE: case MLD2_CHANGE_TO_EXCLUDE: case MLD2_ALLOW_NEW_SOURCES: case MLD2_BLOCK_OLD_SOURCES: break; default: continue; } |
6db6f0eae bridge: multicast... |
974 |
src = eth_hdr(skb)->h_source; |
bc8c20aca bridge: multicast... |
975 976 |
if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE || grec->grec_type == MLD2_MODE_IS_INCLUDE) && |
e57f61858 net: bridge: mcas... |
977 |
nsrcs == 0) { |
bc8c20aca bridge: multicast... |
978 |
br_ip6_multicast_leave_group(br, port, &grec->grec_mca, |
6db6f0eae bridge: multicast... |
979 |
vid, src); |
bc8c20aca bridge: multicast... |
980 981 |
} else { err = br_ip6_multicast_add_group(br, port, |
6db6f0eae bridge: multicast... |
982 983 |
&grec->grec_mca, vid, src); |
9264251ee bridge: re-introd... |
984 |
if (err) |
bc8c20aca bridge: multicast... |
985 986 |
break; } |
08b202b67 bridge br_multica... |
987 988 989 990 991 |
} return err; } #endif |
dc4eb53a9 bridge: adhere to... |
992 |
static bool br_ip4_multicast_select_querier(struct net_bridge *br, |
2cd414319 bridge: memorize ... |
993 |
struct net_bridge_port *port, |
dc4eb53a9 bridge: adhere to... |
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
__be32 saddr) { if (!timer_pending(&br->ip4_own_query.timer) && !timer_pending(&br->ip4_other_query.timer)) goto update; if (!br->ip4_querier.addr.u.ip4) goto update; if (ntohl(saddr) <= ntohl(br->ip4_querier.addr.u.ip4)) goto update; return false; update: br->ip4_querier.addr.u.ip4 = saddr; |
2cd414319 bridge: memorize ... |
1010 1011 |
/* update protected by general multicast_lock by caller */ rcu_assign_pointer(br->ip4_querier.port, port); |
dc4eb53a9 bridge: adhere to... |
1012 1013 1014 1015 1016 |
return true; } #if IS_ENABLED(CONFIG_IPV6) static bool br_ip6_multicast_select_querier(struct net_bridge *br, |
2cd414319 bridge: memorize ... |
1017 |
struct net_bridge_port *port, |
dc4eb53a9 bridge: adhere to... |
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
struct in6_addr *saddr) { if (!timer_pending(&br->ip6_own_query.timer) && !timer_pending(&br->ip6_other_query.timer)) goto update; if (ipv6_addr_cmp(saddr, &br->ip6_querier.addr.u.ip6) <= 0) goto update; return false; update: br->ip6_querier.addr.u.ip6 = *saddr; |
2cd414319 bridge: memorize ... |
1031 1032 |
/* update protected by general multicast_lock by caller */ rcu_assign_pointer(br->ip6_querier.port, port); |
dc4eb53a9 bridge: adhere to... |
1033 1034 1035 1036 1037 |
return true; } #endif static bool br_multicast_select_querier(struct net_bridge *br, |
2cd414319 bridge: memorize ... |
1038 |
struct net_bridge_port *port, |
dc4eb53a9 bridge: adhere to... |
1039 1040 1041 1042 |
struct br_ip *saddr) { switch (saddr->proto) { case htons(ETH_P_IP): |
2cd414319 bridge: memorize ... |
1043 |
return br_ip4_multicast_select_querier(br, port, saddr->u.ip4); |
dc4eb53a9 bridge: adhere to... |
1044 1045 |
#if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): |
2cd414319 bridge: memorize ... |
1046 |
return br_ip6_multicast_select_querier(br, port, &saddr->u.ip6); |
dc4eb53a9 bridge: adhere to... |
1047 1048 1049 1050 1051 |
#endif } return false; } |
cc0fdd802 bridge: separate ... |
1052 |
static void |
90010b36e bridge: rename st... |
1053 1054 1055 |
br_multicast_update_query_timer(struct net_bridge *br, struct bridge_mcast_other_query *query, unsigned long max_delay) |
b00589af3 bridge: disable s... |
1056 |
{ |
90010b36e bridge: rename st... |
1057 1058 |
if (!timer_pending(&query->timer)) query->delay_time = jiffies + max_delay; |
b00589af3 bridge: disable s... |
1059 |
|
90010b36e bridge: rename st... |
1060 |
mod_timer(&query->timer, jiffies + br->multicast_querier_interval); |
b00589af3 bridge: disable s... |
1061 |
} |
6d5496483 switchdev: bridge... |
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
static void br_port_mc_router_state_change(struct net_bridge_port *p, bool is_mc_router) { struct switchdev_attr attr = { .orig_dev = p->dev, .id = SWITCHDEV_ATTR_ID_PORT_MROUTER, .flags = SWITCHDEV_F_DEFER, .u.mrouter = is_mc_router, }; switchdev_port_attr_set(p->dev, &attr); } |
7e80c1244 bridge: simplify ... |
1074 |
/* |
7c77602f5 bridge: fix a typ... |
1075 |
* Add port to router_list |
7e80c1244 bridge: simplify ... |
1076 1077 1078 |
* list is maintained ordered by pointer value * and locked by br->multicast_lock and RCU */ |
0909e1175 bridge: Add multi... |
1079 1080 1081 |
static void br_multicast_add_router(struct net_bridge *br, struct net_bridge_port *port) { |
dcdca2c49 bridge: multicast... |
1082 |
struct net_bridge_port *p; |
b67bfe0d4 hlist: drop the n... |
1083 |
struct hlist_node *slot = NULL; |
dcdca2c49 bridge: multicast... |
1084 |
|
1a040eaca bridge: fix multi... |
1085 1086 |
if (!hlist_unhashed(&port->rlist)) return; |
b67bfe0d4 hlist: drop the n... |
1087 |
hlist_for_each_entry(p, &br->router_list, rlist) { |
7e80c1244 bridge: simplify ... |
1088 1089 |
if ((unsigned long) port >= (unsigned long) p) break; |
b67bfe0d4 hlist: drop the n... |
1090 |
slot = &p->rlist; |
dcdca2c49 bridge: multicast... |
1091 |
} |
7e80c1244 bridge: simplify ... |
1092 |
if (slot) |
1d023284c list: fix order o... |
1093 |
hlist_add_behind_rcu(&port->rlist, slot); |
dcdca2c49 bridge: multicast... |
1094 1095 |
else hlist_add_head_rcu(&port->rlist, &br->router_list); |
949f1e39a bridge: mdb: noti... |
1096 |
br_rtr_notify(br->dev, port, RTM_NEWMDB); |
6d5496483 switchdev: bridge... |
1097 |
br_port_mc_router_state_change(port, true); |
0909e1175 bridge: Add multi... |
1098 |
} |
eb1d16414 bridge: Add core ... |
1099 1100 1101 1102 |
static void br_multicast_mark_router(struct net_bridge *br, struct net_bridge_port *port) { unsigned long now = jiffies; |
eb1d16414 bridge: Add core ... |
1103 1104 |
if (!port) { |
770414207 net: bridge: Noti... |
1105 1106 1107 |
if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) { if (!timer_pending(&br->multicast_router_timer)) br_mc_router_state_change(br, true); |
eb1d16414 bridge: Add core ... |
1108 1109 |
mod_timer(&br->multicast_router_timer, now + br->multicast_querier_interval); |
770414207 net: bridge: Noti... |
1110 |
} |
eb1d16414 bridge: Add core ... |
1111 1112 |
return; } |
a55d8246a bridge: mcast: ad... |
1113 1114 |
if (port->multicast_router == MDB_RTR_TYPE_DISABLED || port->multicast_router == MDB_RTR_TYPE_PERM) |
eb1d16414 bridge: Add core ... |
1115 |
return; |
0909e1175 bridge: Add multi... |
1116 |
br_multicast_add_router(br, port); |
eb1d16414 bridge: Add core ... |
1117 |
|
eb1d16414 bridge: Add core ... |
1118 1119 1120 1121 1122 1123 |
mod_timer(&port->multicast_router_timer, now + br->multicast_querier_interval); } static void br_multicast_query_received(struct net_bridge *br, struct net_bridge_port *port, |
90010b36e bridge: rename st... |
1124 |
struct bridge_mcast_other_query *query, |
dc4eb53a9 bridge: adhere to... |
1125 |
struct br_ip *saddr, |
b00589af3 bridge: disable s... |
1126 |
unsigned long max_delay) |
eb1d16414 bridge: Add core ... |
1127 |
{ |
2cd414319 bridge: memorize ... |
1128 |
if (!br_multicast_select_querier(br, port, saddr)) |
eb1d16414 bridge: Add core ... |
1129 |
return; |
dc4eb53a9 bridge: adhere to... |
1130 |
br_multicast_update_query_timer(br, query, max_delay); |
278e2148c Revert "bridge: d... |
1131 |
br_multicast_mark_router(br, port); |
eb1d16414 bridge: Add core ... |
1132 |
} |
9c2e955c4 net/bridge/br_mul... |
1133 1134 1135 1136 |
static void br_ip4_multicast_query(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb, u16 vid) |
eb1d16414 bridge: Add core ... |
1137 |
{ |
ba5ea6146 bridge: simplify ... |
1138 |
unsigned int transport_len = ip_transport_len(skb); |
b71d1d426 inet: constify ip... |
1139 |
const struct iphdr *iph = ip_hdr(skb); |
eb1d16414 bridge: Add core ... |
1140 1141 1142 1143 |
struct igmphdr *ih = igmp_hdr(skb); struct net_bridge_mdb_entry *mp; struct igmpv3_query *ih3; struct net_bridge_port_group *p; |
e80516880 bridge: add RCU a... |
1144 |
struct net_bridge_port_group __rcu **pp; |
dc4eb53a9 bridge: adhere to... |
1145 |
struct br_ip saddr; |
eb1d16414 bridge: Add core ... |
1146 1147 1148 1149 1150 1151 1152 1153 |
unsigned long max_delay; unsigned long now = jiffies; __be32 group; spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || (port && port->state == BR_STATE_DISABLED)) goto out; |
eb1d16414 bridge: Add core ... |
1154 |
group = ih->group; |
ba5ea6146 bridge: simplify ... |
1155 |
if (transport_len == sizeof(*ih)) { |
eb1d16414 bridge: Add core ... |
1156 1157 1158 1159 1160 1161 |
max_delay = ih->code * (HZ / IGMP_TIMER_SCALE); if (!max_delay) { max_delay = 10 * HZ; group = 0; } |
ba5ea6146 bridge: simplify ... |
1162 |
} else if (transport_len >= sizeof(*ih3)) { |
eb1d16414 bridge: Add core ... |
1163 1164 |
ih3 = igmpv3_query_hdr(skb); if (ih3->nsrcs) |
bec68ff16 bridge: ensure to... |
1165 |
goto out; |
eb1d16414 bridge: Add core ... |
1166 |
|
0ba8c9ec2 bridge br_multica... |
1167 1168 |
max_delay = ih3->code ? IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; |
9afd85c9e net: Export IGMP/... |
1169 |
} else { |
9ed973cc4 bridge: multicast... |
1170 1171 |
goto out; } |
dc4eb53a9 bridge: adhere to... |
1172 1173 1174 |
if (!group) { saddr.proto = htons(ETH_P_IP); saddr.u.ip4 = iph->saddr; |
b00589af3 bridge: disable s... |
1175 |
|
dc4eb53a9 bridge: adhere to... |
1176 1177 |
br_multicast_query_received(br, port, &br->ip4_other_query, &saddr, max_delay); |
eb1d16414 bridge: Add core ... |
1178 |
goto out; |
dc4eb53a9 bridge: adhere to... |
1179 |
} |
eb1d16414 bridge: Add core ... |
1180 |
|
19e3a9c90 net: bridge: conv... |
1181 |
mp = br_mdb_ip4_get(br, group, vid); |
eb1d16414 bridge: Add core ... |
1182 1183 1184 1185 |
if (!mp) goto out; max_delay *= br->multicast_last_member_count; |
ff0fd34ea net: bridge: Rena... |
1186 |
if (mp->host_joined && |
eb1d16414 bridge: Add core ... |
1187 1188 1189 1190 |
(timer_pending(&mp->timer) ? time_after(mp->timer.expires, now + max_delay) : try_to_del_timer_sync(&mp->timer) >= 0)) mod_timer(&mp->timer, now + max_delay); |
e80516880 bridge: add RCU a... |
1191 1192 1193 |
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { |
eb1d16414 bridge: Add core ... |
1194 1195 1196 |
if (timer_pending(&p->timer) ? time_after(p->timer.expires, now + max_delay) : try_to_del_timer_sync(&p->timer) >= 0) |
24f9cdcbd bridge: Fix timer... |
1197 |
mod_timer(&p->timer, now + max_delay); |
eb1d16414 bridge: Add core ... |
1198 1199 1200 1201 |
} out: spin_unlock(&br->multicast_lock); |
eb1d16414 bridge: Add core ... |
1202 |
} |
dfd56b8b3 net: use IS_ENABL... |
1203 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
1204 1205 |
static int br_ip6_multicast_query(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
1206 1207 |
struct sk_buff *skb, u16 vid) |
08b202b67 bridge br_multica... |
1208 |
{ |
ba5ea6146 bridge: simplify ... |
1209 |
unsigned int transport_len = ipv6_transport_len(skb); |
eca2a43bb bridge: fix icmpv... |
1210 |
struct mld_msg *mld; |
08b202b67 bridge br_multica... |
1211 1212 |
struct net_bridge_mdb_entry *mp; struct mld2_query *mld2q; |
e80516880 bridge: add RCU a... |
1213 1214 |
struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; |
dc4eb53a9 bridge: adhere to... |
1215 |
struct br_ip saddr; |
08b202b67 bridge br_multica... |
1216 1217 |
unsigned long max_delay; unsigned long now = jiffies; |
856ce5d08 bridge: fix igmp ... |
1218 |
unsigned int offset = skb_transport_offset(skb); |
b71d1d426 inet: constify ip... |
1219 |
const struct in6_addr *group = NULL; |
9ed973cc4 bridge: multicast... |
1220 |
bool is_general_query; |
08b202b67 bridge br_multica... |
1221 1222 1223 1224 1225 1226 |
int err = 0; spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || (port && port->state == BR_STATE_DISABLED)) goto out; |
ba5ea6146 bridge: simplify ... |
1227 |
if (transport_len == sizeof(*mld)) { |
856ce5d08 bridge: fix igmp ... |
1228 |
if (!pskb_may_pull(skb, offset + sizeof(*mld))) { |
08b202b67 bridge br_multica... |
1229 1230 1231 1232 |
err = -EINVAL; goto out; } mld = (struct mld_msg *) icmp6_hdr(skb); |
4715213d9 bridge: fix endian |
1233 |
max_delay = msecs_to_jiffies(ntohs(mld->mld_maxdelay)); |
08b202b67 bridge br_multica... |
1234 1235 |
if (max_delay) group = &mld->mld_mca; |
248ba8ec0 bridge: don't try... |
1236 |
} else { |
856ce5d08 bridge: fix igmp ... |
1237 |
if (!pskb_may_pull(skb, offset + sizeof(*mld2q))) { |
08b202b67 bridge br_multica... |
1238 1239 1240 1241 1242 1243 |
err = -EINVAL; goto out; } mld2q = (struct mld2_query *)icmp6_hdr(skb); if (!mld2q->mld2q_nsrcs) group = &mld2q->mld2q_mca; |
e3f5b1704 net: ipv6: mld: g... |
1244 1245 |
max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL); |
08b202b67 bridge br_multica... |
1246 |
} |
9ed973cc4 bridge: multicast... |
1247 |
is_general_query = group && ipv6_addr_any(group); |
dc4eb53a9 bridge: adhere to... |
1248 1249 |
if (is_general_query) { saddr.proto = htons(ETH_P_IPV6); |
3b26a5d03 net: bridge: mcas... |
1250 |
saddr.u.ip6 = ipv6_hdr(skb)->saddr; |
b00589af3 bridge: disable s... |
1251 |
|
dc4eb53a9 bridge: adhere to... |
1252 1253 |
br_multicast_query_received(br, port, &br->ip6_other_query, &saddr, max_delay); |
08b202b67 bridge br_multica... |
1254 |
goto out; |
6c03ee8bd bridge: fix smatc... |
1255 1256 |
} else if (!group) { goto out; |
dc4eb53a9 bridge: adhere to... |
1257 |
} |
08b202b67 bridge br_multica... |
1258 |
|
19e3a9c90 net: bridge: conv... |
1259 |
mp = br_mdb_ip6_get(br, group, vid); |
08b202b67 bridge br_multica... |
1260 1261 1262 1263 |
if (!mp) goto out; max_delay *= br->multicast_last_member_count; |
ff0fd34ea net: bridge: Rena... |
1264 |
if (mp->host_joined && |
08b202b67 bridge br_multica... |
1265 1266 1267 1268 |
(timer_pending(&mp->timer) ? time_after(mp->timer.expires, now + max_delay) : try_to_del_timer_sync(&mp->timer) >= 0)) mod_timer(&mp->timer, now + max_delay); |
e80516880 bridge: add RCU a... |
1269 1270 1271 |
for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { |
08b202b67 bridge br_multica... |
1272 1273 1274 |
if (timer_pending(&p->timer) ? time_after(p->timer.expires, now + max_delay) : try_to_del_timer_sync(&p->timer) >= 0) |
24f9cdcbd bridge: Fix timer... |
1275 |
mod_timer(&p->timer, now + max_delay); |
08b202b67 bridge br_multica... |
1276 1277 1278 1279 1280 1281 1282 |
} out: spin_unlock(&br->multicast_lock); return err; } #endif |
90010b36e bridge: rename st... |
1283 1284 1285 1286 1287 |
static void br_multicast_leave_group(struct net_bridge *br, struct net_bridge_port *port, struct br_ip *group, struct bridge_mcast_other_query *other_query, |
6db6f0eae bridge: multicast... |
1288 1289 |
struct bridge_mcast_own_query *own_query, const unsigned char *src) |
eb1d16414 bridge: Add core ... |
1290 |
{ |
eb1d16414 bridge: Add core ... |
1291 1292 1293 1294 |
struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; unsigned long now; unsigned long time; |
eb1d16414 bridge: Add core ... |
1295 1296 |
spin_lock(&br->multicast_lock); if (!netif_running(br->dev) || |
544586f74 bridge: mcast: gi... |
1297 |
(port && port->state == BR_STATE_DISABLED)) |
eb1d16414 bridge: Add core ... |
1298 |
goto out; |
19e3a9c90 net: bridge: conv... |
1299 |
mp = br_mdb_ip_get(br, group); |
eb1d16414 bridge: Add core ... |
1300 1301 |
if (!mp) goto out; |
544586f74 bridge: mcast: gi... |
1302 1303 1304 1305 1306 1307 |
if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) { struct net_bridge_port_group __rcu **pp; for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL; pp = &p->next) { |
6db6f0eae bridge: multicast... |
1308 |
if (!br_port_group_equal(p, port, src)) |
544586f74 bridge: mcast: gi... |
1309 |
continue; |
5c725b6b6 net: bridge: mcas... |
1310 1311 |
if (p->flags & MDB_PG_FLAGS_PERMANENT) break; |
544586f74 bridge: mcast: gi... |
1312 1313 1314 |
rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); |
4329596cb net: bridge: mult... |
1315 |
kfree_rcu(p, rcu); |
45ebcce56 bridge: mdb: Mark... |
1316 |
br_mdb_notify(br->dev, port, group, RTM_DELMDB, |
3247b2720 net: bridge: mcas... |
1317 |
p->flags | MDB_PG_FLAGS_FAST_LEAVE); |
544586f74 bridge: mcast: gi... |
1318 |
|
ff0fd34ea net: bridge: Rena... |
1319 |
if (!mp->ports && !mp->host_joined && |
544586f74 bridge: mcast: gi... |
1320 1321 1322 1323 1324 1325 1326 1327 |
netif_running(br->dev)) mod_timer(&mp->timer, jiffies); } goto out; } if (timer_pending(&other_query->timer)) goto out; |
675779adb net: bridge: conv... |
1328 |
if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { |
6b7df111e bridge: send quer... |
1329 1330 1331 1332 |
__br_multicast_send_query(br, port, &mp->addr); time = jiffies + br->multicast_last_member_count * br->multicast_last_member_interval; |
cc0fdd802 bridge: separate ... |
1333 |
|
90010b36e bridge: rename st... |
1334 |
mod_timer(&own_query->timer, time); |
6b7df111e bridge: send quer... |
1335 1336 1337 1338 |
for (p = mlock_dereference(mp->ports, br); p != NULL; p = mlock_dereference(p->next, br)) { |
6db6f0eae bridge: multicast... |
1339 |
if (!br_port_group_equal(p, port, src)) |
6b7df111e bridge: send quer... |
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
continue; if (!hlist_unhashed(&p->mglist) && (timer_pending(&p->timer) ? time_after(p->timer.expires, time) : try_to_del_timer_sync(&p->timer) >= 0)) { mod_timer(&p->timer, time); } break; } } |
eb1d16414 bridge: Add core ... |
1352 1353 1354 1355 1356 |
now = jiffies; time = now + br->multicast_last_member_count * br->multicast_last_member_interval; if (!port) { |
ff0fd34ea net: bridge: Rena... |
1357 |
if (mp->host_joined && |
eb1d16414 bridge: Add core ... |
1358 1359 1360 1361 |
(timer_pending(&mp->timer) ? time_after(mp->timer.expires, time) : try_to_del_timer_sync(&mp->timer) >= 0)) { mod_timer(&mp->timer, time); |
eb1d16414 bridge: Add core ... |
1362 |
} |
454594f3b Revert "bridge: o... |
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
goto out; } for (p = mlock_dereference(mp->ports, br); p != NULL; p = mlock_dereference(p->next, br)) { if (p->port != port) continue; if (!hlist_unhashed(&p->mglist) && (timer_pending(&p->timer) ? time_after(p->timer.expires, time) : try_to_del_timer_sync(&p->timer) >= 0)) { mod_timer(&p->timer, time); } break; |
eb1d16414 bridge: Add core ... |
1381 |
} |
eb1d16414 bridge: Add core ... |
1382 1383 1384 |
out: spin_unlock(&br->multicast_lock); } |
8ef2a9a59 bridge br_multica... |
1385 1386 |
static void br_ip4_multicast_leave_group(struct net_bridge *br, struct net_bridge_port *port, |
b0e9a30dd bridge: Add vlan ... |
1387 |
__be32 group, |
6db6f0eae bridge: multicast... |
1388 1389 |
__u16 vid, const unsigned char *src) |
8ef2a9a59 bridge br_multica... |
1390 1391 |
{ struct br_ip br_group; |
90010b36e bridge: rename st... |
1392 |
struct bridge_mcast_own_query *own_query; |
8ef2a9a59 bridge br_multica... |
1393 1394 1395 |
if (ipv4_is_local_multicast(group)) return; |
90010b36e bridge: rename st... |
1396 |
own_query = port ? &port->ip4_own_query : &br->ip4_own_query; |
1515a63fc net: bridge: alwa... |
1397 |
memset(&br_group, 0, sizeof(br_group)); |
8ef2a9a59 bridge br_multica... |
1398 1399 |
br_group.u.ip4 = group; br_group.proto = htons(ETH_P_IP); |
b0e9a30dd bridge: Add vlan ... |
1400 |
br_group.vid = vid; |
8ef2a9a59 bridge br_multica... |
1401 |
|
90010b36e bridge: rename st... |
1402 |
br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query, |
6db6f0eae bridge: multicast... |
1403 |
own_query, src); |
8ef2a9a59 bridge br_multica... |
1404 |
} |
dfd56b8b3 net: use IS_ENABL... |
1405 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
1406 1407 |
static void br_ip6_multicast_leave_group(struct net_bridge *br, struct net_bridge_port *port, |
b0e9a30dd bridge: Add vlan ... |
1408 |
const struct in6_addr *group, |
6db6f0eae bridge: multicast... |
1409 1410 |
__u16 vid, const unsigned char *src) |
08b202b67 bridge br_multica... |
1411 1412 |
{ struct br_ip br_group; |
90010b36e bridge: rename st... |
1413 |
struct bridge_mcast_own_query *own_query; |
08b202b67 bridge br_multica... |
1414 |
|
3c3769e63 bridge: apply mul... |
1415 |
if (ipv6_addr_is_ll_all_nodes(group)) |
08b202b67 bridge br_multica... |
1416 |
return; |
90010b36e bridge: rename st... |
1417 |
own_query = port ? &port->ip6_own_query : &br->ip6_own_query; |
1515a63fc net: bridge: alwa... |
1418 |
memset(&br_group, 0, sizeof(br_group)); |
4e3fd7a06 net: remove ipv6_... |
1419 |
br_group.u.ip6 = *group; |
08b202b67 bridge br_multica... |
1420 |
br_group.proto = htons(ETH_P_IPV6); |
b0e9a30dd bridge: Add vlan ... |
1421 |
br_group.vid = vid; |
08b202b67 bridge br_multica... |
1422 |
|
90010b36e bridge: rename st... |
1423 |
br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query, |
6db6f0eae bridge: multicast... |
1424 |
own_query, src); |
08b202b67 bridge br_multica... |
1425 1426 |
} #endif |
8ef2a9a59 bridge br_multica... |
1427 |
|
1080ab95e net: bridge: add ... |
1428 1429 1430 1431 1432 1433 |
static void br_multicast_err_count(const struct net_bridge *br, const struct net_bridge_port *p, __be16 proto) { struct bridge_mcast_stats __percpu *stats; struct bridge_mcast_stats *pstats; |
675779adb net: bridge: conv... |
1434 |
if (!br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) |
1080ab95e net: bridge: add ... |
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 |
return; if (p) stats = p->mcast_stats; else stats = br->mcast_stats; if (WARN_ON(!stats)) return; pstats = this_cpu_ptr(stats); u64_stats_update_begin(&pstats->syncp); switch (proto) { case htons(ETH_P_IP): pstats->mstats.igmp_parse_errors++; break; #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): pstats->mstats.mld_parse_errors++; break; #endif } u64_stats_update_end(&pstats->syncp); } |
91b02d3d1 bridge: mcast: ad... |
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 |
static void br_multicast_pim(struct net_bridge *br, struct net_bridge_port *port, const struct sk_buff *skb) { unsigned int offset = skb_transport_offset(skb); struct pimhdr *pimhdr, _pimhdr; pimhdr = skb_header_pointer(skb, offset, sizeof(_pimhdr), &_pimhdr); if (!pimhdr || pim_hdr_version(pimhdr) != PIM_VERSION || pim_hdr_type(pimhdr) != PIM_TYPE_HELLO) return; br_multicast_mark_router(br, port); } |
4b3087c7e bridge: Snoop Mul... |
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 |
static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb) { if (ip_hdr(skb)->protocol != IPPROTO_IGMP || igmp_hdr(skb)->type != IGMP_MRDISC_ADV) return -ENOMSG; br_multicast_mark_router(br, port); return 0; } |
eb1d16414 bridge: Add core ... |
1485 1486 |
static int br_multicast_ipv4_rcv(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
1487 1488 |
struct sk_buff *skb, u16 vid) |
eb1d16414 bridge: Add core ... |
1489 |
{ |
6db6f0eae bridge: multicast... |
1490 |
const unsigned char *src; |
eb1d16414 bridge: Add core ... |
1491 |
struct igmphdr *ih; |
eb1d16414 bridge: Add core ... |
1492 |
int err; |
ba5ea6146 bridge: simplify ... |
1493 |
err = ip_mc_check_igmp(skb); |
eb1d16414 bridge: Add core ... |
1494 |
|
9afd85c9e net: Export IGMP/... |
1495 |
if (err == -ENOMSG) { |
91b02d3d1 bridge: mcast: ad... |
1496 |
if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) { |
bd4265fe3 bridge: Only floo... |
1497 |
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
91b02d3d1 bridge: mcast: ad... |
1498 1499 1500 |
} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) { if (ip_hdr(skb)->protocol == IPPROTO_PIM) br_multicast_pim(br, port, skb); |
4b3087c7e bridge: Snoop Mul... |
1501 |
} else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) { |
08e71623c bridge: remove re... |
1502 |
br_ip4_multicast_mrd_rcv(br, port, skb); |
91b02d3d1 bridge: mcast: ad... |
1503 |
} |
4b3087c7e bridge: Snoop Mul... |
1504 |
|
eb1d16414 bridge: Add core ... |
1505 |
return 0; |
9afd85c9e net: Export IGMP/... |
1506 |
} else if (err < 0) { |
1080ab95e net: bridge: add ... |
1507 |
br_multicast_err_count(br, port, skb->protocol); |
9afd85c9e net: Export IGMP/... |
1508 |
return err; |
bd4265fe3 bridge: Only floo... |
1509 |
} |
eb1d16414 bridge: Add core ... |
1510 |
|
9afd85c9e net: Export IGMP/... |
1511 |
ih = igmp_hdr(skb); |
6db6f0eae bridge: multicast... |
1512 |
src = eth_hdr(skb)->h_source; |
1080ab95e net: bridge: add ... |
1513 |
BR_INPUT_SKB_CB(skb)->igmp = ih->type; |
eb1d16414 bridge: Add core ... |
1514 1515 1516 1517 |
switch (ih->type) { case IGMP_HOST_MEMBERSHIP_REPORT: case IGMPV2_HOST_MEMBERSHIP_REPORT: |
62b2bcb49 IGMP snooping: se... |
1518 |
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
6db6f0eae bridge: multicast... |
1519 |
err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); |
eb1d16414 bridge: Add core ... |
1520 1521 |
break; case IGMPV3_HOST_MEMBERSHIP_REPORT: |
ba5ea6146 bridge: simplify ... |
1522 |
err = br_ip4_multicast_igmp3_report(br, port, skb, vid); |
eb1d16414 bridge: Add core ... |
1523 1524 |
break; case IGMP_HOST_MEMBERSHIP_QUERY: |
ba5ea6146 bridge: simplify ... |
1525 |
br_ip4_multicast_query(br, port, skb, vid); |
eb1d16414 bridge: Add core ... |
1526 1527 |
break; case IGMP_HOST_LEAVE_MESSAGE: |
6db6f0eae bridge: multicast... |
1528 |
br_ip4_multicast_leave_group(br, port, ih->group, vid, src); |
eb1d16414 bridge: Add core ... |
1529 1530 |
break; } |
a65056ecf net: bridge: exte... |
1531 |
br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, |
1080ab95e net: bridge: add ... |
1532 |
BR_MCAST_DIR_RX); |
eb1d16414 bridge: Add core ... |
1533 1534 |
return err; } |
dfd56b8b3 net: use IS_ENABL... |
1535 |
#if IS_ENABLED(CONFIG_IPV6) |
4b3087c7e bridge: Snoop Mul... |
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 |
static int br_ip6_multicast_mrd_rcv(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb) { int ret; if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6) return -ENOMSG; ret = ipv6_mc_check_icmpv6(skb); if (ret < 0) return ret; if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) return -ENOMSG; br_multicast_mark_router(br, port); return 0; } |
08b202b67 bridge br_multica... |
1556 1557 |
static int br_multicast_ipv6_rcv(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
1558 1559 |
struct sk_buff *skb, u16 vid) |
08b202b67 bridge br_multica... |
1560 |
{ |
6db6f0eae bridge: multicast... |
1561 |
const unsigned char *src; |
9afd85c9e net: Export IGMP/... |
1562 |
struct mld_msg *mld; |
08b202b67 bridge br_multica... |
1563 |
int err; |
ba5ea6146 bridge: simplify ... |
1564 |
err = ipv6_mc_check_mld(skb); |
08b202b67 bridge br_multica... |
1565 |
|
9afd85c9e net: Export IGMP/... |
1566 1567 1568 |
if (err == -ENOMSG) { if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
4b3087c7e bridge: Snoop Mul... |
1569 1570 1571 1572 1573 1574 1575 1576 1577 |
if (ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) { err = br_ip6_multicast_mrd_rcv(br, port, skb); if (err < 0 && err != -ENOMSG) { br_multicast_err_count(br, port, skb->protocol); return err; } } |
08b202b67 bridge br_multica... |
1578 |
return 0; |
9afd85c9e net: Export IGMP/... |
1579 |
} else if (err < 0) { |
1080ab95e net: bridge: add ... |
1580 |
br_multicast_err_count(br, port, skb->protocol); |
9afd85c9e net: Export IGMP/... |
1581 |
return err; |
08b202b67 bridge br_multica... |
1582 |
} |
9afd85c9e net: Export IGMP/... |
1583 |
mld = (struct mld_msg *)skb_transport_header(skb); |
1080ab95e net: bridge: add ... |
1584 |
BR_INPUT_SKB_CB(skb)->igmp = mld->mld_type; |
08b202b67 bridge br_multica... |
1585 |
|
9afd85c9e net: Export IGMP/... |
1586 |
switch (mld->mld_type) { |
08b202b67 bridge br_multica... |
1587 |
case ICMPV6_MGM_REPORT: |
6db6f0eae bridge: multicast... |
1588 |
src = eth_hdr(skb)->h_source; |
fc2af6c73 IGMP snooping: se... |
1589 |
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; |
6db6f0eae bridge: multicast... |
1590 1591 |
err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, src); |
08b202b67 bridge br_multica... |
1592 |
break; |
08b202b67 bridge br_multica... |
1593 |
case ICMPV6_MLD2_REPORT: |
ba5ea6146 bridge: simplify ... |
1594 |
err = br_ip6_multicast_mld2_report(br, port, skb, vid); |
08b202b67 bridge br_multica... |
1595 1596 |
break; case ICMPV6_MGM_QUERY: |
ba5ea6146 bridge: simplify ... |
1597 |
err = br_ip6_multicast_query(br, port, skb, vid); |
08b202b67 bridge br_multica... |
1598 1599 |
break; case ICMPV6_MGM_REDUCTION: |
6db6f0eae bridge: multicast... |
1600 1601 |
src = eth_hdr(skb)->h_source; br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); |
9afd85c9e net: Export IGMP/... |
1602 |
break; |
08b202b67 bridge br_multica... |
1603 |
} |
a65056ecf net: bridge: exte... |
1604 |
br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, |
1080ab95e net: bridge: add ... |
1605 |
BR_MCAST_DIR_RX); |
08b202b67 bridge br_multica... |
1606 1607 1608 |
return err; } #endif |
eb1d16414 bridge: Add core ... |
1609 |
int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, |
06499098a bridge: pass corr... |
1610 |
struct sk_buff *skb, u16 vid) |
eb1d16414 bridge: Add core ... |
1611 |
{ |
1080ab95e net: bridge: add ... |
1612 |
int ret = 0; |
1fafc7a93 bridge br_multica... |
1613 1614 |
BR_INPUT_SKB_CB(skb)->igmp = 0; BR_INPUT_SKB_CB(skb)->mrouters_only = 0; |
13cefad2f net: bridge: conv... |
1615 |
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
eb1d16414 bridge: Add core ... |
1616 1617 1618 1619 |
return 0; switch (skb->protocol) { case htons(ETH_P_IP): |
1080ab95e net: bridge: add ... |
1620 1621 |
ret = br_multicast_ipv4_rcv(br, port, skb, vid); break; |
dfd56b8b3 net: use IS_ENABL... |
1622 |
#if IS_ENABLED(CONFIG_IPV6) |
08b202b67 bridge br_multica... |
1623 |
case htons(ETH_P_IPV6): |
1080ab95e net: bridge: add ... |
1624 1625 |
ret = br_multicast_ipv6_rcv(br, port, skb, vid); break; |
08b202b67 bridge br_multica... |
1626 |
#endif |
eb1d16414 bridge: Add core ... |
1627 |
} |
1080ab95e net: bridge: add ... |
1628 |
return ret; |
eb1d16414 bridge: Add core ... |
1629 |
} |
cc0fdd802 bridge: separate ... |
1630 |
static void br_multicast_query_expired(struct net_bridge *br, |
2cd414319 bridge: memorize ... |
1631 1632 |
struct bridge_mcast_own_query *query, struct bridge_mcast_querier *querier) |
cc0fdd802 bridge: separate ... |
1633 1634 1635 1636 |
{ spin_lock(&br->multicast_lock); if (query->startup_sent < br->multicast_startup_query_count) query->startup_sent++; |
71d9f6149 bridge: fix br_mu... |
1637 |
RCU_INIT_POINTER(querier->port, NULL); |
cc0fdd802 bridge: separate ... |
1638 1639 1640 |
br_multicast_send_query(br, NULL, query); spin_unlock(&br->multicast_lock); } |
88c1f37f0 net: bridge: Conv... |
1641 |
static void br_ip4_multicast_query_expired(struct timer_list *t) |
eb1d16414 bridge: Add core ... |
1642 |
{ |
88c1f37f0 net: bridge: Conv... |
1643 |
struct net_bridge *br = from_timer(br, t, ip4_own_query.timer); |
eb1d16414 bridge: Add core ... |
1644 |
|
2cd414319 bridge: memorize ... |
1645 |
br_multicast_query_expired(br, &br->ip4_own_query, &br->ip4_querier); |
cc0fdd802 bridge: separate ... |
1646 |
} |
eb1d16414 bridge: Add core ... |
1647 |
|
cc0fdd802 bridge: separate ... |
1648 |
#if IS_ENABLED(CONFIG_IPV6) |
88c1f37f0 net: bridge: Conv... |
1649 |
static void br_ip6_multicast_query_expired(struct timer_list *t) |
cc0fdd802 bridge: separate ... |
1650 |
{ |
88c1f37f0 net: bridge: Conv... |
1651 |
struct net_bridge *br = from_timer(br, t, ip6_own_query.timer); |
eb1d16414 bridge: Add core ... |
1652 |
|
2cd414319 bridge: memorize ... |
1653 |
br_multicast_query_expired(br, &br->ip6_own_query, &br->ip6_querier); |
eb1d16414 bridge: Add core ... |
1654 |
} |
cc0fdd802 bridge: separate ... |
1655 |
#endif |
eb1d16414 bridge: Add core ... |
1656 1657 1658 |
void br_multicast_init(struct net_bridge *br) { |
d08c6bc08 net: bridge: incr... |
1659 |
br->hash_max = BR_MULTICAST_DEFAULT_HASH_MAX; |
eb1d16414 bridge: Add core ... |
1660 |
|
7f0aec7a6 bridge: mcast: us... |
1661 |
br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; |
eb1d16414 bridge: Add core ... |
1662 1663 1664 1665 1666 1667 1668 1669 1670 |
br->multicast_last_member_count = 2; br->multicast_startup_query_count = 2; br->multicast_last_member_interval = HZ; br->multicast_query_response_interval = 10 * HZ; br->multicast_startup_query_interval = 125 * HZ / 4; br->multicast_query_interval = 125 * HZ; br->multicast_querier_interval = 255 * HZ; br->multicast_membership_interval = 260 * HZ; |
90010b36e bridge: rename st... |
1671 |
br->ip4_other_query.delay_time = 0; |
2cd414319 bridge: memorize ... |
1672 |
br->ip4_querier.port = NULL; |
aa2ae3e71 bridge: mcast: ad... |
1673 |
br->multicast_igmp_version = 2; |
cc0fdd802 bridge: separate ... |
1674 |
#if IS_ENABLED(CONFIG_IPV6) |
aa2ae3e71 bridge: mcast: ad... |
1675 |
br->multicast_mld_version = 1; |
90010b36e bridge: rename st... |
1676 |
br->ip6_other_query.delay_time = 0; |
2cd414319 bridge: memorize ... |
1677 |
br->ip6_querier.port = NULL; |
cc0fdd802 bridge: separate ... |
1678 |
#endif |
6919622af bridge: mcast: De... |
1679 |
br_opt_toggle(br, BROPT_MULTICAST_ENABLED, true); |
675779adb net: bridge: conv... |
1680 |
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); |
b00589af3 bridge: disable s... |
1681 |
|
eb1d16414 bridge: Add core ... |
1682 |
spin_lock_init(&br->multicast_lock); |
88c1f37f0 net: bridge: Conv... |
1683 1684 1685 1686 1687 1688 |
timer_setup(&br->multicast_router_timer, br_multicast_local_router_expired, 0); timer_setup(&br->ip4_other_query.timer, br_ip4_multicast_querier_expired, 0); timer_setup(&br->ip4_own_query.timer, br_ip4_multicast_query_expired, 0); |
cc0fdd802 bridge: separate ... |
1689 |
#if IS_ENABLED(CONFIG_IPV6) |
88c1f37f0 net: bridge: Conv... |
1690 1691 1692 1693 |
timer_setup(&br->ip6_other_query.timer, br_ip6_multicast_querier_expired, 0); timer_setup(&br->ip6_own_query.timer, br_ip6_multicast_query_expired, 0); |
cc0fdd802 bridge: separate ... |
1694 |
#endif |
19e3a9c90 net: bridge: conv... |
1695 |
INIT_HLIST_HEAD(&br->mdb_list); |
eb1d16414 bridge: Add core ... |
1696 |
} |
4effd28c1 bridge: join all-... |
1697 1698 1699 1700 1701 1702 |
static void br_ip4_multicast_join_snoopers(struct net_bridge *br) { struct in_device *in_dev = in_dev_get(br->dev); if (!in_dev) return; |
9fb20801d net: Fix ip_mc_{d... |
1703 |
__ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC); |
4effd28c1 bridge: join all-... |
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 |
in_dev_put(in_dev); } #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_join_snoopers(struct net_bridge *br) { struct in6_addr addr; ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a)); ipv6_dev_mc_inc(br->dev, &addr); } #else static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br) { } #endif static void br_multicast_join_snoopers(struct net_bridge *br) { br_ip4_multicast_join_snoopers(br); br_ip6_multicast_join_snoopers(br); } static void br_ip4_multicast_leave_snoopers(struct net_bridge *br) { struct in_device *in_dev = in_dev_get(br->dev); if (WARN_ON(!in_dev)) return; |
9fb20801d net: Fix ip_mc_{d... |
1733 |
__ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC); |
4effd28c1 bridge: join all-... |
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 |
in_dev_put(in_dev); } #if IS_ENABLED(CONFIG_IPV6) static void br_ip6_multicast_leave_snoopers(struct net_bridge *br) { struct in6_addr addr; ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a)); ipv6_dev_mc_dec(br->dev, &addr); } #else static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br) { } #endif static void br_multicast_leave_snoopers(struct net_bridge *br) { br_ip4_multicast_leave_snoopers(br); br_ip6_multicast_leave_snoopers(br); } |
cc0fdd802 bridge: separate ... |
1756 |
static void __br_multicast_open(struct net_bridge *br, |
90010b36e bridge: rename st... |
1757 |
struct bridge_mcast_own_query *query) |
eb1d16414 bridge: Add core ... |
1758 |
{ |
cc0fdd802 bridge: separate ... |
1759 |
query->startup_sent = 0; |
eb1d16414 bridge: Add core ... |
1760 |
|
13cefad2f net: bridge: conv... |
1761 |
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) |
eb1d16414 bridge: Add core ... |
1762 |
return; |
cc0fdd802 bridge: separate ... |
1763 1764 1765 1766 1767 |
mod_timer(&query->timer, jiffies); } void br_multicast_open(struct net_bridge *br) { |
4effd28c1 bridge: join all-... |
1768 1769 |
if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) br_multicast_join_snoopers(br); |
90010b36e bridge: rename st... |
1770 |
__br_multicast_open(br, &br->ip4_own_query); |
cc0fdd802 bridge: separate ... |
1771 |
#if IS_ENABLED(CONFIG_IPV6) |
90010b36e bridge: rename st... |
1772 |
__br_multicast_open(br, &br->ip6_own_query); |
cc0fdd802 bridge: separate ... |
1773 |
#endif |
eb1d16414 bridge: Add core ... |
1774 1775 1776 1777 |
} void br_multicast_stop(struct net_bridge *br) { |
eb1d16414 bridge: Add core ... |
1778 |
del_timer_sync(&br->multicast_router_timer); |
90010b36e bridge: rename st... |
1779 1780 |
del_timer_sync(&br->ip4_other_query.timer); del_timer_sync(&br->ip4_own_query.timer); |
cc0fdd802 bridge: separate ... |
1781 |
#if IS_ENABLED(CONFIG_IPV6) |
90010b36e bridge: rename st... |
1782 1783 |
del_timer_sync(&br->ip6_other_query.timer); del_timer_sync(&br->ip6_own_query.timer); |
cc0fdd802 bridge: separate ... |
1784 |
#endif |
4effd28c1 bridge: join all-... |
1785 1786 1787 |
if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) br_multicast_leave_snoopers(br); |
e10177abf bridge: multicast... |
1788 1789 1790 1791 |
} void br_multicast_dev_del(struct net_bridge *br) { |
e10177abf bridge: multicast... |
1792 |
struct net_bridge_mdb_entry *mp; |
19e3a9c90 net: bridge: conv... |
1793 |
struct hlist_node *tmp; |
eb1d16414 bridge: Add core ... |
1794 1795 |
spin_lock_bh(&br->multicast_lock); |
19e3a9c90 net: bridge: conv... |
1796 1797 1798 1799 1800 |
hlist_for_each_entry_safe(mp, tmp, &br->mdb_list, mdb_node) { del_timer(&mp->timer); rhashtable_remove_fast(&br->mdb_hash_tbl, &mp->rhnode, br_mdb_rht_params); hlist_del_rcu(&mp->mdb_node); |
4329596cb net: bridge: mult... |
1801 |
kfree_rcu(mp, rcu); |
eb1d16414 bridge: Add core ... |
1802 |
} |
eb1d16414 bridge: Add core ... |
1803 |
spin_unlock_bh(&br->multicast_lock); |
19e3a9c90 net: bridge: conv... |
1804 |
|
4329596cb net: bridge: mult... |
1805 |
rcu_barrier(); |
eb1d16414 bridge: Add core ... |
1806 |
} |
0909e1175 bridge: Add multi... |
1807 1808 1809 |
int br_multicast_set_router(struct net_bridge *br, unsigned long val) { |
6ae4ae8e5 bridge: allow set... |
1810 |
int err = -EINVAL; |
0909e1175 bridge: Add multi... |
1811 1812 |
spin_lock_bh(&br->multicast_lock); |
0909e1175 bridge: Add multi... |
1813 1814 |
switch (val) { |
7f0aec7a6 bridge: mcast: us... |
1815 1816 |
case MDB_RTR_TYPE_DISABLED: case MDB_RTR_TYPE_PERM: |
770414207 net: bridge: Noti... |
1817 |
br_mc_router_state_change(br, val == MDB_RTR_TYPE_PERM); |
0909e1175 bridge: Add multi... |
1818 |
del_timer(&br->multicast_router_timer); |
770414207 net: bridge: Noti... |
1819 1820 1821 |
br->multicast_router = val; err = 0; break; |
7f0aec7a6 bridge: mcast: us... |
1822 |
case MDB_RTR_TYPE_TEMP_QUERY: |
770414207 net: bridge: Noti... |
1823 1824 |
if (br->multicast_router != MDB_RTR_TYPE_TEMP_QUERY) br_mc_router_state_change(br, false); |
0909e1175 bridge: Add multi... |
1825 1826 1827 |
br->multicast_router = val; err = 0; break; |
0909e1175 bridge: Add multi... |
1828 |
} |
0909e1175 bridge: Add multi... |
1829 1830 1831 1832 |
spin_unlock_bh(&br->multicast_lock); return err; } |
7f0aec7a6 bridge: mcast: us... |
1833 1834 1835 1836 1837 1838 |
static void __del_port_router(struct net_bridge_port *p) { if (hlist_unhashed(&p->rlist)) return; hlist_del_init_rcu(&p->rlist); br_rtr_notify(p->br->dev, p, RTM_DELMDB); |
6d5496483 switchdev: bridge... |
1839 |
br_port_mc_router_state_change(p, false); |
f12e7d95d bridge: mcast: Me... |
1840 1841 1842 1843 |
/* don't allow timer refresh */ if (p->multicast_router == MDB_RTR_TYPE_TEMP) p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; |
7f0aec7a6 bridge: mcast: us... |
1844 |
} |
0909e1175 bridge: Add multi... |
1845 1846 1847 |
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) { struct net_bridge *br = p->br; |
a55d8246a bridge: mcast: ad... |
1848 |
unsigned long now = jiffies; |
6ae4ae8e5 bridge: allow set... |
1849 |
int err = -EINVAL; |
0909e1175 bridge: Add multi... |
1850 1851 |
spin_lock(&br->multicast_lock); |
4950cfd1e bridge: mcast: do... |
1852 |
if (p->multicast_router == val) { |
a55d8246a bridge: mcast: ad... |
1853 1854 1855 1856 |
/* Refresh the temp router port timer */ if (p->multicast_router == MDB_RTR_TYPE_TEMP) mod_timer(&p->multicast_router_timer, now + br->multicast_querier_interval); |
4950cfd1e bridge: mcast: do... |
1857 1858 1859 |
err = 0; goto unlock; } |
0909e1175 bridge: Add multi... |
1860 |
switch (val) { |
7f0aec7a6 bridge: mcast: us... |
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 |
case MDB_RTR_TYPE_DISABLED: p->multicast_router = MDB_RTR_TYPE_DISABLED; __del_port_router(p); del_timer(&p->multicast_router_timer); break; case MDB_RTR_TYPE_TEMP_QUERY: p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY; __del_port_router(p); break; case MDB_RTR_TYPE_PERM: p->multicast_router = MDB_RTR_TYPE_PERM; |
0909e1175 bridge: Add multi... |
1872 |
del_timer(&p->multicast_router_timer); |
0909e1175 bridge: Add multi... |
1873 1874 |
br_multicast_add_router(br, p); break; |
a55d8246a bridge: mcast: ad... |
1875 1876 1877 1878 |
case MDB_RTR_TYPE_TEMP: p->multicast_router = MDB_RTR_TYPE_TEMP; br_multicast_mark_router(br, p); break; |
7f0aec7a6 bridge: mcast: us... |
1879 1880 |
default: goto unlock; |
0909e1175 bridge: Add multi... |
1881 |
} |
7f0aec7a6 bridge: mcast: us... |
1882 1883 |
err = 0; unlock: |
0909e1175 bridge: Add multi... |
1884 1885 1886 1887 |
spin_unlock(&br->multicast_lock); return err; } |
561f1103a bridge: Add multi... |
1888 |
|
cc0fdd802 bridge: separate ... |
1889 |
static void br_multicast_start_querier(struct net_bridge *br, |
90010b36e bridge: rename st... |
1890 |
struct bridge_mcast_own_query *query) |
561f1103a bridge: Add multi... |
1891 1892 |
{ struct net_bridge_port *port; |
748572162 bridge: Add br_mu... |
1893 |
|
cc0fdd802 bridge: separate ... |
1894 |
__br_multicast_open(br, query); |
748572162 bridge: Add br_mu... |
1895 |
|
c5b493ce1 net: bridge: mult... |
1896 1897 |
rcu_read_lock(); list_for_each_entry_rcu(port, &br->port_list, list) { |
748572162 bridge: Add br_mu... |
1898 1899 1900 |
if (port->state == BR_STATE_DISABLED || port->state == BR_STATE_BLOCKING) continue; |
90010b36e bridge: rename st... |
1901 1902 |
if (query == &br->ip4_own_query) br_multicast_enable(&port->ip4_own_query); |
cc0fdd802 bridge: separate ... |
1903 1904 |
#if IS_ENABLED(CONFIG_IPV6) else |
90010b36e bridge: rename st... |
1905 |
br_multicast_enable(&port->ip6_own_query); |
cc0fdd802 bridge: separate ... |
1906 |
#endif |
748572162 bridge: Add br_mu... |
1907 |
} |
c5b493ce1 net: bridge: mult... |
1908 |
rcu_read_unlock(); |
748572162 bridge: Add br_mu... |
1909 1910 1911 1912 |
} int br_multicast_toggle(struct net_bridge *br, unsigned long val) { |
7cb3f9214 bridge: multicast... |
1913 |
struct net_bridge_port *port; |
561f1103a bridge: Add multi... |
1914 |
|
ef5e0d823 bridge: Fix poten... |
1915 |
spin_lock_bh(&br->multicast_lock); |
13cefad2f net: bridge: conv... |
1916 |
if (!!br_opt_get(br, BROPT_MULTICAST_ENABLED) == !!val) |
561f1103a bridge: Add multi... |
1917 |
goto unlock; |
13cefad2f net: bridge: conv... |
1918 1919 |
br_mc_disabled_update(br->dev, val); br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val); |
4effd28c1 bridge: join all-... |
1920 1921 |
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) { br_multicast_leave_snoopers(br); |
561f1103a bridge: Add multi... |
1922 |
goto unlock; |
4effd28c1 bridge: join all-... |
1923 |
} |
561f1103a bridge: Add multi... |
1924 |
|
3a7fda06b bridge: Allow mul... |
1925 1926 |
if (!netif_running(br->dev)) goto unlock; |
7cb3f9214 bridge: multicast... |
1927 1928 1929 |
br_multicast_open(br); list_for_each_entry(port, &br->port_list, list) __br_multicast_enable_port(port); |
561f1103a bridge: Add multi... |
1930 1931 |
unlock: |
ef5e0d823 bridge: Fix poten... |
1932 |
spin_unlock_bh(&br->multicast_lock); |
561f1103a bridge: Add multi... |
1933 |
|
a26d94bff net: bridge: remo... |
1934 |
return 0; |
561f1103a bridge: Add multi... |
1935 |
} |
b195167fc bridge: Add hash ... |
1936 |
|
9341b988e bridge: Export mu... |
1937 1938 1939 |
bool br_multicast_enabled(const struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); |
13cefad2f net: bridge: conv... |
1940 |
return !!br_opt_get(br, BROPT_MULTICAST_ENABLED); |
9341b988e bridge: Export mu... |
1941 1942 |
} EXPORT_SYMBOL_GPL(br_multicast_enabled); |
0912bda43 net: bridge: Expo... |
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 |
bool br_multicast_router(const struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); bool is_router; spin_lock_bh(&br->multicast_lock); is_router = br_multicast_is_router(br); spin_unlock_bh(&br->multicast_lock); return is_router; } EXPORT_SYMBOL_GPL(br_multicast_router); |
c5c232605 bridge: Add multi... |
1954 1955 |
int br_multicast_set_querier(struct net_bridge *br, unsigned long val) { |
b00589af3 bridge: disable s... |
1956 |
unsigned long max_delay; |
c5c232605 bridge: Add multi... |
1957 1958 1959 |
val = !!val; spin_lock_bh(&br->multicast_lock); |
675779adb net: bridge: conv... |
1960 |
if (br_opt_get(br, BROPT_MULTICAST_QUERIER) == val) |
c5c232605 bridge: Add multi... |
1961 |
goto unlock; |
675779adb net: bridge: conv... |
1962 |
br_opt_toggle(br, BROPT_MULTICAST_QUERIER, !!val); |
b00589af3 bridge: disable s... |
1963 1964 1965 1966 |
if (!val) goto unlock; max_delay = br->multicast_query_response_interval; |
b00589af3 bridge: disable s... |
1967 |
|
90010b36e bridge: rename st... |
1968 1969 |
if (!timer_pending(&br->ip4_other_query.timer)) br->ip4_other_query.delay_time = jiffies + max_delay; |
cc0fdd802 bridge: separate ... |
1970 |
|
90010b36e bridge: rename st... |
1971 |
br_multicast_start_querier(br, &br->ip4_own_query); |
cc0fdd802 bridge: separate ... |
1972 1973 |
#if IS_ENABLED(CONFIG_IPV6) |
90010b36e bridge: rename st... |
1974 1975 |
if (!timer_pending(&br->ip6_other_query.timer)) br->ip6_other_query.delay_time = jiffies + max_delay; |
cc0fdd802 bridge: separate ... |
1976 |
|
90010b36e bridge: rename st... |
1977 |
br_multicast_start_querier(br, &br->ip6_own_query); |
cc0fdd802 bridge: separate ... |
1978 |
#endif |
c5c232605 bridge: Add multi... |
1979 1980 1981 1982 1983 1984 |
unlock: spin_unlock_bh(&br->multicast_lock); return 0; } |
5e9235853 bridge: mcast: ad... |
1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 |
int br_multicast_set_igmp_version(struct net_bridge *br, unsigned long val) { /* Currently we support only version 2 and 3 */ switch (val) { case 2: case 3: break; default: return -EINVAL; } spin_lock_bh(&br->multicast_lock); br->multicast_igmp_version = val; spin_unlock_bh(&br->multicast_lock); return 0; } |
aa2ae3e71 bridge: mcast: ad... |
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 |
#if IS_ENABLED(CONFIG_IPV6) int br_multicast_set_mld_version(struct net_bridge *br, unsigned long val) { /* Currently we support version 1 and 2 */ switch (val) { case 1: case 2: break; default: return -EINVAL; } spin_lock_bh(&br->multicast_lock); br->multicast_mld_version = val; spin_unlock_bh(&br->multicast_lock); return 0; } #endif |
07f8ac4a1 bridge: add expor... |
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 |
/** * br_multicast_list_adjacent - Returns snooped multicast addresses * @dev: The bridge port adjacent to which to retrieve addresses * @br_ip_list: The list to store found, snooped multicast IP addresses in * * Creates a list of IP addresses (struct br_ip_list) sensed by the multicast * snooping feature on all bridge ports of dev's bridge device, excluding * the addresses from dev itself. * * Returns the number of items added to br_ip_list. * * Notes: * - br_ip_list needs to be initialized by caller * - br_ip_list might contain duplicates in the end * (needs to be taken care of by caller) * - br_ip_list needs to be freed by caller */ int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list) { struct net_bridge *br; struct net_bridge_port *port; struct net_bridge_port_group *group; struct br_ip_list *entry; int count = 0; rcu_read_lock(); |
35f861e3c net: bridge: use ... |
2048 |
if (!br_ip_list || !netif_is_bridge_port(dev)) |
07f8ac4a1 bridge: add expor... |
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 |
goto unlock; port = br_port_get_rcu(dev); if (!port || !port->br) goto unlock; br = port->br; list_for_each_entry_rcu(port, &br->port_list, list) { if (!port->dev || port->dev == dev) continue; hlist_for_each_entry_rcu(group, &port->mglist, mglist) { entry = kmalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) goto unlock; entry->addr = group->addr; list_add(&entry->list, br_ip_list); count++; } } unlock: rcu_read_unlock(); return count; } EXPORT_SYMBOL_GPL(br_multicast_list_adjacent); |
2cd414319 bridge: memorize ... |
2077 2078 |
/** |
c34963e21 bridge: export kn... |
2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 |
* br_multicast_has_querier_anywhere - Checks for a querier on a bridge * @dev: The bridge port providing the bridge on which to check for a querier * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 * * Checks whether the given interface has a bridge on top and if so returns * true if a valid querier exists anywhere on the bridged link layer. * Otherwise returns false. */ bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto) { struct net_bridge *br; struct net_bridge_port *port; struct ethhdr eth; bool ret = false; rcu_read_lock(); |
35f861e3c net: bridge: use ... |
2095 |
if (!netif_is_bridge_port(dev)) |
c34963e21 bridge: export kn... |
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 |
goto unlock; port = br_port_get_rcu(dev); if (!port || !port->br) goto unlock; br = port->br; memset(ð, 0, sizeof(eth)); eth.h_proto = htons(proto); ret = br_multicast_querier_exists(br, ð); unlock: rcu_read_unlock(); return ret; } EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere); /** |
2cd414319 bridge: memorize ... |
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 |
* br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port * @dev: The bridge port adjacent to which to check for a querier * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 * * Checks whether the given interface has a bridge on top and if so returns * true if a selected querier is behind one of the other ports of this * bridge. Otherwise returns false. */ bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto) { struct net_bridge *br; struct net_bridge_port *port; bool ret = false; rcu_read_lock(); |
35f861e3c net: bridge: use ... |
2131 |
if (!netif_is_bridge_port(dev)) |
2cd414319 bridge: memorize ... |
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 |
goto unlock; port = br_port_get_rcu(dev); if (!port || !port->br) goto unlock; br = port->br; switch (proto) { case ETH_P_IP: if (!timer_pending(&br->ip4_other_query.timer) || rcu_dereference(br->ip4_querier.port) == port) goto unlock; break; |
3993c4e15 bridge: fix compi... |
2146 |
#if IS_ENABLED(CONFIG_IPV6) |
2cd414319 bridge: memorize ... |
2147 2148 2149 2150 2151 |
case ETH_P_IPV6: if (!timer_pending(&br->ip6_other_query.timer) || rcu_dereference(br->ip6_querier.port) == port) goto unlock; break; |
3993c4e15 bridge: fix compi... |
2152 |
#endif |
2cd414319 bridge: memorize ... |
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 |
default: goto unlock; } ret = true; unlock: rcu_read_unlock(); return ret; } EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent); |
1080ab95e net: bridge: add ... |
2163 2164 |
static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats, |
a65056ecf net: bridge: exte... |
2165 |
const struct sk_buff *skb, u8 type, u8 dir) |
1080ab95e net: bridge: add ... |
2166 2167 |
{ struct bridge_mcast_stats *pstats = this_cpu_ptr(stats); |
a65056ecf net: bridge: exte... |
2168 2169 |
__be16 proto = skb->protocol; unsigned int t_len; |
1080ab95e net: bridge: add ... |
2170 2171 2172 2173 |
u64_stats_update_begin(&pstats->syncp); switch (proto) { case htons(ETH_P_IP): |
a65056ecf net: bridge: exte... |
2174 |
t_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb); |
1080ab95e net: bridge: add ... |
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 |
switch (type) { case IGMP_HOST_MEMBERSHIP_REPORT: pstats->mstats.igmp_v1reports[dir]++; break; case IGMPV2_HOST_MEMBERSHIP_REPORT: pstats->mstats.igmp_v2reports[dir]++; break; case IGMPV3_HOST_MEMBERSHIP_REPORT: pstats->mstats.igmp_v3reports[dir]++; break; case IGMP_HOST_MEMBERSHIP_QUERY: |
a65056ecf net: bridge: exte... |
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 |
if (t_len != sizeof(struct igmphdr)) { pstats->mstats.igmp_v3queries[dir]++; } else { unsigned int offset = skb_transport_offset(skb); struct igmphdr *ih, _ihdr; ih = skb_header_pointer(skb, offset, sizeof(_ihdr), &_ihdr); if (!ih) break; if (!ih->code) pstats->mstats.igmp_v1queries[dir]++; else pstats->mstats.igmp_v2queries[dir]++; } |
1080ab95e net: bridge: add ... |
2201 2202 2203 2204 2205 2206 2207 2208 |
break; case IGMP_HOST_LEAVE_MESSAGE: pstats->mstats.igmp_leaves[dir]++; break; } break; #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): |
a65056ecf net: bridge: exte... |
2209 2210 2211 |
t_len = ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr); t_len -= skb_network_header_len(skb); |
1080ab95e net: bridge: add ... |
2212 2213 2214 2215 2216 2217 2218 2219 |
switch (type) { case ICMPV6_MGM_REPORT: pstats->mstats.mld_v1reports[dir]++; break; case ICMPV6_MLD2_REPORT: pstats->mstats.mld_v2reports[dir]++; break; case ICMPV6_MGM_QUERY: |
a65056ecf net: bridge: exte... |
2220 2221 2222 2223 |
if (t_len != sizeof(struct mld_msg)) pstats->mstats.mld_v2queries[dir]++; else pstats->mstats.mld_v1queries[dir]++; |
1080ab95e net: bridge: add ... |
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 |
break; case ICMPV6_MGM_REDUCTION: pstats->mstats.mld_leaves[dir]++; break; } break; #endif /* CONFIG_IPV6 */ } u64_stats_update_end(&pstats->syncp); } void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p, |
a65056ecf net: bridge: exte... |
2236 |
const struct sk_buff *skb, u8 type, u8 dir) |
1080ab95e net: bridge: add ... |
2237 2238 2239 2240 |
{ struct bridge_mcast_stats __percpu *stats; /* if multicast_disabled is true then igmp type can't be set */ |
675779adb net: bridge: conv... |
2241 |
if (!type || !br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) |
1080ab95e net: bridge: add ... |
2242 2243 2244 2245 2246 2247 2248 2249 |
return; if (p) stats = p->mcast_stats; else stats = br->mcast_stats; if (WARN_ON(!stats)) return; |
a65056ecf net: bridge: exte... |
2250 |
br_mcast_stats_add(stats, skb, type, dir); |
1080ab95e net: bridge: add ... |
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 |
} int br_multicast_init_stats(struct net_bridge *br) { br->mcast_stats = netdev_alloc_pcpu_stats(struct bridge_mcast_stats); if (!br->mcast_stats) return -ENOMEM; return 0; } |
b6fe0440c bridge: implement... |
2261 2262 2263 2264 |
void br_multicast_uninit_stats(struct net_bridge *br) { free_percpu(br->mcast_stats); } |
b3b6a84c6 bridge: multicast... |
2265 2266 |
/* noinline for https://bugs.llvm.org/show_bug.cgi?id=45802#c9 */ static noinline_for_stack void mcast_stats_add_dir(u64 *dst, u64 *src) |
1080ab95e net: bridge: add ... |
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 |
{ dst[BR_MCAST_DIR_RX] += src[BR_MCAST_DIR_RX]; dst[BR_MCAST_DIR_TX] += src[BR_MCAST_DIR_TX]; } void br_multicast_get_stats(const struct net_bridge *br, const struct net_bridge_port *p, struct br_mcast_stats *dest) { struct bridge_mcast_stats __percpu *stats; struct br_mcast_stats tdst; int i; memset(dest, 0, sizeof(*dest)); if (p) stats = p->mcast_stats; else stats = br->mcast_stats; if (WARN_ON(!stats)) return; memset(&tdst, 0, sizeof(tdst)); for_each_possible_cpu(i) { struct bridge_mcast_stats *cpu_stats = per_cpu_ptr(stats, i); struct br_mcast_stats temp; unsigned int start; do { start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); memcpy(&temp, &cpu_stats->mstats, sizeof(temp)); } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); |
a65056ecf net: bridge: exte... |
2298 2299 2300 |
mcast_stats_add_dir(tdst.igmp_v1queries, temp.igmp_v1queries); mcast_stats_add_dir(tdst.igmp_v2queries, temp.igmp_v2queries); mcast_stats_add_dir(tdst.igmp_v3queries, temp.igmp_v3queries); |
1080ab95e net: bridge: add ... |
2301 2302 2303 2304 2305 |
mcast_stats_add_dir(tdst.igmp_leaves, temp.igmp_leaves); mcast_stats_add_dir(tdst.igmp_v1reports, temp.igmp_v1reports); mcast_stats_add_dir(tdst.igmp_v2reports, temp.igmp_v2reports); mcast_stats_add_dir(tdst.igmp_v3reports, temp.igmp_v3reports); tdst.igmp_parse_errors += temp.igmp_parse_errors; |
a65056ecf net: bridge: exte... |
2306 2307 |
mcast_stats_add_dir(tdst.mld_v1queries, temp.mld_v1queries); mcast_stats_add_dir(tdst.mld_v2queries, temp.mld_v2queries); |
1080ab95e net: bridge: add ... |
2308 2309 2310 2311 2312 2313 2314 |
mcast_stats_add_dir(tdst.mld_leaves, temp.mld_leaves); mcast_stats_add_dir(tdst.mld_v1reports, temp.mld_v1reports); mcast_stats_add_dir(tdst.mld_v2reports, temp.mld_v2reports); tdst.mld_parse_errors += temp.mld_parse_errors; } memcpy(dest, &tdst, sizeof(*dest)); } |
19e3a9c90 net: bridge: conv... |
2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 |
int br_mdb_hash_init(struct net_bridge *br) { return rhashtable_init(&br->mdb_hash_tbl, &br_mdb_rht_params); } void br_mdb_hash_fini(struct net_bridge *br) { rhashtable_destroy(&br->mdb_hash_tbl); } |