From patchwork Tue Mar 1 10:03:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764470 X-Patchwork-Delegate: kuba@kernel.org 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 09051C433EF for ; Tue, 1 Mar 2022 10:03:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234140AbiCAKEf (ORCPT ); Tue, 1 Mar 2022 05:04:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234029AbiCAKEc (ORCPT ); Tue, 1 Mar 2022 05:04:32 -0500 Received: from mail-lf1-x12a.google.com (mail-lf1-x12a.google.com [IPv6:2a00:1450:4864:20::12a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 64A638BF45 for ; Tue, 1 Mar 2022 02:03:50 -0800 (PST) Received: by mail-lf1-x12a.google.com with SMTP id d23so25900083lfv.13 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=zM8zPtGnbu1TlQXhYJgIqeW0K1TA7KpAJ2eHCW47iD9wyj5ILU3BKEBWpPEiear+lr aU8q5YbCWQLPrCfX1ACB8Lcb2P79t4tNcViiwpVV+RYT7ygE1Pv1+UFj8sReVNC54PF8 +PvlfoEayoDXSXVfA8MBiVX4vska3VSVheNd9JqsYoh8qodLZWQUVclZq0s5211GudaV +wI69XxEdczOOGhiqLOhGnCtZF5wqh7UllBv5W6s+6ArRShqjlFB1Q39WPeos1ytu9xa WoXba6a0/0Zl+mz4K8oGdpUtX/y4O2ohRemvKAXQ7Xd5J1SO2K89YnFN/XK4XP37Km0j Qayw== X-Gm-Message-State: AOAM531T0dDMfV1E7Nc8wJ8L8WY083HtyXt+wc2EVEAyPQdOHWPUTrdV R9AkfnrgN3dS7llOdXX391jT1Q== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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, }; 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) += br_netfilter.o bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o br_multicast_eht.o -bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o br_vlan_options.o +bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o br_vlan_options.o br_mst.o bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o 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 = 0; u8 state; - if (!p || p->state == BR_STATE_DISABLED) + if (!p) goto drop; br = p->br; + + if (br_mst_is_enabled(br)) { + state = BR_STATE_FORWARDING; + } else { + if (p->state == BR_STATE_DISABLED) + goto drop; + + state = p->state; + } + brmctx = &p->br->multicast_ctx; pmctx = &p->multicast_ctx; - state = 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_buff **pskb) return RX_HANDLER_PASS; 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 = PACKET_HOST; 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_vlan *v, + u8 state) +{ + struct net_bridge_vlan_group *vg = nbp_vlan_group(p); + + if (v->state == state) + return; + + br_vlan_set_state(v, state); + + if (v->vid == 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 = nbp_vlan_group(p); + if (!vg) + return; + + list_for_each_entry(v, &vg->vlan_list, vlist) { + if (v->brvlan->msti != 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 = 0; + + if (br_vlan_is_master(v)) + v->state = BR_STATE_FORWARDING; + else + v->state = 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 = nbp_vlan_group(p); + + if (vg->num_vlans) + return -EBUSY; + } + + if (val > 1) + return -EINVAL; + + if (!!val == 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] = { [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NLA_U8 }, [IFLA_BR_MCAST_MLD_VERSION] = { .type = NLA_U8 }, [IFLA_BR_VLAN_STATS_PER_PORT] = { .type = NLA_U8 }, + [IFLA_BR_MST_ENABLED] = { .type = NLA_U8 }, [IFLA_BR_MULTI_BOOLOPT] = NLA_POLICY_EXACT_LEN(sizeof(struct br_boolopt_multi)), }; @@ -1255,6 +1256,14 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], if (err) return err; } + + if (data[IFLA_BR_MST_ENABLED]) { + __u8 mst = nla_get_u8(data[IFLA_BR_MST_ENABLED]); + + err = br_mst_set_enabled(br, mst); + if (err) + return err; + } #endif if (data[IFLA_BR_GROUP_FWD_MASK]) { @@ -1475,6 +1484,7 @@ static size_t br_get_size(const struct net_device *brdev) 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 struct 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 context * @port_mcast_ctx: if MASTER flag unset, this is the per-port/vlan multicast * 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; }; + u16 msti; + struct list_head vlist; 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, }; struct net_bridge { @@ -1765,6 +1769,28 @@ static inline bool br_vlan_state_allowed(u8 state, bool learn_allow) } #endif +/* 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; p->state = state; + if (br_opt_get(p->br, BROPT_MST_ENABLED)) + br_mst_set_state(p, 0, state); + err = switchdev_port_attr_set(p->dev, &attr, NULL); if (err && err != -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); } +static void br_vlan_init_state(struct net_bridge_vlan *v) +{ + struct net_bridge *br; + + if (br_vlan_is_master(v)) + br = v->br; + else + br = v->port->br; + + if (br_opt_get(br, BROPT_MST_ENABLED)) { + br_mst_vlan_init_state(v); + return; + } + + v->state = BR_STATE_FORWARDING; + v->msti = 0; +} + /* This is the shared VLAN add function which works for both ports and bridge * 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 flags, } /* set the state before publishing */ - v->state = BR_STATE_FORWARDING; + br_vlan_init_state(v); err = 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_group *vg, return -EBUSY; } + 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 == state) return 0; From patchwork Tue Mar 1 10:03:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764473 X-Patchwork-Delegate: kuba@kernel.org 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 D7CD9C433FE for ; Tue, 1 Mar 2022 10:04:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232549AbiCAKEl (ORCPT ); Tue, 1 Mar 2022 05:04:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42694 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234095AbiCAKEe (ORCPT ); Tue, 1 Mar 2022 05:04:34 -0500 Received: from mail-lj1-x22d.google.com (mail-lj1-x22d.google.com [IPv6:2a00:1450:4864:20::22d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4BDDB8BF67 for ; Tue, 1 Mar 2022 02:03:51 -0800 (PST) Received: by mail-lj1-x22d.google.com with SMTP id u11so21153556lju.4 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=r/R64tHEZb/qAqBL9hhA321bjFNjuB0HY9e4MqkO2jwrIOPSqNPh1grdq/iCHMqP11 /Sbe6HkI8Yq9TdfE1fr/pMAb/X4EIcDd8zdf50sZ1eZ2ly9QERgee8S2JJR44E4rpjoH SwI48ZbrXSS6Pz2A7yEply2IHLhMKBkpgwpGIEPghDcWh3Gl4H32Fo2bkmsaJnWVcZ8A ekeYj9VqdmOlmo9LAOutbEBL5EMSo+2W6rO2V0QTu29T8SWK8QZjblKlswWqM7pv9dZX x6kbFX+mQwS1KDi06ptrzGYYOrdiZR3fS/lVOVoMb3riZFSilxBFM9CEAiRWbxCcx5wr 2Uvw== X-Gm-Message-State: AOAM533cnWjWLVm9fZU5UP3sMf9vcZYTtBXjA+8TUxA/R6lvYF+TyjCO qH9Dyjx/hA1cZgvrcbLukLKBQQ== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 msti, u8 state) } } +static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) +{ + struct net_bridge_vlan_group *vg = 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 != pv && v->brvlan->msti == 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 = msti; + + list_for_each_entry(p, &mv->br->port_list, list) { + vg = nbp_vlan_group(p); + + pv = 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_bridge *br) } 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 = br_vlan_multicast_router(v_curr); return v_curr->state == range_end->state && - __vlan_tun_can_enter_range(v_curr, range_end) && - curr_mc_rtr == range_mc_rtr; + __vlan_tun_can_enter_range(v_curr, range_end) && + curr_mc_rtr == range_mc_rtr; } 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 net_bridge_vlan *v_curr, const struct net_bridge_vlan *r_end) { return v_curr->vid - r_end->vid == 1 && + v_curr->msti == r_end->msti && ((v_curr->priv_flags ^ r_end->priv_flags) & BR_VLFLAG_GLOBAL_MCAST_ENABLED) == 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 + if (nla_put_u16(skb, BRIDGE_VLANDB_GOPTS_MSTI, v_opts->msti)) + goto out_err; + nla_nest_end(skb, nest); return true; @@ -415,6 +419,7 @@ static size_t rtnl_vlan_global_opts_nlmsg_size(const struct 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_PORTS */ #endif + + nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_GOPTS_MSTI */ + nla_total_size(sizeof(u16)); /* BRIDGE_VLANDB_GOPTS_RANGE */ } @@ -564,6 +569,15 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br, } #endif #endif + if (tb[BRIDGE_VLANDB_GOPTS_MSTI]) { + u16 msti; + + msti = nla_get_u16(tb[BRIDGE_VLANDB_GOPTS_MSTI]); + err = br_mst_vlan_set_msti(v, msti); + if (err) + return err; + *changed = true; + } return 0; } @@ -583,6 +597,7 @@ static const struct nla_policy br_vlan_db_gpol[BRIDGE_VLANDB_GOPTS_MAX + 1] = { [BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL] = { .type = NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL] = { .type = NLA_U64 }, [BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL] = { .type = NLA_U64 }, + [BRIDGE_VLANDB_GOPTS_MSTI] = NLA_POLICY_MAX(NLA_U16, VLAN_N_VID - 1), }; int br_vlan_rtm_process_global_options(struct net_device *dev, From patchwork Tue Mar 1 10:03:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764472 X-Patchwork-Delegate: kuba@kernel.org 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 571E8C433EF for ; Tue, 1 Mar 2022 10:04:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232831AbiCAKEj (ORCPT ); Tue, 1 Mar 2022 05:04:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234100AbiCAKEe (ORCPT ); Tue, 1 Mar 2022 05:04:34 -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 34CE48C7D9 for ; Tue, 1 Mar 2022 02:03:52 -0800 (PST) Received: by mail-lf1-x12b.google.com with SMTP id i11so25991367lfu.3 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=LkJctvfjKHQkhcyVnQkHLKSigSdiRcLjXbRReyn2i/+dEZH3yyunP/aD/oEVjxWLJb 6CjeDYfhcjoG2Py2K/dzSh/TbJ4oHVVSjC2FpUdGwVk9UE9RIk+AFnJV9e/NDYSz1XIQ 9gQt0FoD2qXusLGBLltiioKtbUDkWiL3rgqFpMCB14+XJvC+0iCl9YXWWLzlDLrOY3bI JHljnkHIj1ZCX12ubyoFBe6Ir2HcQ03fc1uyVMlMgr9Hb7YoJFBJs/A91b1sQBWEn6ri PT5yk1AKTQfrWIHgH0+9+olYx6aLHRzUigiB+FVCJq2gNUJhKkqhvfia4++oRo0RwFKu 97Xg== X-Gm-Message-State: AOAM533ipkxeKx48KuS8/TUIVN6Zn8wQ7P9vxAr7g5ZHM9q9zFtL9EPs TZdGHeeGlK8ooPKaRhmo+X5t5w== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 + RTM_GETMST = 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, unsigned 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 *skb, + struct netlink_callback *cb) +{ + struct net_bridge_vlan_group *vg = nbp_vlan_group(p); + int err = 0, idx = 0, s_idx = cb->args[1]; + struct net_bridge_vlan *v; + struct br_port_msg *bpm; + struct nlmsghdr *nlh; + struct nlattr *nest; + unsigned long *seen; + + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + RTM_GETMST, sizeof(*bpm), NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + bpm = nlmsg_data(nlh); + memset(bpm, 0, sizeof(*bpm)); + bpm->ifindex = p->dev->ifindex; + + seen = 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 = 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 = -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 = cb->extack; + const struct nlmsghdr *nlh = 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 = nlmsg_data(nlh); + if (!bpm->ifindex) + return NULL; + + dev = __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 = 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 = 0, idx = 0, s_idx = cb->args[0]; + struct net *net = sock_net(skb->sk); + struct net_bridge_port *p; + struct net_device *dev; + + p = br_mst_nl_get_parse(net, cb); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (p) { + err = br_mst_nl_get_one(p, skb, cb); + if (err != -EMSGSIZE) + return err; + } else { + for_each_netdev(net, dev) { + if (!netif_is_bridge_port(dev)) + continue; + + if (idx < s_idx) + goto skip; + + p = br_port_get_rtnl(dev); + if (WARN_ON(!p)) + return -ENODEV; + + err = br_mst_nl_get_one(p, skb, cb); + if (err == -EMSGSIZE) + break; +skip: + idx++; + } + } + + cb->args[0] = idx; + return skb->len; +} + +static const struct nla_policy br_mst_nl_policy[BRIDGE_MST_ENTRY_MAX + 1] = { + [BRIDGE_MST_ENTRY_MSTI] = NLA_POLICY_RANGE(NLA_U16, + 1, /* 0 reserved for CST */ + VLAN_N_VID - 1), + [BRIDGE_MST_ENTRY_STATE] = 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 = 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 = nla_get_u16(tb[BRIDGE_MST_ENTRY_MSTI]); + state = 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 = sock_net(skb->sk); + struct net_bridge_port *p; + struct br_port_msg *bpm; + struct net_device *dev; + struct nlattr *attr; + int err, msts = 0; + int rem; + + err = nlmsg_parse(nlh, sizeof(*bpm), NULL, BRIDGE_MST_MAX, NULL, + extack); + if (err < 0) + return err; + + bpm = nlmsg_data(nlh); + dev = __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 = 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 = 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 = -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) br_mdb_init(); br_vlan_rtnl_init(); + br_mst_rtnl_init(); rtnl_af_register(&br_af_ops); err = 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; } @@ -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_bridge *br) 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 struct nf_br_ops { From patchwork Tue Mar 1 10:03:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764471 X-Patchwork-Delegate: kuba@kernel.org 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 D51E5C433FE for ; Tue, 1 Mar 2022 10:03:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234145AbiCAKEg (ORCPT ); Tue, 1 Mar 2022 05:04:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42702 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234123AbiCAKEe (ORCPT ); Tue, 1 Mar 2022 05:04:34 -0500 Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 204418CD88 for ; Tue, 1 Mar 2022 02:03:53 -0800 (PST) Received: by mail-lf1-x133.google.com with SMTP id g39so25903528lfv.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=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=sNpkVIphijTZmt/Ym+enBeksniSZqzdY3ODvj96whWpFgVQiCOyXtnEIgwiKWYPNi0 isPFkNjEOF2P7BbGcHJBHUislJWPPqM2wgpSHI9S7jC35qN2SmwO8v0k4k7tNzyZmGuy JEYdycB08u0emcaSYywuBL5vVbz7uxxeeOO9sy+r1/1t9F/XOFLipCkmG6Wbepqv+Hqj b40x40ttMwFm6LW7YvlxiWaB5SBijQUJpkC/uJ9sji1yyAuxjtcIF83olRCB+PlJbvOK p1KQx5OSmPzVoMqJb6LilZgtrL/d+WB5zivOHYoOJ5A1jvcBzz63mbBMjQ10Posc6LV2 /tEw== X-Gm-Message-State: AOAM533nm0YbnGKj9M7CD1OTG3CUFTQGHnHWMYNAqLwbNptDYN+GBpHF A7lB+hpgETRkeSdSpNN2NEe1AQ== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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, }; struct switchdev_brport_flags { @@ -35,6 +36,14 @@ struct switchdev_brport_flags { unsigned long mask; }; +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; }; 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 @@ */ #include +#include #include "br_private.h" @@ -65,9 +66,23 @@ static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) int br_mst_vlan_set_msti(struct net_bridge_vlan *mv, u16 msti) { + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_ID_VLAN_MSTI, + .flags = SWITCHDEV_F_DEFER, + .orig_dev = mv->br->dev, + .u.vlan_attr = { + .vid = mv->vid, + .msti = msti, + }, + }; struct net_bridge_vlan_group *vg; struct net_bridge_vlan *pv; struct net_bridge_port *p; + int err; + + err = switchdev_port_attr_set(mv->br->dev, &attr, NULL); + if (err && err != -EOPNOTSUPP) + return err; mv->msti = msti; 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; } +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 = { + .info = { + .dev = br_dev, + .extack = extack, + .ctx = ctx, + }, + }; + struct net_bridge *br = 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 = br_vlan_group(br); + + list_for_each_entry(v, &vg->vlan_list, vlist) { + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_ID_VLAN_MSTI, + .flags = SWITCHDEV_F_DEFER, + .orig_dev = br_dev, + .u.vlan_attr = { + .vid = v->vid, + .msti = v->msti, + } + }; + + if (!v->msti) + continue; + + attr_info.attr = &attr; + err = nb->notifier_call(nb, SWITCHDEV_PORT_ATTR_SET, &attr_info); + err = 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_port *p, const void *ctx, if (err && err != -EOPNOTSUPP) return err; + err = br_switchdev_mst_replay(br_dev, ctx, true, blocking_nb, extack); + if (err && err != -EOPNOTSUPP) + return err; + err = br_switchdev_mdb_replay(br_dev, dev, ctx, true, blocking_nb, extack); if (err && err != -EOPNOTSUPP) @@ -719,6 +774,8 @@ static void nbp_switchdev_unsync_objs(struct net_bridge_port *p, br_switchdev_mdb_replay(br_dev, dev, ctx, false, blocking_nb, NULL); + br_switchdev_mst_replay(br_dev, ctx, false, blocking_nb, NULL); + br_switchdev_vlan_replay(br_dev, ctx, false, blocking_nb, NULL); } From patchwork Tue Mar 1 10:03:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764474 X-Patchwork-Delegate: kuba@kernel.org 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 B0AB3C433F5 for ; Tue, 1 Mar 2022 10:04:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234166AbiCAKEm (ORCPT ); Tue, 1 Mar 2022 05:04:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42782 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234132AbiCAKEf (ORCPT ); Tue, 1 Mar 2022 05:04:35 -0500 Received: from mail-lj1-x22e.google.com (mail-lj1-x22e.google.com [IPv6:2a00:1450:4864:20::22e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC4847DE2F for ; Tue, 1 Mar 2022 02:03:53 -0800 (PST) Received: by mail-lj1-x22e.google.com with SMTP id y24so2141429ljh.11 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=Ydb8NKNQpUUEMoA5VczNSqcFHupi0poF77itjTh6RBy7oDeGLxp9Sf3StM7xmfND5j QPrLuJGNa0GdICrEpJ99UDXi5ituzsfEHR82inkrZXsegDWuQ5v/9M0gGxGfAlAAhOc7 V0hhrzfAkmY/VW1gIb62mFKTB88vao0/rZLT4R//3uIvMuH2BkYvSN2J+JPY9ai+nv08 aW9/a6u74x/KwB2PO06MQfwzgqz3lwXA+xKHmkMie3axwjCTXnBZsWyVDAfLLEl/V/ZG wbMwxf2zxJ1SH9lgYIsy8awouoN9rjYg1aCVQQORcvjANrPj6FfwPrE6uyorTNVGEzZF ibtw== X-Gm-Message-State: AOAM533sSG4N/RgDuG766HERkXHcZMb/Te4/K8ouzElTDTVGkJYxQrJh EwhuA/z5Q0EINjPucVPv2b253Q== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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, }; +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, struct net_bridge_vlan *v, void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state) { + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_ID_PORT_MST_STATE, + .flags = SWITCHDEV_F_DEFER, + .orig_dev = p->dev, + .u.mst_state = { + .msti = msti, + .state = state, + }, + }; struct net_bridge_vlan_group *vg; struct net_bridge_vlan *v; + int err; vg = nbp_vlan_group(p); if (!vg) @@ -42,6 +52,17 @@ void br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state) 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 = switchdev_port_attr_set(p->dev, &attr, NULL); + if (err && err != -EOPNOTSUPP) + br_warn(p->br, "unable to offload MST state on %s in MSTI %u", + netdev_name(p->dev), msti); } static void br_mst_vlan_sync_state(struct net_bridge_vlan *pv, u16 msti) From patchwork Tue Mar 1 10:03:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764475 X-Patchwork-Delegate: kuba@kernel.org 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 3E6B1C433FE for ; Tue, 1 Mar 2022 10:04:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232748AbiCAKEo (ORCPT ); Tue, 1 Mar 2022 05:04:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42968 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234147AbiCAKEh (ORCPT ); Tue, 1 Mar 2022 05:04:37 -0500 Received: from mail-lj1-x230.google.com (mail-lj1-x230.google.com [IPv6:2a00:1450:4864:20::230]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8E3A8BF35 for ; Tue, 1 Mar 2022 02:03:54 -0800 (PST) Received: by mail-lj1-x230.google.com with SMTP id e8so21170819ljj.2 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=IDSEHO9qRAu7jz2Y2hUod48CboBDW4nUDAC/Ku8AJK6cAH/Ym0PuSMZu7+65pz8K3I fCrXux7FQ48ZtnoylItLrmCKL50XPASuDr2gw0OwOW6ztvLQrcvvpQOs14y6s3GZUcWu WQiUvJFFTBLoZNLbfwbLyuffLgDPL4IFTGLvgnFuJJPLdkrD9ZduieIy9My6A4gPEhqa tgAjexbLTtmkpeXWPVC4kJvKikcpIvP5TGcPQnGldxtoDAel/hDgEF/AG/akE6Ek3utd BKLSA83HC5Jtc6dDAmPS6BnWAaIqLrCb2d3tyrjME40Le9U3QKEEpVY66Jt8SzNav2Am lPDg== X-Gm-Message-State: AOAM531eHAVlefDycbKDthoHnxUh9AHf0i5NNOh7m6WhzYJVD72uN2fS hSJsJYSXR3Teq+F+I5Vdd2PjWg== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 vlan_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 *attr); int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, bool targeted_match); int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, diff --git a/net/dsa/port.c b/net/dsa/port.c index 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; } +int dsa_port_vlan_msti(struct dsa_port *dp, const struct switchdev_attr *attr) +{ + struct dsa_switch *ds = 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, ret = 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 = dsa_port_vlan_msti(dp, attr); + break; default: ret = -EOPNOTSUPP; break; From patchwork Tue Mar 1 10:03:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764476 X-Patchwork-Delegate: kuba@kernel.org 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 5E772C433FE for ; Tue, 1 Mar 2022 10:04:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234132AbiCAKEp (ORCPT ); Tue, 1 Mar 2022 05:04:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234150AbiCAKEi (ORCPT ); Tue, 1 Mar 2022 05:04:38 -0500 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E68BD8C7D9 for ; Tue, 1 Mar 2022 02:03:55 -0800 (PST) Received: by mail-lf1-x136.google.com with SMTP id m14so25967821lfu.4 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=hLsAnRqGCdvenPGE6ki+jf5z1SWU0Fq74cP2jh4wxTC1N6EXBD+GP4pv0hPwp/VhjA 7ophnZ6HkCwxWAl7yn9PhaO6s6RAP6pm5MZmqVneACQxHIsmF4l3EVWF788ar0Cjqbcj a8Mgh15GOf4K/4LbH24grorJwwDp1LkgTJ1IpL6eRJh03F7CBjoHnmtt6W/BcNfE5e5N mEZ06bC4PAl7/MPxU8rSXpTGdujFGPn0p7p8zpWZjztGHxjfe+dj7XnJfNCVrTCYb/C1 vSsk2ztgjEe5X0h/JjBkWtczouoAJHC9ajY5hC4ierIZkP22D6MlQEsnj8qOfpFge6Cy zwOw== X-Gm-Message-State: AOAM531Tf5JTsU/S1l6NvsrhG7DaQUBSdCs8OU2BPtRdLgNz36wGGA/2 DnJIV/bi1fHrvEDUD81WQVbQzA== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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; } +int dsa_port_set_mst_state(struct dsa_port *dp, + const struct switchdev_mst_state *state) +{ + struct dsa_switch *ds = dp->ds; + int err, port = dp->index; + + if (!ds->ops->port_mst_state_set) + return -EOPNOTSUPP; + + err = 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, ret = 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 = 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; From patchwork Tue Mar 1 10:03:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764477 X-Patchwork-Delegate: kuba@kernel.org 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 D9BE6C433EF for ; Tue, 1 Mar 2022 10:04:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234100AbiCAKEq (ORCPT ); Tue, 1 Mar 2022 05:04:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234160AbiCAKEl (ORCPT ); Tue, 1 Mar 2022 05:04:41 -0500 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE6CB8CD88 for ; Tue, 1 Mar 2022 02:03:56 -0800 (PST) Received: by mail-lf1-x12d.google.com with SMTP id d23so25900475lfv.13 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=EPF7PYjisS7IxsqtoCDAoVzWK6gGjwyfddrBEFkl8iUVQ/S6qsBp49SltVlmGx+sBx rmcYoRMEST1inCDMEwh3T7ZnXlegdGrl4VjiLf2ytw0uxjISQwUMcyPghSfh2VH8WDhR 1fXfmzs321OgwSeASgFWlAz2xtHftHHkVgBwp/yX5gamewVLRyFe9JlgsobrxwGWGT6V XtJ374NeMbN2ai7QPIuVPm33uycozZSpoP6O7+qFrvJz1sRb9XMnFtmRgiiWyriI0r3b MAxob/Q+BgGabTwDZmlBlN6M2zKxgB6Dk5OGcR1DgKSeA+7Z5iKiWoWel4PM3SLkbegA IJgg== X-Gm-Message-State: AOAM5322onCSwwhZyE7+oilOXhNGAvVAB+PkqHlvbxrSqbPufCgw9P+O eMuUowlHbEl/3vBiXOxPvWErXw== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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/chip.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); } +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 = { + .valid = true, + .sid = 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; + /* Must be called after mv88e6xxx_vtu_setup (which flushes the + * VTU, thereby also flushing the STU). + */ + err = mv88e6xxx_stu_setup(chip); + if (err) + goto unlock; + /* Setup Switch Port Registers */ for (i = 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 = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .phylink_get_caps = mv88e6095_phylink_get_caps, + .stu_getnext = mv88e6352_g1_stu_getnext, + .stu_loadpurge = mv88e6352_g1_stu_loadpurge, .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; @@ -4968,6 +5004,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .stu_getnext = mv88e6352_g1_stu_getnext, + .stu_loadpurge = mv88e6352_g1_stu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, .serdes_pcs_config = mv88e6352_serdes_pcs_config, @@ -5033,6 +5071,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .stu_getnext = mv88e6390_g1_stu_getnext, + .stu_loadpurge = mv88e6390_g1_stu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390_serdes_get_lane, /* Check status register pause & lpa register */ @@ -5098,6 +5138,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .stu_getnext = mv88e6390_g1_stu_getnext, + .stu_loadpurge = mv88e6390_g1_stu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390x_serdes_get_lane, .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, @@ -5166,6 +5208,8 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .stu_getnext = mv88e6390_g1_stu_getnext, + .stu_loadpurge = mv88e6390_g1_stu_loadpurge, .serdes_power = mv88e6393x_serdes_power, .serdes_get_lane = mv88e6393x_serdes_get_lane, .serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state, @@ -5234,6 +5278,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_ports = 11, .num_internal_phys = 8, .max_vid = 4095, + .max_sid = 63, .port_base_addr = 0x10, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5487,6 +5532,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_internal_phys = 9, .num_gpio = 16, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5510,6 +5556,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_internal_phys = 9, .num_gpio = 16, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5532,6 +5579,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5554,6 +5602,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5576,6 +5625,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5815,6 +5865,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_internal_phys = 5, .num_gpio = 15, .max_vid = 4095, + .max_sid = 63, .port_base_addr = 0x10, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5839,6 +5890,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_internal_phys = 9, .num_gpio = 16, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5863,6 +5915,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_internal_phys = 9, .num_gpio = 16, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, @@ -5886,6 +5939,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .max_vid = 8191, + .max_sid = 63, .port_base_addr = 0x0, .phy_base_addr = 0x0, .global1_addr = 0x1b, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 30b92a265613..be654be69982 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -20,6 +20,7 @@ #define EDSA_HLEN 8 #define MV88E6XXX_N_FID 4096 +#define MV88E6XXX_N_SID 64 #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]; }; @@ -602,6 +610,12 @@ struct mv88e6xxx_ops { int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); + /* 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; @@ -700,6 +714,11 @@ struct mv88e6xxx_hw_stat { int type; }; +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 mv88e6xxx_chip *chip) return chip->info->max_vid; } +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/mv88e6xxx/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 *chip, 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/mv88e6xxx/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_chip *chip, /* Offset 0x03: VTU SID Register */ -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_chip *chip, if (err) return err; - entry->sid = val & MV88E6352_G1_VTU_SID_MASK; + *sid = val & MV88E6352_G1_VTU_SID_MASK; return 0; } -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 = entry->sid & MV88E6352_G1_VTU_SID_MASK; + u16 val = sid & MV88E6352_G1_VTU_SID_MASK; return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val); } @@ -91,7 +89,7 @@ static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op) /* Offset 0x06: VTU VID Register */ 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; - entry->vid = val & 0xfff; + if (vid) { + *vid = val & 0xfff; - if (val & MV88E6390_G1_VTU_VID_PAGE) - entry->vid |= 0x1000; + if (val & MV88E6390_G1_VTU_VID_PAGE) + *vid |= 0x1000; + } - entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); + if (valid) + *valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); return 0; } static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + bool valid, u16 vid) { - u16 val = entry->vid & 0xfff; + u16 val = vid & 0xfff; - if (entry->vid & 0x1000) + if (vid & 0x1000) val |= MV88E6390_G1_VTU_VID_PAGE; - if (entry->valid) + if (valid) val |= MV88E6XXX_G1_VTU_VID_VALID; return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val); @@ -147,7 +148,7 @@ static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6xxx_chip *chip, } 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 mv88e6xxx_chip *chip, /* Extract MemberTag data */ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { unsigned int member_offset = (i % 4) * 4; + unsigned int state_offset = member_offset + 2; - entry->member[i] = (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 = mv88e6185_g1_vtu_stu_data_read(chip, regs); - if (err) - return err; + if (member) + member[i] = (regs[i / 4] >> member_offset) & 0x3; - /* Extract PortState data */ - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { - unsigned int state_offset = (i % 4) * 4 + 2; - - entry->state[i] = (regs[i / 4] >> state_offset) & 0x3; + if (state) + state[i] = (regs[i / 4] >> state_offset) & 0x3; } return 0; } static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + u8 *member, u8 *state) { u16 regs[3] = { 0 }; int i; @@ -199,8 +184,11 @@ static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, unsigned int member_offset = (i % 4) * 4; unsigned int state_offset = member_offset + 2; - regs[i / 4] |= (entry->member[i] & 0x3) << member_offset; - regs[i / 4] |= (entry->state[i] & 0x3) << state_offset; + if (member) + regs[i / 4] |= (member[i] & 0x3) << member_offset; + + if (state) + regs[i / 4] |= (state[i] & 0x3) << state_offset; } /* Write all 3 VTU/STU Data registers */ @@ -268,48 +256,6 @@ static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data) /* VLAN Translation Unit Operations */ -static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - int err; - - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); - if (err) - return err; - - err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); - if (err) - return err; - - err = 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 = mv88e6xxx_g1_vtu_sid_read(chip, vtu); - if (err) - return err; - - stu.sid = vtu->sid - 1; - - err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu); - if (err) - return err; - - if (stu.sid != 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 *chip, * write the VID only once, when the entry is given as invalid. */ if (!entry->valid) { - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = 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 *chip, if (err) return err; - return mv88e6xxx_g1_vtu_vid_read(chip, entry); + return mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, &entry->vid); } int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, @@ -350,11 +296,7 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_read(chip, entry); - if (err) - return err; - - err = mv88e6185_g1_stu_data_read(chip, entry); + err = mv88e6185_g1_vtu_data_read(chip, entry->member, entry->state); if (err) return err; @@ -384,7 +326,7 @@ int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_read(chip, entry); + err = mv88e6185_g1_vtu_data_read(chip, entry->member, NULL); if (err) return err; @@ -392,12 +334,7 @@ int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, if (err) return err; - /* Fetch VLAN PortState data from the STU */ - err = mv88e6xxx_g1_vtu_stu_get(chip, entry); - if (err) - return err; - - err = mv88e6185_g1_stu_data_read(chip, entry); + err = mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } @@ -420,16 +357,11 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, if (err) return err; - /* Fetch VLAN PortState data from the STU */ - err = mv88e6xxx_g1_vtu_stu_get(chip, entry); - if (err) - return err; - - err = mv88e6390_g1_vtu_data_read(chip, entry->state); + err = mv88e6xxx_g1_vtu_fid_read(chip, entry); if (err) return err; - err = mv88e6xxx_g1_vtu_fid_read(chip, entry); + err = 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; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_write(chip, entry); + err = mv88e6185_g1_vtu_data_write(chip, entry->member, entry->state); if (err) return err; @@ -479,27 +411,21 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, if (err) return err; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - /* Write MemberTag and PortState data */ - err = mv88e6185_g1_vtu_data_write(chip, entry); - if (err) - return err; - - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + /* Write MemberTag data */ + err = mv88e6185_g1_vtu_data_write(chip, entry->member, NULL); if (err) return err; - /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); if (err) return err; - err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + err = 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; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - /* Write PortState data */ - err = mv88e6390_g1_vtu_data_write(chip, entry->state); + /* Write MemberTag data */ + err = mv88e6390_g1_vtu_data_write(chip, entry->member); if (err) return err; - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); if (err) return err; - /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; + } - /* Write MemberTag data */ - err = 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 = 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 = 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 = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; + } - err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, NULL); + if (err) + return err; + + if (entry->valid) { + err = mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } - /* Load/Purge VTU entry */ - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); + return 0; } -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 = 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 = 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; @@ -559,16 +557,59 @@ int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) if (err) return err; - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err = 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 = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err = 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); } +/* VTU Violation Management */ + static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) { struct mv88e6xxx_chip *chip = dev_id; - struct mv88e6xxx_vtu_entry entry; + u16 val, vid; int spid; int err; - u16 val; mv88e6xxx_reg_lock(chip); @@ -580,7 +621,7 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) if (err) goto out; - err = mv88e6xxx_g1_vtu_vid_read(chip, &entry); + err = mv88e6xxx_g1_vtu_vid_read(chip, NULL, &vid); if (err) goto out; @@ -588,13 +629,13 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) 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++; } if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n", - entry.vid, spid); + vid, spid); chip->ports[spid].vtu_miss_violation++; } From patchwork Tue Mar 1 10:03:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764479 X-Patchwork-Delegate: kuba@kernel.org 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 8E498C433EF for ; Tue, 1 Mar 2022 10:04:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234182AbiCAKEt (ORCPT ); Tue, 1 Mar 2022 05:04:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234161AbiCAKEl (ORCPT ); Tue, 1 Mar 2022 05:04:41 -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 D95308CDA6 for ; Tue, 1 Mar 2022 02:03:57 -0800 (PST) Received: by mail-lj1-x22c.google.com with SMTP id 29so21102234ljv.10 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=IWXdCdsA/d/C2/Gtq1xnNIhrLCs5kw9FvZYmpFR9Kpz5qZxb7Mulb2YGzDCPjSlHuA 4VmG8KNFj6HgOTuJkamlPEsUq3Jm8CHYKJZUgkHhFslrlTDSBx/SDT67+D8Y6rhbvqQ5 CUdc/Fvg/Lmq7wKfhJkJt009awvaCOKTlaBwPG6alJXsuXfaHyK7EbOmFm66bkJ8D8Si Ej5AIzGX+wLXt0yxGKozRuOl04gAVeUP2ctViz1ncaXEfl6YlfXegfPNBxA7FYzjLSwy jT/5i/7bOPDYGx/0JfaYDr1p2e3z9HNB9EJpPDTtVAMrtUEKixGNRArvlbarhw/suxIK JtYA== X-Gm-Message-State: AOAM5328oESZsVLF78KAcSMxaWMShIByVukYaqdPiYICC4mLCVU4tAxN gaU99SXASeSqNHY2bDIAFit0kQ== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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/chip.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, _MV88E6XXX_REGION_MAX, diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/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 devlink *dl, return 0; } +/** + * 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 = dsa_devlink_to_ds(dl); + struct mv88e6xxx_chip *chip = ds->priv; + struct mv88e6xxx_stu_entry stu; + int err; + + table = kcalloc(mv88e6xxx_max_sid(chip) + 1, + sizeof(struct mv88e6xxx_devlink_stu_entry), + GFP_KERNEL); + if (!table) + return -ENOMEM; + + entry = table; + stu.sid = mv88e6xxx_max_sid(chip); + stu.valid = false; + + mv88e6xxx_reg_lock(chip); + + do { + err = mv88e6xxx_g1_stu_getnext(chip, &stu); + if (err) + break; + + if (!stu.valid) + break; + + err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, + &entry->sid); + err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, + &entry->vid); + err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1, + &entry->data[0]); + err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2, + &entry->data[1]); + err = 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 = (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 = { .destructor = kfree, }; +static struct devlink_region_ops mv88e6xxx_region_stu_ops = { + .name = "stu", + .snapshot = mv88e6xxx_region_stu_snapshot, + .destructor = kfree, +}; + static struct devlink_region_ops mv88e6xxx_region_pvt_ops = { .name = "pvt", .snapshot = mv88e6xxx_region_pvt_snapshot, @@ -640,6 +725,11 @@ static struct mv88e6xxx_region mv88e6xxx_regions[] = { .ops = &mv88e6xxx_region_vtu_ops /* calculated at runtime */ }, + [MV88E6XXX_REGION_STU] = { + .ops = &mv88e6xxx_region_stu_ops, + .cond = mv88e6xxx_has_stu, + /* calculated at runtime */ + }, [MV88E6XXX_REGION_PVT] = { .ops = &mv88e6xxx_region_pvt_ops, .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16), @@ -706,6 +796,10 @@ int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds) size = (mv88e6xxx_max_vid(chip) + 1) * sizeof(struct mv88e6xxx_devlink_vtu_entry); break; + case MV88E6XXX_REGION_STU: + size = (mv88e6xxx_max_sid(chip) + 1) * + sizeof(struct mv88e6xxx_devlink_stu_entry); + break; } region = dsa_devlink_region_create(ds, ops, 1, size); From patchwork Tue Mar 1 10:03:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Waldekranz X-Patchwork-Id: 12764478 X-Patchwork-Delegate: kuba@kernel.org 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 01BEFC433FE for ; Tue, 1 Mar 2022 10:04:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234177AbiCAKEr (ORCPT ); Tue, 1 Mar 2022 05:04:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43496 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234163AbiCAKEl (ORCPT ); Tue, 1 Mar 2022 05:04:41 -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 CC4018CDBB for ; Tue, 1 Mar 2022 02:03:58 -0800 (PST) Received: by mail-lf1-x134.google.com with SMTP id f37so25915891lfv.8 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=lasz787xRlhcnJardy8aEZ6xX4yzyn8f6rQtNtB+1jotblW1S/x61pBhWnBxr+3jnb OFzD3w3FJMYOfpMQCqa+RGhfyIFqwyMofhKCh3fSW79XtHi2zZoneG79LFEVDPZJmhA3 ISf5eNKfeC80nKL/KE1+F7ubDqoviI+ukHj4T6cz2U7sovBO1PC3iuQ0qx6qSLw2SKGe mnVDBD/dl/8+6V0DYmtNCBleTar6Odbm1g+ku3R5tMsXKPsn8eUKDch55QZ/uLzkqWyU abxwWlr6RIeWipHnaRDFS40N+xIp9JHwRgLWNs3OlT2Vn3LZuFf+ExJ4AiuS49J8OfX1 8+dQ== X-Gm-Message-State: AOAM530r2NuHqYQuOEuWnOo3E6kMfm8rPIDsWx+UQ0hoGWTS+03Ur3Pb OXuBnTJf2+KUsqnXDXsPA2VJgQ== 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 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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/chip.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_chip *chip) return mv88e6xxx_stu_loadpurge(chip, &stu); } +static int mv88e6xxx_sid_new(struct mv88e6xxx_chip *chip, u8 *sid) +{ + DECLARE_BITMAP(busy, MV88E6XXX_N_SID) = { 0 }; + struct mv88e6xxx_mst *mst; + + set_bit(0, busy); + + list_for_each_entry(mst, &chip->msts, node) { + set_bit(mst->stu.sid, busy); + } + + *sid = find_first_zero_bit(busy, MV88E6XXX_N_SID); + + return (*sid >= mv88e6xxx_max_sid(chip)) ? -ENOSPC : 0; +} + +static int mv88e6xxx_sid_put(struct mv88e6xxx_chip *chip, u8 sid) +{ + struct mv88e6xxx_mst *mst, *tmp; + int err = 0; + + list_for_each_entry_safe(mst, tmp, &chip->msts, node) { + if (mst->stu.sid == sid) { + if (refcount_dec_and_test(&mst->refcnt)) { + mst->stu.valid = false; + err = 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_device *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 == br && mst->msti == msti) { + refcount_inc(&mst->refcnt); + *sid = mst->stu.sid; + return 0; + } + } + + err = mv88e6xxx_sid_new(chip, sid); + if (err) + return err; + + mst = kzalloc(sizeof(*mst), GFP_KERNEL); + if (!mst) + return -ENOMEM; + + INIT_LIST_HEAD(&mst->node); + refcount_set(&mst->refcnt, 1); + mst->br = br; + mst->msti = msti; + mst->stu.valid = true; + mst->stu.sid = *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 = 0; i < mv88e6xxx_num_ports(chip); i++) + mst->stu.state[i] = 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 = dsa_to_port(ds, port); + struct mv88e6xxx_chip *chip = 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 = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + break; + default: + return -EINVAL; + } + + list_for_each_entry(mst, &chip->msts, node) { + if (mst->br == dsa_port_bridge_dev_get(dp) && + mst->msti == st->msti) { + if (mst->stu.state[port] == state) + return 0; + + mst->stu.state[port] = state; + mv88e6xxx_reg_lock(chip); + err = 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 mv88e6xxx_chip *chip, if (err) return err; + if (!vlan.valid && vlan.sid) { + err = mv88e6xxx_sid_put(chip, vlan.sid); + if (err) + return err; + } + return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); } @@ -2482,6 +2619,44 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, return err; } +static int mv88e6xxx_vlan_msti_set(struct dsa_switch *ds, + const struct switchdev_attr *attr) +{ + const struct switchdev_vlan_attr *vattr = &attr->u.vlan_attr; + struct mv88e6xxx_chip *chip = ds->priv; + struct mv88e6xxx_vtu_entry vlan; + u8 new_sid; + int err; + + mv88e6xxx_reg_lock(chip); + + err = mv88e6xxx_vtu_get(chip, vattr->vid, &vlan); + if (err) + goto unlock; + + if (!vlan.valid) { + err = -EINVAL; + goto unlock; + } + + err = mv88e6xxx_sid_get(chip, attr->orig_dev, vattr->msti, &new_sid); + if (err) + goto unlock; + + if (vlan.sid) { + err = mv88e6xxx_sid_put(chip, vlan.sid); + if (err) + goto unlock; + } + + vlan.sid = new_sid; + err = 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(struct device *dev) mutex_init(&chip->reg_lock); INIT_LIST_HEAD(&chip->mdios); idr_init(&chip->policies); + INIT_LIST_HEAD(&chip->msts); return chip; } @@ -6540,10 +6716,12 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .port_pre_bridge_flags = mv88e6xxx_port_pre_bridge_flags, .port_bridge_flags = mv88e6xxx_port_bridge_flags, .port_stp_state_set = mv88e6xxx_port_stp_state_set, + .port_mst_state_set = mv88e6xxx_port_mst_state_set, .port_fast_age = mv88e6xxx_port_fast_age, .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, .port_vlan_add = mv88e6xxx_port_vlan_add, .port_vlan_del = mv88e6xxx_port_vlan_del, + .vlan_msti_set = mv88e6xxx_vlan_msti_set, .port_fdb_add = mv88e6xxx_port_fdb_add, .port_fdb_del = mv88e6xxx_port_fdb_del, .port_fdb_dump = mv88e6xxx_port_fdb_dump, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.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; }; +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; @@ -397,6 +407,9 @@ struct mv88e6xxx_chip { /* devlink regions */ struct devlink_region *regions[_MV88E6XXX_REGION_MAX]; + + /* Bridge MST to SID mappings */ + struct list_head msts; }; struct mv88e6xxx_bus_ops {