From: Vladimir Oltean <olteanv@gmail.com>
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,
georg.waibel@sensor-technik.de,
Vladimir Oltean <olteanv@gmail.com>
Subject: [PATCH v3 net-next 19/24] net: dsa: sja1105: Add support for Spanning Tree Protocol
Date: Sat, 13 Apr 2019 04:28:17 +0300 [thread overview]
Message-ID: <20190413012822.30931-20-olteanv@gmail.com> (raw)
In-Reply-To: <20190413012822.30931-1-olteanv@gmail.com>
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 <olteanv@gmail.com>
---
Changes in v3:
Added verbiage to the commit message.
Changes in v2:
None.
drivers/net/dsa/sja1105/sja1105_main.c | 108 ++++++++++++++++++++++---
1 file changed, 99 insertions(+), 9 deletions(-)
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 018044f358fd..e4abf8fb2013 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -94,8 +94,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,
.mirrcie = 0,
@@ -126,8 +128,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;
}
@@ -642,12 +653,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;
@@ -680,12 +693,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;
@@ -943,6 +957,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)
{
@@ -955,6 +1013,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
@@ -965,16 +1040,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 */
@@ -993,6 +1079,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)
@@ -1367,6 +1456,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,
--
2.17.1
next prev parent reply other threads:[~2019-04-13 1:29 UTC|newest]
Thread overview: 68+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-13 1:27 [PATCH v3 net-next 00/24] NXP SJA1105 DSA driver Vladimir Oltean
2019-04-13 1:27 ` [PATCH v3 net-next 01/24] lib: Add support for generic packing operations Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 02/24] net: dsa: Fix pharse -> phase typo Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 03/24] net: dsa: Store vlan_filtering as a property of dsa_port Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 04/24] net: dsa: mt7530: Use vlan_filtering property from dsa_port Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 05/24] net: dsa: Add more convenient functions for installing port VLANs Vladimir Oltean
2019-04-16 23:49 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 06/24] net: dsa: Call driver's setup callback after setting up its switchdev notifier Vladimir Oltean
2019-04-13 15:05 ` Andrew Lunn
2019-04-13 1:28 ` [PATCH v3 net-next 07/24] net: dsa: Optional VLAN-based port separation for switches without tagging Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 08/24] net: dsa: Be aware of switches where VLAN filtering is a global setting Vladimir Oltean
2019-04-16 23:54 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 09/24] net: dsa: b53: Let DSA handle mismatched VLAN filtering settings Vladimir Oltean
2019-04-16 23:52 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 10/24] net: dsa: Unset vlan_filtering when ports leave the bridge Vladimir Oltean
2019-04-13 15:11 ` Andrew Lunn
2019-04-16 23:59 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 11/24] net: dsa: mt7530: Let DSA handle the unsetting of vlan_filtering Vladimir Oltean
2019-04-13 15:12 ` Andrew Lunn
2019-04-16 23:59 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 12/24] net: dsa: Copy the vlan_filtering setting on the CPU port if it's global Vladimir Oltean
2019-04-13 15:23 ` Andrew Lunn
2019-04-13 15:37 ` Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 13/24] net: dsa: Allow drivers to filter packets they can decode source port from Vladimir Oltean
2019-04-13 15:39 ` Andrew Lunn
2019-04-13 15:48 ` Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 14/24] net: dsa: Introduce driver for NXP SJA1105 5-port L2 switch Vladimir Oltean
2019-04-13 15:42 ` Andrew Lunn
2019-04-13 15:46 ` Vladimir Oltean
2019-04-13 16:44 ` Andrew Lunn
2019-04-13 21:29 ` Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 15/24] net: dsa: sja1105: Add support for FDB and MDB management Vladimir Oltean
2019-04-13 20:58 ` Jiri Pirko
2019-04-13 1:28 ` [PATCH v3 net-next 16/24] net: dsa: sja1105: Add support for VLAN operations Vladimir Oltean
2019-04-13 20:56 ` Jiri Pirko
2019-04-13 21:39 ` Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 17/24] net: dsa: sja1105: Add support for ethtool port counters Vladimir Oltean
2019-04-13 20:53 ` Jiri Pirko
2019-04-13 21:55 ` Vladimir Oltean
2019-04-14 8:34 ` Jiri Pirko
2019-04-13 1:28 ` [PATCH v3 net-next 18/24] net: dsa: sja1105: Add support for traffic through standalone ports Vladimir Oltean
2019-04-13 16:37 ` Andrew Lunn
2019-04-13 21:27 ` Vladimir Oltean
2019-04-13 22:08 ` Vladimir Oltean
2019-04-13 22:26 ` Vladimir Oltean
2019-04-14 16:17 ` Andrew Lunn
2019-04-14 18:53 ` Vladimir Oltean
2019-04-14 19:13 ` Andrew Lunn
2019-04-14 22:30 ` Vladimir Oltean
2019-04-15 3:07 ` Andrew Lunn
2019-04-17 0:09 ` Florian Fainelli
2019-04-14 16:05 ` Andrew Lunn
2019-04-14 18:42 ` Vladimir Oltean
2019-04-14 19:06 ` Andrew Lunn
2019-04-17 0:16 ` Florian Fainelli
2019-04-13 1:28 ` Vladimir Oltean [this message]
2019-04-13 16:41 ` [PATCH v3 net-next 19/24] net: dsa: sja1105: Add support for Spanning Tree Protocol Andrew Lunn
2019-04-13 1:28 ` [PATCH v3 net-next 20/24] net: dsa: sja1105: Error out if RGMII delays are requested in DT Vladimir Oltean
2019-04-13 16:49 ` Andrew Lunn
2019-04-13 20:47 ` Jiri Pirko
2019-04-13 21:31 ` Vladimir Oltean
2019-04-14 8:35 ` Jiri Pirko
2019-04-13 1:28 ` [PATCH v3 net-next 21/24] net: dsa: sja1105: Prevent PHY jabbering during switch reset Vladimir Oltean
2019-04-13 16:54 ` Andrew Lunn
2019-04-13 1:28 ` [PATCH v3 net-next 22/24] net: dsa: sja1105: Reject unsupported link modes for AN Vladimir Oltean
2019-04-13 1:28 ` [PATCH v3 net-next 23/24] Documentation: net: dsa: Add details about NXP SJA1105 driver Vladimir Oltean
2019-04-17 0:20 ` Florian Fainelli
2019-04-13 1:28 ` [PATCH v3 net-next 24/24] dt-bindings: net: dsa: Add documentation for " Vladimir Oltean
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190413012822.30931-20-olteanv@gmail.com \
--to=olteanv@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=f.fainelli@gmail.com \
--cc=georg.waibel@sensor-technik.de \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=vivien.didelot@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®