diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index a01bd280c722..0adcd1524ab2 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -819,6 +819,7 @@ static int br_mdb_add_group_src_fwd(const struct br_mdb_config *cfg, struct br_mdb_config sg_cfg; struct br_ip sg_ip; u8 flags = 0; + int err; sg_ip = cfg->group; sg_ip.src = src_ip->src; @@ -842,7 +843,11 @@ static int br_mdb_add_group_src_fwd(const struct br_mdb_config *cfg, sg_cfg.filter_mode = MCAST_INCLUDE; sg_cfg.rt_protocol = cfg->rt_protocol; sg_cfg.nlflags = cfg->nlflags; - return br_mdb_add_group_sg(&sg_cfg, sgmp, brmctx, flags, extack); + err = br_mdb_add_group_sg(&sg_cfg, sgmp, brmctx, flags, extack); + if (err) + br_multicast_del_group(sgmp); + + return err; } static int br_mdb_add_group_src(const struct br_mdb_config *cfg, @@ -1047,6 +1052,7 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg, struct net_bridge_mcast *brmctx; struct br_ip group = cfg->group; unsigned char flags = 0; + int err; brmctx = __br_mdb_choose_context(br, entry, extack); if (!brmctx) @@ -1073,9 +1079,13 @@ static int br_mdb_add_group(const struct br_mdb_config *cfg, flags |= MDB_PG_FLAGS_PERMANENT; if (br_multicast_is_star_g(&group)) - return br_mdb_add_group_star_g(cfg, mp, brmctx, flags, extack); + err = br_mdb_add_group_star_g(cfg, mp, brmctx, flags, extack); else - return br_mdb_add_group_sg(cfg, mp, brmctx, flags, extack); + err = br_mdb_add_group_sg(cfg, mp, brmctx, flags, extack); + if (err) + br_multicast_del_group(mp); + + return err; } static int __br_mdb_add(const struct br_mdb_config *cfg, diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 3fbad7b59769..ecc74b73a3e1 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -647,6 +647,14 @@ static void br_multicast_del_mdb_entry(struct net_bridge_mdb_entry *mp) queue_work(system_long_wq, &br->mcast_gc_work); } +void br_multicast_del_group(struct net_bridge_mdb_entry *mp) +{ + if (mp->ports || mp->host_joined) + return; + + br_multicast_del_mdb_entry(mp); +} + static void br_multicast_group_expired(struct timer_list *t) { struct net_bridge_mdb_entry *mp = timer_container_of(mp, t, timer); @@ -1554,6 +1562,7 @@ __br_multicast_add_group(struct net_bridge_mcast *brmctx, p = br_multicast_new_port_group(pmctx->port, group, *pp, 0, src, filter_mode, RTPROT_KERNEL, NULL); if (unlikely(!p)) { + br_multicast_del_group(mp); p = ERR_PTR(-ENOMEM); goto out; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b01997ea9508..ff746f036f54 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -998,6 +998,7 @@ struct net_bridge_mdb_entry * br_mdb_ip_get(struct net_bridge *br, struct br_ip *dst); struct net_bridge_mdb_entry * br_multicast_new_group(struct net_bridge *br, struct br_ip *group); +void br_multicast_del_group(struct net_bridge_mdb_entry *mp); struct net_bridge_port_group * br_multicast_new_port_group(struct net_bridge_port *port, const struct br_ip *group,