summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dsa/8021q.h76
-rw-r--r--include/net/dsa.h2
-rw-r--r--net/dsa/Kconfig11
-rw-r--r--net/dsa/Makefile1
-rw-r--r--net/dsa/tag_8021q.c222
5 files changed, 312 insertions, 0 deletions
diff --git a/include/linux/dsa/8021q.h b/include/linux/dsa/8021q.h
new file mode 100644
index 000000000000..3911e0586478
--- /dev/null
+++ b/include/linux/dsa/8021q.h
@@ -0,0 +1,76 @@
1/* SPDX-License-Identifier: GPL-2.0
2 * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
3 */
4
5#ifndef _NET_DSA_8021Q_H
6#define _NET_DSA_8021Q_H
7
8#include <linux/types.h>
9
10struct dsa_switch;
11struct sk_buff;
12struct net_device;
13struct packet_type;
14
15#if IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q)
16
17int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
18 bool enabled);
19
20struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
21 u16 tpid, u16 tci);
22
23struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev,
24 struct packet_type *pt, u16 *tpid, u16 *tci);
25
26u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port);
27
28u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port);
29
30int dsa_8021q_rx_switch_id(u16 vid);
31
32int dsa_8021q_rx_source_port(u16 vid);
33
34#else
35
36int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
37 bool enabled)
38{
39 return 0;
40}
41
42struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
43 u16 tpid, u16 tci)
44{
45 return NULL;
46}
47
48struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev,
49 struct packet_type *pt, u16 *tpid, u16 *tci)
50{
51 return NULL;
52}
53
54u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
55{
56 return 0;
57}
58
59u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
60{
61 return 0;
62}
63
64int dsa_8021q_rx_switch_id(u16 vid)
65{
66 return 0;
67}
68
69int dsa_8021q_rx_source_port(u16 vid)
70{
71 return 0;
72}
73
74#endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) */
75
76#endif /* _NET_DSA_8021Q_H */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 18db7b8e7a8e..69f3714f42ba 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -42,6 +42,7 @@ struct phylink_link_state;
42#define DSA_TAG_PROTO_MTK_VALUE 9 42#define DSA_TAG_PROTO_MTK_VALUE 9
43#define DSA_TAG_PROTO_QCA_VALUE 10 43#define DSA_TAG_PROTO_QCA_VALUE 10
44#define DSA_TAG_PROTO_TRAILER_VALUE 11 44#define DSA_TAG_PROTO_TRAILER_VALUE 11
45#define DSA_TAG_PROTO_8021Q_VALUE 12
45 46
46enum dsa_tag_protocol { 47enum dsa_tag_protocol {
47 DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, 48 DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -56,6 +57,7 @@ enum dsa_tag_protocol {
56 DSA_TAG_PROTO_MTK = DSA_TAG_PROTO_MTK_VALUE, 57 DSA_TAG_PROTO_MTK = DSA_TAG_PROTO_MTK_VALUE,
57 DSA_TAG_PROTO_QCA = DSA_TAG_PROTO_QCA_VALUE, 58 DSA_TAG_PROTO_QCA = DSA_TAG_PROTO_QCA_VALUE,
58 DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE, 59 DSA_TAG_PROTO_TRAILER = DSA_TAG_PROTO_TRAILER_VALUE,
60 DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE,
59}; 61};
60 62
61struct packet_type; 63struct packet_type;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index c0734028c7dc..fc15a7e1a6df 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -17,6 +17,17 @@ menuconfig NET_DSA
17 17
18if NET_DSA 18if NET_DSA
19 19
20# tagging formats
21config NET_DSA_TAG_8021Q
22 tristate "Tag driver for switches using custom 802.1Q VLAN headers"
23 select VLAN_8021Q
24 help
25 Unlike the other tagging protocols, the 802.1Q config option simply
26 provides helpers for other tagging implementations that might rely on
27 VLAN in one way or another. It is not a complete solution.
28
29 Drivers which use these helpers should select this as dependency.
30
20config NET_DSA_TAG_BRCM_COMMON 31config NET_DSA_TAG_BRCM_COMMON
21 tristate 32 tristate
22 default n 33 default n
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 8a737b6ee94c..e97c794ec57b 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
4dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o 4dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o
5 5
6# tagging formats 6# tagging formats
7obj-$(CONFIG_NET_DSA_TAG_8021Q) += tag_8021q.o
7obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o 8obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
8obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o 9obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
9obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o 10obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
new file mode 100644
index 000000000000..8ae48c7e1e76
--- /dev/null
+++ b/net/dsa/tag_8021q.c
@@ -0,0 +1,222 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
3 *
4 * This module is not a complete tagger implementation. It only provides
5 * primitives for taggers that rely on 802.1Q VLAN tags to use. The
6 * dsa_8021q_netdev_ops is registered for API compliance and not used
7 * directly by callers.
8 */
9#include <linux/if_bridge.h>
10#include <linux/if_vlan.h>
11
12#include "dsa_priv.h"
13
14/* Allocating two VLAN tags per port - one for the RX VID and
15 * the other for the TX VID - see below
16 */
17#define DSA_8021Q_VID_RANGE (DSA_MAX_SWITCHES * DSA_MAX_PORTS)
18#define DSA_8021Q_VID_BASE (VLAN_N_VID - 2 * DSA_8021Q_VID_RANGE - 1)
19#define DSA_8021Q_RX_VID_BASE (DSA_8021Q_VID_BASE)
20#define DSA_8021Q_TX_VID_BASE (DSA_8021Q_VID_BASE + DSA_8021Q_VID_RANGE)
21
22/* Returns the VID to be inserted into the frame from xmit for switch steering
23 * instructions on egress. Encodes switch ID and port ID.
24 */
25u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
26{
27 return DSA_8021Q_TX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
28}
29EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
30
31/* Returns the VID that will be installed as pvid for this switch port, sent as
32 * tagged egress towards the CPU port and decoded by the rcv function.
33 */
34u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
35{
36 return DSA_8021Q_RX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
37}
38EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid);
39
40/* Returns the decoded switch ID from the RX VID. */
41int dsa_8021q_rx_switch_id(u16 vid)
42{
43 return ((vid - DSA_8021Q_RX_VID_BASE) / DSA_MAX_PORTS);
44}
45EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);
46
47/* Returns the decoded port ID from the RX VID. */
48int dsa_8021q_rx_source_port(u16 vid)
49{
50 return ((vid - DSA_8021Q_RX_VID_BASE) % DSA_MAX_PORTS);
51}
52EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
53
54/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
55 * front-panel switch port (here swp0).
56 *
57 * Port identification through VLAN (802.1Q) tags has different requirements
58 * for it to work effectively:
59 * - On RX (ingress from network): each front-panel port must have a pvid
60 * that uniquely identifies it, and the egress of this pvid must be tagged
61 * towards the CPU port, so that software can recover the source port based
62 * on the VID in the frame. But this would only work for standalone ports;
63 * if bridged, this VLAN setup would break autonomous forwarding and would
64 * force all switched traffic to pass through the CPU. So we must also make
65 * the other front-panel ports members of this VID we're adding, albeit
66 * we're not making it their PVID (they'll still have their own).
67 * By the way - just because we're installing the same VID in multiple
68 * switch ports doesn't mean that they'll start to talk to one another, even
69 * while not bridged: the final forwarding decision is still an AND between
70 * the L2 forwarding information (which is limiting forwarding in this case)
71 * and the VLAN-based restrictions (of which there are none in this case,
72 * since all ports are members).
73 * - On TX (ingress from CPU and towards network) we are faced with a problem.
74 * If we were to tag traffic (from within DSA) with the port's pvid, all
75 * would be well, assuming the switch ports were standalone. Frames would
76 * have no choice but to be directed towards the correct front-panel port.
77 * But because we also want the RX VLAN to not break bridging, then
78 * inevitably that means that we have to give them a choice (of what
79 * front-panel port to go out on), and therefore we cannot steer traffic
80 * based on the RX VID. So what we do is simply install one more VID on the
81 * front-panel and CPU ports, and profit off of the fact that steering will
82 * work just by virtue of the fact that there is only one other port that's
83 * a member of the VID we're tagging the traffic with - the desired one.
84 *
85 * So at the end, each front-panel port will have one RX VID (also the PVID),
86 * the RX VID of all other front-panel ports, and one TX VID. Whereas the CPU
87 * port will have the RX and TX VIDs of all front-panel ports, and on top of
88 * that, is also tagged-input and tagged-output (VLAN trunk).
89 *
90 * CPU port CPU port
91 * +-------------+-----+-------------+ +-------------+-----+-------------+
92 * | RX VID | | | | TX VID | | |
93 * | of swp0 | | | | of swp0 | | |
94 * | +-----+ | | +-----+ |
95 * | ^ T | | | Tagged |
96 * | | | | | ingress |
97 * | +-------+---+---+-------+ | | +-----------+ |
98 * | | | | | | | | Untagged |
99 * | | U v U v U v | | v egress |
100 * | +-----+ +-----+ +-----+ +-----+ | | +-----+ +-----+ +-----+ +-----+ |
101 * | | | | | | | | | | | | | | | | | | | |
102 * | |PVID | | | | | | | | | | | | | | | | | |
103 * +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+
104 * swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3
105 */
106int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
107{
108 int upstream = dsa_upstream_port(ds, port);
109 struct dsa_port *dp = &ds->ports[port];
110 struct dsa_port *upstream_dp = &ds->ports[upstream];
111 u16 rx_vid = dsa_8021q_rx_vid(ds, port);
112 u16 tx_vid = dsa_8021q_tx_vid(ds, port);
113 int i, err;
114
115 /* The CPU port is implicitly configured by
116 * configuring the front-panel ports
117 */
118 if (!dsa_is_user_port(ds, port))
119 return 0;
120
121 /* Add this user port's RX VID to the membership list of all others
122 * (including itself). This is so that bridging will not be hindered.
123 * L2 forwarding rules still take precedence when there are no VLAN
124 * restrictions, so there are no concerns about leaking traffic.
125 */
126 for (i = 0; i < ds->num_ports; i++) {
127 struct dsa_port *other_dp = &ds->ports[i];
128 u16 flags;
129
130 if (i == upstream)
131 /* CPU port needs to see this port's RX VID
132 * as tagged egress.
133 */
134 flags = 0;
135 else if (i == port)
136 /* The RX VID is pvid on this port */
137 flags = BRIDGE_VLAN_INFO_UNTAGGED |
138 BRIDGE_VLAN_INFO_PVID;
139 else
140 /* The RX VID is a regular VLAN on all others */
141 flags = BRIDGE_VLAN_INFO_UNTAGGED;
142
143 if (enabled)
144 err = dsa_port_vid_add(other_dp, rx_vid, flags);
145 else
146 err = dsa_port_vid_del(other_dp, rx_vid);
147 if (err) {
148 dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n",
149 rx_vid, port, err);
150 return err;
151 }
152 }
153 /* Finally apply the TX VID on this port and on the CPU port */
154 if (enabled)
155 err = dsa_port_vid_add(dp, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED);
156 else
157 err = dsa_port_vid_del(dp, tx_vid);
158 if (err) {
159 dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n",
160 tx_vid, port, err);
161 return err;
162 }
163 if (enabled)
164 err = dsa_port_vid_add(upstream_dp, tx_vid, 0);
165 else
166 err = dsa_port_vid_del(upstream_dp, tx_vid);
167 if (err) {
168 dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n",
169 tx_vid, upstream, err);
170 return err;
171 }
172
173 return 0;
174}
175EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging);
176
177struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
178 u16 tpid, u16 tci)
179{
180 /* skb->data points at skb_mac_header, which
181 * is fine for vlan_insert_tag.
182 */
183 return vlan_insert_tag(skb, htons(tpid), tci);
184}
185EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
186
187struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev,
188 struct packet_type *pt, u16 *tpid, u16 *tci)
189{
190 struct vlan_ethhdr *tag;
191
192 if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
193 return NULL;
194
195 tag = vlan_eth_hdr(skb);
196 *tpid = ntohs(tag->h_vlan_proto);
197 *tci = ntohs(tag->h_vlan_TCI);
198
199 /* skb->data points in the middle of the VLAN tag,
200 * after tpid and before tci. This is because so far,
201 * ETH_HLEN (DMAC, SMAC, EtherType) bytes were pulled.
202 * There are 2 bytes of VLAN tag left in skb->data, and upper
203 * layers expect the 'real' EtherType to be consumed as well.
204 * Coincidentally, a VLAN header is also of the same size as
205 * the number of bytes that need to be pulled.
206 */
207 skb_pull_rcsum(skb, VLAN_HLEN);
208
209 return skb;
210}
211EXPORT_SYMBOL_GPL(dsa_8021q_rcv);
212
213static const struct dsa_device_ops dsa_8021q_netdev_ops = {
214 .name = "8021q",
215 .proto = DSA_TAG_PROTO_8021Q,
216 .overhead = VLAN_HLEN,
217};
218
219MODULE_LICENSE("GPL v2");
220MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_8021Q);
221
222module_dsa_tag_driver(dsa_8021q_netdev_ops);