Skip to content

Commit b1c8fec

Browse files
idoschkuba-moo
authored andcommitted
bridge: mcast: Add support for (*, G) with a source list and filter mode
In preparation for allowing user space to add (*, G) entries with a source list and associated filter mode, add the necessary plumbing to handle such requests. Extend the MDB configuration structure with a currently empty source array and filter mode that is currently hard coded to EXCLUDE. Add the source entries and the corresponding (S, G) entries before making the new (*, G) port group entry visible to the data path. Handle the creation of each source entry in a similar fashion to how it is created from the data path in response to received Membership Reports: Create the source entry, arm the source timer (if needed), add a corresponding (S, G) forwarding entry and finally mark the source entry as installed (by user space). Add the (S, G) entry by populating an MDB configuration structure and calling br_mdb_add_group_sg() as if a new entry is created by user space, with the sole difference that the 'src_entry' field is set to make sure that the group timer of such entries is never armed. Note that it is not currently possible to add more than 32 source entries to a port group entry. If this proves to be a problem we can either increase 'PG_SRC_ENT_LIMIT' or avoid forcing a limit on entries created by user space. Signed-off-by: Ido Schimmel <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 079afd6 commit b1c8fec

File tree

2 files changed

+132
-3
lines changed

2 files changed

+132
-3
lines changed

net/bridge/br_mdb.c

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,114 @@ static int br_mdb_add_group_sg(const struct br_mdb_config *cfg,
836836
return 0;
837837
}
838838

839+
static int br_mdb_add_group_src_fwd(const struct br_mdb_config *cfg,
840+
struct br_ip *src_ip,
841+
struct net_bridge_mcast *brmctx,
842+
struct netlink_ext_ack *extack)
843+
{
844+
struct net_bridge_mdb_entry *sgmp;
845+
struct br_mdb_config sg_cfg;
846+
struct br_ip sg_ip;
847+
u8 flags = 0;
848+
849+
sg_ip = cfg->group;
850+
sg_ip.src = src_ip->src;
851+
sgmp = br_multicast_new_group(cfg->br, &sg_ip);
852+
if (IS_ERR(sgmp)) {
853+
NL_SET_ERR_MSG_MOD(extack, "Failed to add (S, G) MDB entry");
854+
return PTR_ERR(sgmp);
855+
}
856+
857+
if (cfg->entry->state == MDB_PERMANENT)
858+
flags |= MDB_PG_FLAGS_PERMANENT;
859+
if (cfg->filter_mode == MCAST_EXCLUDE)
860+
flags |= MDB_PG_FLAGS_BLOCKED;
861+
862+
memset(&sg_cfg, 0, sizeof(sg_cfg));
863+
sg_cfg.br = cfg->br;
864+
sg_cfg.p = cfg->p;
865+
sg_cfg.entry = cfg->entry;
866+
sg_cfg.group = sg_ip;
867+
sg_cfg.src_entry = true;
868+
sg_cfg.filter_mode = MCAST_INCLUDE;
869+
return br_mdb_add_group_sg(&sg_cfg, sgmp, brmctx, flags, extack);
870+
}
871+
872+
static int br_mdb_add_group_src(const struct br_mdb_config *cfg,
873+
struct net_bridge_port_group *pg,
874+
struct net_bridge_mcast *brmctx,
875+
struct br_mdb_src_entry *src,
876+
struct netlink_ext_ack *extack)
877+
{
878+
struct net_bridge_group_src *ent;
879+
unsigned long now = jiffies;
880+
int err;
881+
882+
ent = br_multicast_find_group_src(pg, &src->addr);
883+
if (!ent) {
884+
ent = br_multicast_new_group_src(pg, &src->addr);
885+
if (!ent) {
886+
NL_SET_ERR_MSG_MOD(extack, "Failed to add new source entry");
887+
return -ENOSPC;
888+
}
889+
} else {
890+
NL_SET_ERR_MSG_MOD(extack, "Source entry already exists");
891+
return -EEXIST;
892+
}
893+
894+
if (cfg->filter_mode == MCAST_INCLUDE &&
895+
cfg->entry->state == MDB_TEMPORARY)
896+
mod_timer(&ent->timer, now + br_multicast_gmi(brmctx));
897+
else
898+
del_timer(&ent->timer);
899+
900+
/* Install a (S, G) forwarding entry for the source. */
901+
err = br_mdb_add_group_src_fwd(cfg, &src->addr, brmctx, extack);
902+
if (err)
903+
goto err_del_sg;
904+
905+
ent->flags = BR_SGRP_F_INSTALLED | BR_SGRP_F_USER_ADDED;
906+
907+
return 0;
908+
909+
err_del_sg:
910+
__br_multicast_del_group_src(ent);
911+
return err;
912+
}
913+
914+
static void br_mdb_del_group_src(struct net_bridge_port_group *pg,
915+
struct br_mdb_src_entry *src)
916+
{
917+
struct net_bridge_group_src *ent;
918+
919+
ent = br_multicast_find_group_src(pg, &src->addr);
920+
if (WARN_ON_ONCE(!ent))
921+
return;
922+
br_multicast_del_group_src(ent, false);
923+
}
924+
925+
static int br_mdb_add_group_srcs(const struct br_mdb_config *cfg,
926+
struct net_bridge_port_group *pg,
927+
struct net_bridge_mcast *brmctx,
928+
struct netlink_ext_ack *extack)
929+
{
930+
int i, err;
931+
932+
for (i = 0; i < cfg->num_src_entries; i++) {
933+
err = br_mdb_add_group_src(cfg, pg, brmctx,
934+
&cfg->src_entries[i], extack);
935+
if (err)
936+
goto err_del_group_srcs;
937+
}
938+
939+
return 0;
940+
941+
err_del_group_srcs:
942+
for (i--; i >= 0; i--)
943+
br_mdb_del_group_src(pg, &cfg->src_entries[i]);
944+
return err;
945+
}
946+
839947
static int br_mdb_add_group_star_g(const struct br_mdb_config *cfg,
840948
struct net_bridge_mdb_entry *mp,
841949
struct net_bridge_mcast *brmctx,
@@ -845,6 +953,7 @@ static int br_mdb_add_group_star_g(const struct br_mdb_config *cfg,
845953
struct net_bridge_port_group __rcu **pp;
846954
struct net_bridge_port_group *p;
847955
unsigned long now = jiffies;
956+
int err;
848957

849958
for (pp = &mp->ports;
850959
(p = mlock_dereference(*pp, cfg->br)) != NULL;
@@ -858,23 +967,35 @@ static int br_mdb_add_group_star_g(const struct br_mdb_config *cfg,
858967
}
859968

860969
p = br_multicast_new_port_group(cfg->p, &cfg->group, *pp, flags, NULL,
861-
MCAST_EXCLUDE, RTPROT_STATIC);
970+
cfg->filter_mode, RTPROT_STATIC);
862971
if (unlikely(!p)) {
863972
NL_SET_ERR_MSG_MOD(extack, "Couldn't allocate new (*, G) port group");
864973
return -ENOMEM;
865974
}
975+
976+
err = br_mdb_add_group_srcs(cfg, p, brmctx, extack);
977+
if (err)
978+
goto err_del_port_group;
979+
866980
rcu_assign_pointer(*pp, p);
867-
if (!(flags & MDB_PG_FLAGS_PERMANENT))
981+
if (!(flags & MDB_PG_FLAGS_PERMANENT) &&
982+
cfg->filter_mode == MCAST_EXCLUDE)
868983
mod_timer(&p->timer,
869984
now + brmctx->multicast_membership_interval);
870985
br_mdb_notify(cfg->br->dev, mp, p, RTM_NEWMDB);
871986
/* If we are adding a new EXCLUDE port group (*, G), it needs to be
872987
* also added to all (S, G) entries for proper replication.
873988
*/
874-
if (br_multicast_should_handle_mode(brmctx, cfg->group.proto))
989+
if (br_multicast_should_handle_mode(brmctx, cfg->group.proto) &&
990+
cfg->filter_mode == MCAST_EXCLUDE)
875991
br_multicast_star_g_handle_mode(p, MCAST_EXCLUDE);
876992

877993
return 0;
994+
995+
err_del_port_group:
996+
hlist_del_init(&p->mglist);
997+
kfree(p);
998+
return err;
878999
}
8791000

8801001
static int br_mdb_add_group(const struct br_mdb_config *cfg,
@@ -967,6 +1088,7 @@ static int br_mdb_config_init(struct net *net, const struct nlmsghdr *nlh,
9671088
return err;
9681089

9691090
memset(cfg, 0, sizeof(*cfg));
1091+
cfg->filter_mode = MCAST_EXCLUDE;
9701092

9711093
bpm = nlmsg_data(nlh);
9721094
if (!bpm->ifindex) {

net/bridge/br_private.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,19 @@ struct bridge_mcast_stats {
9393
struct u64_stats_sync syncp;
9494
};
9595

96+
struct br_mdb_src_entry {
97+
struct br_ip addr;
98+
};
99+
96100
struct br_mdb_config {
97101
struct net_bridge *br;
98102
struct net_bridge_port *p;
99103
struct br_mdb_entry *entry;
100104
struct br_ip group;
101105
bool src_entry;
106+
u8 filter_mode;
107+
struct br_mdb_src_entry *src_entries;
108+
int num_src_entries;
102109
};
103110
#endif
104111

0 commit comments

Comments
 (0)