Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bridge/br_multicast_eht.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
// Copyright (c) 2020, Nikolay Aleksandrov <[email protected]>
3
#include <linux/err.h>
4
#include <linux/export.h>
5
#include <linux/if_ether.h>
6
#include <linux/igmp.h>
7
#include <linux/in.h>
8
#include <linux/jhash.h>
9
#include <linux/kernel.h>
10
#include <linux/log2.h>
11
#include <linux/netdevice.h>
12
#include <linux/netfilter_bridge.h>
13
#include <linux/random.h>
14
#include <linux/rculist.h>
15
#include <linux/skbuff.h>
16
#include <linux/slab.h>
17
#include <linux/timer.h>
18
#include <linux/inetdevice.h>
19
#include <linux/mroute.h>
20
#include <net/ip.h>
21
#include <net/switchdev.h>
22
#if IS_ENABLED(CONFIG_IPV6)
23
#include <linux/icmpv6.h>
24
#include <net/ipv6.h>
25
#include <net/mld.h>
26
#include <net/ip6_checksum.h>
27
#include <net/addrconf.h>
28
#endif
29
30
#include "br_private.h"
31
#include "br_private_mcast_eht.h"
32
33
static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg,
34
union net_bridge_eht_addr *src_addr,
35
union net_bridge_eht_addr *h_addr);
36
static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
37
struct net_bridge_port_group *pg,
38
union net_bridge_eht_addr *src_addr,
39
union net_bridge_eht_addr *h_addr,
40
int filter_mode,
41
bool allow_zero_src);
42
43
static struct net_bridge_group_eht_host *
44
br_multicast_eht_host_lookup(struct net_bridge_port_group *pg,
45
union net_bridge_eht_addr *h_addr)
46
{
47
struct rb_node *node = pg->eht_host_tree.rb_node;
48
49
while (node) {
50
struct net_bridge_group_eht_host *this;
51
int result;
52
53
this = rb_entry(node, struct net_bridge_group_eht_host,
54
rb_node);
55
result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
56
if (result < 0)
57
node = node->rb_left;
58
else if (result > 0)
59
node = node->rb_right;
60
else
61
return this;
62
}
63
64
return NULL;
65
}
66
67
static int br_multicast_eht_host_filter_mode(struct net_bridge_port_group *pg,
68
union net_bridge_eht_addr *h_addr)
69
{
70
struct net_bridge_group_eht_host *eht_host;
71
72
eht_host = br_multicast_eht_host_lookup(pg, h_addr);
73
if (!eht_host)
74
return MCAST_INCLUDE;
75
76
return eht_host->filter_mode;
77
}
78
79
static struct net_bridge_group_eht_set_entry *
80
br_multicast_eht_set_entry_lookup(struct net_bridge_group_eht_set *eht_set,
81
union net_bridge_eht_addr *h_addr)
82
{
83
struct rb_node *node = eht_set->entry_tree.rb_node;
84
85
while (node) {
86
struct net_bridge_group_eht_set_entry *this;
87
int result;
88
89
this = rb_entry(node, struct net_bridge_group_eht_set_entry,
90
rb_node);
91
result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
92
if (result < 0)
93
node = node->rb_left;
94
else if (result > 0)
95
node = node->rb_right;
96
else
97
return this;
98
}
99
100
return NULL;
101
}
102
103
static struct net_bridge_group_eht_set *
104
br_multicast_eht_set_lookup(struct net_bridge_port_group *pg,
105
union net_bridge_eht_addr *src_addr)
106
{
107
struct rb_node *node = pg->eht_set_tree.rb_node;
108
109
while (node) {
110
struct net_bridge_group_eht_set *this;
111
int result;
112
113
this = rb_entry(node, struct net_bridge_group_eht_set,
114
rb_node);
115
result = memcmp(src_addr, &this->src_addr, sizeof(*src_addr));
116
if (result < 0)
117
node = node->rb_left;
118
else if (result > 0)
119
node = node->rb_right;
120
else
121
return this;
122
}
123
124
return NULL;
125
}
126
127
static void __eht_destroy_host(struct net_bridge_group_eht_host *eht_host)
128
{
129
WARN_ON(!hlist_empty(&eht_host->set_entries));
130
131
br_multicast_eht_hosts_dec(eht_host->pg);
132
133
rb_erase(&eht_host->rb_node, &eht_host->pg->eht_host_tree);
134
RB_CLEAR_NODE(&eht_host->rb_node);
135
kfree(eht_host);
136
}
137
138
static void br_multicast_destroy_eht_set_entry(struct net_bridge_mcast_gc *gc)
139
{
140
struct net_bridge_group_eht_set_entry *set_h;
141
142
set_h = container_of(gc, struct net_bridge_group_eht_set_entry, mcast_gc);
143
WARN_ON(!RB_EMPTY_NODE(&set_h->rb_node));
144
145
timer_shutdown_sync(&set_h->timer);
146
kfree(set_h);
147
}
148
149
static void br_multicast_destroy_eht_set(struct net_bridge_mcast_gc *gc)
150
{
151
struct net_bridge_group_eht_set *eht_set;
152
153
eht_set = container_of(gc, struct net_bridge_group_eht_set, mcast_gc);
154
WARN_ON(!RB_EMPTY_NODE(&eht_set->rb_node));
155
WARN_ON(!RB_EMPTY_ROOT(&eht_set->entry_tree));
156
157
timer_shutdown_sync(&eht_set->timer);
158
kfree(eht_set);
159
}
160
161
static void __eht_del_set_entry(struct net_bridge_group_eht_set_entry *set_h)
162
{
163
struct net_bridge_group_eht_host *eht_host = set_h->h_parent;
164
union net_bridge_eht_addr zero_addr;
165
166
rb_erase(&set_h->rb_node, &set_h->eht_set->entry_tree);
167
RB_CLEAR_NODE(&set_h->rb_node);
168
hlist_del_init(&set_h->host_list);
169
memset(&zero_addr, 0, sizeof(zero_addr));
170
if (memcmp(&set_h->h_addr, &zero_addr, sizeof(zero_addr)))
171
eht_host->num_entries--;
172
hlist_add_head(&set_h->mcast_gc.gc_node, &set_h->br->mcast_gc_list);
173
queue_work(system_long_wq, &set_h->br->mcast_gc_work);
174
175
if (hlist_empty(&eht_host->set_entries))
176
__eht_destroy_host(eht_host);
177
}
178
179
static void br_multicast_del_eht_set(struct net_bridge_group_eht_set *eht_set)
180
{
181
struct net_bridge_group_eht_set_entry *set_h;
182
struct rb_node *node;
183
184
while ((node = rb_first(&eht_set->entry_tree))) {
185
set_h = rb_entry(node, struct net_bridge_group_eht_set_entry,
186
rb_node);
187
__eht_del_set_entry(set_h);
188
}
189
190
rb_erase(&eht_set->rb_node, &eht_set->pg->eht_set_tree);
191
RB_CLEAR_NODE(&eht_set->rb_node);
192
hlist_add_head(&eht_set->mcast_gc.gc_node, &eht_set->br->mcast_gc_list);
193
queue_work(system_long_wq, &eht_set->br->mcast_gc_work);
194
}
195
196
void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg)
197
{
198
struct net_bridge_group_eht_set *eht_set;
199
struct rb_node *node;
200
201
while ((node = rb_first(&pg->eht_set_tree))) {
202
eht_set = rb_entry(node, struct net_bridge_group_eht_set,
203
rb_node);
204
br_multicast_del_eht_set(eht_set);
205
}
206
}
207
208
static void br_multicast_eht_set_entry_expired(struct timer_list *t)
209
{
210
struct net_bridge_group_eht_set_entry *set_h = timer_container_of(set_h,
211
t,
212
timer);
213
struct net_bridge *br = set_h->br;
214
215
spin_lock(&br->multicast_lock);
216
if (RB_EMPTY_NODE(&set_h->rb_node) || timer_pending(&set_h->timer))
217
goto out;
218
219
br_multicast_del_eht_set_entry(set_h->eht_set->pg,
220
&set_h->eht_set->src_addr,
221
&set_h->h_addr);
222
out:
223
spin_unlock(&br->multicast_lock);
224
}
225
226
static void br_multicast_eht_set_expired(struct timer_list *t)
227
{
228
struct net_bridge_group_eht_set *eht_set = timer_container_of(eht_set,
229
t,
230
timer);
231
struct net_bridge *br = eht_set->br;
232
233
spin_lock(&br->multicast_lock);
234
if (RB_EMPTY_NODE(&eht_set->rb_node) || timer_pending(&eht_set->timer))
235
goto out;
236
237
br_multicast_del_eht_set(eht_set);
238
out:
239
spin_unlock(&br->multicast_lock);
240
}
241
242
static struct net_bridge_group_eht_host *
243
__eht_lookup_create_host(struct net_bridge_port_group *pg,
244
union net_bridge_eht_addr *h_addr,
245
unsigned char filter_mode)
246
{
247
struct rb_node **link = &pg->eht_host_tree.rb_node, *parent = NULL;
248
struct net_bridge_group_eht_host *eht_host;
249
250
while (*link) {
251
struct net_bridge_group_eht_host *this;
252
int result;
253
254
this = rb_entry(*link, struct net_bridge_group_eht_host,
255
rb_node);
256
result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
257
parent = *link;
258
if (result < 0)
259
link = &((*link)->rb_left);
260
else if (result > 0)
261
link = &((*link)->rb_right);
262
else
263
return this;
264
}
265
266
if (br_multicast_eht_hosts_over_limit(pg))
267
return NULL;
268
269
eht_host = kzalloc(sizeof(*eht_host), GFP_ATOMIC);
270
if (!eht_host)
271
return NULL;
272
273
memcpy(&eht_host->h_addr, h_addr, sizeof(*h_addr));
274
INIT_HLIST_HEAD(&eht_host->set_entries);
275
eht_host->pg = pg;
276
eht_host->filter_mode = filter_mode;
277
278
rb_link_node(&eht_host->rb_node, parent, link);
279
rb_insert_color(&eht_host->rb_node, &pg->eht_host_tree);
280
281
br_multicast_eht_hosts_inc(pg);
282
283
return eht_host;
284
}
285
286
static struct net_bridge_group_eht_set_entry *
287
__eht_lookup_create_set_entry(struct net_bridge *br,
288
struct net_bridge_group_eht_set *eht_set,
289
struct net_bridge_group_eht_host *eht_host,
290
bool allow_zero_src)
291
{
292
struct rb_node **link = &eht_set->entry_tree.rb_node, *parent = NULL;
293
struct net_bridge_group_eht_set_entry *set_h;
294
295
while (*link) {
296
struct net_bridge_group_eht_set_entry *this;
297
int result;
298
299
this = rb_entry(*link, struct net_bridge_group_eht_set_entry,
300
rb_node);
301
result = memcmp(&eht_host->h_addr, &this->h_addr,
302
sizeof(union net_bridge_eht_addr));
303
parent = *link;
304
if (result < 0)
305
link = &((*link)->rb_left);
306
else if (result > 0)
307
link = &((*link)->rb_right);
308
else
309
return this;
310
}
311
312
/* always allow auto-created zero entry */
313
if (!allow_zero_src && eht_host->num_entries >= PG_SRC_ENT_LIMIT)
314
return NULL;
315
316
set_h = kzalloc(sizeof(*set_h), GFP_ATOMIC);
317
if (!set_h)
318
return NULL;
319
320
memcpy(&set_h->h_addr, &eht_host->h_addr,
321
sizeof(union net_bridge_eht_addr));
322
set_h->mcast_gc.destroy = br_multicast_destroy_eht_set_entry;
323
set_h->eht_set = eht_set;
324
set_h->h_parent = eht_host;
325
set_h->br = br;
326
timer_setup(&set_h->timer, br_multicast_eht_set_entry_expired, 0);
327
328
hlist_add_head(&set_h->host_list, &eht_host->set_entries);
329
rb_link_node(&set_h->rb_node, parent, link);
330
rb_insert_color(&set_h->rb_node, &eht_set->entry_tree);
331
/* we must not count the auto-created zero entry otherwise we won't be
332
* able to track the full list of PG_SRC_ENT_LIMIT entries
333
*/
334
if (!allow_zero_src)
335
eht_host->num_entries++;
336
337
return set_h;
338
}
339
340
static struct net_bridge_group_eht_set *
341
__eht_lookup_create_set(struct net_bridge_port_group *pg,
342
union net_bridge_eht_addr *src_addr)
343
{
344
struct rb_node **link = &pg->eht_set_tree.rb_node, *parent = NULL;
345
struct net_bridge_group_eht_set *eht_set;
346
347
while (*link) {
348
struct net_bridge_group_eht_set *this;
349
int result;
350
351
this = rb_entry(*link, struct net_bridge_group_eht_set,
352
rb_node);
353
result = memcmp(src_addr, &this->src_addr, sizeof(*src_addr));
354
parent = *link;
355
if (result < 0)
356
link = &((*link)->rb_left);
357
else if (result > 0)
358
link = &((*link)->rb_right);
359
else
360
return this;
361
}
362
363
eht_set = kzalloc(sizeof(*eht_set), GFP_ATOMIC);
364
if (!eht_set)
365
return NULL;
366
367
memcpy(&eht_set->src_addr, src_addr, sizeof(*src_addr));
368
eht_set->mcast_gc.destroy = br_multicast_destroy_eht_set;
369
eht_set->pg = pg;
370
eht_set->br = pg->key.port->br;
371
eht_set->entry_tree = RB_ROOT;
372
timer_setup(&eht_set->timer, br_multicast_eht_set_expired, 0);
373
374
rb_link_node(&eht_set->rb_node, parent, link);
375
rb_insert_color(&eht_set->rb_node, &pg->eht_set_tree);
376
377
return eht_set;
378
}
379
380
static void br_multicast_ip_src_to_eht_addr(const struct br_ip *src,
381
union net_bridge_eht_addr *dest)
382
{
383
switch (src->proto) {
384
case htons(ETH_P_IP):
385
dest->ip4 = src->src.ip4;
386
break;
387
#if IS_ENABLED(CONFIG_IPV6)
388
case htons(ETH_P_IPV6):
389
memcpy(&dest->ip6, &src->src.ip6, sizeof(struct in6_addr));
390
break;
391
#endif
392
}
393
}
394
395
static void br_eht_convert_host_filter_mode(const struct net_bridge_mcast *brmctx,
396
struct net_bridge_port_group *pg,
397
union net_bridge_eht_addr *h_addr,
398
int filter_mode)
399
{
400
struct net_bridge_group_eht_host *eht_host;
401
union net_bridge_eht_addr zero_addr;
402
403
eht_host = br_multicast_eht_host_lookup(pg, h_addr);
404
if (eht_host)
405
eht_host->filter_mode = filter_mode;
406
407
memset(&zero_addr, 0, sizeof(zero_addr));
408
switch (filter_mode) {
409
case MCAST_INCLUDE:
410
br_multicast_del_eht_set_entry(pg, &zero_addr, h_addr);
411
break;
412
case MCAST_EXCLUDE:
413
br_multicast_create_eht_set_entry(brmctx, pg, &zero_addr,
414
h_addr, MCAST_EXCLUDE,
415
true);
416
break;
417
}
418
}
419
420
static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
421
struct net_bridge_port_group *pg,
422
union net_bridge_eht_addr *src_addr,
423
union net_bridge_eht_addr *h_addr,
424
int filter_mode,
425
bool allow_zero_src)
426
{
427
struct net_bridge_group_eht_set_entry *set_h;
428
struct net_bridge_group_eht_host *eht_host;
429
struct net_bridge *br = pg->key.port->br;
430
struct net_bridge_group_eht_set *eht_set;
431
union net_bridge_eht_addr zero_addr;
432
433
memset(&zero_addr, 0, sizeof(zero_addr));
434
if (!allow_zero_src && !memcmp(src_addr, &zero_addr, sizeof(zero_addr)))
435
return;
436
437
eht_set = __eht_lookup_create_set(pg, src_addr);
438
if (!eht_set)
439
return;
440
441
eht_host = __eht_lookup_create_host(pg, h_addr, filter_mode);
442
if (!eht_host)
443
goto fail_host;
444
445
set_h = __eht_lookup_create_set_entry(br, eht_set, eht_host,
446
allow_zero_src);
447
if (!set_h)
448
goto fail_set_entry;
449
450
mod_timer(&set_h->timer, jiffies + br_multicast_gmi(brmctx));
451
mod_timer(&eht_set->timer, jiffies + br_multicast_gmi(brmctx));
452
453
return;
454
455
fail_set_entry:
456
if (hlist_empty(&eht_host->set_entries))
457
__eht_destroy_host(eht_host);
458
fail_host:
459
if (RB_EMPTY_ROOT(&eht_set->entry_tree))
460
br_multicast_del_eht_set(eht_set);
461
}
462
463
static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg,
464
union net_bridge_eht_addr *src_addr,
465
union net_bridge_eht_addr *h_addr)
466
{
467
struct net_bridge_group_eht_set_entry *set_h;
468
struct net_bridge_group_eht_set *eht_set;
469
bool set_deleted = false;
470
471
eht_set = br_multicast_eht_set_lookup(pg, src_addr);
472
if (!eht_set)
473
goto out;
474
475
set_h = br_multicast_eht_set_entry_lookup(eht_set, h_addr);
476
if (!set_h)
477
goto out;
478
479
__eht_del_set_entry(set_h);
480
481
if (RB_EMPTY_ROOT(&eht_set->entry_tree)) {
482
br_multicast_del_eht_set(eht_set);
483
set_deleted = true;
484
}
485
486
out:
487
return set_deleted;
488
}
489
490
static void br_multicast_del_eht_host(struct net_bridge_port_group *pg,
491
union net_bridge_eht_addr *h_addr)
492
{
493
struct net_bridge_group_eht_set_entry *set_h;
494
struct net_bridge_group_eht_host *eht_host;
495
struct hlist_node *tmp;
496
497
eht_host = br_multicast_eht_host_lookup(pg, h_addr);
498
if (!eht_host)
499
return;
500
501
hlist_for_each_entry_safe(set_h, tmp, &eht_host->set_entries, host_list)
502
br_multicast_del_eht_set_entry(set_h->eht_set->pg,
503
&set_h->eht_set->src_addr,
504
&set_h->h_addr);
505
}
506
507
/* create new set entries from reports */
508
static void __eht_create_set_entries(const struct net_bridge_mcast *brmctx,
509
struct net_bridge_port_group *pg,
510
union net_bridge_eht_addr *h_addr,
511
void *srcs,
512
u32 nsrcs,
513
size_t addr_size,
514
int filter_mode)
515
{
516
union net_bridge_eht_addr eht_src_addr;
517
u32 src_idx;
518
519
memset(&eht_src_addr, 0, sizeof(eht_src_addr));
520
for (src_idx = 0; src_idx < nsrcs; src_idx++) {
521
memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size);
522
br_multicast_create_eht_set_entry(brmctx, pg, &eht_src_addr,
523
h_addr, filter_mode,
524
false);
525
}
526
}
527
528
/* delete existing set entries and their (S,G) entries if they were the last */
529
static bool __eht_del_set_entries(struct net_bridge_port_group *pg,
530
union net_bridge_eht_addr *h_addr,
531
void *srcs,
532
u32 nsrcs,
533
size_t addr_size)
534
{
535
union net_bridge_eht_addr eht_src_addr;
536
struct net_bridge_group_src *src_ent;
537
bool changed = false;
538
struct br_ip src_ip;
539
u32 src_idx;
540
541
memset(&eht_src_addr, 0, sizeof(eht_src_addr));
542
memset(&src_ip, 0, sizeof(src_ip));
543
src_ip.proto = pg->key.addr.proto;
544
for (src_idx = 0; src_idx < nsrcs; src_idx++) {
545
memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size);
546
if (!br_multicast_del_eht_set_entry(pg, &eht_src_addr, h_addr))
547
continue;
548
memcpy(&src_ip, srcs + (src_idx * addr_size), addr_size);
549
src_ent = br_multicast_find_group_src(pg, &src_ip);
550
if (!src_ent)
551
continue;
552
br_multicast_del_group_src(src_ent, true);
553
changed = true;
554
}
555
556
return changed;
557
}
558
559
static bool br_multicast_eht_allow(const struct net_bridge_mcast *brmctx,
560
struct net_bridge_port_group *pg,
561
union net_bridge_eht_addr *h_addr,
562
void *srcs,
563
u32 nsrcs,
564
size_t addr_size)
565
{
566
bool changed = false;
567
568
switch (br_multicast_eht_host_filter_mode(pg, h_addr)) {
569
case MCAST_INCLUDE:
570
__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs,
571
addr_size, MCAST_INCLUDE);
572
break;
573
case MCAST_EXCLUDE:
574
changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs,
575
addr_size);
576
break;
577
}
578
579
return changed;
580
}
581
582
static bool br_multicast_eht_block(const struct net_bridge_mcast *brmctx,
583
struct net_bridge_port_group *pg,
584
union net_bridge_eht_addr *h_addr,
585
void *srcs,
586
u32 nsrcs,
587
size_t addr_size)
588
{
589
bool changed = false;
590
591
switch (br_multicast_eht_host_filter_mode(pg, h_addr)) {
592
case MCAST_INCLUDE:
593
changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs,
594
addr_size);
595
break;
596
case MCAST_EXCLUDE:
597
__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
598
MCAST_EXCLUDE);
599
break;
600
}
601
602
return changed;
603
}
604
605
/* flush_entries is true when changing mode */
606
static bool __eht_inc_exc(const struct net_bridge_mcast *brmctx,
607
struct net_bridge_port_group *pg,
608
union net_bridge_eht_addr *h_addr,
609
void *srcs,
610
u32 nsrcs,
611
size_t addr_size,
612
unsigned char filter_mode,
613
bool to_report)
614
{
615
bool changed = false, flush_entries = to_report;
616
union net_bridge_eht_addr eht_src_addr;
617
618
if (br_multicast_eht_host_filter_mode(pg, h_addr) != filter_mode)
619
flush_entries = true;
620
621
memset(&eht_src_addr, 0, sizeof(eht_src_addr));
622
/* if we're changing mode del host and its entries */
623
if (flush_entries)
624
br_multicast_del_eht_host(pg, h_addr);
625
__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
626
filter_mode);
627
/* we can be missing sets only if we've deleted some entries */
628
if (flush_entries) {
629
struct net_bridge_group_eht_set *eht_set;
630
struct net_bridge_group_src *src_ent;
631
struct hlist_node *tmp;
632
633
hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) {
634
br_multicast_ip_src_to_eht_addr(&src_ent->addr,
635
&eht_src_addr);
636
if (!br_multicast_eht_set_lookup(pg, &eht_src_addr)) {
637
br_multicast_del_group_src(src_ent, true);
638
changed = true;
639
continue;
640
}
641
/* this is an optimization for TO_INCLUDE where we lower
642
* the set's timeout to LMQT to catch timeout hosts:
643
* - host A (timing out): set entries X, Y
644
* - host B: set entry Z (new from current TO_INCLUDE)
645
* sends BLOCK Z after LMQT but host A's EHT
646
* entries still exist (unless lowered to LMQT
647
* so they can timeout with the S,Gs)
648
* => we wait another LMQT, when we can just delete the
649
* group immediately
650
*/
651
if (!(src_ent->flags & BR_SGRP_F_SEND) ||
652
filter_mode != MCAST_INCLUDE ||
653
!to_report)
654
continue;
655
eht_set = br_multicast_eht_set_lookup(pg,
656
&eht_src_addr);
657
if (!eht_set)
658
continue;
659
mod_timer(&eht_set->timer, jiffies + br_multicast_lmqt(brmctx));
660
}
661
}
662
663
return changed;
664
}
665
666
static bool br_multicast_eht_inc(const struct net_bridge_mcast *brmctx,
667
struct net_bridge_port_group *pg,
668
union net_bridge_eht_addr *h_addr,
669
void *srcs,
670
u32 nsrcs,
671
size_t addr_size,
672
bool to_report)
673
{
674
bool changed;
675
676
changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
677
MCAST_INCLUDE, to_report);
678
br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_INCLUDE);
679
680
return changed;
681
}
682
683
static bool br_multicast_eht_exc(const struct net_bridge_mcast *brmctx,
684
struct net_bridge_port_group *pg,
685
union net_bridge_eht_addr *h_addr,
686
void *srcs,
687
u32 nsrcs,
688
size_t addr_size,
689
bool to_report)
690
{
691
bool changed;
692
693
changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
694
MCAST_EXCLUDE, to_report);
695
br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_EXCLUDE);
696
697
return changed;
698
}
699
700
static bool __eht_ip4_handle(const struct net_bridge_mcast *brmctx,
701
struct net_bridge_port_group *pg,
702
union net_bridge_eht_addr *h_addr,
703
void *srcs,
704
u32 nsrcs,
705
int grec_type)
706
{
707
bool changed = false, to_report = false;
708
709
switch (grec_type) {
710
case IGMPV3_ALLOW_NEW_SOURCES:
711
br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
712
sizeof(__be32));
713
break;
714
case IGMPV3_BLOCK_OLD_SOURCES:
715
changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
716
sizeof(__be32));
717
break;
718
case IGMPV3_CHANGE_TO_INCLUDE:
719
to_report = true;
720
fallthrough;
721
case IGMPV3_MODE_IS_INCLUDE:
722
changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
723
sizeof(__be32), to_report);
724
break;
725
case IGMPV3_CHANGE_TO_EXCLUDE:
726
to_report = true;
727
fallthrough;
728
case IGMPV3_MODE_IS_EXCLUDE:
729
changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
730
sizeof(__be32), to_report);
731
break;
732
}
733
734
return changed;
735
}
736
737
#if IS_ENABLED(CONFIG_IPV6)
738
static bool __eht_ip6_handle(const struct net_bridge_mcast *brmctx,
739
struct net_bridge_port_group *pg,
740
union net_bridge_eht_addr *h_addr,
741
void *srcs,
742
u32 nsrcs,
743
int grec_type)
744
{
745
bool changed = false, to_report = false;
746
747
switch (grec_type) {
748
case MLD2_ALLOW_NEW_SOURCES:
749
br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
750
sizeof(struct in6_addr));
751
break;
752
case MLD2_BLOCK_OLD_SOURCES:
753
changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
754
sizeof(struct in6_addr));
755
break;
756
case MLD2_CHANGE_TO_INCLUDE:
757
to_report = true;
758
fallthrough;
759
case MLD2_MODE_IS_INCLUDE:
760
changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
761
sizeof(struct in6_addr),
762
to_report);
763
break;
764
case MLD2_CHANGE_TO_EXCLUDE:
765
to_report = true;
766
fallthrough;
767
case MLD2_MODE_IS_EXCLUDE:
768
changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
769
sizeof(struct in6_addr),
770
to_report);
771
break;
772
}
773
774
return changed;
775
}
776
#endif
777
778
/* true means an entry was deleted */
779
bool br_multicast_eht_handle(const struct net_bridge_mcast *brmctx,
780
struct net_bridge_port_group *pg,
781
void *h_addr,
782
void *srcs,
783
u32 nsrcs,
784
size_t addr_size,
785
int grec_type)
786
{
787
bool eht_enabled = !!(pg->key.port->flags & BR_MULTICAST_FAST_LEAVE);
788
union net_bridge_eht_addr eht_host_addr;
789
bool changed = false;
790
791
if (!eht_enabled)
792
goto out;
793
794
memset(&eht_host_addr, 0, sizeof(eht_host_addr));
795
memcpy(&eht_host_addr, h_addr, addr_size);
796
if (addr_size == sizeof(__be32))
797
changed = __eht_ip4_handle(brmctx, pg, &eht_host_addr, srcs,
798
nsrcs, grec_type);
799
#if IS_ENABLED(CONFIG_IPV6)
800
else
801
changed = __eht_ip6_handle(brmctx, pg, &eht_host_addr, srcs,
802
nsrcs, grec_type);
803
#endif
804
805
out:
806
return changed;
807
}
808
809
int br_multicast_eht_set_hosts_limit(struct net_bridge_port *p,
810
u32 eht_hosts_limit)
811
{
812
struct net_bridge *br = p->br;
813
814
if (!eht_hosts_limit)
815
return -EINVAL;
816
817
spin_lock_bh(&br->multicast_lock);
818
p->multicast_eht_hosts_limit = eht_hosts_limit;
819
spin_unlock_bh(&br->multicast_lock);
820
821
return 0;
822
}
823
824