From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 30072C43219 for ; Wed, 16 Feb 2022 13:30:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234410AbiBPNap (ORCPT ); Wed, 16 Feb 2022 08:30:45 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42724 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234271AbiBPNaj (ORCPT ); Wed, 16 Feb 2022 08:30:39 -0500 Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 441C7172E4A for ; Wed, 16 Feb 2022 05:30:26 -0800 (PST) Received: by mail-lf1-x133.google.com with SMTP id u20so3877599lff.2 for ; Wed, 16 Feb 2022 05:30:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=XlQYLM8l9YP6fA05hV8ZIQiqX+CEM3X6J0L0A3uQZHU=; b=uZP+bmSmdF22/IqQAh7JhsXN7QUJilKpebrKmLzK12rBZsPq1h9TgvyMeiLzx/sixU V3lQIUHbvXyOZyadaX2UZJyu7MpzGABS16JU1eObqqrsn1MOcEi98EMvPrO4QLtOtFKx ZuzOKJEkQxnMdwE9e0GIy65Br/qjiQtU5JzoQ/hyILRdJI+y4clL4RvC8VgfRc3vIytm B9eIaEhHu/xXy7yD9ZupEQ9I+w20t8wF4ycy88nerSTcn4rVBPKLgdAn3vREbP4PHwj8 u3NyHm9aqxFOCjxeCa9842WCNgD1QrE/vGXFRd1a/TaCTAonCpQCBQh6hi16QD+Fb3kK kgvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=XlQYLM8l9YP6fA05hV8ZIQiqX+CEM3X6J0L0A3uQZHU=; b=kzssYHNYtrwCvVvOuQq6iRk/3aDdl7e98LZwx3tnASBqOGbNV+xZEpAgGkl4DHatwU qqqj7D7Fs77T28R0ioSwIXvnn0wZgELnlE6cJLi8jqeWAApuC4N0DBZRgikCai8oVBUI ptDmGmbmexFmR0N4lYc8dLIsja/vJ2LGH8NzLfFrCOnBHIXQpQMSD/QAoI3uh/cZyRmZ kmy4MrxtNZqaOgYPCy2qW+zpZqemvoM0z5+3JR0XlB70wNgiYCj2n/DEvPKrlCM6PmYY 6TSbeiD3qdBm8EeRmhgBzK9rzbFmgy39BOkqLouNiOp8Gt7WxqV/NaWTvsV99YDf80Vo VSUg== X-Gm-Message-State: AOAM531aA6a6qNg75zd3XK0ZiL0S9RDwVSZLSiu4ABOAy/QidQ03J/zD Dauorj8EB4tzeA8rVFpqHdKuog== X-Google-Smtp-Source: ABdhPJyQA20O4VzBdbt1DxD1vQ6wknk3/9R1oWsaaINMwDaRKtMimKINpObqBOpmiAABr4M1tYtvWg== X-Received: by 2002:a05:6512:3f9:b0:443:3c86:31f1 with SMTP id n25-20020a05651203f900b004433c8631f1mr2002015lfq.532.1645018224491; Wed, 16 Feb 2022 05:30:24 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:23 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 1/9] net: bridge: vlan: Introduce multiple spanning trees (MST) Date: Wed, 16 Feb 2022 14:29:26 +0100 Message-Id: <20220216132934.1775649-2-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Before this commit, the bridge was able to manage the forwarding state of a port on either a global or per-VLAN basis. I.e. either 1:N or N:N. There are two issues with this: 1. In order to support MSTP (802.1Q-2018 13.5), the controlling entity expects the bridge to be able to group multiple VLANs to operate on the same tree (MST). I.e. an M:N mapping, where M <=3D N. 2. Some hardware (e.g. mv88e6xxx) has a smaller pool of spanning tree groups than VLANs. I.e. the full set of 4k VLANs can be configured, but each VLAN must be mapped to one of only 64 spanning trees. While somewhat less efficient (and non-atomic), (1) can be worked around in software by iterating over all affected VLANs when changing the state of a tree to make sure that they are all in sync. Unfortunately, (2) means that offloading is not possible in this architecture. Therefore, add a level of indirection in the per-VLAN STP state. By default, each new VLAN will be assigned to a separate MST. I.e. there are no functional changes introduced by this commit. Upcoming commits will then extend the VLAN DB configuration to allow arbitrary M:N mappings. Signed-off-by: Tobias Waldekranz --- include/linux/if_bridge.h | 6 ++ net/bridge/br_private.h | 41 +++++-- net/bridge/br_vlan.c | 200 +++++++++++++++++++++++++++++++++-- net/bridge/br_vlan_options.c | 9 +- 4 files changed, 234 insertions(+), 22 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 509e18c7e740..a3b0e95c3047 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -118,6 +118,7 @@ int br_vlan_get_info(const struct net_device *dev, u16 = vid, struct bridge_vlan_info *p_vinfo); int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid, struct bridge_vlan_info *p_vinfo); +int br_vlan_get_mstid(const struct net_device *dev, u16 vid, u16 *mstid); #else static inline bool br_vlan_enabled(const struct net_device *dev) { @@ -150,6 +151,11 @@ static inline int br_vlan_get_info_rcu(const struct ne= t_device *dev, u16 vid, { return -EINVAL; } +static inline int br_vlan_get_mstid(const struct net_device *dev, u16 vid, + u16 *mstid) +{ + return -EINVAL; +} #endif =20 #if IS_ENABLED(CONFIG_BRIDGE) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2661dda1a92b..7781e7a4449b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -153,6 +153,14 @@ struct br_tunnel_info { struct metadata_dst __rcu *tunnel_dst; }; =20 +struct br_vlan_mst { + refcount_t refcnt; + u16 id; + u8 state; + + struct rcu_head rcu; +}; + /* private vlan flags */ enum { BR_VLFLAG_PER_PORT_STATS =3D BIT(0), @@ -168,7 +176,8 @@ enum { * @vid: VLAN id * @flags: bridge vlan flags * @priv_flags: private (in-kernel) bridge vlan flags - * @state: STP state (e.g. blocking, learning, forwarding) + * @mst: the port's STP state (e.g. blocking, learning, forwarding) in the= MST + * associated with this VLAN * @stats: per-cpu VLAN statistics * @br: if MASTER flag set, this points to a bridge struct * @port: if MASTER flag unset, this points to a port struct @@ -192,7 +201,7 @@ struct net_bridge_vlan { u16 vid; u16 flags; u16 priv_flags; - u8 state; + struct br_vlan_mst __rcu *mst; struct pcpu_sw_netstats __percpu *stats; union { struct net_bridge *br; @@ -215,6 +224,20 @@ struct net_bridge_vlan { struct rcu_head rcu; }; =20 +static inline u8 br_vlan_get_state_rcu(const struct net_bridge_vlan *v) +{ + const struct br_vlan_mst *mst =3D rcu_dereference(v->mst); + + return mst->state; +} + +static inline u8 br_vlan_get_state_rtnl(const struct net_bridge_vlan *v) +{ + const struct br_vlan_mst *mst =3D rtnl_dereference(v->mst); + + return mst->state; +} + /** * struct net_bridge_vlan_group * @@ -1179,7 +1202,7 @@ br_multicast_port_ctx_state_disabled(const struct net= _bridge_mcast_port *pmctx) return pmctx->port->state =3D=3D BR_STATE_DISABLED || (br_multicast_port_ctx_is_vlan(pmctx) && (br_multicast_port_ctx_vlan_disabled(pmctx) || - pmctx->vlan->state =3D=3D BR_STATE_DISABLED)); + br_vlan_get_state_rcu(pmctx->vlan) =3D=3D BR_STATE_DISABLED)); } =20 static inline bool @@ -1188,7 +1211,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 =3D=3D BR_STATE_BLOCKING || (br_multicast_port_ctx_is_vlan(pmctx) && - pmctx->vlan->state =3D=3D BR_STATE_BLOCKING); + br_vlan_get_state_rcu(pmctx->vlan) =3D=3D BR_STATE_BLOCKING); } =20 static inline bool @@ -1729,15 +1752,11 @@ bool br_vlan_global_opts_can_enter_range(const stru= ct 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); =20 -/* vlan state manipulation helpers using *_ONCE to annotate lock-free acce= ss */ -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); + struct br_vlan_mst *mst =3D rtnl_dereference(v->mst); + + mst->state =3D state; } =20 static inline u8 br_vlan_get_pvid_state(const struct net_bridge_vlan_group= *vg) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 6315e43a7a3e..b0383ec6cc91 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -34,6 +34,187 @@ static struct net_bridge_vlan *br_vlan_lookup(struct rh= ashtable *tbl, u16 vid) return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params); } =20 +static void br_vlan_mst_rcu_free(struct rcu_head *rcu) +{ + struct br_vlan_mst *mst =3D container_of(rcu, struct br_vlan_mst, rcu); + + kfree(mst); +} + +static void br_vlan_mst_put(struct net_bridge_vlan *v) +{ + struct br_vlan_mst *mst =3D rtnl_dereference(v->mst); + + if (refcount_dec_and_test(&mst->refcnt)) + call_rcu(&mst->rcu, br_vlan_mst_rcu_free); +} + +static struct br_vlan_mst *br_vlan_mst_new(u16 id) +{ + struct br_vlan_mst *mst; + + mst =3D kzalloc(sizeof(*mst), GFP_KERNEL); + if (!mst) + return NULL; + + refcount_set(&mst->refcnt, 1); + mst->id =3D id; + mst->state =3D BR_STATE_FORWARDING; + return mst; +} + +static int br_vlan_mstid_get_free(struct net_bridge *br) +{ + const struct net_bridge_vlan *v; + struct rhashtable_iter iter; + struct br_vlan_mst *mst; + unsigned long *busy; + int err =3D 0; + u16 id; + + busy =3D bitmap_zalloc(VLAN_N_VID, GFP_KERNEL); + if (!busy) + return -ENOMEM; + + /* MSTID 0 is reserved for the CIST */ + set_bit(0, busy); + + rhashtable_walk_enter(&br_vlan_group(br)->vlan_hash, &iter); + rhashtable_walk_start(&iter); + + while ((v =3D rhashtable_walk_next(&iter))) { + if (IS_ERR(v)) { + err =3D PTR_ERR(v); + goto out_free; + } + + mst =3D rtnl_dereference(v->mst); + set_bit(mst->id, busy); + } + + rhashtable_walk_stop(&iter); + + id =3D find_first_zero_bit(busy, VLAN_N_VID); + if (id >=3D VLAN_N_VID) + err =3D -ENOSPC; + +out_free: + kfree(busy); + return err ? : id; +} + +u16 br_vlan_mstid_get(const struct net_bridge_vlan *v) +{ + const struct net_bridge_vlan *masterv; + const struct br_vlan_mst *mst; + const struct net_bridge *br; + + if (br_vlan_is_master(v)) + br =3D v->br; + else + br =3D v->port->br; + + masterv =3D br_vlan_lookup(&br_vlan_group(br)->vlan_hash, v->vid); + + mst =3D rtnl_dereference(masterv->mst); + + return mst->id; +} + +int br_vlan_get_mstid(const struct net_device *dev, u16 vid, u16 *mstid) +{ + struct net_bridge *br =3D netdev_priv(dev); + struct net_bridge_vlan *v; + + v =3D br_vlan_lookup(&br_vlan_group(br)->vlan_hash, vid); + if (!v) + return -ENOENT; + + *mstid =3D br_vlan_mstid_get(v); + return 0; +} +EXPORT_SYMBOL_GPL(br_vlan_get_mstid); + +static struct br_vlan_mst *br_vlan_group_mst_get(struct net_bridge_vlan_gr= oup *vg, u16 mstid) +{ + struct net_bridge_vlan *v; + struct br_vlan_mst *mst; + + list_for_each_entry(v, &vg->vlan_list, vlist) { + mst =3D rtnl_dereference(v->mst); + if (mst->id =3D=3D mstid) { + refcount_inc(&mst->refcnt); + return mst; + } + } + + return NULL; +} + +static int br_vlan_mst_migrate(struct net_bridge_vlan *v, u16 mstid) +{ + struct net_bridge_vlan_group *vg; + struct br_vlan_mst *mst; + + if (br_vlan_is_master(v)) + vg =3D br_vlan_group(v->br); + else + vg =3D nbp_vlan_group(v->port); + + mst =3D br_vlan_group_mst_get(vg, mstid); + if (!mst) { + mst =3D br_vlan_mst_new(mstid); + if (!mst) + return -ENOMEM; + } + + if (rtnl_dereference(v->mst)) + br_vlan_mst_put(v); + + rcu_assign_pointer(v->mst, mst); + return 0; +} + +static int br_vlan_mst_init_master(struct net_bridge_vlan *v) +{ + struct net_bridge *br =3D v->br; + struct br_vlan_mst *mst; + int mstid; + + /* The bridge VLAN is always added first, either as context or + * as a proper entry. Since the bridge default is a 1:1 map + * from VID to MST, we always need to allocate a new ID in + * this case. + */ + mstid =3D br_vlan_mstid_get_free(br); + if (mstid < 0) + return mstid; + + mst =3D br_vlan_mst_new(mstid); + if (!mst) + return -ENOMEM; + + rcu_assign_pointer(v->mst, mst); + return 0; +} + +static int br_vlan_mst_init_port(struct net_bridge_vlan *v) +{ + u16 mstid; + + mstid =3D br_vlan_mstid_get(v); + + return br_vlan_mst_migrate(v, mstid); +} + +static int br_vlan_mst_init(struct net_bridge_vlan *v) +{ + if (br_vlan_is_master(v)) + return br_vlan_mst_init_master(v); + else + return br_vlan_mst_init_port(v); +} + static bool __vlan_add_pvid(struct net_bridge_vlan_group *vg, const struct net_bridge_vlan *v) { @@ -41,7 +222,7 @@ static bool __vlan_add_pvid(struct net_bridge_vlan_group= *vg, return false; =20 smp_wmb(); - br_vlan_set_pvid_state(vg, v->state); + br_vlan_set_pvid_state(vg, br_vlan_get_state_rtnl(v)); vg->pvid =3D v->vid; =20 return true; @@ -301,13 +482,14 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 = flags, vg->num_vlans++; } =20 - /* set the state before publishing */ - v->state =3D BR_STATE_FORWARDING; + err =3D br_vlan_mst_init(v); + if (err) + goto out_fdb_insert; =20 err =3D rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, br_vlan_rht_params); if (err) - goto out_fdb_insert; + goto out_mst_init; =20 __vlan_add_list(v); __vlan_add_flags(v, flags); @@ -318,6 +500,9 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 fl= ags, out: return err; =20 +out_mst_init: + br_vlan_mst_put(v); + out_fdb_insert: if (br_vlan_should_use(v)) { br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid); @@ -385,6 +570,7 @@ static int __vlan_del(struct net_bridge_vlan *v) call_rcu(&v->rcu, nbp_vlan_rcu_free); } =20 + br_vlan_mst_put(v); br_vlan_put_master(masterv); out: return err; @@ -578,7 +764,7 @@ static bool __allowed_ingress(const struct net_bridge *= br, goto drop; =20 if (*state =3D=3D BR_STATE_FORWARDING) { - *state =3D br_vlan_get_state(v); + *state =3D br_vlan_get_state_rcu(v); if (!br_vlan_state_allowed(*state, true)) goto drop; } @@ -631,7 +817,7 @@ bool br_allowed_egress(struct net_bridge_vlan_group *vg, br_vlan_get_tag(skb, &vid); v =3D br_vlan_find(vg, vid); if (v && br_vlan_should_use(v) && - br_vlan_state_allowed(br_vlan_get_state(v), false)) + br_vlan_state_allowed(br_vlan_get_state_rcu(v), false)) return true; =20 return false; @@ -665,7 +851,7 @@ bool br_should_learn(struct net_bridge_port *p, struct = sk_buff *skb, u16 *vid) } =20 v =3D br_vlan_find(vg, *vid); - if (v && br_vlan_state_allowed(br_vlan_get_state(v), true)) + if (v && br_vlan_state_allowed(br_vlan_get_state_rcu(v), true)) return true; =20 return false; diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index a6382973b3e7..0b1099709d4b 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -43,14 +43,14 @@ bool br_vlan_opts_eq_range(const struct net_bridge_vlan= *v_curr, u8 range_mc_rtr =3D br_vlan_multicast_router(range_end); u8 curr_mc_rtr =3D br_vlan_multicast_router(v_curr); =20 - return v_curr->state =3D=3D range_end->state && + return br_vlan_get_state_rtnl(v_curr) =3D=3D br_vlan_get_state_rtnl(range= _end) && __vlan_tun_can_enter_range(v_curr, range_end) && curr_mc_rtr =3D=3D range_mc_rtr; } =20 bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *= v) { - if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, br_vlan_get_state(v)) || + if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, br_vlan_get_state_rtnl(v))= || !__vlan_tun_put(skb, v)) return false; =20 @@ -99,7 +99,7 @@ static int br_vlan_modify_state(struct net_bridge_vlan_gr= oup *vg, return -EBUSY; } =20 - if (v->state =3D=3D state) + if (br_vlan_get_state_rtnl(v) =3D=3D state) return 0; =20 if (v->vid =3D=3D br_get_pvid(vg)) @@ -294,7 +294,8 @@ bool br_vlan_global_opts_can_enter_range(const struct n= et_bridge_vlan *v_curr, ((v_curr->priv_flags ^ r_end->priv_flags) & BR_VLFLAG_GLOBAL_MCAST_ENABLED) =3D=3D 0 && br_multicast_ctx_options_equal(&v_curr->br_mcast_ctx, - &r_end->br_mcast_ctx); + &r_end->br_mcast_ctx) && + br_vlan_mstid_get(v_curr) =3D=3D br_vlan_mstid_get(r_end); } =20 bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 vid, u16 vid_range, --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6259C433F5 for ; Wed, 16 Feb 2022 13:30:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234439AbiBPNaq (ORCPT ); Wed, 16 Feb 2022 08:30:46 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234329AbiBPNaj (ORCPT ); Wed, 16 Feb 2022 08:30:39 -0500 Received: from mail-lj1-x22d.google.com (mail-lj1-x22d.google.com [IPv6:2a00:1450:4864:20::22d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4A285171291 for ; Wed, 16 Feb 2022 05:30:27 -0800 (PST) Received: by mail-lj1-x22d.google.com with SMTP id bx31so3389132ljb.0 for ; Wed, 16 Feb 2022 05:30:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=1CB4EUxFKWWI52Kz17aW6jZZJSTVpsgoKc4ur1YzcMA=; b=w73/uLp75Ob6mZY/GoZBQ3VdlKKx9uIt18VnJKjs81yvPTh9ma3bhetUB54GlatmyX SsBkqnp6YpcF+bQDQCGABlyboYCJ2NNE23QK3WZ4Dg+EdT7lhcnY5ZKWCV3gubXke/Ci atzgu+eHBNDOisygn9mYk3qhkfPA5BZZJ0nwLif5cBY5VeBqb6cb9CafTtvrh5fFWRf/ NO9CR3HZxwLQoSEoU3nQuzsKLggOxHkCYbZZVaTtiXUrcv3htFUu3LsbeOS692zNkVKd v95/7aOAMP1QIebU/pjCLxqmQgFazCSSSjuE3z20kknQSOdfM4QrVIJLJwgk7at2FJK1 EE/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=1CB4EUxFKWWI52Kz17aW6jZZJSTVpsgoKc4ur1YzcMA=; b=yn03PGNV1Kg6jAZsgTbiCeYwNFnDus96dXAH7sRPTdt7ClKQmqmnJkdZ8urLmqNcio pBK29TVhqOndpvlhUpl+6GO7PsPrcVkRASgw9tsw5ieuNQNvC8rR2784hKksZrbP6omW rC2IowhLwUk23+WyPO3J3u8ohEW6MgWI+HvmCwoiO2XGHzbBAfyIUfeHAG1bhLRQpE+l H4EDr9DneCxHUWfPBdxJGUn0G8N7Xes8xi9+8oiArJTr5K3PXaicfeOe2WhGfGfBY81Z Q4W6O3v7ucvOtkSoHlbmSblpWOusZINdUAzndkJBUG2NvcytOpLk3kUQNKVSICNglene mGLA== X-Gm-Message-State: AOAM531LtfUljygu0cghf31fKWK/eOTXE0V0dz8K1MRa6VRvvyPUFBaV eaplWPm/LEFlG12ZYcbDfTsohw== X-Google-Smtp-Source: ABdhPJxIr0Fq0qdce4wqKBLB00c24HZ3fofKRdwkEGoZFNoIN46TqTgp7iHVd4dCVfJ/wiMClW2beg== X-Received: by 2002:a2e:8e7b:0:b0:246:355:fbc0 with SMTP id t27-20020a2e8e7b000000b002460355fbc0mr2069502ljk.356.1645018225644; Wed, 16 Feb 2022 05:30:25 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:24 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 2/9] net: bridge: vlan: Allow multiple VLANs to be mapped to a single MST Date: Wed, 16 Feb 2022 14:29:27 +0100 Message-Id: <20220216132934.1775649-3-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Allow a VLAN to change its MSTID. In particular, allow multiple VLANs to use the same MSTID. This is a global VLAN setting, i.e. any VLANs bound to the same MSTID will share their per-VLAN STP states on all bridge ports. Example: By default, each VLAN is placed in a separate MSTID: root@coronet:~# ip link add dev br0 type bridge vlan_filtering 1 root@coronet:~# ip link set dev eth1 master br0 root@coronet:~# bridge vlan add dev eth1 vid 2 pvid untagged root@coronet:~# bridge vlan add dev eth1 vid 3 root@coronet:~# bridge vlan global port vlan-id br0 1 mcast_snooping 1 mca_interval 1000 mstid 1 2 mcast_snooping 1 mca_interval 1000 mstid 2 3 mcast_snooping 1 mca_interval 1000 mstid 3 Once two or more VLANs are bound to the same MSTID, their states move in lockstep, independent of which VID is used to access the state: root@coronet:~# bridge vlan global set dev br0 vid 2 mstid 10 root@coronet:~# bridge vlan global set dev br0 vid 3 mstid 10 root@coronet:~# bridge -d vlan global port vlan-id br0 1 mcast_snooping 1 mca_interval 1000 mstid 1 2-3 mcast_snooping 1 mca_interval 1000 mstid 10 root@coronet:~# bridge vlan set dev eth1 vid 2 state blocking root@coronet:~# bridge -d vlan port vlan-id eth1 1 Egress Untagged state forwarding mcast_router 1 2 PVID Egress Untagged state blocking mcast_router 1 3 state blocking mcast_router 1 br0 1 PVID Egress Untagged state forwarding mcast_router 1 root@coronet:~# bridge vlan set dev eth1 vid 3 state forwarding root@coronet:~# bridge -d vlan port vlan-id eth1 1 Egress Untagged state forwarding mcast_router 1 2 PVID Egress Untagged state forwarding mcast_router 1 3 state forwarding mcast_router 1 br0 1 PVID Egress Untagged state forwarding mcast_router 1 Signed-off-by: Tobias Waldekranz --- include/uapi/linux/if_bridge.h | 1 + net/bridge/br_private.h | 3 ++ net/bridge/br_vlan.c | 53 ++++++++++++++++++++++++++-------- net/bridge/br_vlan_options.c | 17 ++++++++++- 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 2711c3522010..4a971b419d9f 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -564,6 +564,7 @@ enum { BRIDGE_VLANDB_GOPTS_MCAST_QUERIER, BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS, BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE, + BRIDGE_VLANDB_GOPTS_MSTID, __BRIDGE_VLANDB_GOPTS_MAX }; #define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 7781e7a4449b..5b121cf7aabe 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1759,6 +1759,9 @@ static inline void br_vlan_set_state(struct net_bridg= e_vlan *v, u8 state) mst->state =3D state; } =20 +u16 br_vlan_mstid_get(const struct net_bridge_vlan *v); +int br_vlan_mstid_set(struct net_bridge_vlan *v, u16 mstid); + static inline u8 br_vlan_get_pvid_state(const struct net_bridge_vlan_group= *vg) { return READ_ONCE(vg->pvid_state); diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index b0383ec6cc91..459e84a7354d 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -41,10 +41,8 @@ static void br_vlan_mst_rcu_free(struct rcu_head *rcu) kfree(mst); } =20 -static void br_vlan_mst_put(struct net_bridge_vlan *v) +static void br_vlan_mst_put(struct br_vlan_mst *mst) { - struct br_vlan_mst *mst =3D rtnl_dereference(v->mst); - if (refcount_dec_and_test(&mst->refcnt)) call_rcu(&mst->rcu, br_vlan_mst_rcu_free); } @@ -153,13 +151,17 @@ static struct br_vlan_mst *br_vlan_group_mst_get(stru= ct net_bridge_vlan_group *v =20 static int br_vlan_mst_migrate(struct net_bridge_vlan *v, u16 mstid) { + struct br_vlan_mst *mst, *old_mst; struct net_bridge_vlan_group *vg; - struct br_vlan_mst *mst; + struct net_bridge *br; =20 - if (br_vlan_is_master(v)) - vg =3D br_vlan_group(v->br); - else + if (br_vlan_is_master(v)) { + br =3D v->br; + vg =3D br_vlan_group(br); + } else { + br =3D v->port->br; vg =3D nbp_vlan_group(v->port); + } =20 mst =3D br_vlan_group_mst_get(vg, mstid); if (!mst) { @@ -168,10 +170,37 @@ static int br_vlan_mst_migrate(struct net_bridge_vlan= *v, u16 mstid) return -ENOMEM; } =20 - if (rtnl_dereference(v->mst)) - br_vlan_mst_put(v); - + old_mst =3D rtnl_dereference(v->mst); rcu_assign_pointer(v->mst, mst); + + if (old_mst) + br_vlan_mst_put(old_mst); + + return 0; +} + +int br_vlan_mstid_set(struct net_bridge_vlan *v, u16 mstid) +{ + struct net_bridge *br =3D v->br; + struct net_bridge_port *p; + int err; + + err =3D br_vlan_mst_migrate(v, mstid); + if (err) + return err; + + list_for_each_entry(p, &br->port_list, list) { + struct net_bridge_vlan_group *vg =3D nbp_vlan_group(p); + struct net_bridge_vlan *portv; + + portv =3D br_vlan_lookup(&vg->vlan_hash, v->vid); + if (!portv) + continue; + + err =3D br_vlan_mst_migrate(portv, mstid); + if (err) + return err; + } return 0; } =20 @@ -501,7 +530,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 fl= ags, return err; =20 out_mst_init: - br_vlan_mst_put(v); + br_vlan_mst_put(rtnl_dereference(v->mst)); =20 out_fdb_insert: if (br_vlan_should_use(v)) { @@ -570,7 +599,7 @@ static int __vlan_del(struct net_bridge_vlan *v) call_rcu(&v->rcu, nbp_vlan_rcu_free); } =20 - br_vlan_mst_put(v); + br_vlan_mst_put(rtnl_dereference(v->mst)); br_vlan_put_master(masterv); out: return err; diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index 0b1099709d4b..1c0fd55fe6c9 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -380,6 +380,9 @@ bool br_vlan_global_opts_fill(struct sk_buff *skb, u16 = vid, u16 vid_range, #endif #endif =20 + if (nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_MSTID, br_vlan_mstid_get(v_opts)= )) + goto out_err; + nla_nest_end(skb, nest); =20 return true; @@ -411,7 +414,9 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(const st= ruct net_bridge_vlan *v) + nla_total_size(0) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS */ + br_rports_size(&v->br_mcast_ctx) /* BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_P= ORTS */ #endif - + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ + + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_GOPTS_RANGE */ + + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_GOPTS_MSTID */ + + 0; } =20 static void br_vlan_global_opts_notify(const struct net_bridge *br, @@ -560,6 +565,15 @@ static int br_vlan_process_global_one_opts(const struc= t net_bridge *br, } #endif #endif + if (tb[BRIDGE_VLANDB_GOPTS_MSTID]) { + u16 mstid; + + mstid =3D nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_MSTID]); + err =3D br_vlan_mstid_set(v, mstid); + if (err) + return err; + *changed =3D true; + } =20 return 0; } @@ -579,6 +593,7 @@ static const struct nla_policy br_vlan_db_gpol[BRIDGE_V= LANDB_GOPTS_MAX + 1] =3D { [BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL] =3D { .type =3D NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL] =3D { .type =3D NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL] =3D { .type =3D NLA_U64 = }, + [BRIDGE_VLANDB_GOPTS_MSTID] =3D NLA_POLICY_RANGE(NLA_U16, 1, 4094), }; =20 int br_vlan_rtm_process_global_options(struct net_device *dev, --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20E11C43217 for ; Wed, 16 Feb 2022 13:30:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234472AbiBPNau (ORCPT ); Wed, 16 Feb 2022 08:30:50 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234347AbiBPNak (ORCPT ); Wed, 16 Feb 2022 08:30:40 -0500 Received: from mail-lj1-x230.google.com (mail-lj1-x230.google.com [IPv6:2a00:1450:4864:20::230]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4157F17289E for ; Wed, 16 Feb 2022 05:30:28 -0800 (PST) Received: by mail-lj1-x230.google.com with SMTP id bx31so3389222ljb.0 for ; Wed, 16 Feb 2022 05:30:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=DYnfKqTSgC5uj+SzX4mt7uAq7sGgk7Wi7t60amasNV0=; b=oxgfrsXStgeuX6tCRI8Jrp2u3JdDVV8hMQYPzHmSvI8GOYa/IRYkpGoSbIKCUVYZZq pyHvHY1anxMNK9X3eJvqEjDG8+48vm6wLm0q79+bJQrnw6kKhbSZDh9v7OhufwQ+Q3xI oLCefAUu7MkS0wFIseqacZjsATPxgvlxhqk2bPdQy3tOYs/4/PNsx74hC8j6vPA2EwYt 3A3BL4DVRusjAv56hhWzQ6BHib7nvN6z/HRpBkZ2Kf/OBYwIDQzKlAV3Oco5C881kPaY UlURxMwmPCiivCJYZPoiZh9ffuVp7p7wamxtLGKluisKrMujGYQOYudOCEHVFBU9YR7I SyvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=DYnfKqTSgC5uj+SzX4mt7uAq7sGgk7Wi7t60amasNV0=; b=SNmNpXwGdyWHdzUETjrO8wgxq/fPZECzqvrb5UhGlNVxGnKM56N92l/Zz6DlnPFVH2 E5M4RHtRtfgWj7IO9V/catpeUHw1/KIuOsuoaFtrfYu3fSmZ4XaBMO3MTeupaHV4pJ3+ yE3NpdlF3R3KdFleFtMRq5SQNdMKMmcNtbBL09PEzbZAEu05R0Es8LRZtR855ZTU1O6z I4d1NKNddkU5TjoGf/az6GaaBRezmK9JCaG896CYdKxuKXX7eR7O+Ru7iuZ3/hDz/dqZ TZtMLS15pHlyQqL2tV2nOpoc9R/QZfTqFmiKO6bTBmz7hAmnhsjw21tNsEpNHgQFns1A 8QHg== X-Gm-Message-State: AOAM530Ny0NU/vtwsm8Rl7jsxPH7Lhcln39+uLk4Pgayz1XBeVvpMcyu 4eM86NfrXIRsBNKgLkMPxf3jhQ== X-Google-Smtp-Source: ABdhPJwJFoP2AoBOi0/Lpv5FIoWr4q1oM0BAHDJboChbC8FCLPQd4CMCNVbVyuPHiaJPBASD8aIioQ== X-Received: by 2002:a2e:8346:0:b0:246:c11:b4c3 with SMTP id l6-20020a2e8346000000b002460c11b4c3mr1485442ljh.351.1645018226660; Wed, 16 Feb 2022 05:30:26 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:26 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 3/9] net: bridge: vlan: Notify switchdev drivers of VLAN MST migrations Date: Wed, 16 Feb 2022 14:29:28 +0100 Message-Id: <20220216132934.1775649-4-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Whenever a VLAN moves to a new MSTID, send a switchdev notification so that switchdevs can track a bridge's VID to MSTID mapping. Signed-off-by: Tobias Waldekranz --- include/net/switchdev.h | 10 ++++++++++ net/bridge/br_vlan.c | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index d353793dfeb5..ee4a7bd1e540 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -28,6 +28,7 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED, SWITCHDEV_ATTR_ID_BRIDGE_MROUTER, SWITCHDEV_ATTR_ID_MRP_PORT_ROLE, + SWITCHDEV_ATTR_ID_VLAN_MSTID, }; =20 struct switchdev_brport_flags { @@ -35,6 +36,14 @@ struct switchdev_brport_flags { unsigned long mask; }; =20 +struct switchdev_vlan_attr { + u16 vid; + + union { + u16 mstid; + }; +}; + struct switchdev_attr { struct net_device *orig_dev; enum switchdev_attr_id id; @@ -50,6 +59,7 @@ struct switchdev_attr { u16 vlan_protocol; /* BRIDGE_VLAN_PROTOCOL */ bool mc_disabled; /* MC_DISABLED */ u8 mrp_port_role; /* MRP_PORT_ROLE */ + struct switchdev_vlan_attr vlan_attr; /* VLAN_* */ } u; }; =20 diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 459e84a7354d..c45a34c14e10 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -173,6 +173,26 @@ static int br_vlan_mst_migrate(struct net_bridge_vlan = *v, u16 mstid) old_mst =3D rtnl_dereference(v->mst); rcu_assign_pointer(v->mst, mst); =20 + if (br_vlan_is_master(v)) { + struct switchdev_attr attr =3D { + .id =3D SWITCHDEV_ATTR_ID_VLAN_MSTID, + .flags =3D SWITCHDEV_F_DEFER, + .orig_dev =3D br->dev, + .u.vlan_attr =3D { + .vid =3D v->vid, + .mstid =3D mstid, + }, + }; + int err; + + err =3D switchdev_port_attr_set(br->dev, &attr, NULL); + if (err && err !=3D -EOPNOTSUPP) { + rcu_assign_pointer(v->mst, old_mst); + br_vlan_mst_put(mst); + return err; + } + } + if (old_mst) br_vlan_mst_put(old_mst); =20 --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E048C4332F for ; Wed, 16 Feb 2022 13:30:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234510AbiBPNbG (ORCPT ); Wed, 16 Feb 2022 08:31:06 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234354AbiBPNal (ORCPT ); Wed, 16 Feb 2022 08:30:41 -0500 Received: from mail-lf1-x12a.google.com (mail-lf1-x12a.google.com [IPv6:2a00:1450:4864:20::12a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28C1C1712B4 for ; Wed, 16 Feb 2022 05:30:29 -0800 (PST) Received: by mail-lf1-x12a.google.com with SMTP id b11so3802433lfb.12 for ; Wed, 16 Feb 2022 05:30:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=cB26irAVuZwgNbEFS2NIqDPkpe7vp7yzpsmTQMM5rLM=; b=uPIDQeX7oc2WSeCALfzmEetKxr7dbxXYjQ+wziKJoKb/BtdBPLPbLjZiTrubzjScbg ZGuhh0jF8MSrl2nsbmravglWDZ2yny96hMFByFSyLRXXr3GKCocOVtaM6RT/F2qSAabo 2OSZaAb3m88zWumgY9rqUyk9zBkjVhOMNnBaxByHxj12hWiNwmzA26mLec+PBWB2Xk7x JjX/+rEMoiEdmf3QZtS9aF75KfkwdUsjLtglwt0C+P3sZZY8TleUYAE+VF8ChIQ04lL7 XKw0rVTPBoSJ7JqH/S4uMMwSEvwjuaA9c4JolSs0B3I297r7yLFsfSfvPafx8mY71FUb sg2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=cB26irAVuZwgNbEFS2NIqDPkpe7vp7yzpsmTQMM5rLM=; b=ol4NyidzhRKptDpEV/RwEQz7KuRTMDgno7QFHEvsJPLghnLpzMbca2FnY6gv1AZgVg y0qWK8uyLKl7IHS0ZlDk3RSCbyanr6iSGZfGNFhDvE9s2n1Y58coDqdoq9ipEKAWiTx9 5cJditRIiEwUEMNBASsm02arnOpxAsnuelPoKC9LmfDp9r9VZLt2CfoaU4k24fADu0hN ZzW3Jn+rlVm39O4fGZn5n8lq8dDV9gueGs3iNuAv/gCaS8JLvftwgbdKawwAO9FSRR9B 0fpNUnhduZAFQy99jxuEv7EZI36FQcW9+0grq6hyxf5K9NGEZg0X7mnScgR1rnvjFG9x Oekg== X-Gm-Message-State: AOAM531AonTWOtUyMb0ZEnjcTyE1QU9Ltnbi+P+/6YKswcJdIvKkLIIs kuKxyooaltFRfXaCd5IMUkYCYw== X-Google-Smtp-Source: ABdhPJxZkV6eMfaeGtpjNsinws3XN9P9qHnpwCss+A2MtvJiN9KtLVQWEjrU0ogr3ac2onGKtFfefQ== X-Received: by 2002:ac2:4d04:0:b0:443:9688:7ced with SMTP id r4-20020ac24d04000000b0044396887cedmr874565lfi.37.1645018227501; Wed, 16 Feb 2022 05:30:27 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:27 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 4/9] net: bridge: vlan: Notify switchdev drivers of MST state changes Date: Wed, 16 Feb 2022 14:29:29 +0100 Message-Id: <20220216132934.1775649-5-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Generate a switchdev notification whenever a per-VLAN STP state changes. This notification is keyed by the VLANs MSTID rather than the VID, since multiple VLANs may share the same MST instance. Signed-off-by: Tobias Waldekranz --- include/net/switchdev.h | 7 +++++++ net/bridge/br_vlan_options.c | 22 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index ee4a7bd1e540..0a3e0e0bb10a 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -19,6 +19,7 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_ID_UNDEFINED, SWITCHDEV_ATTR_ID_PORT_STP_STATE, + SWITCHDEV_ATTR_ID_PORT_MST_STATE, SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, SWITCHDEV_ATTR_ID_PORT_MROUTER, @@ -31,6 +32,11 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_ID_VLAN_MSTID, }; =20 +struct switchdev_mst_state { + u16 mstid; + u8 state; +}; + struct switchdev_brport_flags { unsigned long val; unsigned long mask; @@ -52,6 +58,7 @@ struct switchdev_attr { void (*complete)(struct net_device *dev, int err, void *priv); union { u8 stp_state; /* PORT_STP_STATE */ + struct switchdev_mst_state mst_state; /* PORT_MST_STATE */ struct switchdev_brport_flags brport_flags; /* PORT_BRIDGE_FLAGS */ bool mrouter; /* PORT_MROUTER */ clock_t ageing_time; /* BRIDGE_AGEING_TIME */ diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index 1c0fd55fe6c9..b8840294f98e 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -5,6 +5,7 @@ #include #include #include +#include =20 #include "br_private.h" #include "br_private_tunnel.h" @@ -80,7 +81,16 @@ static int br_vlan_modify_state(struct net_bridge_vlan_g= roup *vg, bool *changed, struct netlink_ext_ack *extack) { + struct switchdev_attr attr =3D { + .id =3D SWITCHDEV_ATTR_ID_PORT_MST_STATE, + .flags =3D SWITCHDEV_F_DEFER, + .u.mst_state =3D { + .mstid =3D br_vlan_mstid_get(v), + .state =3D state, + }, + }; struct net_bridge *br; + int err; =20 ASSERT_RTNL(); =20 @@ -89,10 +99,12 @@ static int br_vlan_modify_state(struct net_bridge_vlan_= group *vg, return -EINVAL; } =20 - if (br_vlan_is_brentry(v)) + if (br_vlan_is_brentry(v)) { br =3D v->br; - else + } else { br =3D v->port->br; + attr.orig_dev =3D v->port->dev; + } =20 if (br->stp_enabled =3D=3D BR_KERNEL_STP) { NL_SET_ERR_MSG_MOD(extack, "Can't modify vlan state when using kernel ST= P"); @@ -102,6 +114,12 @@ static int br_vlan_modify_state(struct net_bridge_vlan= _group *vg, if (br_vlan_get_state_rtnl(v) =3D=3D state) return 0; =20 + if (attr.orig_dev) { + err =3D switchdev_port_attr_set(attr.orig_dev, &attr, NULL); + if (err && err !=3D -EOPNOTSUPP) + return err; + } + if (v->vid =3D=3D br_get_pvid(vg)) br_vlan_set_pvid_state(vg, state); =20 --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 500AEC4321E for ; Wed, 16 Feb 2022 13:30:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234413AbiBPNbA (ORCPT ); Wed, 16 Feb 2022 08:31:00 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234345AbiBPNam (ORCPT ); Wed, 16 Feb 2022 08:30:42 -0500 Received: from mail-lf1-x131.google.com (mail-lf1-x131.google.com [IPv6:2a00:1450:4864:20::131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 625EE166E1C for ; Wed, 16 Feb 2022 05:30:30 -0800 (PST) Received: by mail-lf1-x131.google.com with SMTP id p22so3866269lfu.5 for ; Wed, 16 Feb 2022 05:30:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=V1eQh2z2Mp1dVqtDPqG/YccGeTfz3qSetOtmZo+4lcI=; b=4Z9spyZJh7I6GdzYp1fUuY70ylRefnQynE2afvnnLFa/c9ru744iYsrV7GcIN6GCIr azVyPHTH8XsrmRbOF/9lSx5VTcSZAfTlNk0LmtMdOvUycpITjHKdm01opJv6+j3Yz5Ro c/ztRs1SefZd5LUk5cDjkz1Vq+TR6PsWDvLGVHZhnLPP8axeyShWStroQAlIxab7MZp1 UwS+th+DXfSoDOp92F7yzPH6Xv/F71AhcnEd0lepnoZ5ry01Sf1xg95Y1uTY779/YcvD vMgLZV5svdBdcAST0pvnBH6TS1vD0+BOGrVJg6VUSR9cMTYLcbrkYGzHSYtxN3geykH+ V/6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=V1eQh2z2Mp1dVqtDPqG/YccGeTfz3qSetOtmZo+4lcI=; b=sR1ZQ+C6lvBHrsPMRYSBHJ7V/6bcNEheOM4RTnaEiIUnscBXprZVPCEEmvlHTfGDBQ g01pK86SK5unoeYKoqHDuaEuxckUAWYxAFqlxhaGqnu/rWETlvshmx/HoWg+B5vDViDs LPpFqCjOJqSNc1HpxpfmxD8M/WIPskPcAX0px7haAVEJbAbPvJBcl+9WYkyowmI+ECSN 3Gpz9kYnKFWP5QgEoyw2H29Gzh9JjxY4Qyd8Ewy3qZA+TKdbTsCza/mgz8+fmHiCy6/l P3MXVb0zsMZxAiRhSrhZPWJSsWFnx/JbOikrAwZLhYCnsYZUp6vBzUopLvyE5zJkDQC6 EFBg== X-Gm-Message-State: AOAM532c1sjRBvLw4HujQ46TGcFwZ/gG3J2undr2cdAdG0K6FbFEpDA+ Q2meSpNoiMvlIv9YLHdS0ARCiw== X-Google-Smtp-Source: ABdhPJxrdT9GpN5CD0SXwHRy99cf5gwLF/Zjv5+srBYJhHsU3KKNdraqOtxfe9PAMcnY4S+oWN1L8Q== X-Received: by 2002:a05:6512:22c5:b0:443:890c:a9e3 with SMTP id g5-20020a05651222c500b00443890ca9e3mr2007506lfu.662.1645018228436; Wed, 16 Feb 2022 05:30:28 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:28 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 5/9] net: dsa: Pass VLAN MST migration notifications to driver Date: Wed, 16 Feb 2022 14:29:30 +0100 Message-Id: <20220216132934.1775649-6-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add the usual trampoline functionality from the generic DSA layer down to the drivers for VLAN MST migrations. Signed-off-by: Tobias Waldekranz --- include/net/dsa.h | 3 +++ net/bridge/br_vlan.c | 2 +- net/dsa/dsa_priv.h | 1 + net/dsa/port.c | 10 ++++++++++ net/dsa/slave.c | 6 ++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index fd1f62a6e0a8..2aabe7f0b176 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -901,6 +901,9 @@ struct dsa_switch_ops { struct netlink_ext_ack *extack); int (*port_vlan_del)(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); + int (*vlan_mstid_set)(struct dsa_switch *ds, + const struct switchdev_attr *attr); + /* * Forwarding database */ diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index c45a34c14e10..48b2f5dd277c 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -173,7 +173,7 @@ static int br_vlan_mst_migrate(struct net_bridge_vlan *= v, u16 mstid) old_mst =3D rtnl_dereference(v->mst); rcu_assign_pointer(v->mst, mst); =20 - if (br_vlan_is_master(v)) { + if (!old_mst || br_vlan_is_master(v)) { struct switchdev_attr attr =3D { .id =3D SWITCHDEV_ATTR_ID_VLAN_MSTID, .flags =3D SWITCHDEV_F_DEFER, diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2bbfa9efe9f8..43709c005461 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -204,6 +204,7 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool v= lan_filtering, struct netlink_ext_ack *extack); bool dsa_port_skip_vlan_configuration(struct dsa_port *dp); int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock); +int dsa_port_vlan_mstid(struct dsa_port *dp, const struct switchdev_attr *= attr); int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, bool targeted_match); int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, diff --git a/net/dsa/port.c b/net/dsa/port.c index bd78192e0e47..4fb2bf2383d9 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -729,6 +729,16 @@ int dsa_port_bridge_flags(struct dsa_port *dp, return 0; } =20 +int dsa_port_vlan_mstid(struct dsa_port *dp, const struct switchdev_attr *= attr) +{ + struct dsa_switch *ds =3D dp->ds; + + if (!ds->ops->vlan_mstid_set) + return -EOPNOTSUPP; + + return ds->ops->vlan_mstid_set(ds, attr); +} + int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, bool targeted_match) { diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 2f6caf5d037e..0a5e44105add 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -314,6 +314,12 @@ static int dsa_slave_port_attr_set(struct net_device *= dev, const void *ctx, =20 ret =3D dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); break; + case SWITCHDEV_ATTR_ID_VLAN_MSTID: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret =3D dsa_port_vlan_mstid(dp, attr); + break; default: ret =3D -EOPNOTSUPP; break; --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD9AEC433EF for ; Wed, 16 Feb 2022 13:30:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234580AbiBPNbK (ORCPT ); Wed, 16 Feb 2022 08:31:10 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234352AbiBPNan (ORCPT ); Wed, 16 Feb 2022 08:30:43 -0500 Received: from mail-lf1-x131.google.com (mail-lf1-x131.google.com [IPv6:2a00:1450:4864:20::131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3DDDB18338A for ; Wed, 16 Feb 2022 05:30:31 -0800 (PST) Received: by mail-lf1-x131.google.com with SMTP id b11so3802598lfb.12 for ; Wed, 16 Feb 2022 05:30:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=sO7CNG0sSQG2qIDEEmS29gE5qWYIsAYkV+SmsMaOSJ4=; b=gOrriYj16c35aVCnfYWpRbk0Atd6fYsrMATkiD1ZUM2tcGyId/6rTmembEUOmPLJSt gYijA3m/cbaLv75Kj/xyi/3f2Q7QHz96y0zSfBlh4uPonHh+xibUVzAMwPEL6+fhG2AH ftAolTsPvTIDoCuNzUzo6W3B3+BAFCyL9ERaqw/WsOwOdlMHiDErnfbSL7oTtmDBmAyj oJxh/5dbwEEgXqQuLGtCO3UwBt3jvfHB66SzfHwCPhIYrvatLaSrPCU5unZzssKxe80Y NQjwDtsDSqD4ZMOprRF+nJtsB13dFQ54jUCWS+wUh2gHHgRoQb6NpjO8g1+v4MHrT9HX 4G8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=sO7CNG0sSQG2qIDEEmS29gE5qWYIsAYkV+SmsMaOSJ4=; b=nN0n3T/QzjMYFnaaOM98t0Z5007rSe897Hd6/pu/iwZa2CnZA00ze0VhoC6kiaFwmR Ruf2szZXvT6rvGQfpbAljXG3ZMZOBpp7V2SX4AJQWBL17nr9gUs1gh25kgPOcLpKSTl6 f814eOSpbD/JS/fgbdweGxVd6oLBS+U/n0NhHcT0tAfsIllXTEvrNlAA0yPbcn93nRR7 Sl4mmXHDffMLfdcRhBMtCqxc32MsgcDJyg0KAqALyYOeNxv/jD8X9UgkblWijbFP6df7 6nxMo4AVR+UgnIe9C5EtEjI1nvEVDO5lw9KrYNdTQAQMPSaSMmQujAwNTa1qek6LZZDp EXOA== X-Gm-Message-State: AOAM531QcEhxTtYj+OCzCGWbrtDwEzaZk2ZtIL0sE0ZQ8Ia4S6Jvr3MA cAIbk4oHwOa0fqdiHIgkwxYGUQ== X-Google-Smtp-Source: ABdhPJx2UytE2+3TxqwsBnenNFkHZlwOqXn+BLp+1SNYsWCd5bYpzcXqbQsl8/D/zA8Xk6OSWPsezA== X-Received: by 2002:a19:dc0f:0:b0:439:702c:d83b with SMTP id t15-20020a19dc0f000000b00439702cd83bmr1932630lfg.192.1645018229578; Wed, 16 Feb 2022 05:30:29 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:28 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 6/9] net: dsa: Pass MST state changes to driver Date: Wed, 16 Feb 2022 14:29:31 +0100 Message-Id: <20220216132934.1775649-7-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add the usual trampoline functionality from the generic DSA layer down to the drivers for MST state changes. Signed-off-by: Tobias Waldekranz --- include/net/dsa.h | 2 ++ net/dsa/dsa_priv.h | 2 ++ net/dsa/port.c | 30 ++++++++++++++++++++++++++++++ net/dsa/slave.c | 6 ++++++ 4 files changed, 40 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 2aabe7f0b176..f030afb68f46 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -882,6 +882,8 @@ struct dsa_switch_ops { struct dsa_bridge bridge); void (*port_stp_state_set)(struct dsa_switch *ds, int port, u8 state); + int (*port_mst_state_set)(struct dsa_switch *ds, int port, + const struct switchdev_mst_state *state); void (*port_fast_age)(struct dsa_switch *ds, int port); int (*port_pre_bridge_flags)(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 43709c005461..96d09184de5d 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -185,6 +185,8 @@ static inline struct net_device *dsa_master_find_slave(= struct net_device *dev, void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp, const struct dsa_device_ops *tag_ops); int dsa_port_set_state(struct dsa_port *dp, u8 state, bool do_fast_age); +int dsa_port_set_mst_state(struct dsa_port *dp, + const struct switchdev_mst_state *state); int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy); int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy); void dsa_port_disable_rt(struct dsa_port *dp); diff --git a/net/dsa/port.c b/net/dsa/port.c index 4fb2bf2383d9..a34779658f17 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -108,6 +108,36 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, = bool do_fast_age) return 0; } =20 +int dsa_port_set_mst_state(struct dsa_port *dp, + const struct switchdev_mst_state *state) +{ + struct dsa_switch *ds =3D dp->ds; + int err, port =3D dp->index; + + if (!ds->ops->port_mst_state_set) + return -EOPNOTSUPP; + + err =3D ds->ops->port_mst_state_set(ds, port, state); + if (err) + return err; + + if (!dsa_port_can_configure_learning(dp) || dp->learning) { + switch (state->state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + /* Ideally we would only fast age entries + * belonging to VLANs controlled by this + * MST. + */ + dsa_port_fast_age(dp); + break; + } + } + + return 0; +} + static void dsa_port_set_state_now(struct dsa_port *dp, u8 state, bool do_fast_age) { diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0a5e44105add..48075d697588 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -288,6 +288,12 @@ static int dsa_slave_port_attr_set(struct net_device *= dev, const void *ctx, =20 ret =3D dsa_port_set_state(dp, attr->u.stp_state, true); break; + case SWITCHDEV_ATTR_ID_PORT_MST_STATE: + if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret =3D dsa_port_set_mst_state(dp, &attr->u.mst_state); + break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) return -EOPNOTSUPP; --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2764C433EF for ; Wed, 16 Feb 2022 13:31:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234422AbiBPNbU (ORCPT ); Wed, 16 Feb 2022 08:31:20 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234415AbiBPNap (ORCPT ); Wed, 16 Feb 2022 08:30:45 -0500 Received: from mail-lf1-x132.google.com (mail-lf1-x132.google.com [IPv6:2a00:1450:4864:20::132]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 974DA166E1C for ; Wed, 16 Feb 2022 05:30:32 -0800 (PST) Received: by mail-lf1-x132.google.com with SMTP id p22so3866497lfu.5 for ; Wed, 16 Feb 2022 05:30:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=/dGkBG/AL/OmQrFSF3PUEoxbQpNPrSZOnReBz5Z0zkw=; b=40TMiDsCRaHX7hBfhs4oGTQEd4V+40QbIGFli/2/NTaeOCt6xlqnP5TB4XkW+CBV/6 +gpNYvjFHtqAs61GK15nIWh/DYU+SiFjn/v7ZImlKqTzIA/OzQwiBRleydjou6W2EekI UBjInpzWj9+ru33C8lsgeMi2UaSQB6KNutDtDuN/L7L/3jq/aowrH3o6A4z8CurKWLGq A1rP5R9gPf7wtB5kv+5i+9CaTx8gCV/j5mDxtg7znoietEGtfBgfhBShSGEV2/o0YgtM FXZIgtfL2UY25KyWn5Kv0aqNsYuLDujw+IU+Yk/v6sKEX1xTSUKZb5QuoG69ByW4l62Z v7+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=/dGkBG/AL/OmQrFSF3PUEoxbQpNPrSZOnReBz5Z0zkw=; b=KJ+/IloSgb8Klw66VF0DJKwbNGd856P/FQJnnI3foyNJmJC60b+fyIk2W24pU7oDw9 QJBbeVHHAJloO0+Q8Otw+9pg6cmh1kBFdeBHmWwy/n7xaFxqCggLdVqgGtcpey8lvbbh iq8mjdNliHofAELE61Gc1UYADDojLirbD/Wu0ncYbIX+wTLtvarLY0mXsjtK4M76xvmz JZ/0HBFrDxERKV+GfKxu1uoqXXFRc/AHdeMWIuf8lpj2l5MpgqGi4m2S4m56wpMTqx7m xZaR3C+JLZBQhMn9SVjXQd2qtqiANmFbPsAapCmg3aULIX42heuBxCuPGc5UveniMxam g2kQ== X-Gm-Message-State: AOAM533fLavvSYxrGsY6oIO5VV8U6ETUOYNZ/dYUGVc/2fMgXy4gf0iw iSsv6WeB/y1lulhEJI5GLQpYeA== X-Google-Smtp-Source: ABdhPJyI96fXxwdjtQkQZKKH7ruptn31G5CSbNYyIcM6204tWLe0Fyk9Nt2hr8cWYA0c+XhwvveCvQ== X-Received: by 2002:ac2:4893:0:b0:443:3b8d:b54f with SMTP id x19-20020ac24893000000b004433b8db54fmr1932331lfc.73.1645018230742; Wed, 16 Feb 2022 05:30:30 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:30 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 7/9] net: dsa: mv88e6xxx: Disentangle STU from VTU Date: Wed, 16 Feb 2022 14:29:32 +0100 Message-Id: <20220216132934.1775649-8-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In early LinkStreet silicon (e.g. 6095/6185), the per-VLAN STP states were kept in the VTU - there was no concept of a SID. Later, the information was split into two tables, where the VTU only tracked memberships and deferred the STP state tracking to the STU via a pointer (SID). This meant that a group of VLANs could share the same STU entry. Most likely, this was done to align with MSTP (802.1Q-2018, Clause 13), which is built on this principle. While the VTU is still 4k lines on most devices, the STU is capped at 64 entries. This means that the current stategy, updating STU info whenever a VTU entry is updated, can not easily support MSTP because: - The maximum number of VIDs would also be capped at 64, as we would have to allocate one SID for every VTU entry - even if many VLANs would effectively share the same MST. - MSTP updates would be unnecessarily slow as you would have to iterate over all VLANs that share the same MST. In order to support MSTP offloading in the future, manage the STU as a separate entity from the VTU. Only add support for newer hardware with separate VTU and STU. VTU-only devices can also be supported, but essentially this requires a software implementation of an STU (fanning out state changed to all VLANs tied to the same MST). Signed-off-by: Tobias Waldekranz --- drivers/net/dsa/mv88e6xxx/chip.c | 54 ++++ drivers/net/dsa/mv88e6xxx/chip.h | 24 ++ drivers/net/dsa/mv88e6xxx/global1.h | 10 + drivers/net/dsa/mv88e6xxx/global1_vtu.c | 311 ++++++++++++++---------- 4 files changed, 264 insertions(+), 135 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/c= hip.c index 34036c555977..39cf1bae161e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1790,6 +1790,33 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *= chip, u16 *fid) return mv88e6xxx_g1_atu_flush(chip, *fid, true); } =20 +static int mv88e6xxx_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + if (!chip->info->ops->stu_loadpurge) + return -EOPNOTSUPP; + + return chip->info->ops->stu_loadpurge(chip, entry); +} + +static int mv88e6xxx_stu_setup(struct mv88e6xxx_chip *chip) +{ + struct mv88e6xxx_stu_entry stu =3D { + .valid =3D true, + .sid =3D 0 + }; + + if (!mv88e6xxx_has_stu(chip)) + return 0; + + /* Make sure that SID 0 is always valid. This is used by VTU + * entries that do not make use of the STU, e.g. when creating + * a VLAN upper on a port that is also part of a VLAN + * filtering bridge. + */ + return mv88e6xxx_stu_loadpurge(chip, &stu); +} + static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, u16 vid) { @@ -3415,6 +3442,13 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) if (err) goto unlock; =20 + /* Must be called after mv88e6xxx_vtu_setup (which flushes the + * VTU, thereby also flushing the STU). + */ + err =3D mv88e6xxx_stu_setup(chip); + if (err) + goto unlock; + /* Setup Switch Port Registers */ for (i =3D 0; i < mv88e6xxx_num_ports(chip); i++) { if (dsa_is_unused_port(ds, i)) @@ -3870,6 +3904,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops =3D { .vtu_getnext =3D mv88e6352_g1_vtu_getnext, .vtu_loadpurge =3D mv88e6352_g1_vtu_loadpurge, .phylink_get_caps =3D mv88e6095_phylink_get_caps, + .stu_getnext =3D mv88e6352_g1_stu_getnext, + .stu_loadpurge =3D mv88e6352_g1_stu_loadpurge, .set_max_frame_size =3D mv88e6185_g1_set_max_frame_size, }; =20 @@ -4956,6 +4992,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops =3D { .atu_set_hash =3D mv88e6165_g1_atu_set_hash, .vtu_getnext =3D mv88e6352_g1_vtu_getnext, .vtu_loadpurge =3D mv88e6352_g1_vtu_loadpurge, + .stu_getnext =3D mv88e6352_g1_stu_getnext, + .stu_loadpurge =3D mv88e6352_g1_stu_loadpurge, .serdes_get_lane =3D mv88e6352_serdes_get_lane, .serdes_pcs_get_state =3D mv88e6352_serdes_pcs_get_state, .serdes_pcs_config =3D mv88e6352_serdes_pcs_config, @@ -5021,6 +5059,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops =3D { .atu_set_hash =3D mv88e6165_g1_atu_set_hash, .vtu_getnext =3D mv88e6390_g1_vtu_getnext, .vtu_loadpurge =3D mv88e6390_g1_vtu_loadpurge, + .stu_getnext =3D mv88e6390_g1_stu_getnext, + .stu_loadpurge =3D mv88e6390_g1_stu_loadpurge, .serdes_power =3D mv88e6390_serdes_power, .serdes_get_lane =3D mv88e6390_serdes_get_lane, /* Check status register pause & lpa register */ @@ -5086,6 +5126,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops =3D { .atu_set_hash =3D mv88e6165_g1_atu_set_hash, .vtu_getnext =3D mv88e6390_g1_vtu_getnext, .vtu_loadpurge =3D mv88e6390_g1_vtu_loadpurge, + .stu_getnext =3D mv88e6390_g1_stu_getnext, + .stu_loadpurge =3D mv88e6390_g1_stu_loadpurge, .serdes_power =3D mv88e6390_serdes_power, .serdes_get_lane =3D mv88e6390x_serdes_get_lane, .serdes_pcs_get_state =3D mv88e6390_serdes_pcs_get_state, @@ -5154,6 +5196,8 @@ static const struct mv88e6xxx_ops mv88e6393x_ops =3D { .atu_set_hash =3D mv88e6165_g1_atu_set_hash, .vtu_getnext =3D mv88e6390_g1_vtu_getnext, .vtu_loadpurge =3D mv88e6390_g1_vtu_loadpurge, + .stu_getnext =3D mv88e6390_g1_stu_getnext, + .stu_loadpurge =3D mv88e6390_g1_stu_loadpurge, .serdes_power =3D mv88e6393x_serdes_power, .serdes_get_lane =3D mv88e6393x_serdes_get_lane, .serdes_pcs_get_state =3D mv88e6393x_serdes_pcs_get_state, @@ -5222,6 +5266,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_ports =3D 11, .num_internal_phys =3D 8, .max_vid =3D 4095, + .max_sid =3D 63, .port_base_addr =3D 0x10, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5475,6 +5520,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_internal_phys =3D 9, .num_gpio =3D 16, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5498,6 +5544,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_internal_phys =3D 9, .num_gpio =3D 16, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5520,6 +5567,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_ports =3D 11, /* 10 + Z80 */ .num_internal_phys =3D 9, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5542,6 +5590,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_ports =3D 11, /* 10 + Z80 */ .num_internal_phys =3D 9, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5564,6 +5613,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_ports =3D 11, /* 10 + Z80 */ .num_internal_phys =3D 9, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5803,6 +5853,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_internal_phys =3D 5, .num_gpio =3D 15, .max_vid =3D 4095, + .max_sid =3D 63, .port_base_addr =3D 0x10, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5827,6 +5878,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_internal_phys =3D 9, .num_gpio =3D 16, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5851,6 +5903,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_internal_phys =3D 9, .num_gpio =3D 16, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, @@ -5874,6 +5927,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = =3D { .num_ports =3D 11, /* 10 + Z80 */ .num_internal_phys =3D 9, .max_vid =3D 8191, + .max_sid =3D 63, .port_base_addr =3D 0x0, .phy_base_addr =3D 0x0, .global1_addr =3D 0x1b, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/c= hip.h index 30b92a265613..be654be69982 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -20,6 +20,7 @@ =20 #define EDSA_HLEN 8 #define MV88E6XXX_N_FID 4096 +#define MV88E6XXX_N_SID 64 =20 #define MV88E6XXX_FID_STANDALONE 0 #define MV88E6XXX_FID_BRIDGED 1 @@ -130,6 +131,7 @@ struct mv88e6xxx_info { unsigned int num_internal_phys; unsigned int num_gpio; unsigned int max_vid; + unsigned int max_sid; unsigned int port_base_addr; unsigned int phy_base_addr; unsigned int global1_addr; @@ -181,6 +183,12 @@ struct mv88e6xxx_vtu_entry { bool valid; bool policy; u8 member[DSA_MAX_PORTS]; + u8 state[DSA_MAX_PORTS]; /* Older silicon has no STU */ +}; + +struct mv88e6xxx_stu_entry { + u8 sid; + bool valid; u8 state[DSA_MAX_PORTS]; }; =20 @@ -602,6 +610,12 @@ struct mv88e6xxx_ops { int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); =20 + /* Spanning Tree Unit operations */ + int (*stu_getnext)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); + int (*stu_loadpurge)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); + /* GPIO operations */ const struct mv88e6xxx_gpio_ops *gpio_ops; =20 @@ -700,6 +714,11 @@ struct mv88e6xxx_hw_stat { int type; }; =20 +static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip) +{ + return chip->info->max_sid > 0; +} + static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip) { return chip->info->pvt; @@ -730,6 +749,11 @@ static inline unsigned int mv88e6xxx_max_vid(struct mv= 88e6xxx_chip *chip) return chip->info->max_vid; } =20 +static inline unsigned int mv88e6xxx_max_sid(struct mv88e6xxx_chip *chip) +{ + return chip->info->max_sid; +} + static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) { return GENMASK((s32)mv88e6xxx_num_ports(chip) - 1, 0); diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xx= x/global1.h index 2c1607c858a1..65958b2a0d3a 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -348,6 +348,16 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *ch= ip, int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); +int mv88e6352_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); +int mv88e6352_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); +int mv88e6390_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); +int mv88e6390_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry); int mv88e6xxx_g1_vtu_prob_irq_setup(struct mv88e6xxx_chip *chip); void mv88e6xxx_g1_vtu_prob_irq_free(struct mv88e6xxx_chip *chip); int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid); diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88= e6xxx/global1_vtu.c index b1bd9274a562..38e18f5811bf 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -44,8 +44,7 @@ static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_ch= ip *chip, =20 /* Offset 0x03: VTU SID Register */ =20 -static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, u8 *sid) { u16 val; int err; @@ -54,15 +53,14 @@ static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_c= hip *chip, if (err) return err; =20 - entry->sid =3D val & MV88E6352_G1_VTU_SID_MASK; + *sid =3D val & MV88E6352_G1_VTU_SID_MASK; =20 return 0; } =20 -static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, u8 sid) { - u16 val =3D entry->sid & MV88E6352_G1_VTU_SID_MASK; + u16 val =3D sid & MV88E6352_G1_VTU_SID_MASK; =20 return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val); } @@ -91,7 +89,7 @@ static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chi= p, u16 op) /* Offset 0x06: VTU VID Register */ =20 static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + bool *valid, u16 *vid) { u16 val; int err; @@ -100,25 +98,28 @@ static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_= chip *chip, if (err) return err; =20 - entry->vid =3D val & 0xfff; + if (vid) { + *vid =3D val & 0xfff; =20 - if (val & MV88E6390_G1_VTU_VID_PAGE) - entry->vid |=3D 0x1000; + if (val & MV88E6390_G1_VTU_VID_PAGE) + *vid |=3D 0x1000; + } =20 - entry->valid =3D !!(val & MV88E6XXX_G1_VTU_VID_VALID); + if (valid) + *valid =3D !!(val & MV88E6XXX_G1_VTU_VID_VALID); =20 return 0; } =20 static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + bool valid, u16 vid) { - u16 val =3D entry->vid & 0xfff; + u16 val =3D vid & 0xfff; =20 - if (entry->vid & 0x1000) + if (vid & 0x1000) val |=3D MV88E6390_G1_VTU_VID_PAGE; =20 - if (entry->valid) + if (valid) val |=3D MV88E6XXX_G1_VTU_VID_VALID; =20 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val); @@ -147,7 +148,7 @@ static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6= xxx_chip *chip, } =20 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + u8 *member, u8 *state) { u16 regs[3]; int err; @@ -160,36 +161,20 @@ static int mv88e6185_g1_vtu_data_read(struct mv88e6xx= x_chip *chip, /* Extract MemberTag data */ for (i =3D 0; i < mv88e6xxx_num_ports(chip); ++i) { unsigned int member_offset =3D (i % 4) * 4; + unsigned int state_offset =3D member_offset + 2; =20 - entry->member[i] =3D (regs[i / 4] >> member_offset) & 0x3; - } - - return 0; -} - -static int mv88e6185_g1_stu_data_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - u16 regs[3]; - int err; - int i; - - err =3D mv88e6185_g1_vtu_stu_data_read(chip, regs); - if (err) - return err; + if (member) + member[i] =3D (regs[i / 4] >> member_offset) & 0x3; =20 - /* Extract PortState data */ - for (i =3D 0; i < mv88e6xxx_num_ports(chip); ++i) { - unsigned int state_offset =3D (i % 4) * 4 + 2; - - entry->state[i] =3D (regs[i / 4] >> state_offset) & 0x3; + if (state) + state[i] =3D (regs[i / 4] >> state_offset) & 0x3; } =20 return 0; } =20 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + u8 *member, u8 *state) { u16 regs[3] =3D { 0 }; int i; @@ -199,8 +184,11 @@ static int mv88e6185_g1_vtu_data_write(struct mv88e6xx= x_chip *chip, unsigned int member_offset =3D (i % 4) * 4; unsigned int state_offset =3D member_offset + 2; =20 - regs[i / 4] |=3D (entry->member[i] & 0x3) << member_offset; - regs[i / 4] |=3D (entry->state[i] & 0x3) << state_offset; + if (member) + regs[i / 4] |=3D (member[i] & 0x3) << member_offset; + + if (state) + regs[i / 4] |=3D (state[i] & 0x3) << state_offset; } =20 /* Write all 3 VTU/STU Data registers */ @@ -268,48 +256,6 @@ static int mv88e6390_g1_vtu_data_write(struct mv88e6xx= x_chip *chip, u8 *data) =20 /* VLAN Translation Unit Operations */ =20 -static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - int err; - - err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry); - if (err) - return err; - - err =3D mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); - if (err) - return err; - - err =3D mv88e6xxx_g1_vtu_sid_read(chip, entry); - if (err) - return err; - - return mv88e6xxx_g1_vtu_vid_read(chip, entry); -} - -static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *vtu) -{ - struct mv88e6xxx_vtu_entry stu; - int err; - - err =3D mv88e6xxx_g1_vtu_sid_read(chip, vtu); - if (err) - return err; - - stu.sid =3D vtu->sid - 1; - - err =3D mv88e6xxx_g1_vtu_stu_getnext(chip, &stu); - if (err) - return err; - - if (stu.sid !=3D vtu->sid || !stu.valid) - return -EINVAL; - - return 0; -} - int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { @@ -327,7 +273,7 @@ int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chi= p, * write the VID only once, when the entry is given as invalid. */ if (!entry->valid) { - err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_vid_write(chip, false, entry->vid); if (err) return err; } @@ -336,7 +282,7 @@ int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chi= p, if (err) return err; =20 - return mv88e6xxx_g1_vtu_vid_read(chip, entry); + return mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, &entry->vid); } =20 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, @@ -350,11 +296,7 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *ch= ip, return err; =20 if (entry->valid) { - err =3D mv88e6185_g1_vtu_data_read(chip, entry); - if (err) - return err; - - err =3D mv88e6185_g1_stu_data_read(chip, entry); + err =3D mv88e6185_g1_vtu_data_read(chip, entry->member, entry->state); if (err) return err; =20 @@ -384,7 +326,7 @@ int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chi= p, return err; =20 if (entry->valid) { - err =3D mv88e6185_g1_vtu_data_read(chip, entry); + err =3D mv88e6185_g1_vtu_data_read(chip, entry->member, NULL); if (err) return err; =20 @@ -392,12 +334,7 @@ int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *ch= ip, if (err) return err; =20 - /* Fetch VLAN PortState data from the STU */ - err =3D mv88e6xxx_g1_vtu_stu_get(chip, entry); - if (err) - return err; - - err =3D mv88e6185_g1_stu_data_read(chip, entry); + err =3D mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } @@ -420,16 +357,11 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *c= hip, if (err) return err; =20 - /* Fetch VLAN PortState data from the STU */ - err =3D mv88e6xxx_g1_vtu_stu_get(chip, entry); - if (err) - return err; - - err =3D mv88e6390_g1_vtu_data_read(chip, entry->state); + err =3D mv88e6xxx_g1_vtu_fid_read(chip, entry); if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_fid_read(chip, entry); + err =3D mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } @@ -447,12 +379,12 @@ int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip = *chip, if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; =20 if (entry->valid) { - err =3D mv88e6185_g1_vtu_data_write(chip, entry); + err =3D mv88e6185_g1_vtu_data_write(chip, entry->member, entry->state); if (err) return err; =20 @@ -479,27 +411,21 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip = *chip, if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; =20 if (entry->valid) { - /* Write MemberTag and PortState data */ - err =3D mv88e6185_g1_vtu_data_write(chip, entry); - if (err) - return err; - - err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry); + /* Write MemberTag data */ + err =3D mv88e6185_g1_vtu_data_write(chip, entry->member, NULL); if (err) return err; =20 - /* Load STU entry */ - err =3D mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); + err =3D mv88e6xxx_g1_vtu_fid_write(chip, entry); if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_fid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; } @@ -517,41 +443,113 @@ int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip= *chip, if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; =20 if (entry->valid) { - /* Write PortState data */ - err =3D mv88e6390_g1_vtu_data_write(chip, entry->state); + /* Write MemberTag data */ + err =3D mv88e6390_g1_vtu_data_write(chip, entry->member); if (err) return err; =20 - err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_fid_write(chip, entry); if (err) return err; =20 - /* Load STU entry */ - err =3D mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); + err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; + } =20 - /* Write MemberTag data */ - err =3D mv88e6390_g1_vtu_data_write(chip, entry->member); + /* Load/Purge VTU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); +} + +int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) +{ + int err; + + err =3D mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); +} + +/* Spanning Tree Unit Operations */ + +int mv88e6xxx_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err =3D mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + /* To get the next higher active SID, the STU GetNext operation can be + * started again without setting the SID registers since it already + * contains the last SID. + * + * To save a few hardware accesses and abstract this to the caller, + * write the SID only once, when the entry is given as invalid. + */ + if (!entry->valid) { + err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; + } =20 - err =3D mv88e6xxx_g1_vtu_fid_write(chip, entry); + err =3D mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); + if (err) + return err; + + err =3D mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, NULL); + if (err) + return err; + + if (entry->valid) { + err =3D mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } =20 - /* Load/Purge VTU entry */ - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); + return 0; } =20 -int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) +int mv88e6352_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err =3D mv88e6xxx_g1_stu_getnext(chip, entry); + if (err) + return err; + + if (!entry->valid) + return 0; + + return mv88e6185_g1_vtu_data_read(chip, NULL, entry->state); +} + +int mv88e6390_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err =3D mv88e6xxx_g1_stu_getnext(chip, entry); + if (err) + return err; + + if (!entry->valid) + return 0; + + return mv88e6390_g1_vtu_data_read(chip, entry->state); +} + +int mv88e6352_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) { int err; =20 @@ -559,16 +557,59 @@ int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chi= p) if (err) return err; =20 - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); + err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err =3D mv88e6185_g1_vtu_data_write(chip, NULL, entry->state); + if (err) + return err; + } + + /* Load/Purge STU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); +} + +int mv88e6390_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err =3D mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err =3D mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err =3D mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err =3D mv88e6390_g1_vtu_data_write(chip, entry->state); + if (err) + return err; + } + + /* Load/Purge STU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); } =20 +/* VTU Violation Management */ + static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_= id) { struct mv88e6xxx_chip *chip =3D dev_id; - struct mv88e6xxx_vtu_entry entry; + u16 val, vid; int spid; int err; - u16 val; =20 mv88e6xxx_reg_lock(chip); =20 @@ -580,7 +621,7 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(= int irq, void *dev_id) if (err) goto out; =20 - err =3D mv88e6xxx_g1_vtu_vid_read(chip, &entry); + err =3D mv88e6xxx_g1_vtu_vid_read(chip, NULL, &vid); if (err) goto out; =20 @@ -588,13 +629,13 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_f= n(int irq, void *dev_id) =20 if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) { dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source = port %d\n", - entry.vid, spid); + vid, spid); chip->ports[spid].vtu_member_violation++; } =20 if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source po= rt %d\n", - entry.vid, spid); + vid, spid); chip->ports[spid].vtu_miss_violation++; } =20 --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 14B0FC433F5 for ; Wed, 16 Feb 2022 13:31:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234424AbiBPNbM (ORCPT ); Wed, 16 Feb 2022 08:31:12 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234487AbiBPNau (ORCPT ); Wed, 16 Feb 2022 08:30:50 -0500 Received: from mail-lf1-x12c.google.com (mail-lf1-x12c.google.com [IPv6:2a00:1450:4864:20::12c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C073A1728B2 for ; Wed, 16 Feb 2022 05:30:33 -0800 (PST) Received: by mail-lf1-x12c.google.com with SMTP id p22so3866586lfu.5 for ; Wed, 16 Feb 2022 05:30:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=9aG6JPCK/sc9cnjNg+7v1niwfwPA6zUyJ/dRYHoXrdI=; b=GNtYHMmflkakwZq6i29RsDao3BrZgSdMt7dT6HQzznhCZixxEG4L5+AACLMCgtmOw+ BI9wm+/9nQOAtYxgsHh3DTWOQJ5lwf97Rv0atJp/dPjzFGbAs8yAbL/aQkJOONiwRgnh 6LyCkyyQ11vk8AHBIL9pavnlsyGIU6b9h7oq+TjxKi65VNRfv+dHMiZ3d+uQ4ftFomEM hSGRuaZ3xnyUh5Hikuh0aUFit7zHWcH3XwzY1lcNN8sKT53oRFjpOPrsskfoyTB/Mv1E 4YmEhpNXHdHnaKmoJ51SuNhAxucOm8hoC9sl2zopI+sN1eRjGUDQC2V3byXyg9cHoLxo +Ozw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=9aG6JPCK/sc9cnjNg+7v1niwfwPA6zUyJ/dRYHoXrdI=; b=Mn8NNOl6llmeRPvRj5YZFWnxxili3Fayzy+v8KJXlpXlDWdsqxAZAlhixpT3/dKHwv xIYqLs1H3zQH+POZgqG0u6IExft0TkaFDDjep4p+gEkJfgKoGGXV+St3xEELPxW0gMkm Z01jTLzJWAwgzWFgfATvFpARVXX8ZRR05HDfllUx2ac31rgaZu1ozYVQUxfD8qVruFDF Djpewk+iHoHK7MhMbqQeNYMZ+BWykcYwHb4juiSlXMUBiovz+mPQ0MUMjlVukFrbia3t xnE6nd+qN9uQYeGEhYRmvnM1OXdWud0hJn4O9Npy8Tx0LmOHha2GIG5RvEO/Yu1/ua2O HCiA== X-Gm-Message-State: AOAM530wSWZNJ1Ecef2c6hHRJbqKn18YYQXRrUpUTTZWLz33/XV3uiFv cLTa54UC9UiCdBcfT+lWC4NIHg== X-Google-Smtp-Source: ABdhPJyg+scehAihayVhY44Bgyvv+/FzyTQyajhhfVYNAwXSUcRrxMD/t+haHu8aNvmZhZ5P/vQH3w== X-Received: by 2002:a05:6512:3d94:b0:43e:af37:af96 with SMTP id k20-20020a0565123d9400b0043eaf37af96mr1973403lfv.469.1645018231909; Wed, 16 Feb 2022 05:30:31 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:31 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 8/9] net: dsa: mv88e6xxx: Export STU as devlink region Date: Wed, 16 Feb 2022 14:29:33 +0100 Message-Id: <20220216132934.1775649-9-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Export the raw STU data in a devlink region so that it can be inspected from userspace and compared to the current bridge configuration. Signed-off-by: Tobias Waldekranz --- drivers/net/dsa/mv88e6xxx/chip.h | 1 + drivers/net/dsa/mv88e6xxx/devlink.c | 94 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/c= hip.h index be654be69982..6d4daa24d3e5 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -287,6 +287,7 @@ enum mv88e6xxx_region_id { MV88E6XXX_REGION_GLOBAL2, MV88E6XXX_REGION_ATU, MV88E6XXX_REGION_VTU, + MV88E6XXX_REGION_STU, MV88E6XXX_REGION_PVT, =20 _MV88E6XXX_REGION_MAX, diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xx= x/devlink.c index 381068395c63..1266eabee086 100644 --- a/drivers/net/dsa/mv88e6xxx/devlink.c +++ b/drivers/net/dsa/mv88e6xxx/devlink.c @@ -503,6 +503,85 @@ static int mv88e6xxx_region_vtu_snapshot(struct devlin= k *dl, return 0; } =20 +/** + * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry + * @sid: Global1/3: SID, unknown filters and learning. + * @vid: Global1/6: Valid bit. + * @data: Global1/7-9: Membership data and priority override. + * @resvd: Reserved. In case we forgot something. + * + * The STU entry format varies between chipset generations. Peridot + * and Amethyst packs the STU data into Global1/7-8. Older silicon + * spreads the information across all three VTU data registers - + * inheriting the layout of even older hardware that had no STU at + * all. Since this is a low-level debug interface, copy all data + * verbatim and defer parsing to the consumer. + */ +struct mv88e6xxx_devlink_stu_entry { + u16 sid; + u16 vid; + u16 data[3]; + u16 resvd; +}; + +static int mv88e6xxx_region_stu_snapshot(struct devlink *dl, + const struct devlink_region_ops *ops, + struct netlink_ext_ack *extack, + u8 **data) +{ + struct mv88e6xxx_devlink_stu_entry *table, *entry; + struct dsa_switch *ds =3D dsa_devlink_to_ds(dl); + struct mv88e6xxx_chip *chip =3D ds->priv; + struct mv88e6xxx_stu_entry stu; + int err; + + table =3D kcalloc(mv88e6xxx_max_sid(chip) + 1, + sizeof(struct mv88e6xxx_devlink_stu_entry), + GFP_KERNEL); + if (!table) + return -ENOMEM; + + entry =3D table; + stu.sid =3D mv88e6xxx_max_sid(chip); + stu.valid =3D false; + + mv88e6xxx_reg_lock(chip); + + do { + err =3D mv88e6xxx_g1_stu_getnext(chip, &stu); + if (err) + break; + + if (!stu.valid) + break; + + err =3D err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, + &entry->sid); + err =3D err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, + &entry->vid); + err =3D err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1, + &entry->data[0]); + err =3D err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2, + &entry->data[1]); + err =3D err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3, + &entry->data[2]); + if (err) + break; + + entry++; + } while (stu.sid < mv88e6xxx_max_sid(chip)); + + mv88e6xxx_reg_unlock(chip); + + if (err) { + kfree(table); + return err; + } + + *data =3D (u8 *)table; + return 0; +} + static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl, const struct devlink_region_ops *ops, struct netlink_ext_ack *extack, @@ -605,6 +684,12 @@ static struct devlink_region_ops mv88e6xxx_region_vtu_= ops =3D { .destructor =3D kfree, }; =20 +static struct devlink_region_ops mv88e6xxx_region_stu_ops =3D { + .name =3D "stu", + .snapshot =3D mv88e6xxx_region_stu_snapshot, + .destructor =3D kfree, +}; + static struct devlink_region_ops mv88e6xxx_region_pvt_ops =3D { .name =3D "pvt", .snapshot =3D mv88e6xxx_region_pvt_snapshot, @@ -640,6 +725,11 @@ static struct mv88e6xxx_region mv88e6xxx_regions[] =3D= { .ops =3D &mv88e6xxx_region_vtu_ops /* calculated at runtime */ }, + [MV88E6XXX_REGION_STU] =3D { + .ops =3D &mv88e6xxx_region_stu_ops, + .cond =3D mv88e6xxx_has_stu, + /* calculated at runtime */ + }, [MV88E6XXX_REGION_PVT] =3D { .ops =3D &mv88e6xxx_region_pvt_ops, .size =3D MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16), @@ -706,6 +796,10 @@ int mv88e6xxx_setup_devlink_regions_global(struct dsa_= switch *ds) size =3D (mv88e6xxx_max_vid(chip) + 1) * sizeof(struct mv88e6xxx_devlink_vtu_entry); break; + case MV88E6XXX_REGION_STU: + size =3D (mv88e6xxx_max_sid(chip) + 1) * + sizeof(struct mv88e6xxx_devlink_stu_entry); + break; } =20 region =3D dsa_devlink_region_create(ds, ops, 1, size); --=20 2.25.1 From nobody Sun Jun 28 01:54:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A766AC433EF for ; Wed, 16 Feb 2022 13:31:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233744AbiBPNbn (ORCPT ); Wed, 16 Feb 2022 08:31:43 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:42970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234500AbiBPNav (ORCPT ); Wed, 16 Feb 2022 08:30:51 -0500 Received: from mail-lf1-x12f.google.com (mail-lf1-x12f.google.com [IPv6:2a00:1450:4864:20::12f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9DEE3187151 for ; Wed, 16 Feb 2022 05:30:34 -0800 (PST) Received: by mail-lf1-x12f.google.com with SMTP id u20so3878306lff.2 for ; Wed, 16 Feb 2022 05:30:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=waldekranz-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:organization:content-transfer-encoding; bh=u25luItvkqFvSc0IbNowHTs0MkxngGGoablxIWJFpwU=; b=3zRscAoQJZnIioqtBwiIL/vS+HSuL/8Cha1JTBeTnsScmyJWJL6yPWMHWoYiXnhWK5 uClzxydU8kDbfamIU2QAvn66jwTS9se1S9KE+Qc6olXMszJVdb388rvoUTUI4+G9Uigz 9Bbbg5EuMDXE6kbHFdvtedX8085umN9i0vcxL+qCGJf/oz2vLQ2PcUWfyX1Z1CJwJ/pM l7Zr4mfmdpJLVfnU982RcZOY+OtCZoyml37YU6+6WD1Tk45qdsFH+IhlSMHVcGt6f7V6 26OKdqv703p/W3YtC5RgXMyWs018GU69RHGsOtXGQ8Zd43hpnpbcAS9OCz4JeEi1lvOA IhXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:organization:content-transfer-encoding; bh=u25luItvkqFvSc0IbNowHTs0MkxngGGoablxIWJFpwU=; b=s58aFCpsJYF8wIosPXqi4zlsEjVyLAEJ74aQnN4HdDvocZ71nSyoyET4hu0zD7+2S4 P9c/MuN56L+J0FsOPM0ZDyK8+LYMQITn4sDKctt2tgAWiOU+VcUKgxmKKu7dioXGY4RT xtOtaq9QSpAgYHgEGXD3mxs5DOg24LSkmaznUf39WfVBhphMS/ddPbP0eTVL0wlHXxds +CozwPquD1m+slJ3npMlcPe8aoH/fWZC/qgRrGBKZbGPVBdO96c/k0cWxyWuVjADuCyN xAz/25hGHpG0imUKBiSxzPkBWCybld+LyZn16Wpe6HXgcIBfmCKJeMvQNB5anYa2JVCe VK7A== X-Gm-Message-State: AOAM531Hn0PUs9bH/IEQB9lmtPznoHE1CKhonEj1zEFcq5ZpmSHoi3fz Q9Uk6aZNR7YwzRtuSR7Ge4XDMA== X-Google-Smtp-Source: ABdhPJwfxAkbPMUou9xRm+3FfBXpZIFVnjko/BOIfxWn7VkxklvEIWdQabyQpHhC/gj2gb5biiHKtw== X-Received: by 2002:a05:6512:10d6:b0:443:1439:2615 with SMTP id k22-20020a05651210d600b0044314392615mr2070897lfg.602.1645018232955; Wed, 16 Feb 2022 05:30:32 -0800 (PST) Received: from veiron.westermo.com (static-193-12-47-89.cust.tele2.se. [193.12.47.89]) by smtp.gmail.com with ESMTPSA id v6sm234780ljd.86.2022.02.16.05.30.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Feb 2022 05:30:32 -0800 (PST) From: Tobias Waldekranz To: davem@davemloft.net, kuba@kernel.org Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , Vladimir Oltean , Jiri Pirko , Ivan Vecera , Roopa Prabhu , Nikolay Aleksandrov , Russell King , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [RFC net-next 9/9] net: dsa: mv88e6xxx: MST Offloading Date: Wed, 16 Feb 2022 14:29:34 +0100 Message-Id: <20220216132934.1775649-10-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220216132934.1775649-1-tobias@waldekranz.com> References: <20220216132934.1775649-1-tobias@waldekranz.com> MIME-Version: 1.0 Organization: Westermo Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Allocate a SID in the STU for each MSTID in use by a bridge and handle the mapping of MSTIDs to VLANs using the SID field of each VTU entry. Signed-off-by: Tobias Waldekranz --- drivers/net/dsa/mv88e6xxx/chip.c | 169 +++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 13 +++ 2 files changed, 182 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/c= hip.c index 39cf1bae161e..7d9ef041252d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1817,6 +1817,128 @@ static int mv88e6xxx_stu_setup(struct mv88e6xxx_chi= p *chip) return mv88e6xxx_stu_loadpurge(chip, &stu); } =20 +static int mv88e6xxx_sid_new(struct mv88e6xxx_chip *chip, u8 *sid) +{ + DECLARE_BITMAP(busy, MV88E6XXX_N_SID) =3D { 0 }; + struct mv88e6xxx_mst *mst; + + set_bit(0, busy); + + list_for_each_entry(mst, &chip->msts, node) { + set_bit(mst->stu.sid, busy); + } + + *sid =3D find_first_zero_bit(busy, MV88E6XXX_N_SID); + + return (*sid >=3D mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0; +} + +static int mv88e6xxx_sid_put(struct mv88e6xxx_chip *chip, u8 sid) +{ + struct mv88e6xxx_mst *mst, *tmp; + int err =3D 0; + + list_for_each_entry_safe(mst, tmp, &chip->msts, node) { + if (mst->stu.sid =3D=3D sid) { + if (refcount_dec_and_test(&mst->refcnt)) { + mst->stu.valid =3D false; + err =3D mv88e6xxx_stu_loadpurge(chip, &mst->stu); + list_del(&mst->node); + kfree(mst); + } + + return err; + } + } + + return -ENOENT; +} + +static int mv88e6xxx_sid_get(struct mv88e6xxx_chip *chip, struct net_devic= e *br, + u16 mstid, u8 *sid) +{ + struct mv88e6xxx_mst *mst; + int err; + + if (!br) + return 0; + + if (!mv88e6xxx_has_stu(chip)) + return -EOPNOTSUPP; + + list_for_each_entry(mst, &chip->msts, node) { + if (mst->br =3D=3D br && mst->mstid =3D=3D mstid) { + refcount_inc(&mst->refcnt); + *sid =3D mst->stu.sid; + return 0; + } + } + + err =3D mv88e6xxx_sid_new(chip, sid); + if (err) + return err; + + mst =3D kzalloc(sizeof(*mst), GFP_KERNEL); + if (!mst) + return -ENOMEM; + + INIT_LIST_HEAD(&mst->node); + refcount_set(&mst->refcnt, 1); + mst->br =3D br; + mst->mstid =3D mstid; + mst->stu.valid =3D true; + mst->stu.sid =3D *sid; + list_add_tail(&mst->node, &chip->msts); + return mv88e6xxx_stu_loadpurge(chip, &mst->stu); +} + +static int mv88e6xxx_port_mst_state_set(struct dsa_switch *ds, int port, + const struct switchdev_mst_state *st) +{ + struct dsa_port *dp =3D dsa_to_port(ds, port); + struct mv88e6xxx_chip *chip =3D ds->priv; + struct mv88e6xxx_mst *mst; + u8 state; + int err; + + if (!mv88e6xxx_has_stu(chip)) + return -EOPNOTSUPP; + + switch (st->state) { + case BR_STATE_DISABLED: + state =3D MV88E6XXX_PORT_CTL0_STATE_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + state =3D MV88E6XXX_PORT_CTL0_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + state =3D MV88E6XXX_PORT_CTL0_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + state =3D MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + break; + default: + return -EINVAL; + } + + list_for_each_entry(mst, &chip->msts, node) { + if (mst->br =3D=3D dsa_port_bridge_dev_get(dp) && + mst->mstid =3D=3D st->mstid) { + if (mst->stu.state[port] =3D=3D state) + return 0; + + mst->stu.state[port] =3D state; + mv88e6xxx_reg_lock(chip); + err =3D mv88e6xxx_stu_loadpurge(chip, &mst->stu); + mv88e6xxx_reg_unlock(chip); + return err; + } + } + + return -ENOENT; +} + static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, u16 vid) { @@ -2436,6 +2558,12 @@ static int mv88e6xxx_port_vlan_leave(struct mv88e6xx= x_chip *chip, if (err) return err; =20 + if (!vlan.valid) { + err =3D mv88e6xxx_sid_put(chip, vlan.sid); + if (err) + return err; + } + return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); } =20 @@ -2474,6 +2602,44 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch= *ds, int port, return err; } =20 +static int mv88e6xxx_vlan_mstid_set(struct dsa_switch *ds, + const struct switchdev_attr *attr) +{ + const struct switchdev_vlan_attr *vattr =3D &attr->u.vlan_attr; + struct mv88e6xxx_chip *chip =3D ds->priv; + struct mv88e6xxx_vtu_entry vlan; + u8 new_sid; + int err; + + mv88e6xxx_reg_lock(chip); + + err =3D mv88e6xxx_vtu_get(chip, vattr->vid, &vlan); + if (err) + goto unlock; + + if (!vlan.valid) { + err =3D -EINVAL; + goto unlock; + } + + err =3D mv88e6xxx_sid_get(chip, attr->orig_dev, vattr->mstid, &new_sid); + if (err) + goto unlock; + + if (vlan.sid) { + err =3D mv88e6xxx_sid_put(chip, vlan.sid); + if (err) + goto unlock; + } + + vlan.sid =3D new_sid; + err =3D mv88e6xxx_vtu_loadpurge(chip, &vlan); + +unlock: + mv88e6xxx_reg_unlock(chip); + return err; +} + static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid) { @@ -5996,6 +6162,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(st= ruct device *dev) mutex_init(&chip->reg_lock); INIT_LIST_HEAD(&chip->mdios); idr_init(&chip->policies); + INIT_LIST_HEAD(&chip->msts); =20 return chip; } @@ -6518,10 +6685,12 @@ static const struct dsa_switch_ops mv88e6xxx_switch= _ops =3D { .port_pre_bridge_flags =3D mv88e6xxx_port_pre_bridge_flags, .port_bridge_flags =3D mv88e6xxx_port_bridge_flags, .port_stp_state_set =3D mv88e6xxx_port_stp_state_set, + .port_mst_state_set =3D mv88e6xxx_port_mst_state_set, .port_fast_age =3D mv88e6xxx_port_fast_age, .port_vlan_filtering =3D mv88e6xxx_port_vlan_filtering, .port_vlan_add =3D mv88e6xxx_port_vlan_add, .port_vlan_del =3D mv88e6xxx_port_vlan_del, + .vlan_mstid_set =3D mv88e6xxx_vlan_mstid_set, .port_fdb_add =3D mv88e6xxx_port_fdb_add, .port_fdb_del =3D mv88e6xxx_port_fdb_del, .port_fdb_dump =3D mv88e6xxx_port_fdb_dump, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/c= hip.h index 6d4daa24d3e5..af0f53b65689 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -297,6 +297,16 @@ struct mv88e6xxx_region_priv { enum mv88e6xxx_region_id id; }; =20 +struct mv88e6xxx_mst { + struct list_head node; + + refcount_t refcnt; + struct net_device *br; + u16 mstid; + + struct mv88e6xxx_stu_entry stu; +}; + struct mv88e6xxx_chip { const struct mv88e6xxx_info *info; =20 @@ -397,6 +407,9 @@ struct mv88e6xxx_chip { =20 /* devlink regions */ struct devlink_region *regions[_MV88E6XXX_REGION_MAX]; + + /* Bridge MST to SID mappings */ + struct list_head msts; }; =20 struct mv88e6xxx_bus_ops { --=20 2.25.1