Commit d5a10222 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by Jakub Kicinski

net: bridge: multicast: mark IGMPv3/MLDv2 fast-leave deletes

Mark groups which were deleted due to fast leave/EHT.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e87e4b5c
...@@ -442,7 +442,8 @@ static void br_multicast_fwd_src_add(struct net_bridge_group_src *src) ...@@ -442,7 +442,8 @@ static void br_multicast_fwd_src_add(struct net_bridge_group_src *src)
br_multicast_sg_add_exclude_ports(star_mp, sg); br_multicast_sg_add_exclude_ports(star_mp, sg);
} }
static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src) static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src,
bool fastleave)
{ {
struct net_bridge_port_group *p, *pg = src->pg; struct net_bridge_port_group *p, *pg = src->pg;
struct net_bridge_port_group __rcu **pp; struct net_bridge_port_group __rcu **pp;
...@@ -467,6 +468,8 @@ static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src) ...@@ -467,6 +468,8 @@ static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src)
(p->flags & MDB_PG_FLAGS_PERMANENT)) (p->flags & MDB_PG_FLAGS_PERMANENT))
break; break;
if (fastleave)
p->flags |= MDB_PG_FLAGS_FAST_LEAVE;
br_multicast_del_pg(mp, p, pp); br_multicast_del_pg(mp, p, pp);
break; break;
} }
...@@ -560,11 +563,12 @@ static void br_multicast_destroy_group_src(struct net_bridge_mcast_gc *gc) ...@@ -560,11 +563,12 @@ static void br_multicast_destroy_group_src(struct net_bridge_mcast_gc *gc)
kfree_rcu(src, rcu); kfree_rcu(src, rcu);
} }
void br_multicast_del_group_src(struct net_bridge_group_src *src) void br_multicast_del_group_src(struct net_bridge_group_src *src,
bool fastleave)
{ {
struct net_bridge *br = src->pg->key.port->br; struct net_bridge *br = src->pg->key.port->br;
br_multicast_fwd_src_remove(src); br_multicast_fwd_src_remove(src, fastleave);
hlist_del_init_rcu(&src->node); hlist_del_init_rcu(&src->node);
src->pg->src_ents--; src->pg->src_ents--;
hlist_add_head(&src->mcast_gc.gc_node, &br->mcast_gc_list); hlist_add_head(&src->mcast_gc.gc_node, &br->mcast_gc_list);
...@@ -596,7 +600,7 @@ void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, ...@@ -596,7 +600,7 @@ void br_multicast_del_pg(struct net_bridge_mdb_entry *mp,
hlist_del_init(&pg->mglist); hlist_del_init(&pg->mglist);
br_multicast_eht_clean_sets(pg); br_multicast_eht_clean_sets(pg);
hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node) hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node)
br_multicast_del_group_src(ent); br_multicast_del_group_src(ent, false);
br_mdb_notify(br->dev, mp, pg, RTM_DELMDB); br_mdb_notify(br->dev, mp, pg, RTM_DELMDB);
if (!br_multicast_is_star_g(&mp->addr)) { if (!br_multicast_is_star_g(&mp->addr)) {
rhashtable_remove_fast(&br->sg_port_tbl, &pg->rhnode, rhashtable_remove_fast(&br->sg_port_tbl, &pg->rhnode,
...@@ -653,7 +657,7 @@ static void br_multicast_port_group_expired(struct timer_list *t) ...@@ -653,7 +657,7 @@ static void br_multicast_port_group_expired(struct timer_list *t)
pg->filter_mode = MCAST_INCLUDE; pg->filter_mode = MCAST_INCLUDE;
hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) { hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) {
if (!timer_pending(&src_ent->timer)) { if (!timer_pending(&src_ent->timer)) {
br_multicast_del_group_src(src_ent); br_multicast_del_group_src(src_ent, false);
changed = true; changed = true;
} }
} }
...@@ -1080,7 +1084,7 @@ static void br_multicast_group_src_expired(struct timer_list *t) ...@@ -1080,7 +1084,7 @@ static void br_multicast_group_src_expired(struct timer_list *t)
pg = src->pg; pg = src->pg;
if (pg->filter_mode == MCAST_INCLUDE) { if (pg->filter_mode == MCAST_INCLUDE) {
br_multicast_del_group_src(src); br_multicast_del_group_src(src, false);
if (!hlist_empty(&pg->src_list)) if (!hlist_empty(&pg->src_list))
goto out; goto out;
br_multicast_find_del_pg(br, pg); br_multicast_find_del_pg(br, pg);
...@@ -1704,7 +1708,7 @@ static int __grp_src_delete_marked(struct net_bridge_port_group *pg) ...@@ -1704,7 +1708,7 @@ static int __grp_src_delete_marked(struct net_bridge_port_group *pg)
hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node) hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node)
if (ent->flags & BR_SGRP_F_DELETE) { if (ent->flags & BR_SGRP_F_DELETE) {
br_multicast_del_group_src(ent); br_multicast_del_group_src(ent, false);
deleted++; deleted++;
} }
...@@ -2053,6 +2057,7 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2053,6 +2057,7 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr,
} }
if (br_multicast_eht_should_del_pg(pg)) { if (br_multicast_eht_should_del_pg(pg)) {
pg->flags |= MDB_PG_FLAGS_FAST_LEAVE;
br_multicast_find_del_pg(pg->key.port->br, pg); br_multicast_find_del_pg(pg->key.port->br, pg);
/* a notification has already been sent and we shouldn't /* a notification has already been sent and we shouldn't
* access pg after the delete so we have to return false * access pg after the delete so we have to return false
...@@ -2273,6 +2278,8 @@ static bool br_multicast_block(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2273,6 +2278,8 @@ static bool br_multicast_block(struct net_bridge_port_group *pg, void *h_addr,
if ((pg->filter_mode == MCAST_INCLUDE && hlist_empty(&pg->src_list)) || if ((pg->filter_mode == MCAST_INCLUDE && hlist_empty(&pg->src_list)) ||
br_multicast_eht_should_del_pg(pg)) { br_multicast_eht_should_del_pg(pg)) {
if (br_multicast_eht_should_del_pg(pg))
pg->flags |= MDB_PG_FLAGS_FAST_LEAVE;
br_multicast_find_del_pg(pg->key.port->br, pg); br_multicast_find_del_pg(pg->key.port->br, pg);
/* a notification has already been sent and we shouldn't /* a notification has already been sent and we shouldn't
* access pg after the delete so we have to return false * access pg after the delete so we have to return false
......
...@@ -537,7 +537,7 @@ static bool __eht_allow_excl(struct net_bridge_port_group *pg, ...@@ -537,7 +537,7 @@ static bool __eht_allow_excl(struct net_bridge_port_group *pg,
src_ent = br_multicast_find_group_src(pg, &src_ip); src_ent = br_multicast_find_group_src(pg, &src_ip);
if (!src_ent) if (!src_ent)
continue; continue;
br_multicast_del_group_src(src_ent); br_multicast_del_group_src(src_ent, true);
changed = true; changed = true;
} }
} }
...@@ -588,7 +588,7 @@ static bool __eht_block_incl(struct net_bridge_port_group *pg, ...@@ -588,7 +588,7 @@ static bool __eht_block_incl(struct net_bridge_port_group *pg,
src_ent = br_multicast_find_group_src(pg, &src_ip); src_ent = br_multicast_find_group_src(pg, &src_ip);
if (!src_ent) if (!src_ent)
continue; continue;
br_multicast_del_group_src(src_ent); br_multicast_del_group_src(src_ent, true);
changed = true; changed = true;
} }
...@@ -625,7 +625,7 @@ static bool __eht_block_excl(struct net_bridge_port_group *pg, ...@@ -625,7 +625,7 @@ static bool __eht_block_excl(struct net_bridge_port_group *pg,
src_ent = br_multicast_find_group_src(pg, &src_ip); src_ent = br_multicast_find_group_src(pg, &src_ip);
if (!src_ent) if (!src_ent)
continue; continue;
br_multicast_del_group_src(src_ent); br_multicast_del_group_src(src_ent, true);
changed = true; changed = true;
} }
} }
...@@ -689,7 +689,7 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg, ...@@ -689,7 +689,7 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg,
br_multicast_ip_src_to_eht_addr(&src_ent->addr, br_multicast_ip_src_to_eht_addr(&src_ent->addr,
&eht_src_addr); &eht_src_addr);
if (!br_multicast_eht_set_lookup(pg, &eht_src_addr)) { if (!br_multicast_eht_set_lookup(pg, &eht_src_addr)) {
br_multicast_del_group_src(src_ent); br_multicast_del_group_src(src_ent, true);
changed = true; changed = true;
continue; continue;
} }
......
...@@ -850,7 +850,8 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, ...@@ -850,7 +850,8 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
struct net_bridge_port_group *sg); struct net_bridge_port_group *sg);
struct net_bridge_group_src * struct net_bridge_group_src *
br_multicast_find_group_src(struct net_bridge_port_group *pg, struct br_ip *ip); br_multicast_find_group_src(struct net_bridge_port_group *pg, struct br_ip *ip);
void br_multicast_del_group_src(struct net_bridge_group_src *src); void br_multicast_del_group_src(struct net_bridge_group_src *src,
bool fastleave);
static inline bool br_group_is_l2(const struct br_ip *group) static inline bool br_group_is_l2(const struct br_ip *group)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment