summaryrefslogtreecommitdiffstats
path: root/net/dsa/tag_dsa.c
diff options
context:
space:
mode:
authorTobias Waldekranz <tobias@waldekranz.com>2021-01-13 09:42:55 +0100
committerJakub Kicinski <kuba@kernel.org>2021-01-14 17:11:56 -0800
commit5b60dadb71db7df94b824a0fab20acc1eabb9050 (patch)
tree5ed24f6e4f8e303577b29b6c83b8efa36eed6e1f /net/dsa/tag_dsa.c
parent57e661aae6a823140787dbcc34d92e223e2f71c5 (diff)
downloadlinux-5b60dadb71db7df94b824a0fab20acc1eabb9050.tar.bz2
net: dsa: tag_dsa: Support reception of packets from LAG devices
Packets ingressing on a LAG that egress on the CPU port, which are not classified as management, will have a FORWARD tag that does not contain the normal source device/port tuple. Instead the trunk bit will be set, and the port field holds the LAG id. Since the exact source port information is not available in the tag, frames are injected directly on the LAG interface and thus do never pass through any DSA port interface on ingress. Management frames (TO_CPU) are not affected and will pass through the DSA port interface as usual. Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/dsa/tag_dsa.c')
-rw-r--r--net/dsa/tag_dsa.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 112c7c6dd568..7e7b7decdf39 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -163,6 +163,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
u8 extra)
{
int source_device, source_port;
+ bool trunk = false;
enum dsa_code code;
enum dsa_cmd cmd;
u8 *dsa_header;
@@ -174,6 +175,8 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
switch (cmd) {
case DSA_CMD_FORWARD:
skb->offload_fwd_mark = 1;
+
+ trunk = !!(dsa_header[1] & 7);
break;
case DSA_CMD_TO_CPU:
@@ -216,7 +219,19 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
source_device = dsa_header[0] & 0x1f;
source_port = (dsa_header[1] >> 3) & 0x1f;
- skb->dev = dsa_master_find_slave(dev, source_device, source_port);
+ if (trunk) {
+ struct dsa_port *cpu_dp = dev->dsa_ptr;
+
+ /* The exact source port is not available in the tag,
+ * so we inject the frame directly on the upper
+ * team/bond.
+ */
+ skb->dev = dsa_lag_dev(cpu_dp->dst, source_port);
+ } else {
+ skb->dev = dsa_master_find_slave(dev, source_device,
+ source_port);
+ }
+
if (!skb->dev)
return NULL;