summaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorVladimir Oltean <olteanv@gmail.com>2019-05-05 06:19:27 -0400
committerDavid S. Miller <davem@davemloft.net>2019-05-06 00:52:42 -0400
commit227d07a07ef126272ea2eed97fd136cd7a803d81 (patch)
treed5004e1438e81abf29266b349005ae3a945f7e72 /net/dsa
parentc362beb072e14b929eb657dc174d83ccdd9b0eed (diff)
net: dsa: sja1105: Add support for traffic through standalone ports
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 <olteanv@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/Kconfig9
-rw-r--r--net/dsa/Makefile1
-rw-r--r--net/dsa/tag_sja1105.c131
3 files changed, 141 insertions, 0 deletions
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
102 Say Y or M if you want to enable support for tagging frames for the 102 Say Y or M if you want to enable support for tagging frames for the
103 SMSC/Microchip LAN9303 family of switches. 103 SMSC/Microchip LAN9303 family of switches.
104 104
105config NET_DSA_TAG_SJA1105
106 tristate "Tag driver for NXP SJA1105 switches"
107 select NET_DSA_TAG_8021Q
108 help
109 Say Y or M if you want to enable support for tagging frames with the
110 NXP SJA1105 switch family. Both the native tagging protocol (which
111 is only for link-local traffic) as well as non-native tagging (based
112 on a custom 802.1Q VLAN header) are available.
113
105config NET_DSA_TAG_TRAILER 114config NET_DSA_TAG_TRAILER
106 tristate "Tag driver for switches using a trailer tag" 115 tristate "Tag driver for switches using a trailer tag"
107 help 116 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
13obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o 13obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
14obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o 14obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
15obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o 15obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
16obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
16obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o 17obj-$(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 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
3 */
4#include <linux/if_vlan.h>
5#include <linux/dsa/sja1105.h>
6#include <linux/dsa/8021q.h>
7#include <linux/packing.h>
8#include "dsa_priv.h"
9
10/* Similar to is_link_local_ether_addr(hdr->h_dest) but also covers PTP */
11static inline bool sja1105_is_link_local(const struct sk_buff *skb)
12{
13 const struct ethhdr *hdr = eth_hdr(skb);
14 u64 dmac = ether_addr_to_u64(hdr->h_dest);
15
16 if ((dmac & SJA1105_LINKLOCAL_FILTER_A_MASK) ==
17 SJA1105_LINKLOCAL_FILTER_A)
18 return true;
19 if ((dmac & SJA1105_LINKLOCAL_FILTER_B_MASK) ==
20 SJA1105_LINKLOCAL_FILTER_B)
21 return true;
22 return false;
23}
24
25/* This is the first time the tagger sees the frame on RX.
26 * Figure out if we can decode it, and if we can, annotate skb->cb with how we
27 * plan to do that, so we don't need to check again in the rcv function.
28 */
29static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev)
30{
31 if (sja1105_is_link_local(skb)) {
32 SJA1105_SKB_CB(skb)->type = SJA1105_FRAME_TYPE_LINK_LOCAL;
33 return true;
34 }
35 if (!dsa_port_is_vlan_filtering(dev->dsa_ptr)) {
36 SJA1105_SKB_CB(skb)->type = SJA1105_FRAME_TYPE_NORMAL;
37 return true;
38 }
39 return false;
40}
41
42static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
43 struct net_device *netdev)
44{
45 struct dsa_port *dp = dsa_slave_to_port(netdev);
46 struct dsa_switch *ds = dp->ds;
47 u16 tx_vid = dsa_8021q_tx_vid(ds, dp->index);
48 u8 pcp = skb->priority;
49
50 /* Transmitting management traffic does not rely upon switch tagging,
51 * but instead SPI-installed management routes. Part 2 of this
52 * is the .port_deferred_xmit driver callback.
53 */
54 if (unlikely(sja1105_is_link_local(skb)))
55 return dsa_defer_xmit(skb, netdev);
56
57 /* If we are under a vlan_filtering bridge, IP termination on
58 * switch ports based on 802.1Q tags is simply too brittle to
59 * be passable. So just defer to the dsa_slave_notag_xmit
60 * implementation.
61 */
62 if (dsa_port_is_vlan_filtering(dp))
63 return skb;
64
65 return dsa_8021q_xmit(skb, netdev, ETH_P_SJA1105,
66 ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
67}
68
69static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
70 struct net_device *netdev,
71 struct packet_type *pt)
72{
73 struct ethhdr *hdr = eth_hdr(skb);
74 u64 source_port, switch_id;
75 struct sk_buff *nskb;
76 u16 tpid, vid, tci;
77 bool is_tagged;
78
79 nskb = dsa_8021q_rcv(skb, netdev, pt, &tpid, &tci);
80 is_tagged = (nskb && tpid == ETH_P_SJA1105);
81
82 skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
83 vid = tci & VLAN_VID_MASK;
84
85 skb->offload_fwd_mark = 1;
86
87 if (SJA1105_SKB_CB(skb)->type == SJA1105_FRAME_TYPE_LINK_LOCAL) {
88 /* Management traffic path. Switch embeds the switch ID and
89 * port ID into bytes of the destination MAC, courtesy of
90 * the incl_srcpt options.
91 */
92 source_port = hdr->h_dest[3];
93 switch_id = hdr->h_dest[4];
94 /* Clear the DMAC bytes that were mangled by the switch */
95 hdr->h_dest[3] = 0;
96 hdr->h_dest[4] = 0;
97 } else {
98 /* Normal traffic path. */
99 source_port = dsa_8021q_rx_source_port(vid);
100 switch_id = dsa_8021q_rx_switch_id(vid);
101 }
102
103 skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
104 if (!skb->dev) {
105 netdev_warn(netdev, "Couldn't decode source port\n");
106 return NULL;
107 }
108
109 /* Delete/overwrite fake VLAN header, DSA expects to not find
110 * it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN).
111 */
112 if (is_tagged)
113 memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - VLAN_HLEN,
114 ETH_HLEN - VLAN_HLEN);
115
116 return skb;
117}
118
119static struct dsa_device_ops sja1105_netdev_ops = {
120 .name = "sja1105",
121 .proto = DSA_TAG_PROTO_SJA1105,
122 .xmit = sja1105_xmit,
123 .rcv = sja1105_rcv,
124 .filter = sja1105_filter,
125 .overhead = VLAN_HLEN,
126};
127
128MODULE_LICENSE("GPL v2");
129MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SJA1105);
130
131module_dsa_tag_driver(sja1105_netdev_ops);