-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy path0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch
More file actions
141 lines (125 loc) · 4.57 KB
/
Copy path0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch
File metadata and controls
141 lines (125 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
From baeccc8d6402fca534a9706e1343e35bd04eb505 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 12 Feb 2025 22:03:14 +0100
Subject: [PATCH 27/50] net: dsa: mv88e6xxx: Only activate LAG offloading when
bridged
The current port isolation scheme for mv88e6xxx is detailed here:
https://lore.kernel.org/netdev/20220203101657.990241-1-tobias@waldekranz.com/
As it turns out, this is not compatible with LAGs. Consider the
following setup:
.-----.
| CPU |
'--+--'
|
.--0--. .-----.
| sw1 9---0 sw2 |
'-----' '-4-5-'
A LAG is created from sw2p{4,5}, using ID 0, but it is not attached
to any bridge - so port isolation is active. Let's walk through a
packet's journey to the CPU:
1. Packet ingresses sw2p4, the MapDA bit is not set, so it is flooded
according to the PVT, which only contains sw2p0
2. Packet egresses sw2p0 with FORWARD vid:0 dev:2 port:0(lag)
3. Packet ingresses sw1p9, the VTU policy bit is set for VLAN 0, thus
the packet is classified as MGMT and trapped to the CPU
4. Packet egresses sw1p0 with TO_CPU vid:0 dev:2 port:0
5. Packet ingresses CPU, since no user port is mapped to sw2p0 the
packet is dropped
The problem is that in step 2, the original source port information is
lost (replaced with "lag 0"), and then sw1 rewrites the ingressing
FORWARD to a TO_CPU, which does not have a LAG bit. As a result, after
the translation between steps 3 and 4, it now looks as if the packet
originally ingressed on sw2p0.
Therefore, defer enabling the LAG offload until it joins a bridge. In
the example above, it means that the original source port (sw2p4)
information will be in the FORWARD sent in step 2, which allows the
existing port isolation to work as intended.
Before joining a bridge, the offload does not offer any performance
benefit anyway. All ingressing packet will always have to go to the
CPU; egress traffic always relies on software hashing.
---
drivers/net/dsa/mv88e6xxx/chip.c | 42 +++++++++++++++-----------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 161ce87a8871..d379799c0a16 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3058,6 +3058,7 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ unsigned int lagid;
int err;
mv88e6xxx_reg_lock(chip);
@@ -3066,6 +3067,13 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
if (err)
goto unlock;
+ if ((lagid = dsa_port_lag_id_get(dsa_to_port(ds, port)))) {
+ /* DSA LAG IDs are one-based */
+ err = mv88e6xxx_port_set_trunk(chip, port, true, lagid - 1);
+ if (err)
+ goto unlock;
+ }
+
err = mv88e6xxx_port_set_map_da(chip, port, true);
if (err)
goto unlock;
@@ -3110,6 +3118,14 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
"port %d failed to restore map-DA: %pe\n",
port, ERR_PTR(err));
+ if (dsa_port_lag_id_get(dsa_to_port(ds, port))) {
+ err = mv88e6xxx_port_set_trunk(chip, port, false, 0);
+ if (err)
+ dev_err(ds->dev,
+ "port %d failed to disable trunking: %pe\n",
+ port, ERR_PTR(err));
+ }
+
err = mv88e6xxx_port_commit_pvid(chip, port);
if (err)
dev_err(ds->dev,
@@ -7066,30 +7082,13 @@ static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack)
{
struct mv88e6xxx_chip *chip = ds->priv;
- int err, id;
+ int err;
if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
return -EOPNOTSUPP;
- /* DSA LAG IDs are one-based */
- id = lag.id - 1;
-
mv88e6xxx_reg_lock(chip);
-
- err = mv88e6xxx_port_set_trunk(chip, port, true, id);
- if (err)
- goto err_unlock;
-
err = mv88e6xxx_lag_sync_masks_map(ds, lag);
- if (err)
- goto err_clear_trunk;
-
- mv88e6xxx_reg_unlock(chip);
- return 0;
-
-err_clear_trunk:
- mv88e6xxx_port_set_trunk(chip, port, false, 0);
-err_unlock:
mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -7098,13 +7097,12 @@ static int mv88e6xxx_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag)
{
struct mv88e6xxx_chip *chip = ds->priv;
- int err_sync, err_trunk;
+ int err;
mv88e6xxx_reg_lock(chip);
- err_sync = mv88e6xxx_lag_sync_masks_map(ds, lag);
- err_trunk = mv88e6xxx_port_set_trunk(chip, port, false, 0);
+ err = mv88e6xxx_lag_sync_masks_map(ds, lag);
mv88e6xxx_reg_unlock(chip);
- return err_sync ? : err_trunk;
+ return err;
}
static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,