aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorDENG Qingfang <dengqf6@mail2.sysu.edu.cn>2020-04-25 20:08:00 +0800
committerFelix Fietkau <nbd@nbd.name>2020-06-04 22:21:42 +0200
commit7c47f6601d6da216b811a00fd6dcc5e1a96c2e09 (patch)
tree9081928a27006fb2e9e71b6691b9b7d5d96b3161 /target
parentdc4ffaa5ab6830ba9c5b9d9569db2c2aef26755a (diff)
downloadupstream-7c47f6601d6da216b811a00fd6dcc5e1a96c2e09.tar.gz
upstream-7c47f6601d6da216b811a00fd6dcc5e1a96c2e09.tar.bz2
upstream-7c47f6601d6da216b811a00fd6dcc5e1a96c2e09.zip
generic: mt7530: fix roaming from DSA user ports
When a client moves from a DSA user port to a software port in a bridge, it cannot reach any other clients that connected to the DSA user ports. That is because SA learning on the CPU port is disabled, so the switch ignores the client's frames from the CPU port and still thinks it is at the user port. Fix it by enabling SA learning on the CPU port. To prevent the switch from learning from flooding frames from the CPU port, set skb->offload_fwd_mark to 1 for unicast and broadcast frames, and let the switch flood them instead of trapping to the CPU port. Multicast frames still need to be trapped to the CPU port for snooping, so set the SA_DIS bit of the MTK tag to 1 when transmitting those frames to disable SA learning. Signed-off-by: DENG Qingfang <dengqf6@mail2.sysu.edu.cn>
Diffstat (limited to 'target')
-rw-r--r--target/linux/generic/backport-5.4/754-v5.7-net-dsa-mt7530-fix-roaming-from-DSA-user-ports.patch116
1 files changed, 116 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/754-v5.7-net-dsa-mt7530-fix-roaming-from-DSA-user-ports.patch b/target/linux/generic/backport-5.4/754-v5.7-net-dsa-mt7530-fix-roaming-from-DSA-user-ports.patch
new file mode 100644
index 0000000000..1dcc9e44f7
--- /dev/null
+++ b/target/linux/generic/backport-5.4/754-v5.7-net-dsa-mt7530-fix-roaming-from-DSA-user-ports.patch
@@ -0,0 +1,116 @@
+From 5e5502e012b8129e11be616acb0f9c34bc8f8adb Mon Sep 17 00:00:00 2001
+From: DENG Qingfang <dqfext@gmail.com>
+Date: Wed, 13 May 2020 23:10:16 +0800
+Subject: net: dsa: mt7530: fix roaming from DSA user ports
+
+When a client moves from a DSA user port to a software port in a bridge,
+it cannot reach any other clients that connected to the DSA user ports.
+That is because SA learning on the CPU port is disabled, so the switch
+ignores the client's frames from the CPU port and still thinks it is at
+the user port.
+
+Fix it by enabling SA learning on the CPU port.
+
+To prevent the switch from learning from flooding frames from the CPU
+port, set skb->offload_fwd_mark to 1 for unicast and broadcast frames,
+and let the switch flood them instead of trapping to the CPU port.
+Multicast frames still need to be trapped to the CPU port for snooping,
+so set the SA_DIS bit of the MTK tag to 1 when transmitting those frames
+to disable SA learning.
+
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 9 ++-------
+ drivers/net/dsa/mt7530.h | 1 +
+ net/dsa/tag_mtk.c | 15 +++++++++++++++
+ 3 files changed, 18 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -639,11 +639,8 @@ mt7530_cpu_port_enable(struct mt7530_pri
+ mt7530_write(priv, MT7530_PVC_P(port),
+ PORT_SPEC_TAG);
+
+- /* Disable auto learning on the cpu port */
+- mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
+-
+- /* Unknown unicast frame fordwarding to the cpu port */
+- mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
++ /* Unknown multicast frame forwarding to the cpu port */
++ mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port)));
+
+ /* Set CPU port number */
+ if (priv->id == ID_MT7621)
+@@ -1298,8 +1295,6 @@ mt7530_setup(struct dsa_switch *ds)
+ /* Enable and reset MIB counters */
+ mt7530_mib_reset(ds);
+
+- mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
+-
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
+ /* Disable forwarding by default on all ports */
+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -31,6 +31,7 @@ enum {
+ #define MT7530_MFC 0x10
+ #define BC_FFP(x) (((x) & 0xff) << 24)
+ #define UNM_FFP(x) (((x) & 0xff) << 16)
++#define UNM_FFP_MASK UNM_FFP(~0)
+ #define UNU_FFP(x) (((x) & 0xff) << 8)
+ #define UNU_FFP_MASK UNU_FFP(~0)
+ #define CPU_EN BIT(7)
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -15,6 +15,7 @@
+ #define MTK_HDR_XMIT_TAGGED_TPID_8100 1
+ #define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
+ #define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0)
++#define MTK_HDR_XMIT_SA_DIS BIT(6)
+
+ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+@@ -22,6 +23,9 @@ static struct sk_buff *mtk_tag_xmit(stru
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+ u8 *mtk_tag;
+ bool is_vlan_skb = true;
++ unsigned char *dest = eth_hdr(skb)->h_dest;
++ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
++ !is_broadcast_ether_addr(dest);
+
+ /* Build the special tag after the MAC Source Address. If VLAN header
+ * is present, it's required that VLAN header and special tag is
+@@ -47,6 +51,10 @@ static struct sk_buff *mtk_tag_xmit(stru
+ MTK_HDR_XMIT_UNTAGGED;
+ mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
+
++ /* Disable SA learning for multicast frames */
++ if (unlikely(is_multicast_skb))
++ mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS;
++
+ /* Tag control information is kept for 802.1Q */
+ if (!is_vlan_skb) {
+ mtk_tag[2] = 0;
+@@ -61,6 +69,9 @@ static struct sk_buff *mtk_tag_rcv(struc
+ {
+ int port;
+ __be16 *phdr, hdr;
++ unsigned char *dest = eth_hdr(skb)->h_dest;
++ bool is_multicast_skb = is_multicast_ether_addr(dest) &&
++ !is_broadcast_ether_addr(dest);
+
+ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
+ return NULL;
+@@ -86,6 +97,10 @@ static struct sk_buff *mtk_tag_rcv(struc
+ if (!skb->dev)
+ return NULL;
+
++ /* Only unicast or broadcast frames are offloaded */
++ if (likely(!is_multicast_skb))
++ skb->offload_fwd_mark = 1;
++
+ return skb;
+ }
+