From patchwork Sat May 4 01:18: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: 1095101 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="cSwF2+Lr"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrl6483pz9s7T for ; Sat, 4 May 2019 11:19:46 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726957AbfEDBSm (ORCPT ); Fri, 3 May 2019 21:18:42 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:33411 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726622AbfEDBSl (ORCPT ); Fri, 3 May 2019 21:18:41 -0400 Received: by mail-wr1-f67.google.com with SMTP id e28so9949444wra.0; Fri, 03 May 2019 18:18:40 -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=tHmbQEBxmUDjUBw4vJF51xJd9xZGVrC7H9l/slmei+4=; b=cSwF2+LrR+XqUOXvwzSjtPv5S1kFJUKtnCMqzIAjPN0znGxe3Vwq4HET5M2MJSSAv8 FqUFK5bGhO1TaOT7r+sTHI7B7NT2ZhnHgKbFgdAovlpRHCVJuCIjo8WhN9PQkWRllqGC kc4tBlx5mRL4pg5xrqKfd1xkH5sm5pGrXlQzKCF6ppNxofUjax6odu0612pOxa+4v1S+ he7roxQN3I3cIQWDy5F2L2HNfDpQ8YQ9JtJhg3WQgd5rrB7550Xf0098qXVrnwVRXb2i cl/gpoFxuA2YxI1Y6qmNBpH1Sdx9Q2OBvCONHa/B5Z/yClfcD9O9lkRf0kTaPx7O8uDB kxZQ== 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=tHmbQEBxmUDjUBw4vJF51xJd9xZGVrC7H9l/slmei+4=; b=gVMw7owJleyT3zvg4VgPLtiqF/w1pKi9OKG+hJ635vXDJ8nt+ZYBpLYsbigz8C75b6 Acs44T9pAV8ot1CLJv/xt5tsl2s5TrLtcCV4LURNiHXeiHRdCzFp4mjJPrt+18dglHUG /8Rd1WANmV40qFkpKYk9Ed+rqH3xg6RDFnd+ToY5jyyzpDx0wHHCqy7KUViLBrCoaCX2 UUb9EDVlc/kMN95hVrwV/aejH0ZZ1+sUz1kUkidFEJX4f7w0/t7KFQL4SqDQE1MO+aJL ydic2w2FDTOaafgjtFkuDuaLPH/16fDwXbb2Etk9KsUR6YFcymJ0BnjCTUUbfxR6AvYD GpGg== X-Gm-Message-State: APjAAAXjvvcHGozdM6WKUpsyog/oYDgzJSa1RMaGDMehGKHrUuuAlcmh sin7eBchEWIj3/BbtIS+10ODRGue7DE= X-Google-Smtp-Source: APXvYqz8nJX5LmH7U2oTaGMYxl5oVTjYXLA/pg+avz3nYvbXWp603XeUsnVcyzY6//hHeoaITxqehw== X-Received: by 2002:adf:f309:: with SMTP id i9mr9010499wro.258.1556932719680; Fri, 03 May 2019 18:18:39 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id t1sm3937639wro.34.2019.05.03.18.18.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18:39 -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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 1/9] net: dsa: Call driver's setup callback after setting up its switchdev notifier Date: Sat, 4 May 2019 04:18:18 +0300 Message-Id: <20190504011826.30477-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- 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 01:18: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: 1095100 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="qOoLbGlo"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrl03kLTz9s5c for ; Sat, 4 May 2019 11:19:40 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727129AbfEDBSo (ORCPT ); Fri, 3 May 2019 21:18:44 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:55965 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726714AbfEDBSn (ORCPT ); Fri, 3 May 2019 21:18:43 -0400 Received: by mail-wm1-f68.google.com with SMTP id y2so8720608wmi.5; Fri, 03 May 2019 18:18:41 -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=sQbUt0SGqYwRVaiqKgn2i3F7QMKYbh9JHG7KYJhy1+M=; b=qOoLbGloqJNQkw9+f8BJhUrZR2VTLm+OItlWqzD45xQwVgdtDMU/6uoHLFvje1aSj1 MnRIjm8ZmE146746oLfWTulU0AzxD0GdyKzYDKxvDFGSDhs+tEK+yjoe7E5KRZ7LONTa aLj7HSWOaPSTDxEMrpZL7/Bzm0n3Fm+NdUPIj7NN/alFamFVYFKLkF4T8FnnWDtRFZ1T pO9RIA6iGsTpHi7LcydaiuJdiDihLohQIqGSuRBKTUqXRY4nSM/vpfBWcOF1iwnCcH9i n+CQ1umzwzF/zvHIjqZKhkUyjUT+3AF9okJ70hkZCQlWDTiiy/ssYM3+jyT7dSXEa1LZ odBQ== 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=sQbUt0SGqYwRVaiqKgn2i3F7QMKYbh9JHG7KYJhy1+M=; b=eHQCB3e2Vt22TC6eYB1K6Z7mPd2fHuMlEdKeSEn3uXV0RQ1m6x8Gi/hgu1KUuEL3k3 /oFD9cuhVIAQinFVf4/cqcIzHjZM4ro1ImI7YWXX2Ik14tu7yqPUla1hgrZa72N+yvHT Tju6emhw9sq9PVFuXmNnhC2eDIBwKTUyM6+93sy4TvVGqblpFq1PgTg/yl7WcG0oGzFM WwZJD4sCpYingRMrbmJGzQkHxYwErzPAuvmOIXHTBYK+A7c+SIoDBFNhNVGhBbBtor8d 82G8fjAzxlKBIc7D75KxI/WkrO2+Z/SkMcoQ5QBAO34b412jb7kqBsAAxTP3Xnzk2fxM LMNA== X-Gm-Message-State: APjAAAUxudjJKcLE5dXfq1196l6bolNT5CVqwRnsiYtbSR0mP4W3sFhY ChYc4xx6HheQiXMZmJlACdQ= X-Google-Smtp-Source: APXvYqxW0V1iM8sBaTdVxr4BLaW1LVMBtf2jjmD2D0wyV2K3Dq/WjkZTEdfqxBNIWChGSIu1enRimA== X-Received: by 2002:a05:600c:224d:: with SMTP id a13mr8034762wmm.25.1556932720738; Fri, 03 May 2019 18:18:40 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id t1sm3937639wro.34.2019.05.03.18.18.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18:40 -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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 2/9] net: dsa: Optional VLAN-based port separation for switches without tagging Date: Sat, 4 May 2019 04:18:19 +0300 Message-Id: <20190504011826.30477-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- 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 01:18:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095099 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="h6nyEu8O"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkx3KVgz9s7T for ; Sat, 4 May 2019 11:19:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727427AbfEDBTc (ORCPT ); Fri, 3 May 2019 21:19:32 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:44714 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726622AbfEDBSo (ORCPT ); Fri, 3 May 2019 21:18:44 -0400 Received: by mail-wr1-f68.google.com with SMTP id c5so9883047wrs.11; Fri, 03 May 2019 18:18:42 -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=r3gWbU66Gb4F+ksq9kAmK2pxg5SekFLFxe9XHbpja70=; b=h6nyEu8Olbvb1Bb0OZjlUr7rl+IwQ1HBFPh8JaEad/RcuwThjcXfqMBYNtuF0qiYE3 ubhQMzv6zVLJYfKWjGnALjx9XsboLvr3NZ5HasWmLV8x+WC8I8P8cxwZZng6sG6S9b6m STduepBM+bWOpMRuBoBrR2ztC0TLd4jixLENnxxXgzoKrdgOn58GmNl1zDdA3c+DDAFz QD1PXaMyHA1DwOnTwYCtlFPwlyQywZ8J66bWQ8DUlapjieem+xCfECr8NIUwSA0Lchoz Fct8iDHz9hbOE5pdzu+NrAx64xqSBDas3tQRS5tsXpo6B5yRlBZ6oLD7tJX5FVuQYl6z dSxQ== 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=r3gWbU66Gb4F+ksq9kAmK2pxg5SekFLFxe9XHbpja70=; b=KOYWSuY5snuqBrWd3L2rNZoGMaArKNbj3RYlytuCsR7LaMshTuFP6xT9t6WtSR66it ++oF2guRUxahfnyUHFW1pYongk4NPKSTFfrkGVXNljFHhnfqg+j4tHOJ7tmwFAkhSttm +tyZNqL8k4qz3lvk1wcTVhlz9cPONsrftO5YuHlzwwAg9la8r6H6PG6z68AqJQhpeBUk +1smU7cUOvPDTuemL5Vwj3IgHWDCTSVctBZBXpYohxj5L6BYj27ukDvqe/odLI+LwLPa jO8EmdgvvsFTGuf6D3Z3A2xDcg8BQPgDRARiW9t80xbQqL1cPPp6pU/qR1mUHPmU6lX+ o/cA== X-Gm-Message-State: APjAAAVQjvo6KK1v2yAQ97R5Ao3m10QpaHIhOaNrktGFZ30w1nFvt8aZ oCFpsSB+gns08hRb8SA4aCI= X-Google-Smtp-Source: APXvYqwkRP8yhXOi9qIm3Jh1JPyOaHjqBhRADffLKh8mHhWraKgwvOIe/EIZTFAgyhL2Yu/uWGcadQ== X-Received: by 2002:a5d:67cb:: with SMTP id n11mr9139408wrw.3.1556932721801; Fri, 03 May 2019 18:18:41 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id t1sm3937639wro.34.2019.05.03.18.18.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18:41 -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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 3/9] net: dsa: Allow drivers to filter packets they can decode source port from Date: Sat, 4 May 2019 04:18:20 +0300 Message-Id: <20190504011826.30477-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 Reviewed-by: Florian Fainelli --- 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 01:18:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095097 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="RoKwLq8g"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkf0ZG2z9s7T for ; Sat, 4 May 2019 11:19:22 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727209AbfEDBSq (ORCPT ); Fri, 3 May 2019 21:18:46 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:51379 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727083AbfEDBSp (ORCPT ); Fri, 3 May 2019 21:18:45 -0400 Received: by mail-wm1-f68.google.com with SMTP id t76so9077150wmt.1; Fri, 03 May 2019 18:18:43 -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=FlBiYAFdqgyAcPlF8/ahth/Wy5yXLY78rXBUogr2yyg=; b=RoKwLq8geN5IWbpPxfEdAcrza/aNwRNlGyrtKhJVPDL3WspfLfRY8PU9qaEFx4Uoo1 idA/D6HsA7GytvhxdHxlKi2qA9nyj3ChCTvn1w1K+NvpQsyvme62A8BlbgDBxMGSIN5j erfchs/zrnFpE+B+7nJQAjopt4VG7TkDUZGw1t/9AOI4bvKLfco6nKlyubGDJ3d76hDc LDlLMpqTbt9kF0GB+aVW65QuLFGKpbXlIxHZMf3zoURXk8bBVxV2F7d1bBe8Cf1KlWtQ 1RB0Yu1TBxa0caUgCR9hH+lH9CGV15VXWlPdSm6JKUMwBTTA/Nqd+pzN0qJoBXIbqK0s yDhA== 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=FlBiYAFdqgyAcPlF8/ahth/Wy5yXLY78rXBUogr2yyg=; b=tBxN3uLO5eUVykliggIGIb4MC87k32j6gtAoOwEs/XJqHVmAZZOKWuW1V0+G5YQ9OT +wh2Pe3yHIUU6ONUJVYmNuKbKl1f26g4oSqNefEpxZW2xfAYKPWIOV0bqpbmuflfGf7R I1/+yG+Hsgs2DV8wXSjtEtk4eEDf174RfRs8jpYcEgBbLMv6SJE62CRQ9zVUUItcW5HX 3XyH6z3GpZDaBfp3dMYYBTlZS/8yAnZxUJKegPyU8R22P+qH9QJ7ScZWPfBMXYN3ozda mnUwCNW5pqNopFHy9p1gLfQRSRcMxyARAq7mSHpmsjLg8B0Hg/v7VBybF8ZpxEzNK6GZ 19QQ== X-Gm-Message-State: APjAAAUZa1KZrjLhRSdztOHQXnlMy/i38R8VwnwbmLF4piJ6c+VXOCtC 0eq9EHfYFWzESvm4vC2jGQw= X-Google-Smtp-Source: APXvYqwEBrQoCJWfHO+mi+HM0KWfsaOAn8df0cCMbIcZ+3ILEg9tBcp4s+YV7GSE2wHSAYUeqq2FqQ== X-Received: by 2002:a7b:c844:: with SMTP id c4mr8184298wml.108.1556932723215; Fri, 03 May 2019 18:18:43 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id t1sm3937639wro.34.2019.05.03.18.18.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18:42 -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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 4/9] net: dsa: Keep private info in the skb->cb Date: Sat, 4 May 2019 04:18:21 +0300 Message-Id: <20190504011826.30477-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 persistent skb info on transmit and receive. 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 --- 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 01:18:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095098 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="bcFrJEoU"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkm1NXkz9s5c for ; Sat, 4 May 2019 11:19:28 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727409AbfEDBTX (ORCPT ); Fri, 3 May 2019 21:19:23 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:53752 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726714AbfEDBSq (ORCPT ); Fri, 3 May 2019 21:18:46 -0400 Received: by mail-wm1-f66.google.com with SMTP id q15so9033396wmf.3; Fri, 03 May 2019 18:18:45 -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=nzBWUxtxpVGUsJl9dQFkvbFimymw5p/mAoy1qHkZo4I=; b=bcFrJEoUVBbonFhLf0suyCZWAZeV8Ao/Yjf/7FIBNvhvXVI5BBdZSFfeiLtEvK1QCw KrouoeiFsdfEynYBdgk8dPKL3TjVyeZ9JvTW8yG90PrWlUIu3Aa+aH3jffWcEQt/Twql LU09550MdN8hkNmVysHhpoK0gedgy42AYg1/KztmIR49vp4dQx2Wke51mWr5RQjQd8kb Xwo1Jk/oKzj+6oWMT4PqOXQfKR9g0/AxJDZ1k7NGPEuL5jAvhrsCo10KFyoIHm5OJX7P jCJyj9fuqxmHFTXRhfHh2jHnx032VEMGfuAeYKkjjk1z0EBPUV+d8mEbiUNMjuxOI82n HgRQ== 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=nzBWUxtxpVGUsJl9dQFkvbFimymw5p/mAoy1qHkZo4I=; b=ClXkN+OaWZI1vbU/3W10gipN3g1FDEybvHsOfYvZKlFRPGmZEe6NvLKK4NWFtZMndp IrMDM3kwt92+Jvl8pAAPahf1ufaTFYHofwBzPj8RV7Up7EUvVOdbp9+bzB+TdCdum/ly 4ez0TRbgsekN1xLtOY01SwovDZDRZU4iTA9EeAW3R7G1acy8c7DMmtqgTOO95KMgZt3G seAZxNPZbQhTuETEwEOizA1fDpg19uh62mctIV4UfWgHfg5tF6jPoWRG3TGl2yiRYoKC gOloJy2Cz/xcoryQ0R9l2p0KWZULjnYND8e1Eyq7Fcy37vCvvXdw0aOD/VKxsQTNRyoa TpHA== X-Gm-Message-State: APjAAAWQJFV2sB+9rI9A+pmS5WU6vquUh3GanDJzsf3S/4vhH0f9WNOp 8r+47ar0iGK1rzuKDJe224YHZqCL8ow= X-Google-Smtp-Source: APXvYqyT38JYCKSu65Hp6ZClQ2j7L80AKnhZo3E0w6Di9uuGhSifbcqt2aIhcqXmZaQkLMdhuB8QAQ== X-Received: by 2002:a05:600c:2208:: with SMTP id z8mr8060782wml.89.1556932724530; Fri, 03 May 2019 18:18:44 -0700 (PDT) Received: from localhost.localdomain (5-12-225-227.residential.rdsnet.ro. [5.12.225.227]) by smtp.gmail.com with ESMTPSA id t1sm3937639wro.34.2019.05.03.18.18.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18:43 -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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 5/9] net: dsa: Add support for deferred xmit Date: Sat, 4 May 2019 04:18:22 +0300 Message-Id: <20190504011826.30477-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 some convincing work in order 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 --- include/net/dsa.h | 12 +++++++++ net/dsa/dsa_priv.h | 2 ++ net/dsa/slave.c | 61 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 63 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..cfb8cba6458c 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 *******************************************************/ @@ -1407,6 +1442,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 01:18:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095096 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="TAHzkIPo"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkZ4z16z9s7T for ; Sat, 4 May 2019 11:19:18 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727276AbfEDBSs (ORCPT ); Fri, 3 May 2019 21:18:48 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:40663 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727173AbfEDBSr (ORCPT ); Fri, 3 May 2019 21:18:47 -0400 Received: by mail-wr1-f66.google.com with SMTP id h4so9907703wre.7; Fri, 03 May 2019 18:18: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=IIUcmLhElCI93DDESapOvTPyO5IBp1J0kUUxpCHpsLo=; b=TAHzkIPowTU1+WIShGaYjfvfNKHN9zgkohUh1z1XDTs2Hu+h5JJ9W1Vy4DY5td/8QR 0Z2skqtz6lDiBbU7/bF9ccEROLptdRQW3Y+BciEnyyriJJMDCy6VpOg62w/Z1YA7rS+9 r0NpickGwHYujg8vrNXA2RBaM/6yhIKFHCyuzytMMAAPaLU6JN4Wa5pfNzwhu19TeXrU GmYlActx+j/3FhTyz6KXMIi06vg/BD9zyfwOEdrK5gFhRViyXm/uEbe/XQ/peW1+uKs4 AnSfem0hAPrDtWk9G6kwQYWjvAuuR9EkaQiv7O0XLPa/H6gsssIdWKZDeTe7fcsilMFe XS1A== 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=IIUcmLhElCI93DDESapOvTPyO5IBp1J0kUUxpCHpsLo=; b=W/P++xG991eWspZGponKnV/0cHVvZT12yiHw0EPQLWe+jWbaAMFBwGKifWJ3d9DVED kStGLNQdWNAWsmTW8dX0LtgssRpanDFa5i2EXk8lQgF/YFFWXd1AfhoFgnJnCR3i/PqZ U+qmpBLBDGVpup6zUIJ4DOMNHiY1HnCTsd4qVWgwCYUFHnIip46Nz3yXbYmRrF88E7u1 5Hr5aotG9aMYz1xqydTfwr3rimM2wcPGl0BmlTahpBVddFUjsiiLz+L4SPFVWq+//ivQ Xqh/RDG59Gq/ifWLnm2RLUN5o1uIxMqDdblvuJK20Itrdz0uPiUEd8l7BgGRFgqFFGgA rYTw== X-Gm-Message-State: APjAAAV2SYOaN0TfKxOCIjavc299+egH+8X6Wyh0omI4eKx4oeU3GI4e 5GiPYRNJdezzH+SUvcyTrDVcvnFgDBc= X-Google-Smtp-Source: APXvYqzUOCUy2aHxl1msfJ6vU+Qy6gE1WfFArAwklpYsZPABh8pQCWjUOxRFpQDhwPJuyvGnQBvaLA== X-Received: by 2002:a05:6000:ca:: with SMTP id q10mr1684102wrx.148.1556932725473; Fri, 03 May 2019 18:18: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 t1sm3937639wro.34.2019.05.03.18.18.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18: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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 6/9] net: dsa: Add a private structure pointer to dsa_port Date: Sat, 4 May 2019 04:18:23 +0300 Message-Id: <20190504011826.30477-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- 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 01:18:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095093 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="aW7FGCaL"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkC24Ppz9sNR for ; Sat, 4 May 2019 11:18:59 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727314AbfEDBSv (ORCPT ); Fri, 3 May 2019 21:18:51 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:53135 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727225AbfEDBSt (ORCPT ); Fri, 3 May 2019 21:18:49 -0400 Received: by mail-wm1-f65.google.com with SMTP id v189so164709wmf.2; Fri, 03 May 2019 18:18:47 -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=jDlOyzYxb2X15fTRrIvVQ2s330TI1tJ2f24otz2Y9D0=; b=aW7FGCaLiuUg15MzJokbfa8/tDVY5om+uMc27vD2V0XVQLEQrc/pVTRCeO5TtHLfqu 09xA5hBtY+WO8RjE9QbQLJRw6/AXvKo3vTD+PpMje/ZTiG5TGKyaGrqbAq3MKZ/mATFV gckd+geBXlN7InDWVNkTu2cmUUOutKDjMEKxfN6P6+4Ta2wT/IXIo9p2kR/ts/2vyTpH RBRBP60AoOGqVYQvEygixqI82S2lMwPUf5Ru++6Sr72QJG37/duFDTXxjOgGc8TlTRll VCjDVHnmxaLgD8RmeVRqnq/ivL6Ev6uVK8pf7taQajMCXQu4X3HM0F0PU+APauDf7tFb wTaA== 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=jDlOyzYxb2X15fTRrIvVQ2s330TI1tJ2f24otz2Y9D0=; b=pR+v96e0IIMv8jHU6bHxtZ5IMuY5kjGPiMm6w7ddRcEym+DuKMuwDneXREoD+ppEWK Loqn6zW7pH3NY+wzD8aAikqiuvkDmqZclpGI3zWzxXZLOE82nfTtdzb+HktfYUFlit3K aaBMQGtZfmauKYNj3zL6UF4BABacJ+OhWYGWMTPkJ14yR3b+cge1pFE77e093cqN094h DHJ5lUi8opXtdzqf/MDVXhtESXgwTe84p0AC3jRtYl5s+LwcikP90iPy2WueOqptjqb7 5RZJ+90GkvGWaFsQYs0ILqlquOzTxycA87zq8YC0YRUdhH4ZkZnKm/Meba9AFrZtqT2Y iJHA== X-Gm-Message-State: APjAAAX49EXGstUUrqINqW5f/EiP8kxU247FEhZJ2yyDiWfP5UqrFrZ1 6juIERrzGbV6cBuiuR5f7HQ= X-Google-Smtp-Source: APXvYqx/4S1t2dJUFXMZZoliHAjKDF/UOUquYcDJe6170OObSNIJwvVqDAIupxOW1QvOAQ8TwLQykQ== X-Received: by 2002:a1c:f311:: with SMTP id q17mr8504961wmq.144.1556932726465; Fri, 03 May 2019 18:18: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 t1sm3937639wro.34.2019.05.03.18.18.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18: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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 7/9] net: dsa: sja1105: Add support for traffic through standalone ports Date: Sat, 4 May 2019 04:18:24 +0300 Message-Id: <20190504011826.30477-8-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- 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 01:18:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095095 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="puSOgNxf"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkW0sbdz9s7T for ; Sat, 4 May 2019 11:19:15 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727384AbfEDBTK (ORCPT ); Fri, 3 May 2019 21:19:10 -0400 Received: from mail-wr1-f66.google.com ([209.85.221.66]:35536 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727244AbfEDBSu (ORCPT ); Fri, 3 May 2019 21:18:50 -0400 Received: by mail-wr1-f66.google.com with SMTP id h15so4214200wrb.2; Fri, 03 May 2019 18:18: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=u8pB9pyoxRn1MnVVmPZp2ReBr/rRxljvZbKQ55zY18M=; b=puSOgNxfxKKuMeEsG5MDg4++K+r2Y/aFrzVdHPxyA+UJtH+hMtbrtq4sK50pR12G/d QvYLiEgzRpM2L2KLMvDlxs2GNhieeqVPGljM7BTV5F147XOpE3j9Vqv6vJ8aNKQ0LXIx aGzZRuwuKrAZN7vUAPbLh8uPBaH47iMtEXuwB0tws5JkHFOdJUDBOJ6IGzkfRgblKSzc 09YLegJljHf5Hw4dp/KJAtKa5u4fKEi7cXNZ0OjCpFIfjEMC95O5y5DIVWUV6D3JONyM m/qSNcjJvnTYcRMgVUgIKo8QxIXIsd8AxMncFwowxdwXvEEemaiULgfooY5/pA3yrzGp 0Hzw== 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=u8pB9pyoxRn1MnVVmPZp2ReBr/rRxljvZbKQ55zY18M=; b=mnFTBD1XXdC6jR/8q0uedUlHjChNCWidXGud1zKERvnj35gWgYCC1yHVZ2jMtwQwOg 7ekkL/gKOnIjqe2vxYGUMD+7Q1SVbFTVkpOIe8vCFXySb96jCD/Cg9pPovHYHAaC5JOR Fiv+MWlPbkgA0SYl//WWmiZAzqioC4G5HQaJgI9i1Amv9LQ9b260pMvP+KZwruqjem6C 5ihlA5imi6LzsjmvDe6ZeEaJocRYkqHv/i08t+7uuyJd+tqgQ+uI020dTaV7qOjMJzKf 90vkLENWO9WhN7jHvjijTU6k8LxFmCrpGfByZL9IWtVhaGkwxJspUyFBGrU583pIJwaU lJ3g== X-Gm-Message-State: APjAAAUgQiePl5hOByoj4fvEa/FYBRKXOlAZG6FTxBKUnr10tgGgbvMD zLI4xZL6g1Z5VfgI1h9tLHQ= X-Google-Smtp-Source: APXvYqzCAHakxHgO/sz8j/bNwJFtGhGj0RwBJEtIlHqwtI/NXYph8HunYTw34RkoyIGfOpinc4Oq1w== X-Received: by 2002:adf:dc08:: with SMTP id t8mr8740602wri.220.1556932727468; Fri, 03 May 2019 18:18: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 t1sm3937639wro.34.2019.05.03.18.18.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18: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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 8/9] net: dsa: sja1105: Add support for Spanning Tree Protocol Date: Sat, 4 May 2019 04:18:25 +0300 Message-Id: <20190504011826.30477-9-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- 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 01:18:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1095094 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="ThXkQdds"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44wrkM2twBz9s5c for ; Sat, 4 May 2019 11:19:07 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727353AbfEDBTC (ORCPT ); Fri, 3 May 2019 21:19:02 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:43063 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727279AbfEDBSu (ORCPT ); Fri, 3 May 2019 21:18:50 -0400 Received: by mail-wr1-f67.google.com with SMTP id q10so1202832wrj.10; Fri, 03 May 2019 18:18: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=GMxx0hfNg0S6TyYo+/TlCXzUzs2MTlBPjkoBkX7WuR4=; b=ThXkQdds0bXV/6iNdU9sDDldrsniUrWXyrr5niTtye0xU22q6V/0VxKudOQJh1wIyI rDtXjfgFLeIIGvlgjoPUrZtH3GNN2lqjLWuF0l8QQRdktK0Wd5cZo1pewyuJCMeuk68S Ezf8PxdCFC9g78a1Xo9p4XZCcX5igkqsoi+ld5VEAMtyGt5MwUQcvBnYy9WPMDNNDkvm /Xed7J6Q5cCrexRAcTYmW/cPzUiZOps770YC2Uah0WjPjYfM1qQ6qziz1nQmo/+5UzrV rfCoHjPhpV9Dh7gDKwvBgUctMxSZ6XogIjFop8LtuzHcR4fnVO7ulgDaqQHnrv4Ir25E M5ng== 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=GMxx0hfNg0S6TyYo+/TlCXzUzs2MTlBPjkoBkX7WuR4=; b=qh5jPTQ3INlCe8VibX3JcMy0Fmns+3bvEsB6nIV+msDSNZL6s/vJyLp0heS3sLcNB6 LsuV0wlsLzmcKzgJRG4OMLQnPQIozDCru85JLXX5xSVskV4muu0nW64RZomdoLzGQM2H wpnmWCxNdWdrdr/iKldYFrtip1ZxYKaOVCqb4bQPnPGjUNY3tSPNn7XX9uGss8J4iSEg 6o4Ad11WB5fSTJVNM5lEW4s5WY83SZcaW7MxjgkXfGRoj0pK8ZpOAQBFJrSjnMo0JuUw ylNPtgkMDLn0GGtbSycWvFTXI2+GfKa5/vbSmmTISWgRueGrnQSHvdUTiQHYl3YMCDze JmXg== X-Gm-Message-State: APjAAAW24QFzftgEKuVbRuVPt7neYdtcPOECFNuP8paowbRpsPy2BuhO FfJXbWkv1gvEpB9ou0bnRV8= X-Google-Smtp-Source: APXvYqxYVrjTJI6PgE5QIuCBsBKS8TK3l7sDnzcY0OsQIxwXzxX+gMarSylz7ciXcVQfRQFRABerwg== X-Received: by 2002:adf:f2c9:: with SMTP id d9mr9461622wrp.36.1556932728532; Fri, 03 May 2019 18:18: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 t1sm3937639wro.34.2019.05.03.18.18.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 03 May 2019 18:18: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, linux-kernel@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 9/9] Documentation: net: dsa: sja1105: Add info about supported traffic modes Date: Sat, 4 May 2019 04:18:26 +0300 Message-Id: <20190504011826.30477-10-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190504011826.30477-1-olteanv@gmail.com> References: <20190504011826.30477-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 --- Documentation/networking/dsa/sja1105.rst | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index 7c13b40915c0..a70a04164d07 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,23 @@ 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. + +Other notable features +====================== + +The switches have a PTP Hardware Clock that can be steered through SPI and used +for timestamping management traffic on ingress and egress. +Also, the T, Q and S devices support TTEthernet (an implementation of SAE +AS6802 from TTTech), which is a set of Ethernet QoS enhancements somewhat +similar in behavior to IEEE TSN (time-aware shaping, time-based policing). +Configuring these features is currently not supported in the driver. + Device Tree bindings and board design =====================================