From patchwork Sat May 4 13:59:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095237 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="gtXHSqOa"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9c72wVqz9s6w for ; Sat, 4 May 2019 23:59:51 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726969AbfEDN7u (ORCPT ); Sat, 4 May 2019 09:59:50 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:38826 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726230AbfEDN7t (ORCPT ); Sat, 4 May 2019 09:59:49 -0400 Received: by mail-wm1-f68.google.com with SMTP id f2so4916322wmj.3 for ; Sat, 04 May 2019 06:59:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ayIYSxG6qThnYCYT1YaBgiQ6EuXJ3DaEJwMfddDhfR0=; b=gtXHSqOarsh0JH5WIcUi6O2z5w8ap0PFlV3eXMWYY6ame0Y+h39njeR2XmCp+8+q0J nnCQvg4WVcyWtvJHXoLAS6WzOIeK/JTFzUZwz4QUxioPozQ0NYQqORO6adq3ul49eUD5 wV8H5a9kDLOOA998wXhZSmLVPfF9SCV9QSg5MfR3xJVyxH21HIkiNYgQKzqQP85xKv06 B019MD9A6blYN6/0CPFhEvMF4+4ONaWnZEpyDs9FJWgm1SNhcmAWBtQxd53ALHDJxuDK K8mq5/rwJ/UpDjVIK5GDf1oDsbcphj8cHze1u3MJPehufe1hB3jzl1jKWMeqhyVvui5k 3g4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ayIYSxG6qThnYCYT1YaBgiQ6EuXJ3DaEJwMfddDhfR0=; b=A9JEzNVhn4knRvR+T7e2CZS0TJxN89zkCEzKzROGWVywkC2Fe8edUksJ1WltUoftis VpKz4kBZ2UTeETDyjsMDWF2duNr02RLCo19pbUgJsksH49XAkyZa6sI7Bkj59aAMfio3 15l/fbe31ErvHsQGxWyckM1cw/BBAeWQQZ2HQCtVMSQOh+tcvh2uB6Fnm0c4bZsdPgju JmOjr+45SfqDdPAlx3Ef6Pr3yJtMMUSyx3ekCezSFxKiZWxQ5mIrC5quAhCMkJkWF2jU s34G83a5VvhNxN+ppgjfkjxCxuGXC+ipUC8q8OtDvJ1kEuvp9ziks6Lu3PShe7zlSTl0 HUvQ== X-Gm-Message-State: APjAAAV4c63YxRmPLqHsfEB9odWfZVnik/9cXzEU6PfSoQa81jSgduxg qMHanWbbJz33lMmJR5pbNr8= X-Google-Smtp-Source: APXvYqzLKtSxuxoE/6+JnvqqgXFmMSlbUTxUdv07Gp88wujON17bJ6UnjsqHm5BGpC0vSz2GmaPorQ== X-Received: by 2002:a1c:e08a:: with SMTP id x132mr10038113wmg.24.1556978385786; Sat, 04 May 2019 06:59:45 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:45 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 1/9] net: dsa: Call driver's setup callback after setting up its switchdev notifier Date: Sat, 4 May 2019 16:59:11 +0300 Message-Id: <20190504135919.23185-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This allows the driver to perform some manipulations of its own during setup, using generic switchdev calls. Having the notifiers registered at setup time is important because otherwise any switchdev transaction emitted during this time would be ignored (dispatched to an empty call chain). One current usage scenario is for the driver to request DSA to set up 802.1Q based switch tagging for its ports. There is no danger for the driver setup code to start racing now with switchdev events emitted from the network stack (such as bridge core) even if the notifier is registered earlier. This is because the network stack needs a net_device as a vehicle to perform switchdev operations, and the slave net_devices are registered later than the core driver setup anyway (ds->ops->setup in dsa_switch_setup vs dsa_port_setup). Luckily DSA doesn't need a net_device to carry out switchdev callbacks, and therefore drivers shouldn't assume either that net_devices are available at the time their switchdev callbacks get invoked. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Reviewed-by: Vivien Didelot --- Changes in v2: - None. net/dsa/dsa2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index bbc9f56e89b9..f1ad80851616 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -371,14 +371,14 @@ static int dsa_switch_setup(struct dsa_switch *ds) if (err) return err; - err = ds->ops->setup(ds); - if (err < 0) - return err; - err = dsa_switch_register_notifier(ds); if (err) return err; + err = ds->ops->setup(ds); + if (err < 0) + return err; + if (!ds->slave_mii_bus && ds->ops->phy_read) { ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); if (!ds->slave_mii_bus) From patchwork Sat May 4 13:59:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095239 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="nWuEazso"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cC6vpkz9s4Y for ; Sat, 4 May 2019 23:59:55 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727129AbfEDN7y (ORCPT ); Sat, 4 May 2019 09:59:54 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:35866 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726215AbfEDN7u (ORCPT ); Sat, 4 May 2019 09:59:50 -0400 Received: by mail-wm1-f65.google.com with SMTP id a10so1546420wme.1 for ; Sat, 04 May 2019 06:59:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=SBBTnnBuL8kKQlDekVzJmVKPErfeIIHUK+7d67VDqW8=; b=nWuEazsotyxrcc+kgaWfqxo9w4jVPCa7AoHgFMfo14qmUPHvmHmyT7AcJDKokEASD3 7kPEuERfqIYuxJJrATVq2kYF/W+5c1ijmdcKg/K9hB4km3J0jwZD9pZLZEFnZAmTKDEc Hks2VdbFY02xxUfLuyq8GsYA61+lPA/1tjEfh+uRN1kGFnv5AG/2qvGsAehc6qTbtBIg xSWwfN/BdMJNmSO+7vIBJ443cO6c5uogVhNmUsjo2HbeJRSqkwyCFKvm1oYmwYEd5i0X 9LM3EcAyyHae5EmLH7c+DpNqp4k9QQkyKd1Gs+IDWnSTuPb/QJNMfnv4cwGoQRlgXvjR vQ3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SBBTnnBuL8kKQlDekVzJmVKPErfeIIHUK+7d67VDqW8=; b=n1p9ylY77hqg8SnKdCuFvHqpu7P4lzJs2CFrHWP+FD7jSUmkDCOwfcJaQWiNpvgTg6 NUs3E4Hz9tJboLrKPChxdHXXLydbTnAvg6/psKhTSTmLh2i1MRjliL37mDLZgz/BkGj7 7xrsxI0otVHHzLnTgzOw5Ipqpr5MxaWb976znBcOrfNh8jBPoDc2tbOrsVmFZMNdjHbC l9/teAYORY4EoqTpTS4PhWI+D5b98ZGkUDi194Qd42BDWF6xrX80HWXpg+Og+aW0p5sq G3gogrxk+Q3Mo9SVTvZxKw6tq2SbRNa1XWfTMRH+86Chw1IZHdypvSFN1+wCnwG/jjI+ 5jOA== X-Gm-Message-State: APjAAAXpK2iFox+xzSfDesnJnU5RkAXogUzVIdZR1s7j0jm/GMVS1pYS Jke/Ry7gdkIT2xQhW9rrflo= X-Google-Smtp-Source: APXvYqwtmwo1qvbeNe8xP4zOzYpTGTJxM3/u7Tdkr6jvG/DLVyjqw0ugxH8AueCVeVJ3S7ImmBqVuA== X-Received: by 2002:a7b:ca42:: with SMTP id m2mr10170194wml.35.1556978386768; Sat, 04 May 2019 06:59:46 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:46 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 2/9] net: dsa: Optional VLAN-based port separation for switches without tagging Date: Sat, 4 May 2019 16:59:12 +0300 Message-Id: <20190504135919.23185-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch provides generic DSA code for using VLAN (802.1Q) tags for the same purpose as a dedicated switch tag for injection/extraction. It is based on the discussions and interest that has been so far expressed in https://www.spinics.net/lists/netdev/msg556125.html. Unlike all other DSA-supported tagging protocols, CONFIG_NET_DSA_TAG_8021Q does not offer a complete solution for drivers (nor can it). Instead, it provides generic code that driver can opt into calling: - dsa_8021q_xmit: Inserts a VLAN header with the specified contents. Can be called from another tagging protocol's xmit function. Currently the LAN9303 driver is inserting headers that are simply 802.1Q with custom fields, so this is an opportunity for code reuse. - dsa_8021q_rcv: Retrieves the TPID and TCI from a VLAN-tagged skb. Removing the VLAN header is left as a decision for the caller to make. - dsa_port_setup_8021q_tagging: For each user port, installs an Rx VID and a Tx VID, for proper untagged traffic identification on ingress and steering on egress. Also sets up the VLAN trunk on the upstream (CPU or DSA) port. Drivers are intentionally left to call this function explicitly, depending on the context and hardware support. The expected switch behavior and VLAN semantics should not be violated under any conditions. That is, after calling dsa_port_setup_8021q_tagging, the hardware should still pass all ingress traffic, be it tagged or untagged. For uniformity with the other tagging protocols, a module for the dsa_8021q_netdev_ops structure is registered, but the typical usage is to set up another tagging protocol which selects CONFIG_NET_DSA_TAG_8021Q, and calls the API from tag_8021q.h. Null function definitions are also provided so that a "depends on" is not forced in the Kconfig. This tagging protocol only works when switch ports are standalone, or when they are added to a VLAN-unaware bridge. It will probably remain this way for the reasons below. When added to a bridge that has vlan_filtering 1, the bridge core will install its own VLANs and reset the pvids through switchdev. For the bridge core, switchdev is a write-only pipe. All VLAN-related state is kept in the bridge core and nothing is read from DSA/switchdev or from the driver. So the bridge core will break this port separation because it will install the vlan_default_pvid into all switchdev ports. Even if we could teach the bridge driver about switchdev preference of a certain vlan_default_pvid (task difficult in itself since the current setting is per-bridge but we would need it per-port), there would still exist many other challenges. Firstly, in the DSA rcv callback, a driver would have to perform an iterative reverse lookup to find the correct switch port. That is because the port is a bridge slave, so its Rx VID (port PVID) is subject to user configuration. How would we ensure that the user doesn't reset the pvid to a different value (which would make an O(1) translation impossible), or to a non-unique value within this DSA switch tree (which would make any translation impossible)? Finally, not all switch ports are equal in DSA, and that makes it difficult for the bridge to be completely aware of this anyway. The CPU port needs to transmit tagged packets (VLAN trunk) in order for the DSA rcv code to be able to decode source information. But the bridge code has absolutely no idea which switch port is the CPU port, if nothing else then just because there is no netdevice registered by DSA for the CPU port. Also DSA does not currently allow the user to specify that they want the CPU port to do VLAN trunking anyway. VLANs are added to the CPU port using the same flags as they were added on the user port. So the VLANs installed by dsa_port_setup_8021q_tagging per driver request should remain private from the bridge's and user's perspective, and should not alter the VLAN semantics observed by the user. In the current implementation a VLAN range ending at 4095 (VLAN_N_VID) is reserved for this purpose. Each port receives a unique Rx VLAN and a unique Tx VLAN. Separate VLANs are needed for Rx and Tx because they serve different purposes: on Rx the switch must process traffic as untagged and process it with a port-based VLAN, but with care not to hinder bridging. On the other hand, the Tx VLAN is where the reachability restrictions are imposed, since by tagging frames in the xmit callback we are telling the switch onto which port to steer the frame. Some general guidance on how this support might be employed for real-life hardware (some comments made by Florian Fainelli): - If the hardware supports VLAN tag stacking, it should somehow back up its private VLAN settings when the bridge tries to override them. Then the driver could re-apply them as outer tags. Dedicating an outer tag per bridge device would allow identical inner tag VID numbers to co-exist, yet preserve broadcast domain isolation. - If the switch cannot handle VLAN tag stacking, it should disable this port separation when added as slave to a vlan_filtering bridge, in that case having reduced functionality. - Drivers for old switches that don't support the entire VLAN_N_VID range will need to rework the current range selection mechanism. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Vivien Didelot --- Changes in v2: - None. include/linux/dsa/8021q.h | 76 +++++++++++++ include/net/dsa.h | 2 + net/dsa/Kconfig | 11 ++ net/dsa/Makefile | 1 + net/dsa/tag_8021q.c | 222 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+) create mode 100644 include/linux/dsa/8021q.h create mode 100644 net/dsa/tag_8021q.c diff --git a/include/linux/dsa/8021q.h b/include/linux/dsa/8021q.h new file mode 100644 index 000000000000..3911e0586478 --- /dev/null +++ b/include/linux/dsa/8021q.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2019, Vladimir Oltean + */ + +#ifndef _NET_DSA_8021Q_H +#define _NET_DSA_8021Q_H + +#include + +struct dsa_switch; +struct sk_buff; +struct net_device; +struct packet_type; + +#if IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) + +int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, + bool enabled); + +struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, + u16 tpid, u16 tci); + +struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev, + struct packet_type *pt, u16 *tpid, u16 *tci); + +u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port); + +u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port); + +int dsa_8021q_rx_switch_id(u16 vid); + +int dsa_8021q_rx_source_port(u16 vid); + +#else + +int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, + bool enabled) +{ + return 0; +} + +struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, + u16 tpid, u16 tci) +{ + return NULL; +} + +struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev, + struct packet_type *pt, u16 *tpid, u16 *tci) +{ + return NULL; +} + +u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port) +{ + return 0; +} + +u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port) +{ + return 0; +} + +int dsa_8021q_rx_switch_id(u16 vid) +{ + return 0; +} + +int dsa_8021q_rx_source_port(u16 vid) +{ + return 0; +} + +#endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) */ + +#endif /* _NET_DSA_8021Q_H */ diff --git a/include/net/dsa.h b/include/net/dsa.h index 18db7b8e7a8e..69f3714f42ba 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -42,6 +42,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_MTK_VALUE 9 #define DSA_TAG_PROTO_QCA_VALUE 10 #define DSA_TAG_PROTO_TRAILER_VALUE 11 +#define DSA_TAG_PROTO_8021Q_VALUE 12 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -56,6 +57,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_MTK = DSA_TAG_PROTO_MTK_VALUE, DSA_TAG_PROTO_QCA = DSA_TAG_PROTO_QCA_VALUE, DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, + DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index c0734028c7dc..fc15a7e1a6df 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -17,6 +17,17 @@ menuconfig NET_DSA if NET_DSA +# tagging formats +config NET_DSA_TAG_8021Q + tristate "Tag driver for switches using custom 802.1Q VLAN headers" + select VLAN_8021Q + help + Unlike the other tagging protocols, the 802.1Q config option simply + provides helpers for other tagging implementations that might rely on + VLAN in one way or another. It is not a complete solution. + + Drivers which use these helpers should select this as dependency. + config NET_DSA_TAG_BRCM_COMMON tristate default n diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 8a737b6ee94c..e97c794ec57b 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o # tagging formats +obj-$(CONFIG_NET_DSA_TAG_8021Q) += tag_8021q.o obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c new file mode 100644 index 000000000000..8ae48c7e1e76 --- /dev/null +++ b/net/dsa/tag_8021q.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Vladimir Oltean + * + * This module is not a complete tagger implementation. It only provides + * primitives for taggers that rely on 802.1Q VLAN tags to use. The + * dsa_8021q_netdev_ops is registered for API compliance and not used + * directly by callers. + */ +#include +#include + +#include "dsa_priv.h" + +/* Allocating two VLAN tags per port - one for the RX VID and + * the other for the TX VID - see below + */ +#define DSA_8021Q_VID_RANGE (DSA_MAX_SWITCHES * DSA_MAX_PORTS) +#define DSA_8021Q_VID_BASE (VLAN_N_VID - 2 * DSA_8021Q_VID_RANGE - 1) +#define DSA_8021Q_RX_VID_BASE (DSA_8021Q_VID_BASE) +#define DSA_8021Q_TX_VID_BASE (DSA_8021Q_VID_BASE + DSA_8021Q_VID_RANGE) + +/* Returns the VID to be inserted into the frame from xmit for switch steering + * instructions on egress. Encodes switch ID and port ID. + */ +u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port) +{ + return DSA_8021Q_TX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port; +} +EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid); + +/* Returns the VID that will be installed as pvid for this switch port, sent as + * tagged egress towards the CPU port and decoded by the rcv function. + */ +u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port) +{ + return DSA_8021Q_RX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port; +} +EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid); + +/* Returns the decoded switch ID from the RX VID. */ +int dsa_8021q_rx_switch_id(u16 vid) +{ + return ((vid - DSA_8021Q_RX_VID_BASE) / DSA_MAX_PORTS); +} +EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id); + +/* Returns the decoded port ID from the RX VID. */ +int dsa_8021q_rx_source_port(u16 vid) +{ + return ((vid - DSA_8021Q_RX_VID_BASE) % DSA_MAX_PORTS); +} +EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port); + +/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single + * front-panel switch port (here swp0). + * + * Port identification through VLAN (802.1Q) tags has different requirements + * for it to work effectively: + * - On RX (ingress from network): each front-panel port must have a pvid + * that uniquely identifies it, and the egress of this pvid must be tagged + * towards the CPU port, so that software can recover the source port based + * on the VID in the frame. But this would only work for standalone ports; + * if bridged, this VLAN setup would break autonomous forwarding and would + * force all switched traffic to pass through the CPU. So we must also make + * the other front-panel ports members of this VID we're adding, albeit + * we're not making it their PVID (they'll still have their own). + * By the way - just because we're installing the same VID in multiple + * switch ports doesn't mean that they'll start to talk to one another, even + * while not bridged: the final forwarding decision is still an AND between + * the L2 forwarding information (which is limiting forwarding in this case) + * and the VLAN-based restrictions (of which there are none in this case, + * since all ports are members). + * - On TX (ingress from CPU and towards network) we are faced with a problem. + * If we were to tag traffic (from within DSA) with the port's pvid, all + * would be well, assuming the switch ports were standalone. Frames would + * have no choice but to be directed towards the correct front-panel port. + * But because we also want the RX VLAN to not break bridging, then + * inevitably that means that we have to give them a choice (of what + * front-panel port to go out on), and therefore we cannot steer traffic + * based on the RX VID. So what we do is simply install one more VID on the + * front-panel and CPU ports, and profit off of the fact that steering will + * work just by virtue of the fact that there is only one other port that's + * a member of the VID we're tagging the traffic with - the desired one. + * + * So at the end, each front-panel port will have one RX VID (also the PVID), + * the RX VID of all other front-panel ports, and one TX VID. Whereas the CPU + * port will have the RX and TX VIDs of all front-panel ports, and on top of + * that, is also tagged-input and tagged-output (VLAN trunk). + * + * CPU port CPU port + * +-------------+-----+-------------+ +-------------+-----+-------------+ + * | RX VID | | | | TX VID | | | + * | of swp0 | | | | of swp0 | | | + * | +-----+ | | +-----+ | + * | ^ T | | | Tagged | + * | | | | | ingress | + * | +-------+---+---+-------+ | | +-----------+ | + * | | | | | | | | Untagged | + * | | U v U v U v | | v egress | + * | +-----+ +-----+ +-----+ +-----+ | | +-----+ +-----+ +-----+ +-----+ | + * | | | | | | | | | | | | | | | | | | | | + * | |PVID | | | | | | | | | | | | | | | | | | + * +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+ + * swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3 + */ +int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) +{ + int upstream = dsa_upstream_port(ds, port); + struct dsa_port *dp = &ds->ports[port]; + struct dsa_port *upstream_dp = &ds->ports[upstream]; + u16 rx_vid = dsa_8021q_rx_vid(ds, port); + u16 tx_vid = dsa_8021q_tx_vid(ds, port); + int i, err; + + /* The CPU port is implicitly configured by + * configuring the front-panel ports + */ + if (!dsa_is_user_port(ds, port)) + return 0; + + /* Add this user port's RX VID to the membership list of all others + * (including itself). This is so that bridging will not be hindered. + * L2 forwarding rules still take precedence when there are no VLAN + * restrictions, so there are no concerns about leaking traffic. + */ + for (i = 0; i < ds->num_ports; i++) { + struct dsa_port *other_dp = &ds->ports[i]; + u16 flags; + + if (i == upstream) + /* CPU port needs to see this port's RX VID + * as tagged egress. + */ + flags = 0; + else if (i == port) + /* The RX VID is pvid on this port */ + flags = BRIDGE_VLAN_INFO_UNTAGGED | + BRIDGE_VLAN_INFO_PVID; + else + /* The RX VID is a regular VLAN on all others */ + flags = BRIDGE_VLAN_INFO_UNTAGGED; + + if (enabled) + err = dsa_port_vid_add(other_dp, rx_vid, flags); + else + err = dsa_port_vid_del(other_dp, rx_vid); + if (err) { + dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n", + rx_vid, port, err); + return err; + } + } + /* Finally apply the TX VID on this port and on the CPU port */ + if (enabled) + err = dsa_port_vid_add(dp, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED); + else + err = dsa_port_vid_del(dp, tx_vid); + if (err) { + dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n", + tx_vid, port, err); + return err; + } + if (enabled) + err = dsa_port_vid_add(upstream_dp, tx_vid, 0); + else + err = dsa_port_vid_del(upstream_dp, tx_vid); + if (err) { + dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n", + tx_vid, upstream, err); + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging); + +struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, + u16 tpid, u16 tci) +{ + /* skb->data points at skb_mac_header, which + * is fine for vlan_insert_tag. + */ + return vlan_insert_tag(skb, htons(tpid), tci); +} +EXPORT_SYMBOL_GPL(dsa_8021q_xmit); + +struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev, + struct packet_type *pt, u16 *tpid, u16 *tci) +{ + struct vlan_ethhdr *tag; + + if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) + return NULL; + + tag = vlan_eth_hdr(skb); + *tpid = ntohs(tag->h_vlan_proto); + *tci = ntohs(tag->h_vlan_TCI); + + /* skb->data points in the middle of the VLAN tag, + * after tpid and before tci. This is because so far, + * ETH_HLEN (DMAC, SMAC, EtherType) bytes were pulled. + * There are 2 bytes of VLAN tag left in skb->data, and upper + * layers expect the 'real' EtherType to be consumed as well. + * Coincidentally, a VLAN header is also of the same size as + * the number of bytes that need to be pulled. + */ + skb_pull_rcsum(skb, VLAN_HLEN); + + return skb; +} +EXPORT_SYMBOL_GPL(dsa_8021q_rcv); + +static const struct dsa_device_ops dsa_8021q_netdev_ops = { + .name = "8021q", + .proto = DSA_TAG_PROTO_8021Q, + .overhead = VLAN_HLEN, +}; + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_8021Q); + +module_dsa_tag_driver(dsa_8021q_netdev_ops); From patchwork Sat May 4 13:59:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095242 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="vYORLASC"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cL6r72z9s4Y for ; Sun, 5 May 2019 00:00:02 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727220AbfEDOAB (ORCPT ); Sat, 4 May 2019 10:00:01 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:39391 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726862AbfEDN7v (ORCPT ); Sat, 4 May 2019 09:59:51 -0400 Received: by mail-wr1-f65.google.com with SMTP id a9so11336975wrp.6 for ; Sat, 04 May 2019 06:59:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mZBzIvvNgMRVpYhhnkdzLEwHFoExuGomuvWKglGuCvU=; b=vYORLASCmDhy5L4/6+Brt9qwGh5fJq2+/PbkpXwr1Eg6Msgv8XdujF2/jc3SMH1bgW XOa9fTxYhhuVPqtBlX1IPOiKrraY0kJqT8GVtSGpix39BvUJ/RIQoO0E8Sfax8QQHtF1 4JTI2bMOG/CfJNFU9rkmIjsRgZnJzjcXu0HJOpgBWU9y0UFCefdrEth5SIYLav6fE59n bcR6nkaWm7KBA1Ly4P/Ed2e41o8AEV0aCMcsUHIZAvpAT3LX10J+TFAG7ICDD1+MPGVD 50Lvhsbbba2Oxe3Xs0XktXd2scttnBcGenGN7K0ShmjtC6Hc5WPsWx59HjNrqz4AQxCe EOBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mZBzIvvNgMRVpYhhnkdzLEwHFoExuGomuvWKglGuCvU=; b=ei2c0YyozLqirrn5u6MRXVeM9zPRTysEfQo8IgtrzW8Fc1RhTjqDvSFSqOZpTF2I35 DzHrYRelHKCpZCE3WKQrgbmuLPL3NfYqpKjRs/aNsT2EJLBwMMPi3LUvkla4l+9kk6dT smo3lQviDzi74BBVUFET7kxEUnFfQHgiqTku4BFkIegHlF8sIMegpIkFpdtKfRygJtju D411prBDb+RyHUBUQTHXAUBRGTRLtCvAZ0hlTHw6c5SXvob+bqRGx/44Z6fQ1jShvlu7 IVmt+BCp16CsuB7b5+MsPNUqIuUZ9DfLg0kj2TPuYn8T3UruGMwEUocHFIgxAp9JeXqt MfJQ== X-Gm-Message-State: APjAAAVwxQBMi3dNHH8eXTdz8sCzLmQ1fkESKjAS/6jKtI7v+odmrQv5 DCSjxT3mgytCiO7tOKMCmKg= X-Google-Smtp-Source: APXvYqyXfARV23Wpm13S6eVYt50tQAeXbB+0swO6kut1Au0vfw6IV5IYQ5lA+yqSEVSD7iWzEyHgAg== X-Received: by 2002:adf:ba93:: with SMTP id p19mr11701868wrg.195.1556978387891; Sat, 04 May 2019 06:59:47 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:47 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 3/9] net: dsa: Allow drivers to filter packets they can decode source port from Date: Sat, 4 May 2019 16:59:13 +0300 Message-Id: <20190504135919.23185-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Frames get processed by DSA and redirected to switch port net devices based on the ETH_P_XDSA multiplexed packet_type handler found by the network stack when calling eth_type_trans(). The running assumption is that once the DSA .rcv function is called, DSA is always able to decode the switch tag in order to change the skb->dev from its master. However there are tagging protocols (such as the new DSA_TAG_PROTO_SJA1105, user of DSA_TAG_PROTO_8021Q) where this assumption is not completely true, since switch tagging piggybacks on the absence of a vlan_filtering bridge. Moreover, management traffic (BPDU, PTP) for this switch doesn't rely on switch tagging, but on a different mechanism. So it would make sense to at least be able to terminate that. Having DSA receive traffic it can't decode would put it in an impossible situation: the eth_type_trans() function would invoke the DSA .rcv(), which could not change skb->dev, then eth_type_trans() would be invoked again, which again would call the DSA .rcv, and the packet would never be able to exit the DSA filter and would spiral in a loop until the whole system dies. This happens because eth_type_trans() doesn't actually look at the skb (so as to identify a potential tag) when it deems it as being ETH_P_XDSA. It just checks whether skb->dev has a DSA private pointer installed (therefore it's a DSA master) and that there exists a .rcv callback (everybody except DSA_TAG_PROTO_NONE has that). This is understandable as there are many switch tags out there, and exhaustively checking for all of them is far from ideal. The solution lies in introducing a filtering function for each tagging protocol. In the absence of a filtering function, all traffic is passed to the .rcv DSA callback. The tagging protocol should see the filtering function as a pre-validation that it can decode the incoming skb. The traffic that doesn't match the filter will bypass the DSA .rcv callback and be left on the master netdevice, which wasn't previously possible. Signed-off-by: Vladimir Oltean --- Changes in v2: - None. include/net/dsa.h | 15 +++++++++++++++ net/dsa/dsa2.c | 1 + net/ethernet/eth.c | 6 +++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 69f3714f42ba..c90ceeec7d1f 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -69,6 +69,11 @@ struct dsa_device_ops { struct packet_type *pt); int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, int *offset); + /* Used to determine which traffic should match the DSA filter in + * eth_type_trans, and which, if any, should bypass it and be processed + * as regular on the master net device. + */ + bool (*filter)(const struct sk_buff *skb, struct net_device *dev); unsigned int overhead; const char *name; enum dsa_tag_protocol proto; @@ -148,6 +153,7 @@ struct dsa_port { struct dsa_switch_tree *dst; struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); + bool (*filter)(const struct sk_buff *skb, struct net_device *dev); enum { DSA_PORT_TYPE_UNUSED = 0, @@ -520,6 +526,15 @@ static inline bool netdev_uses_dsa(struct net_device *dev) return false; } +static inline bool dsa_can_decode(const struct sk_buff *skb, + struct net_device *dev) +{ +#if IS_ENABLED(CONFIG_NET_DSA) + return !dev->dsa_ptr->filter || dev->dsa_ptr->filter(skb, dev); +#endif + return false; +} + struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n); void dsa_unregister_switch(struct dsa_switch *ds); int dsa_register_switch(struct dsa_switch *ds); diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index f1ad80851616..3b5f434cad3f 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -586,6 +586,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master) } dp->type = DSA_PORT_TYPE_CPU; + dp->filter = tag_ops->filter; dp->rcv = tag_ops->rcv; dp->tag_ops = tag_ops; dp->master = master; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 0f9863dc4d44..fddcee38c1da 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -185,8 +185,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) * at all, so we check here whether one of those tagging * variants has been configured on the receiving interface, * and if so, set skb->protocol without looking at the packet. + * The DSA tagging protocol may be able to decode some but not all + * traffic (for example only for management). In that case give it the + * option to filter the packets from which it can decode source port + * information. */ - if (unlikely(netdev_uses_dsa(dev))) + if (unlikely(netdev_uses_dsa(dev)) && dsa_can_decode(skb, dev)) return htons(ETH_P_XDSA); if (likely(eth_proto_is_802_3(eth->h_proto))) From patchwork Sat May 4 13:59:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095238 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="KNeySPD6"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cB0t92z9s4Y for ; Sat, 4 May 2019 23:59:54 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727057AbfEDN7w (ORCPT ); Sat, 4 May 2019 09:59:52 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:33109 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726957AbfEDN7u (ORCPT ); Sat, 4 May 2019 09:59:50 -0400 Received: by mail-wm1-f65.google.com with SMTP id s18so1645132wmh.0 for ; Sat, 04 May 2019 06:59:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=U5eHXmezP4NAsJ4OJ3h0l/KejYRt6wZYqXMwgL5OzQw=; b=KNeySPD6U2P1GFm/Xe/Gg7odNhCB5DIsuJ6I6Ps5839CbobI52z9SQcQuU8W87riGo BaukBKynKTAaRpEzmH2pIUy440kRBBqYr6LjWDQpNUuGZSBe8b/Qc9CDu9jvB6zRh81y eQWTutKk+Vur7xw6ShGx8mpJFkoxR6DfQ1RH9qheVWdf1a4nMS0iX6Ivn9hK1D7a/RHy KZFHFh+h7BOKWH+C875chVP8W1aoHu4TOlrakGlAPbRCEGrPVWnztx0M7g+LG/XFIpzP pFPQ+6k6k9jpwNumS8eufK7c8ELtKMVNxoptD6jWeMwJZeYrGrIFnyO+X8UGwJZT0VyE 2ubw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=U5eHXmezP4NAsJ4OJ3h0l/KejYRt6wZYqXMwgL5OzQw=; b=m2+4yF9/Lsau+Q0pvqxGsp3TciG1yCqtgewc7T4IK9po/murUIf2dYGX6c7o/KYMGW IJqiBwpi8mQ/GpQndxMXV03GnK36OHdG6O3Hl6E8nDu2ZYDxciVNcJPm8S3yEFeu15g1 YdsukC3P8McuxzTZ2s2jNnowkblNn8GOLfZS57LbYFCr6FHN6UGhjOzYSveqpSZWWlpv b4XQay6Gj8cUMDfRGGKgdP5Eb82DD0ZDepSBOBiG2eMITILYB9ym2DVVULDMRndkK9zI iKDxyR7uC8P9U7Q/bi7MRswOW0Oysqw2aOrm1rnCE3WrqkaCIqOycf69OlaOZRop3BKF Zhaw== X-Gm-Message-State: APjAAAWkTG5Dby6QWZJtuKdXfXEo1uZW1a3A4k3VbxkEsR+sXPKV3D1c SV2MaGBfnja0fwCun6TNuDk= X-Google-Smtp-Source: APXvYqwrh7TSs4rxmIKt04LrXqQB7ALrUADwx6ULGAaiBOOvl28OqEmZmVQBMLZkIVkYxUpXZQ4Hag== X-Received: by 2002:a7b:cb81:: with SMTP id m1mr10694270wmi.9.1556978388813; Sat, 04 May 2019 06:59:48 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:48 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 4/9] net: dsa: Keep private info in the skb->cb Date: Sat, 4 May 2019 16:59:14 +0300 Message-Id: <20190504135919.23185-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Map a DSA structure over the 48-byte control block that will hold skb info on transmit and receive. This is only for use within the DSA processing layer (e.g. communicating between DSA core and tagger) and not for passing info around with other layers such as the master net device. Also add a DSA_SKB_CB_PRIV() macro which retrieves a pointer to the space up to 48 bytes that the DSA structure does not use. This space can be used for drivers to add their own private info. One use is for the PTP timestamping code path. When cloning a skb, annotate the original with a pointer to the clone, which the driver can then find easily and place the timestamp to. This avoids the need of a separate queue to hold clones and a way to match an original to a cloned skb. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- Changes in v2: - Added a clarification about intended use in the commit message. include/net/dsa.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index c90ceeec7d1f..8f5fcec30b13 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -83,6 +83,34 @@ struct dsa_device_ops { #define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \ MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE)) +struct dsa_skb_cb { + struct sk_buff *clone; +}; + +struct __dsa_skb_cb { + struct dsa_skb_cb cb; + u8 priv[48 - sizeof(struct dsa_skb_cb)]; +}; + +#define __DSA_SKB_CB(skb) ((struct __dsa_skb_cb *)((skb)->cb)) + +#define DSA_SKB_CB(skb) ((struct dsa_skb_cb *)((skb)->cb)) + +#define DSA_SKB_CB_COPY(nskb, skb) \ + { *__DSA_SKB_CB(nskb) = *__DSA_SKB_CB(skb); } + +#define DSA_SKB_CB_ZERO(skb) \ + { *__DSA_SKB_CB(skb) = (struct __dsa_skb_cb) {0}; } + +#define DSA_SKB_CB_PRIV(skb) \ + ((void *)(skb)->cb + offsetof(struct __dsa_skb_cb, priv)) + +#define DSA_SKB_CB_CLONE(clone, skb) \ + { \ + DSA_SKB_CB_COPY(clone, skb); \ + DSA_SKB_CB(skb)->clone = clone; \ + } + struct dsa_switch_tree { struct list_head list; From patchwork Sat May 4 13:59:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095240 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="s5aGboez"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cD6vWMz9s6w for ; Sat, 4 May 2019 23:59:56 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727166AbfEDN7z (ORCPT ); Sat, 4 May 2019 09:59:55 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:35133 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726230AbfEDN7w (ORCPT ); Sat, 4 May 2019 09:59:52 -0400 Received: by mail-wm1-f68.google.com with SMTP id y197so9837941wmd.0 for ; Sat, 04 May 2019 06:59:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RiEvJ6he1TQrv7QLMZ3/XbJsneBrjxQwTZEdSmc690Y=; b=s5aGboezgS/G7oXXM5ultuNFPHwB4t4JekKYrbdEaALsjzBuuGu3cySLp3w7WKvGUR FJyoKmk+2B1ihuQ1rscNO/YIz7N87Vn//g8gOBdMfEIygzzYRQ+ue1zO3RDaHFNdvCBM tlrcPzxEP8lnMY3sAKle3YPuBUjpEXr/cR6vgU5ZjK0b2NyVLkwPSyCz1tug703t32Cg QkGL3oY4MXrkKOnHcHgeCFp9/qD4TPVgvdxq263DcqHIIB2KYoZi8OpdEwLutwpCBRTS jzviPtCI2EQft6u/xzpAGzplW2NHOgGbqbEKFLE8PRoMbZ4vBu6NkvB3YmFaTRyTUETc s9Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RiEvJ6he1TQrv7QLMZ3/XbJsneBrjxQwTZEdSmc690Y=; b=fvDmO3k+uPm1ku4T5zK4eBBRG+rpG5TOjLWkdaHMKlGJVoXq8+d1C+9qQzz7XwyB+m lJmhUIDDJ9E6aQD2AYjdky8JviZkp2txgmFgHm7YQXwDvqCU0S42OIE/rZvYSGbV7CTN gnF1X4yfHNyNmtHtXFUeGAanqC+O0SWXh46RVTEjibr1VdBRUwzFfw7nw+fPre7tu5XG 72KTx7pgc0NET9JPveEUbNgIVtuURT8tqa4uswB5otCfvvZQvYSD87JceFzLWLwU+fwk nf2RvlB4nDM6IVQe6HqPrEUdl8D94OgnEpR3OJETZa86cT6wdpu/Ln7HqFmazCfHVdwL feeA== X-Gm-Message-State: APjAAAVAkLAyeumJ+5KtIe6Ioe9VlvR4GduWJK2Jzcs56abIbobmMPtB LKfKiVsCXQLHkqe4Ro/VTEw= X-Google-Smtp-Source: APXvYqzOL1eWaroRAOZ1I0H05VIw0gNj93tjhKmrhJI8Z5fdC31ZLDM4wEBWx6K8bXWTQvyMB5ULYQ== X-Received: by 2002:a1c:b605:: with SMTP id g5mr9639203wmf.151.1556978389783; Sat, 04 May 2019 06:59:49 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:49 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 5/9] net: dsa: Add support for deferred xmit Date: Sat, 4 May 2019 16:59:15 +0300 Message-Id: <20190504135919.23185-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Some hardware needs to take work to get convinced to receive frames on the CPU port (such as the sja1105 which takes temporary L2 forwarding rules over SPI that last for a single frame). Such work needs a sleepable context, and because the regular .ndo_start_xmit is atomic, this cannot be done in the tagger. So introduce a generic DSA mechanism that sets up a transmit skb queue and a workqueue for deferred transmission. The new driver callback (.port_deferred_xmit) is in dsa_switch and not in the tagger because the operations that require sleeping typically also involve interacting with the hardware, and not simply skb manipulations. Therefore having it there simplifies the structure a bit and makes it unnecessary to export functions from the driver to the tagger. The driver is responsible of calling dsa_enqueue_skb which transfers it to the master netdevice. This is so that it has a chance of performing some more work afterwards, such as cleanup or TX timestamping. To tell DSA that skb xmit deferral is required, I have thought about changing the return type of the tagger .xmit from struct sk_buff * into a enum dsa_tx_t that could potentially encode a DSA_XMIT_DEFER value. But the trailer tagger is reallocating every skb on xmit and therefore making a valid use of the pointer return value. So instead of reworking the API in complicated ways, right now a boolean property in the newly introduced DSA_SKB_CB is set. Signed-off-by: Vladimir Oltean --- Changes in v2: - Prevented a race condition between the xmit workqueue and the dsa_slave_suspend. include/net/dsa.h | 12 +++++++++ net/dsa/dsa_priv.h | 2 ++ net/dsa/slave.c | 64 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 8f5fcec30b13..936d53139865 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -85,6 +85,7 @@ struct dsa_device_ops { struct dsa_skb_cb { struct sk_buff *clone; + bool deferred_xmit; }; struct __dsa_skb_cb { @@ -202,6 +203,10 @@ struct dsa_port { struct net_device *bridge_dev; struct devlink_port devlink_port; struct phylink *pl; + + struct work_struct xmit_work; + struct sk_buff_head xmit_queue; + /* * Original copy of the master netdev ethtool_ops */ @@ -536,6 +541,12 @@ struct dsa_switch_ops { struct sk_buff *clone, unsigned int type); bool (*port_rxtstamp)(struct dsa_switch *ds, int port, struct sk_buff *skb, unsigned int type); + + /* + * Deferred frame Tx + */ + netdev_tx_t (*port_deferred_xmit)(struct dsa_switch *ds, int port, + struct sk_buff *skb); }; struct dsa_switch_driver { @@ -631,6 +642,7 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev, #define BRCM_TAG_GET_QUEUE(v) ((v) & 0xff) +netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev); int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data); int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data); int dsa_port_get_phy_sset_count(struct dsa_port *dp); diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index b434f5ff55ab..8f1222324646 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -174,6 +174,8 @@ int dsa_slave_resume(struct net_device *slave_dev); int dsa_slave_register_notifier(void); void dsa_slave_unregister_notifier(void); +void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev); + static inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8ad9bf957da1..534dfbc27b1e 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -120,6 +120,9 @@ static int dsa_slave_close(struct net_device *dev) struct net_device *master = dsa_slave_to_master(dev); struct dsa_port *dp = dsa_slave_to_port(dev); + cancel_work_sync(&dp->xmit_work); + skb_queue_purge(&dp->xmit_queue); + phylink_stop(dp->pl); dsa_port_disable(dp); @@ -430,6 +433,24 @@ static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, kfree_skb(clone); } +netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev) +{ + /* SKB for netpoll still need to be mangled with the protocol-specific + * tag to be successfully transmitted + */ + if (unlikely(netpoll_tx_running(dev))) + return dsa_slave_netpoll_send_skb(dev, skb); + + /* Queue the SKB for transmission on the parent interface, but + * do not modify its EtherType + */ + skb->dev = dsa_slave_to_master(dev); + dev_queue_xmit(skb); + + return NETDEV_TX_OK; +} +EXPORT_SYMBOL_GPL(dsa_enqueue_skb); + static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); @@ -452,23 +473,37 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) */ nskb = p->xmit(skb, dev); if (!nskb) { - kfree_skb(skb); + if (!DSA_SKB_CB(skb)->deferred_xmit) + kfree_skb(skb); return NETDEV_TX_OK; } - /* SKB for netpoll still need to be mangled with the protocol-specific - * tag to be successfully transmitted - */ - if (unlikely(netpoll_tx_running(dev))) - return dsa_slave_netpoll_send_skb(dev, nskb); + return dsa_enqueue_skb(nskb, dev); +} - /* Queue the SKB for transmission on the parent interface, but - * do not modify its EtherType - */ - nskb->dev = dsa_slave_to_master(dev); - dev_queue_xmit(nskb); +void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); - return NETDEV_TX_OK; + DSA_SKB_CB(skb)->deferred_xmit = true; + + skb_queue_tail(&dp->xmit_queue, skb); + schedule_work(&dp->xmit_work); + return NULL; +} +EXPORT_SYMBOL_GPL(dsa_defer_xmit); + +static void dsa_port_xmit_work(struct work_struct *work) +{ + struct dsa_port *dp = container_of(work, struct dsa_port, xmit_work); + struct dsa_switch *ds = dp->ds; + struct sk_buff *skb; + + if (unlikely(!ds->ops->port_deferred_xmit)) + return; + + while ((skb = skb_dequeue(&dp->xmit_queue)) != NULL) + ds->ops->port_deferred_xmit(ds, dp->index, skb); } /* ethtool operations *******************************************************/ @@ -1320,6 +1355,9 @@ int dsa_slave_suspend(struct net_device *slave_dev) if (!netif_running(slave_dev)) return 0; + cancel_work_sync(&dp->xmit_work); + skb_queue_purge(&dp->xmit_queue); + netif_device_detach(slave_dev); rtnl_lock(); @@ -1407,6 +1445,8 @@ int dsa_slave_create(struct dsa_port *port) } p->dp = port; INIT_LIST_HEAD(&p->mall_tc_list); + INIT_WORK(&port->xmit_work, dsa_port_xmit_work); + skb_queue_head_init(&port->xmit_queue); p->xmit = cpu_dp->tag_ops->xmit; port->slave = slave_dev; From patchwork Sat May 4 13:59:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095241 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="DJubk3Ew"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cJ2K61z9s4Y for ; Sun, 5 May 2019 00:00:00 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727184AbfEDN75 (ORCPT ); Sat, 4 May 2019 09:59:57 -0400 Received: from mail-wm1-f67.google.com ([209.85.128.67]:51640 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727020AbfEDN7w (ORCPT ); Sat, 4 May 2019 09:59:52 -0400 Received: by mail-wm1-f67.google.com with SMTP id t76so10384909wmt.1 for ; Sat, 04 May 2019 06:59:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=n86PQ7i51t6Ws6rTZUhS9zC+UeigcpROi1AyLP/YXmw=; b=DJubk3EwBE8OKBnsUx2DB2jGKvqddXjRD+MjY6JEEDhBU0kfsTlOK222j5gdvy1602 pHkUN+/SS6ccW4r4jdAx5s50zRkdfex88JXByucXZflPi7EPDdiZg1mr9CAp8IfG/zio aRPpY7gAIS7vwWtECSeO7CGcnpGXvk1brZiw7iS7SmoStRr6GxZoefd1TwfeftmwmE2a 3IzlPa3wMcyIVxlm96B0NVsuZLYzdqDit4RcztgybrIduOt8gmFUOXnOpKeNeaxyfJSY jATbRqjynrnrYn40ZrMmSiaPno4J/2K9d+jO9XC8AHWy3zmrNswYJl8I9IN/4zCouG7F RrKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=n86PQ7i51t6Ws6rTZUhS9zC+UeigcpROi1AyLP/YXmw=; b=KyXzN9M73y0QXrlFlw2+Ss8HZpDIKc46VTimscLQ4nTVRSEtIBNONrlXnNiZLEwDl1 0QM/CeZ2vT0gLh2kLAqrlhE8dTwHbwt5Wt6zFXb+jbkKNCFqQwWrvqyOpqJ5HNzffSNx 62g7+lkCkIJIpuGwiRccZpHCsSEedxx7NnZf4ME+t/uOL53xewk1cRNjHZdUnRsgw7+R no5Y5F5SrWmCuhgQDe6hWzUSCkVXTTfnKjnipJ0nPC+Ma2li7ChMg2IZEUYBAymsdt+s b9X7xcyCsyDnCNP+WEq2RjcIe+B7tS/g6hvsXARUZSi2b8uXY46CqNZOcHBsUiJ9avAZ PapA== X-Gm-Message-State: APjAAAUnB4eow9tHz1Cl4xWnFSDb/SpYmwmQoddP9ZjfS4Fj85UF3Rc+ Oif7tz9OAD0d8yBqPD1+Jpc= X-Google-Smtp-Source: APXvYqydrjEvKRYk2q/WC86NMpm3acifDCcvTAakrfLyZNIXqgeU7gfkubCSkKwg5M0yQHmMN31Tzw== X-Received: by 2002:a05:600c:2206:: with SMTP id z6mr10709538wml.80.1556978390869; Sat, 04 May 2019 06:59:50 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:50 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 6/9] net: dsa: Add a private structure pointer to dsa_port Date: Sat, 4 May 2019 16:59:16 +0300 Message-Id: <20190504135919.23185-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This is supposed to share information between the driver and the tagger, or used by the tagger to keep some state. Its use is optional. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Vivien Didelot --- Changes in v2: - None. include/net/dsa.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 936d53139865..b9e0ef6c5750 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -207,6 +207,12 @@ struct dsa_port { struct work_struct xmit_work; struct sk_buff_head xmit_queue; + /* + * Give the switch driver somewhere to hang its per-port private data + * structures (accessible from the tagger). + */ + void *priv; + /* * Original copy of the master netdev ethtool_ops */ From patchwork Sat May 4 13:59:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095245 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="lb77Ux06"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cT5nSNz9s4Y for ; Sun, 5 May 2019 00:00:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727242AbfEDOAE (ORCPT ); Sat, 4 May 2019 10:00:04 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:35134 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727066AbfEDN7z (ORCPT ); Sat, 4 May 2019 09:59:55 -0400 Received: by mail-wm1-f66.google.com with SMTP id y197so9837993wmd.0 for ; Sat, 04 May 2019 06:59:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BqnaWQAmLqaSijwyCx43v66+pIeQXgxyJZUB8u0BocY=; b=lb77Ux06CrK3Qp9oNOqbyEWnaxArLyhBwMyBoPAYiSn9axH4LUeWEwg7o5ZF+A04oD ooByWLF10V/PzZH/4r3V+ZeGv9DVNcQaEkCPdUAd8nSymNgTeNPD2nsjZyZjxtwLd31c JvD/UGis6b1E9v5g0vDn/JCS5wHcpowVM/+X7fVxkH+HgShN2cjqvYYIKHg8jkmaKA7y MQS0j9T1+s8j0s0d9khRlbwtHIvx/+aVwOtE4qHfgpiXgMjcq1CadmbHcR4dGsc++xz1 cp1BthZ1QX7TCb06iELyyGGhfLjUgzeD4FX3HOCDtnBSRKeZr5uAvHMwSmkCK9Mxs1oi tE1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BqnaWQAmLqaSijwyCx43v66+pIeQXgxyJZUB8u0BocY=; b=Xm+8LRrct7yvjnSlloN2tObMGy0DgTXhN8tzA3kenr30+SO7n+YNMZLDEVNj+17wKt JTGjHSLpgMr73xUBAIj/ttZL7Re5NhGd4lwfkyARqTctMyZfUs0KpKovJeBMvPKlWCFg 5DZpdgIR6CvRE1qVqqoORGHZZtxf1TvYwTMYvFp+Yp4d6MXd1yoiWFaQWZhUH7qv/e26 SNLZa1BEr4ksclJaSV2RziWQ9sdtP21CPK0Y9DeNG0Pp68EH8hsM3PBJYAVl7JoT4yLi V0rk6Yuz7DofNEuaFqBmpGojKbOQHC4GRdhaVG0evPl/09zzWiLMh7pO1DWYB3SMmnWm VDfg== X-Gm-Message-State: APjAAAXljenigoOa7rYYNDJdCMJX+aFFElr9FOGsvpvIBLxfR9qyISo3 5vg5CwTHrDBdZvcS/u5VUXM= X-Google-Smtp-Source: APXvYqyH9/xGEGC+wSPdDp7QULexo0Zg2k2WVioamf1UeqqNIVouwB30K19oN4ryH+5XnSc0OlAX4Q== X-Received: by 2002:a1c:eb03:: with SMTP id j3mr10290580wmh.15.1556978391819; Sat, 04 May 2019 06:59:51 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:51 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 7/9] net: dsa: sja1105: Add support for traffic through standalone ports Date: Sat, 4 May 2019 16:59:17 +0300 Message-Id: <20190504135919.23185-8-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In order to support this, we are creating a make-shift switch tag out of a VLAN trunk configured on the CPU port. Termination of normal traffic on switch ports only works when not under a vlan_filtering bridge. Termination of management (PTP, BPDU) traffic works under all circumstances because it uses a different tagging mechanism (incl_srcpt). We are making use of the generic CONFIG_NET_DSA_TAG_8021Q code and leveraging it from our own CONFIG_NET_DSA_TAG_SJA1105. There are two types of traffic: regular and link-local. The link-local traffic received on the CPU port is trapped from the switch's regular forwarding decisions because it matched one of the two DMAC filters for management traffic. On transmission, the switch requires special massaging for these link-local frames. Due to a weird implementation of the switching IP, by default it drops link-local frames that originate on the CPU port. It needs to be told where to forward them to, through an SPI command ("management route") that is valid for only a single frame. So when we're sending link-local traffic, we are using the dsa_defer_xmit mechanism. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- Changes in v2: - None. drivers/net/dsa/sja1105/Kconfig | 1 + drivers/net/dsa/sja1105/sja1105.h | 6 ++ drivers/net/dsa/sja1105/sja1105_main.c | 138 +++++++++++++++++++++++-- include/linux/dsa/sja1105.h | 35 +++++-- include/net/dsa.h | 2 + net/dsa/Kconfig | 9 ++ net/dsa/Makefile | 1 + net/dsa/tag_sja1105.c | 131 +++++++++++++++++++++++ 8 files changed, 308 insertions(+), 15 deletions(-) create mode 100644 net/dsa/tag_sja1105.c diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig index 038685bb9d57..757751a89819 100644 --- a/drivers/net/dsa/sja1105/Kconfig +++ b/drivers/net/dsa/sja1105/Kconfig @@ -1,6 +1,7 @@ config NET_DSA_SJA1105 tristate "NXP SJA1105 Ethernet switch family support" depends on NET_DSA && SPI + select NET_DSA_TAG_SJA1105 select PACKING select CRC32 help diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index b0a155b57e17..b043bfc408f2 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -7,6 +7,7 @@ #include #include +#include #include "sja1105_static_config.h" #define SJA1105_NUM_PORTS 5 @@ -65,6 +66,11 @@ struct sja1105_private { struct gpio_desc *reset_gpio; struct spi_device *spidev; struct dsa_switch *ds; + struct sja1105_port ports[SJA1105_NUM_PORTS]; + /* Serializes transmission of management frames so that + * the switch doesn't confuse them with one another. + */ + struct mutex mgmt_lock; }; #include "sja1105_dynamic_config.h" diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 74f8ff9e17e0..785bb42cb993 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "sja1105.h" static void sja1105_hw_reset(struct gpio_desc *gpio, unsigned int pulse_len, @@ -406,11 +407,14 @@ static int sja1105_init_general_params(struct sja1105_private *priv) .tpid2 = ETH_P_SJA1105, }; struct sja1105_table *table; - int i; + int i, k = 0; - for (i = 0; i < SJA1105_NUM_PORTS; i++) + for (i = 0; i < SJA1105_NUM_PORTS; i++) { if (dsa_is_dsa_port(priv->ds, i)) default_general_params.casc_port = i; + else if (dsa_is_user_port(priv->ds, i)) + priv->ports[i].mgmt_slot = k++; + } table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; @@ -1146,10 +1150,27 @@ static int sja1105_vlan_apply(struct sja1105_private *priv, int port, u16 vid, return 0; } +static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled) +{ + int rc, i; + + for (i = 0; i < SJA1105_NUM_PORTS; i++) { + rc = dsa_port_setup_8021q_tagging(ds, i, enabled); + if (rc < 0) { + dev_err(ds->dev, "Failed to setup VLAN tagging for port %d: %d\n", + i, rc); + return rc; + } + } + dev_info(ds->dev, "%s switch tagging\n", + enabled ? "Enabled" : "Disabled"); + return 0; +} + static enum dsa_tag_protocol sja1105_get_tag_protocol(struct dsa_switch *ds, int port) { - return DSA_TAG_PROTO_NONE; + return DSA_TAG_PROTO_SJA1105; } /* This callback needs to be present */ @@ -1173,7 +1194,11 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) if (rc) dev_err(ds->dev, "Failed to change VLAN Ethertype\n"); - return rc; + /* Switch port identification based on 802.1Q is only passable + * if we are not under a vlan_filtering bridge. So make sure + * the two configurations are mutually exclusive. + */ + return sja1105_setup_8021q_tagging(ds, !enabled); } static void sja1105_vlan_add(struct dsa_switch *ds, int port, @@ -1276,7 +1301,98 @@ static int sja1105_setup(struct dsa_switch *ds) */ ds->vlan_filtering_is_global = true; - return 0; + /* The DSA/switchdev model brings up switch ports in standalone mode by + * default, and that means vlan_filtering is 0 since they're not under + * a bridge, so it's safe to set up switch tagging at this time. + */ + return sja1105_setup_8021q_tagging(ds, true); +} + +static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot, + struct sk_buff *skb) +{ + struct sja1105_mgmt_entry mgmt_route = {0}; + struct sja1105_private *priv = ds->priv; + struct ethhdr *hdr; + int timeout = 10; + int rc; + + hdr = eth_hdr(skb); + + mgmt_route.macaddr = ether_addr_to_u64(hdr->h_dest); + mgmt_route.destports = BIT(port); + mgmt_route.enfport = 1; + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE, + slot, &mgmt_route, true); + if (rc < 0) { + kfree_skb(skb); + return rc; + } + + /* Transfer skb to the host port. */ + dsa_enqueue_skb(skb, ds->ports[port].slave); + + /* Wait until the switch has processed the frame */ + do { + rc = sja1105_dynamic_config_read(priv, BLK_IDX_MGMT_ROUTE, + slot, &mgmt_route); + if (rc < 0) { + dev_err_ratelimited(priv->ds->dev, + "failed to poll for mgmt route\n"); + continue; + } + + /* UM10944: The ENFPORT flag of the respective entry is + * cleared when a match is found. The host can use this + * flag as an acknowledgment. + */ + cpu_relax(); + } while (mgmt_route.enfport && --timeout); + + if (!timeout) { + /* Clean up the management route so that a follow-up + * frame may not match on it by mistake. + */ + sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE, + slot, &mgmt_route, false); + dev_err_ratelimited(priv->ds->dev, "xmit timed out\n"); + } + + return NETDEV_TX_OK; +} + +/* Deferred work is unfortunately necessary because setting up the management + * route cannot be done from atomit context (SPI transfer takes a sleepable + * lock on the bus) + */ +static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, + struct sk_buff *skb) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_port *sp = &priv->ports[port]; + int slot = sp->mgmt_slot; + + /* The tragic fact about the switch having 4x2 slots for installing + * management routes is that all of them except one are actually + * useless. + * If 2 slots are simultaneously configured for two BPDUs sent to the + * same (multicast) DMAC but on different egress ports, the switch + * would confuse them and redirect first frame it receives on the CPU + * port towards the port configured on the numerically first slot + * (therefore wrong port), then second received frame on second slot + * (also wrong port). + * So for all practical purposes, there needs to be a lock that + * prevents that from happening. The slot used here is utterly useless + * (could have simply been 0 just as fine), but we are doing it + * nonetheless, in case a smarter idea ever comes up in the future. + */ + mutex_lock(&priv->mgmt_lock); + + sja1105_mgmt_xmit(ds, port, slot, skb); + + mutex_unlock(&priv->mgmt_lock); + return NETDEV_TX_OK; } /* The MAXAGE setting belongs to the L2 Forwarding Parameters table, @@ -1324,6 +1440,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_mdb_prepare = sja1105_mdb_prepare, .port_mdb_add = sja1105_mdb_add, .port_mdb_del = sja1105_mdb_del, + .port_deferred_xmit = sja1105_port_deferred_xmit, }; static int sja1105_check_device_id(struct sja1105_private *priv) @@ -1367,7 +1484,7 @@ static int sja1105_probe(struct spi_device *spi) struct device *dev = &spi->dev; struct sja1105_private *priv; struct dsa_switch *ds; - int rc; + int rc, i; if (!dev->of_node) { dev_err(dev, "No DTS bindings for SJA1105 driver\n"); @@ -1418,6 +1535,15 @@ static int sja1105_probe(struct spi_device *spi) ds->priv = priv; priv->ds = ds; + /* Connections between dsa_port and sja1105_port */ + for (i = 0; i < SJA1105_NUM_PORTS; i++) { + struct sja1105_port *sp = &priv->ports[i]; + + ds->ports[i].priv = sp; + sp->dp = &ds->ports[i]; + } + mutex_init(&priv->mgmt_lock); + return dsa_register_switch(priv->ds); } diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h index abf3977e34fd..603a02e5a8cb 100644 --- a/include/linux/dsa/sja1105.h +++ b/include/linux/dsa/sja1105.h @@ -2,22 +2,39 @@ * Copyright (c) 2019, Vladimir Oltean */ -/* Included by drivers/net/dsa/sja1105/sja1105.h */ +/* Included by drivers/net/dsa/sja1105/sja1105.h and net/dsa/tag_sja1105.c */ #ifndef _NET_DSA_SJA1105_H #define _NET_DSA_SJA1105_H +#include #include +#include #define ETH_P_SJA1105 ETH_P_DSA_8021Q -/* The switch can only be convinced to stay in unmanaged mode and not trap any - * link-local traffic by actually telling it to filter frames sent at the - * 00:00:00:00:00:00 destination MAC. - */ -#define SJA1105_LINKLOCAL_FILTER_A 0x000000000000ull -#define SJA1105_LINKLOCAL_FILTER_A_MASK 0xFFFFFFFFFFFFull -#define SJA1105_LINKLOCAL_FILTER_B 0x000000000000ull -#define SJA1105_LINKLOCAL_FILTER_B_MASK 0xFFFFFFFFFFFFull +/* IEEE 802.3 Annex 57A: Slow Protocols PDUs (01:80:C2:xx:xx:xx) */ +#define SJA1105_LINKLOCAL_FILTER_A 0x0180C2000000ull +#define SJA1105_LINKLOCAL_FILTER_A_MASK 0xFFFFFF000000ull +/* IEEE 1588 Annex F: Transport of PTP over Ethernet (01:1B:19:xx:xx:xx) */ +#define SJA1105_LINKLOCAL_FILTER_B 0x011B19000000ull +#define SJA1105_LINKLOCAL_FILTER_B_MASK 0xFFFFFF000000ull + +enum sja1105_frame_type { + SJA1105_FRAME_TYPE_NORMAL = 0, + SJA1105_FRAME_TYPE_LINK_LOCAL, +}; + +struct sja1105_skb_cb { + enum sja1105_frame_type type; +}; + +#define SJA1105_SKB_CB(skb) \ + ((struct sja1105_skb_cb *)DSA_SKB_CB_PRIV(skb)) + +struct sja1105_port { + struct dsa_port *dp; + int mgmt_slot; +}; #endif /* _NET_DSA_SJA1105_H */ diff --git a/include/net/dsa.h b/include/net/dsa.h index b9e0ef6c5750..e3c99b763c00 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -43,6 +43,7 @@ struct phylink_link_state; #define DSA_TAG_PROTO_QCA_VALUE 10 #define DSA_TAG_PROTO_TRAILER_VALUE 11 #define DSA_TAG_PROTO_8021Q_VALUE 12 +#define DSA_TAG_PROTO_SJA1105_VALUE 13 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, @@ -58,6 +59,7 @@ enum dsa_tag_protocol { DSA_TAG_PROTO_QCA = DSA_TAG_PROTO_QCA_VALUE, DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, + DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, }; struct packet_type; diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index fc15a7e1a6df..cf855352a440 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -102,6 +102,15 @@ config NET_DSA_TAG_LAN9303 Say Y or M if you want to enable support for tagging frames for the SMSC/Microchip LAN9303 family of switches. +config NET_DSA_TAG_SJA1105 + tristate "Tag driver for NXP SJA1105 switches" + select NET_DSA_TAG_8021Q + help + Say Y or M if you want to enable support for tagging frames with the + NXP SJA1105 switch family. Both the native tagging protocol (which + is only for link-local traffic) as well as non-native tagging (based + on a custom 802.1Q VLAN header) are available. + config NET_DSA_TAG_TRAILER tristate "Tag driver for switches using a trailer tag" help diff --git a/net/dsa/Makefile b/net/dsa/Makefile index e97c794ec57b..c342f54715ba 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -13,4 +13,5 @@ obj-$(CONFIG_NET_DSA_TAG_KSZ_COMMON) += tag_ksz.o obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o +obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c new file mode 100644 index 000000000000..969402c7dbf1 --- /dev/null +++ b/net/dsa/tag_sja1105.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Vladimir Oltean + */ +#include +#include +#include +#include +#include "dsa_priv.h" + +/* Similar to is_link_local_ether_addr(hdr->h_dest) but also covers PTP */ +static inline bool sja1105_is_link_local(const struct sk_buff *skb) +{ + const struct ethhdr *hdr = eth_hdr(skb); + u64 dmac = ether_addr_to_u64(hdr->h_dest); + + if ((dmac & SJA1105_LINKLOCAL_FILTER_A_MASK) == + SJA1105_LINKLOCAL_FILTER_A) + return true; + if ((dmac & SJA1105_LINKLOCAL_FILTER_B_MASK) == + SJA1105_LINKLOCAL_FILTER_B) + return true; + return false; +} + +/* This is the first time the tagger sees the frame on RX. + * Figure out if we can decode it, and if we can, annotate skb->cb with how we + * plan to do that, so we don't need to check again in the rcv function. + */ +static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev) +{ + if (sja1105_is_link_local(skb)) { + SJA1105_SKB_CB(skb)->type = SJA1105_FRAME_TYPE_LINK_LOCAL; + return true; + } + if (!dsa_port_is_vlan_filtering(dev->dsa_ptr)) { + SJA1105_SKB_CB(skb)->type = SJA1105_FRAME_TYPE_NORMAL; + return true; + } + return false; +} + +static struct sk_buff *sja1105_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_switch *ds = dp->ds; + u16 tx_vid = dsa_8021q_tx_vid(ds, dp->index); + u8 pcp = skb->priority; + + /* Transmitting management traffic does not rely upon switch tagging, + * but instead SPI-installed management routes. Part 2 of this + * is the .port_deferred_xmit driver callback. + */ + if (unlikely(sja1105_is_link_local(skb))) + return dsa_defer_xmit(skb, netdev); + + /* If we are under a vlan_filtering bridge, IP termination on + * switch ports based on 802.1Q tags is simply too brittle to + * be passable. So just defer to the dsa_slave_notag_xmit + * implementation. + */ + if (dsa_port_is_vlan_filtering(dp)) + return skb; + + return dsa_8021q_xmit(skb, netdev, ETH_P_SJA1105, + ((pcp << VLAN_PRIO_SHIFT) | tx_vid)); +} + +static struct sk_buff *sja1105_rcv(struct sk_buff *skb, + struct net_device *netdev, + struct packet_type *pt) +{ + struct ethhdr *hdr = eth_hdr(skb); + u64 source_port, switch_id; + struct sk_buff *nskb; + u16 tpid, vid, tci; + bool is_tagged; + + nskb = dsa_8021q_rcv(skb, netdev, pt, &tpid, &tci); + is_tagged = (nskb && tpid == ETH_P_SJA1105); + + skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + vid = tci & VLAN_VID_MASK; + + skb->offload_fwd_mark = 1; + + if (SJA1105_SKB_CB(skb)->type == SJA1105_FRAME_TYPE_LINK_LOCAL) { + /* Management traffic path. Switch embeds the switch ID and + * port ID into bytes of the destination MAC, courtesy of + * the incl_srcpt options. + */ + source_port = hdr->h_dest[3]; + switch_id = hdr->h_dest[4]; + /* Clear the DMAC bytes that were mangled by the switch */ + hdr->h_dest[3] = 0; + hdr->h_dest[4] = 0; + } else { + /* Normal traffic path. */ + source_port = dsa_8021q_rx_source_port(vid); + switch_id = dsa_8021q_rx_switch_id(vid); + } + + skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); + if (!skb->dev) { + netdev_warn(netdev, "Couldn't decode source port\n"); + return NULL; + } + + /* Delete/overwrite fake VLAN header, DSA expects to not find + * it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN). + */ + if (is_tagged) + memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - VLAN_HLEN, + ETH_HLEN - VLAN_HLEN); + + return skb; +} + +static struct dsa_device_ops sja1105_netdev_ops = { + .name = "sja1105", + .proto = DSA_TAG_PROTO_SJA1105, + .xmit = sja1105_xmit, + .rcv = sja1105_rcv, + .filter = sja1105_filter, + .overhead = VLAN_HLEN, +}; + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SJA1105); + +module_dsa_tag_driver(sja1105_netdev_ops); From patchwork Sat May 4 13:59:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095243 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="l7XS6+uP"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cR4CPZz9s6w for ; Sun, 5 May 2019 00:00:07 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727280AbfEDOAG (ORCPT ); Sat, 4 May 2019 10:00:06 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:38689 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727094AbfEDN7y (ORCPT ); Sat, 4 May 2019 09:59:54 -0400 Received: by mail-wr1-f67.google.com with SMTP id k16so11345772wrn.5 for ; Sat, 04 May 2019 06:59:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=kaahSbLYWK2X/K+kZwgb05NR3m8iRxELeRzOlfLI3Tg=; b=l7XS6+uPvcoDdLRZuNvcwGouYf5/0Gvm56HJowltvymXXY/m/KWYUDSmOjEW3+tuFZ N5RIgfZEC29D6KUZ/TGgUazmqaX45HJgHCGw8l8vaVqmx7wkwZkUewLZ6XdsDTSbqbBI Fabl8hJBU8vpz7sBbVKtmqDCrkDmjmfOzk+DaBk1nZgGeFMSuzNbdOQ0x7mOWMKo9NOx yb3hhjDayXFvTE0zUouaKiuxHoAj1BmML2MyxkcfEg3wQ6CbaSADz7NVKX64w2qiUx6s 6IQDjFdk4ydP/Q8gDIOB8/1Fw75cZEGHiQ7ZPpFRd7+pPtO9nOsKPjBvUmpXs7O9HDn/ CZHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=kaahSbLYWK2X/K+kZwgb05NR3m8iRxELeRzOlfLI3Tg=; b=VvqsOPtxxvpk3RZcFj1OXHyjiEBImnRZ7Yr4TRk60Zw0RW3RMzAgDgvVuifXbBs+Nu +Dxyudxk65R0OqUOFHJmr4rxIjV3Io1pmxqbg2t7Js6GwklHdM3PQKoe2Sjk8skaPzIe X6UxF+2P7T6kQWcNCBy4Iw/2zd7MWpQyzLP/w5TzkAEXdI+feBuWFh7mD2N6YuHDOanJ +VPH450/XK0ebJ6RhKQgM2wIrvPmAgtLSmzKF8q+UWNim5YKpPCceNZcgZ+ZRx82QmzE jkiV6ZNoeoj3W3GINuF5lmHKPpcy/Fha2wpxa68Xj+IMD0TgCCybct4ZZpNi6eERlswi bahw== X-Gm-Message-State: APjAAAXqN5XVBPVFloHB7iIqocUOnwT/8TIOjwPTlsLozWp0fOG3Tt0t YLHY0m5BGYoa75EOsjiCUv4= X-Google-Smtp-Source: APXvYqziT90s+G4OOP8UmSRr4gGlGsY42yE2ZlfLKziGF6s03kcXcTIHyYqAUD/m/zTlScuu51uhdQ== X-Received: by 2002:adf:ee8d:: with SMTP id b13mr7071226wro.219.1556978392792; Sat, 04 May 2019 06:59:52 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:52 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 8/9] net: dsa: sja1105: Add support for Spanning Tree Protocol Date: Sat, 4 May 2019 16:59:18 +0300 Message-Id: <20190504135919.23185-9-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org While not explicitly documented as supported in UM10944, compliance with the STP states can be obtained by manipulating 3 settings at the (per-port) MAC config level: dynamic learning, inhibiting reception of regular traffic, and inhibiting transmission of regular traffic. In all these modes, transmission and reception of special BPDU frames from the stack is still enabled (not inhibited by the MAC-level settings). On ingress, BPDUs are classified by the MAC filter as link-local (01-80-C2-00-00-00) and forwarded to the CPU port. This mechanism works under all conditions (even without the custom 802.1Q tagging) because the switch hardware inserts the source port and switch ID into bytes 4 and 5 of the MAC-filtered frames. Then the DSA .rcv handler needs to put back zeroes into the MAC address after decoding the source port information. On egress, BPDUs are transmitted using management routes from the xmit worker thread. Again this does not require switch tagging, as the switch port is programmed through SPI to hold a temporary (single-fire) route for a frame with the programmed destination MAC (01-80-C2-00-00-00). STP is activated using the following commands and was tested by connecting two front-panel ports together and noticing that switching loops were prevented (one port remains in the blocking state): $ ip link add name br0 type bridge stp_state 1 && ip link set br0 up $ for eth in $(ls /sys/devices/platform/soc/2100000.spi/spi_master/spi0/spi0.1/net/); do ip link set ${eth} master br0 && ip link set ${eth} up; done Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli --- Changes in v2: - None. drivers/net/dsa/sja1105/sja1105_main.c | 108 ++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 785bb42cb993..50ff625c85d6 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -92,8 +92,10 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) .drpuntag = false, /* Don't retag 802.1p (VID 0) traffic with the pvid */ .retag = false, - /* Enable learning and I/O on user ports by default. */ - .dyn_learn = true, + /* Disable learning and I/O on user ports by default - + * STP will enable it. + */ + .dyn_learn = false, .egress = false, .ingress = false, }; @@ -119,8 +121,17 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv) mac = table->entries; - for (i = 0; i < SJA1105_NUM_PORTS; i++) + for (i = 0; i < SJA1105_NUM_PORTS; i++) { mac[i] = default_mac; + if (i == dsa_upstream_port(priv->ds, i)) { + /* STP doesn't get called for CPU port, so we need to + * set the I/O parameters statically. + */ + mac[i].dyn_learn = true; + mac[i].ingress = true; + mac[i].egress = true; + } + } return 0; } @@ -655,12 +666,14 @@ static sja1105_speed_t sja1105_get_speed_cfg(unsigned int speed_mbps) * for a specific port. * * @speed_mbps: If 0, leave the speed unchanged, else adapt MAC to PHY speed. - * @enabled: Manage Rx and Tx settings for this port. Overrides the static - * configuration settings. + * @enabled: Manage Rx and Tx settings for this port. If false, overrides the + * settings from the STP state, but not persistently (does not + * overwrite the static MAC info for this port). */ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, int speed_mbps, bool enabled) { + struct sja1105_mac_config_entry dyn_mac; struct sja1105_xmii_params_entry *mii; struct sja1105_mac_config_entry *mac; struct device *dev = priv->ds->dev; @@ -693,12 +706,13 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * the code common, we'll use the static configuration tables as a * reasonable approximation for both E/T and P/Q/R/S. */ - mac[port].ingress = enabled; - mac[port].egress = enabled; + dyn_mac = mac[port]; + dyn_mac.ingress = enabled && mac[port].ingress; + dyn_mac.egress = enabled && mac[port].egress; /* Write to the dynamic reconfiguration tables */ rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, - port, &mac[port], true); + port, &dyn_mac, true); if (rc < 0) { dev_err(dev, "Failed to write MAC config: %d\n", rc); return rc; @@ -986,6 +1000,50 @@ static int sja1105_bridge_member(struct dsa_switch *ds, int port, port, &l2_fwd[port], true); } +static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, + u8 state) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_mac_config_entry *mac; + + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; + + switch (state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: + /* From UM10944 description of DRPDTAG (why put this there?): + * "Management traffic flows to the port regardless of the state + * of the INGRESS flag". So BPDUs are still be allowed to pass. + * At the moment no difference between DISABLED and BLOCKING. + */ + mac[port].ingress = false; + mac[port].egress = false; + mac[port].dyn_learn = false; + break; + case BR_STATE_LISTENING: + mac[port].ingress = true; + mac[port].egress = false; + mac[port].dyn_learn = false; + break; + case BR_STATE_LEARNING: + mac[port].ingress = true; + mac[port].egress = false; + mac[port].dyn_learn = true; + break; + case BR_STATE_FORWARDING: + mac[port].ingress = true; + mac[port].egress = true; + mac[port].dyn_learn = true; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port, + &mac[port], true); +} + static int sja1105_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) { @@ -998,6 +1056,23 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, sja1105_bridge_member(ds, port, br, false); } +static u8 sja1105_stp_state_get(struct sja1105_private *priv, int port) +{ + struct sja1105_mac_config_entry *mac; + + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; + + if (!mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn) + return BR_STATE_BLOCKING; + if (mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn) + return BR_STATE_LISTENING; + if (mac[port].ingress && !mac[port].egress && mac[port].dyn_learn) + return BR_STATE_LEARNING; + if (mac[port].ingress && mac[port].egress && mac[port].dyn_learn) + return BR_STATE_FORWARDING; + return -EINVAL; +} + /* For situations where we need to change a setting at runtime that is only * available through the static configuration, resetting the switch in order * to upload the new static config is unavoidable. Back up the settings we @@ -1008,16 +1083,27 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) { struct sja1105_mac_config_entry *mac; int speed_mbps[SJA1105_NUM_PORTS]; + u8 stp_state[SJA1105_NUM_PORTS]; int rc, i; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; /* Back up settings changed by sja1105_adjust_port_config and - * and restore their defaults. + * sja1105_bridge_stp_state_set and restore their defaults. */ for (i = 0; i < SJA1105_NUM_PORTS; i++) { speed_mbps[i] = sja1105_speed[mac[i].speed]; mac[i].speed = SJA1105_SPEED_AUTO; + if (i == dsa_upstream_port(priv->ds, i)) { + mac[i].ingress = true; + mac[i].egress = true; + mac[i].dyn_learn = true; + } else { + stp_state[i] = sja1105_stp_state_get(priv, i); + mac[i].ingress = false; + mac[i].egress = false; + mac[i].dyn_learn = false; + } } /* Reset switch and send updated static configuration */ @@ -1036,6 +1122,9 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) for (i = 0; i < SJA1105_NUM_PORTS; i++) { bool enabled = (speed_mbps[i] != 0); + if (i != dsa_upstream_port(priv->ds, i)) + sja1105_bridge_stp_state_set(priv->ds, i, stp_state[i]); + rc = sja1105_adjust_port_config(priv, i, speed_mbps[i], enabled); if (rc < 0) @@ -1433,6 +1522,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_fdb_del = sja1105_fdb_del, .port_bridge_join = sja1105_bridge_join, .port_bridge_leave = sja1105_bridge_leave, + .port_stp_state_set = sja1105_bridge_stp_state_set, .port_vlan_prepare = sja1105_vlan_prepare, .port_vlan_filtering = sja1105_vlan_filtering, .port_vlan_add = sja1105_vlan_add, From patchwork Sat May 4 13:59:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095244 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="oSHPbfl9"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44x9cS32d9z9s9y for ; Sun, 5 May 2019 00:00:08 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727259AbfEDOAF (ORCPT ); Sat, 4 May 2019 10:00:05 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:39396 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727123AbfEDN7z (ORCPT ); Sat, 4 May 2019 09:59:55 -0400 Received: by mail-wr1-f66.google.com with SMTP id a9so11337158wrp.6 for ; Sat, 04 May 2019 06:59:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fcdZSyklgi7K9FSsRh5grySW4jJiRCGA2nvA+DLoxac=; b=oSHPbfl98DmBmbKSi9a1dvQuKJZWIfT9tokPg9BWU2VuFIJhHkplNtcz82JFCT5CE4 7CVkYpOWXdzpbO7NkcgXWginN9FD30CdWnQIhsoTvCcphb85FoSHBse+yKDD/ZsQ4kIl ZjVtqu73KwNmS4a55wkbuppQtXAltxv8vcofwl0rP5QGO+mMRAjiyTdAGbONUeVe95/l RY/B1LXlMkxvxvW5u65om2TIpkOtAyNq8OZlh98PJir5Dqr8yMrMyWsX0XWN4x++USh2 VK+5M7VVFdf6OfFGLUrIr3tY60yy+n6k1e5J820gNO8IbBS6N4lUokELYJIe6I8NHVIX GxMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fcdZSyklgi7K9FSsRh5grySW4jJiRCGA2nvA+DLoxac=; b=GOy8yap+E2wrnxx1gBatOgO2Yoi1QOin5Rz0/hJFFg564lYGEvliBDj5y/43ipWjmN QjOQFzEUDgdJ38AACyiFIed1QYFFSrlfNVK+xxYigyv4wiMswWrZGKdwDB0upi5bIOrO GyUntBBCaPzjn+lbSMNmZxPYN5U20/+dfU438dTscF7I+nIURVUjX7yLeE6ED4H58i7h NA7uEgHfewWaUFpQVyCHwdusSH/EZJ++7DRNEieiKGlBbPtNz6aofeIeGrj4Q4Vp2bl2 Y3VlbklvqoT/vcIa5TekdbTmrlSgGPJ++O78cXjZS+zRXPUYXLAr4bIDCP4r00Z+HhB7 auvA== X-Gm-Message-State: APjAAAWtEVf+qFjsKZBYjUBRUyqNfqwXM9EMKMTm7O0dRG3Q48qAQw24 LX0qnPRAbKDdvJMCCLeL/cw= X-Google-Smtp-Source: APXvYqzSdBO+Ui0VX8Pa/FQhHvSktLjkOR7Bq5Ipf/tHxSBN05DUN+2yQxWBT+zAUcAr/0t84ABPpQ== X-Received: by 2002:adf:dd4a:: with SMTP id u10mr6449232wrm.152.1556978393846; Sat, 04 May 2019 06:59:53 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id s16sm5085940wrg.71.2019.05.04.06.59.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 May 2019 06:59:53 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next v2 9/9] Documentation: net: dsa: sja1105: Add info about supported traffic modes Date: Sat, 4 May 2019 16:59:19 +0300 Message-Id: <20190504135919.23185-10-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504135919.23185-1-olteanv@gmail.com> References: <20190504135919.23185-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Signed-off-by: Vladimir Oltean --- Changes in v2: - Added clarification about bridging other netdevices with swich ports. - Removed "Other notable features" section. Documentation/networking/dsa/sja1105.rst | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index 7c13b40915c0..ea7bac438cfd 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -63,6 +63,38 @@ If that changed setting can be transmitted to the switch through the dynamic reconfiguration interface, it is; otherwise the switch is reset and reprogrammed with the updated static configuration. +Traffic support +=============== + +The switches do not support switch tagging in hardware. But they do support +customizing the TPID by which VLAN traffic is identified as such. The switch +driver is leveraging ``CONFIG_NET_DSA_TAG_8021Q`` by requesting that special +VLANs (with a custom TPID of ``ETH_P_EDSA`` instead of ``ETH_P_8021Q``) are +installed on its ports when not in ``vlan_filtering`` mode. This does not +interfere with the reception and transmission of real 802.1Q-tagged traffic, +because the switch does no longer parse those packets as VLAN after the TPID +change. +The TPID is restored when ``vlan_filtering`` is requested by the user through +the bridge layer, and general IP termination becomes no longer possible through +the switch netdevices in this mode. + +The switches have two programmable filters for link-local destination MACs. +These are used to trap BPDUs and PTP traffic to the master netdevice, and are +further used to support STP and 1588 ordinary clock/boundary clock +functionality. + +The following traffic modes are supported over the switch netdevices: + ++--------------------+------------+------------------+------------------+ +| | Standalone | Bridged with | Bridged with | +| | ports | vlan_filtering 0 | vlan_filtering 1 | ++====================+============+==================+==================+ +| Regular traffic | Yes | Yes | No (use master) | ++--------------------+------------+------------------+------------------+ +| Management traffic | Yes | Yes | Yes | +| (BPDU, PTP) | | | | ++--------------------+------------+------------------+------------------+ + Switching features ================== @@ -92,6 +124,28 @@ that VLAN awareness is global at the switch level is that once a bridge with ``vlan_filtering`` enslaves at least one switch port, the other un-bridged ports are no longer available for standalone traffic termination. +Topology and loop detection through STP is supported. + +L2 FDB manipulation (add/delete/dump) is currently possible for the first +generation devices. Aging time of FDB entries, as well as enabling fully static +management (no address learning and no flooding of unknown traffic) is not yet +configurable in the driver. + +A special comment about bridging with other netdevices (illustrated with an +example): + +A board has eth0, eth1, swp0@eth1, swp1@eth1, swp2@eth1, swp3@eth1. +The switch ports (swp0-3) are under br0. +It is desired that eth0 is turned into another switched port that communicates +with swp0-3. + +If br0 has vlan_filtering 0, then eth0 can simply be added to br0 with the +intended results. +If br0 has vlan_filtering 1, then a new br1 interface needs to be created that +enslaves eth0 and eth1 (the DSA master of the switch ports). This is because in +this mode, the switch ports beneath br0 are not capable of regular traffic, and +are only used as a conduit for switchdev operations. + Device Tree bindings and board design =====================================