net: bridge: multicast: add EHT allow/block handling

Add support for IGMPv3/MLDv2 allow/block EHT handling. Similar to how
the reports are processed we have 2 cases when the group is in include
or exclude mode, these are processed as follows:
 - group include
  - allow: create missing entries
  - block: remove existing matching entries and remove the corresponding
    S,G entries if there are no more set host entries, then possibly
    delete the whole group if there are no more S,G entries

 - group exclude
  - allow
    - host include: create missing entries
    - host exclude: remove existing matching entries and remove the
      corresponding S,G entries if there are no more set host entries
  - block
    - host include: remove existing matching entries and remove the
      corresponding S,G entries if there are no more set host entries,
      then possibly delete the whole group if there are no more S,G entries
    - host exclude: create missing entries

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Nikolay Aleksandrov
2021-01-20 16:51:58 +02:00
committed by Jakub Kicinski
parent dba6b0a5ca
commit 474ddb37fa
4 changed files with 290 additions and 14 deletions

View File

@@ -560,7 +560,7 @@ static void br_multicast_destroy_group_src(struct net_bridge_mcast_gc *gc)
kfree_rcu(src, rcu);
}
static void br_multicast_del_group_src(struct net_bridge_group_src *src)
void br_multicast_del_group_src(struct net_bridge_group_src *src)
{
struct net_bridge *br = src->pg->key.port->br;
@@ -1092,7 +1092,7 @@ out:
spin_unlock(&br->multicast_lock);
}
static 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)
{
struct net_bridge_group_src *ent;
@@ -1804,7 +1804,8 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg)
* EXCLUDE (X,Y) ALLOW (A) EXCLUDE (X+A,Y-A) (A)=GMI
*/
static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size)
void *srcs, u32 nsrcs, size_t addr_size,
int grec_type)
{
struct net_bridge *br = pg->key.port->br;
struct net_bridge_group_src *ent;
@@ -1828,6 +1829,9 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_a
__grp_src_mod_timer(ent, now + br_multicast_gmi(br));
}
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type))
changed = true;
return changed;
}
@@ -2140,7 +2144,7 @@ static bool br_multicast_toex(struct net_bridge_port_group *pg, void *h_addr,
* INCLUDE (A) BLOCK (B) INCLUDE (A) Send Q(G,A*B)
*/
static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size)
void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{
struct net_bridge_group_src *ent;
u32 src_idx, to_send = 0;
@@ -2161,6 +2165,9 @@ static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr,
}
}
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type))
changed = true;
if (to_send)
__grp_src_query_marked_and_rexmit(pg);
@@ -2180,7 +2187,7 @@ static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr,
* Send Q(G,A-Y)
*/
static bool __grp_src_block_excl(struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size)
void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{
struct net_bridge_group_src *ent;
u32 src_idx, to_send = 0;
@@ -2208,6 +2215,9 @@ static bool __grp_src_block_excl(struct net_bridge_port_group *pg, void *h_addr,
}
}
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type))
changed = true;
if (to_send)
__grp_src_query_marked_and_rexmit(pg);
@@ -2215,16 +2225,18 @@ static bool __grp_src_block_excl(struct net_bridge_port_group *pg, void *h_addr,
}
static bool br_multicast_block(struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size)
void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{
bool changed = false;
switch (pg->filter_mode) {
case MCAST_INCLUDE:
changed = __grp_src_block_incl(pg, h_addr, srcs, nsrcs, addr_size);
changed = __grp_src_block_incl(pg, h_addr, srcs, nsrcs, addr_size,
grec_type);
break;
case MCAST_EXCLUDE:
changed = __grp_src_block_excl(pg, h_addr, srcs, nsrcs, addr_size);
changed = __grp_src_block_excl(pg, h_addr, srcs, nsrcs, addr_size,
grec_type);
break;
}
@@ -2327,11 +2339,11 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
switch (type) {
case IGMPV3_ALLOW_NEW_SOURCES:
changed = br_multicast_isinc_allow(pg, h_addr, grec->grec_src,
nsrcs, sizeof(__be32));
nsrcs, sizeof(__be32), type);
break;
case IGMPV3_MODE_IS_INCLUDE:
changed = br_multicast_isinc_allow(pg, h_addr, grec->grec_src,
nsrcs, sizeof(__be32));
nsrcs, sizeof(__be32), type);
break;
case IGMPV3_MODE_IS_EXCLUDE:
changed = br_multicast_isexc(pg, h_addr, grec->grec_src,
@@ -2347,7 +2359,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
break;
case IGMPV3_BLOCK_OLD_SOURCES:
changed = br_multicast_block(pg, h_addr, grec->grec_src,
nsrcs, sizeof(__be32));
nsrcs, sizeof(__be32), type);
break;
}
if (changed)
@@ -2455,12 +2467,14 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
case MLD2_ALLOW_NEW_SOURCES:
changed = br_multicast_isinc_allow(pg, h_addr,
grec->grec_src, nsrcs,
sizeof(struct in6_addr));
sizeof(struct in6_addr),
grec->grec_type);
break;
case MLD2_MODE_IS_INCLUDE:
changed = br_multicast_isinc_allow(pg, h_addr,
grec->grec_src, nsrcs,
sizeof(struct in6_addr));
sizeof(struct in6_addr),
grec->grec_type);
break;
case MLD2_MODE_IS_EXCLUDE:
changed = br_multicast_isexc(pg, h_addr,
@@ -2480,7 +2494,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
case MLD2_BLOCK_OLD_SOURCES:
changed = br_multicast_block(pg, h_addr,
grec->grec_src, nsrcs,
sizeof(struct in6_addr));
sizeof(struct in6_addr),
grec->grec_type);
break;
}
if (changed)