diff options
author | David S. Miller <davem@davemloft.net> | 2021-08-17 10:37:29 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-08-17 10:37:29 +0100 |
commit | 4aefc7973cfc0dace91a9a95f4f554ecd0364caf (patch) | |
tree | abbcb462c6bc991f2f988a4f62a43f760b18f2e4 | |
parent | 2cb594240b7a28cb3badfb651351d8c9bfab228d (diff) | |
parent | affce9a774ca2514aaa5638fde92c57a476dfd79 (diff) |
Merge branch 'bridge-vlan-fixes'
Nikolay Aleksandrov says:
====================
net: bridge: vlan: fixes for vlan mcast contexts
These are four fixes for vlan multicast contexts. The first patch enables
mcast ctx snooping when adding already existing master vlans to be
consistent with the rest of the code. The second patch accounts for the
mcast ctx router ports when allocating skb for notification. The third
one fixes two suspicious rcu usages due to wrong vlan group helper, and
the fourth updates host vlan mcast state along with port mcast state.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/bridge/br_mdb.c | 30 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 10 | ||||
-rw-r--r-- | net/bridge/br_private.h | 7 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 1 | ||||
-rw-r--r-- | net/bridge/br_vlan_options.c | 17 |
5 files changed, 48 insertions, 17 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 389ff3c1e9d9..0281453f7766 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -37,6 +37,36 @@ br_ip6_rports_get_timer(struct net_bridge_mcast_port *pmctx, #endif } +static size_t __br_rports_one_size(void) +{ + return nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PORT */ + nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_TIMER */ + nla_total_size(sizeof(u8)) + /* MDBA_ROUTER_PATTR_TYPE */ + nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_INET_TIMER */ + nla_total_size(sizeof(u32)) + /* MDBA_ROUTER_PATTR_INET6_TIMER */ + nla_total_size(sizeof(u32)); /* MDBA_ROUTER_PATTR_VID */ +} + +size_t br_rports_size(const struct net_bridge_mcast *brmctx) +{ + struct net_bridge_mcast_port *pmctx; + size_t size = nla_total_size(0); /* MDBA_ROUTER */ + + rcu_read_lock(); + hlist_for_each_entry_rcu(pmctx, &brmctx->ip4_mc_router_list, + ip4_rlist) + size += __br_rports_one_size(); + +#if IS_ENABLED(CONFIG_IPV6) + hlist_for_each_entry_rcu(pmctx, &brmctx->ip6_mc_router_list, + ip6_rlist) + size += __br_rports_one_size(); +#endif + rcu_read_unlock(); + + return size; +} + int br_rports_fill_info(struct sk_buff *skb, const struct net_bridge_mcast *brmctx) { diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index e411dd814c58..16e686f5b9e9 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -221,7 +221,7 @@ br_multicast_pg_to_port_ctx(const struct net_bridge_port_group *pg) * can safely be used on return */ rcu_read_lock(); - vlan = br_vlan_find(nbp_vlan_group(pg->key.port), pg->key.addr.vid); + vlan = br_vlan_find(nbp_vlan_group_rcu(pg->key.port), pg->key.addr.vid); if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx)) pmctx = &vlan->port_mcast_ctx; else @@ -4074,7 +4074,7 @@ void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, bool on) } } -void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, bool on) +static void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, bool on) { struct net_bridge_port *p; @@ -4089,6 +4089,9 @@ void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, bool on) continue; br_multicast_toggle_one_vlan(vport, on); } + + if (br_vlan_is_brentry(vlan)) + br_multicast_toggle_one_vlan(vlan, on); } int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on, @@ -4329,7 +4332,8 @@ static void br_multicast_start_querier(struct net_bridge_mcast *brmctx, if (br_multicast_ctx_is_vlan(brmctx)) { struct net_bridge_vlan *vlan; - vlan = br_vlan_find(nbp_vlan_group(port), brmctx->vlan->vid); + vlan = br_vlan_find(nbp_vlan_group_rcu(port), + brmctx->vlan->vid); if (!vlan || br_multicast_port_ctx_state_stopped(&vlan->port_mcast_ctx)) continue; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 9b1bf98a2c5a..21b292eb2b3e 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -938,7 +938,6 @@ void br_multicast_port_ctx_init(struct net_bridge_port *port, struct net_bridge_mcast_port *pmctx); void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pmctx); void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, bool on); -void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, bool on); int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on, struct netlink_ext_ack *extack); bool br_multicast_toggle_global_vlan(struct net_bridge_vlan *vlan, bool on); @@ -952,6 +951,7 @@ int br_multicast_dump_querier_state(struct sk_buff *skb, const struct net_bridge_mcast *brmctx, int nest_attr); size_t br_multicast_querier_state_size(void); +size_t br_rports_size(const struct net_bridge_mcast *brmctx); static inline bool br_group_is_l2(const struct br_ip *group) { @@ -1369,11 +1369,6 @@ static inline void br_multicast_toggle_one_vlan(struct net_bridge_vlan *vlan, { } -static inline void br_multicast_toggle_vlan(struct net_bridge_vlan *vlan, - bool on) -{ -} - static inline int br_multicast_toggle_vlan_snooping(struct net_bridge *br, bool on, struct netlink_ext_ack *extack) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index cbc922681a76..e25e288e7a85 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -694,6 +694,7 @@ static int br_vlan_add_existing(struct net_bridge *br, vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY; vg->num_vlans++; *changed = true; + br_multicast_toggle_one_vlan(vlan, true); } if (__vlan_add_flags(vlan, flags)) diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index 49dec53a4a74..a3b8a086284b 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -362,7 +362,7 @@ out_err: return false; } -static size_t rtnl_vlan_global_opts_nlmsg_size(void) +static size_t rtnl_vlan_global_opts_nlmsg_size(const struct net_bridge_vlan *v) { return NLMSG_ALIGN(sizeof(struct br_vlan_msg)) + nla_total_size(0) /* BRIDGE_VLANDB_GLOBAL_OPTIONS */ @@ -382,6 +382,8 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(void) + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER */ + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER */ + br_multicast_querier_state_size() /* BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE */ + + nla_total_size(0) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */ + + br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */ #endif + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ } @@ -398,7 +400,12 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, /* right now notifications are done only with rtnl held */ ASSERT_RTNL(); - skb = nlmsg_new(rtnl_vlan_global_opts_nlmsg_size(), GFP_KERNEL); + /* need to find the vlan due to flags/options */ + v = br_vlan_find(br_vlan_group(br), vid); + if (!v) + return; + + skb = nlmsg_new(rtnl_vlan_global_opts_nlmsg_size(v), GFP_KERNEL); if (!skb) goto out_err; @@ -411,11 +418,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, bvm->family = AF_BRIDGE; bvm->ifindex = br->dev->ifindex; - /* need to find the vlan due to flags/options */ - v = br_vlan_find(br_vlan_group(br), vid); - if (!v) - goto out_kfree; - if (!br_vlan_global_opts_fill(skb, vid, vid_range, v)) goto out_err; @@ -425,7 +427,6 @@ static void br_vlan_global_opts_notify(const struct net_bridge *br, out_err: rtnl_set_sk_err(dev_net(br->dev), RTNLGRP_BRVLAN, err); -out_kfree: kfree_skb(skb); } |