Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

DENG Qingfang and committed by
David S. Miller
5e5502e0 b6dd5acd

+18 -7
+2 -7
drivers/net/dsa/mt7530.c
··· 628 628 mt7530_write(priv, MT7530_PVC_P(port), 629 629 PORT_SPEC_TAG); 630 630 631 - /* Disable auto learning on the cpu port */ 632 - mt7530_set(priv, MT7530_PSC_P(port), SA_DIS); 633 - 634 - /* Unknown unicast frame fordwarding to the cpu port */ 635 - mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port))); 631 + /* Unknown multicast frame forwarding to the cpu port */ 632 + mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port))); 636 633 637 634 /* Set CPU port number */ 638 635 if (priv->id == ID_MT7621) ··· 1290 1293 1291 1294 /* Enable and reset MIB counters */ 1292 1295 mt7530_mib_reset(ds); 1293 - 1294 - mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK); 1295 1296 1296 1297 for (i = 0; i < MT7530_NUM_PORTS; i++) { 1297 1298 /* Disable forwarding by default on all ports */
+1
drivers/net/dsa/mt7530.h
··· 31 31 #define MT7530_MFC 0x10 32 32 #define BC_FFP(x) (((x) & 0xff) << 24) 33 33 #define UNM_FFP(x) (((x) & 0xff) << 16) 34 + #define UNM_FFP_MASK UNM_FFP(~0) 34 35 #define UNU_FFP(x) (((x) & 0xff) << 8) 35 36 #define UNU_FFP_MASK UNU_FFP(~0) 36 37 #define CPU_EN BIT(7)
+15
net/dsa/tag_mtk.c
··· 15 15 #define MTK_HDR_XMIT_TAGGED_TPID_8100 1 16 16 #define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) 17 17 #define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0) 18 + #define MTK_HDR_XMIT_SA_DIS BIT(6) 18 19 19 20 static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, 20 21 struct net_device *dev) ··· 23 22 struct dsa_port *dp = dsa_slave_to_port(dev); 24 23 u8 *mtk_tag; 25 24 bool is_vlan_skb = true; 25 + unsigned char *dest = eth_hdr(skb)->h_dest; 26 + bool is_multicast_skb = is_multicast_ether_addr(dest) && 27 + !is_broadcast_ether_addr(dest); 26 28 27 29 /* Build the special tag after the MAC Source Address. If VLAN header 28 30 * is present, it's required that VLAN header and special tag is ··· 51 47 MTK_HDR_XMIT_UNTAGGED; 52 48 mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; 53 49 50 + /* Disable SA learning for multicast frames */ 51 + if (unlikely(is_multicast_skb)) 52 + mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS; 53 + 54 54 /* Tag control information is kept for 802.1Q */ 55 55 if (!is_vlan_skb) { 56 56 mtk_tag[2] = 0; ··· 69 61 { 70 62 int port; 71 63 __be16 *phdr, hdr; 64 + unsigned char *dest = eth_hdr(skb)->h_dest; 65 + bool is_multicast_skb = is_multicast_ether_addr(dest) && 66 + !is_broadcast_ether_addr(dest); 72 67 73 68 if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) 74 69 return NULL; ··· 96 85 skb->dev = dsa_master_find_slave(dev, 0, port); 97 86 if (!skb->dev) 98 87 return NULL; 88 + 89 + /* Only unicast or broadcast frames are offloaded */ 90 + if (likely(!is_multicast_skb)) 91 + skb->offload_fwd_mark = 1; 99 92 100 93 return skb; 101 94 }