br_multicast_eht.c (22467B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2// Copyright (c) 2020, Nikolay Aleksandrov <nikolay@nvidia.com> 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 33static 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); 36static 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 43static struct net_bridge_group_eht_host * 44br_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 67static 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 79static struct net_bridge_group_eht_set_entry * 80br_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 103static struct net_bridge_group_eht_set * 104br_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 127static 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 138static 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 del_timer_sync(&set_h->timer); 146 kfree(set_h); 147} 148 149static 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 del_timer_sync(&eht_set->timer); 158 kfree(eht_set); 159} 160 161static 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 179static 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 196void 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 208static void br_multicast_eht_set_entry_expired(struct timer_list *t) 209{ 210 struct net_bridge_group_eht_set_entry *set_h = from_timer(set_h, t, timer); 211 struct net_bridge *br = set_h->br; 212 213 spin_lock(&br->multicast_lock); 214 if (RB_EMPTY_NODE(&set_h->rb_node) || timer_pending(&set_h->timer)) 215 goto out; 216 217 br_multicast_del_eht_set_entry(set_h->eht_set->pg, 218 &set_h->eht_set->src_addr, 219 &set_h->h_addr); 220out: 221 spin_unlock(&br->multicast_lock); 222} 223 224static void br_multicast_eht_set_expired(struct timer_list *t) 225{ 226 struct net_bridge_group_eht_set *eht_set = from_timer(eht_set, t, 227 timer); 228 struct net_bridge *br = eht_set->br; 229 230 spin_lock(&br->multicast_lock); 231 if (RB_EMPTY_NODE(&eht_set->rb_node) || timer_pending(&eht_set->timer)) 232 goto out; 233 234 br_multicast_del_eht_set(eht_set); 235out: 236 spin_unlock(&br->multicast_lock); 237} 238 239static struct net_bridge_group_eht_host * 240__eht_lookup_create_host(struct net_bridge_port_group *pg, 241 union net_bridge_eht_addr *h_addr, 242 unsigned char filter_mode) 243{ 244 struct rb_node **link = &pg->eht_host_tree.rb_node, *parent = NULL; 245 struct net_bridge_group_eht_host *eht_host; 246 247 while (*link) { 248 struct net_bridge_group_eht_host *this; 249 int result; 250 251 this = rb_entry(*link, struct net_bridge_group_eht_host, 252 rb_node); 253 result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr)); 254 parent = *link; 255 if (result < 0) 256 link = &((*link)->rb_left); 257 else if (result > 0) 258 link = &((*link)->rb_right); 259 else 260 return this; 261 } 262 263 if (br_multicast_eht_hosts_over_limit(pg)) 264 return NULL; 265 266 eht_host = kzalloc(sizeof(*eht_host), GFP_ATOMIC); 267 if (!eht_host) 268 return NULL; 269 270 memcpy(&eht_host->h_addr, h_addr, sizeof(*h_addr)); 271 INIT_HLIST_HEAD(&eht_host->set_entries); 272 eht_host->pg = pg; 273 eht_host->filter_mode = filter_mode; 274 275 rb_link_node(&eht_host->rb_node, parent, link); 276 rb_insert_color(&eht_host->rb_node, &pg->eht_host_tree); 277 278 br_multicast_eht_hosts_inc(pg); 279 280 return eht_host; 281} 282 283static struct net_bridge_group_eht_set_entry * 284__eht_lookup_create_set_entry(struct net_bridge *br, 285 struct net_bridge_group_eht_set *eht_set, 286 struct net_bridge_group_eht_host *eht_host, 287 bool allow_zero_src) 288{ 289 struct rb_node **link = &eht_set->entry_tree.rb_node, *parent = NULL; 290 struct net_bridge_group_eht_set_entry *set_h; 291 292 while (*link) { 293 struct net_bridge_group_eht_set_entry *this; 294 int result; 295 296 this = rb_entry(*link, struct net_bridge_group_eht_set_entry, 297 rb_node); 298 result = memcmp(&eht_host->h_addr, &this->h_addr, 299 sizeof(union net_bridge_eht_addr)); 300 parent = *link; 301 if (result < 0) 302 link = &((*link)->rb_left); 303 else if (result > 0) 304 link = &((*link)->rb_right); 305 else 306 return this; 307 } 308 309 /* always allow auto-created zero entry */ 310 if (!allow_zero_src && eht_host->num_entries >= PG_SRC_ENT_LIMIT) 311 return NULL; 312 313 set_h = kzalloc(sizeof(*set_h), GFP_ATOMIC); 314 if (!set_h) 315 return NULL; 316 317 memcpy(&set_h->h_addr, &eht_host->h_addr, 318 sizeof(union net_bridge_eht_addr)); 319 set_h->mcast_gc.destroy = br_multicast_destroy_eht_set_entry; 320 set_h->eht_set = eht_set; 321 set_h->h_parent = eht_host; 322 set_h->br = br; 323 timer_setup(&set_h->timer, br_multicast_eht_set_entry_expired, 0); 324 325 hlist_add_head(&set_h->host_list, &eht_host->set_entries); 326 rb_link_node(&set_h->rb_node, parent, link); 327 rb_insert_color(&set_h->rb_node, &eht_set->entry_tree); 328 /* we must not count the auto-created zero entry otherwise we won't be 329 * able to track the full list of PG_SRC_ENT_LIMIT entries 330 */ 331 if (!allow_zero_src) 332 eht_host->num_entries++; 333 334 return set_h; 335} 336 337static struct net_bridge_group_eht_set * 338__eht_lookup_create_set(struct net_bridge_port_group *pg, 339 union net_bridge_eht_addr *src_addr) 340{ 341 struct rb_node **link = &pg->eht_set_tree.rb_node, *parent = NULL; 342 struct net_bridge_group_eht_set *eht_set; 343 344 while (*link) { 345 struct net_bridge_group_eht_set *this; 346 int result; 347 348 this = rb_entry(*link, struct net_bridge_group_eht_set, 349 rb_node); 350 result = memcmp(src_addr, &this->src_addr, sizeof(*src_addr)); 351 parent = *link; 352 if (result < 0) 353 link = &((*link)->rb_left); 354 else if (result > 0) 355 link = &((*link)->rb_right); 356 else 357 return this; 358 } 359 360 eht_set = kzalloc(sizeof(*eht_set), GFP_ATOMIC); 361 if (!eht_set) 362 return NULL; 363 364 memcpy(&eht_set->src_addr, src_addr, sizeof(*src_addr)); 365 eht_set->mcast_gc.destroy = br_multicast_destroy_eht_set; 366 eht_set->pg = pg; 367 eht_set->br = pg->key.port->br; 368 eht_set->entry_tree = RB_ROOT; 369 timer_setup(&eht_set->timer, br_multicast_eht_set_expired, 0); 370 371 rb_link_node(&eht_set->rb_node, parent, link); 372 rb_insert_color(&eht_set->rb_node, &pg->eht_set_tree); 373 374 return eht_set; 375} 376 377static void br_multicast_ip_src_to_eht_addr(const struct br_ip *src, 378 union net_bridge_eht_addr *dest) 379{ 380 switch (src->proto) { 381 case htons(ETH_P_IP): 382 dest->ip4 = src->src.ip4; 383 break; 384#if IS_ENABLED(CONFIG_IPV6) 385 case htons(ETH_P_IPV6): 386 memcpy(&dest->ip6, &src->src.ip6, sizeof(struct in6_addr)); 387 break; 388#endif 389 } 390} 391 392static void br_eht_convert_host_filter_mode(const struct net_bridge_mcast *brmctx, 393 struct net_bridge_port_group *pg, 394 union net_bridge_eht_addr *h_addr, 395 int filter_mode) 396{ 397 struct net_bridge_group_eht_host *eht_host; 398 union net_bridge_eht_addr zero_addr; 399 400 eht_host = br_multicast_eht_host_lookup(pg, h_addr); 401 if (eht_host) 402 eht_host->filter_mode = filter_mode; 403 404 memset(&zero_addr, 0, sizeof(zero_addr)); 405 switch (filter_mode) { 406 case MCAST_INCLUDE: 407 br_multicast_del_eht_set_entry(pg, &zero_addr, h_addr); 408 break; 409 case MCAST_EXCLUDE: 410 br_multicast_create_eht_set_entry(brmctx, pg, &zero_addr, 411 h_addr, MCAST_EXCLUDE, 412 true); 413 break; 414 } 415} 416 417static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx, 418 struct net_bridge_port_group *pg, 419 union net_bridge_eht_addr *src_addr, 420 union net_bridge_eht_addr *h_addr, 421 int filter_mode, 422 bool allow_zero_src) 423{ 424 struct net_bridge_group_eht_set_entry *set_h; 425 struct net_bridge_group_eht_host *eht_host; 426 struct net_bridge *br = pg->key.port->br; 427 struct net_bridge_group_eht_set *eht_set; 428 union net_bridge_eht_addr zero_addr; 429 430 memset(&zero_addr, 0, sizeof(zero_addr)); 431 if (!allow_zero_src && !memcmp(src_addr, &zero_addr, sizeof(zero_addr))) 432 return; 433 434 eht_set = __eht_lookup_create_set(pg, src_addr); 435 if (!eht_set) 436 return; 437 438 eht_host = __eht_lookup_create_host(pg, h_addr, filter_mode); 439 if (!eht_host) 440 goto fail_host; 441 442 set_h = __eht_lookup_create_set_entry(br, eht_set, eht_host, 443 allow_zero_src); 444 if (!set_h) 445 goto fail_set_entry; 446 447 mod_timer(&set_h->timer, jiffies + br_multicast_gmi(brmctx)); 448 mod_timer(&eht_set->timer, jiffies + br_multicast_gmi(brmctx)); 449 450 return; 451 452fail_set_entry: 453 if (hlist_empty(&eht_host->set_entries)) 454 __eht_destroy_host(eht_host); 455fail_host: 456 if (RB_EMPTY_ROOT(&eht_set->entry_tree)) 457 br_multicast_del_eht_set(eht_set); 458} 459 460static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg, 461 union net_bridge_eht_addr *src_addr, 462 union net_bridge_eht_addr *h_addr) 463{ 464 struct net_bridge_group_eht_set_entry *set_h; 465 struct net_bridge_group_eht_set *eht_set; 466 bool set_deleted = false; 467 468 eht_set = br_multicast_eht_set_lookup(pg, src_addr); 469 if (!eht_set) 470 goto out; 471 472 set_h = br_multicast_eht_set_entry_lookup(eht_set, h_addr); 473 if (!set_h) 474 goto out; 475 476 __eht_del_set_entry(set_h); 477 478 if (RB_EMPTY_ROOT(&eht_set->entry_tree)) { 479 br_multicast_del_eht_set(eht_set); 480 set_deleted = true; 481 } 482 483out: 484 return set_deleted; 485} 486 487static void br_multicast_del_eht_host(struct net_bridge_port_group *pg, 488 union net_bridge_eht_addr *h_addr) 489{ 490 struct net_bridge_group_eht_set_entry *set_h; 491 struct net_bridge_group_eht_host *eht_host; 492 struct hlist_node *tmp; 493 494 eht_host = br_multicast_eht_host_lookup(pg, h_addr); 495 if (!eht_host) 496 return; 497 498 hlist_for_each_entry_safe(set_h, tmp, &eht_host->set_entries, host_list) 499 br_multicast_del_eht_set_entry(set_h->eht_set->pg, 500 &set_h->eht_set->src_addr, 501 &set_h->h_addr); 502} 503 504/* create new set entries from reports */ 505static void __eht_create_set_entries(const struct net_bridge_mcast *brmctx, 506 struct net_bridge_port_group *pg, 507 union net_bridge_eht_addr *h_addr, 508 void *srcs, 509 u32 nsrcs, 510 size_t addr_size, 511 int filter_mode) 512{ 513 union net_bridge_eht_addr eht_src_addr; 514 u32 src_idx; 515 516 memset(&eht_src_addr, 0, sizeof(eht_src_addr)); 517 for (src_idx = 0; src_idx < nsrcs; src_idx++) { 518 memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size); 519 br_multicast_create_eht_set_entry(brmctx, pg, &eht_src_addr, 520 h_addr, filter_mode, 521 false); 522 } 523} 524 525/* delete existing set entries and their (S,G) entries if they were the last */ 526static bool __eht_del_set_entries(struct net_bridge_port_group *pg, 527 union net_bridge_eht_addr *h_addr, 528 void *srcs, 529 u32 nsrcs, 530 size_t addr_size) 531{ 532 union net_bridge_eht_addr eht_src_addr; 533 struct net_bridge_group_src *src_ent; 534 bool changed = false; 535 struct br_ip src_ip; 536 u32 src_idx; 537 538 memset(&eht_src_addr, 0, sizeof(eht_src_addr)); 539 memset(&src_ip, 0, sizeof(src_ip)); 540 src_ip.proto = pg->key.addr.proto; 541 for (src_idx = 0; src_idx < nsrcs; src_idx++) { 542 memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size); 543 if (!br_multicast_del_eht_set_entry(pg, &eht_src_addr, h_addr)) 544 continue; 545 memcpy(&src_ip, srcs + (src_idx * addr_size), addr_size); 546 src_ent = br_multicast_find_group_src(pg, &src_ip); 547 if (!src_ent) 548 continue; 549 br_multicast_del_group_src(src_ent, true); 550 changed = true; 551 } 552 553 return changed; 554} 555 556static bool br_multicast_eht_allow(const struct net_bridge_mcast *brmctx, 557 struct net_bridge_port_group *pg, 558 union net_bridge_eht_addr *h_addr, 559 void *srcs, 560 u32 nsrcs, 561 size_t addr_size) 562{ 563 bool changed = false; 564 565 switch (br_multicast_eht_host_filter_mode(pg, h_addr)) { 566 case MCAST_INCLUDE: 567 __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, 568 addr_size, MCAST_INCLUDE); 569 break; 570 case MCAST_EXCLUDE: 571 changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs, 572 addr_size); 573 break; 574 } 575 576 return changed; 577} 578 579static bool br_multicast_eht_block(const struct net_bridge_mcast *brmctx, 580 struct net_bridge_port_group *pg, 581 union net_bridge_eht_addr *h_addr, 582 void *srcs, 583 u32 nsrcs, 584 size_t addr_size) 585{ 586 bool changed = false; 587 588 switch (br_multicast_eht_host_filter_mode(pg, h_addr)) { 589 case MCAST_INCLUDE: 590 changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs, 591 addr_size); 592 break; 593 case MCAST_EXCLUDE: 594 __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size, 595 MCAST_EXCLUDE); 596 break; 597 } 598 599 return changed; 600} 601 602/* flush_entries is true when changing mode */ 603static bool __eht_inc_exc(const struct net_bridge_mcast *brmctx, 604 struct net_bridge_port_group *pg, 605 union net_bridge_eht_addr *h_addr, 606 void *srcs, 607 u32 nsrcs, 608 size_t addr_size, 609 unsigned char filter_mode, 610 bool to_report) 611{ 612 bool changed = false, flush_entries = to_report; 613 union net_bridge_eht_addr eht_src_addr; 614 615 if (br_multicast_eht_host_filter_mode(pg, h_addr) != filter_mode) 616 flush_entries = true; 617 618 memset(&eht_src_addr, 0, sizeof(eht_src_addr)); 619 /* if we're changing mode del host and its entries */ 620 if (flush_entries) 621 br_multicast_del_eht_host(pg, h_addr); 622 __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size, 623 filter_mode); 624 /* we can be missing sets only if we've deleted some entries */ 625 if (flush_entries) { 626 struct net_bridge_group_eht_set *eht_set; 627 struct net_bridge_group_src *src_ent; 628 struct hlist_node *tmp; 629 630 hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) { 631 br_multicast_ip_src_to_eht_addr(&src_ent->addr, 632 &eht_src_addr); 633 if (!br_multicast_eht_set_lookup(pg, &eht_src_addr)) { 634 br_multicast_del_group_src(src_ent, true); 635 changed = true; 636 continue; 637 } 638 /* this is an optimization for TO_INCLUDE where we lower 639 * the set's timeout to LMQT to catch timeout hosts: 640 * - host A (timing out): set entries X, Y 641 * - host B: set entry Z (new from current TO_INCLUDE) 642 * sends BLOCK Z after LMQT but host A's EHT 643 * entries still exist (unless lowered to LMQT 644 * so they can timeout with the S,Gs) 645 * => we wait another LMQT, when we can just delete the 646 * group immediately 647 */ 648 if (!(src_ent->flags & BR_SGRP_F_SEND) || 649 filter_mode != MCAST_INCLUDE || 650 !to_report) 651 continue; 652 eht_set = br_multicast_eht_set_lookup(pg, 653 &eht_src_addr); 654 if (!eht_set) 655 continue; 656 mod_timer(&eht_set->timer, jiffies + br_multicast_lmqt(brmctx)); 657 } 658 } 659 660 return changed; 661} 662 663static bool br_multicast_eht_inc(const struct net_bridge_mcast *brmctx, 664 struct net_bridge_port_group *pg, 665 union net_bridge_eht_addr *h_addr, 666 void *srcs, 667 u32 nsrcs, 668 size_t addr_size, 669 bool to_report) 670{ 671 bool changed; 672 673 changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size, 674 MCAST_INCLUDE, to_report); 675 br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_INCLUDE); 676 677 return changed; 678} 679 680static bool br_multicast_eht_exc(const struct net_bridge_mcast *brmctx, 681 struct net_bridge_port_group *pg, 682 union net_bridge_eht_addr *h_addr, 683 void *srcs, 684 u32 nsrcs, 685 size_t addr_size, 686 bool to_report) 687{ 688 bool changed; 689 690 changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size, 691 MCAST_EXCLUDE, to_report); 692 br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_EXCLUDE); 693 694 return changed; 695} 696 697static bool __eht_ip4_handle(const struct net_bridge_mcast *brmctx, 698 struct net_bridge_port_group *pg, 699 union net_bridge_eht_addr *h_addr, 700 void *srcs, 701 u32 nsrcs, 702 int grec_type) 703{ 704 bool changed = false, to_report = false; 705 706 switch (grec_type) { 707 case IGMPV3_ALLOW_NEW_SOURCES: 708 br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs, 709 sizeof(__be32)); 710 break; 711 case IGMPV3_BLOCK_OLD_SOURCES: 712 changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs, 713 sizeof(__be32)); 714 break; 715 case IGMPV3_CHANGE_TO_INCLUDE: 716 to_report = true; 717 fallthrough; 718 case IGMPV3_MODE_IS_INCLUDE: 719 changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs, 720 sizeof(__be32), to_report); 721 break; 722 case IGMPV3_CHANGE_TO_EXCLUDE: 723 to_report = true; 724 fallthrough; 725 case IGMPV3_MODE_IS_EXCLUDE: 726 changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs, 727 sizeof(__be32), to_report); 728 break; 729 } 730 731 return changed; 732} 733 734#if IS_ENABLED(CONFIG_IPV6) 735static bool __eht_ip6_handle(const struct net_bridge_mcast *brmctx, 736 struct net_bridge_port_group *pg, 737 union net_bridge_eht_addr *h_addr, 738 void *srcs, 739 u32 nsrcs, 740 int grec_type) 741{ 742 bool changed = false, to_report = false; 743 744 switch (grec_type) { 745 case MLD2_ALLOW_NEW_SOURCES: 746 br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs, 747 sizeof(struct in6_addr)); 748 break; 749 case MLD2_BLOCK_OLD_SOURCES: 750 changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs, 751 sizeof(struct in6_addr)); 752 break; 753 case MLD2_CHANGE_TO_INCLUDE: 754 to_report = true; 755 fallthrough; 756 case MLD2_MODE_IS_INCLUDE: 757 changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs, 758 sizeof(struct in6_addr), 759 to_report); 760 break; 761 case MLD2_CHANGE_TO_EXCLUDE: 762 to_report = true; 763 fallthrough; 764 case MLD2_MODE_IS_EXCLUDE: 765 changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs, 766 sizeof(struct in6_addr), 767 to_report); 768 break; 769 } 770 771 return changed; 772} 773#endif 774 775/* true means an entry was deleted */ 776bool br_multicast_eht_handle(const struct net_bridge_mcast *brmctx, 777 struct net_bridge_port_group *pg, 778 void *h_addr, 779 void *srcs, 780 u32 nsrcs, 781 size_t addr_size, 782 int grec_type) 783{ 784 bool eht_enabled = !!(pg->key.port->flags & BR_MULTICAST_FAST_LEAVE); 785 union net_bridge_eht_addr eht_host_addr; 786 bool changed = false; 787 788 if (!eht_enabled) 789 goto out; 790 791 memset(&eht_host_addr, 0, sizeof(eht_host_addr)); 792 memcpy(&eht_host_addr, h_addr, addr_size); 793 if (addr_size == sizeof(__be32)) 794 changed = __eht_ip4_handle(brmctx, pg, &eht_host_addr, srcs, 795 nsrcs, grec_type); 796#if IS_ENABLED(CONFIG_IPV6) 797 else 798 changed = __eht_ip6_handle(brmctx, pg, &eht_host_addr, srcs, 799 nsrcs, grec_type); 800#endif 801 802out: 803 return changed; 804} 805 806int br_multicast_eht_set_hosts_limit(struct net_bridge_port *p, 807 u32 eht_hosts_limit) 808{ 809 struct net_bridge *br = p->br; 810 811 if (!eht_hosts_limit) 812 return -EINVAL; 813 814 spin_lock_bh(&br->multicast_lock); 815 p->multicast_eht_hosts_limit = eht_hosts_limit; 816 spin_unlock_bh(&br->multicast_lock); 817 818 return 0; 819}