hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/dsa/switch.c
....@@ -1,17 +1,15 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Handling of a single switch chip, part of a switch fabric
34 *
45 * Copyright (c) 2017 Savoir-faire Linux Inc.
56 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
117 */
128
9
+#include <linux/if_bridge.h>
1310 #include <linux/netdevice.h>
1411 #include <linux/notifier.h>
12
+#include <linux/if_vlan.h>
1513 #include <net/switchdev.h>
1614
1715 #include "dsa_priv.h"
....@@ -22,7 +20,7 @@
2220 int i;
2321
2422 for (i = 0; i < ds->num_ports; ++i) {
25
- struct dsa_port *dp = &ds->ports[i];
23
+ struct dsa_port *dp = dsa_to_port(ds, i);
2624
2725 if (dp->ageing_time && dp->ageing_time < ageing_time)
2826 ageing_time = dp->ageing_time;
....@@ -54,14 +52,53 @@
5452 return 0;
5553 }
5654
55
+static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
56
+ struct dsa_notifier_mtu_info *info)
57
+{
58
+ if (ds->index == info->sw_index)
59
+ return (port == info->port) || dsa_is_dsa_port(ds, port);
60
+
61
+ if (!info->propagate_upstream)
62
+ return false;
63
+
64
+ if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
65
+ return true;
66
+
67
+ return false;
68
+}
69
+
70
+static int dsa_switch_mtu(struct dsa_switch *ds,
71
+ struct dsa_notifier_mtu_info *info)
72
+{
73
+ int port, ret;
74
+
75
+ if (!ds->ops->port_change_mtu)
76
+ return -EOPNOTSUPP;
77
+
78
+ for (port = 0; port < ds->num_ports; port++) {
79
+ if (dsa_switch_mtu_match(ds, port, info)) {
80
+ ret = ds->ops->port_change_mtu(ds, port, info->mtu);
81
+ if (ret)
82
+ return ret;
83
+ }
84
+ }
85
+
86
+ return 0;
87
+}
88
+
5789 static int dsa_switch_bridge_join(struct dsa_switch *ds,
5890 struct dsa_notifier_bridge_info *info)
5991 {
60
- if (ds->index == info->sw_index && ds->ops->port_bridge_join)
92
+ struct dsa_switch_tree *dst = ds->dst;
93
+
94
+ if (dst->index == info->tree_index && ds->index == info->sw_index &&
95
+ ds->ops->port_bridge_join)
6196 return ds->ops->port_bridge_join(ds, info->port, info->br);
6297
63
- if (ds->index != info->sw_index && ds->ops->crosschip_bridge_join)
64
- return ds->ops->crosschip_bridge_join(ds, info->sw_index,
98
+ if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
99
+ ds->ops->crosschip_bridge_join)
100
+ return ds->ops->crosschip_bridge_join(ds, info->tree_index,
101
+ info->sw_index,
65102 info->port, info->br);
66103
67104 return 0;
....@@ -70,13 +107,52 @@
70107 static int dsa_switch_bridge_leave(struct dsa_switch *ds,
71108 struct dsa_notifier_bridge_info *info)
72109 {
73
- if (ds->index == info->sw_index && ds->ops->port_bridge_leave)
110
+ bool unset_vlan_filtering = br_vlan_enabled(info->br);
111
+ struct dsa_switch_tree *dst = ds->dst;
112
+ int err, i;
113
+
114
+ if (dst->index == info->tree_index && ds->index == info->sw_index &&
115
+ ds->ops->port_bridge_leave)
74116 ds->ops->port_bridge_leave(ds, info->port, info->br);
75117
76
- if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave)
77
- ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
118
+ if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
119
+ ds->ops->crosschip_bridge_leave)
120
+ ds->ops->crosschip_bridge_leave(ds, info->tree_index,
121
+ info->sw_index, info->port,
78122 info->br);
79123
124
+ /* If the bridge was vlan_filtering, the bridge core doesn't trigger an
125
+ * event for changing vlan_filtering setting upon slave ports leaving
126
+ * it. That is a good thing, because that lets us handle it and also
127
+ * handle the case where the switch's vlan_filtering setting is global
128
+ * (not per port). When that happens, the correct moment to trigger the
129
+ * vlan_filtering callback is only when the last port left this bridge.
130
+ */
131
+ if (unset_vlan_filtering && ds->vlan_filtering_is_global) {
132
+ for (i = 0; i < ds->num_ports; i++) {
133
+ if (i == info->port)
134
+ continue;
135
+ if (dsa_to_port(ds, i)->bridge_dev == info->br) {
136
+ unset_vlan_filtering = false;
137
+ break;
138
+ }
139
+ }
140
+ }
141
+ if (unset_vlan_filtering) {
142
+ struct switchdev_trans trans;
143
+
144
+ trans.ph_prepare = true;
145
+ err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
146
+ false, &trans);
147
+ if (err && err != EOPNOTSUPP)
148
+ return err;
149
+
150
+ trans.ph_prepare = false;
151
+ err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
152
+ false, &trans);
153
+ if (err && err != EOPNOTSUPP)
154
+ return err;
155
+ }
80156 return 0;
81157 }
82158
....@@ -102,57 +178,51 @@
102178 return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
103179 }
104180
105
-static int
106
-dsa_switch_mdb_prepare_bitmap(struct dsa_switch *ds,
107
- const struct switchdev_obj_port_mdb *mdb,
108
- const unsigned long *bitmap)
181
+static bool dsa_switch_mdb_match(struct dsa_switch *ds, int port,
182
+ struct dsa_notifier_mdb_info *info)
183
+{
184
+ if (ds->index == info->sw_index && port == info->port)
185
+ return true;
186
+
187
+ if (dsa_is_dsa_port(ds, port))
188
+ return true;
189
+
190
+ return false;
191
+}
192
+
193
+static int dsa_switch_mdb_prepare(struct dsa_switch *ds,
194
+ struct dsa_notifier_mdb_info *info)
109195 {
110196 int port, err;
111197
112198 if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
113199 return -EOPNOTSUPP;
114200
115
- for_each_set_bit(port, bitmap, ds->num_ports) {
116
- err = ds->ops->port_mdb_prepare(ds, port, mdb);
117
- if (err)
118
- return err;
201
+ for (port = 0; port < ds->num_ports; port++) {
202
+ if (dsa_switch_mdb_match(ds, port, info)) {
203
+ err = ds->ops->port_mdb_prepare(ds, port, info->mdb);
204
+ if (err)
205
+ return err;
206
+ }
119207 }
120208
121209 return 0;
122210 }
123211
124
-static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds,
125
- const struct switchdev_obj_port_mdb *mdb,
126
- const unsigned long *bitmap)
127
-{
128
- int port;
129
-
130
- if (!ds->ops->port_mdb_add)
131
- return;
132
-
133
- for_each_set_bit(port, bitmap, ds->num_ports)
134
- ds->ops->port_mdb_add(ds, port, mdb);
135
-}
136
-
137212 static int dsa_switch_mdb_add(struct dsa_switch *ds,
138213 struct dsa_notifier_mdb_info *info)
139214 {
140
- const struct switchdev_obj_port_mdb *mdb = info->mdb;
141
- struct switchdev_trans *trans = info->trans;
142215 int port;
143216
144
- /* Build a mask of Multicast group members */
145
- bitmap_zero(ds->bitmap, ds->num_ports);
146
- if (ds->index == info->sw_index)
147
- set_bit(info->port, ds->bitmap);
217
+ if (switchdev_trans_ph_prepare(info->trans))
218
+ return dsa_switch_mdb_prepare(ds, info);
219
+
220
+ if (!ds->ops->port_mdb_add)
221
+ return 0;
222
+
148223 for (port = 0; port < ds->num_ports; port++)
149
- if (dsa_is_dsa_port(ds, port))
150
- set_bit(port, ds->bitmap);
151
-
152
- if (switchdev_trans_ph_prepare(trans))
153
- return dsa_switch_mdb_prepare_bitmap(ds, mdb, ds->bitmap);
154
-
155
- dsa_switch_mdb_add_bitmap(ds, mdb, ds->bitmap);
224
+ if (dsa_switch_mdb_match(ds, port, info))
225
+ ds->ops->port_mdb_add(ds, port, info->mdb);
156226
157227 return 0;
158228 }
....@@ -160,66 +230,60 @@
160230 static int dsa_switch_mdb_del(struct dsa_switch *ds,
161231 struct dsa_notifier_mdb_info *info)
162232 {
163
- const struct switchdev_obj_port_mdb *mdb = info->mdb;
164
-
165233 if (!ds->ops->port_mdb_del)
166234 return -EOPNOTSUPP;
167235
168236 if (ds->index == info->sw_index)
169
- return ds->ops->port_mdb_del(ds, info->port, mdb);
237
+ return ds->ops->port_mdb_del(ds, info->port, info->mdb);
170238
171239 return 0;
172240 }
173241
174
-static int
175
-dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds,
176
- const struct switchdev_obj_port_vlan *vlan,
177
- const unsigned long *bitmap)
242
+static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
243
+ struct dsa_notifier_vlan_info *info)
244
+{
245
+ if (ds->index == info->sw_index && port == info->port)
246
+ return true;
247
+
248
+ if (dsa_is_dsa_port(ds, port))
249
+ return true;
250
+
251
+ return false;
252
+}
253
+
254
+static int dsa_switch_vlan_prepare(struct dsa_switch *ds,
255
+ struct dsa_notifier_vlan_info *info)
178256 {
179257 int port, err;
180258
181259 if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
182260 return -EOPNOTSUPP;
183261
184
- for_each_set_bit(port, bitmap, ds->num_ports) {
185
- err = ds->ops->port_vlan_prepare(ds, port, vlan);
186
- if (err)
187
- return err;
262
+ for (port = 0; port < ds->num_ports; port++) {
263
+ if (dsa_switch_vlan_match(ds, port, info)) {
264
+ err = ds->ops->port_vlan_prepare(ds, port, info->vlan);
265
+ if (err)
266
+ return err;
267
+ }
188268 }
189269
190270 return 0;
191271 }
192272
193
-static void
194
-dsa_switch_vlan_add_bitmap(struct dsa_switch *ds,
195
- const struct switchdev_obj_port_vlan *vlan,
196
- const unsigned long *bitmap)
197
-{
198
- int port;
199
-
200
- for_each_set_bit(port, bitmap, ds->num_ports)
201
- ds->ops->port_vlan_add(ds, port, vlan);
202
-}
203
-
204273 static int dsa_switch_vlan_add(struct dsa_switch *ds,
205274 struct dsa_notifier_vlan_info *info)
206275 {
207
- const struct switchdev_obj_port_vlan *vlan = info->vlan;
208
- struct switchdev_trans *trans = info->trans;
209276 int port;
210277
211
- /* Build a mask of VLAN members */
212
- bitmap_zero(ds->bitmap, ds->num_ports);
213
- if (ds->index == info->sw_index)
214
- set_bit(info->port, ds->bitmap);
278
+ if (switchdev_trans_ph_prepare(info->trans))
279
+ return dsa_switch_vlan_prepare(ds, info);
280
+
281
+ if (!ds->ops->port_vlan_add)
282
+ return 0;
283
+
215284 for (port = 0; port < ds->num_ports; port++)
216
- if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
217
- set_bit(port, ds->bitmap);
218
-
219
- if (switchdev_trans_ph_prepare(trans))
220
- return dsa_switch_vlan_prepare_bitmap(ds, vlan, ds->bitmap);
221
-
222
- dsa_switch_vlan_add_bitmap(ds, vlan, ds->bitmap);
285
+ if (dsa_switch_vlan_match(ds, port, info))
286
+ ds->ops->port_vlan_add(ds, port, info->vlan);
223287
224288 return 0;
225289 }
....@@ -227,14 +291,15 @@
227291 static int dsa_switch_vlan_del(struct dsa_switch *ds,
228292 struct dsa_notifier_vlan_info *info)
229293 {
230
- const struct switchdev_obj_port_vlan *vlan = info->vlan;
231
-
232294 if (!ds->ops->port_vlan_del)
233295 return -EOPNOTSUPP;
234296
235297 if (ds->index == info->sw_index)
236
- return ds->ops->port_vlan_del(ds, info->port, vlan);
298
+ return ds->ops->port_vlan_del(ds, info->port, info->vlan);
237299
300
+ /* Do not deprogram the DSA links as they may be used as conduit
301
+ * for other VLAN members in the fabric.
302
+ */
238303 return 0;
239304 }
240305
....@@ -272,6 +337,9 @@
272337 case DSA_NOTIFIER_VLAN_DEL:
273338 err = dsa_switch_vlan_del(ds, info);
274339 break;
340
+ case DSA_NOTIFIER_MTU:
341
+ err = dsa_switch_mtu(ds, info);
342
+ break;
275343 default:
276344 err = -EOPNOTSUPP;
277345 break;