hc
2024-01-31 f9004dbfff8a3fbbd7e2a88c8a4327c7f2f8e5b2
kernel/net/bridge/br.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Generic parts
34 * Linux ethernet bridge
45 *
56 * Authors:
67 * Lennert Buytenhek <buytenh@gnu.org>
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License
10
- * as published by the Free Software Foundation; either version
11
- * 2 of the License, or (at your option) any later version.
128 */
139
1410 #include <linux/module.h>
....@@ -31,6 +27,8 @@
3127 */
3228 static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
3329 {
30
+ struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
31
+ struct netdev_notifier_pre_changeaddr_info *prechaddr_info;
3432 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
3533 struct net_bridge_port *p;
3634 struct net_bridge *br;
....@@ -38,10 +36,19 @@
3836 bool changed_addr;
3937 int err;
4038
41
- /* register of bridge completed, add sysfs entries */
42
- if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) {
43
- br_sysfs_addbr(dev);
44
- return NOTIFY_DONE;
39
+ if (dev->priv_flags & IFF_EBRIDGE) {
40
+ err = br_vlan_bridge_event(dev, event, ptr);
41
+ if (err)
42
+ return notifier_from_errno(err);
43
+
44
+ if (event == NETDEV_REGISTER) {
45
+ /* register of bridge completed, add sysfs entries */
46
+ err = br_sysfs_addbr(dev);
47
+ if (err)
48
+ return notifier_from_errno(err);
49
+
50
+ return NOTIFY_DONE;
51
+ }
4552 }
4653
4754 /* not a port of a bridge */
....@@ -54,6 +61,17 @@
5461 switch (event) {
5562 case NETDEV_CHANGEMTU:
5663 br_mtu_auto_adjust(br);
64
+ break;
65
+
66
+ case NETDEV_PRE_CHANGEADDR:
67
+ if (br->dev->addr_assign_type == NET_ADDR_SET)
68
+ break;
69
+ prechaddr_info = ptr;
70
+ err = dev_pre_changeaddr_notify(br->dev,
71
+ prechaddr_info->dev_addr,
72
+ extack);
73
+ if (err)
74
+ return notifier_from_errno(err);
5775 break;
5876
5977 case NETDEV_CHANGEADDR:
....@@ -113,6 +131,9 @@
113131 break;
114132 }
115133
134
+ if (event != NETDEV_UNREGISTER)
135
+ br_vlan_port_event(p, event);
136
+
116137 /* Events that may cause spanning tree to refresh */
117138 if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
118139 event == NETDEV_CHANGE || event == NETDEV_DOWN))
....@@ -151,7 +172,7 @@
151172 break;
152173 }
153174 br_fdb_offloaded_set(br, p, fdb_info->addr,
154
- fdb_info->vid);
175
+ fdb_info->vid, true);
155176 break;
156177 case SWITCHDEV_FDB_DEL_TO_BRIDGE:
157178 fdb_info = ptr;
....@@ -163,7 +184,12 @@
163184 case SWITCHDEV_FDB_OFFLOADED:
164185 fdb_info = ptr;
165186 br_fdb_offloaded_set(br, p, fdb_info->addr,
166
- fdb_info->vid);
187
+ fdb_info->vid, fdb_info->offloaded);
188
+ break;
189
+ case SWITCHDEV_FDB_FLUSH_TO_BRIDGE:
190
+ fdb_info = ptr;
191
+ /* Don't delete static entries */
192
+ br_fdb_delete_by_port(br, p, fdb_info->vid, 0);
167193 break;
168194 }
169195
....@@ -174,6 +200,98 @@
174200 static struct notifier_block br_switchdev_notifier = {
175201 .notifier_call = br_switchdev_event,
176202 };
203
+
204
+/* br_boolopt_toggle - change user-controlled boolean option
205
+ *
206
+ * @br: bridge device
207
+ * @opt: id of the option to change
208
+ * @on: new option value
209
+ * @extack: extack for error messages
210
+ *
211
+ * Changes the value of the respective boolean option to @on taking care of
212
+ * any internal option value mapping and configuration.
213
+ */
214
+int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
215
+ struct netlink_ext_ack *extack)
216
+{
217
+ switch (opt) {
218
+ case BR_BOOLOPT_NO_LL_LEARN:
219
+ br_opt_toggle(br, BROPT_NO_LL_LEARN, on);
220
+ break;
221
+ default:
222
+ /* shouldn't be called with unsupported options */
223
+ WARN_ON(1);
224
+ break;
225
+ }
226
+
227
+ return 0;
228
+}
229
+
230
+int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
231
+{
232
+ switch (opt) {
233
+ case BR_BOOLOPT_NO_LL_LEARN:
234
+ return br_opt_get(br, BROPT_NO_LL_LEARN);
235
+ default:
236
+ /* shouldn't be called with unsupported options */
237
+ WARN_ON(1);
238
+ break;
239
+ }
240
+
241
+ return 0;
242
+}
243
+
244
+int br_boolopt_multi_toggle(struct net_bridge *br,
245
+ struct br_boolopt_multi *bm,
246
+ struct netlink_ext_ack *extack)
247
+{
248
+ unsigned long bitmap = bm->optmask;
249
+ int err = 0;
250
+ int opt_id;
251
+
252
+ for_each_set_bit(opt_id, &bitmap, BR_BOOLOPT_MAX) {
253
+ bool on = !!(bm->optval & BIT(opt_id));
254
+
255
+ err = br_boolopt_toggle(br, opt_id, on, extack);
256
+ if (err) {
257
+ br_debug(br, "boolopt multi-toggle error: option: %d current: %d new: %d error: %d\n",
258
+ opt_id, br_boolopt_get(br, opt_id), on, err);
259
+ break;
260
+ }
261
+ }
262
+
263
+ return err;
264
+}
265
+
266
+void br_boolopt_multi_get(const struct net_bridge *br,
267
+ struct br_boolopt_multi *bm)
268
+{
269
+ u32 optval = 0;
270
+ int opt_id;
271
+
272
+ for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
273
+ optval |= (br_boolopt_get(br, opt_id) << opt_id);
274
+
275
+ bm->optval = optval;
276
+ bm->optmask = GENMASK((BR_BOOLOPT_MAX - 1), 0);
277
+}
278
+
279
+/* private bridge options, controlled by the kernel */
280
+void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
281
+{
282
+ bool cur = !!br_opt_get(br, opt);
283
+
284
+ br_debug(br, "toggle option: %d state: %d -> %d\n",
285
+ opt, cur, on);
286
+
287
+ if (cur == on)
288
+ return;
289
+
290
+ if (on)
291
+ set_bit(opt, &br->options);
292
+ else
293
+ clear_bit(opt, &br->options);
294
+}
177295
178296 static void __net_exit br_net_exit(struct net *net)
179297 {
....@@ -202,7 +320,7 @@
202320 {
203321 int err;
204322
205
- BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
323
+ BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > sizeof_field(struct sk_buff, cb));
206324
207325 err = stp_proto_register(&br_stp_proto);
208326 if (err < 0) {