13cc8f3d696965c450707c8041f4189c1e1dea59
[openwrt/openwrt.git] /
1 From 675992be6f7b603b8cfda4678f173e1021fc1ab6 Mon Sep 17 00:00:00 2001
2 From: Vladimir Oltean <vladimir.oltean@nxp.com>
3 Date: Thu, 7 Oct 2021 19:47:10 +0300
4 Subject: [PATCH] net: dsa: mv88e6xxx: keep the pvid at 0 when VLAN-unaware
5
6 The VLAN support in mv88e6xxx has a loaded history. Commit 2ea7a679ca2a
7 ("net: dsa: Don't add vlans when vlan filtering is disabled") noticed
8 some issues with VLAN and decided the best way to deal with them was to
9 make the DSA core ignore VLANs added by the bridge while VLAN awareness
10 is turned off. Those issues were never explained, just presented as
11 "at least one corner case".
12
13 That approach had problems of its own, presented by
14 commit 54a0ed0df496 ("net: dsa: provide an option for drivers to always
15 receive bridge VLANs") for the DSA core, followed by
16 commit 1fb74191988f ("net: dsa: mv88e6xxx: fix vlan setup") which
17 applied ds->configure_vlan_while_not_filtering = true for mv88e6xxx in
18 particular.
19
20 We still don't know what corner case Andrew saw when he wrote
21 commit 2ea7a679ca2a ("net: dsa: Don't add vlans when vlan filtering is
22 disabled"), but Tobias now reports that when we use TX forwarding
23 offload, pinging an external station from the bridge device is broken if
24 the front-facing DSA user port has flooding turned off. The full
25 description is in the link below, but for short, when a mv88e6xxx port
26 is under a VLAN-unaware bridge, it inherits that bridge's pvid.
27 So packets ingressing a user port will be classified to e.g. VID 1
28 (assuming that value for the bridge_default_pvid), whereas when
29 tag_dsa.c xmits towards a user port, it always sends packets using a VID
30 of 0 if that port is standalone or under a VLAN-unaware bridge - or at
31 least it did so prior to commit d82f8ab0d874 ("net: dsa: tag_dsa:
32 offload the bridge forwarding process").
33
34 In any case, when there is a conversation between the CPU and a station
35 connected to a user port, the station's MAC address is learned in VID 1
36 but the CPU tries to transmit through VID 0. The packets reach the
37 intended station, but via flooding and not by virtue of matching the
38 existing ATU entry.
39
40 DSA has established (and enforced in other drivers: sja1105, felix,
41 mt7530) that a VLAN-unaware port should use a private pvid, and not
42 inherit the one from the bridge. The bridge's pvid should only be
43 inherited when that bridge is VLAN-aware, so all state transitions need
44 to be handled. On the other hand, all bridge VLANs should sit in the VTU
45 starting with the moment when the bridge offloads them via switchdev,
46 they are just not used.
47
48 This solves the problem that Tobias sees because packets ingressing on
49 VLAN-unaware user ports now get classified to VID 0, which is also the
50 VID used by tag_dsa.c on xmit.
51
52 Fixes: d82f8ab0d874 ("net: dsa: tag_dsa: offload the bridge forwarding process")
53 Link: https://patchwork.kernel.org/project/netdevbpf/patch/20211003222312.284175-2-vladimir.oltean@nxp.com/#24491503
54 Reported-by: Tobias Waldekranz <tobias@waldekranz.com>
55 Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
56 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
57 ---
58 drivers/net/dsa/mv88e6xxx/chip.c | 56 +++++++++++++++++++++++++++++---
59 drivers/net/dsa/mv88e6xxx/chip.h | 6 ++++
60 drivers/net/dsa/mv88e6xxx/port.c | 21 ++++++++++++
61 drivers/net/dsa/mv88e6xxx/port.h | 2 ++
62 4 files changed, 81 insertions(+), 4 deletions(-)
63
64 --- a/drivers/net/dsa/mv88e6xxx/chip.c
65 +++ b/drivers/net/dsa/mv88e6xxx/chip.c
66 @@ -1590,6 +1590,26 @@ static int mv88e6xxx_port_check_hw_vlan(
67 return 0;
68 }
69
70 +static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
71 +{
72 + struct dsa_port *dp = dsa_to_port(chip->ds, port);
73 + struct mv88e6xxx_port *p = &chip->ports[port];
74 + bool drop_untagged = false;
75 + u16 pvid = 0;
76 + int err;
77 +
78 + if (dp->bridge_dev && br_vlan_enabled(dp->bridge_dev)) {
79 + pvid = p->bridge_pvid.vid;
80 + drop_untagged = !p->bridge_pvid.valid;
81 + }
82 +
83 + err = mv88e6xxx_port_set_pvid(chip, port, pvid);
84 + if (err)
85 + return err;
86 +
87 + return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
88 +}
89 +
90 static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
91 bool vlan_filtering,
92 struct switchdev_trans *trans)
93 @@ -1603,7 +1623,16 @@ static int mv88e6xxx_port_vlan_filtering
94 return chip->info->max_vid ? 0 : -EOPNOTSUPP;
95
96 mv88e6xxx_reg_lock(chip);
97 +
98 err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
99 + if (err)
100 + goto unlock;
101 +
102 + err = mv88e6xxx_port_commit_pvid(chip, port);
103 + if (err)
104 + goto unlock;
105 +
106 +unlock:
107 mv88e6xxx_reg_unlock(chip);
108
109 return err;
110 @@ -1986,8 +2015,10 @@ static void mv88e6xxx_port_vlan_add(stru
111 struct mv88e6xxx_chip *chip = ds->priv;
112 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
113 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
114 + struct mv88e6xxx_port *p = &chip->ports[port];
115 bool warn;
116 u8 member;
117 + int err;
118 u16 vid;
119
120 if (!chip->info->max_vid)
121 @@ -2012,9 +2043,23 @@ static void mv88e6xxx_port_vlan_add(stru
122 dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port,
123 vid, untagged ? 'u' : 't');
124
125 - if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end))
126 - dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
127 - vlan->vid_end);
128 + if (pvid) {
129 + p->bridge_pvid.vid = vlan->vid_end;
130 + p->bridge_pvid.valid = true;
131 +
132 + err = mv88e6xxx_port_commit_pvid(chip, port);
133 + if (err)
134 + dev_err(ds->dev, "p%d: failed to set PVID %d", port,
135 + vlan->vid_end);
136 + } else if (vlan->vid_end && p->bridge_pvid.vid == vlan->vid_end) {
137 + /* The old pvid was reinstalled as a non-pvid VLAN */
138 + p->bridge_pvid.valid = false;
139 +
140 + err = mv88e6xxx_port_commit_pvid(chip, port);
141 + if (err)
142 + dev_err(ds->dev, "p%d: failed to unset PVID %d", port,
143 + vlan->vid_end);
144 + }
145
146 mv88e6xxx_reg_unlock(chip);
147 }
148 @@ -2065,6 +2110,7 @@ static int mv88e6xxx_port_vlan_del(struc
149 const struct switchdev_obj_port_vlan *vlan)
150 {
151 struct mv88e6xxx_chip *chip = ds->priv;
152 + struct mv88e6xxx_port *p = &chip->ports[port];
153 u16 pvid, vid;
154 int err = 0;
155
156 @@ -2083,7 +2129,9 @@ static int mv88e6xxx_port_vlan_del(struc
157 goto unlock;
158
159 if (vid == pvid) {
160 - err = mv88e6xxx_port_set_pvid(chip, port, 0);
161 + p->bridge_pvid.valid = false;
162 +
163 + err = mv88e6xxx_port_commit_pvid(chip, port);
164 if (err)
165 goto unlock;
166 }
167 --- a/drivers/net/dsa/mv88e6xxx/chip.h
168 +++ b/drivers/net/dsa/mv88e6xxx/chip.h
169 @@ -224,9 +224,15 @@ struct mv88e6xxx_policy {
170 u16 vid;
171 };
172
173 +struct mv88e6xxx_vlan {
174 + u16 vid;
175 + bool valid;
176 +};
177 +
178 struct mv88e6xxx_port {
179 struct mv88e6xxx_chip *chip;
180 int port;
181 + struct mv88e6xxx_vlan bridge_pvid;
182 u64 serdes_stats[2];
183 u64 atu_member_violation;
184 u64 atu_miss_violation;
185 --- a/drivers/net/dsa/mv88e6xxx/port.c
186 +++ b/drivers/net/dsa/mv88e6xxx/port.c
187 @@ -1062,6 +1062,27 @@ int mv88e6xxx_port_set_8021q_mode(struct
188 return 0;
189 }
190
191 +int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
192 + bool drop_untagged)
193 +{
194 + u16 old, new;
195 + int err;
196 +
197 + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);
198 + if (err)
199 + return err;
200 +
201 + if (drop_untagged)
202 + new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
203 + else
204 + new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
205 +
206 + if (new == old)
207 + return 0;
208 +
209 + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);
210 +}
211 +
212 int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
213 {
214 u16 reg;
215 --- a/drivers/net/dsa/mv88e6xxx/port.h
216 +++ b/drivers/net/dsa/mv88e6xxx/port.h
217 @@ -364,6 +364,8 @@ int mv88e6390x_port_set_cmode(struct mv8
218 phy_interface_t mode);
219 int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
220 int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
221 +int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
222 + bool drop_untagged);
223 int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
224 int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
225 int upstream_port);