net: dsa: tag_8021q: replace the SVL bridging with VLAN-unaware IVL bridging
[linux-block.git] / net / dsa / tag_8021q.c
CommitLineData
f9bbe447
VO
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 */
f9bbe447 9#include <linux/if_vlan.h>
ac02a451 10#include <linux/dsa/8021q.h>
f9bbe447
VO
11
12#include "dsa_priv.h"
13
0471dd42
VO
14/* Binary structure of the fake 12-bit VID field (when the TPID is
15 * ETH_P_DSA_8021Q):
16 *
17 * | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
18 * +-----------+-----+-----------------+-----------+-----------------------+
b6ad86e6 19 * | DIR | VBID| SWITCH_ID | VBID | PORT |
0471dd42
VO
20 * +-----------+-----+-----------------+-----------+-----------------------+
21 *
22 * DIR - VID[11:10]:
23 * Direction flags.
24 * * 1 (0b01) for RX VLAN,
25 * * 2 (0b10) for TX VLAN.
26 * These values make the special VIDs of 0, 1 and 4095 to be left
27 * unused by this coding scheme.
28 *
0471dd42 29 * SWITCH_ID - VID[8:6]:
fcee85f1 30 * Index of switch within DSA tree. Must be between 0 and 7.
0471dd42 31 *
b6ad86e6
VO
32 * VBID - { VID[9], VID[5:4] }:
33 * Virtual bridge ID. If between 1 and 7, packet targets the broadcast
34 * domain of a bridge. If transmitted as zero, packet targets a single
35 * port. Field only valid on transmit, must be ignored on receive.
0fac6aa0 36 *
0471dd42 37 * PORT - VID[3:0]:
fcee85f1 38 * Index of switch port. Must be between 0 and 15.
f9bbe447 39 */
0471dd42
VO
40
41#define DSA_8021Q_DIR_SHIFT 10
42#define DSA_8021Q_DIR_MASK GENMASK(11, 10)
43#define DSA_8021Q_DIR(x) (((x) << DSA_8021Q_DIR_SHIFT) & \
44 DSA_8021Q_DIR_MASK)
45#define DSA_8021Q_DIR_RX DSA_8021Q_DIR(1)
46#define DSA_8021Q_DIR_TX DSA_8021Q_DIR(2)
47
48#define DSA_8021Q_SWITCH_ID_SHIFT 6
49#define DSA_8021Q_SWITCH_ID_MASK GENMASK(8, 6)
50#define DSA_8021Q_SWITCH_ID(x) (((x) << DSA_8021Q_SWITCH_ID_SHIFT) & \
51 DSA_8021Q_SWITCH_ID_MASK)
52
b6ad86e6
VO
53#define DSA_8021Q_VBID_HI_SHIFT 9
54#define DSA_8021Q_VBID_HI_MASK GENMASK(9, 9)
55#define DSA_8021Q_VBID_LO_SHIFT 4
56#define DSA_8021Q_VBID_LO_MASK GENMASK(5, 4)
57#define DSA_8021Q_VBID_HI(x) (((x) & GENMASK(2, 2)) >> 2)
58#define DSA_8021Q_VBID_LO(x) ((x) & GENMASK(1, 0))
59#define DSA_8021Q_VBID(x) \
60 (((DSA_8021Q_VBID_LO(x) << DSA_8021Q_VBID_LO_SHIFT) & \
61 DSA_8021Q_VBID_LO_MASK) | \
62 ((DSA_8021Q_VBID_HI(x) << DSA_8021Q_VBID_HI_SHIFT) & \
63 DSA_8021Q_VBID_HI_MASK))
64
0471dd42
VO
65#define DSA_8021Q_PORT_SHIFT 0
66#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
67#define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \
68 DSA_8021Q_PORT_MASK)
f9bbe447 69
3f9bb030 70u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num)
b6ad86e6 71{
3f9bb030
VO
72 /* The VBID value of 0 is reserved for precise TX, but it is also
73 * reserved/invalid for the bridge_num, so all is well.
74 */
75 return DSA_8021Q_DIR_TX | DSA_8021Q_VBID(bridge_num);
b6ad86e6
VO
76}
77EXPORT_SYMBOL_GPL(dsa_8021q_bridge_tx_fwd_offload_vid);
78
f9bbe447
VO
79/* Returns the VID to be inserted into the frame from xmit for switch steering
80 * instructions on egress. Encodes switch ID and port ID.
81 */
992e5cc7 82u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp)
f9bbe447 83{
992e5cc7
VO
84 return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
85 DSA_8021Q_PORT(dp->index);
f9bbe447 86}
992e5cc7 87EXPORT_SYMBOL_GPL(dsa_tag_8021q_tx_vid);
f9bbe447
VO
88
89/* Returns the VID that will be installed as pvid for this switch port, sent as
90 * tagged egress towards the CPU port and decoded by the rcv function.
91 */
992e5cc7 92u16 dsa_tag_8021q_rx_vid(const struct dsa_port *dp)
f9bbe447 93{
992e5cc7
VO
94 return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
95 DSA_8021Q_PORT(dp->index);
f9bbe447 96}
992e5cc7 97EXPORT_SYMBOL_GPL(dsa_tag_8021q_rx_vid);
f9bbe447
VO
98
99/* Returns the decoded switch ID from the RX VID. */
100int dsa_8021q_rx_switch_id(u16 vid)
101{
0471dd42 102 return (vid & DSA_8021Q_SWITCH_ID_MASK) >> DSA_8021Q_SWITCH_ID_SHIFT;
f9bbe447
VO
103}
104EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);
105
106/* Returns the decoded port ID from the RX VID. */
107int dsa_8021q_rx_source_port(u16 vid)
108{
0471dd42 109 return (vid & DSA_8021Q_PORT_MASK) >> DSA_8021Q_PORT_SHIFT;
f9bbe447
VO
110}
111EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
112
91495f21
VO
113/* Returns the decoded VBID from the RX VID. */
114static int dsa_tag_8021q_rx_vbid(u16 vid)
115{
116 u16 vbid_hi = (vid & DSA_8021Q_VBID_HI_MASK) >> DSA_8021Q_VBID_HI_SHIFT;
117 u16 vbid_lo = (vid & DSA_8021Q_VBID_LO_MASK) >> DSA_8021Q_VBID_LO_SHIFT;
118
119 return (vbid_hi << 2) | vbid_lo;
120}
121
9c7caf28
VO
122bool vid_is_dsa_8021q_rxvlan(u16 vid)
123{
124 return (vid & DSA_8021Q_DIR_MASK) == DSA_8021Q_DIR_RX;
125}
126EXPORT_SYMBOL_GPL(vid_is_dsa_8021q_rxvlan);
127
128bool vid_is_dsa_8021q_txvlan(u16 vid)
129{
130 return (vid & DSA_8021Q_DIR_MASK) == DSA_8021Q_DIR_TX;
131}
132EXPORT_SYMBOL_GPL(vid_is_dsa_8021q_txvlan);
133
1f66b0f0
VO
134bool vid_is_dsa_8021q(u16 vid)
135{
9c7caf28 136 return vid_is_dsa_8021q_rxvlan(vid) || vid_is_dsa_8021q_txvlan(vid);
1f66b0f0
VO
137}
138EXPORT_SYMBOL_GPL(vid_is_dsa_8021q);
139
c64b9c05
VO
140static struct dsa_tag_8021q_vlan *
141dsa_tag_8021q_vlan_find(struct dsa_8021q_context *ctx, int port, u16 vid)
142{
143 struct dsa_tag_8021q_vlan *v;
144
145 list_for_each_entry(v, &ctx->vlans, list)
146 if (v->vid == vid && v->port == port)
147 return v;
148
149 return NULL;
150}
151
fac6abd5
VO
152static int dsa_port_do_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid,
153 u16 flags)
5f33183b 154{
fac6abd5
VO
155 struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
156 struct dsa_switch *ds = dp->ds;
c64b9c05 157 struct dsa_tag_8021q_vlan *v;
fac6abd5 158 int port = dp->index;
c64b9c05
VO
159 int err;
160
161 /* No need to bother with refcounting for user ports */
162 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
163 return ds->ops->tag_8021q_vlan_add(ds, port, vid, flags);
164
165 v = dsa_tag_8021q_vlan_find(ctx, port, vid);
166 if (v) {
167 refcount_inc(&v->refcount);
168 return 0;
169 }
170
171 v = kzalloc(sizeof(*v), GFP_KERNEL);
172 if (!v)
173 return -ENOMEM;
174
175 err = ds->ops->tag_8021q_vlan_add(ds, port, vid, flags);
176 if (err) {
177 kfree(v);
178 return err;
179 }
180
181 v->vid = vid;
182 v->port = port;
183 refcount_set(&v->refcount, 1);
184 list_add_tail(&v->list, &ctx->vlans);
185
186 return 0;
187}
188
fac6abd5 189static int dsa_port_do_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid)
c64b9c05 190{
fac6abd5
VO
191 struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
192 struct dsa_switch *ds = dp->ds;
c64b9c05 193 struct dsa_tag_8021q_vlan *v;
fac6abd5 194 int port = dp->index;
c64b9c05
VO
195 int err;
196
197 /* No need to bother with refcounting for user ports */
198 if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
199 return ds->ops->tag_8021q_vlan_del(ds, port, vid);
200
201 v = dsa_tag_8021q_vlan_find(ctx, port, vid);
202 if (!v)
203 return -ENOENT;
204
205 if (!refcount_dec_and_test(&v->refcount))
206 return 0;
207
208 err = ds->ops->tag_8021q_vlan_del(ds, port, vid);
209 if (err) {
210 refcount_inc(&v->refcount);
211 return err;
212 }
213
214 list_del(&v->list);
215 kfree(v);
216
217 return 0;
218}
5f33183b 219
c64b9c05 220static bool
fac6abd5
VO
221dsa_port_tag_8021q_vlan_match(struct dsa_port *dp,
222 struct dsa_notifier_tag_8021q_vlan_info *info)
c64b9c05 223{
fac6abd5
VO
224 struct dsa_switch *ds = dp->ds;
225
226 if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
c64b9c05
VO
227 return true;
228
229 if (ds->dst->index == info->tree_index && ds->index == info->sw_index)
fac6abd5 230 return dp->index == info->port;
c64b9c05
VO
231
232 return false;
233}
234
235int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
236 struct dsa_notifier_tag_8021q_vlan_info *info)
237{
fac6abd5
VO
238 struct dsa_port *dp;
239 int err;
c64b9c05
VO
240
241 /* Since we use dsa_broadcast(), there might be other switches in other
242 * trees which don't support tag_8021q, so don't return an error.
243 * Or they might even support tag_8021q but have not registered yet to
244 * use it (maybe they use another tagger currently).
245 */
246 if (!ds->ops->tag_8021q_vlan_add || !ds->tag_8021q_ctx)
247 return 0;
5f33183b 248
fac6abd5
VO
249 dsa_switch_for_each_port(dp, ds) {
250 if (dsa_port_tag_8021q_vlan_match(dp, info)) {
c64b9c05
VO
251 u16 flags = 0;
252
fac6abd5 253 if (dsa_port_is_user(dp))
c64b9c05
VO
254 flags |= BRIDGE_VLAN_INFO_UNTAGGED;
255
91495f21 256 /* Standalone VLANs are PVIDs */
c64b9c05
VO
257 if (vid_is_dsa_8021q_rxvlan(info->vid) &&
258 dsa_8021q_rx_switch_id(info->vid) == ds->index &&
fac6abd5 259 dsa_8021q_rx_source_port(info->vid) == dp->index)
c64b9c05
VO
260 flags |= BRIDGE_VLAN_INFO_PVID;
261
91495f21
VO
262 /* And bridging VLANs are PVIDs too on user ports */
263 if (dsa_tag_8021q_rx_vbid(info->vid) &&
264 dsa_port_is_user(dp))
265 flags |= BRIDGE_VLAN_INFO_PVID;
266
fac6abd5
VO
267 err = dsa_port_do_tag_8021q_vlan_add(dp, info->vid,
268 flags);
c64b9c05
VO
269 if (err)
270 return err;
271 }
272 }
273
274 return 0;
275}
276
277int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
278 struct dsa_notifier_tag_8021q_vlan_info *info)
279{
fac6abd5
VO
280 struct dsa_port *dp;
281 int err;
c64b9c05
VO
282
283 if (!ds->ops->tag_8021q_vlan_del || !ds->tag_8021q_ctx)
284 return 0;
285
fac6abd5
VO
286 dsa_switch_for_each_port(dp, ds) {
287 if (dsa_port_tag_8021q_vlan_match(dp, info)) {
288 err = dsa_port_do_tag_8021q_vlan_del(dp, info->vid);
c64b9c05
VO
289 if (err)
290 return err;
291 }
292 }
293
294 return 0;
5f33183b
VO
295}
296
f9bbe447
VO
297/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
298 * front-panel switch port (here swp0).
299 *
300 * Port identification through VLAN (802.1Q) tags has different requirements
301 * for it to work effectively:
302 * - On RX (ingress from network): each front-panel port must have a pvid
303 * that uniquely identifies it, and the egress of this pvid must be tagged
304 * towards the CPU port, so that software can recover the source port based
305 * on the VID in the frame. But this would only work for standalone ports;
306 * if bridged, this VLAN setup would break autonomous forwarding and would
307 * force all switched traffic to pass through the CPU. So we must also make
308 * the other front-panel ports members of this VID we're adding, albeit
309 * we're not making it their PVID (they'll still have their own).
f9bbe447
VO
310 * - On TX (ingress from CPU and towards network) we are faced with a problem.
311 * If we were to tag traffic (from within DSA) with the port's pvid, all
312 * would be well, assuming the switch ports were standalone. Frames would
313 * have no choice but to be directed towards the correct front-panel port.
314 * But because we also want the RX VLAN to not break bridging, then
315 * inevitably that means that we have to give them a choice (of what
316 * front-panel port to go out on), and therefore we cannot steer traffic
317 * based on the RX VID. So what we do is simply install one more VID on the
318 * front-panel and CPU ports, and profit off of the fact that steering will
319 * work just by virtue of the fact that there is only one other port that's
320 * a member of the VID we're tagging the traffic with - the desired one.
321 *
322 * So at the end, each front-panel port will have one RX VID (also the PVID),
e19cc13c
VO
323 * the RX VID of all other front-panel ports that are in the same bridge, and
324 * one TX VID. Whereas the CPU port will have the RX and TX VIDs of all
325 * front-panel ports, and on top of that, is also tagged-input and
326 * tagged-output (VLAN trunk).
f9bbe447
VO
327 *
328 * CPU port CPU port
329 * +-------------+-----+-------------+ +-------------+-----+-------------+
330 * | RX VID | | | | TX VID | | |
331 * | of swp0 | | | | of swp0 | | |
332 * | +-----+ | | +-----+ |
333 * | ^ T | | | Tagged |
334 * | | | | | ingress |
335 * | +-------+---+---+-------+ | | +-----------+ |
336 * | | | | | | | | Untagged |
337 * | | U v U v U v | | v egress |
338 * | +-----+ +-----+ +-----+ +-----+ | | +-----+ +-----+ +-----+ +-----+ |
339 * | | | | | | | | | | | | | | | | | | | |
340 * | |PVID | | | | | | | | | | | | | | | | | |
341 * +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+
342 * swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3
343 */
91495f21
VO
344int dsa_tag_8021q_bridge_join(struct dsa_switch *ds, int port,
345 struct dsa_bridge bridge)
e19cc13c 346{
91495f21
VO
347 struct dsa_port *dp = dsa_to_port(ds, port);
348 u16 standalone_vid, bridge_vid;
fac6abd5 349 int err;
e19cc13c 350
91495f21
VO
351 /* Delete the standalone VLAN of the port and replace it with a
352 * bridging VLAN
353 */
354 standalone_vid = dsa_tag_8021q_rx_vid(dp);
355 bridge_vid = dsa_8021q_bridge_tx_fwd_offload_vid(bridge.num);
e19cc13c 356
91495f21
VO
357 err = dsa_port_tag_8021q_vlan_add(dp, bridge_vid, true);
358 if (err)
359 return err;
e19cc13c 360
91495f21 361 dsa_port_tag_8021q_vlan_del(dp, standalone_vid, false);
e19cc13c
VO
362
363 return 0;
364}
91495f21 365EXPORT_SYMBOL_GPL(dsa_tag_8021q_bridge_join);
e19cc13c 366
91495f21
VO
367void dsa_tag_8021q_bridge_leave(struct dsa_switch *ds, int port,
368 struct dsa_bridge bridge)
e19cc13c 369{
91495f21
VO
370 struct dsa_port *dp = dsa_to_port(ds, port);
371 u16 standalone_vid, bridge_vid;
372 int err;
e19cc13c 373
91495f21
VO
374 /* Delete the bridging VLAN of the port and replace it with a
375 * standalone VLAN
376 */
377 standalone_vid = dsa_tag_8021q_rx_vid(dp);
378 bridge_vid = dsa_8021q_bridge_tx_fwd_offload_vid(bridge.num);
e19cc13c 379
91495f21
VO
380 err = dsa_port_tag_8021q_vlan_add(dp, standalone_vid, false);
381 if (err) {
382 dev_err(ds->dev,
383 "Failed to delete tag_8021q standalone VLAN %d from port %d: %pe\n",
384 standalone_vid, port, ERR_PTR(err));
e19cc13c
VO
385 }
386
91495f21 387 dsa_port_tag_8021q_vlan_del(dp, bridge_vid, true);
b6ad86e6 388}
91495f21 389EXPORT_SYMBOL_GPL(dsa_tag_8021q_bridge_leave);
b6ad86e6 390
e19cc13c 391/* Set up a port's tag_8021q RX and TX VLAN for standalone mode operation */
c64b9c05 392static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port)
f9bbe447 393{
d7b1fd52 394 struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
c64b9c05 395 struct dsa_port *dp = dsa_to_port(ds, port);
992e5cc7
VO
396 u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
397 u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
bbed0bbd 398 struct net_device *master;
e19cc13c 399 int err;
f9bbe447
VO
400
401 /* The CPU port is implicitly configured by
402 * configuring the front-panel ports
403 */
c64b9c05 404 if (!dsa_port_is_user(dp))
f9bbe447
VO
405 return 0;
406
c64b9c05 407 master = dp->cpu_dp->master;
bbed0bbd 408
f9bbe447
VO
409 /* Add this user port's RX VID to the membership list of all others
410 * (including itself). This is so that bridging will not be hindered.
411 * L2 forwarding rules still take precedence when there are no VLAN
412 * restrictions, so there are no concerns about leaking traffic.
413 */
b2b89133 414 err = dsa_port_tag_8021q_vlan_add(dp, rx_vid, false);
d34d2baa 415 if (err) {
d7b1fd52 416 dev_err(ds->dev,
69ebb370
VO
417 "Failed to apply RX VID %d to port %d: %pe\n",
418 rx_vid, port, ERR_PTR(err));
d34d2baa
IC
419 return err;
420 }
421
0fac6aa0 422 /* Add @rx_vid to the master's RX filter. */
c64b9c05 423 vlan_vid_add(master, ctx->proto, rx_vid);
bbed0bbd 424
f9bbe447 425 /* Finally apply the TX VID on this port and on the CPU port */
b2b89133 426 err = dsa_port_tag_8021q_vlan_add(dp, tx_vid, false);
f9bbe447 427 if (err) {
d7b1fd52 428 dev_err(ds->dev,
69ebb370
VO
429 "Failed to apply TX VID %d on port %d: %pe\n",
430 tx_vid, port, ERR_PTR(err));
f9bbe447
VO
431 return err;
432 }
f9bbe447 433
5f33183b 434 return err;
f9bbe447 435}
7e092af2 436
c64b9c05
VO
437static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port)
438{
439 struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
440 struct dsa_port *dp = dsa_to_port(ds, port);
992e5cc7
VO
441 u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
442 u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
c64b9c05
VO
443 struct net_device *master;
444
445 /* The CPU port is implicitly configured by
446 * configuring the front-panel ports
447 */
448 if (!dsa_port_is_user(dp))
449 return;
450
451 master = dp->cpu_dp->master;
452
724395f4 453 dsa_port_tag_8021q_vlan_del(dp, rx_vid, false);
c64b9c05
VO
454
455 vlan_vid_del(master, ctx->proto, rx_vid);
456
724395f4 457 dsa_port_tag_8021q_vlan_del(dp, tx_vid, false);
c64b9c05
VO
458}
459
460static int dsa_tag_8021q_setup(struct dsa_switch *ds)
7e092af2 461{
a81a4574 462 int err, port;
7e092af2 463
bbed0bbd
VO
464 ASSERT_RTNL();
465
d7b1fd52 466 for (port = 0; port < ds->num_ports; port++) {
c64b9c05 467 err = dsa_tag_8021q_port_setup(ds, port);
a81a4574 468 if (err < 0) {
d7b1fd52 469 dev_err(ds->dev,
69ebb370
VO
470 "Failed to setup VLAN tagging for port %d: %pe\n",
471 port, ERR_PTR(err));
a81a4574 472 return err;
7e092af2
VO
473 }
474 }
475
476 return 0;
477}
f9bbe447 478
c64b9c05 479static void dsa_tag_8021q_teardown(struct dsa_switch *ds)
ac02a451 480{
c64b9c05 481 int port;
ac02a451 482
c64b9c05 483 ASSERT_RTNL();
ac02a451 484
c64b9c05
VO
485 for (port = 0; port < ds->num_ports; port++)
486 dsa_tag_8021q_port_teardown(ds, port);
ac02a451 487}
ac02a451 488
5da11eb4 489int dsa_tag_8021q_register(struct dsa_switch *ds, __be16 proto)
cedf4670
VO
490{
491 struct dsa_8021q_context *ctx;
492
493 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
494 if (!ctx)
d7b1fd52 495 return -ENOMEM;
cedf4670 496
cedf4670
VO
497 ctx->proto = proto;
498 ctx->ds = ds;
499
c64b9c05 500 INIT_LIST_HEAD(&ctx->vlans);
cedf4670 501
d7b1fd52
VO
502 ds->tag_8021q_ctx = ctx;
503
c64b9c05 504 return dsa_tag_8021q_setup(ds);
cedf4670
VO
505}
506EXPORT_SYMBOL_GPL(dsa_tag_8021q_register);
507
d7b1fd52 508void dsa_tag_8021q_unregister(struct dsa_switch *ds)
cedf4670 509{
d7b1fd52 510 struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
c64b9c05 511 struct dsa_tag_8021q_vlan *v, *n;
328621f6 512
c64b9c05 513 dsa_tag_8021q_teardown(ds);
cedf4670 514
c64b9c05
VO
515 list_for_each_entry_safe(v, n, &ctx->vlans, list) {
516 list_del(&v->list);
517 kfree(v);
cedf4670
VO
518 }
519
d7b1fd52
VO
520 ds->tag_8021q_ctx = NULL;
521
cedf4670
VO
522 kfree(ctx);
523}
524EXPORT_SYMBOL_GPL(dsa_tag_8021q_unregister);
525
f9bbe447
VO
526struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
527 u16 tpid, u16 tci)
528{
529 /* skb->data points at skb_mac_header, which
530 * is fine for vlan_insert_tag.
531 */
532 return vlan_insert_tag(skb, htons(tpid), tci);
533}
534EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
535
0fac6aa0 536void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id)
233697b3
VO
537{
538 u16 vid, tci;
539
233697b3
VO
540 if (skb_vlan_tag_present(skb)) {
541 tci = skb_vlan_tag_get(skb);
542 __vlan_hwaccel_clear_tag(skb);
543 } else {
c8620335 544 skb_push_rcsum(skb, ETH_HLEN);
233697b3 545 __skb_vlan_pop(skb, &tci);
c8620335 546 skb_pull_rcsum(skb, ETH_HLEN);
233697b3 547 }
233697b3
VO
548
549 vid = tci & VLAN_VID_MASK;
550
551 *source_port = dsa_8021q_rx_source_port(vid);
552 *switch_id = dsa_8021q_rx_switch_id(vid);
233697b3
VO
553 skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
554}
555EXPORT_SYMBOL_GPL(dsa_8021q_rcv);