[PATCH] net: dsa: microchip: fix bridging with more than two member ports

Svenning Sørensen posted 1 patch 4 years, 4 months ago
drivers/net/dsa/microchip/ksz_common.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
[PATCH] net: dsa: microchip: fix bridging with more than two member ports
Posted by Svenning Sørensen 4 years, 4 months ago
Commit b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
plugged a packet leak between ports that were members of different bridges.
Unfortunately, this broke another use case, namely that of more than two
ports that are members of the same bridge.

After that commit, when a port is added to a bridge, hardware bridging
between other member ports of that bridge will be cleared, preventing
packet exchange between them.

Fix by ensuring that the Port VLAN Membership bitmap includes any existing
ports in the bridge, not just the port being added.

Fixes: b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
Signed-off-by: Svenning Sørensen <sss@secomea.com>
---
 drivers/net/dsa/microchip/ksz_common.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 55dbda04ea62..243f8ad6d06e 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -26,7 +26,7 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
 	struct dsa_switch *ds = dev->ds;
 	u8 port_member = 0, cpu_port;
 	const struct dsa_port *dp;
-	int i;
+	int i, j;
 
 	if (!dsa_is_user_port(ds, port))
 		return;
@@ -45,13 +45,33 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
 			continue;
 		if (!dsa_port_bridge_same(dp, other_dp))
 			continue;
+		if (other_p->stp_state != BR_STATE_FORWARDING)
+			continue;
 
-		if (other_p->stp_state == BR_STATE_FORWARDING &&
-		    p->stp_state == BR_STATE_FORWARDING) {
+		if (p->stp_state == BR_STATE_FORWARDING) {
 			val |= BIT(port);
 			port_member |= BIT(i);
 		}
 
+		/* Retain port [i]'s relationship to other ports than [port] */
+		for (j = 0; j < ds->num_ports; j++) {
+			const struct dsa_port *third_dp;
+			struct ksz_port *third_p;
+
+			if (j == i)
+				continue;
+			if (j == port)
+				continue;
+			if (!dsa_is_user_port(ds, j))
+				continue;
+			third_p = &dev->ports[j];
+			if (third_p->stp_state != BR_STATE_FORWARDING)
+				continue;
+			third_dp = dsa_to_port(ds, j);
+			if (dsa_port_bridge_same(other_dp, third_dp))
+				val |= BIT(j);
+		}
+
 		dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
 	}
 
-- 
2.20.1

Re: [PATCH] net: dsa: microchip: fix bridging with more than two member ports
Posted by Oleksij Rempel 4 years, 4 months ago
On Fri, Feb 18, 2022 at 11:27:01AM +0000, Svenning Sørensen wrote:
> Commit b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
> plugged a packet leak between ports that were members of different bridges.
> Unfortunately, this broke another use case, namely that of more than two
> ports that are members of the same bridge.
> 
> After that commit, when a port is added to a bridge, hardware bridging
> between other member ports of that bridge will be cleared, preventing
> packet exchange between them.
> 
> Fix by ensuring that the Port VLAN Membership bitmap includes any existing
> ports in the bridge, not just the port being added.
> 
> Fixes: b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
> Signed-off-by: Svenning Sørensen <sss@secomea.com>

Thank you for your patch. You are right. I'm able to reproduce this issue on
ksz9477.

Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>

> ---
>  drivers/net/dsa/microchip/ksz_common.c | 26 +++++++++++++++++++++++---
>  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
> index 55dbda04ea62..243f8ad6d06e 100644
> --- a/drivers/net/dsa/microchip/ksz_common.c
> +++ b/drivers/net/dsa/microchip/ksz_common.c
> @@ -26,7 +26,7 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
>  	struct dsa_switch *ds = dev->ds;
>  	u8 port_member = 0, cpu_port;
>  	const struct dsa_port *dp;
> -	int i;
> +	int i, j;
>  
>  	if (!dsa_is_user_port(ds, port))
>  		return;
> @@ -45,13 +45,33 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
>  			continue;
>  		if (!dsa_port_bridge_same(dp, other_dp))
>  			continue;
> +		if (other_p->stp_state != BR_STATE_FORWARDING)
> +			continue;
>  
> -		if (other_p->stp_state == BR_STATE_FORWARDING &&
> -		    p->stp_state == BR_STATE_FORWARDING) {
> +		if (p->stp_state == BR_STATE_FORWARDING) {
>  			val |= BIT(port);
>  			port_member |= BIT(i);
>  		}
>  
> +		/* Retain port [i]'s relationship to other ports than [port] */
> +		for (j = 0; j < ds->num_ports; j++) {
> +			const struct dsa_port *third_dp;
> +			struct ksz_port *third_p;
> +
> +			if (j == i)
> +				continue;
> +			if (j == port)
> +				continue;
> +			if (!dsa_is_user_port(ds, j))
> +				continue;
> +			third_p = &dev->ports[j];
> +			if (third_p->stp_state != BR_STATE_FORWARDING)
> +				continue;
> +			third_dp = dsa_to_port(ds, j);
> +			if (dsa_port_bridge_same(other_dp, third_dp))
> +				val |= BIT(j);
> +		}
> +
>  		dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
>  	}
>  
> -- 
> 2.20.1
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
Re: [PATCH] net: dsa: microchip: fix bridging with more than two member ports
Posted by patchwork-bot+netdevbpf@kernel.org 4 years, 4 months ago
Hello:

This patch was applied to netdev/net.git (master)
by David S. Miller <davem@davemloft.net>:

On Fri, 18 Feb 2022 11:27:01 +0000 you wrote:
> Commit b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
> plugged a packet leak between ports that were members of different bridges.
> Unfortunately, this broke another use case, namely that of more than two
> ports that are members of the same bridge.
> 
> After that commit, when a port is added to a bridge, hardware bridging
> between other member ports of that bridge will be cleared, preventing
> packet exchange between them.
> 
> [...]

Here is the summary with links:
  - net: dsa: microchip: fix bridging with more than two member ports
    https://git.kernel.org/netdev/net/c/3d00827a90db

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html