提交 adc47037 编写于 作者: N Nikolay Aleksandrov 提交者: David S. Miller

net: bridge: multicast: use multicast contexts instead of bridge or port

Pass multicast context pointers to multicast functions instead of bridge/port.
This would make it easier later to switch these contexts to their per-vlan
versions. The patch is basically search and replace, no functional changes.
Signed-off-by: NNikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 d3d065c0
...@@ -28,6 +28,7 @@ EXPORT_SYMBOL_GPL(nf_br_ops); ...@@ -28,6 +28,7 @@ EXPORT_SYMBOL_GPL(nf_br_ops);
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct net_bridge *br = netdev_priv(dev); struct net_bridge *br = netdev_priv(dev);
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
struct net_bridge_fdb_entry *dst; struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst; struct net_bridge_mdb_entry *mdst;
const struct nf_br_ops *nf_ops; const struct nf_br_ops *nf_ops;
...@@ -82,15 +83,15 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -82,15 +83,15 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
br_flood(br, skb, BR_PKT_MULTICAST, false, true); br_flood(br, skb, BR_PKT_MULTICAST, false, true);
goto out; goto out;
} }
if (br_multicast_rcv(br, NULL, skb, vid)) { if (br_multicast_rcv(brmctx, NULL, skb, vid)) {
kfree_skb(skb); kfree_skb(skb);
goto out; goto out;
} }
mdst = br_mdb_get(br, skb, vid); mdst = br_mdb_get(brmctx, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb), mdst)) br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst))
br_multicast_flood(mdst, skb, false, true); br_multicast_flood(mdst, skb, brmctx, false, true);
else else
br_flood(br, skb, BR_PKT_MULTICAST, false, true); br_flood(br, skb, BR_PKT_MULTICAST, false, true);
} else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
......
...@@ -267,20 +267,19 @@ static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb, ...@@ -267,20 +267,19 @@ static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
/* called with rcu_read_lock */ /* called with rcu_read_lock */
void br_multicast_flood(struct net_bridge_mdb_entry *mdst, void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb, struct sk_buff *skb,
struct net_bridge_mcast *brmctx,
bool local_rcv, bool local_orig) bool local_rcv, bool local_orig)
{ {
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *prev = NULL; struct net_bridge_port *prev = NULL;
struct net_bridge_port_group *p; struct net_bridge_port_group *p;
bool allow_mode_include = true; bool allow_mode_include = true;
struct hlist_node *rp; struct hlist_node *rp;
rp = br_multicast_get_first_rport_node(br, skb); rp = br_multicast_get_first_rport_node(brmctx, skb);
if (mdst) { if (mdst) {
p = rcu_dereference(mdst->ports); p = rcu_dereference(mdst->ports);
if (br_multicast_should_handle_mode(br, mdst->addr.proto) && if (br_multicast_should_handle_mode(brmctx, mdst->addr.proto) &&
br_multicast_is_star_g(&mdst->addr)) br_multicast_is_star_g(&mdst->addr))
allow_mode_include = false; allow_mode_include = false;
} else { } else {
......
...@@ -69,8 +69,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -69,8 +69,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
struct net_bridge_port *p = br_port_get_rcu(skb->dev); struct net_bridge_port *p = br_port_get_rcu(skb->dev);
enum br_pkt_type pkt_type = BR_PKT_UNICAST; enum br_pkt_type pkt_type = BR_PKT_UNICAST;
struct net_bridge_fdb_entry *dst = NULL; struct net_bridge_fdb_entry *dst = NULL;
struct net_bridge_mcast_port *pmctx;
struct net_bridge_mdb_entry *mdst; struct net_bridge_mdb_entry *mdst;
bool local_rcv, mcast_hit = false; bool local_rcv, mcast_hit = false;
struct net_bridge_mcast *brmctx;
struct net_bridge *br; struct net_bridge *br;
u16 vid = 0; u16 vid = 0;
u8 state; u8 state;
...@@ -78,6 +80,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -78,6 +80,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if (!p || p->state == BR_STATE_DISABLED) if (!p || p->state == BR_STATE_DISABLED)
goto drop; goto drop;
brmctx = &p->br->multicast_ctx;
pmctx = &p->multicast_ctx;
state = p->state; state = p->state;
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid, if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid,
&state)) &state))
...@@ -98,7 +102,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -98,7 +102,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
local_rcv = true; local_rcv = true;
} else { } else {
pkt_type = BR_PKT_MULTICAST; pkt_type = BR_PKT_MULTICAST;
if (br_multicast_rcv(br, p, skb, vid)) if (br_multicast_rcv(brmctx, pmctx, skb, vid))
goto drop; goto drop;
} }
} }
...@@ -128,11 +132,11 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -128,11 +132,11 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
switch (pkt_type) { switch (pkt_type) {
case BR_PKT_MULTICAST: case BR_PKT_MULTICAST:
mdst = br_mdb_get(br, skb, vid); mdst = br_mdb_get(brmctx, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb), mdst)) { br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) {
if ((mdst && mdst->host_joined) || if ((mdst && mdst->host_joined) ||
br_multicast_is_router(br, skb)) { br_multicast_is_router(brmctx, skb)) {
local_rcv = true; local_rcv = true;
br->dev->stats.multicast++; br->dev->stats.multicast++;
} }
...@@ -162,7 +166,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -162,7 +166,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if (!mcast_hit) if (!mcast_hit)
br_flood(br, skb, pkt_type, local_rcv, false); br_flood(br, skb, pkt_type, local_rcv, false);
else else
br_multicast_flood(mdst, skb, local_rcv, false); br_multicast_flood(mdst, skb, brmctx, local_rcv, false);
} }
if (local_rcv) if (local_rcv)
......
...@@ -1092,7 +1092,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port, ...@@ -1092,7 +1092,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
* a new INCLUDE port (S,G) then all of *,G EXCLUDE ports need to be * a new INCLUDE port (S,G) then all of *,G EXCLUDE ports need to be
* added to it for proper replication * added to it for proper replication
*/ */
if (br_multicast_should_handle_mode(br, group.proto)) { if (br_multicast_should_handle_mode(&br->multicast_ctx, group.proto)) {
switch (filter_mode) { switch (filter_mode) {
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
br_multicast_star_g_handle_mode(p, MCAST_EXCLUDE); br_multicast_star_g_handle_mode(p, MCAST_EXCLUDE);
......
...@@ -49,30 +49,30 @@ static const struct rhashtable_params br_sg_port_rht_params = { ...@@ -49,30 +49,30 @@ static const struct rhashtable_params br_sg_port_rht_params = {
.automatic_shrinking = true, .automatic_shrinking = true,
}; };
static void br_multicast_start_querier(struct net_bridge *br, static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
struct bridge_mcast_own_query *query); struct bridge_mcast_own_query *query);
static void br_ip4_multicast_add_router(struct net_bridge *br, static void br_ip4_multicast_add_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port); struct net_bridge_mcast_port *pmctx);
static void br_ip4_multicast_leave_group(struct net_bridge *br, static void br_ip4_multicast_leave_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
__be32 group, __be32 group,
__u16 vid, __u16 vid,
const unsigned char *src); const unsigned char *src);
static void br_multicast_port_group_rexmit(struct timer_list *t); static void br_multicast_port_group_rexmit(struct timer_list *t);
static void static void
br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted); br_multicast_rport_del_notify(struct net_bridge_mcast_port *pmctx, bool deleted);
static void br_ip6_multicast_add_router(struct net_bridge *br, static void br_ip6_multicast_add_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port); struct net_bridge_mcast_port *pmctx);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br, static void br_ip6_multicast_leave_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
const struct in6_addr *group, const struct in6_addr *group,
__u16 vid, const unsigned char *src); __u16 vid, const unsigned char *src);
#endif #endif
static struct net_bridge_port_group * static struct net_bridge_port_group *
__br_multicast_add_group(struct net_bridge *br, __br_multicast_add_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct br_ip *group, struct br_ip *group,
const unsigned char *src, const unsigned char *src,
u8 filter_mode, u8 filter_mode,
...@@ -140,9 +140,10 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br, ...@@ -140,9 +140,10 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(struct net_bridge *br,
} }
#endif #endif
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge_mcast *brmctx,
struct sk_buff *skb, u16 vid) struct sk_buff *skb, u16 vid)
{ {
struct net_bridge *br = brmctx->br;
struct br_ip ip; struct br_ip ip;
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
...@@ -158,7 +159,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, ...@@ -158,7 +159,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
switch (skb->protocol) { switch (skb->protocol) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
ip.dst.ip4 = ip_hdr(skb)->daddr; ip.dst.ip4 = ip_hdr(skb)->daddr;
if (br->multicast_ctx.multicast_igmp_version == 3) { if (brmctx->multicast_igmp_version == 3) {
struct net_bridge_mdb_entry *mdb; struct net_bridge_mdb_entry *mdb;
ip.src.ip4 = ip_hdr(skb)->saddr; ip.src.ip4 = ip_hdr(skb)->saddr;
...@@ -171,7 +172,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, ...@@ -171,7 +172,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
ip.dst.ip6 = ipv6_hdr(skb)->daddr; ip.dst.ip6 = ipv6_hdr(skb)->daddr;
if (br->multicast_ctx.multicast_mld_version == 2) { if (brmctx->multicast_mld_version == 2) {
struct net_bridge_mdb_entry *mdb; struct net_bridge_mdb_entry *mdb;
ip.src.ip6 = ipv6_hdr(skb)->saddr; ip.src.ip6 = ipv6_hdr(skb)->saddr;
...@@ -203,20 +204,23 @@ static bool br_port_group_equal(struct net_bridge_port_group *p, ...@@ -203,20 +204,23 @@ static bool br_port_group_equal(struct net_bridge_port_group *p,
return ether_addr_equal(src, p->eth_addr); return ether_addr_equal(src, p->eth_addr);
} }
static void __fwd_add_star_excl(struct net_bridge_port_group *pg, static void __fwd_add_star_excl(struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg,
struct br_ip *sg_ip) struct br_ip *sg_ip)
{ {
struct net_bridge_port_group_sg_key sg_key; struct net_bridge_port_group_sg_key sg_key;
struct net_bridge *br = pg->key.port->br;
struct net_bridge_port_group *src_pg; struct net_bridge_port_group *src_pg;
struct net_bridge_mcast *brmctx;
memset(&sg_key, 0, sizeof(sg_key)); memset(&sg_key, 0, sizeof(sg_key));
brmctx = &pg->key.port->br->multicast_ctx;
sg_key.port = pg->key.port; sg_key.port = pg->key.port;
sg_key.addr = *sg_ip; sg_key.addr = *sg_ip;
if (br_sg_port_find(br, &sg_key)) if (br_sg_port_find(brmctx->br, &sg_key))
return; return;
src_pg = __br_multicast_add_group(br, pg->key.port, sg_ip, pg->eth_addr, src_pg = __br_multicast_add_group(brmctx, pmctx,
sg_ip, pg->eth_addr,
MCAST_INCLUDE, false, false); MCAST_INCLUDE, false, false);
if (IS_ERR_OR_NULL(src_pg) || if (IS_ERR_OR_NULL(src_pg) ||
src_pg->rt_protocol != RTPROT_KERNEL) src_pg->rt_protocol != RTPROT_KERNEL)
...@@ -256,6 +260,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg, ...@@ -256,6 +260,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg,
{ {
struct net_bridge *br = pg->key.port->br; struct net_bridge *br = pg->key.port->br;
struct net_bridge_port_group *pg_lst; struct net_bridge_port_group *pg_lst;
struct net_bridge_mcast_port *pmctx;
struct net_bridge_mdb_entry *mp; struct net_bridge_mdb_entry *mp;
struct br_ip sg_ip; struct br_ip sg_ip;
...@@ -265,6 +270,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg, ...@@ -265,6 +270,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg,
mp = br_mdb_ip_get(br, &pg->key.addr); mp = br_mdb_ip_get(br, &pg->key.addr);
if (!mp) if (!mp)
return; return;
pmctx = &pg->key.port->multicast_ctx;
memset(&sg_ip, 0, sizeof(sg_ip)); memset(&sg_ip, 0, sizeof(sg_ip));
sg_ip = pg->key.addr; sg_ip = pg->key.addr;
...@@ -284,7 +290,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg, ...@@ -284,7 +290,7 @@ void br_multicast_star_g_handle_mode(struct net_bridge_port_group *pg,
__fwd_del_star_excl(pg, &sg_ip); __fwd_del_star_excl(pg, &sg_ip);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
__fwd_add_star_excl(pg, &sg_ip); __fwd_add_star_excl(pmctx, pg, &sg_ip);
break; break;
} }
} }
...@@ -377,7 +383,9 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, ...@@ -377,7 +383,9 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
{ {
struct net_bridge_port_group_sg_key sg_key; struct net_bridge_port_group_sg_key sg_key;
struct net_bridge *br = star_mp->br; struct net_bridge *br = star_mp->br;
struct net_bridge_mcast_port *pmctx;
struct net_bridge_port_group *pg; struct net_bridge_port_group *pg;
struct net_bridge_mcast *brmctx;
if (WARN_ON(br_multicast_is_star_g(&sg->key.addr))) if (WARN_ON(br_multicast_is_star_g(&sg->key.addr)))
return; return;
...@@ -387,6 +395,7 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, ...@@ -387,6 +395,7 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
br_multicast_sg_host_state(star_mp, sg); br_multicast_sg_host_state(star_mp, sg);
memset(&sg_key, 0, sizeof(sg_key)); memset(&sg_key, 0, sizeof(sg_key));
sg_key.addr = sg->key.addr; sg_key.addr = sg->key.addr;
brmctx = &br->multicast_ctx;
/* we need to add all exclude ports to the S,G */ /* we need to add all exclude ports to the S,G */
for (pg = mlock_dereference(star_mp->ports, br); for (pg = mlock_dereference(star_mp->ports, br);
pg; pg;
...@@ -400,7 +409,8 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, ...@@ -400,7 +409,8 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
if (br_sg_port_find(br, &sg_key)) if (br_sg_port_find(br, &sg_key))
continue; continue;
src_pg = __br_multicast_add_group(br, pg->key.port, pmctx = &pg->key.port->multicast_ctx;
src_pg = __br_multicast_add_group(brmctx, pmctx,
&sg->key.addr, &sg->key.addr,
sg->eth_addr, sg->eth_addr,
MCAST_INCLUDE, false, false); MCAST_INCLUDE, false, false);
...@@ -414,16 +424,21 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, ...@@ -414,16 +424,21 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp,
static void br_multicast_fwd_src_add(struct net_bridge_group_src *src) static void br_multicast_fwd_src_add(struct net_bridge_group_src *src)
{ {
struct net_bridge_mdb_entry *star_mp; struct net_bridge_mdb_entry *star_mp;
struct net_bridge_mcast_port *pmctx;
struct net_bridge_port_group *sg; struct net_bridge_port_group *sg;
struct net_bridge_mcast *brmctx;
struct br_ip sg_ip; struct br_ip sg_ip;
if (src->flags & BR_SGRP_F_INSTALLED) if (src->flags & BR_SGRP_F_INSTALLED)
return; return;
memset(&sg_ip, 0, sizeof(sg_ip)); memset(&sg_ip, 0, sizeof(sg_ip));
pmctx = &src->pg->key.port->multicast_ctx;
brmctx = &src->br->multicast_ctx;
sg_ip = src->pg->key.addr; sg_ip = src->pg->key.addr;
sg_ip.src = src->addr.src; sg_ip.src = src->addr.src;
sg = __br_multicast_add_group(src->br, src->pg->key.port, &sg_ip,
sg = __br_multicast_add_group(brmctx, pmctx, &sg_ip,
src->pg->eth_addr, MCAST_INCLUDE, false, src->pg->eth_addr, MCAST_INCLUDE, false,
!timer_pending(&src->timer)); !timer_pending(&src->timer));
if (IS_ERR_OR_NULL(sg)) if (IS_ERR_OR_NULL(sg))
...@@ -692,14 +707,13 @@ static void br_multicast_gc(struct hlist_head *head) ...@@ -692,14 +707,13 @@ static void br_multicast_gc(struct hlist_head *head)
} }
} }
static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg, struct net_bridge_port_group *pg,
__be32 ip_dst, __be32 group, __be32 ip_dst, __be32 group,
bool with_srcs, bool over_lmqt, bool with_srcs, bool over_lmqt,
u8 sflag, u8 *igmp_type, u8 sflag, u8 *igmp_type,
bool *need_rexmit) bool *need_rexmit)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
struct net_bridge_port *p = pg ? pg->key.port : NULL; struct net_bridge_port *p = pg ? pg->key.port : NULL;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
size_t pkt_size, igmp_hdr_size; size_t pkt_size, igmp_hdr_size;
...@@ -735,10 +749,10 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, ...@@ -735,10 +749,10 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
pkt_size = sizeof(*eth) + sizeof(*iph) + 4 + igmp_hdr_size; pkt_size = sizeof(*eth) + sizeof(*iph) + 4 + igmp_hdr_size;
if ((p && pkt_size > p->dev->mtu) || if ((p && pkt_size > p->dev->mtu) ||
pkt_size > br->dev->mtu) pkt_size > brmctx->br->dev->mtu)
return NULL; return NULL;
skb = netdev_alloc_skb_ip_align(br->dev, pkt_size); skb = netdev_alloc_skb_ip_align(brmctx->br->dev, pkt_size);
if (!skb) if (!skb)
goto out; goto out;
...@@ -747,7 +761,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, ...@@ -747,7 +761,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
eth = eth_hdr(skb); eth = eth_hdr(skb);
ether_addr_copy(eth->h_source, br->dev->dev_addr); ether_addr_copy(eth->h_source, brmctx->br->dev->dev_addr);
ip_eth_mc_map(ip_dst, eth->h_dest); ip_eth_mc_map(ip_dst, eth->h_dest);
eth->h_proto = htons(ETH_P_IP); eth->h_proto = htons(ETH_P_IP);
skb_put(skb, sizeof(*eth)); skb_put(skb, sizeof(*eth));
...@@ -763,8 +777,8 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, ...@@ -763,8 +777,8 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
iph->frag_off = htons(IP_DF); iph->frag_off = htons(IP_DF);
iph->ttl = 1; iph->ttl = 1;
iph->protocol = IPPROTO_IGMP; iph->protocol = IPPROTO_IGMP;
iph->saddr = br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR) ? iph->saddr = br_opt_get(brmctx->br, BROPT_MULTICAST_QUERY_USE_IFADDR) ?
inet_select_addr(br->dev, 0, RT_SCOPE_LINK) : 0; inet_select_addr(brmctx->br->dev, 0, RT_SCOPE_LINK) : 0;
iph->daddr = ip_dst; iph->daddr = ip_dst;
((u8 *)&iph[1])[0] = IPOPT_RA; ((u8 *)&iph[1])[0] = IPOPT_RA;
((u8 *)&iph[1])[1] = 4; ((u8 *)&iph[1])[1] = 4;
...@@ -838,7 +852,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br, ...@@ -838,7 +852,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg, struct net_bridge_port_group *pg,
const struct in6_addr *ip6_dst, const struct in6_addr *ip6_dst,
const struct in6_addr *group, const struct in6_addr *group,
...@@ -846,7 +860,6 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ...@@ -846,7 +860,6 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
u8 sflag, u8 *igmp_type, u8 sflag, u8 *igmp_type,
bool *need_rexmit) bool *need_rexmit)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
struct net_bridge_port *p = pg ? pg->key.port : NULL; struct net_bridge_port *p = pg ? pg->key.port : NULL;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
size_t pkt_size, mld_hdr_size; size_t pkt_size, mld_hdr_size;
...@@ -884,10 +897,10 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ...@@ -884,10 +897,10 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
pkt_size = sizeof(*eth) + sizeof(*ip6h) + 8 + mld_hdr_size; pkt_size = sizeof(*eth) + sizeof(*ip6h) + 8 + mld_hdr_size;
if ((p && pkt_size > p->dev->mtu) || if ((p && pkt_size > p->dev->mtu) ||
pkt_size > br->dev->mtu) pkt_size > brmctx->br->dev->mtu)
return NULL; return NULL;
skb = netdev_alloc_skb_ip_align(br->dev, pkt_size); skb = netdev_alloc_skb_ip_align(brmctx->br->dev, pkt_size);
if (!skb) if (!skb)
goto out; goto out;
...@@ -897,7 +910,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ...@@ -897,7 +910,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
eth = eth_hdr(skb); eth = eth_hdr(skb);
ether_addr_copy(eth->h_source, br->dev->dev_addr); ether_addr_copy(eth->h_source, brmctx->br->dev->dev_addr);
eth->h_proto = htons(ETH_P_IPV6); eth->h_proto = htons(ETH_P_IPV6);
skb_put(skb, sizeof(*eth)); skb_put(skb, sizeof(*eth));
...@@ -910,14 +923,14 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ...@@ -910,14 +923,14 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
ip6h->nexthdr = IPPROTO_HOPOPTS; ip6h->nexthdr = IPPROTO_HOPOPTS;
ip6h->hop_limit = 1; ip6h->hop_limit = 1;
ip6h->daddr = *ip6_dst; ip6h->daddr = *ip6_dst;
if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, if (ipv6_dev_get_saddr(dev_net(brmctx->br->dev), brmctx->br->dev,
&ip6h->saddr)) { &ip6h->daddr, 0, &ip6h->saddr)) {
kfree_skb(skb); kfree_skb(skb);
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, false); br_opt_toggle(brmctx->br, BROPT_HAS_IPV6_ADDR, false);
return NULL; return NULL;
} }
br_opt_toggle(br, BROPT_HAS_IPV6_ADDR, true); br_opt_toggle(brmctx->br, BROPT_HAS_IPV6_ADDR, true);
ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
hopopt = (u8 *)(ip6h + 1); hopopt = (u8 *)(ip6h + 1);
...@@ -1002,7 +1015,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, ...@@ -1002,7 +1015,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
} }
#endif #endif
static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, static struct sk_buff *br_multicast_alloc_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg, struct net_bridge_port_group *pg,
struct br_ip *ip_dst, struct br_ip *ip_dst,
struct br_ip *group, struct br_ip *group,
...@@ -1015,7 +1028,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, ...@@ -1015,7 +1028,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
switch (group->proto) { switch (group->proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
ip4_dst = ip_dst ? ip_dst->dst.ip4 : htonl(INADDR_ALLHOSTS_GROUP); ip4_dst = ip_dst ? ip_dst->dst.ip4 : htonl(INADDR_ALLHOSTS_GROUP);
return br_ip4_multicast_alloc_query(br, pg, return br_ip4_multicast_alloc_query(brmctx, pg,
ip4_dst, group->dst.ip4, ip4_dst, group->dst.ip4,
with_srcs, over_lmqt, with_srcs, over_lmqt,
sflag, igmp_type, sflag, igmp_type,
...@@ -1030,7 +1043,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, ...@@ -1030,7 +1043,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
ipv6_addr_set(&ip6_dst, htonl(0xff020000), 0, 0, ipv6_addr_set(&ip6_dst, htonl(0xff020000), 0, 0,
htonl(1)); htonl(1));
return br_ip6_multicast_alloc_query(br, pg, return br_ip6_multicast_alloc_query(brmctx, pg,
&ip6_dst, &group->dst.ip6, &ip6_dst, &group->dst.ip6,
with_srcs, over_lmqt, with_srcs, over_lmqt,
sflag, igmp_type, sflag, igmp_type,
...@@ -1238,8 +1251,8 @@ void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify) ...@@ -1238,8 +1251,8 @@ void br_multicast_host_leave(struct net_bridge_mdb_entry *mp, bool notify)
} }
static struct net_bridge_port_group * static struct net_bridge_port_group *
__br_multicast_add_group(struct net_bridge *br, __br_multicast_add_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct br_ip *group, struct br_ip *group,
const unsigned char *src, const unsigned char *src,
u8 filter_mode, u8 filter_mode,
...@@ -1251,29 +1264,29 @@ __br_multicast_add_group(struct net_bridge *br, ...@@ -1251,29 +1264,29 @@ __br_multicast_add_group(struct net_bridge *br,
struct net_bridge_mdb_entry *mp; struct net_bridge_mdb_entry *mp;
unsigned long now = jiffies; unsigned long now = jiffies;
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
(port && port->state == BR_STATE_DISABLED)) (pmctx && pmctx->port->state == BR_STATE_DISABLED))
goto out; goto out;
mp = br_multicast_new_group(br, group); mp = br_multicast_new_group(brmctx->br, group);
if (IS_ERR(mp)) if (IS_ERR(mp))
return ERR_CAST(mp); return ERR_CAST(mp);
if (!port) { if (!pmctx) {
br_multicast_host_join(mp, true); br_multicast_host_join(mp, true);
goto out; goto out;
} }
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, brmctx->br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (br_port_group_equal(p, port, src)) if (br_port_group_equal(p, pmctx->port, src))
goto found; goto found;
if ((unsigned long)p->key.port < (unsigned long)port) if ((unsigned long)p->key.port < (unsigned long)pmctx->port)
break; break;
} }
p = br_multicast_new_port_group(port, group, *pp, 0, src, p = br_multicast_new_port_group(pmctx->port, group, *pp, 0, src,
filter_mode, RTPROT_KERNEL); filter_mode, RTPROT_KERNEL);
if (unlikely(!p)) { if (unlikely(!p)) {
p = ERR_PTR(-ENOMEM); p = ERR_PTR(-ENOMEM);
...@@ -1282,19 +1295,19 @@ __br_multicast_add_group(struct net_bridge *br, ...@@ -1282,19 +1295,19 @@ __br_multicast_add_group(struct net_bridge *br,
rcu_assign_pointer(*pp, p); rcu_assign_pointer(*pp, p);
if (blocked) if (blocked)
p->flags |= MDB_PG_FLAGS_BLOCKED; p->flags |= MDB_PG_FLAGS_BLOCKED;
br_mdb_notify(br->dev, mp, p, RTM_NEWMDB); br_mdb_notify(brmctx->br->dev, mp, p, RTM_NEWMDB);
found: found:
if (igmpv2_mldv1) if (igmpv2_mldv1)
mod_timer(&p->timer, mod_timer(&p->timer,
now + br->multicast_ctx.multicast_membership_interval); now + brmctx->multicast_membership_interval);
out: out:
return p; return p;
} }
static int br_multicast_add_group(struct net_bridge *br, static int br_multicast_add_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct br_ip *group, struct br_ip *group,
const unsigned char *src, const unsigned char *src,
u8 filter_mode, u8 filter_mode,
...@@ -1303,18 +1316,18 @@ static int br_multicast_add_group(struct net_bridge *br, ...@@ -1303,18 +1316,18 @@ static int br_multicast_add_group(struct net_bridge *br,
struct net_bridge_port_group *pg; struct net_bridge_port_group *pg;
int err; int err;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
pg = __br_multicast_add_group(br, port, group, src, filter_mode, pg = __br_multicast_add_group(brmctx, pmctx, group, src, filter_mode,
igmpv2_mldv1, false); igmpv2_mldv1, false);
/* NULL is considered valid for host joined groups */ /* NULL is considered valid for host joined groups */
err = PTR_ERR_OR_ZERO(pg); err = PTR_ERR_OR_ZERO(pg);
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
return err; return err;
} }
static int br_ip4_multicast_add_group(struct net_bridge *br, static int br_ip4_multicast_add_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
__be32 group, __be32 group,
__u16 vid, __u16 vid,
const unsigned char *src, const unsigned char *src,
...@@ -1332,13 +1345,13 @@ static int br_ip4_multicast_add_group(struct net_bridge *br, ...@@ -1332,13 +1345,13 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
br_group.vid = vid; br_group.vid = vid;
filter_mode = igmpv2 ? MCAST_EXCLUDE : MCAST_INCLUDE; filter_mode = igmpv2 ? MCAST_EXCLUDE : MCAST_INCLUDE;
return br_multicast_add_group(br, port, &br_group, src, filter_mode, return br_multicast_add_group(brmctx, pmctx, &br_group, src,
igmpv2); filter_mode, igmpv2);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_add_group(struct net_bridge *br, static int br_ip6_multicast_add_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
const struct in6_addr *group, const struct in6_addr *group,
__u16 vid, __u16 vid,
const unsigned char *src, const unsigned char *src,
...@@ -1356,8 +1369,8 @@ static int br_ip6_multicast_add_group(struct net_bridge *br, ...@@ -1356,8 +1369,8 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
br_group.vid = vid; br_group.vid = vid;
filter_mode = mldv1 ? MCAST_EXCLUDE : MCAST_INCLUDE; filter_mode = mldv1 ? MCAST_EXCLUDE : MCAST_INCLUDE;
return br_multicast_add_group(br, port, &br_group, src, filter_mode, return br_multicast_add_group(brmctx, pmctx, &br_group, src,
mldv1); filter_mode, mldv1);
} }
#endif #endif
...@@ -1370,15 +1383,15 @@ static bool br_multicast_rport_del(struct hlist_node *rlist) ...@@ -1370,15 +1383,15 @@ static bool br_multicast_rport_del(struct hlist_node *rlist)
return true; return true;
} }
static bool br_ip4_multicast_rport_del(struct net_bridge_port *p) static bool br_ip4_multicast_rport_del(struct net_bridge_mcast_port *pmctx)
{ {
return br_multicast_rport_del(&p->multicast_ctx.ip4_rlist); return br_multicast_rport_del(&pmctx->ip4_rlist);
} }
static bool br_ip6_multicast_rport_del(struct net_bridge_port *p) static bool br_ip6_multicast_rport_del(struct net_bridge_mcast_port *pmctx)
{ {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
return br_multicast_rport_del(&p->multicast_ctx.ip6_rlist); return br_multicast_rport_del(&pmctx->ip6_rlist);
#else #else
return false; return false;
#endif #endif
...@@ -1398,7 +1411,7 @@ static void br_multicast_router_expired(struct net_bridge_mcast_port *pmctx, ...@@ -1398,7 +1411,7 @@ static void br_multicast_router_expired(struct net_bridge_mcast_port *pmctx,
goto out; goto out;
del = br_multicast_rport_del(rlist); del = br_multicast_rport_del(rlist);
br_multicast_rport_del_notify(pmctx->port, del); br_multicast_rport_del_notify(pmctx, del);
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
} }
...@@ -1475,7 +1488,7 @@ static void br_multicast_querier_expired(struct net_bridge_mcast *brmctx, ...@@ -1475,7 +1488,7 @@ static void br_multicast_querier_expired(struct net_bridge_mcast *brmctx,
!br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED)) !br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED))
goto out; goto out;
br_multicast_start_querier(brmctx->br, query); br_multicast_start_querier(brmctx, query);
out: out:
spin_unlock(&brmctx->br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
...@@ -1499,12 +1512,10 @@ static void br_ip6_multicast_querier_expired(struct timer_list *t) ...@@ -1499,12 +1512,10 @@ static void br_ip6_multicast_querier_expired(struct timer_list *t)
} }
#endif #endif
static void br_multicast_select_own_querier(struct net_bridge *br, static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
struct br_ip *ip, struct br_ip *ip,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
if (ip->proto == htons(ETH_P_IP)) if (ip->proto == htons(ETH_P_IP))
brmctx->ip4_querier.addr.src.ip4 = ip_hdr(skb)->saddr; brmctx->ip4_querier.addr.src.ip4 = ip_hdr(skb)->saddr;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
...@@ -1513,8 +1524,8 @@ static void br_multicast_select_own_querier(struct net_bridge *br, ...@@ -1513,8 +1524,8 @@ static void br_multicast_select_own_querier(struct net_bridge *br,
#endif #endif
} }
static void __br_multicast_send_query(struct net_bridge *br, static void __br_multicast_send_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg, struct net_bridge_port_group *pg,
struct br_ip *ip_dst, struct br_ip *ip_dst,
struct br_ip *group, struct br_ip *group,
...@@ -1527,18 +1538,18 @@ static void __br_multicast_send_query(struct net_bridge *br, ...@@ -1527,18 +1538,18 @@ static void __br_multicast_send_query(struct net_bridge *br,
u8 igmp_type; u8 igmp_type;
again_under_lmqt: again_under_lmqt:
skb = br_multicast_alloc_query(br, pg, ip_dst, group, with_srcs, skb = br_multicast_alloc_query(brmctx, pg, ip_dst, group, with_srcs,
over_lmqt, sflag, &igmp_type, over_lmqt, sflag, &igmp_type,
need_rexmit); need_rexmit);
if (!skb) if (!skb)
return; return;
if (port) { if (pmctx) {
skb->dev = port->dev; skb->dev = pmctx->port->dev;
br_multicast_count(br, port, skb, igmp_type, br_multicast_count(brmctx->br, pmctx->port, skb, igmp_type,
BR_MCAST_DIR_TX); BR_MCAST_DIR_TX);
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
dev_net(port->dev), NULL, skb, NULL, skb->dev, dev_net(pmctx->port->dev), NULL, skb, NULL, skb->dev,
br_dev_queue_push_xmit); br_dev_queue_push_xmit);
if (over_lmqt && with_srcs && sflag) { if (over_lmqt && with_srcs && sflag) {
...@@ -1546,31 +1557,30 @@ static void __br_multicast_send_query(struct net_bridge *br, ...@@ -1546,31 +1557,30 @@ static void __br_multicast_send_query(struct net_bridge *br,
goto again_under_lmqt; goto again_under_lmqt;
} }
} else { } else {
br_multicast_select_own_querier(br, group, skb); br_multicast_select_own_querier(brmctx, group, skb);
br_multicast_count(br, port, skb, igmp_type, br_multicast_count(brmctx->br, NULL, skb, igmp_type,
BR_MCAST_DIR_RX); BR_MCAST_DIR_RX);
netif_rx(skb); netif_rx(skb);
} }
} }
static void br_multicast_send_query(struct net_bridge *br, static void br_multicast_send_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct bridge_mcast_own_query *own_query) struct bridge_mcast_own_query *own_query)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
struct bridge_mcast_other_query *other_query = NULL; struct bridge_mcast_other_query *other_query = NULL;
struct br_ip br_group; struct br_ip br_group;
unsigned long time; unsigned long time;
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED) ||
!br_opt_get(br, BROPT_MULTICAST_QUERIER)) !br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER))
return; return;
memset(&br_group.dst, 0, sizeof(br_group.dst)); memset(&br_group.dst, 0, sizeof(br_group.dst));
if (port ? (own_query == &port->multicast_ctx.ip4_own_query) : if (pmctx ? (own_query == &pmctx->ip4_own_query) :
(own_query == &brmctx->ip4_own_query)) { (own_query == &brmctx->ip4_own_query)) {
other_query = &brmctx->ip4_other_query; other_query = &brmctx->ip4_other_query;
br_group.proto = htons(ETH_P_IP); br_group.proto = htons(ETH_P_IP);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
...@@ -1583,8 +1593,8 @@ static void br_multicast_send_query(struct net_bridge *br, ...@@ -1583,8 +1593,8 @@ static void br_multicast_send_query(struct net_bridge *br,
if (!other_query || timer_pending(&other_query->timer)) if (!other_query || timer_pending(&other_query->timer))
return; return;
__br_multicast_send_query(br, port, NULL, NULL, &br_group, false, 0, __br_multicast_send_query(brmctx, pmctx, NULL, NULL, &br_group, false,
NULL); 0, NULL);
time = jiffies; time = jiffies;
time += own_query->startup_sent < brmctx->multicast_startup_query_count ? time += own_query->startup_sent < brmctx->multicast_startup_query_count ?
...@@ -1607,7 +1617,7 @@ br_multicast_port_query_expired(struct net_bridge_mcast_port *pmctx, ...@@ -1607,7 +1617,7 @@ br_multicast_port_query_expired(struct net_bridge_mcast_port *pmctx,
if (query->startup_sent < br->multicast_ctx.multicast_startup_query_count) if (query->startup_sent < br->multicast_ctx.multicast_startup_query_count)
query->startup_sent++; query->startup_sent++;
br_multicast_send_query(pmctx->port->br, pmctx->port, query); br_multicast_send_query(&br->multicast_ctx, pmctx, query);
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
...@@ -1636,7 +1646,8 @@ static void br_multicast_port_group_rexmit(struct timer_list *t) ...@@ -1636,7 +1646,8 @@ static void br_multicast_port_group_rexmit(struct timer_list *t)
struct net_bridge_port_group *pg = from_timer(pg, t, rexmit_timer); struct net_bridge_port_group *pg = from_timer(pg, t, rexmit_timer);
struct bridge_mcast_other_query *other_query = NULL; struct bridge_mcast_other_query *other_query = NULL;
struct net_bridge *br = pg->key.port->br; struct net_bridge *br = pg->key.port->br;
struct net_bridge_mcast *brmctx = &br->multicast_ctx; struct net_bridge_mcast_port *pmctx;
struct net_bridge_mcast *brmctx;
bool need_rexmit = false; bool need_rexmit = false;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
...@@ -1645,6 +1656,8 @@ static void br_multicast_port_group_rexmit(struct timer_list *t) ...@@ -1645,6 +1656,8 @@ static void br_multicast_port_group_rexmit(struct timer_list *t)
!br_opt_get(br, BROPT_MULTICAST_QUERIER)) !br_opt_get(br, BROPT_MULTICAST_QUERIER))
goto out; goto out;
brmctx = &br->multicast_ctx;
pmctx = &pg->key.port->multicast_ctx;
if (pg->key.addr.proto == htons(ETH_P_IP)) if (pg->key.addr.proto == htons(ETH_P_IP))
other_query = &brmctx->ip4_other_query; other_query = &brmctx->ip4_other_query;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
...@@ -1657,10 +1670,10 @@ static void br_multicast_port_group_rexmit(struct timer_list *t) ...@@ -1657,10 +1670,10 @@ static void br_multicast_port_group_rexmit(struct timer_list *t)
if (pg->grp_query_rexmit_cnt) { if (pg->grp_query_rexmit_cnt) {
pg->grp_query_rexmit_cnt--; pg->grp_query_rexmit_cnt--;
__br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, __br_multicast_send_query(brmctx, pmctx, pg, &pg->key.addr,
&pg->key.addr, false, 1, NULL); &pg->key.addr, false, 1, NULL);
} }
__br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, __br_multicast_send_query(brmctx, pmctx, pg, &pg->key.addr,
&pg->key.addr, true, 0, &need_rexmit); &pg->key.addr, true, 0, &need_rexmit);
if (pg->grp_query_rexmit_cnt || need_rexmit) if (pg->grp_query_rexmit_cnt || need_rexmit)
...@@ -1756,20 +1769,21 @@ static void br_multicast_enable(struct bridge_mcast_own_query *query) ...@@ -1756,20 +1769,21 @@ static void br_multicast_enable(struct bridge_mcast_own_query *query)
mod_timer(&query->timer, jiffies); mod_timer(&query->timer, jiffies);
} }
static void __br_multicast_enable_port(struct net_bridge_port *port) static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
{ {
struct net_bridge *br = port->br; struct net_bridge *br = pmctx->port->br;
struct net_bridge_mcast *brmctx = &pmctx->port->br->multicast_ctx;
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev)) if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) || !netif_running(br->dev))
return; return;
br_multicast_enable(&port->multicast_ctx.ip4_own_query); br_multicast_enable(&pmctx->ip4_own_query);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
br_multicast_enable(&port->multicast_ctx.ip6_own_query); br_multicast_enable(&pmctx->ip6_own_query);
#endif #endif
if (port->multicast_ctx.multicast_router == MDB_RTR_TYPE_PERM) { if (pmctx->multicast_router == MDB_RTR_TYPE_PERM) {
br_ip4_multicast_add_router(br, port); br_ip4_multicast_add_router(brmctx, pmctx);
br_ip6_multicast_add_router(br, port); br_ip6_multicast_add_router(brmctx, pmctx);
} }
} }
...@@ -1778,12 +1792,13 @@ void br_multicast_enable_port(struct net_bridge_port *port) ...@@ -1778,12 +1792,13 @@ void br_multicast_enable_port(struct net_bridge_port *port)
struct net_bridge *br = port->br; struct net_bridge *br = port->br;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
__br_multicast_enable_port(port); __br_multicast_enable_port_ctx(&port->multicast_ctx);
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
} }
void br_multicast_disable_port(struct net_bridge_port *port) void br_multicast_disable_port(struct net_bridge_port *port)
{ {
struct net_bridge_mcast_port *pmctx = &port->multicast_ctx;
struct net_bridge *br = port->br; struct net_bridge *br = port->br;
struct net_bridge_port_group *pg; struct net_bridge_port_group *pg;
struct hlist_node *n; struct hlist_node *n;
...@@ -1794,15 +1809,15 @@ void br_multicast_disable_port(struct net_bridge_port *port) ...@@ -1794,15 +1809,15 @@ void br_multicast_disable_port(struct net_bridge_port *port)
if (!(pg->flags & MDB_PG_FLAGS_PERMANENT)) if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
br_multicast_find_del_pg(br, pg); br_multicast_find_del_pg(br, pg);
del |= br_ip4_multicast_rport_del(port); del |= br_ip4_multicast_rport_del(pmctx);
del_timer(&port->multicast_ctx.ip4_mc_router_timer); del_timer(&pmctx->ip4_mc_router_timer);
del_timer(&port->multicast_ctx.ip4_own_query.timer); del_timer(&pmctx->ip4_own_query.timer);
del |= br_ip6_multicast_rport_del(port); del |= br_ip6_multicast_rport_del(pmctx);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
del_timer(&port->multicast_ctx.ip6_mc_router_timer); del_timer(&pmctx->ip6_mc_router_timer);
del_timer(&port->multicast_ctx.ip6_own_query.timer); del_timer(&pmctx->ip6_own_query.timer);
#endif #endif
br_multicast_rport_del_notify(port, del); br_multicast_rport_del_notify(pmctx, del);
spin_unlock(&br->multicast_lock); spin_unlock(&br->multicast_lock);
} }
...@@ -1828,17 +1843,17 @@ static void __grp_src_mod_timer(struct net_bridge_group_src *src, ...@@ -1828,17 +1843,17 @@ static void __grp_src_mod_timer(struct net_bridge_group_src *src,
br_multicast_fwd_src_handle(src); br_multicast_fwd_src_handle(src);
} }
static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg) static void __grp_src_query_marked_and_rexmit(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg)
{ {
struct bridge_mcast_other_query *other_query = NULL; struct bridge_mcast_other_query *other_query = NULL;
struct net_bridge *br = pg->key.port->br;
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
u32 lmqc = brmctx->multicast_last_member_count; u32 lmqc = brmctx->multicast_last_member_count;
unsigned long lmqt, lmi, now = jiffies; unsigned long lmqt, lmi, now = jiffies;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
!br_opt_get(br, BROPT_MULTICAST_ENABLED)) !br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED))
return; return;
if (pg->key.addr.proto == htons(ETH_P_IP)) if (pg->key.addr.proto == htons(ETH_P_IP))
...@@ -1848,12 +1863,13 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1848,12 +1863,13 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg)
other_query = &brmctx->ip6_other_query; other_query = &brmctx->ip6_other_query;
#endif #endif
lmqt = now + br_multicast_lmqt(br); lmqt = now + br_multicast_lmqt(brmctx);
hlist_for_each_entry(ent, &pg->src_list, node) { hlist_for_each_entry(ent, &pg->src_list, node) {
if (ent->flags & BR_SGRP_F_SEND) { if (ent->flags & BR_SGRP_F_SEND) {
ent->flags &= ~BR_SGRP_F_SEND; ent->flags &= ~BR_SGRP_F_SEND;
if (ent->timer.expires > lmqt) { if (ent->timer.expires > lmqt) {
if (br_opt_get(br, BROPT_MULTICAST_QUERIER) && if (br_opt_get(brmctx->br,
BROPT_MULTICAST_QUERIER) &&
other_query && other_query &&
!timer_pending(&other_query->timer)) !timer_pending(&other_query->timer))
ent->src_query_rexmit_cnt = lmqc; ent->src_query_rexmit_cnt = lmqc;
...@@ -1862,11 +1878,11 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1862,11 +1878,11 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg)
} }
} }
if (!br_opt_get(br, BROPT_MULTICAST_QUERIER) || if (!br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER) ||
!other_query || timer_pending(&other_query->timer)) !other_query || timer_pending(&other_query->timer))
return; return;
__br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, __br_multicast_send_query(brmctx, pmctx, pg, &pg->key.addr,
&pg->key.addr, true, 1, NULL); &pg->key.addr, true, 1, NULL);
lmi = now + brmctx->multicast_last_member_interval; lmi = now + brmctx->multicast_last_member_interval;
...@@ -1875,15 +1891,15 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1875,15 +1891,15 @@ static void __grp_src_query_marked_and_rexmit(struct net_bridge_port_group *pg)
mod_timer(&pg->rexmit_timer, lmi); mod_timer(&pg->rexmit_timer, lmi);
} }
static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg) static void __grp_send_query_and_rexmit(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg)
{ {
struct bridge_mcast_other_query *other_query = NULL; struct bridge_mcast_other_query *other_query = NULL;
struct net_bridge *br = pg->key.port->br;
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
unsigned long now = jiffies, lmi; unsigned long now = jiffies, lmi;
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
!br_opt_get(br, BROPT_MULTICAST_ENABLED)) !br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED))
return; return;
if (pg->key.addr.proto == htons(ETH_P_IP)) if (pg->key.addr.proto == htons(ETH_P_IP))
...@@ -1893,11 +1909,11 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1893,11 +1909,11 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg)
other_query = &brmctx->ip6_other_query; other_query = &brmctx->ip6_other_query;
#endif #endif
if (br_opt_get(br, BROPT_MULTICAST_QUERIER) && if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER) &&
other_query && !timer_pending(&other_query->timer)) { other_query && !timer_pending(&other_query->timer)) {
lmi = now + brmctx->multicast_last_member_interval; lmi = now + brmctx->multicast_last_member_interval;
pg->grp_query_rexmit_cnt = brmctx->multicast_last_member_count - 1; pg->grp_query_rexmit_cnt = brmctx->multicast_last_member_count - 1;
__br_multicast_send_query(br, pg->key.port, pg, &pg->key.addr, __br_multicast_send_query(brmctx, pmctx, pg, &pg->key.addr,
&pg->key.addr, false, 0, NULL); &pg->key.addr, false, 0, NULL);
if (!timer_pending(&pg->rexmit_timer) || if (!timer_pending(&pg->rexmit_timer) ||
time_after(pg->rexmit_timer.expires, lmi)) time_after(pg->rexmit_timer.expires, lmi))
...@@ -1906,8 +1922,8 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1906,8 +1922,8 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg)
if (pg->filter_mode == MCAST_EXCLUDE && if (pg->filter_mode == MCAST_EXCLUDE &&
(!timer_pending(&pg->timer) || (!timer_pending(&pg->timer) ||
time_after(pg->timer.expires, now + br_multicast_lmqt(br)))) time_after(pg->timer.expires, now + br_multicast_lmqt(brmctx))))
mod_timer(&pg->timer, now + br_multicast_lmqt(br)); mod_timer(&pg->timer, now + br_multicast_lmqt(brmctx));
} }
/* State Msg type New state Actions /* State Msg type New state Actions
...@@ -1915,11 +1931,11 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg) ...@@ -1915,11 +1931,11 @@ static void __grp_send_query_and_rexmit(struct net_bridge_port_group *pg)
* INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI * INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI
* EXCLUDE (X,Y) ALLOW (A) EXCLUDE (X+A,Y-A) (A)=GMI * 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, static bool br_multicast_isinc_allow(const struct net_bridge_mcast *brmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
unsigned long now = jiffies; unsigned long now = jiffies;
bool changed = false; bool changed = false;
...@@ -1938,10 +1954,11 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_a ...@@ -1938,10 +1954,11 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_a
} }
if (ent) if (ent)
__grp_src_mod_timer(ent, now + br_multicast_gmi(br)); __grp_src_mod_timer(ent, now + br_multicast_gmi(brmctx));
} }
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
return changed; return changed;
...@@ -1952,7 +1969,8 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_a ...@@ -1952,7 +1969,8 @@ static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg, void *h_a
* Delete (A-B) * Delete (A-B)
* Group Timer=GMI * Group Timer=GMI
*/ */
static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, void *h_addr, static void __grp_src_isexc_incl(const struct net_bridge_mcast *brmctx,
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) int grec_type)
{ {
...@@ -1976,7 +1994,8 @@ static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -1976,7 +1994,8 @@ static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, void *h_addr,
br_multicast_fwd_src_handle(ent); br_multicast_fwd_src_handle(ent);
} }
br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type); br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type);
__grp_src_delete_marked(pg); __grp_src_delete_marked(pg);
} }
...@@ -1987,11 +2006,11 @@ static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -1987,11 +2006,11 @@ static void __grp_src_isexc_incl(struct net_bridge_port_group *pg, void *h_addr,
* Delete (Y-A) * Delete (Y-A)
* Group Timer=GMI * Group Timer=GMI
*/ */
static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, void *h_addr, static bool __grp_src_isexc_excl(const struct net_bridge_mcast *brmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
unsigned long now = jiffies; unsigned long now = jiffies;
bool changed = false; bool changed = false;
...@@ -2012,13 +2031,14 @@ static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2012,13 +2031,14 @@ static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, void *h_addr,
ent = br_multicast_new_group_src(pg, &src_ip); ent = br_multicast_new_group_src(pg, &src_ip);
if (ent) { if (ent) {
__grp_src_mod_timer(ent, __grp_src_mod_timer(ent,
now + br_multicast_gmi(br)); now + br_multicast_gmi(brmctx));
changed = true; changed = true;
} }
} }
} }
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (__grp_src_delete_marked(pg)) if (__grp_src_delete_marked(pg))
...@@ -2027,28 +2047,28 @@ static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2027,28 +2047,28 @@ static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg, void *h_addr,
return changed; return changed;
} }
static bool br_multicast_isexc(struct net_bridge_port_group *pg, void *h_addr, static bool br_multicast_isexc(const struct net_bridge_mcast *brmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
bool changed = false; bool changed = false;
switch (pg->filter_mode) { switch (pg->filter_mode) {
case MCAST_INCLUDE: case MCAST_INCLUDE:
__grp_src_isexc_incl(pg, h_addr, srcs, nsrcs, addr_size, __grp_src_isexc_incl(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type); grec_type);
br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE); br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE);
changed = true; changed = true;
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
changed = __grp_src_isexc_excl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_isexc_excl(brmctx, pg, h_addr, srcs, nsrcs,
grec_type); addr_size, grec_type);
break; break;
} }
pg->filter_mode = MCAST_EXCLUDE; pg->filter_mode = MCAST_EXCLUDE;
mod_timer(&pg->timer, jiffies + br_multicast_gmi(br)); mod_timer(&pg->timer, jiffies + br_multicast_gmi(brmctx));
return changed; return changed;
} }
...@@ -2057,11 +2077,12 @@ static bool br_multicast_isexc(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2057,11 +2077,12 @@ static bool br_multicast_isexc(struct net_bridge_port_group *pg, void *h_addr,
* INCLUDE (A) TO_IN (B) INCLUDE (A+B) (B)=GMI * INCLUDE (A) TO_IN (B) INCLUDE (A+B) (B)=GMI
* Send Q(G,A-B) * Send Q(G,A-B)
*/ */
static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, void *h_addr, static bool __grp_src_toin_incl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
u32 src_idx, to_send = pg->src_ents; u32 src_idx, to_send = pg->src_ents;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
unsigned long now = jiffies; unsigned long now = jiffies;
...@@ -2085,14 +2106,15 @@ static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2085,14 +2106,15 @@ static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, void *h_addr,
changed = true; changed = true;
} }
if (ent) if (ent)
__grp_src_mod_timer(ent, now + br_multicast_gmi(br)); __grp_src_mod_timer(ent, now + br_multicast_gmi(brmctx));
} }
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
return changed; return changed;
} }
...@@ -2102,11 +2124,12 @@ static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2102,11 +2124,12 @@ static bool __grp_src_toin_incl(struct net_bridge_port_group *pg, void *h_addr,
* Send Q(G,X-A) * Send Q(G,X-A)
* Send Q(G) * Send Q(G)
*/ */
static bool __grp_src_toin_excl(struct net_bridge_port_group *pg, void *h_addr, static bool __grp_src_toin_excl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
u32 src_idx, to_send = pg->src_ents; u32 src_idx, to_send = pg->src_ents;
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
unsigned long now = jiffies; unsigned long now = jiffies;
...@@ -2133,21 +2156,24 @@ static bool __grp_src_toin_excl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2133,21 +2156,24 @@ static bool __grp_src_toin_excl(struct net_bridge_port_group *pg, void *h_addr,
changed = true; changed = true;
} }
if (ent) if (ent)
__grp_src_mod_timer(ent, now + br_multicast_gmi(br)); __grp_src_mod_timer(ent, now + br_multicast_gmi(brmctx));
} }
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
__grp_send_query_and_rexmit(pg); __grp_send_query_and_rexmit(brmctx, pmctx, pg);
return changed; return changed;
} }
static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr, static bool br_multicast_toin(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
...@@ -2155,12 +2181,12 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2155,12 +2181,12 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr,
switch (pg->filter_mode) { switch (pg->filter_mode) {
case MCAST_INCLUDE: case MCAST_INCLUDE:
changed = __grp_src_toin_incl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_toin_incl(brmctx, pmctx, pg, h_addr, srcs,
grec_type); nsrcs, addr_size, grec_type);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
changed = __grp_src_toin_excl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_toin_excl(brmctx, pmctx, pg, h_addr, srcs,
grec_type); nsrcs, addr_size, grec_type);
break; break;
} }
...@@ -2182,7 +2208,9 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2182,7 +2208,9 @@ static bool br_multicast_toin(struct net_bridge_port_group *pg, void *h_addr,
* Send Q(G,A*B) * Send Q(G,A*B)
* Group Timer=GMI * Group Timer=GMI
*/ */
static void __grp_src_toex_incl(struct net_bridge_port_group *pg, void *h_addr, static void __grp_src_toex_incl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
...@@ -2209,11 +2237,12 @@ static void __grp_src_toex_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2209,11 +2237,12 @@ static void __grp_src_toex_incl(struct net_bridge_port_group *pg, void *h_addr,
br_multicast_fwd_src_handle(ent); br_multicast_fwd_src_handle(ent);
} }
br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type); br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type);
__grp_src_delete_marked(pg); __grp_src_delete_marked(pg);
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
} }
/* State Msg type New state Actions /* State Msg type New state Actions
...@@ -2223,7 +2252,9 @@ static void __grp_src_toex_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2223,7 +2252,9 @@ static void __grp_src_toex_incl(struct net_bridge_port_group *pg, void *h_addr,
* Send Q(G,A-Y) * Send Q(G,A-Y)
* Group Timer=GMI * Group Timer=GMI
*/ */
static bool __grp_src_toex_excl(struct net_bridge_port_group *pg, void *h_addr, static bool __grp_src_toex_excl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
...@@ -2255,39 +2286,41 @@ static bool __grp_src_toex_excl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2255,39 +2286,41 @@ static bool __grp_src_toex_excl(struct net_bridge_port_group *pg, void *h_addr,
} }
} }
if (br_multicast_eht_handle(pg, h_addr, srcs, nsrcs, addr_size, grec_type)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (__grp_src_delete_marked(pg)) if (__grp_src_delete_marked(pg))
changed = true; changed = true;
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
return changed; return changed;
} }
static bool br_multicast_toex(struct net_bridge_port_group *pg, void *h_addr, static bool br_multicast_toex(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
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) int grec_type)
{ {
struct net_bridge *br = pg->key.port->br;
bool changed = false; bool changed = false;
switch (pg->filter_mode) { switch (pg->filter_mode) {
case MCAST_INCLUDE: case MCAST_INCLUDE:
__grp_src_toex_incl(pg, h_addr, srcs, nsrcs, addr_size, __grp_src_toex_incl(brmctx, pmctx, pg, h_addr, srcs, nsrcs,
grec_type); addr_size, grec_type);
br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE); br_multicast_star_g_handle_mode(pg, MCAST_EXCLUDE);
changed = true; changed = true;
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
changed = __grp_src_toex_excl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_toex_excl(brmctx, pmctx, pg, h_addr, srcs,
grec_type); nsrcs, addr_size, grec_type);
break; break;
} }
pg->filter_mode = MCAST_EXCLUDE; pg->filter_mode = MCAST_EXCLUDE;
mod_timer(&pg->timer, jiffies + br_multicast_gmi(br)); mod_timer(&pg->timer, jiffies + br_multicast_gmi(brmctx));
return changed; return changed;
} }
...@@ -2295,7 +2328,9 @@ static bool br_multicast_toex(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2295,7 +2328,9 @@ static bool br_multicast_toex(struct net_bridge_port_group *pg, void *h_addr,
/* State Msg type New state Actions /* State Msg type New state Actions
* INCLUDE (A) BLOCK (B) INCLUDE (A) Send Q(G,A*B) * 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, static bool __grp_src_block_incl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size, int grec_type) void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{ {
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
...@@ -2317,11 +2352,12 @@ static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2317,11 +2352,12 @@ 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)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
return changed; return changed;
} }
...@@ -2330,7 +2366,9 @@ static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2330,7 +2366,9 @@ static bool __grp_src_block_incl(struct net_bridge_port_group *pg, void *h_addr,
* EXCLUDE (X,Y) BLOCK (A) EXCLUDE (X+(A-Y),Y) (A-X-Y)=Group Timer * EXCLUDE (X,Y) BLOCK (A) EXCLUDE (X+(A-Y),Y) (A-X-Y)=Group Timer
* Send Q(G,A-Y) * Send Q(G,A-Y)
*/ */
static bool __grp_src_block_excl(struct net_bridge_port_group *pg, void *h_addr, static bool __grp_src_block_excl(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size, int grec_type) void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{ {
struct net_bridge_group_src *ent; struct net_bridge_group_src *ent;
...@@ -2359,28 +2397,31 @@ static bool __grp_src_block_excl(struct net_bridge_port_group *pg, void *h_addr, ...@@ -2359,28 +2397,31 @@ 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)) if (br_multicast_eht_handle(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
grec_type))
changed = true; changed = true;
if (to_send) if (to_send)
__grp_src_query_marked_and_rexmit(pg); __grp_src_query_marked_and_rexmit(brmctx, pmctx, pg);
return changed; return changed;
} }
static bool br_multicast_block(struct net_bridge_port_group *pg, void *h_addr, static bool br_multicast_block(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct net_bridge_port_group *pg, void *h_addr,
void *srcs, u32 nsrcs, size_t addr_size, int grec_type) void *srcs, u32 nsrcs, size_t addr_size, int grec_type)
{ {
bool changed = false; bool changed = false;
switch (pg->filter_mode) { switch (pg->filter_mode) {
case MCAST_INCLUDE: case MCAST_INCLUDE:
changed = __grp_src_block_incl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_block_incl(brmctx, pmctx, pg, h_addr, srcs,
grec_type); nsrcs, addr_size, grec_type);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
changed = __grp_src_block_excl(pg, h_addr, srcs, nsrcs, addr_size, changed = __grp_src_block_excl(brmctx, pmctx, pg, h_addr, srcs,
grec_type); nsrcs, addr_size, grec_type);
break; break;
} }
...@@ -2415,12 +2456,12 @@ br_multicast_find_port(struct net_bridge_mdb_entry *mp, ...@@ -2415,12 +2456,12 @@ br_multicast_find_port(struct net_bridge_mdb_entry *mp,
return NULL; return NULL;
} }
static int br_ip4_multicast_igmp3_report(struct net_bridge *br, static int br_ip4_multicast_igmp3_report(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
bool igmpv2 = br->multicast_ctx.multicast_igmp_version == 2; bool igmpv2 = brmctx->multicast_igmp_version == 2;
struct net_bridge_mdb_entry *mdst; struct net_bridge_mdb_entry *mdst;
struct net_bridge_port_group *pg; struct net_bridge_port_group *pg;
const unsigned char *src; const unsigned char *src;
...@@ -2467,25 +2508,26 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, ...@@ -2467,25 +2508,26 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
if (nsrcs == 0 && if (nsrcs == 0 &&
(type == IGMPV3_CHANGE_TO_INCLUDE || (type == IGMPV3_CHANGE_TO_INCLUDE ||
type == IGMPV3_MODE_IS_INCLUDE)) { type == IGMPV3_MODE_IS_INCLUDE)) {
if (!port || igmpv2) { if (!pmctx || igmpv2) {
br_ip4_multicast_leave_group(br, port, group, vid, src); br_ip4_multicast_leave_group(brmctx, pmctx,
group, vid, src);
continue; continue;
} }
} else { } else {
err = br_ip4_multicast_add_group(br, port, group, vid, err = br_ip4_multicast_add_group(brmctx, pmctx, group,
src, igmpv2); vid, src, igmpv2);
if (err) if (err)
break; break;
} }
if (!port || igmpv2) if (!pmctx || igmpv2)
continue; continue;
spin_lock_bh(&br->multicast_lock); spin_lock_bh(&brmctx->br->multicast_lock);
mdst = br_mdb_ip4_get(br, group, vid); mdst = br_mdb_ip4_get(brmctx->br, group, vid);
if (!mdst) if (!mdst)
goto unlock_continue; goto unlock_continue;
pg = br_multicast_find_port(mdst, port, src); pg = br_multicast_find_port(mdst, pmctx->port, src);
if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT)) if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT))
goto unlock_continue; goto unlock_continue;
/* reload grec and host addr */ /* reload grec and host addr */
...@@ -2493,46 +2535,52 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, ...@@ -2493,46 +2535,52 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
h_addr = &ip_hdr(skb)->saddr; h_addr = &ip_hdr(skb)->saddr;
switch (type) { switch (type) {
case IGMPV3_ALLOW_NEW_SOURCES: case IGMPV3_ALLOW_NEW_SOURCES:
changed = br_multicast_isinc_allow(pg, h_addr, grec->grec_src, changed = br_multicast_isinc_allow(brmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
case IGMPV3_MODE_IS_INCLUDE: case IGMPV3_MODE_IS_INCLUDE:
changed = br_multicast_isinc_allow(pg, h_addr, grec->grec_src, changed = br_multicast_isinc_allow(brmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
case IGMPV3_MODE_IS_EXCLUDE: case IGMPV3_MODE_IS_EXCLUDE:
changed = br_multicast_isexc(pg, h_addr, grec->grec_src, changed = br_multicast_isexc(brmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
case IGMPV3_CHANGE_TO_INCLUDE: case IGMPV3_CHANGE_TO_INCLUDE:
changed = br_multicast_toin(pg, h_addr, grec->grec_src, changed = br_multicast_toin(brmctx, pmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
case IGMPV3_CHANGE_TO_EXCLUDE: case IGMPV3_CHANGE_TO_EXCLUDE:
changed = br_multicast_toex(pg, h_addr, grec->grec_src, changed = br_multicast_toex(brmctx, pmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
case IGMPV3_BLOCK_OLD_SOURCES: case IGMPV3_BLOCK_OLD_SOURCES:
changed = br_multicast_block(pg, h_addr, grec->grec_src, changed = br_multicast_block(brmctx, pmctx, pg, h_addr,
grec->grec_src,
nsrcs, sizeof(__be32), type); nsrcs, sizeof(__be32), type);
break; break;
} }
if (changed) if (changed)
br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB); br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_NEWMDB);
unlock_continue: unlock_continue:
spin_unlock_bh(&br->multicast_lock); spin_unlock_bh(&brmctx->br->multicast_lock);
} }
return err; return err;
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_mld2_report(struct net_bridge *br, static int br_ip6_multicast_mld2_report(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
bool mldv1 = br->multicast_ctx.multicast_mld_version == 1; bool mldv1 = brmctx->multicast_mld_version == 1;
struct net_bridge_mdb_entry *mdst; struct net_bridge_mdb_entry *mdst;
struct net_bridge_port_group *pg; struct net_bridge_port_group *pg;
unsigned int nsrcs_offset; unsigned int nsrcs_offset;
...@@ -2593,85 +2641,83 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, ...@@ -2593,85 +2641,83 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE || if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
grec->grec_type == MLD2_MODE_IS_INCLUDE) && grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
nsrcs == 0) { nsrcs == 0) {
if (!port || mldv1) { if (!pmctx || mldv1) {
br_ip6_multicast_leave_group(br, port, br_ip6_multicast_leave_group(brmctx, pmctx,
&grec->grec_mca, &grec->grec_mca,
vid, src); vid, src);
continue; continue;
} }
} else { } else {
err = br_ip6_multicast_add_group(br, port, err = br_ip6_multicast_add_group(brmctx, pmctx,
&grec->grec_mca, vid, &grec->grec_mca, vid,
src, mldv1); src, mldv1);
if (err) if (err)
break; break;
} }
if (!port || mldv1) if (!pmctx || mldv1)
continue; continue;
spin_lock_bh(&br->multicast_lock); spin_lock_bh(&brmctx->br->multicast_lock);
mdst = br_mdb_ip6_get(br, &grec->grec_mca, vid); mdst = br_mdb_ip6_get(brmctx->br, &grec->grec_mca, vid);
if (!mdst) if (!mdst)
goto unlock_continue; goto unlock_continue;
pg = br_multicast_find_port(mdst, port, src); pg = br_multicast_find_port(mdst, pmctx->port, src);
if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT)) if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT))
goto unlock_continue; goto unlock_continue;
h_addr = &ipv6_hdr(skb)->saddr; h_addr = &ipv6_hdr(skb)->saddr;
switch (grec->grec_type) { switch (grec->grec_type) {
case MLD2_ALLOW_NEW_SOURCES: case MLD2_ALLOW_NEW_SOURCES:
changed = br_multicast_isinc_allow(pg, h_addr, changed = br_multicast_isinc_allow(brmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
case MLD2_MODE_IS_INCLUDE: case MLD2_MODE_IS_INCLUDE:
changed = br_multicast_isinc_allow(pg, h_addr, changed = br_multicast_isinc_allow(brmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
case MLD2_MODE_IS_EXCLUDE: case MLD2_MODE_IS_EXCLUDE:
changed = br_multicast_isexc(pg, h_addr, changed = br_multicast_isexc(brmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
case MLD2_CHANGE_TO_INCLUDE: case MLD2_CHANGE_TO_INCLUDE:
changed = br_multicast_toin(pg, h_addr, changed = br_multicast_toin(brmctx, pmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
case MLD2_CHANGE_TO_EXCLUDE: case MLD2_CHANGE_TO_EXCLUDE:
changed = br_multicast_toex(pg, h_addr, changed = br_multicast_toex(brmctx, pmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
case MLD2_BLOCK_OLD_SOURCES: case MLD2_BLOCK_OLD_SOURCES:
changed = br_multicast_block(pg, h_addr, changed = br_multicast_block(brmctx, pmctx, pg, h_addr,
grec->grec_src, nsrcs, grec->grec_src, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
grec->grec_type); grec->grec_type);
break; break;
} }
if (changed) if (changed)
br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB); br_mdb_notify(brmctx->br->dev, mdst, pg, RTM_NEWMDB);
unlock_continue: unlock_continue:
spin_unlock_bh(&br->multicast_lock); spin_unlock_bh(&brmctx->br->multicast_lock);
} }
return err; return err;
} }
#endif #endif
static bool br_ip4_multicast_select_querier(struct net_bridge *br, static bool br_ip4_multicast_select_querier(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_port *port,
__be32 saddr) __be32 saddr)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
if (!timer_pending(&brmctx->ip4_own_query.timer) && if (!timer_pending(&brmctx->ip4_own_query.timer) &&
!timer_pending(&brmctx->ip4_other_query.timer)) !timer_pending(&brmctx->ip4_other_query.timer))
goto update; goto update;
...@@ -2694,12 +2740,10 @@ static bool br_ip4_multicast_select_querier(struct net_bridge *br, ...@@ -2694,12 +2740,10 @@ static bool br_ip4_multicast_select_querier(struct net_bridge *br,
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static bool br_ip6_multicast_select_querier(struct net_bridge *br, static bool br_ip6_multicast_select_querier(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_port *port,
struct in6_addr *saddr) struct in6_addr *saddr)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
if (!timer_pending(&brmctx->ip6_own_query.timer) && if (!timer_pending(&brmctx->ip6_own_query.timer) &&
!timer_pending(&brmctx->ip6_other_query.timer)) !timer_pending(&brmctx->ip6_other_query.timer))
goto update; goto update;
...@@ -2720,15 +2764,14 @@ static bool br_ip6_multicast_select_querier(struct net_bridge *br, ...@@ -2720,15 +2764,14 @@ static bool br_ip6_multicast_select_querier(struct net_bridge *br,
#endif #endif
static void static void
br_multicast_update_query_timer(struct net_bridge *br, br_multicast_update_query_timer(struct net_bridge_mcast *brmctx,
struct bridge_mcast_other_query *query, struct bridge_mcast_other_query *query,
unsigned long max_delay) unsigned long max_delay)
{ {
if (!timer_pending(&query->timer)) if (!timer_pending(&query->timer))
query->delay_time = jiffies + max_delay; query->delay_time = jiffies + max_delay;
mod_timer(&query->timer, jiffies + mod_timer(&query->timer, jiffies + brmctx->multicast_querier_interval);
br->multicast_ctx.multicast_querier_interval);
} }
static void br_port_mc_router_state_change(struct net_bridge_port *p, static void br_port_mc_router_state_change(struct net_bridge_port *p,
...@@ -2785,14 +2828,14 @@ br_multicast_get_rport_slot(struct net_bridge_mcast *brmctx, ...@@ -2785,14 +2828,14 @@ br_multicast_get_rport_slot(struct net_bridge_mcast *brmctx,
return slot; return slot;
} }
static bool br_multicast_no_router_otherpf(struct net_bridge_port *port, static bool br_multicast_no_router_otherpf(struct net_bridge_mcast_port *pmctx,
struct hlist_node *rnode) struct hlist_node *rnode)
{ {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (rnode != &port->multicast_ctx.ip6_rlist) if (rnode != &pmctx->ip6_rlist)
return hlist_unhashed(&port->multicast_ctx.ip6_rlist); return hlist_unhashed(&pmctx->ip6_rlist);
else else
return hlist_unhashed(&port->multicast_ctx.ip4_rlist); return hlist_unhashed(&pmctx->ip4_rlist);
#else #else
return true; return true;
#endif #endif
...@@ -2803,7 +2846,7 @@ static bool br_multicast_no_router_otherpf(struct net_bridge_port *port, ...@@ -2803,7 +2846,7 @@ static bool br_multicast_no_router_otherpf(struct net_bridge_port *port,
* and locked by br->multicast_lock and RCU * and locked by br->multicast_lock and RCU
*/ */
static void br_multicast_add_router(struct net_bridge_mcast *brmctx, static void br_multicast_add_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct hlist_node *rlist, struct hlist_node *rlist,
struct hlist_head *mc_router_list) struct hlist_head *mc_router_list)
{ {
...@@ -2812,7 +2855,7 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx, ...@@ -2812,7 +2855,7 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx,
if (!hlist_unhashed(rlist)) if (!hlist_unhashed(rlist))
return; return;
slot = br_multicast_get_rport_slot(brmctx, port, mc_router_list); slot = br_multicast_get_rport_slot(brmctx, pmctx->port, mc_router_list);
if (slot) if (slot)
hlist_add_behind_rcu(rlist, slot); hlist_add_behind_rcu(rlist, slot);
...@@ -2823,9 +2866,9 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx, ...@@ -2823,9 +2866,9 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx,
* switched from no IPv4/IPv6 multicast router to a new * switched from no IPv4/IPv6 multicast router to a new
* IPv4 or IPv6 multicast router. * IPv4 or IPv6 multicast router.
*/ */
if (br_multicast_no_router_otherpf(port, rlist)) { if (br_multicast_no_router_otherpf(pmctx, rlist)) {
br_rtr_notify(port->br->dev, port, RTM_NEWMDB); br_rtr_notify(pmctx->port->br->dev, pmctx->port, RTM_NEWMDB);
br_port_mc_router_state_change(port, true); br_port_mc_router_state_change(pmctx->port, true);
} }
} }
...@@ -2833,123 +2876,119 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx, ...@@ -2833,123 +2876,119 @@ static void br_multicast_add_router(struct net_bridge_mcast *brmctx,
* list is maintained ordered by pointer value * list is maintained ordered by pointer value
* and locked by br->multicast_lock and RCU * and locked by br->multicast_lock and RCU
*/ */
static void br_ip4_multicast_add_router(struct net_bridge *br, static void br_ip4_multicast_add_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port) struct net_bridge_mcast_port *pmctx)
{ {
br_multicast_add_router(&br->multicast_ctx, port, br_multicast_add_router(brmctx, pmctx, &pmctx->ip4_rlist,
&port->multicast_ctx.ip4_rlist, &brmctx->ip4_mc_router_list);
&br->multicast_ctx.ip4_mc_router_list);
} }
/* Add port to router_list /* Add port to router_list
* list is maintained ordered by pointer value * list is maintained ordered by pointer value
* and locked by br->multicast_lock and RCU * and locked by br->multicast_lock and RCU
*/ */
static void br_ip6_multicast_add_router(struct net_bridge *br, static void br_ip6_multicast_add_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port) struct net_bridge_mcast_port *pmctx)
{ {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
br_multicast_add_router(&br->multicast_ctx, port, br_multicast_add_router(brmctx, pmctx, &pmctx->ip6_rlist,
&port->multicast_ctx.ip6_rlist, &brmctx->ip6_mc_router_list);
&br->multicast_ctx.ip6_mc_router_list);
#endif #endif
} }
static void br_multicast_mark_router(struct net_bridge *br, static void br_multicast_mark_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct timer_list *timer, struct timer_list *timer,
struct hlist_node *rlist, struct hlist_node *rlist,
struct hlist_head *mc_router_list) struct hlist_head *mc_router_list)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
unsigned long now = jiffies; unsigned long now = jiffies;
if (!port) { if (!pmctx) {
if (brmctx->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) { if (brmctx->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) {
if (!br_ip4_multicast_is_router(brmctx) && if (!br_ip4_multicast_is_router(brmctx) &&
!br_ip6_multicast_is_router(brmctx)) !br_ip6_multicast_is_router(brmctx))
br_mc_router_state_change(br, true); br_mc_router_state_change(brmctx->br, true);
mod_timer(timer, now + brmctx->multicast_querier_interval); mod_timer(timer, now + brmctx->multicast_querier_interval);
} }
return; return;
} }
if (port->multicast_ctx.multicast_router == MDB_RTR_TYPE_DISABLED || if (pmctx->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_ctx.multicast_router == MDB_RTR_TYPE_PERM) pmctx->multicast_router == MDB_RTR_TYPE_PERM)
return; return;
br_multicast_add_router(brmctx, port, rlist, mc_router_list); br_multicast_add_router(brmctx, pmctx, rlist, mc_router_list);
mod_timer(timer, now + brmctx->multicast_querier_interval); mod_timer(timer, now + brmctx->multicast_querier_interval);
} }
static void br_ip4_multicast_mark_router(struct net_bridge *br, static void br_ip4_multicast_mark_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port) struct net_bridge_mcast_port *pmctx)
{ {
struct timer_list *timer = &br->multicast_ctx.ip4_mc_router_timer; struct timer_list *timer = &brmctx->ip4_mc_router_timer;
struct hlist_node *rlist = NULL; struct hlist_node *rlist = NULL;
if (port) { if (pmctx) {
timer = &port->multicast_ctx.ip4_mc_router_timer; timer = &pmctx->ip4_mc_router_timer;
rlist = &port->multicast_ctx.ip4_rlist; rlist = &pmctx->ip4_rlist;
} }
br_multicast_mark_router(br, port, timer, rlist, br_multicast_mark_router(brmctx, pmctx, timer, rlist,
&br->multicast_ctx.ip4_mc_router_list); &brmctx->ip4_mc_router_list);
} }
static void br_ip6_multicast_mark_router(struct net_bridge *br, static void br_ip6_multicast_mark_router(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port) struct net_bridge_mcast_port *pmctx)
{ {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
struct timer_list *timer = &br->multicast_ctx.ip6_mc_router_timer; struct timer_list *timer = &brmctx->ip6_mc_router_timer;
struct hlist_node *rlist = NULL; struct hlist_node *rlist = NULL;
if (port) { if (pmctx) {
timer = &port->multicast_ctx.ip6_mc_router_timer; timer = &pmctx->ip6_mc_router_timer;
rlist = &port->multicast_ctx.ip6_rlist; rlist = &pmctx->ip6_rlist;
} }
br_multicast_mark_router(br, port, timer, rlist, br_multicast_mark_router(brmctx, pmctx, timer, rlist,
&br->multicast_ctx.ip6_mc_router_list); &brmctx->ip6_mc_router_list);
#endif #endif
} }
static void static void
br_ip4_multicast_query_received(struct net_bridge *br, br_ip4_multicast_query_received(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct bridge_mcast_other_query *query, struct bridge_mcast_other_query *query,
struct br_ip *saddr, struct br_ip *saddr,
unsigned long max_delay) unsigned long max_delay)
{ {
if (!br_ip4_multicast_select_querier(br, port, saddr->src.ip4)) if (!br_ip4_multicast_select_querier(brmctx, pmctx->port, saddr->src.ip4))
return; return;
br_multicast_update_query_timer(br, query, max_delay); br_multicast_update_query_timer(brmctx, query, max_delay);
br_ip4_multicast_mark_router(br, port); br_ip4_multicast_mark_router(brmctx, pmctx);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static void static void
br_ip6_multicast_query_received(struct net_bridge *br, br_ip6_multicast_query_received(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct bridge_mcast_other_query *query, struct bridge_mcast_other_query *query,
struct br_ip *saddr, struct br_ip *saddr,
unsigned long max_delay) unsigned long max_delay)
{ {
if (!br_ip6_multicast_select_querier(br, port, &saddr->src.ip6)) if (!br_ip6_multicast_select_querier(brmctx, pmctx->port, &saddr->src.ip6))
return; return;
br_multicast_update_query_timer(br, query, max_delay); br_multicast_update_query_timer(brmctx, query, max_delay);
br_ip6_multicast_mark_router(br, port); br_ip6_multicast_mark_router(brmctx, pmctx);
} }
#endif #endif
static void br_ip4_multicast_query(struct net_bridge *br, static void br_ip4_multicast_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
unsigned int transport_len = ip_transport_len(skb); unsigned int transport_len = ip_transport_len(skb);
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
struct igmphdr *ih = igmp_hdr(skb); struct igmphdr *ih = igmp_hdr(skb);
...@@ -2962,9 +3001,9 @@ static void br_ip4_multicast_query(struct net_bridge *br, ...@@ -2962,9 +3001,9 @@ static void br_ip4_multicast_query(struct net_bridge *br,
unsigned long now = jiffies; unsigned long now = jiffies;
__be32 group; __be32 group;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
(port && port->state == BR_STATE_DISABLED)) (pmctx && pmctx->port->state == BR_STATE_DISABLED))
goto out; goto out;
group = ih->group; group = ih->group;
...@@ -2993,13 +3032,13 @@ static void br_ip4_multicast_query(struct net_bridge *br, ...@@ -2993,13 +3032,13 @@ static void br_ip4_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IP); saddr.proto = htons(ETH_P_IP);
saddr.src.ip4 = iph->saddr; saddr.src.ip4 = iph->saddr;
br_ip4_multicast_query_received(br, port, br_ip4_multicast_query_received(brmctx, pmctx,
&brmctx->ip4_other_query, &brmctx->ip4_other_query,
&saddr, max_delay); &saddr, max_delay);
goto out; goto out;
} }
mp = br_mdb_ip4_get(br, group, vid); mp = br_mdb_ip4_get(brmctx->br, group, vid);
if (!mp) if (!mp)
goto out; goto out;
...@@ -3012,7 +3051,7 @@ static void br_ip4_multicast_query(struct net_bridge *br, ...@@ -3012,7 +3051,7 @@ static void br_ip4_multicast_query(struct net_bridge *br,
mod_timer(&mp->timer, now + max_delay); mod_timer(&mp->timer, now + max_delay);
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, brmctx->br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (timer_pending(&p->timer) ? if (timer_pending(&p->timer) ?
time_after(p->timer.expires, now + max_delay) : time_after(p->timer.expires, now + max_delay) :
...@@ -3023,16 +3062,15 @@ static void br_ip4_multicast_query(struct net_bridge *br, ...@@ -3023,16 +3062,15 @@ static void br_ip4_multicast_query(struct net_bridge *br,
} }
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_query(struct net_bridge *br, static int br_ip6_multicast_query(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
unsigned int transport_len = ipv6_transport_len(skb); unsigned int transport_len = ipv6_transport_len(skb);
struct mld_msg *mld; struct mld_msg *mld;
struct net_bridge_mdb_entry *mp; struct net_bridge_mdb_entry *mp;
...@@ -3047,9 +3085,9 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -3047,9 +3085,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
bool is_general_query; bool is_general_query;
int err = 0; int err = 0;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
(port && port->state == BR_STATE_DISABLED)) (pmctx && pmctx->port->state == BR_STATE_DISABLED))
goto out; goto out;
if (transport_len == sizeof(*mld)) { if (transport_len == sizeof(*mld)) {
...@@ -3083,7 +3121,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -3083,7 +3121,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IPV6); saddr.proto = htons(ETH_P_IPV6);
saddr.src.ip6 = ipv6_hdr(skb)->saddr; saddr.src.ip6 = ipv6_hdr(skb)->saddr;
br_ip6_multicast_query_received(br, port, br_ip6_multicast_query_received(brmctx, pmctx,
&brmctx->ip6_other_query, &brmctx->ip6_other_query,
&saddr, max_delay); &saddr, max_delay);
goto out; goto out;
...@@ -3091,7 +3129,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -3091,7 +3129,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
goto out; goto out;
} }
mp = br_mdb_ip6_get(br, group, vid); mp = br_mdb_ip6_get(brmctx->br, group, vid);
if (!mp) if (!mp)
goto out; goto out;
...@@ -3103,7 +3141,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -3103,7 +3141,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
mod_timer(&mp->timer, now + max_delay); mod_timer(&mp->timer, now + max_delay);
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, brmctx->br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (timer_pending(&p->timer) ? if (timer_pending(&p->timer) ?
time_after(p->timer.expires, now + max_delay) : time_after(p->timer.expires, now + max_delay) :
...@@ -3114,41 +3152,40 @@ static int br_ip6_multicast_query(struct net_bridge *br, ...@@ -3114,41 +3152,40 @@ static int br_ip6_multicast_query(struct net_bridge *br,
} }
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
return err; return err;
} }
#endif #endif
static void static void
br_multicast_leave_group(struct net_bridge *br, br_multicast_leave_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct br_ip *group, struct br_ip *group,
struct bridge_mcast_other_query *other_query, struct bridge_mcast_other_query *other_query,
struct bridge_mcast_own_query *own_query, struct bridge_mcast_own_query *own_query,
const unsigned char *src) const unsigned char *src)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
struct net_bridge_mdb_entry *mp; struct net_bridge_mdb_entry *mp;
struct net_bridge_port_group *p; struct net_bridge_port_group *p;
unsigned long now; unsigned long now;
unsigned long time; unsigned long time;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
if (!netif_running(br->dev) || if (!netif_running(brmctx->br->dev) ||
(port && port->state == BR_STATE_DISABLED)) (pmctx && pmctx->port->state == BR_STATE_DISABLED))
goto out; goto out;
mp = br_mdb_ip_get(br, group); mp = br_mdb_ip_get(brmctx->br, group);
if (!mp) if (!mp)
goto out; goto out;
if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) { if (pmctx && (pmctx->port->flags & BR_MULTICAST_FAST_LEAVE)) {
struct net_bridge_port_group __rcu **pp; struct net_bridge_port_group __rcu **pp;
for (pp = &mp->ports; for (pp = &mp->ports;
(p = mlock_dereference(*pp, br)) != NULL; (p = mlock_dereference(*pp, brmctx->br)) != NULL;
pp = &p->next) { pp = &p->next) {
if (!br_port_group_equal(p, port, src)) if (!br_port_group_equal(p, pmctx->port, src))
continue; continue;
if (p->flags & MDB_PG_FLAGS_PERMANENT) if (p->flags & MDB_PG_FLAGS_PERMANENT)
...@@ -3163,8 +3200,8 @@ br_multicast_leave_group(struct net_bridge *br, ...@@ -3163,8 +3200,8 @@ br_multicast_leave_group(struct net_bridge *br,
if (timer_pending(&other_query->timer)) if (timer_pending(&other_query->timer))
goto out; goto out;
if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER)) {
__br_multicast_send_query(br, port, NULL, NULL, &mp->addr, __br_multicast_send_query(brmctx, pmctx, NULL, NULL, &mp->addr,
false, 0, NULL); false, 0, NULL);
time = jiffies + brmctx->multicast_last_member_count * time = jiffies + brmctx->multicast_last_member_count *
...@@ -3172,10 +3209,10 @@ br_multicast_leave_group(struct net_bridge *br, ...@@ -3172,10 +3209,10 @@ br_multicast_leave_group(struct net_bridge *br,
mod_timer(&own_query->timer, time); mod_timer(&own_query->timer, time);
for (p = mlock_dereference(mp->ports, br); for (p = mlock_dereference(mp->ports, brmctx->br);
p != NULL; p != NULL;
p = mlock_dereference(p->next, br)) { p = mlock_dereference(p->next, brmctx->br)) {
if (!br_port_group_equal(p, port, src)) if (!br_port_group_equal(p, pmctx->port, src))
continue; continue;
if (!hlist_unhashed(&p->mglist) && if (!hlist_unhashed(&p->mglist) &&
...@@ -3193,7 +3230,7 @@ br_multicast_leave_group(struct net_bridge *br, ...@@ -3193,7 +3230,7 @@ br_multicast_leave_group(struct net_bridge *br,
time = now + brmctx->multicast_last_member_count * time = now + brmctx->multicast_last_member_count *
brmctx->multicast_last_member_interval; brmctx->multicast_last_member_interval;
if (!port) { if (!pmctx) {
if (mp->host_joined && if (mp->host_joined &&
(timer_pending(&mp->timer) ? (timer_pending(&mp->timer) ?
time_after(mp->timer.expires, time) : time_after(mp->timer.expires, time) :
...@@ -3204,10 +3241,10 @@ br_multicast_leave_group(struct net_bridge *br, ...@@ -3204,10 +3241,10 @@ br_multicast_leave_group(struct net_bridge *br,
goto out; goto out;
} }
for (p = mlock_dereference(mp->ports, br); for (p = mlock_dereference(mp->ports, brmctx->br);
p != NULL; p != NULL;
p = mlock_dereference(p->next, br)) { p = mlock_dereference(p->next, brmctx->br)) {
if (p->key.port != port) if (p->key.port != pmctx->port)
continue; continue;
if (!hlist_unhashed(&p->mglist) && if (!hlist_unhashed(&p->mglist) &&
...@@ -3220,11 +3257,11 @@ br_multicast_leave_group(struct net_bridge *br, ...@@ -3220,11 +3257,11 @@ br_multicast_leave_group(struct net_bridge *br,
break; break;
} }
out: out:
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
} }
static void br_ip4_multicast_leave_group(struct net_bridge *br, static void br_ip4_multicast_leave_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
__be32 group, __be32 group,
__u16 vid, __u16 vid,
const unsigned char *src) const unsigned char *src)
...@@ -3235,22 +3272,21 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br, ...@@ -3235,22 +3272,21 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
if (ipv4_is_local_multicast(group)) if (ipv4_is_local_multicast(group))
return; return;
own_query = port ? &port->multicast_ctx.ip4_own_query : own_query = pmctx ? &pmctx->ip4_own_query : &brmctx->ip4_own_query;
&br->multicast_ctx.ip4_own_query;
memset(&br_group, 0, sizeof(br_group)); memset(&br_group, 0, sizeof(br_group));
br_group.dst.ip4 = group; br_group.dst.ip4 = group;
br_group.proto = htons(ETH_P_IP); br_group.proto = htons(ETH_P_IP);
br_group.vid = vid; br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group, br_multicast_leave_group(brmctx, pmctx, &br_group,
&br->multicast_ctx.ip4_other_query, &brmctx->ip4_other_query,
own_query, src); own_query, src);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br, static void br_ip6_multicast_leave_group(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
const struct in6_addr *group, const struct in6_addr *group,
__u16 vid, __u16 vid,
const unsigned char *src) const unsigned char *src)
...@@ -3261,16 +3297,15 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br, ...@@ -3261,16 +3297,15 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
if (ipv6_addr_is_ll_all_nodes(group)) if (ipv6_addr_is_ll_all_nodes(group))
return; return;
own_query = port ? &port->multicast_ctx.ip6_own_query : own_query = pmctx ? &pmctx->ip6_own_query : &brmctx->ip6_own_query;
&br->multicast_ctx.ip6_own_query;
memset(&br_group, 0, sizeof(br_group)); memset(&br_group, 0, sizeof(br_group));
br_group.dst.ip6 = *group; br_group.dst.ip6 = *group;
br_group.proto = htons(ETH_P_IPV6); br_group.proto = htons(ETH_P_IPV6);
br_group.vid = vid; br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group, br_multicast_leave_group(brmctx, pmctx, &br_group,
&br->multicast_ctx.ip6_other_query, &brmctx->ip6_other_query,
own_query, src); own_query, src);
} }
#endif #endif
...@@ -3308,8 +3343,8 @@ static void br_multicast_err_count(const struct net_bridge *br, ...@@ -3308,8 +3343,8 @@ static void br_multicast_err_count(const struct net_bridge *br,
u64_stats_update_end(&pstats->syncp); u64_stats_update_end(&pstats->syncp);
} }
static void br_multicast_pim(struct net_bridge *br, static void br_multicast_pim(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
const struct sk_buff *skb) const struct sk_buff *skb)
{ {
unsigned int offset = skb_transport_offset(skb); unsigned int offset = skb_transport_offset(skb);
...@@ -3320,31 +3355,32 @@ static void br_multicast_pim(struct net_bridge *br, ...@@ -3320,31 +3355,32 @@ static void br_multicast_pim(struct net_bridge *br,
pim_hdr_type(pimhdr) != PIM_TYPE_HELLO) pim_hdr_type(pimhdr) != PIM_TYPE_HELLO)
return; return;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
br_ip4_multicast_mark_router(br, port); br_ip4_multicast_mark_router(brmctx, pmctx);
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
} }
static int br_ip4_multicast_mrd_rcv(struct net_bridge *br, static int br_ip4_multicast_mrd_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb) struct sk_buff *skb)
{ {
if (ip_hdr(skb)->protocol != IPPROTO_IGMP || if (ip_hdr(skb)->protocol != IPPROTO_IGMP ||
igmp_hdr(skb)->type != IGMP_MRDISC_ADV) igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
return -ENOMSG; return -ENOMSG;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
br_ip4_multicast_mark_router(br, port); br_ip4_multicast_mark_router(brmctx, pmctx);
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
return 0; return 0;
} }
static int br_multicast_ipv4_rcv(struct net_bridge *br, static int br_multicast_ipv4_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
struct net_bridge_port *p = pmctx ? pmctx->port : NULL;
const unsigned char *src; const unsigned char *src;
struct igmphdr *ih; struct igmphdr *ih;
int err; int err;
...@@ -3356,14 +3392,14 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, ...@@ -3356,14 +3392,14 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) { } else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
if (ip_hdr(skb)->protocol == IPPROTO_PIM) if (ip_hdr(skb)->protocol == IPPROTO_PIM)
br_multicast_pim(br, port, skb); br_multicast_pim(brmctx, pmctx, skb);
} else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) { } else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) {
br_ip4_multicast_mrd_rcv(br, port, skb); br_ip4_multicast_mrd_rcv(brmctx, pmctx, skb);
} }
return 0; return 0;
} else if (err < 0) { } else if (err < 0) {
br_multicast_err_count(br, port, skb->protocol); br_multicast_err_count(brmctx->br, p, skb->protocol);
return err; return err;
} }
...@@ -3375,44 +3411,45 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, ...@@ -3375,44 +3411,45 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV2_HOST_MEMBERSHIP_REPORT:
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
err = br_ip4_multicast_add_group(br, port, ih->group, vid, src, err = br_ip4_multicast_add_group(brmctx, pmctx, ih->group, vid,
true); src, true);
break; break;
case IGMPV3_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT:
err = br_ip4_multicast_igmp3_report(br, port, skb, vid); err = br_ip4_multicast_igmp3_report(brmctx, pmctx, skb, vid);
break; break;
case IGMP_HOST_MEMBERSHIP_QUERY: case IGMP_HOST_MEMBERSHIP_QUERY:
br_ip4_multicast_query(br, port, skb, vid); br_ip4_multicast_query(brmctx, pmctx, skb, vid);
break; break;
case IGMP_HOST_LEAVE_MESSAGE: case IGMP_HOST_LEAVE_MESSAGE:
br_ip4_multicast_leave_group(br, port, ih->group, vid, src); br_ip4_multicast_leave_group(brmctx, pmctx, ih->group, vid, src);
break; break;
} }
br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, br_multicast_count(brmctx->br, p, skb, BR_INPUT_SKB_CB(skb)->igmp,
BR_MCAST_DIR_RX); BR_MCAST_DIR_RX);
return err; return err;
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_mrd_rcv(struct net_bridge *br, static void br_ip6_multicast_mrd_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb) struct sk_buff *skb)
{ {
if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV) if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV)
return; return;
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
br_ip6_multicast_mark_router(br, port); br_ip6_multicast_mark_router(brmctx, pmctx);
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
} }
static int br_multicast_ipv6_rcv(struct net_bridge *br, static int br_multicast_ipv6_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
struct net_bridge_port *p = pmctx ? pmctx->port : NULL;
const unsigned char *src; const unsigned char *src;
struct mld_msg *mld; struct mld_msg *mld;
int err; int err;
...@@ -3424,11 +3461,11 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, ...@@ -3424,11 +3461,11 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
if (err == -ENODATA && if (err == -ENODATA &&
ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr))
br_ip6_multicast_mrd_rcv(br, port, skb); br_ip6_multicast_mrd_rcv(brmctx, pmctx, skb);
return 0; return 0;
} else if (err < 0) { } else if (err < 0) {
br_multicast_err_count(br, port, skb->protocol); br_multicast_err_count(brmctx->br, p, skb->protocol);
return err; return err;
} }
...@@ -3439,29 +3476,31 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, ...@@ -3439,29 +3476,31 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
case ICMPV6_MGM_REPORT: case ICMPV6_MGM_REPORT:
src = eth_hdr(skb)->h_source; src = eth_hdr(skb)->h_source;
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, err = br_ip6_multicast_add_group(brmctx, pmctx, &mld->mld_mca,
src, true); vid, src, true);
break; break;
case ICMPV6_MLD2_REPORT: case ICMPV6_MLD2_REPORT:
err = br_ip6_multicast_mld2_report(br, port, skb, vid); err = br_ip6_multicast_mld2_report(brmctx, pmctx, skb, vid);
break; break;
case ICMPV6_MGM_QUERY: case ICMPV6_MGM_QUERY:
err = br_ip6_multicast_query(br, port, skb, vid); err = br_ip6_multicast_query(brmctx, pmctx, skb, vid);
break; break;
case ICMPV6_MGM_REDUCTION: case ICMPV6_MGM_REDUCTION:
src = eth_hdr(skb)->h_source; src = eth_hdr(skb)->h_source;
br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); br_ip6_multicast_leave_group(brmctx, pmctx, &mld->mld_mca, vid,
src);
break; break;
} }
br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp, br_multicast_count(brmctx->br, p, skb, BR_INPUT_SKB_CB(skb)->igmp,
BR_MCAST_DIR_RX); BR_MCAST_DIR_RX);
return err; return err;
} }
#endif #endif
int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, int br_multicast_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, u16 vid) struct sk_buff *skb, u16 vid)
{ {
int ret = 0; int ret = 0;
...@@ -3469,16 +3508,16 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, ...@@ -3469,16 +3508,16 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
BR_INPUT_SKB_CB(skb)->igmp = 0; BR_INPUT_SKB_CB(skb)->igmp = 0;
BR_INPUT_SKB_CB(skb)->mrouters_only = 0; BR_INPUT_SKB_CB(skb)->mrouters_only = 0;
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) if (!br_opt_get(brmctx->br, BROPT_MULTICAST_ENABLED))
return 0; return 0;
switch (skb->protocol) { switch (skb->protocol) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
ret = br_multicast_ipv4_rcv(br, port, skb, vid); ret = br_multicast_ipv4_rcv(brmctx, pmctx, skb, vid);
break; break;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
ret = br_multicast_ipv6_rcv(br, port, skb, vid); ret = br_multicast_ipv6_rcv(brmctx, pmctx, skb, vid);
break; break;
#endif #endif
} }
...@@ -3486,17 +3525,17 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, ...@@ -3486,17 +3525,17 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
return ret; return ret;
} }
static void br_multicast_query_expired(struct net_bridge *br, static void br_multicast_query_expired(struct net_bridge_mcast *brmctx,
struct bridge_mcast_own_query *query, struct bridge_mcast_own_query *query,
struct bridge_mcast_querier *querier) struct bridge_mcast_querier *querier)
{ {
spin_lock(&br->multicast_lock); spin_lock(&brmctx->br->multicast_lock);
if (query->startup_sent < br->multicast_ctx.multicast_startup_query_count) if (query->startup_sent < brmctx->multicast_startup_query_count)
query->startup_sent++; query->startup_sent++;
RCU_INIT_POINTER(querier->port, NULL); RCU_INIT_POINTER(querier->port, NULL);
br_multicast_send_query(br, NULL, query); br_multicast_send_query(brmctx, NULL, query);
spin_unlock(&br->multicast_lock); spin_unlock(&brmctx->br->multicast_lock);
} }
static void br_ip4_multicast_query_expired(struct timer_list *t) static void br_ip4_multicast_query_expired(struct timer_list *t)
...@@ -3504,7 +3543,7 @@ static void br_ip4_multicast_query_expired(struct timer_list *t) ...@@ -3504,7 +3543,7 @@ static void br_ip4_multicast_query_expired(struct timer_list *t)
struct net_bridge_mcast *brmctx = from_timer(brmctx, t, struct net_bridge_mcast *brmctx = from_timer(brmctx, t,
ip4_own_query.timer); ip4_own_query.timer);
br_multicast_query_expired(brmctx->br, &brmctx->ip4_own_query, br_multicast_query_expired(brmctx, &brmctx->ip4_own_query,
&brmctx->ip4_querier); &brmctx->ip4_querier);
} }
...@@ -3514,7 +3553,7 @@ static void br_ip6_multicast_query_expired(struct timer_list *t) ...@@ -3514,7 +3553,7 @@ static void br_ip6_multicast_query_expired(struct timer_list *t)
struct net_bridge_mcast *brmctx = from_timer(brmctx, t, struct net_bridge_mcast *brmctx = from_timer(brmctx, t,
ip6_own_query.timer); ip6_own_query.timer);
br_multicast_query_expired(brmctx->br, &brmctx->ip6_own_query, br_multicast_query_expired(brmctx, &brmctx->ip6_own_query,
&brmctx->ip6_querier); &brmctx->ip6_querier);
} }
#endif #endif
...@@ -3722,7 +3761,7 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val) ...@@ -3722,7 +3761,7 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
} }
static void static void
br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted) br_multicast_rport_del_notify(struct net_bridge_mcast_port *pmctx, bool deleted)
{ {
if (!deleted) if (!deleted)
return; return;
...@@ -3730,36 +3769,37 @@ br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted) ...@@ -3730,36 +3769,37 @@ br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted)
/* For backwards compatibility for now, only notify if there is /* For backwards compatibility for now, only notify if there is
* no multicast router anymore for both IPv4 and IPv6. * no multicast router anymore for both IPv4 and IPv6.
*/ */
if (!hlist_unhashed(&p->multicast_ctx.ip4_rlist)) if (!hlist_unhashed(&pmctx->ip4_rlist))
return; return;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (!hlist_unhashed(&p->multicast_ctx.ip6_rlist)) if (!hlist_unhashed(&pmctx->ip6_rlist))
return; return;
#endif #endif
br_rtr_notify(p->br->dev, p, RTM_DELMDB); br_rtr_notify(pmctx->port->br->dev, pmctx->port, RTM_DELMDB);
br_port_mc_router_state_change(p, false); br_port_mc_router_state_change(pmctx->port, false);
/* don't allow timer refresh */ /* don't allow timer refresh */
if (p->multicast_ctx.multicast_router == MDB_RTR_TYPE_TEMP) if (pmctx->multicast_router == MDB_RTR_TYPE_TEMP)
p->multicast_ctx.multicast_router = MDB_RTR_TYPE_TEMP_QUERY; pmctx->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
} }
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
{ {
struct net_bridge_mcast *brmctx = &p->br->multicast_ctx; struct net_bridge_mcast *brmctx = &p->br->multicast_ctx;
struct net_bridge_mcast_port *pmctx = &p->multicast_ctx;
unsigned long now = jiffies; unsigned long now = jiffies;
int err = -EINVAL; int err = -EINVAL;
bool del = false; bool del = false;
spin_lock(&p->br->multicast_lock); spin_lock(&p->br->multicast_lock);
if (p->multicast_ctx.multicast_router == val) { if (pmctx->multicast_router == val) {
/* Refresh the temp router port timer */ /* Refresh the temp router port timer */
if (p->multicast_ctx.multicast_router == MDB_RTR_TYPE_TEMP) { if (pmctx->multicast_router == MDB_RTR_TYPE_TEMP) {
mod_timer(&p->multicast_ctx.ip4_mc_router_timer, mod_timer(&pmctx->ip4_mc_router_timer,
now + brmctx->multicast_querier_interval); now + brmctx->multicast_querier_interval);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
mod_timer(&p->multicast_ctx.ip6_mc_router_timer, mod_timer(&pmctx->ip6_mc_router_timer,
now + brmctx->multicast_querier_interval); now + brmctx->multicast_querier_interval);
#endif #endif
} }
...@@ -3768,34 +3808,34 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) ...@@ -3768,34 +3808,34 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
} }
switch (val) { switch (val) {
case MDB_RTR_TYPE_DISABLED: case MDB_RTR_TYPE_DISABLED:
p->multicast_ctx.multicast_router = MDB_RTR_TYPE_DISABLED; pmctx->multicast_router = MDB_RTR_TYPE_DISABLED;
del |= br_ip4_multicast_rport_del(p); del |= br_ip4_multicast_rport_del(pmctx);
del_timer(&p->multicast_ctx.ip4_mc_router_timer); del_timer(&pmctx->ip4_mc_router_timer);
del |= br_ip6_multicast_rport_del(p); del |= br_ip6_multicast_rport_del(pmctx);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
del_timer(&p->multicast_ctx.ip6_mc_router_timer); del_timer(&pmctx->ip6_mc_router_timer);
#endif #endif
br_multicast_rport_del_notify(p, del); br_multicast_rport_del_notify(pmctx, del);
break; break;
case MDB_RTR_TYPE_TEMP_QUERY: case MDB_RTR_TYPE_TEMP_QUERY:
p->multicast_ctx.multicast_router = MDB_RTR_TYPE_TEMP_QUERY; pmctx->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
del |= br_ip4_multicast_rport_del(p); del |= br_ip4_multicast_rport_del(pmctx);
del |= br_ip6_multicast_rport_del(p); del |= br_ip6_multicast_rport_del(pmctx);
br_multicast_rport_del_notify(p, del); br_multicast_rport_del_notify(pmctx, del);
break; break;
case MDB_RTR_TYPE_PERM: case MDB_RTR_TYPE_PERM:
p->multicast_ctx.multicast_router = MDB_RTR_TYPE_PERM; pmctx->multicast_router = MDB_RTR_TYPE_PERM;
del_timer(&p->multicast_ctx.ip4_mc_router_timer); del_timer(&pmctx->ip4_mc_router_timer);
br_ip4_multicast_add_router(p->br, p); br_ip4_multicast_add_router(brmctx, pmctx);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
del_timer(&p->multicast_ctx.ip6_mc_router_timer); del_timer(&pmctx->ip6_mc_router_timer);
#endif #endif
br_ip6_multicast_add_router(p->br, p); br_ip6_multicast_add_router(brmctx, pmctx);
break; break;
case MDB_RTR_TYPE_TEMP: case MDB_RTR_TYPE_TEMP:
p->multicast_ctx.multicast_router = MDB_RTR_TYPE_TEMP; pmctx->multicast_router = MDB_RTR_TYPE_TEMP;
br_ip4_multicast_mark_router(p->br, p); br_ip4_multicast_mark_router(brmctx, pmctx);
br_ip6_multicast_mark_router(p->br, p); br_ip6_multicast_mark_router(brmctx, pmctx);
break; break;
default: default:
goto unlock; goto unlock;
...@@ -3807,20 +3847,20 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) ...@@ -3807,20 +3847,20 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
return err; return err;
} }
static void br_multicast_start_querier(struct net_bridge *br, static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
struct bridge_mcast_own_query *query) struct bridge_mcast_own_query *query)
{ {
struct net_bridge_port *port; struct net_bridge_port *port;
__br_multicast_open(br, query); __br_multicast_open(brmctx->br, query);
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(port, &br->port_list, list) { list_for_each_entry_rcu(port, &brmctx->br->port_list, list) {
if (port->state == BR_STATE_DISABLED || if (port->state == BR_STATE_DISABLED ||
port->state == BR_STATE_BLOCKING) port->state == BR_STATE_BLOCKING)
continue; continue;
if (query == &br->multicast_ctx.ip4_own_query) if (query == &brmctx->ip4_own_query)
br_multicast_enable(&port->multicast_ctx.ip4_own_query); br_multicast_enable(&port->multicast_ctx.ip4_own_query);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
else else
...@@ -3858,7 +3898,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val, ...@@ -3858,7 +3898,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val,
br_multicast_open(br); br_multicast_open(br);
list_for_each_entry(port, &br->port_list, list) list_for_each_entry(port, &br->port_list, list)
__br_multicast_enable_port(port); __br_multicast_enable_port_ctx(&port->multicast_ctx);
change_snoopers = true; change_snoopers = true;
...@@ -3901,7 +3941,7 @@ bool br_multicast_router(const struct net_device *dev) ...@@ -3901,7 +3941,7 @@ bool br_multicast_router(const struct net_device *dev)
bool is_router; bool is_router;
spin_lock_bh(&br->multicast_lock); spin_lock_bh(&br->multicast_lock);
is_router = br_multicast_is_router(br, NULL); is_router = br_multicast_is_router(&br->multicast_ctx, NULL);
spin_unlock_bh(&br->multicast_lock); spin_unlock_bh(&br->multicast_lock);
return is_router; return is_router;
} }
...@@ -3927,13 +3967,13 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val) ...@@ -3927,13 +3967,13 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
if (!timer_pending(&brmctx->ip4_other_query.timer)) if (!timer_pending(&brmctx->ip4_other_query.timer))
brmctx->ip4_other_query.delay_time = jiffies + max_delay; brmctx->ip4_other_query.delay_time = jiffies + max_delay;
br_multicast_start_querier(br, &brmctx->ip4_own_query); br_multicast_start_querier(brmctx, &brmctx->ip4_own_query);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (!timer_pending(&brmctx->ip6_other_query.timer)) if (!timer_pending(&brmctx->ip6_other_query.timer))
brmctx->ip6_other_query.delay_time = jiffies + max_delay; brmctx->ip6_other_query.delay_time = jiffies + max_delay;
br_multicast_start_querier(br, &brmctx->ip6_own_query); br_multicast_start_querier(brmctx, &brmctx->ip6_own_query);
#endif #endif
unlock: unlock:
...@@ -4066,7 +4106,7 @@ bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto) ...@@ -4066,7 +4106,7 @@ bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto)
memset(&eth, 0, sizeof(eth)); memset(&eth, 0, sizeof(eth));
eth.h_proto = htons(proto); eth.h_proto = htons(proto);
ret = br_multicast_querier_exists(br, &eth, NULL); ret = br_multicast_querier_exists(&br->multicast_ctx, &eth, NULL);
unlock: unlock:
rcu_read_unlock(); rcu_read_unlock();
...@@ -4254,7 +4294,8 @@ static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats, ...@@ -4254,7 +4294,8 @@ static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
u64_stats_update_end(&pstats->syncp); u64_stats_update_end(&pstats->syncp);
} }
void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p, void br_multicast_count(struct net_bridge *br,
const struct net_bridge_port *p,
const struct sk_buff *skb, u8 type, u8 dir) const struct sk_buff *skb, u8 type, u8 dir)
{ {
struct bridge_mcast_stats __percpu *stats; struct bridge_mcast_stats __percpu *stats;
......
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg, static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg,
union net_bridge_eht_addr *src_addr, union net_bridge_eht_addr *src_addr,
union net_bridge_eht_addr *h_addr); union net_bridge_eht_addr *h_addr);
static void br_multicast_create_eht_set_entry(struct net_bridge_port_group *pg, static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *src_addr, union net_bridge_eht_addr *src_addr,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
int filter_mode, int filter_mode,
...@@ -388,7 +389,8 @@ static void br_multicast_ip_src_to_eht_addr(const struct br_ip *src, ...@@ -388,7 +389,8 @@ static void br_multicast_ip_src_to_eht_addr(const struct br_ip *src,
} }
} }
static void br_eht_convert_host_filter_mode(struct net_bridge_port_group *pg, static void br_eht_convert_host_filter_mode(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
int filter_mode) int filter_mode)
{ {
...@@ -405,14 +407,15 @@ static void br_eht_convert_host_filter_mode(struct net_bridge_port_group *pg, ...@@ -405,14 +407,15 @@ static void br_eht_convert_host_filter_mode(struct net_bridge_port_group *pg,
br_multicast_del_eht_set_entry(pg, &zero_addr, h_addr); br_multicast_del_eht_set_entry(pg, &zero_addr, h_addr);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
br_multicast_create_eht_set_entry(pg, &zero_addr, h_addr, br_multicast_create_eht_set_entry(brmctx, pg, &zero_addr,
MCAST_EXCLUDE, h_addr, MCAST_EXCLUDE,
true); true);
break; break;
} }
} }
static void br_multicast_create_eht_set_entry(struct net_bridge_port_group *pg, static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *src_addr, union net_bridge_eht_addr *src_addr,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
int filter_mode, int filter_mode,
...@@ -441,8 +444,8 @@ static void br_multicast_create_eht_set_entry(struct net_bridge_port_group *pg, ...@@ -441,8 +444,8 @@ static void br_multicast_create_eht_set_entry(struct net_bridge_port_group *pg,
if (!set_h) if (!set_h)
goto fail_set_entry; goto fail_set_entry;
mod_timer(&set_h->timer, jiffies + br_multicast_gmi(br)); mod_timer(&set_h->timer, jiffies + br_multicast_gmi(brmctx));
mod_timer(&eht_set->timer, jiffies + br_multicast_gmi(br)); mod_timer(&eht_set->timer, jiffies + br_multicast_gmi(brmctx));
return; return;
...@@ -499,7 +502,8 @@ static void br_multicast_del_eht_host(struct net_bridge_port_group *pg, ...@@ -499,7 +502,8 @@ static void br_multicast_del_eht_host(struct net_bridge_port_group *pg,
} }
/* create new set entries from reports */ /* create new set entries from reports */
static void __eht_create_set_entries(struct net_bridge_port_group *pg, static void __eht_create_set_entries(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -512,8 +516,8 @@ static void __eht_create_set_entries(struct net_bridge_port_group *pg, ...@@ -512,8 +516,8 @@ static void __eht_create_set_entries(struct net_bridge_port_group *pg,
memset(&eht_src_addr, 0, sizeof(eht_src_addr)); memset(&eht_src_addr, 0, sizeof(eht_src_addr));
for (src_idx = 0; src_idx < nsrcs; src_idx++) { for (src_idx = 0; src_idx < nsrcs; src_idx++) {
memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size); memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size);
br_multicast_create_eht_set_entry(pg, &eht_src_addr, h_addr, br_multicast_create_eht_set_entry(brmctx, pg, &eht_src_addr,
filter_mode, h_addr, filter_mode,
false); false);
} }
} }
...@@ -549,7 +553,8 @@ static bool __eht_del_set_entries(struct net_bridge_port_group *pg, ...@@ -549,7 +553,8 @@ static bool __eht_del_set_entries(struct net_bridge_port_group *pg,
return changed; return changed;
} }
static bool br_multicast_eht_allow(struct net_bridge_port_group *pg, static bool br_multicast_eht_allow(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -559,8 +564,8 @@ static bool br_multicast_eht_allow(struct net_bridge_port_group *pg, ...@@ -559,8 +564,8 @@ static bool br_multicast_eht_allow(struct net_bridge_port_group *pg,
switch (br_multicast_eht_host_filter_mode(pg, h_addr)) { switch (br_multicast_eht_host_filter_mode(pg, h_addr)) {
case MCAST_INCLUDE: case MCAST_INCLUDE:
__eht_create_set_entries(pg, h_addr, srcs, nsrcs, addr_size, __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs,
MCAST_INCLUDE); addr_size, MCAST_INCLUDE);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs, changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs,
...@@ -571,7 +576,8 @@ static bool br_multicast_eht_allow(struct net_bridge_port_group *pg, ...@@ -571,7 +576,8 @@ static bool br_multicast_eht_allow(struct net_bridge_port_group *pg,
return changed; return changed;
} }
static bool br_multicast_eht_block(struct net_bridge_port_group *pg, static bool br_multicast_eht_block(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -585,7 +591,7 @@ static bool br_multicast_eht_block(struct net_bridge_port_group *pg, ...@@ -585,7 +591,7 @@ static bool br_multicast_eht_block(struct net_bridge_port_group *pg,
addr_size); addr_size);
break; break;
case MCAST_EXCLUDE: case MCAST_EXCLUDE:
__eht_create_set_entries(pg, h_addr, srcs, nsrcs, addr_size, __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
MCAST_EXCLUDE); MCAST_EXCLUDE);
break; break;
} }
...@@ -594,7 +600,8 @@ static bool br_multicast_eht_block(struct net_bridge_port_group *pg, ...@@ -594,7 +600,8 @@ static bool br_multicast_eht_block(struct net_bridge_port_group *pg,
} }
/* flush_entries is true when changing mode */ /* flush_entries is true when changing mode */
static bool __eht_inc_exc(struct net_bridge_port_group *pg, static bool __eht_inc_exc(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -612,11 +619,10 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg, ...@@ -612,11 +619,10 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg,
/* if we're changing mode del host and its entries */ /* if we're changing mode del host and its entries */
if (flush_entries) if (flush_entries)
br_multicast_del_eht_host(pg, h_addr); br_multicast_del_eht_host(pg, h_addr);
__eht_create_set_entries(pg, h_addr, srcs, nsrcs, addr_size, __eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
filter_mode); filter_mode);
/* we can be missing sets only if we've deleted some entries */ /* we can be missing sets only if we've deleted some entries */
if (flush_entries) { if (flush_entries) {
struct net_bridge *br = pg->key.port->br;
struct net_bridge_group_eht_set *eht_set; struct net_bridge_group_eht_set *eht_set;
struct net_bridge_group_src *src_ent; struct net_bridge_group_src *src_ent;
struct hlist_node *tmp; struct hlist_node *tmp;
...@@ -647,14 +653,15 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg, ...@@ -647,14 +653,15 @@ static bool __eht_inc_exc(struct net_bridge_port_group *pg,
&eht_src_addr); &eht_src_addr);
if (!eht_set) if (!eht_set)
continue; continue;
mod_timer(&eht_set->timer, jiffies + br_multicast_lmqt(br)); mod_timer(&eht_set->timer, jiffies + br_multicast_lmqt(brmctx));
} }
} }
return changed; return changed;
} }
static bool br_multicast_eht_inc(struct net_bridge_port_group *pg, static bool br_multicast_eht_inc(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -663,14 +670,15 @@ static bool br_multicast_eht_inc(struct net_bridge_port_group *pg, ...@@ -663,14 +670,15 @@ static bool br_multicast_eht_inc(struct net_bridge_port_group *pg,
{ {
bool changed; bool changed;
changed = __eht_inc_exc(pg, h_addr, srcs, nsrcs, addr_size, changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
MCAST_INCLUDE, to_report); MCAST_INCLUDE, to_report);
br_eht_convert_host_filter_mode(pg, h_addr, MCAST_INCLUDE); br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_INCLUDE);
return changed; return changed;
} }
static bool br_multicast_eht_exc(struct net_bridge_port_group *pg, static bool br_multicast_eht_exc(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -679,14 +687,15 @@ static bool br_multicast_eht_exc(struct net_bridge_port_group *pg, ...@@ -679,14 +687,15 @@ static bool br_multicast_eht_exc(struct net_bridge_port_group *pg,
{ {
bool changed; bool changed;
changed = __eht_inc_exc(pg, h_addr, srcs, nsrcs, addr_size, changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
MCAST_EXCLUDE, to_report); MCAST_EXCLUDE, to_report);
br_eht_convert_host_filter_mode(pg, h_addr, MCAST_EXCLUDE); br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_EXCLUDE);
return changed; return changed;
} }
static bool __eht_ip4_handle(struct net_bridge_port_group *pg, static bool __eht_ip4_handle(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -696,24 +705,25 @@ static bool __eht_ip4_handle(struct net_bridge_port_group *pg, ...@@ -696,24 +705,25 @@ static bool __eht_ip4_handle(struct net_bridge_port_group *pg,
switch (grec_type) { switch (grec_type) {
case IGMPV3_ALLOW_NEW_SOURCES: case IGMPV3_ALLOW_NEW_SOURCES:
br_multicast_eht_allow(pg, h_addr, srcs, nsrcs, sizeof(__be32)); br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(__be32));
break; break;
case IGMPV3_BLOCK_OLD_SOURCES: case IGMPV3_BLOCK_OLD_SOURCES:
changed = br_multicast_eht_block(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(__be32)); sizeof(__be32));
break; break;
case IGMPV3_CHANGE_TO_INCLUDE: case IGMPV3_CHANGE_TO_INCLUDE:
to_report = true; to_report = true;
fallthrough; fallthrough;
case IGMPV3_MODE_IS_INCLUDE: case IGMPV3_MODE_IS_INCLUDE:
changed = br_multicast_eht_inc(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(__be32), to_report); sizeof(__be32), to_report);
break; break;
case IGMPV3_CHANGE_TO_EXCLUDE: case IGMPV3_CHANGE_TO_EXCLUDE:
to_report = true; to_report = true;
fallthrough; fallthrough;
case IGMPV3_MODE_IS_EXCLUDE: case IGMPV3_MODE_IS_EXCLUDE:
changed = br_multicast_eht_exc(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(__be32), to_report); sizeof(__be32), to_report);
break; break;
} }
...@@ -722,7 +732,8 @@ static bool __eht_ip4_handle(struct net_bridge_port_group *pg, ...@@ -722,7 +732,8 @@ static bool __eht_ip4_handle(struct net_bridge_port_group *pg,
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static bool __eht_ip6_handle(struct net_bridge_port_group *pg, static bool __eht_ip6_handle(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
union net_bridge_eht_addr *h_addr, union net_bridge_eht_addr *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -732,18 +743,18 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg, ...@@ -732,18 +743,18 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg,
switch (grec_type) { switch (grec_type) {
case MLD2_ALLOW_NEW_SOURCES: case MLD2_ALLOW_NEW_SOURCES:
br_multicast_eht_allow(pg, h_addr, srcs, nsrcs, br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
break; break;
case MLD2_BLOCK_OLD_SOURCES: case MLD2_BLOCK_OLD_SOURCES:
changed = br_multicast_eht_block(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
break; break;
case MLD2_CHANGE_TO_INCLUDE: case MLD2_CHANGE_TO_INCLUDE:
to_report = true; to_report = true;
fallthrough; fallthrough;
case MLD2_MODE_IS_INCLUDE: case MLD2_MODE_IS_INCLUDE:
changed = br_multicast_eht_inc(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
to_report); to_report);
break; break;
...@@ -751,7 +762,7 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg, ...@@ -751,7 +762,7 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg,
to_report = true; to_report = true;
fallthrough; fallthrough;
case MLD2_MODE_IS_EXCLUDE: case MLD2_MODE_IS_EXCLUDE:
changed = br_multicast_eht_exc(pg, h_addr, srcs, nsrcs, changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
sizeof(struct in6_addr), sizeof(struct in6_addr),
to_report); to_report);
break; break;
...@@ -762,7 +773,8 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg, ...@@ -762,7 +773,8 @@ static bool __eht_ip6_handle(struct net_bridge_port_group *pg,
#endif #endif
/* true means an entry was deleted */ /* true means an entry was deleted */
bool br_multicast_eht_handle(struct net_bridge_port_group *pg, bool br_multicast_eht_handle(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
void *h_addr, void *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
...@@ -779,12 +791,12 @@ bool br_multicast_eht_handle(struct net_bridge_port_group *pg, ...@@ -779,12 +791,12 @@ bool br_multicast_eht_handle(struct net_bridge_port_group *pg,
memset(&eht_host_addr, 0, sizeof(eht_host_addr)); memset(&eht_host_addr, 0, sizeof(eht_host_addr));
memcpy(&eht_host_addr, h_addr, addr_size); memcpy(&eht_host_addr, h_addr, addr_size);
if (addr_size == sizeof(__be32)) if (addr_size == sizeof(__be32))
changed = __eht_ip4_handle(pg, &eht_host_addr, srcs, nsrcs, changed = __eht_ip4_handle(brmctx, pg, &eht_host_addr, srcs,
grec_type); nsrcs, grec_type);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
else else
changed = __eht_ip6_handle(pg, &eht_host_addr, srcs, nsrcs, changed = __eht_ip6_handle(brmctx, pg, &eht_host_addr, srcs,
grec_type); nsrcs, grec_type);
#endif #endif
out: out:
......
...@@ -817,9 +817,10 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, ...@@ -817,9 +817,10 @@ int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd,
/* br_multicast.c */ /* br_multicast.c */
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, int br_multicast_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, u16 vid); struct sk_buff *skb, u16 vid);
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge_mcast *brmctx,
struct sk_buff *skb, u16 vid); struct sk_buff *skb, u16 vid);
int br_multicast_add_port(struct net_bridge_port *port); int br_multicast_add_port(struct net_bridge_port *port);
void br_multicast_del_port(struct net_bridge_port *port); void br_multicast_del_port(struct net_bridge_port *port);
...@@ -831,8 +832,9 @@ void br_multicast_leave_snoopers(struct net_bridge *br); ...@@ -831,8 +832,9 @@ void br_multicast_leave_snoopers(struct net_bridge *br);
void br_multicast_open(struct net_bridge *br); void br_multicast_open(struct net_bridge *br);
void br_multicast_stop(struct net_bridge *br); void br_multicast_stop(struct net_bridge *br);
void br_multicast_dev_del(struct net_bridge *br); void br_multicast_dev_del(struct net_bridge *br);
void br_multicast_flood(struct net_bridge_mdb_entry *mdst, void br_multicast_flood(struct net_bridge_mdb_entry *mdst, struct sk_buff *skb,
struct sk_buff *skb, bool local_rcv, bool local_orig); struct net_bridge_mcast *brmctx,
bool local_rcv, bool local_orig);
int br_multicast_set_router(struct net_bridge *br, unsigned long val); int br_multicast_set_router(struct net_bridge *br, unsigned long val);
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val); int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val);
int br_multicast_toggle(struct net_bridge *br, unsigned long val, int br_multicast_toggle(struct net_bridge *br, unsigned long val,
...@@ -861,7 +863,8 @@ void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port, ...@@ -861,7 +863,8 @@ void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, void br_multicast_del_pg(struct net_bridge_mdb_entry *mp,
struct net_bridge_port_group *pg, struct net_bridge_port_group *pg,
struct net_bridge_port_group __rcu **pp); struct net_bridge_port_group __rcu **pp);
void br_multicast_count(struct net_bridge *br, const struct net_bridge_port *p, void br_multicast_count(struct net_bridge *br,
const struct net_bridge_port *p,
const struct sk_buff *skb, u8 type, u8 dir); const struct sk_buff *skb, u8 type, u8 dir);
int br_multicast_init_stats(struct net_bridge *br); int br_multicast_init_stats(struct net_bridge *br);
void br_multicast_uninit_stats(struct net_bridge *br); void br_multicast_uninit_stats(struct net_bridge *br);
...@@ -890,10 +893,9 @@ static inline bool br_group_is_l2(const struct br_ip *group) ...@@ -890,10 +893,9 @@ static inline bool br_group_is_l2(const struct br_ip *group)
rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
static inline struct hlist_node * static inline struct hlist_node *
br_multicast_get_first_rport_node(struct net_bridge *br, struct sk_buff *skb) br_multicast_get_first_rport_node(struct net_bridge_mcast *brmctx,
struct sk_buff *skb)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (skb->protocol == htons(ETH_P_IPV6)) if (skb->protocol == htons(ETH_P_IPV6))
return rcu_dereference(hlist_first_rcu(&brmctx->ip6_mc_router_list)); return rcu_dereference(hlist_first_rcu(&brmctx->ip6_mc_router_list));
...@@ -936,10 +938,8 @@ static inline bool br_ip6_multicast_is_router(struct net_bridge_mcast *brmctx) ...@@ -936,10 +938,8 @@ static inline bool br_ip6_multicast_is_router(struct net_bridge_mcast *brmctx)
} }
static inline bool static inline bool
br_multicast_is_router(struct net_bridge *br, struct sk_buff *skb) br_multicast_is_router(struct net_bridge_mcast *brmctx, struct sk_buff *skb)
{ {
struct net_bridge_mcast *brmctx = &br->multicast_ctx;
switch (brmctx->multicast_router) { switch (brmctx->multicast_router) {
case MDB_RTR_TYPE_PERM: case MDB_RTR_TYPE_PERM:
return true; return true;
...@@ -960,14 +960,14 @@ br_multicast_is_router(struct net_bridge *br, struct sk_buff *skb) ...@@ -960,14 +960,14 @@ br_multicast_is_router(struct net_bridge *br, struct sk_buff *skb)
} }
static inline bool static inline bool
__br_multicast_querier_exists(struct net_bridge *br, __br_multicast_querier_exists(struct net_bridge_mcast *brmctx,
struct bridge_mcast_other_query *querier, struct bridge_mcast_other_query *querier,
const bool is_ipv6) const bool is_ipv6)
{ {
bool own_querier_enabled; bool own_querier_enabled;
if (br_opt_get(br, BROPT_MULTICAST_QUERIER)) { if (br_opt_get(brmctx->br, BROPT_MULTICAST_QUERIER)) {
if (is_ipv6 && !br_opt_get(br, BROPT_HAS_IPV6_ADDR)) if (is_ipv6 && !br_opt_get(brmctx->br, BROPT_HAS_IPV6_ADDR))
own_querier_enabled = false; own_querier_enabled = false;
else else
own_querier_enabled = true; own_querier_enabled = true;
...@@ -979,18 +979,18 @@ __br_multicast_querier_exists(struct net_bridge *br, ...@@ -979,18 +979,18 @@ __br_multicast_querier_exists(struct net_bridge *br,
(own_querier_enabled || timer_pending(&querier->timer)); (own_querier_enabled || timer_pending(&querier->timer));
} }
static inline bool br_multicast_querier_exists(struct net_bridge *br, static inline bool br_multicast_querier_exists(struct net_bridge_mcast *brmctx,
struct ethhdr *eth, struct ethhdr *eth,
const struct net_bridge_mdb_entry *mdb) const struct net_bridge_mdb_entry *mdb)
{ {
switch (eth->h_proto) { switch (eth->h_proto) {
case (htons(ETH_P_IP)): case (htons(ETH_P_IP)):
return __br_multicast_querier_exists(br, return __br_multicast_querier_exists(brmctx,
&br->multicast_ctx.ip4_other_query, false); &brmctx->ip4_other_query, false);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case (htons(ETH_P_IPV6)): case (htons(ETH_P_IPV6)):
return __br_multicast_querier_exists(br, return __br_multicast_querier_exists(brmctx,
&br->multicast_ctx.ip6_other_query, true); &brmctx->ip6_other_query, true);
#endif #endif
default: default:
return !!mdb && br_group_is_l2(&mdb->addr); return !!mdb && br_group_is_l2(&mdb->addr);
...@@ -1011,15 +1011,16 @@ static inline bool br_multicast_is_star_g(const struct br_ip *ip) ...@@ -1011,15 +1011,16 @@ static inline bool br_multicast_is_star_g(const struct br_ip *ip)
} }
} }
static inline bool br_multicast_should_handle_mode(const struct net_bridge *br, static inline bool
__be16 proto) br_multicast_should_handle_mode(const struct net_bridge_mcast *brmctx,
__be16 proto)
{ {
switch (proto) { switch (proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
return !!(br->multicast_ctx.multicast_igmp_version == 3); return !!(brmctx->multicast_igmp_version == 3);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
return !!(br->multicast_ctx.multicast_mld_version == 2); return !!(brmctx->multicast_mld_version == 2);
#endif #endif
default: default:
return false; return false;
...@@ -1031,28 +1032,28 @@ static inline int br_multicast_igmp_type(const struct sk_buff *skb) ...@@ -1031,28 +1032,28 @@ static inline int br_multicast_igmp_type(const struct sk_buff *skb)
return BR_INPUT_SKB_CB(skb)->igmp; return BR_INPUT_SKB_CB(skb)->igmp;
} }
static inline unsigned long br_multicast_lmqt(const struct net_bridge *br) static inline unsigned long br_multicast_lmqt(const struct net_bridge_mcast *brmctx)
{ {
return br->multicast_ctx.multicast_last_member_interval * return brmctx->multicast_last_member_interval *
br->multicast_ctx.multicast_last_member_count; brmctx->multicast_last_member_count;
} }
static inline unsigned long br_multicast_gmi(const struct net_bridge *br) static inline unsigned long br_multicast_gmi(const struct net_bridge_mcast *brmctx)
{ {
/* use the RFC default of 2 for QRV */ /* use the RFC default of 2 for QRV */
return 2 * br->multicast_ctx.multicast_query_interval + return 2 * brmctx->multicast_query_interval +
br->multicast_ctx.multicast_query_response_interval; brmctx->multicast_query_response_interval;
} }
#else #else
static inline int br_multicast_rcv(struct net_bridge *br, static inline int br_multicast_rcv(struct net_bridge_mcast *brmctx,
struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx,
struct sk_buff *skb, struct sk_buff *skb,
u16 vid) u16 vid)
{ {
return 0; return 0;
} }
static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge_mcast *brmctx,
struct sk_buff *skb, u16 vid) struct sk_buff *skb, u16 vid)
{ {
return NULL; return NULL;
...@@ -1101,17 +1102,18 @@ static inline void br_multicast_dev_del(struct net_bridge *br) ...@@ -1101,17 +1102,18 @@ static inline void br_multicast_dev_del(struct net_bridge *br)
static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst, static inline void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb, struct sk_buff *skb,
struct net_bridge_mcast *brmctx,
bool local_rcv, bool local_orig) bool local_rcv, bool local_orig)
{ {
} }
static inline bool br_multicast_is_router(struct net_bridge *br, static inline bool br_multicast_is_router(struct net_bridge_mcast *brmctx,
struct sk_buff *skb) struct sk_buff *skb)
{ {
return false; return false;
} }
static inline bool br_multicast_querier_exists(struct net_bridge *br, static inline bool br_multicast_querier_exists(struct net_bridge_mcast *brmctx,
struct ethhdr *eth, struct ethhdr *eth,
const struct net_bridge_mdb_entry *mdb) const struct net_bridge_mdb_entry *mdb)
{ {
......
...@@ -51,7 +51,8 @@ struct net_bridge_group_eht_set { ...@@ -51,7 +51,8 @@ struct net_bridge_group_eht_set {
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg); void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg);
bool br_multicast_eht_handle(struct net_bridge_port_group *pg, bool br_multicast_eht_handle(const struct net_bridge_mcast *brmctx,
struct net_bridge_port_group *pg,
void *h_addr, void *h_addr,
void *srcs, void *srcs,
u32 nsrcs, u32 nsrcs,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册