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