net: bridge: use br_vlan_get_state to get vlan state

The vlan state can change under RTNL or RCU (mst), so use the helper
to get the state properly throughout the bridge driver.

Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260903143138.1574598-10-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Nikolay Aleksandrov 2026-09-03 17:31:38 +03:00 committed by Jakub Kicinski
parent f20c448115
commit 9ef138b168
4 changed files with 17 additions and 15 deletions

View File

@ -70,7 +70,7 @@ int br_mst_get_state(const struct net_device *dev, u16 msti, u8 *state)
list_for_each_entry(v, &vg->vlan_list, vlist) {
if (v->brvlan->msti == msti) {
*state = v->state;
*state = br_vlan_get_state(v);
return 0;
}
}
@ -145,7 +145,7 @@ static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti)
* it.
*/
if (v != pv && v->brvlan->msti == msti) {
br_mst_vlan_set_state(vg, pv, v->state);
br_mst_vlan_set_state(vg, pv, br_vlan_get_state(v));
return;
}
}
@ -282,7 +282,8 @@ int br_mst_fill_info(struct sk_buff *skb,
nest = nla_nest_start_noflag(skb, IFLA_BRIDGE_MST_ENTRY);
if (!nest ||
nla_put_u16(skb, IFLA_BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) ||
nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE, v->state)) {
nla_put_u8(skb, IFLA_BRIDGE_MST_ENTRY_STATE,
br_vlan_get_state(v))) {
err = -EMSGSIZE;
break;
}

View File

@ -687,6 +687,15 @@ static inline bool br_vlan_should_use(const struct net_bridge_vlan *v)
return true;
}
/* The vlan state can be changed with only rcu held by the mst code so
* annotate the lock-free read. br_vlan_set_state() is kept further down
* because it needs br_multicast_update_vlan_mcast_ctx().
*/
static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
{
return READ_ONCE(v->state);
}
static inline bool nbp_state_should_learn(const struct net_bridge_port *p)
{
return p->state == BR_STATE_LEARNING || p->state == BR_STATE_FORWARDING;
@ -1299,7 +1308,7 @@ br_multicast_port_ctx_state_disabled(const struct net_bridge_mcast_port *pmctx)
return pmctx->port->state == BR_STATE_DISABLED ||
(br_multicast_port_ctx_is_vlan(pmctx) &&
(br_multicast_port_ctx_vlan_disabled(pmctx) ||
pmctx->vlan->state == BR_STATE_DISABLED));
br_vlan_get_state(pmctx->vlan) == BR_STATE_DISABLED));
}
static inline bool
@ -1308,7 +1317,7 @@ br_multicast_port_ctx_state_stopped(const struct net_bridge_mcast_port *pmctx)
return br_multicast_port_ctx_state_disabled(pmctx) ||
pmctx->port->state == BR_STATE_BLOCKING ||
(br_multicast_port_ctx_is_vlan(pmctx) &&
pmctx->vlan->state == BR_STATE_BLOCKING);
br_vlan_get_state(pmctx->vlan) == BR_STATE_BLOCKING);
}
static inline bool
@ -1916,14 +1925,6 @@ bool br_vlan_global_opts_can_enter_range(const struct net_bridge_vlan *v_curr,
bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range,
const struct net_bridge_vlan *v_opts);
/* vlan state manipulation helpers using *_ONCE to annotate lock-free access,
* while br_vlan_set_state() may access data protected by multicast_lock.
*/
static inline u8 br_vlan_get_state(const struct net_bridge_vlan *v)
{
return READ_ONCE(v->state);
}
static inline void br_vlan_set_state(struct net_bridge_vlan *v, u8 state)
{
WRITE_ONCE(v->state, state);

View File

@ -40,7 +40,7 @@ static void __vlan_add_pvid(struct net_bridge_vlan_group *vg,
if (vg->pvid == v->vid)
return;
br_vlan_set_pvid_state(vg, v->state);
br_vlan_set_pvid_state(vg, br_vlan_get_state(v));
WRITE_ONCE(vg->pvid, v->vid);
}

View File

@ -43,7 +43,7 @@ bool br_vlan_opts_eq_range(const struct net_bridge_vlan *v_curr,
u8 range_mc_rtr = br_vlan_multicast_router(range_end);
u8 curr_mc_rtr = br_vlan_multicast_router(v_curr);
if (v_curr->state != range_end->state)
if (br_vlan_get_state(v_curr) != br_vlan_get_state(range_end))
return false;
if (!__vlan_tun_can_enter_range(v_curr, range_end))