From nobody Tue Jun 23 17:22:14 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 44202C433F5 for ; Tue, 1 Mar 2022 10:04:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234175AbiCAKEr (ORCPT ); Tue, 1 Mar 2022 05:04:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42588 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233639AbiCAKEc (ORCPT ); Tue, 1 Mar 2022 05:04:32 -0500 Received: from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com [IPv6:2a00:1450:4864:20::12b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61AA08BF35 for ; Tue, 1 Mar 2022 02:03:50 -0800 (PST) Received: by mail-lf1-x12b.google.com with SMTP id w27so25975301lfa.5 for ; Tue, 01 Mar 2022 02:03:50 -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=soqNIu0iZXYKGoeg5fysgUJf/i7Fd0LPBuPDz6+ETkE=; b=RQFqju729+zbobiJJ66cSJ/tNlAOMqRPvrUm4m5xP0XT7amFkV33K7jbFlh2KrfHDk uZ7i7LpiQZ0PI00pQdUc4zUrXP8pdaCm/Pf/ROXMy4NYjaG7ZF0hS+RYZ3b0tH3eLn/6 z53RGoSzO5S9edpVmoaeUo4nQV3IMRj4d6NDK5f6YnZ5rEboDIUaCXfZMnfMT8G+SIdg QPmTwE1T7KBOeOQEcg4RzPIWskFWU5AyQ7/3p7Yh4xyJxsc3I1COt1gxFbIhsUJZnrAM vIj+5NTY1YJZTOXkPqCBWA1kzbshSaPJiPOY5Q6VFlo8SBi+l0DE2Iaq4K6nURwVroCq Fc5A== 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=soqNIu0iZXYKGoeg5fysgUJf/i7Fd0LPBuPDz6+ETkE=; b=FqbCG7m3zc2QRTKSDgeikW30dgGrBQhJW1YRzn5+lxuKcLmqEPRn7D8Fg7OGZ1fUot YDqxndGwRv14lSohTF5U6IWVaX0RWElHq2Pj2BpGCvW8hsIJ/x9JB9e10ZoPNvbf9JnK xEuGuKuIaOP0PQHzBhcb492PXkR5VLk3HjLZ9zwB9PAtGnTcfxLrS01Q72lMAOm8r5RY i/A0IFaId4nLk1Bw9cqDuj3jBz1EzXM5I08fHfb3tAN5N0GvULZO0EEim98EVhb4JJY5 9wHDZtmYmlODSY6V8GDMLeXEje+6FTzWw4uUNRPRS6CLY3WBaOoQqrNlas6QvTE+hIG1 uhcQ== X-Gm-Message-State: AOAM531rK4ORxdP5mb9wHNJVY9pNFQArcaCGF9+BFBTw1BJWZ3NCqMNp 7sSTXY+gs2Os5CCkxvEl8AZglg== X-Google-Smtp-Source: ABdhPJxWVmiHoQwdZpQDKjvR8Zzvq72vgxnfzolgqDV50mvlEYBQNgOoY+e0Mhzv7QpWd7l/INTNBQ== X-Received: by 2002:a05:6512:2808:b0:43f:4baa:7e5f with SMTP id cf8-20020a056512280800b0043f4baa7e5fmr15099670lfb.498.1646129028592; Tue, 01 Mar 2022 02:03:48 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:48 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 01/10] net: bridge: mst: Multiple Spanning Tree (MST) mode Date: Tue, 1 Mar 2022 11:03:12 +0100 Message-Id: <20220301100321.951175-2-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 the user to switch from the current per-VLAN STP mode to an MST mode. Up to this point, per-VLAN STP states where always isolated from each other. This is in contrast to the MSTP standard (802.1Q-2018, Clause 13.5), where VLANs are grouped into MST instances (MSTIs), and the state is managed on a per-MSTI level, rather that at the per-VLAN level. Perhaps due to the prevalence of the standard, many switching ASICs are built after the same model. Therefore, add a corresponding MST mode to the bridge, which we can later add offloading support for in a straight-forward way. For now, all VLANs are fixed to MSTI 0, also called the Common Spanning Tree (CST). That is, all VLANs will follow the port-global state. Upcoming changes will make this actually useful by allowing VLANs to be mapped to arbitrary MSTIs and allow individual MSTI states to be changed. Signed-off-by: Tobias Waldekranz --- include/uapi/linux/if_link.h | 1 + net/bridge/Makefile | 2 +- net/bridge/br_input.c | 17 +++++++- net/bridge/br_mst.c | 83 ++++++++++++++++++++++++++++++++++++ net/bridge/br_netlink.c | 14 +++++- net/bridge/br_private.h | 26 +++++++++++ net/bridge/br_stp.c | 3 ++ net/bridge/br_vlan.c | 20 ++++++++- net/bridge/br_vlan_options.c | 5 +++ 9 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 net/bridge/br_mst.c diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index e315e53125f4..7e0a653aafa3 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -482,6 +482,7 @@ enum { IFLA_BR_VLAN_STATS_PER_PORT, IFLA_BR_MULTI_BOOLOPT, IFLA_BR_MCAST_QUERIER_STATE, + IFLA_BR_MST_ENABLED, __IFLA_BR_MAX, }; =20 diff --git a/net/bridge/Makefile b/net/bridge/Makefile index 7fb9a021873b..24bd1c0a9a5a 100644 --- a/net/bridge/Makefile +++ b/net/bridge/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_BRIDGE_NETFILTER) +=3D br_netfilter.o =20 bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) +=3D br_multicast.o br_mdb.o br_mult= icast_eht.o =20 -bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) +=3D br_vlan.o br_vlan_tunnel.o br_= vlan_options.o +bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) +=3D br_vlan.o br_vlan_tunnel.o br_= vlan_options.o br_mst.o =20 bridge-$(CONFIG_NET_SWITCHDEV) +=3D br_switchdev.o =20 diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e0c13fcc50ed..196417859c4a 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -78,13 +78,22 @@ int br_handle_frame_finish(struct net *net, struct sock= *sk, struct sk_buff *skb u16 vid =3D 0; u8 state; =20 - if (!p || p->state =3D=3D BR_STATE_DISABLED) + if (!p) goto drop; =20 br =3D p->br; + + if (br_mst_is_enabled(br)) { + state =3D BR_STATE_FORWARDING; + } else { + if (p->state =3D=3D BR_STATE_DISABLED) + goto drop; + + state =3D p->state; + } + brmctx =3D &p->br->multicast_ctx; pmctx =3D &p->multicast_ctx; - state =3D p->state; if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid, &state, &vlan)) goto out; @@ -370,9 +379,13 @@ static rx_handler_result_t br_handle_frame(struct sk_b= uff **pskb) return RX_HANDLER_PASS; =20 forward: + if (br_mst_is_enabled(p->br)) + goto defer_stp_filtering; + switch (p->state) { case BR_STATE_FORWARDING: case BR_STATE_LEARNING: +defer_stp_filtering: if (ether_addr_equal(p->br->dev->dev_addr, dest)) skb->pkt_type =3D PACKET_HOST; =20 diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c new file mode 100644 index 000000000000..ad6e91670fa8 --- /dev/null +++ b/net/bridge/br_mst.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Bridge Multiple Spanning Tree Support + * + * Authors: + * Tobias Waldekranz + */ + +#include + +#include "br_private.h" + +DEFINE_STATIC_KEY_FALSE(br_mst_used); + +void br_mst_vlan_set_state(struct net_bridge_port *p, struct net_bridge_vl= an *v, + u8 state) +{ + struct net_bridge_vlan_group *vg =3D nbp_vlan_group(p); + + if (v->state =3D=3D state) + return; + + br_vlan_set_state(v, state); + + if (v->vid =3D=3D vg->pvid) + br_vlan_set_pvid_state(vg, state); +} + +void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state) +{ + struct net_bridge_vlan_group *vg; + struct net_bridge_vlan *v; + + vg =3D nbp_vlan_group(p); + if (!vg) + return; + + list_for_each_entry(v, &vg->vlan_list, vlist) { + if (v->brvlan->msti !=3D msti) + continue; + + br_mst_vlan_set_state(p, v, state); + } +} + +void br_mst_vlan_init_state(struct net_bridge_vlan *v) +{ + /* VLANs always start out in MSTI 0 (CST) */ + v->msti =3D 0; + + if (br_vlan_is_master(v)) + v->state =3D BR_STATE_FORWARDING; + else + v->state =3D v->port->state; +} + +int br_mst_set_enabled(struct net_bridge *br, unsigned long val) +{ + struct net_bridge_vlan_group *vg; + struct net_bridge_port *p; + + /* Mode may only be changed when there are no port VLANs. */ + list_for_each_entry(p, &br->port_list, list) { + vg =3D nbp_vlan_group(p); + + if (vg->num_vlans) + return -EBUSY; + } + + if (val > 1) + return -EINVAL; + + if (!!val =3D=3D br_opt_get(br, BROPT_MST_ENABLED)) + return 0; + + if (val) + static_branch_enable(&br_mst_used); + else + static_branch_disable(&br_mst_used); + + br_opt_toggle(br, BROPT_MST_ENABLED, !!val); + return 0; +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 7d4432ca9a20..a17a0fe25a58 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1163,6 +1163,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX = + 1] =3D { [IFLA_BR_MCAST_IGMP_VERSION] =3D { .type =3D NLA_U8 }, [IFLA_BR_MCAST_MLD_VERSION] =3D { .type =3D NLA_U8 }, [IFLA_BR_VLAN_STATS_PER_PORT] =3D { .type =3D NLA_U8 }, + [IFLA_BR_MST_ENABLED] =3D { .type =3D NLA_U8 }, [IFLA_BR_MULTI_BOOLOPT] =3D NLA_POLICY_EXACT_LEN(sizeof(struct br_boolopt_multi)), }; @@ -1255,6 +1256,14 @@ static int br_changelink(struct net_device *brdev, s= truct nlattr *tb[], if (err) return err; } + + if (data[IFLA_BR_MST_ENABLED]) { + __u8 mst =3D nla_get_u8(data[IFLA_BR_MST_ENABLED]); + + err =3D br_mst_set_enabled(br, mst); + if (err) + return err; + } #endif =20 if (data[IFLA_BR_GROUP_FWD_MASK]) { @@ -1475,6 +1484,7 @@ static size_t br_get_size(const struct net_device *br= dev) nla_total_size(sizeof(u16)) + /* IFLA_BR_VLAN_DEFAULT_PVID */ nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_ENABLED */ nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_PER_PORT */ + nla_total_size(sizeof(u8)) + /* IFLA_BR_MST_ENABLED */ #endif nla_total_size(sizeof(u16)) + /* IFLA_BR_GROUP_FWD_MASK */ nla_total_size(sizeof(struct ifla_bridge_id)) + /* IFLA_BR_ROOT_= ID */ @@ -1572,7 +1582,9 @@ static int br_fill_info(struct sk_buff *skb, const st= ruct net_device *brdev) nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) || nla_put_u8(skb, IFLA_BR_VLAN_STATS_PER_PORT, - br_opt_get(br, BROPT_VLAN_STATS_PER_PORT))) + br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) || + nla_put_u8(skb, IFLA_BR_MST_ENABLED, + br_opt_get(br, BROPT_MST_ENABLED))) return -EMSGSIZE; #endif #ifdef CONFIG_BRIDGE_IGMP_SNOOPING diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 48bc61ebc211..af50ad036b06 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -178,6 +178,7 @@ enum { * @br_mcast_ctx: if MASTER flag set, this is the global vlan multicast co= ntext * @port_mcast_ctx: if MASTER flag unset, this is the per-port/vlan multic= ast * context + * @msti: if MASTER flag set, this holds the VLANs MST instance * @vlist: sorted list of VLAN entries * @rcu: used for entry destruction * @@ -210,6 +211,8 @@ struct net_bridge_vlan { struct net_bridge_mcast_port port_mcast_ctx; }; =20 + u16 msti; + struct list_head vlist; =20 struct rcu_head rcu; @@ -445,6 +448,7 @@ enum net_bridge_opts { BROPT_NO_LL_LEARN, BROPT_VLAN_BRIDGE_BINDING, BROPT_MCAST_VLAN_SNOOPING_ENABLED, + BROPT_MST_ENABLED, }; =20 struct net_bridge { @@ -1765,6 +1769,28 @@ static inline bool br_vlan_state_allowed(u8 state, b= ool learn_allow) } #endif =20 +/* br_mst.c */ +#ifdef CONFIG_BRIDGE_VLAN_FILTERING +DECLARE_STATIC_KEY_FALSE(br_mst_used); +static inline bool br_mst_is_enabled(struct net_bridge *br) +{ + return static_branch_unlikely(&br_mst_used) && + br_opt_get(br, BROPT_MST_ENABLED); +} + +void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state); +void br_mst_vlan_init_state(struct net_bridge_vlan *v); +int br_mst_set_enabled(struct net_bridge *br, unsigned long val); +#else +static inline bool br_mst_is_enabled(struct net_bridge *br) +{ + return false; +} + +static inline void br_mst_set_state(struct net_bridge_port *p, + u16 msti, u8 state) {} +#endif + struct nf_br_ops { int (*br_dev_xmit_hook)(struct sk_buff *skb); }; diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 1d80f34a139c..82a97a021a57 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -43,6 +43,9 @@ void br_set_state(struct net_bridge_port *p, unsigned int= state) return; =20 p->state =3D state; + if (br_opt_get(p->br, BROPT_MST_ENABLED)) + br_mst_set_state(p, 0, state); + err =3D switchdev_port_attr_set(p->dev, &attr, NULL); if (err && err !=3D -EOPNOTSUPP) br_warn(p->br, "error setting offload STP state on port %u(%s)\n", diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 7557e90b60e1..0f5e75ccac79 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -226,6 +226,24 @@ static void nbp_vlan_rcu_free(struct rcu_head *rcu) kfree(v); } =20 +static void br_vlan_init_state(struct net_bridge_vlan *v) +{ + struct net_bridge *br; + + if (br_vlan_is_master(v)) + br =3D v->br; + else + br =3D v->port->br; + + if (br_opt_get(br, BROPT_MST_ENABLED)) { + br_mst_vlan_init_state(v); + return; + } + + v->state =3D BR_STATE_FORWARDING; + v->msti =3D 0; +} + /* This is the shared VLAN add function which works for both ports and bri= dge * devices. There are four possible calls to this function in terms of the * vlan entry type: @@ -322,7 +340,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 fl= ags, } =20 /* set the state before publishing */ - v->state =3D BR_STATE_FORWARDING; + br_vlan_init_state(v); =20 err =3D rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode, br_vlan_rht_params); diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index a6382973b3e7..09112b56e79c 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -99,6 +99,11 @@ static int br_vlan_modify_state(struct net_bridge_vlan_g= roup *vg, return -EBUSY; } =20 + if (br_opt_get(br, BROPT_MST_ENABLED)) { + NL_SET_ERR_MSG_MOD(extack, "Can't modify vlan state directly when MST is= enabled"); + return -EBUSY; + } + if (v->state =3D=3D state) return 0; =20 --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 51445C433F5 for ; Tue, 1 Mar 2022 10:04:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234148AbiCAKEh (ORCPT ); Tue, 1 Mar 2022 05:04:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42576 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232831AbiCAKEc (ORCPT ); Tue, 1 Mar 2022 05:04:32 -0500 Received: from mail-lj1-x236.google.com (mail-lj1-x236.google.com [IPv6:2a00:1450:4864:20::236]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48B6F8BF51 for ; Tue, 1 Mar 2022 02:03:51 -0800 (PST) Received: by mail-lj1-x236.google.com with SMTP id p20so21208085ljo.0 for ; Tue, 01 Mar 2022 02:03:51 -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=TorS1hGSGK7gVjrV8Qc3nxSXYTymGjX+CNdkNNnR/GA=; b=IHK2cKoOjejo2yV7FeSiH551FwrVRpD43Pnli49F6yd9A1Ouh5DZriXYAUVFKgsHHI JYldmIWFVA6Av6DPm0ub1YdCIY7zSX4sTSPDPlZ/Ui6KRQZU0VyPrYb45jUThtI2tUPK vzk6Mt3sl6eMuTGaYt7x/pFulbZFnLyKV4ZvNd6Tf9mZ3oDJxVlQ+MyJTDWbPZ6OsNfZ V9yogzoxj42jzt5+ZAbrgClsalmtsS7HC91of2Fst9uGNlLAEfkzkDTOGx3HeJWUpNiI zU6XPuJlWWt5dK3kPhBh9q9U6id1UhaE1CXfSrzYAM8gAzhH6pQ1bEfDvnueWeHuLDED BT7g== 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=TorS1hGSGK7gVjrV8Qc3nxSXYTymGjX+CNdkNNnR/GA=; b=f92+Bmkguj5BAVb/+QxdtWaFYpadubDNDPu62RaHuantI073mvWsH0/t1P2m4wLHPA 8yUXsVX2s1+ed5vi1vhXxuRKYZpdVBbCCWQnn+hE4z8aaaB5dG9kHfLukxNiIkaQ1gGc AHUcBWeQN8HkN4l3IES+SELs3vQ6/cDpNGlgQYxWFR3zvo4UjT1oZq0vBdzfygnkmKdd nldlw+X3rCyvREL2mQ4G6ryN8r2bwUsYj4arImnsEG1GEhTAJRIeI2N0+b2YXcX9kAeF N7GLjg1YIy4kDn3/6vC//94LLuq+ZyLxEfb9tMrdpOHb/jDFYmbItdbM4oFC/G/Gnth0 pclQ== X-Gm-Message-State: AOAM531XaUiJrpxTs32v1zjBLUfyX4ZWibmozsRNWJ2IUSWE5axk06at fvDdhnmgdlvwru4lK90yzWu2Lw== X-Google-Smtp-Source: ABdhPJyNZibPzKx3/F2x/ASiY/qezSt+at9UIW7WaW1im/5Iw+n6lKWELUJGmj2AzYnBM9XTWXO8gg== X-Received: by 2002:a05:651c:386:b0:244:e2ab:87f9 with SMTP id e6-20020a05651c038600b00244e2ab87f9mr17051246ljp.201.1646129029542; Tue, 01 Mar 2022 02:03:49 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:49 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 02/10] net: bridge: mst: Allow changing a VLAN's MSTI Date: Tue, 1 Mar 2022 11:03:13 +0100 Message-Id: <20220301100321.951175-3-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 move out of the CST (MSTI 0), to an independent tree. The user manages the VID to MSTI mappings via a global VLAN setting. The proposed iproute2 interface would be: bridge vlan global set dev br0 vid msti Changing the state in non-zero MSTIs is still not supported, but will be addressed in upcoming changes. Signed-off-by: Tobias Waldekranz --- include/uapi/linux/if_bridge.h | 1 + net/bridge/br_mst.c | 39 ++++++++++++++++++++++++++++++++++ net/bridge/br_private.h | 1 + net/bridge/br_vlan_options.c | 19 +++++++++++++++-- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 2711c3522010..b68016f625b7 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_MSTI, __BRIDGE_VLANDB_GOPTS_MAX }; #define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1) diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c index ad6e91670fa8..f3b8e279b85c 100644 --- a/net/bridge/br_mst.c +++ b/net/bridge/br_mst.c @@ -43,6 +43,45 @@ void br_mst_set_state(struct net_bridge_port *p, u16 mst= i, u8 state) } } =20 +static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) +{ + struct net_bridge_vlan_group *vg =3D nbp_vlan_group(pv->port); + struct net_bridge_vlan *v; + + list_for_each_entry(v, &vg->vlan_list, vlist) { + /* If this port already has a defined state in this + * MSTI (through some other VLAN membership), inherit + * it. + */ + if (v !=3D pv && v->brvlan->msti =3D=3D msti) { + br_mst_vlan_set_state(pv->port, pv, v->state); + return; + } + } + + /* Otherwise, start out in a new MSTI with all ports disabled. */ + return br_mst_vlan_set_state(pv->port, pv, BR_STATE_DISABLED); +} + +int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti) +{ + struct net_bridge_vlan_group *vg; + struct net_bridge_vlan *pv; + struct net_bridge_port *p; + + mv->msti =3D msti; + + list_for_each_entry(p, &mv->br->port_list, list) { + vg =3D nbp_vlan_group(p); + + pv =3D br_vlan_find(vg, mv->vid); + if (pv) + br_mst_vlan_sync_state(pv, msti); + } + + return 0; +} + void br_mst_vlan_init_state(struct net_bridge_vlan *v) { /* VLANs always start out in MSTI 0 (CST) */ diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index af50ad036b06..63601043abca 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1779,6 +1779,7 @@ static inline bool br_mst_is_enabled(struct net_bridg= e *br) } =20 void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state); +int br_mst_vlan_set_msti(struct net_bridge_vlan *v, u16 msti); void br_mst_vlan_init_state(struct net_bridge_vlan *v); int br_mst_set_enabled(struct net_bridge *br, unsigned long val); #else diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c index 09112b56e79c..87a9c80d26d3 100644 --- a/net/bridge/br_vlan_options.c +++ b/net/bridge/br_vlan_options.c @@ -44,8 +44,8 @@ bool br_vlan_opts_eq_range(const struct net_bridge_vlan *= v_curr, u8 curr_mc_rtr =3D br_vlan_multicast_router(v_curr); =20 return v_curr->state =3D=3D range_end->state && - __vlan_tun_can_enter_range(v_curr, range_end) && - curr_mc_rtr =3D=3D range_mc_rtr; + __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) @@ -296,6 +296,7 @@ bool br_vlan_global_opts_can_enter_range(const struct n= et_bridge_vlan *v_curr, const struct net_bridge_vlan *r_end) { return v_curr->vid - r_end->vid =3D=3D 1 && + v_curr->msti =3D=3D r_end->msti && ((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, @@ -384,6 +385,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_MSTI, v_opts->msti)) + goto out_err; + nla_nest_end(skb, nest); =20 return true; @@ -415,6 +419,7 @@ 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_MSTI */ + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ } =20 @@ -564,6 +569,15 @@ static int br_vlan_process_global_one_opts(const struc= t net_bridge *br, } #endif #endif + if (tb[BRIDGE_VLANDB_GOPTS_MSTI]) { + u16 msti; + + msti =3D nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_MSTI]); + err =3D br_mst_vlan_set_msti(v, msti); + if (err) + return err; + *changed =3D true; + } =20 return 0; } @@ -583,6 +597,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_MSTI] =3D NLA_POLICY_MAX(NLA_U16, VLAN_N_VID - 1), }; =20 int br_vlan_rtm_process_global_options(struct net_device *dev, --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 A3599C433FE for ; Tue, 1 Mar 2022 10:04:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232541AbiCAKEy (ORCPT ); Tue, 1 Mar 2022 05:04:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42698 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234122AbiCAKEe (ORCPT ); Tue, 1 Mar 2022 05:04:34 -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 39DE68C7F9 for ; Tue, 1 Mar 2022 02:03:52 -0800 (PST) Received: by mail-lf1-x12f.google.com with SMTP id g39so25903472lfv.10 for ; Tue, 01 Mar 2022 02:03:52 -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=F7C7hTgWjqEspqVB5o/KBKjFtzJiq1s+50mM/TkwxFA=; b=V4O/UoO/JgvAZkw0yy7b0zlYGOTooT4tJk2CtxYvgcK9GD0NByvjD9UwaueB/Ad/Gg cHUfY8E/iI/EmJfwLMkramHWaW8+3wx6SUO916alOah6LrUFMy/JtXuEePFC9ATm6dPG rfNBCr4SMhDX2iL+qEaexR6FrNE43rZrEUg9QcVuVbcHRUBlxM0mu1NPuwyIBsP8t+sW fxwHI+sxguycgvKcumtTsJCC+7dfuQjmZJA50FsmFbOe6dNpnS/C5Dls6Bp5chlCCL8M 9rSaL/CCFhO/uY3q86bMmZuE6AisTUIzhjkNlM3etQFwrivK9UQS2XvZkkMA53lw98gR bUPw== 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=F7C7hTgWjqEspqVB5o/KBKjFtzJiq1s+50mM/TkwxFA=; b=t5BLfos5MYzQZ0EURCao4chmfKxTJl+87F+JinWtocdjGjEkFixj4YXD9XjdzCdXSV 2BlADiZtv5d00dVpgo9eWPPm2MtkJzauPwWpZkDDkYNl5oQcFGmHS1ALjyS4Dzn/2B/B t4+R08sccDuCC+QYrzUEW/VVJ0hqCIHakRM41oc1gbj5ww0ULWHFyoZcT/JVoFcH6cXo i2N+IhqTYJ6eiLz3w1Chm3HZDgRfTIDoORw0Kdzg3BlSV5DiCCfNbcFwWRulUkjoZaib 6yPreyObh02k8+vq8BZZ8JuvufUkXMovhIGTmKOfXE1aFPcAm7EqEOTe/58Wq9i8h74+ xzYg== X-Gm-Message-State: AOAM530LNAfyTadX6Xsdo3NGPZ53o1hM2i3d6Fw9mO9Vpcx7mwieZLnu S6yNTWyG9mc4D1ntdZy+qh8zjA== X-Google-Smtp-Source: ABdhPJzqxlr+XPuNwWeG42zHKgVNoGPMUzjCoxsSBR1Ubk9lCAsqj7x05ohHlJyjcK8Z6HRiAxCtzg== X-Received: by 2002:ac2:58cf:0:b0:437:96c2:deed with SMTP id u15-20020ac258cf000000b0043796c2deedmr15018061lfo.137.1646129030473; Tue, 01 Mar 2022 02:03:50 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:50 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 03/10] net: bridge: mst: Support setting and reporting MST port states Date: Tue, 1 Mar 2022 11:03:14 +0100 Message-Id: <20220301100321.951175-4-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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" Make it possible to change the port state in a given MSTI. This is done through a new netlink interface, since the MSTIs are objects in their own right. The proposed iproute2 interface would be: bridge mst set dev msti state Current states in all applicable MSTIs can also be dumped. The proposed iproute interface looks like this: $ bridge mst port msti vb1 0 state forwarding 100 state disabled vb2 0 state forwarding 100 state forwarding The preexisting per-VLAN states are still valid in the MST mode (although they are read-only), and can be queried as usual if one is interested in knowing a particular VLAN's state without having to care about the VID to MSTI mapping (in this example VLAN 20 and 30 are bound to MSTI 100): $ bridge -d vlan port vlan-id vb1 10 state forwarding mcast_router 1 20 state disabled mcast_router 1 30 state disabled mcast_router 1 40 state forwarding mcast_router 1 vb2 10 state forwarding mcast_router 1 20 state forwarding mcast_router 1 30 state forwarding mcast_router 1 40 state forwarding mcast_router 1 Signed-off-by: Tobias Waldekranz --- include/uapi/linux/if_bridge.h | 16 +++ include/uapi/linux/rtnetlink.h | 5 + net/bridge/br_mst.c | 244 +++++++++++++++++++++++++++++++++ net/bridge/br_netlink.c | 3 + net/bridge/br_private.h | 4 + 5 files changed, 272 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index b68016f625b7..784482527861 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -785,4 +785,20 @@ enum { __BRIDGE_QUERIER_MAX }; #define BRIDGE_QUERIER_MAX (__BRIDGE_QUERIER_MAX - 1) + +enum { + BRIDGE_MST_UNSPEC, + BRIDGE_MST_ENTRY, + __BRIDGE_MST_MAX, +}; +#define BRIDGE_MST_MAX (__BRIDGE_MST_MAX - 1) + +enum { + BRIDGE_MST_ENTRY_UNSPEC, + BRIDGE_MST_ENTRY_MSTI, + BRIDGE_MST_ENTRY_STATE, + __BRIDGE_MST_ENTRY_MAX, +}; +#define BRIDGE_MST_ENTRY_MAX (__BRIDGE_MST_ENTRY_MAX - 1) + #endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 0970cb4b1b88..4a48f3ce862c 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -192,6 +192,11 @@ enum { RTM_GETTUNNEL, #define RTM_GETTUNNEL RTM_GETTUNNEL =20 + RTM_GETMST =3D 124 + 2, +#define RTM_GETMST RTM_GETMST + RTM_SETMST, +#define RTM_SETMST RTM_SETMST + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c index f3b8e279b85c..8dea8e7257fd 100644 --- a/net/bridge/br_mst.c +++ b/net/bridge/br_mst.c @@ -120,3 +120,247 @@ int br_mst_set_enabled(struct net_bridge *br, unsigne= d long val) br_opt_toggle(br, BROPT_MST_ENABLED, !!val); return 0; } + +static int br_mst_nl_get_one(struct net_bridge_port *p, struct sk_buff *sk= b, + struct netlink_callback *cb) +{ + struct net_bridge_vlan_group *vg =3D nbp_vlan_group(p); + int err =3D 0, idx =3D 0, s_idx =3D cb->args[1]; + struct net_bridge_vlan *v; + struct br_port_msg *bpm; + struct nlmsghdr *nlh; + struct nlattr *nest; + unsigned long *seen; + + nlh =3D nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + RTM_GETMST, sizeof(*bpm), NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + bpm =3D nlmsg_data(nlh); + memset(bpm, 0, sizeof(*bpm)); + bpm->ifindex =3D p->dev->ifindex; + + seen =3D bitmap_zalloc(VLAN_N_VID, 0); + if (!seen) + return -ENOMEM; + + list_for_each_entry(v, &vg->vlan_list, vlist) { + if (test_bit(v->brvlan->msti, seen)) + continue; + + if (idx < s_idx) + goto skip; + + nest =3D nla_nest_start_noflag(skb, BRIDGE_MST_ENTRY); + if (!nest || + nla_put_u16(skb, BRIDGE_MST_ENTRY_MSTI, v->brvlan->msti) || + nla_put_u8(skb, BRIDGE_MST_ENTRY_STATE, v->state)) { + err =3D -EMSGSIZE; + break; + } + nla_nest_end(skb, nest); + + set_bit(v->brvlan->msti, seen); +skip: + idx++; + } + + kfree(seen); + nlmsg_end(skb, nlh); + return err; +} + +static struct net_bridge_port *br_mst_nl_get_parse(struct net *net, + struct netlink_callback *cb) +{ + struct netlink_ext_ack *extack =3D cb->extack; + const struct nlmsghdr *nlh =3D cb->nlh; + struct net_bridge_port *p; + struct br_port_msg *bpm; + struct net_device *dev; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*bpm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for mst get request"); + return ERR_PTR(-EINVAL); + } + + if (nlmsg_attrlen(nlh, sizeof(*bpm))) { + NL_SET_ERR_MSG(extack, "Invalid data after header in mst get request"); + return ERR_PTR(-EINVAL); + } + + bpm =3D nlmsg_data(nlh); + if (!bpm->ifindex) + return NULL; + + dev =3D __dev_get_by_index(net, bpm->ifindex); + if (!dev) + return ERR_PTR(-ENODEV); + + if (!netif_is_bridge_port(dev)) { + NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge port"); + return ERR_PTR(-EINVAL); + } + + p =3D br_port_get_rtnl(dev); + if (WARN_ON(!p)) + return ERR_PTR(-ENODEV); + + if (!br_opt_get(p->br, BROPT_MST_ENABLED)) { + NL_SET_ERR_MSG_MOD(extack, "Can't query MST state when MST is disabled"); + return ERR_PTR(-EINVAL); + } + + return p; +} + +static int br_mst_nl_get(struct sk_buff *skb, struct netlink_callback *cb) +{ + int err =3D 0, idx =3D 0, s_idx =3D cb->args[0]; + struct net *net =3D sock_net(skb->sk); + struct net_bridge_port *p; + struct net_device *dev; + + p =3D br_mst_nl_get_parse(net, cb); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (p) { + err =3D br_mst_nl_get_one(p, skb, cb); + if (err !=3D -EMSGSIZE) + return err; + } else { + for_each_netdev(net, dev) { + if (!netif_is_bridge_port(dev)) + continue; + + if (idx < s_idx) + goto skip; + + p =3D br_port_get_rtnl(dev); + if (WARN_ON(!p)) + return -ENODEV; + + err =3D br_mst_nl_get_one(p, skb, cb); + if (err =3D=3D -EMSGSIZE) + break; +skip: + idx++; + } + } + + cb->args[0] =3D idx; + return skb->len; +} + +static const struct nla_policy br_mst_nl_policy[BRIDGE_MST_ENTRY_MAX + 1] = =3D { + [BRIDGE_MST_ENTRY_MSTI] =3D NLA_POLICY_RANGE(NLA_U16, + 1, /* 0 reserved for CST */ + VLAN_N_VID - 1), + [BRIDGE_MST_ENTRY_STATE] =3D NLA_POLICY_RANGE(NLA_U8, + BR_STATE_DISABLED, + BR_STATE_BLOCKING), +}; + +static int br_mst_nl_set_one(struct net_bridge_port *p, + const struct nlattr *attr, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[BRIDGE_MST_ENTRY_MAX + 1]; + u16 msti; + u8 state; + int err; + + err =3D nla_parse_nested(tb, BRIDGE_MST_ENTRY_MAX, attr, + br_mst_nl_policy, extack); + if (err) + return err; + + if (!tb[BRIDGE_MST_ENTRY_MSTI]) { + NL_SET_ERR_MSG_MOD(extack, "MSTI not specified"); + return -EINVAL; + } + + if (!tb[BRIDGE_MST_ENTRY_STATE]) { + NL_SET_ERR_MSG_MOD(extack, "State not specified"); + return -EINVAL; + } + + msti =3D nla_get_u16(tb[BRIDGE_MST_ENTRY_MSTI]); + state =3D nla_get_u8(tb[BRIDGE_MST_ENTRY_STATE]); + + br_mst_set_state(p, msti, state); + return 0; +} + +static int br_mst_nl_set(struct sk_buff *skb, struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + struct net *net =3D sock_net(skb->sk); + struct net_bridge_port *p; + struct br_port_msg *bpm; + struct net_device *dev; + struct nlattr *attr; + int err, msts =3D 0; + int rem; + + err =3D nlmsg_parse(nlh, sizeof(*bpm), NULL, BRIDGE_MST_MAX, NULL, + extack); + if (err < 0) + return err; + + bpm =3D nlmsg_data(nlh); + dev =3D __dev_get_by_index(net, bpm->ifindex); + if (!dev) + return -ENODEV; + + if (!netif_is_bridge_port(dev)) { + NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge port"); + return -EINVAL; + } + + p =3D br_port_get_rtnl(dev); + if (WARN_ON(!p)) + return -ENODEV; + + if (!br_opt_get(p->br, BROPT_MST_ENABLED)) { + NL_SET_ERR_MSG_MOD(extack, "Can't modify MST state when MST is disabled"= ); + return -EBUSY; + } + + nlmsg_for_each_attr(attr, nlh, sizeof(*bpm), rem) { + switch (nla_type(attr)) { + case BRIDGE_MST_ENTRY: + err =3D br_mst_nl_set_one(p, attr, extack); + break; + default: + continue; + } + + msts++; + if (err) + break; + } + + if (!msts) { + NL_SET_ERR_MSG_MOD(extack, "Found no MST entries to process"); + err =3D -EINVAL; + } + + return err; +} + +void br_mst_rtnl_init(void) +{ + rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETMST, NULL, + br_mst_nl_get, 0); + rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_SETMST, + br_mst_nl_set, NULL, 0); +} + +void br_mst_rtnl_uninit(void) +{ + rtnl_unregister(PF_BRIDGE, RTM_SETMST); + rtnl_unregister(PF_BRIDGE, RTM_GETMST); +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index a17a0fe25a58..6d70d6f9cf17 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1813,6 +1813,7 @@ int __init br_netlink_init(void) =20 br_mdb_init(); br_vlan_rtnl_init(); + br_mst_rtnl_init(); rtnl_af_register(&br_af_ops); =20 err =3D rtnl_link_register(&br_link_ops); @@ -1824,6 +1825,7 @@ int __init br_netlink_init(void) out_af: rtnl_af_unregister(&br_af_ops); br_mdb_uninit(); + br_mst_rtnl_uninit(); return err; } =20 @@ -1831,6 +1833,7 @@ void br_netlink_fini(void) { br_mdb_uninit(); br_vlan_rtnl_uninit(); + br_mst_rtnl_uninit(); rtnl_af_unregister(&br_af_ops); rtnl_link_unregister(&br_link_ops); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 63601043abca..7882a65ffb43 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1782,6 +1782,8 @@ void br_mst_set_state(struct net_bridge_port *p, u16 = msti, u8 state); int br_mst_vlan_set_msti(struct net_bridge_vlan *v, u16 msti); void br_mst_vlan_init_state(struct net_bridge_vlan *v); int br_mst_set_enabled(struct net_bridge *br, unsigned long val); +void br_mst_rtnl_init(void); +void br_mst_rtnl_uninit(void); #else static inline bool br_mst_is_enabled(struct net_bridge *br) { @@ -1790,6 +1792,8 @@ static inline bool br_mst_is_enabled(struct net_bridg= e *br) =20 static inline void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state) {} +static inline void br_mst_rtnl_init(void) {} +static inline void br_mst_rtnl_uninit(void) {} #endif =20 struct nf_br_ops { --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 A74C4C4332F for ; Tue, 1 Mar 2022 10:04:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234161AbiCAKEu (ORCPT ); Tue, 1 Mar 2022 05:04:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234120AbiCAKEe (ORCPT ); Tue, 1 Mar 2022 05:04:34 -0500 Received: from mail-lf1-x134.google.com (mail-lf1-x134.google.com [IPv6:2a00:1450:4864:20::134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D9128CD85 for ; Tue, 1 Mar 2022 02:03:53 -0800 (PST) Received: by mail-lf1-x134.google.com with SMTP id t13so13956003lfd.9 for ; Tue, 01 Mar 2022 02:03:53 -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=az/xSk1cFf+663WFNGMDSdL6ZlzUb+e0Y66c2dIgICk=; b=BAOoXkp2k++ip4yaBp/8jKULasDNMBKsbfUiwLa2swzc45xYddCAwlwEjXR/CkAjTQ wCBsk/75rf+PZDUPTGpFI7K70MMZADloPUZuf83G/riFugsxNBll2we87yL/E1xiVKEd 5oZhYXwr5B7Xwv2XyW0x7joHVlq23hwZlvGBaETYqOle7q9uB4/OLLf5UwlkM1o/YTcY flkohhEtgyDl22CNGpQrGrfUZUgkFua8LIT06Tp/j+zlV/PPHoheCUg9VssBL3i4EvfX f1S+TnJ3VtAPRJ4wJKBvVvIJrJtmhHyqaiz+UviJeKLvutwZ8tn2KbR5633jVxCDcood Ac0Q== 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=az/xSk1cFf+663WFNGMDSdL6ZlzUb+e0Y66c2dIgICk=; b=Zu6uATdIhE5IcnbgfGUYuHhfAUSXR+p/9AupBhWrs/GLMZWVMw19OOoGOXPfUIH5hb xuJa5g/2c4IUZB+1rFjC3zgk9YTWoufb99sAma8RRuOP4xMK45htPn+nASaJylZrcXkQ cuPo7z0kTzZgaH12MAdWBIHEqZ1Mem+YoxGH0Eg+slaP5Flqozq1qcEYcQyLv9buJJrm EFaM/qHQRIqNjikhVnUcWP5DP+GAnDyh3kslZ80gT7AWujzaHXeNPECZRHIUpLKi+wGI qZJDnSzCNE3rAZ+8CXbKQ3LEiuOqDKk37ej2/JlZCK9zaUxglbF6Qgg6aOPAg+wBU8eD jHPA== X-Gm-Message-State: AOAM530rjL8WPqN6s0XycL3WbLvxps1GSP+4sf/JtWzTbNPuS+H5kkt+ W/zVNyoSl/VLT1WsOL4fE8S3xg== X-Google-Smtp-Source: ABdhPJydVSWWFKX0WRaP+6FV4Fs0fLx4UES4/xqRCI6RbrV0UXC2SO2MHSNAUfkaPW9qLY1X843mEw== X-Received: by 2002:a05:6512:22c4:b0:43a:13a8:7e55 with SMTP id g4-20020a05651222c400b0043a13a87e55mr15155916lfu.296.1646129031409; Tue, 01 Mar 2022 02:03:51 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:51 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 04/10] net: bridge: mst: Notify switchdev drivers of VLAN MSTI migrations Date: Tue, 1 Mar 2022 11:03:15 +0100 Message-Id: <20220301100321.951175-5-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 MSTI, send a switchdev notification so that switchdevs can... ...either refuse the migration if the hardware does not support offloading of MST... ..or track a bridge's VID to MSTI mapping when offloading is supported. Signed-off-by: Tobias Waldekranz --- include/net/switchdev.h | 10 +++++++ net/bridge/br_mst.c | 15 +++++++++++ net/bridge/br_switchdev.c | 57 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 3e424d40fae3..39e57aa5005a 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_MSTI, }; =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 msti; + }; +}; + 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_mst.c b/net/bridge/br_mst.c index 8dea8e7257fd..aba603675165 100644 --- a/net/bridge/br_mst.c +++ b/net/bridge/br_mst.c @@ -7,6 +7,7 @@ */ =20 #include +#include =20 #include "br_private.h" =20 @@ -65,9 +66,23 @@ static void br_mst_vlan_sync_state(struct net_bridge_vla= n *pv, u16 msti) =20 int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti) { + struct switchdev_attr attr =3D { + .id =3D SWITCHDEV_ATTR_ID_VLAN_MSTI, + .flags =3D SWITCHDEV_F_DEFER, + .orig_dev =3D mv->br->dev, + .u.vlan_attr =3D { + .vid =3D mv->vid, + .msti =3D msti, + }, + }; struct net_bridge_vlan_group *vg; struct net_bridge_vlan *pv; struct net_bridge_port *p; + int err; + + err =3D switchdev_port_attr_set(mv->br->dev, &attr, NULL); + if (err && err !=3D -EOPNOTSUPP) + return err; =20 mv->msti =3D msti; =20 diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 6f6a70121a5e..160d7659f88a 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -428,6 +428,57 @@ static int br_switchdev_vlan_replay(struct net_device = *br_dev, return 0; } =20 +static int br_switchdev_mst_replay(struct net_device *br_dev, + const void *ctx, bool adding, + struct notifier_block *nb, + struct netlink_ext_ack *extack) +{ + struct switchdev_notifier_port_attr_info attr_info =3D { + .info =3D { + .dev =3D br_dev, + .extack =3D extack, + .ctx =3D ctx, + }, + }; + struct net_bridge *br =3D netdev_priv(br_dev); + struct net_bridge_vlan_group *vg; + struct net_bridge_vlan *v; + int err; + + ASSERT_RTNL(); + + if (!nb) + return 0; + + if (!netif_is_bridge_master(br_dev)) + return -EINVAL; + + vg =3D br_vlan_group(br); + + list_for_each_entry(v, &vg->vlan_list, vlist) { + struct switchdev_attr attr =3D { + .id =3D SWITCHDEV_ATTR_ID_VLAN_MSTI, + .flags =3D SWITCHDEV_F_DEFER, + .orig_dev =3D br_dev, + .u.vlan_attr =3D { + .vid =3D v->vid, + .msti =3D v->msti, + } + }; + + if (!v->msti) + continue; + + attr_info.attr =3D &attr; + err =3D nb->notifier_call(nb, SWITCHDEV_PORT_ATTR_SET, &attr_info); + err =3D notifier_to_errno(err); + if (err) + return err; + } + + return 0; +} + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING struct br_switchdev_mdb_complete_info { struct net_bridge_port *port; @@ -695,6 +746,10 @@ static int nbp_switchdev_sync_objs(struct net_bridge_p= ort *p, const void *ctx, if (err && err !=3D -EOPNOTSUPP) return err; =20 + err =3D br_switchdev_mst_replay(br_dev, ctx, true, blocking_nb, extack); + if (err && err !=3D -EOPNOTSUPP) + return err; + err =3D br_switchdev_mdb_replay(br_dev, dev, ctx, true, blocking_nb, extack); if (err && err !=3D -EOPNOTSUPP) @@ -719,6 +774,8 @@ static void nbp_switchdev_unsync_objs(struct net_bridge= _port *p, =20 br_switchdev_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL); =20 + br_switchdev_mst_replay(br_dev, ctx, false, blocking_nb, NULL); + br_switchdev_vlan_replay(br_dev, ctx, false, blocking_nb, NULL); } =20 --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 40476C433FE for ; Tue, 1 Mar 2022 10:04:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234164AbiCAKFB (ORCPT ); Tue, 1 Mar 2022 05:05:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42780 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234130AbiCAKEf (ORCPT ); Tue, 1 Mar 2022 05:04:35 -0500 Received: from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com [IPv6:2a00:1450:4864:20::22c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EFA178BF1E for ; Tue, 1 Mar 2022 02:03:53 -0800 (PST) Received: by mail-lj1-x22c.google.com with SMTP id 29so21102046ljv.10 for ; Tue, 01 Mar 2022 02:03:53 -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=yuCZ0mCQ7kvhi5DjalgIG8uPVoVRxyzFJETY+ZZ8iS8=; b=KnpuOsFuuWdfSJ00n5q4w09njAQx7uXq7CpPG8PscWCUNiGj2gQQDMtf2GhNH22mq2 9FRdqeadjDIV6pveBFo1wOtZtuCBHNQCy3XU75fZR0rVf7vypjUiebZ8bk4SGKfsOO1p 1E+6+W2/4VRvWXagQtvFTLpvJnCbm9WOeJL3zGRQph/pfSQFHZMMylkNwbEFp5HkXUi/ ocyVKBw8GVWsod6PiMVH3pf6bl4CaL9nkm7s5ZewI8UZnKW9DRdOaF4/u3p4rH0TrMPa 2n9B/1kLyS5zjb/8En4MmPXVZQ9jGZN3ovow3ZTOFn4hn+l1ut3I2CpiudqjCG/yuJ8z V78w== 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=yuCZ0mCQ7kvhi5DjalgIG8uPVoVRxyzFJETY+ZZ8iS8=; b=s3ctyRwoPL+BZ1deJeGMGiP/JsOzzPM4ppoPGisesK7vzlBUbRF6ng705DX61lNWMe 4Av8czrXWj/LQTvk+18SevruGcC/AsJ0+CMh8e5uqkFP6DSl49cYLyFxqiYmYzYXO2yk rAKFtXiFT3NL2yDpGw6omObXP6NglxeFuEaXGPEiRVtgIWUOxCvNLjHoX4EG4mOipxcO r4fmzcs0cdBct7Oo81/oxw9cPdRxo9IZlfb1XFyryK5mWw5dro64Up1TddSErBjI3OMp O71Oz53nZbZvtlMaDIwYUCS5SjfFTTDX1Dm+0QVsy8/gNucwe3OM/5Kv9P7LI2KJfSVZ Cl+A== X-Gm-Message-State: AOAM532SwTeIhu8b3Um+FO7KJJHVzFGXeY5BC73TGGJSBv70wS7Atd0D yoJxTUqX4IZQS2dOIvGcfmm1vQ== X-Google-Smtp-Source: ABdhPJzvAuB+A+tyWYUg2p36MtoBhoJgiKxJMZXVYU1+owvHEHDxWRu2futMleOP+zx/WGNstCBbEg== X-Received: by 2002:a2e:9ac7:0:b0:244:9022:220b with SMTP id p7-20020a2e9ac7000000b002449022220bmr16728216ljj.254.1646129032272; Tue, 01 Mar 2022 02:03:52 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:51 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 05/10] net: bridge: mst: Notify switchdev drivers of MST state changes Date: Tue, 1 Mar 2022 11:03:16 +0100 Message-Id: <20220301100321.951175-6-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 an MST state changes. This notification is keyed by the VLANs MSTI 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_mst.c | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 39e57aa5005a..441beeb2fda5 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_MSTI, }; =20 +struct switchdev_mst_state { + u16 msti; + 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_mst.c b/net/bridge/br_mst.c index aba603675165..9cdd7d9e07c6 100644 --- a/net/bridge/br_mst.c +++ b/net/bridge/br_mst.c @@ -29,8 +29,18 @@ void br_mst_vlan_set_state(struct net_bridge_port *p, st= ruct net_bridge_vlan *v, =20 void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state) { + struct switchdev_attr attr =3D { + .id =3D SWITCHDEV_ATTR_ID_PORT_MST_STATE, + .flags =3D SWITCHDEV_F_DEFER, + .orig_dev =3D p->dev, + .u.mst_state =3D { + .msti =3D msti, + .state =3D state, + }, + }; struct net_bridge_vlan_group *vg; struct net_bridge_vlan *v; + int err; =20 vg =3D nbp_vlan_group(p); if (!vg) @@ -42,6 +52,17 @@ void br_mst_set_state(struct net_bridge_port *p, u16 mst= i, u8 state) =20 br_mst_vlan_set_state(p, v, state); } + + if (!msti) + /* MSTI 0 (CST) state changes are notified via the + * regular SWITCHDEV_ATTR_ID_PORT_STP_STATE. + */ + return; + + err =3D switchdev_port_attr_set(p->dev, &attr, NULL); + if (err && err !=3D -EOPNOTSUPP) + br_warn(p->br, "unable to offload MST state on %s in MSTI %u", + netdev_name(p->dev), msti); } =20 static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 E64C3C433EF for ; Tue, 1 Mar 2022 10:04:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231880AbiCAKFG (ORCPT ); Tue, 1 Mar 2022 05:05:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234146AbiCAKEh (ORCPT ); Tue, 1 Mar 2022 05:04:37 -0500 Received: from mail-lj1-x229.google.com (mail-lj1-x229.google.com [IPv6:2a00:1450:4864:20::229]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C72058BF2C for ; Tue, 1 Mar 2022 02:03:54 -0800 (PST) Received: by mail-lj1-x229.google.com with SMTP id s25so21145420lji.5 for ; Tue, 01 Mar 2022 02:03:54 -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=9f7PbMRM1byMWVKRPVH2DH+qKFogCebwnAS9gVQDC5I=; b=LfKQcjKEK5wI+sNFr+DRYqUk+bAEDYWDniCP2ki23Pban4lZywbpkNO37WC9287GE4 GUzTXcC7WfXhifu+HNVLh3hQagN1CsjazTGcN3YY2uq8fGGDGzCdya5i61D0NX15he2/ dIiLOrDJZrDvV0yjBETAqcapWu/haPjOuIcTKoDX8Paqo2R7I+0MO1yWX5zT2rZgwihK xKwRYi/rzfgmKXKBSRmq020acgJjGZn41GrlcN2YqxDnHHu1Oip0P2qDOMmjgQYO8OBt L2mkd/8V0lV7bWm+pIbFhLZVdOI+r9Ck9VzcPQJYvLqw/AJ/f7OtO1THeQOLZSPJzWcF +Kkw== 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=9f7PbMRM1byMWVKRPVH2DH+qKFogCebwnAS9gVQDC5I=; b=MvR92cO+LmiMSMpfkRMmzYwwJhwb5jQ1pRVFjtDaJsBk4nZFsenwsS6K3QqC+TtwVv tJfox+abYAmPIvpe4D+1/7cnMSh2ffG8M9zwL0jaLO54tK82XJvCUGGd2VdTDx5m/rBB MQwKFErHC531BygfocFOO1CnsZzFaS6BthPnMjnFllzrog6arr6hptoUT1JWeM79ojzc X6bfaXv3ME0BvablKDxG7AcJic3vsbtcwXzHwLvWSQEvYvMs6kCM11ugtfzNx+KgzVnm 0ZYwfVFnvNOCb5AlcW+25Lq7pFr1vPfSRc6HEmBCnhx4QotqmOPPzkl0zbqhpQ7SFObX UOOA== X-Gm-Message-State: AOAM531P0fNfz6lP7110rZvuEiM7XsJOY1DqkQvVOmXZa40XN8oDVtDM ZsRo5xKUuj6u51BMIz7p68JBNA== X-Google-Smtp-Source: ABdhPJzMCZtiN5flmK0LILPNyZm7i1BbaUaNC+ytrvpDRyBrkkkb3keXqM+c+OqQ6Jt4nH5EEwLwDg== X-Received: by 2002:a2e:bc09:0:b0:246:7327:879b with SMTP id b9-20020a2ebc09000000b002467327879bmr13832354ljf.381.1646129033092; Tue, 01 Mar 2022 02:03:53 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:52 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 06/10] net: dsa: Pass VLAN MSTI migration notifications to driver Date: Tue, 1 Mar 2022 11:03:17 +0100 Message-Id: <20220301100321.951175-7-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 MSTI migrations. Signed-off-by: Tobias Waldekranz --- include/net/dsa.h | 3 +++ net/dsa/dsa_priv.h | 1 + net/dsa/port.c | 10 ++++++++++ net/dsa/slave.c | 6 ++++++ 4 files changed, 20 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index cfedcfb86350..cc8acb01bd9b 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -962,6 +962,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_msti_set)(struct dsa_switch *ds, + const struct switchdev_attr *attr); + /* * Forwarding database */ diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 07c0ad52395a..87ec0697e92e 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -217,6 +217,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_msti(struct dsa_port *dp, const struct switchdev_attr *a= ttr); 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 d9da425a17fb..5f45cb7d70ba 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -778,6 +778,16 @@ int dsa_port_bridge_flags(struct dsa_port *dp, return 0; } =20 +int dsa_port_vlan_msti(struct dsa_port *dp, const struct switchdev_attr *a= ttr) +{ + struct dsa_switch *ds =3D dp->ds; + + if (!ds->ops->vlan_msti_set) + return -EOPNOTSUPP; + + return ds->ops->vlan_msti_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 089616206b11..c6ffcd782b5a 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_MSTI: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret =3D dsa_port_vlan_msti(dp, attr); + break; default: ret =3D -EOPNOTSUPP; break; --=20 2.25.1 From nobody Tue Jun 23 17:22:14 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 15EF8C433EF for ; Tue, 1 Mar 2022 10:04:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234202AbiCAKFT (ORCPT ); Tue, 1 Mar 2022 05:05:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234149AbiCAKEi (ORCPT ); Tue, 1 Mar 2022 05:04:38 -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 E3C658BF67 for ; Tue, 1 Mar 2022 02:03:55 -0800 (PST) Received: by mail-lf1-x131.google.com with SMTP id t13so13956156lfd.9 for ; Tue, 01 Mar 2022 02:03:55 -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=dN16fgCTqmhSfWtON594E0vOkCFf2RmkoetWGdp6JJ4=; b=FGP37pZXEBxkL0RxQNnVRGaX5eyOsC22WbmLISe8yfJ43HMUdsFMgaXv9tkRS4DpVG tjGzCvGsTtjeWS+jnvH5B8+Yp0D8sycoVCMC3x1VD+fqlEoJdOXBZAkevk4YU74QVAk1 S5ohNO6qfTP38dNJWcXPMuzxIRN7XtdtSoEONxXDoc74FLrZM4zM8X32zs+4tEagEIkD w76Srz/HbjzTAXMO6Jxw6l2CfLw7TcYeWVSyE90AFjDExj1M8DmPp93Em1NJxpYfj38U DbO1BDdxtMQwnqJF6B6W6I7OS/++rHXExExII94jWf2+Ux04FqkA2vPbo1YwpemaydjV 5Tug== 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=dN16fgCTqmhSfWtON594E0vOkCFf2RmkoetWGdp6JJ4=; b=S4dJQHdtHwLw0B28lZxRovBgcDgE9lTGXwbFBB02LoxT1wv/xvQIEZlN0OMLiVF0VU 4aijf0jgrvchZGqneoanSmw6rbAq3ukA2Bz2brSLVeb/A6sb3yiTT+LFMi3brSJTI58n vr0N9BbewPm4T7t6blCDRZudL81NyJHYECB5D6PfRCcstsA+LtejXFE9U1p+rNQZ6Cyt cyHVTN0/jldFYgperQx9AJNxfZRM7YUESn/z3gqu2FPGmYe+ZHetbMAMdczH2GC12p5V 2lvc7LQVX6Ajojg5PAW5oM2KwznuLtPoT9MzU0tOur7f2xy0aCNGwFwXcWuKKFvguJFK envQ== X-Gm-Message-State: AOAM5330EKs9ougZrzQBTFmXAvATqZ04FQye127W5xCsAX1KMm7Cl/RD 8tbgqNy4WLNsAMNAeejj8pN3gJcbCzULiq0F X-Google-Smtp-Source: ABdhPJzd8u7r/RDGEtANGyQfgwedHUl5shTP/BHfpDtp0lTOI/ubmRMWeuVYHto4/ElK6FcsVT7r0g== X-Received: by 2002:ac2:5295:0:b0:443:ddce:d283 with SMTP id q21-20020ac25295000000b00443ddced283mr15040074lfm.246.1646129034218; Tue, 01 Mar 2022 02:03:54 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:53 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 07/10] net: dsa: Pass MST state changes to driver Date: Tue, 1 Mar 2022 11:03:18 +0100 Message-Id: <20220301100321.951175-8-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 cc8acb01bd9b..096e6e3a8e1e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -943,6 +943,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 87ec0697e92e..a620e079ebc5 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -198,6 +198,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 5f45cb7d70ba..26cfbc8ab499 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 c6ffcd782b5a..32b006a5b778 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 Tue Jun 23 17:22:14 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 A0367C433EF for ; Tue, 1 Mar 2022 10:04:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234228AbiCAKFP (ORCPT ); Tue, 1 Mar 2022 05:05:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43374 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234158AbiCAKEk (ORCPT ); Tue, 1 Mar 2022 05:04:40 -0500 Received: from mail-lf1-x130.google.com (mail-lf1-x130.google.com [IPv6:2a00:1450:4864:20::130]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EBB0A8CD85 for ; Tue, 1 Mar 2022 02:03:56 -0800 (PST) Received: by mail-lf1-x130.google.com with SMTP id j15so25921643lfe.11 for ; Tue, 01 Mar 2022 02:03:56 -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=bNDwoR5UyYVkMq4l68oZNNn7ga9pQEMw2kh4eXRN9FQ=; b=Z0+Ug1iTClcrIGKvXQIvTKt6TDxVL7gY4aH8KqK01xoCj2LarbakN3YbOYSZMDR4GE RJQOlf4qnw+yks+NtSiBUSyZXbk92hwje1WF1qO5aTcbL+DyLnhAHnwUAOl+lS49Fb+g AX2Mx5lDbHGHUIoYc8j4VY09JzTmB96KuG6n4QrE4OLP3TZns5MzEx/1eE6bwaHXQqTi sYxojEcLvpXr4vRhIyQxSCkeXV/XV27j9RT82he0A59cAczOEmYAuzTytxkoYcZwjT8p Kl/E+zUkMQKHRC+PZ9SZCskd1IJq/Gi1we1A+oZLMvhbK4OO/KyBFe7JoxNu5Onr0TFo iApQ== 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=bNDwoR5UyYVkMq4l68oZNNn7ga9pQEMw2kh4eXRN9FQ=; b=fzActTZgxt/ubTgmzeKhq3EjtEJd2QfKqAkdL2TNH+3D3fq05CMoYAbcgMBb1wTed5 FkJTJEjJmu5KoErH1waoc8hPxHCkkTqjg/GD2v95wL3U8TLJrm7AdDnqi4Z+SuPDldoE 9vUP0DuBFAR7d/6F0hLofKSCpDLELpMPD0DBIAdmP4VB3OppWyD4Jt/wRMw4N0mlD4GR poILFROMSWFS4R6hSpaFbEpLwVryXkMHixFYZykmy3KfKAi0FxL0P535MzxzWmi8t+qL tu2HXMbpyZFUZMg45hgzW1RAVJpvNL360HwASgSdDtjRxLX2rfiwugzkybrIpQdprViK 89pQ== X-Gm-Message-State: AOAM530D9WM7Xg7rLSqFTKMHq3BXafjleb2HGENiQ5Z+by+X86phIki8 sNBLEAHJLKw+Ds/jd30sI2g/+A== X-Google-Smtp-Source: ABdhPJxs/Pf3hkfXe7QOobx7y6Sq636fFSYvAn/zGYkAH32rw7ZnvIID7MPrnR+MnStX5L8pcpAECg== X-Received: by 2002:a05:6512:36d0:b0:442:4cb2:df5 with SMTP id e16-20020a05651236d000b004424cb20df5mr14909460lfs.648.1646129035115; Tue, 01 Mar 2022 02:03:55 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:54 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 08/10] net: dsa: mv88e6xxx: Disentangle STU from VTU Date: Tue, 1 Mar 2022 11:03:19 +0100 Message-Id: <20220301100321.951175-9-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 84b90fc36c58..c14a62aa6a6c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1791,6 +1791,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) { @@ -3427,6 +3454,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)) @@ -3882,6 +3916,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 @@ -4968,6 +5004,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, @@ -5033,6 +5071,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 */ @@ -5098,6 +5138,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, @@ -5166,6 +5208,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, @@ -5234,6 +5278,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, @@ -5487,6 +5532,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, @@ -5510,6 +5556,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, @@ -5532,6 +5579,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, @@ -5554,6 +5602,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, @@ -5576,6 +5625,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, @@ -5815,6 +5865,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, @@ -5839,6 +5890,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, @@ -5863,6 +5915,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, @@ -5886,6 +5939,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 Tue Jun 23 17:22:14 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 9FDC6C433F5 for ; Tue, 1 Mar 2022 10:04:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234147AbiCAKFL (ORCPT ); Tue, 1 Mar 2022 05:05:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234157AbiCAKEk (ORCPT ); Tue, 1 Mar 2022 05:04:40 -0500 Received: from mail-lj1-x22f.google.com (mail-lj1-x22f.google.com [IPv6:2a00:1450:4864:20::22f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D92E58CDA3 for ; Tue, 1 Mar 2022 02:03:57 -0800 (PST) Received: by mail-lj1-x22f.google.com with SMTP id y24so2141651ljh.11 for ; Tue, 01 Mar 2022 02:03:57 -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=dMz97POLoB/rvgv4lh3Wm2uwAH6bOuL/AqYXcbD2KQGkhEWLvjBuTaVWfmPtCPZIrn tuf2WnuNnTz6LMiG8wxHT8C+8NzZ8CffzayeLoadPQIigk63Xle1QI1d51negUkxNvpF GiC542zbVtC12eSovgrmut/nb2aEwT09ofq0YWKDIA0QNkyIQ+A4wMJ/RciE0j/oMKxb ySlxhUxrdGjzG7afLCqthqGD5QEsZBKUWGCXuBEPpjiEsQ0hlDn1vg9duW8kce1k4KiG SwtoUXC5H5WiXLLrY+ffBMSJYL26fDgR3Qu+QgQVib1DKCQbOzww7OmZKKs4RDIOhQks JR0Q== 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=lfo49rEfI6zZHxIl5bPzCOZBtgNWhOL1N3YqGem8GIMH46ae2wbQ234f1ACcmKSzj5 yL7m6RC8TXdtTDBzX0CrnkQ9l//9WQaTrGk/dgpWLVQMoW2UA4wBkPzLuR8h8l/LBUyK 0BptDQEAIVTWvyagW4xUam+J2s9f2arBfRHACyhbw9ShizspyjWcKQKUUZ10VJam2F1Z P8z1MCfzmBewrI/yfUYxqVazF72yHfhJYcfgzouNt5YaBCYA9F7WSLkCNgwXEpL5yZnW 9fMpp+mviTH/dA/PNkHKBY/Q3Tnf2Na5xpskNpEs6rW5OvsZJ40RbbS8btqnD8ilUKSz r10Q== X-Gm-Message-State: AOAM533Ob9qaBDeea+iHEIVuC41QxwNDDoV9z4xLa6VRjQCs3jQhFWsF inLgEoUgT6O6htTVgqz1lQ0eaw== X-Google-Smtp-Source: ABdhPJzlxUGPympF9oBT7T14ljrqe3/UKL6S64m2KsGlenzwBcr0vutEaCND8YDUhFDHuDJ7MUuduw== X-Received: by 2002:a2e:a4dc:0:b0:246:4205:98e7 with SMTP id p28-20020a2ea4dc000000b00246420598e7mr16357247ljm.55.1646129036124; Tue, 01 Mar 2022 02:03:56 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:55 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 09/10] net: dsa: mv88e6xxx: Export STU as devlink region Date: Tue, 1 Mar 2022 11:03:20 +0100 Message-Id: <20220301100321.951175-10-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 Tue Jun 23 17:22:14 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 CAFF9C433EF for ; Tue, 1 Mar 2022 10:04:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234213AbiCAKFX (ORCPT ); Tue, 1 Mar 2022 05:05:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234162AbiCAKEl (ORCPT ); Tue, 1 Mar 2022 05:04:41 -0500 Received: from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com [IPv6:2a00:1450:4864:20::12b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C957C8CDB8 for ; Tue, 1 Mar 2022 02:03:58 -0800 (PST) Received: by mail-lf1-x12b.google.com with SMTP id j15so25921799lfe.11 for ; Tue, 01 Mar 2022 02:03:58 -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=jqsbZZHdMda2x9oc6NoF+wlcHcbYportSlPaVmfdhdw=; b=HKk0hQezxCK92/j7bOgiYTr1ECclfO1RYVPOgm46iOd8IVv5YZuP1DX0qbTwEjSY5T I17GcmYYNnBdIVrkuyZQH7hT6jUZ6giAsrpQ5NwG3UhUdCXT1Vcsh70SiqjjMuCTZFZJ +avKxmLzhlgl19XI+uwyDb04MO7YB53WviZKZrrpXc0teudQ7xYobGV+Ur2m9T8yL/DT vBcnDdltpcRrxFcAdI7ehZTchPIYwmmAWvCl3rxMVGhhxst2FYtMv9tf18Ag0i9Z9qkg CO+q9T8HuUYPDmlDPjVnKPbaIJEsSNyK/sUWd5GCVhVonZ/1fjwyqopw8e1xKDBuOrnx y3TQ== 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=jqsbZZHdMda2x9oc6NoF+wlcHcbYportSlPaVmfdhdw=; b=g5womRt01qTuoMKhxlbSfDOk5hur2+iTUbqByNQCGXGhu0NfYEHL9drYANnqrhYI5D S3VumWFK1flPt/mKJBEoW/NrYTP8C5FIJD7fapzZWsMlu7SUeN36QXUpjhvD4Qq6Pg91 xu7nhU1Y1mddgraVcjdSeGSXEmgBZ7BG2SdnimA0qmKIQXbNiRRNEhqjBeoZ3xhu55RL gHN79Dt2dzUlG3dR1nyE0a0ercB6C14rp0MaKq9a0NhaRrtRIvAx6yGm1W7oURs8wjLr pPwLxI+EFWTs6tPb6fcoMam4rQYoJrWqMo4Fhl43uuOLMwD1rfyRmZL8UAFibVUKQliA I66A== X-Gm-Message-State: AOAM533+QUHtCCds9OFCSXwO7h7X2CNHUgaKAPd8R8fynWFJ6RQiVsAw 5s2kSecTFbkHTTP8yUFEMuiNVA== X-Google-Smtp-Source: ABdhPJzyTHyE7Ya2J9YjwlEf5uGw6oVRODcnx+gLqTw8XPZn4iWGc0QoLBGe3pNm1B66bq8IOMwHHw== X-Received: by 2002:a05:6512:114c:b0:434:b7a7:1fdc with SMTP id m12-20020a056512114c00b00434b7a71fdcmr15109807lfg.608.1646129037075; Tue, 01 Mar 2022 02:03:57 -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 s27-20020a05651c049b00b002460fd4252asm1826822ljc.100.2022.03.01.02.03.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Mar 2022 02:03:56 -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 , Petr Machata , Cooper Lees , Ido Schimmel , Matt Johnston , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bridge@lists.linux-foundation.org Subject: [PATCH v2 net-next 10/10] net: dsa: mv88e6xxx: MST Offloading Date: Tue, 1 Mar 2022 11:03:21 +0100 Message-Id: <20220301100321.951175-11-tobias@waldekranz.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220301100321.951175-1-tobias@waldekranz.com> References: <20220301100321.951175-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 | 178 +++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 13 +++ 2 files changed, 191 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/c= hip.c index c14a62aa6a6c..4fb4ec1dff79 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1818,6 +1818,137 @@ 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 msti, u8 *sid) +{ + struct mv88e6xxx_mst *mst; + int err, i; + + 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->msti =3D=3D msti) { + 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->msti =3D msti; + mst->stu.valid =3D true; + mst->stu.sid =3D *sid; + + /* The bridge starts out all ports in the disabled state. But + * a STU state of disabled means to go by the port-global + * state. So we set all user port's initial state to blocking, + * to match the bridge's behavior. + */ + for (i =3D 0; i < mv88e6xxx_num_ports(chip); i++) + mst->stu.state[i] =3D dsa_is_user_port(chip->ds, i) ? + MV88E6XXX_PORT_CTL0_STATE_BLOCKING : + MV88E6XXX_PORT_CTL0_STATE_DISABLED; + + 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: + 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->msti =3D=3D st->msti) { + 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) { @@ -2437,6 +2568,12 @@ static int mv88e6xxx_port_vlan_leave(struct mv88e6xx= x_chip *chip, if (err) return err; =20 + if (!vlan.valid && vlan.sid) { + err =3D mv88e6xxx_sid_put(chip, vlan.sid); + if (err) + return err; + } + return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); } =20 @@ -2482,6 +2619,44 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch= *ds, int port, return err; } =20 +static int mv88e6xxx_vlan_msti_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->msti, &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, struct dsa_db db) @@ -6008,6 +6183,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; } @@ -6540,10 +6716,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_msti_set =3D mv88e6xxx_vlan_msti_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..6a0b66354e1d 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 msti; + + 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