Commit 0471dd42 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: tag_8021q: Create a stable binary format

Tools like tcpdump need to be able to decode the significance of fake
VLAN headers that DSA uses to separate switch ports.

But currently these have no global significance - they are simply an
ordered list of DSA_MAX_SWITCHES x DSA_MAX_PORTS numbers ending at 4095.

The reason why this is submitted as a fix is that the existing mapping
of VIDs should not enter into a stable kernel, so we can pretend that
only the new format exists. This way tcpdump won't need to try to make
something out of the VLAN tags on 5.2 kernels.

Fixes: f9bbe447 ("net: dsa: Optional VLAN-based port separation for switches without tagging")
Signed-off-by: default avatarVladimir Oltean <olteanv@gmail.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d34d2baa
...@@ -11,20 +11,59 @@ ...@@ -11,20 +11,59 @@
#include "dsa_priv.h" #include "dsa_priv.h"
/* Allocating two VLAN tags per port - one for the RX VID and /* Binary structure of the fake 12-bit VID field (when the TPID is
* the other for the TX VID - see below * ETH_P_DSA_8021Q):
*
* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* +-----------+-----+-----------------+-----------+-----------------------+
* | DIR | RSV | SWITCH_ID | RSV | PORT |
* +-----------+-----+-----------------+-----------+-----------------------+
*
* DIR - VID[11:10]:
* Direction flags.
* * 1 (0b01) for RX VLAN,
* * 2 (0b10) for TX VLAN.
* These values make the special VIDs of 0, 1 and 4095 to be left
* unused by this coding scheme.
*
* RSV - VID[9]:
* To be used for further expansion of SWITCH_ID or for other purposes.
*
* SWITCH_ID - VID[8:6]:
* Index of switch within DSA tree. Must be between 0 and
* DSA_MAX_SWITCHES - 1.
*
* RSV - VID[5:4]:
* To be used for further expansion of PORT or for other purposes.
*
* PORT - VID[3:0]:
* Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1.
*/ */
#define DSA_8021Q_VID_RANGE (DSA_MAX_SWITCHES * DSA_MAX_PORTS)
#define DSA_8021Q_VID_BASE (VLAN_N_VID - 2 * DSA_8021Q_VID_RANGE - 1) #define DSA_8021Q_DIR_SHIFT 10
#define DSA_8021Q_RX_VID_BASE (DSA_8021Q_VID_BASE) #define DSA_8021Q_DIR_MASK GENMASK(11, 10)
#define DSA_8021Q_TX_VID_BASE (DSA_8021Q_VID_BASE + DSA_8021Q_VID_RANGE) #define DSA_8021Q_DIR(x) (((x) << DSA_8021Q_DIR_SHIFT) & \
DSA_8021Q_DIR_MASK)
#define DSA_8021Q_DIR_RX DSA_8021Q_DIR(1)
#define DSA_8021Q_DIR_TX DSA_8021Q_DIR(2)
#define DSA_8021Q_SWITCH_ID_SHIFT 6
#define DSA_8021Q_SWITCH_ID_MASK GENMASK(8, 6)
#define DSA_8021Q_SWITCH_ID(x) (((x) << DSA_8021Q_SWITCH_ID_SHIFT) & \
DSA_8021Q_SWITCH_ID_MASK)
#define DSA_8021Q_PORT_SHIFT 0
#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
#define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \
DSA_8021Q_PORT_MASK)
/* Returns the VID to be inserted into the frame from xmit for switch steering /* Returns the VID to be inserted into the frame from xmit for switch steering
* instructions on egress. Encodes switch ID and port ID. * instructions on egress. Encodes switch ID and port ID.
*/ */
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port) u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
{ {
return DSA_8021Q_TX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port; return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
} }
EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid); EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
...@@ -33,21 +72,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid); ...@@ -33,21 +72,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
*/ */
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port) u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
{ {
return DSA_8021Q_RX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port; return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
} }
EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid); EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid);
/* Returns the decoded switch ID from the RX VID. */ /* Returns the decoded switch ID from the RX VID. */
int dsa_8021q_rx_switch_id(u16 vid) int dsa_8021q_rx_switch_id(u16 vid)
{ {
return ((vid - DSA_8021Q_RX_VID_BASE) / DSA_MAX_PORTS); return (vid & DSA_8021Q_SWITCH_ID_MASK) >> DSA_8021Q_SWITCH_ID_SHIFT;
} }
EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id); EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);
/* Returns the decoded port ID from the RX VID. */ /* Returns the decoded port ID from the RX VID. */
int dsa_8021q_rx_source_port(u16 vid) int dsa_8021q_rx_source_port(u16 vid)
{ {
return ((vid - DSA_8021Q_RX_VID_BASE) % DSA_MAX_PORTS); return (vid & DSA_8021Q_PORT_MASK) >> DSA_8021Q_PORT_SHIFT;
} }
EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port); EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment