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(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}
 820