Skip to content

Commit c3bc6de

Browse files
committed
Merge branch 'Fixes-for-DSA-tagging-using-802-1Q'
Vladimir Oltean says: ==================== Fixes for DSA tagging using 802.1Q During the prototyping for the "Decoupling PHYLINK from struct net_device" patchset, the CPU port of the sja1105 driver was moved to a different spot. This uncovered an issue in the tag_8021q DSA code, which used to work by mistake - the CPU port was the last hardware port numerically, and this was masking an ordering issue which is very likely to be seen in other drivers that make use of 802.1Q tags. A question was also raised whether the VID numbers bear any meaning, and the conclusion was that they don't, at least not in an absolute sense. The second patch defines bit fields inside the DSA 802.1Q VID so that tcpdump can decode it unambiguously (although the meaning is now clear even by visual inspection). ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 2180843 + 0471dd4 commit c3bc6de

File tree

1 file changed

+65
-14
lines changed

1 file changed

+65
-14
lines changed

net/dsa/tag_8021q.c

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,59 @@
1111

1212
#include "dsa_priv.h"
1313

14-
/* Allocating two VLAN tags per port - one for the RX VID and
15-
* the other for the TX VID - see below
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+
* +-----------+-----+-----------------+-----------+-----------------------+
19+
* | DIR | RSV | SWITCH_ID | RSV | PORT |
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+
*
29+
* RSV - VID[9]:
30+
* To be used for further expansion of SWITCH_ID or for other purposes.
31+
*
32+
* SWITCH_ID - VID[8:6]:
33+
* Index of switch within DSA tree. Must be between 0 and
34+
* DSA_MAX_SWITCHES - 1.
35+
*
36+
* RSV - VID[5:4]:
37+
* To be used for further expansion of PORT or for other purposes.
38+
*
39+
* PORT - VID[3:0]:
40+
* Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1.
1641
*/
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)
42+
43+
#define DSA_8021Q_DIR_SHIFT 10
44+
#define DSA_8021Q_DIR_MASK GENMASK(11, 10)
45+
#define DSA_8021Q_DIR(x) (((x) << DSA_8021Q_DIR_SHIFT) & \
46+
DSA_8021Q_DIR_MASK)
47+
#define DSA_8021Q_DIR_RX DSA_8021Q_DIR(1)
48+
#define DSA_8021Q_DIR_TX DSA_8021Q_DIR(2)
49+
50+
#define DSA_8021Q_SWITCH_ID_SHIFT 6
51+
#define DSA_8021Q_SWITCH_ID_MASK GENMASK(8, 6)
52+
#define DSA_8021Q_SWITCH_ID(x) (((x) << DSA_8021Q_SWITCH_ID_SHIFT) & \
53+
DSA_8021Q_SWITCH_ID_MASK)
54+
55+
#define DSA_8021Q_PORT_SHIFT 0
56+
#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
57+
#define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \
58+
DSA_8021Q_PORT_MASK)
2159

2260
/* Returns the VID to be inserted into the frame from xmit for switch steering
2361
* instructions on egress. Encodes switch ID and port ID.
2462
*/
2563
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
2664
{
27-
return DSA_8021Q_TX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
65+
return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(ds->index) |
66+
DSA_8021Q_PORT(port);
2867
}
2968
EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
3069

@@ -33,21 +72,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
3372
*/
3473
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
3574
{
36-
return DSA_8021Q_RX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
75+
return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(ds->index) |
76+
DSA_8021Q_PORT(port);
3777
}
3878
EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid);
3979

4080
/* Returns the decoded switch ID from the RX VID. */
4181
int dsa_8021q_rx_switch_id(u16 vid)
4282
{
43-
return ((vid - DSA_8021Q_RX_VID_BASE) / DSA_MAX_PORTS);
83+
return (vid & DSA_8021Q_SWITCH_ID_MASK) >> DSA_8021Q_SWITCH_ID_SHIFT;
4484
}
4585
EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);
4686

4787
/* Returns the decoded port ID from the RX VID. */
4888
int dsa_8021q_rx_source_port(u16 vid)
4989
{
50-
return ((vid - DSA_8021Q_RX_VID_BASE) % DSA_MAX_PORTS);
90+
return (vid & DSA_8021Q_PORT_MASK) >> DSA_8021Q_PORT_SHIFT;
5191
}
5292
EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
5393

@@ -128,10 +168,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
128168
u16 flags;
129169

130170
if (i == upstream)
131-
/* CPU port needs to see this port's RX VID
132-
* as tagged egress.
133-
*/
134-
flags = 0;
171+
continue;
135172
else if (i == port)
136173
/* The RX VID is pvid on this port */
137174
flags = BRIDGE_VLAN_INFO_UNTAGGED |
@@ -150,6 +187,20 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
150187
return err;
151188
}
152189
}
190+
191+
/* CPU port needs to see this port's RX VID
192+
* as tagged egress.
193+
*/
194+
if (enabled)
195+
err = dsa_port_vid_add(upstream_dp, rx_vid, 0);
196+
else
197+
err = dsa_port_vid_del(upstream_dp, rx_vid);
198+
if (err) {
199+
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n",
200+
rx_vid, port, err);
201+
return err;
202+
}
203+
153204
/* Finally apply the TX VID on this port and on the CPU port */
154205
if (enabled)
155206
err = dsa_port_vid_add(dp, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED);

0 commit comments

Comments
 (0)