mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
net: bridge: mcast: support for IGMPV3/MLDv2 MODE_IS_INCLUDE/EXCLUDE report
In order to process IGMPV3/MLDv2_MODE_IS_INCLUDE/EXCLUDE report types we need some new helpers which allow us to set/clear flags for all current entries and later delete marked entries after the report sources have been processed. v3: add IPv6/MLDv2 support v2: drop flag helpers and directly do flag bit operations Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
0436862e41
commit
e6231bca6a
@ -1229,6 +1229,21 @@ void br_multicast_disable_port(struct net_bridge_port *port)
|
||||
spin_unlock(&br->multicast_lock);
|
||||
}
|
||||
|
||||
static int __grp_src_delete_marked(struct net_bridge_port_group *pg)
|
||||
{
|
||||
struct net_bridge_group_src *ent;
|
||||
struct hlist_node *tmp;
|
||||
int deleted = 0;
|
||||
|
||||
hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node)
|
||||
if (ent->flags & BR_SGRP_F_DELETE) {
|
||||
br_multicast_del_group_src(ent);
|
||||
deleted++;
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/* State Msg type New state Actions
|
||||
* INCLUDE (A) IS_IN (B) INCLUDE (A+B) (B)=GMI
|
||||
* INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI
|
||||
@ -1263,6 +1278,101 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg,
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* State Msg type New state Actions
|
||||
* INCLUDE (A) IS_EX (B) EXCLUDE (A*B,B-A) (B-A)=0
|
||||
* Delete (A-B)
|
||||
* Group Timer=GMI
|
||||
*/
|
||||
static void __grp_src_isexc_incl(struct net_bridge_port_group *pg,
|
||||
void *srcs, u32 nsrcs, size_t src_size)
|
||||
{
|
||||
struct net_bridge_group_src *ent;
|
||||
struct br_ip src_ip;
|
||||
u32 src_idx;
|
||||
|
||||
hlist_for_each_entry(ent, &pg->src_list, node)
|
||||
ent->flags |= BR_SGRP_F_DELETE;
|
||||
|
||||
memset(&src_ip, 0, sizeof(src_ip));
|
||||
src_ip.proto = pg->addr.proto;
|
||||
for (src_idx = 0; src_idx < nsrcs; src_idx++) {
|
||||
memcpy(&src_ip.u, srcs, src_size);
|
||||
ent = br_multicast_find_group_src(pg, &src_ip);
|
||||
if (ent)
|
||||
ent->flags &= ~BR_SGRP_F_DELETE;
|
||||
else
|
||||
br_multicast_new_group_src(pg, &src_ip);
|
||||
srcs += src_size;
|
||||
}
|
||||
|
||||
__grp_src_delete_marked(pg);
|
||||
}
|
||||
|
||||
/* State Msg type New state Actions
|
||||
* EXCLUDE (X,Y) IS_EX (A) EXCLUDE (A-Y,Y*A) (A-X-Y)=GMI
|
||||
* Delete (X-A)
|
||||
* Delete (Y-A)
|
||||
* Group Timer=GMI
|
||||
*/
|
||||
static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg,
|
||||
void *srcs, u32 nsrcs, size_t src_size)
|
||||
{
|
||||
struct net_bridge *br = pg->port->br;
|
||||
struct net_bridge_group_src *ent;
|
||||
unsigned long now = jiffies;
|
||||
bool changed = false;
|
||||
struct br_ip src_ip;
|
||||
u32 src_idx;
|
||||
|
||||
hlist_for_each_entry(ent, &pg->src_list, node)
|
||||
ent->flags |= BR_SGRP_F_DELETE;
|
||||
|
||||
memset(&src_ip, 0, sizeof(src_ip));
|
||||
src_ip.proto = pg->addr.proto;
|
||||
for (src_idx = 0; src_idx < nsrcs; src_idx++) {
|
||||
memcpy(&src_ip.u, srcs, src_size);
|
||||
ent = br_multicast_find_group_src(pg, &src_ip);
|
||||
if (ent) {
|
||||
ent->flags &= ~BR_SGRP_F_DELETE;
|
||||
} else {
|
||||
ent = br_multicast_new_group_src(pg, &src_ip);
|
||||
if (ent) {
|
||||
mod_timer(&ent->timer,
|
||||
now + br_multicast_gmi(br));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
srcs += src_size;
|
||||
}
|
||||
|
||||
if (__grp_src_delete_marked(pg))
|
||||
changed = true;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool br_multicast_isexc(struct net_bridge_port_group *pg,
|
||||
void *srcs, u32 nsrcs, size_t src_size)
|
||||
{
|
||||
struct net_bridge *br = pg->port->br;
|
||||
bool changed = false;
|
||||
|
||||
switch (pg->filter_mode) {
|
||||
case MCAST_INCLUDE:
|
||||
__grp_src_isexc_incl(pg, srcs, nsrcs, src_size);
|
||||
changed = true;
|
||||
break;
|
||||
case MCAST_EXCLUDE:
|
||||
changed = __grp_src_isexc_excl(pg, srcs, nsrcs, src_size);
|
||||
break;
|
||||
}
|
||||
|
||||
pg->filter_mode = MCAST_EXCLUDE;
|
||||
mod_timer(&pg->timer, jiffies + br_multicast_gmi(br));
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static struct net_bridge_port_group *
|
||||
br_multicast_find_port(struct net_bridge_mdb_entry *mp,
|
||||
struct net_bridge_port *p,
|
||||
@ -1360,6 +1470,14 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
|
||||
changed = br_multicast_isinc_allow(pg, grec->grec_src,
|
||||
nsrcs, sizeof(__be32));
|
||||
break;
|
||||
case IGMPV3_MODE_IS_INCLUDE:
|
||||
changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs,
|
||||
sizeof(__be32));
|
||||
break;
|
||||
case IGMPV3_MODE_IS_EXCLUDE:
|
||||
changed = br_multicast_isexc(pg, grec->grec_src, nsrcs,
|
||||
sizeof(__be32));
|
||||
break;
|
||||
}
|
||||
if (changed)
|
||||
br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
|
||||
@ -1466,6 +1584,14 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
|
||||
nsrcs,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
case MLD2_MODE_IS_INCLUDE:
|
||||
changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
case MLD2_MODE_IS_EXCLUDE:
|
||||
changed = br_multicast_isexc(pg, grec->grec_src, nsrcs,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
}
|
||||
if (changed)
|
||||
br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
|
||||
|
Loading…
Reference in New Issue
Block a user