blob: 1fac72cc617ff7e1851b715860a95e9a1247b9b1 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Generic parts
4 * Linux ethernet bridge
5 *
6 * Authors:
7 * Lennert Buytenhek <buytenh@gnu.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/netdevice.h>
13#include <linux/etherdevice.h>
14#include <linux/init.h>
Stephen Hemmingercf0f02d2006-03-20 22:59:06 -080015#include <linux/llc.h>
16#include <net/llc.h>
Patrick McHardy7c85fbf2008-07-05 21:25:56 -070017#include <net/stp.h>
Jiri Pirko3aeb6612015-01-15 23:49:37 +010018#include <net/switchdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20#include "br_private.h"
21
Cong Wangb1282722014-05-20 17:30:00 -070022/*
23 * Handle changes in state of network devices enslaved to a bridge.
24 *
25 * Note: don't care about up/down if bridge itself is down, because
26 * port state is checked when bridge is brought up.
27 */
28static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
29{
Petr Machatab89df652018-12-13 11:54:39 +000030 struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
31 struct netdev_notifier_pre_changeaddr_info *prechaddr_info;
Cong Wangb1282722014-05-20 17:30:00 -070032 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
33 struct net_bridge_port *p;
34 struct net_bridge *br;
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +030035 bool notified = false;
Cong Wangb1282722014-05-20 17:30:00 -070036 bool changed_addr;
37 int err;
38
Kyungrok Chung254ec032021-10-16 20:21:36 +090039 if (netif_is_bridge_master(dev)) {
Nikolay Aleksandrov091adf92019-08-02 13:57:36 +030040 err = br_vlan_bridge_event(dev, event, ptr);
41 if (err)
42 return notifier_from_errno(err);
43
Mike Manning9c0ec2e2019-04-18 18:35:33 +010044 if (event == NETDEV_REGISTER) {
45 /* register of bridge completed, add sysfs entries */
Wang Hai989a1db2020-12-11 20:29:21 +080046 err = br_sysfs_addbr(dev);
47 if (err)
48 return notifier_from_errno(err);
49
Mike Manning9c0ec2e2019-04-18 18:35:33 +010050 return NOTIFY_DONE;
51 }
Cong Wangb1282722014-05-20 17:30:00 -070052 }
53
54 /* not a port of a bridge */
55 p = br_port_get_rtnl(dev);
56 if (!p)
57 return NOTIFY_DONE;
58
59 br = p->br;
60
61 switch (event) {
62 case NETDEV_CHANGEMTU:
Nikolay Aleksandrov804b8542018-03-30 13:46:19 +030063 br_mtu_auto_adjust(br);
Cong Wangb1282722014-05-20 17:30:00 -070064 break;
65
Petr Machatab89df652018-12-13 11:54:39 +000066 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);
75 break;
76
Cong Wangb1282722014-05-20 17:30:00 -070077 case NETDEV_CHANGEADDR:
78 spin_lock_bh(&br->lock);
79 br_fdb_changeaddr(p, dev->dev_addr);
80 changed_addr = br_stp_recalculate_bridge_id(br);
81 spin_unlock_bh(&br->lock);
82
83 if (changed_addr)
84 call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
85
86 break;
87
88 case NETDEV_CHANGE:
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +030089 br_port_carrier_check(p, &notified);
Cong Wangb1282722014-05-20 17:30:00 -070090 break;
91
92 case NETDEV_FEAT_CHANGE:
93 netdev_update_features(br->dev);
94 break;
95
96 case NETDEV_DOWN:
97 spin_lock_bh(&br->lock);
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +030098 if (br->dev->flags & IFF_UP) {
Cong Wangb1282722014-05-20 17:30:00 -070099 br_stp_disable_port(p);
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +0300100 notified = true;
101 }
Cong Wangb1282722014-05-20 17:30:00 -0700102 spin_unlock_bh(&br->lock);
103 break;
104
105 case NETDEV_UP:
106 if (netif_running(br->dev) && netif_oper_up(dev)) {
107 spin_lock_bh(&br->lock);
108 br_stp_enable_port(p);
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +0300109 notified = true;
Cong Wangb1282722014-05-20 17:30:00 -0700110 spin_unlock_bh(&br->lock);
111 }
112 break;
113
114 case NETDEV_UNREGISTER:
115 br_del_if(br, dev);
116 break;
117
118 case NETDEV_CHANGENAME:
119 err = br_sysfs_renameif(p);
120 if (err)
121 return notifier_from_errno(err);
122 break;
123
124 case NETDEV_PRE_TYPE_CHANGE:
Menglong Dongefb5b332021-01-07 18:53:32 -0800125 /* Forbid underlying device to change its type. */
Cong Wangb1282722014-05-20 17:30:00 -0700126 return NOTIFY_BAD;
127
128 case NETDEV_RESEND_IGMP:
129 /* Propagate to master device */
130 call_netdevice_notifiers(event, br->dev);
131 break;
132 }
133
Ido Schimmel697cd362019-04-22 09:33:19 +0000134 if (event != NETDEV_UNREGISTER)
135 br_vlan_port_event(p, event);
Mike Manning9c0ec2e2019-04-18 18:35:33 +0100136
Cong Wangb1282722014-05-20 17:30:00 -0700137 /* Events that may cause spanning tree to refresh */
Nikolay Aleksandrovfaa1cd82018-05-03 13:47:24 +0300138 if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
139 event == NETDEV_CHANGE || event == NETDEV_DOWN))
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200140 br_ifinfo_notify(RTM_NEWLINK, NULL, p);
Cong Wangb1282722014-05-20 17:30:00 -0700141
142 return NOTIFY_DONE;
143}
144
145static struct notifier_block br_device_notifier = {
146 .notifier_call = br_device_event
147};
148
Arkadi Sharshevsky0baa10f2017-06-08 08:44:12 +0200149/* called with RTNL or RCU */
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700150static int br_switchdev_event(struct notifier_block *unused,
151 unsigned long event, void *ptr)
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100152{
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700153 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100154 struct net_bridge_port *p;
155 struct net_bridge *br;
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700156 struct switchdev_notifier_fdb_info *fdb_info;
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100157 int err = NOTIFY_DONE;
158
Arkadi Sharshevsky0baa10f2017-06-08 08:44:12 +0200159 p = br_port_get_rtnl_rcu(dev);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100160 if (!p)
161 goto out;
162
163 br = p->br;
164
165 switch (event) {
Arkadi Sharshevsky6b26b512017-06-08 08:44:14 +0200166 case SWITCHDEV_FDB_ADD_TO_BRIDGE:
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100167 fdb_info = ptr;
168 err = br_fdb_external_learn_add(br, p, fdb_info->addr,
Nikolay Aleksandrov45a68782021-08-10 14:00:10 +0300169 fdb_info->vid, false);
Arkadi Sharshevsky9fe8bce2017-06-08 08:44:15 +0200170 if (err) {
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100171 err = notifier_from_errno(err);
Arkadi Sharshevsky9fe8bce2017-06-08 08:44:15 +0200172 break;
173 }
174 br_fdb_offloaded_set(br, p, fdb_info->addr,
Ido Schimmele9ba0fb2018-10-17 08:53:29 +0000175 fdb_info->vid, true);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100176 break;
Arkadi Sharshevsky6b26b512017-06-08 08:44:14 +0200177 case SWITCHDEV_FDB_DEL_TO_BRIDGE:
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100178 fdb_info = ptr;
179 err = br_fdb_external_learn_del(br, p, fdb_info->addr,
Petr Machata161d82d2018-05-03 14:43:53 +0200180 fdb_info->vid, false);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100181 if (err)
182 err = notifier_from_errno(err);
183 break;
Arkadi Sharshevsky9fe8bce2017-06-08 08:44:15 +0200184 case SWITCHDEV_FDB_OFFLOADED:
185 fdb_info = ptr;
186 br_fdb_offloaded_set(br, p, fdb_info->addr,
Ido Schimmele9ba0fb2018-10-17 08:53:29 +0000187 fdb_info->vid, fdb_info->offloaded);
Arkadi Sharshevsky9fe8bce2017-06-08 08:44:15 +0200188 break;
Alexandra Winterd05e8e62020-09-10 19:23:48 +0200189 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);
193 break;
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100194 }
195
196out:
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100197 return err;
198}
199
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700200static struct notifier_block br_switchdev_notifier = {
201 .notifier_call = br_switchdev_event,
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100202};
203
Vladimir Oltean957e2232021-08-03 23:34:08 +0300204/* called under rtnl_mutex */
205static int br_switchdev_blocking_event(struct notifier_block *nb,
206 unsigned long event, void *ptr)
207{
208 struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
209 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
210 struct switchdev_notifier_brport_info *brport_info;
211 const struct switchdev_brport *b;
212 struct net_bridge_port *p;
213 int err = NOTIFY_DONE;
214
215 p = br_port_get_rtnl(dev);
216 if (!p)
217 goto out;
218
219 switch (event) {
220 case SWITCHDEV_BRPORT_OFFLOADED:
221 brport_info = ptr;
222 b = &brport_info->brport;
223
224 err = br_switchdev_port_offload(p, b->dev, b->ctx,
225 b->atomic_nb, b->blocking_nb,
226 b->tx_fwd_offload, extack);
227 err = notifier_from_errno(err);
228 break;
229 case SWITCHDEV_BRPORT_UNOFFLOADED:
230 brport_info = ptr;
231 b = &brport_info->brport;
232
233 br_switchdev_port_unoffload(p, b->ctx, b->atomic_nb,
234 b->blocking_nb);
235 break;
236 }
237
238out:
239 return err;
240}
241
242static struct notifier_block br_switchdev_blocking_notifier = {
243 .notifier_call = br_switchdev_blocking_event,
244};
245
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200246/* br_boolopt_toggle - change user-controlled boolean option
247 *
248 * @br: bridge device
249 * @opt: id of the option to change
250 * @on: new option value
251 * @extack: extack for error messages
252 *
253 * Changes the value of the respective boolean option to @on taking care of
254 * any internal option value mapping and configuration.
255 */
256int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
257 struct netlink_ext_ack *extack)
258{
Nikolay Aleksandrovf4b70022021-07-19 20:06:28 +0300259 int err = 0;
260
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200261 switch (opt) {
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200262 case BR_BOOLOPT_NO_LL_LEARN:
263 br_opt_toggle(br, BROPT_NO_LL_LEARN, on);
264 break;
Nikolay Aleksandrovf4b70022021-07-19 20:06:28 +0300265 case BR_BOOLOPT_MCAST_VLAN_SNOOPING:
266 err = br_multicast_toggle_vlan_snooping(br, on, extack);
267 break;
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200268 default:
269 /* shouldn't be called with unsupported options */
270 WARN_ON(1);
271 break;
272 }
273
Nikolay Aleksandrovf4b70022021-07-19 20:06:28 +0300274 return err;
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200275}
276
277int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
278{
279 switch (opt) {
Nikolay Aleksandrov70e42722018-11-24 04:34:21 +0200280 case BR_BOOLOPT_NO_LL_LEARN:
281 return br_opt_get(br, BROPT_NO_LL_LEARN);
Nikolay Aleksandrovf4b70022021-07-19 20:06:28 +0300282 case BR_BOOLOPT_MCAST_VLAN_SNOOPING:
283 return br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED);
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200284 default:
285 /* shouldn't be called with unsupported options */
286 WARN_ON(1);
287 break;
288 }
289
290 return 0;
291}
292
293int br_boolopt_multi_toggle(struct net_bridge *br,
294 struct br_boolopt_multi *bm,
295 struct netlink_ext_ack *extack)
296{
297 unsigned long bitmap = bm->optmask;
298 int err = 0;
299 int opt_id;
300
301 for_each_set_bit(opt_id, &bitmap, BR_BOOLOPT_MAX) {
302 bool on = !!(bm->optval & BIT(opt_id));
303
304 err = br_boolopt_toggle(br, opt_id, on, extack);
305 if (err) {
306 br_debug(br, "boolopt multi-toggle error: option: %d current: %d new: %d error: %d\n",
307 opt_id, br_boolopt_get(br, opt_id), on, err);
308 break;
309 }
310 }
311
312 return err;
313}
314
315void br_boolopt_multi_get(const struct net_bridge *br,
316 struct br_boolopt_multi *bm)
317{
318 u32 optval = 0;
319 int opt_id;
320
321 for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
322 optval |= (br_boolopt_get(br, opt_id) << opt_id);
323
324 bm->optval = optval;
Nikolay Aleksandrov1ed1ccb2018-11-24 04:34:22 +0200325 bm->optmask = GENMASK((BR_BOOLOPT_MAX - 1), 0);
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +0200326}
327
328/* private bridge options, controlled by the kernel */
Nikolay Aleksandrovae757672018-09-26 17:01:00 +0300329void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
330{
331 bool cur = !!br_opt_get(br, opt);
332
333 br_debug(br, "toggle option: %d state: %d -> %d\n",
334 opt, cur, on);
335
336 if (cur == on)
337 return;
338
339 if (on)
340 set_bit(opt, &br->options);
341 else
342 clear_bit(opt, &br->options);
343}
344
WANG Congb86f81cc2014-01-10 13:58:47 -0800345static void __net_exit br_net_exit(struct net *net)
346{
347 struct net_device *dev;
348 LIST_HEAD(list);
349
350 rtnl_lock();
351 for_each_netdev(net, dev)
Kyungrok Chung254ec032021-10-16 20:21:36 +0900352 if (netif_is_bridge_master(dev))
WANG Congb86f81cc2014-01-10 13:58:47 -0800353 br_dev_delete(dev, &list);
354
355 unregister_netdevice_many(&list);
356 rtnl_unlock();
357
358}
Stephen Hemmingercf0f02d2006-03-20 22:59:06 -0800359
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700360static struct pernet_operations br_net_ops = {
361 .exit = br_net_exit,
362};
363
WANG Congb86f81cc2014-01-10 13:58:47 -0800364static const struct stp_proto br_stp_proto = {
365 .rcv = br_stp_rcv,
366};
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368static int __init br_init(void)
369{
Stephen Hemmingerc0909712006-05-25 15:59:33 -0700370 int err;
371
Pankaj Bharadiyac5936422019-12-09 10:31:43 -0800372 BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > sizeof_field(struct sk_buff, cb));
Florian Westphal71e168b12015-03-03 13:53:31 +0100373
Patrick McHardy7c85fbf2008-07-05 21:25:56 -0700374 err = stp_proto_register(&br_stp_proto);
375 if (err < 0) {
stephen hemminger28a16c92010-05-10 09:31:09 +0000376 pr_err("bridge: can't register sap for STP\n");
Patrick McHardy7c85fbf2008-07-05 21:25:56 -0700377 return err;
Stephen Hemmingercf0f02d2006-03-20 22:59:06 -0800378 }
379
Akinobu Mita87a596e2007-04-07 18:57:07 +0900380 err = br_fdb_init();
381 if (err)
Pavel Emelyanov17efdd42007-11-29 23:41:43 +1100382 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700384 err = register_pernet_subsys(&br_net_ops);
Stephen Hemmingerc0909712006-05-25 15:59:33 -0700385 if (err)
386 goto err_out1;
387
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200388 err = br_nf_core_init();
Stephen Hemmingerc0909712006-05-25 15:59:33 -0700389 if (err)
390 goto err_out2;
391
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700392 err = register_netdevice_notifier(&br_device_notifier);
Thomas Graf32fe21c2007-03-22 11:59:03 -0700393 if (err)
394 goto err_out3;
395
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700396 err = register_switchdev_notifier(&br_switchdev_notifier);
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700397 if (err)
398 goto err_out4;
399
Vladimir Oltean957e2232021-08-03 23:34:08 +0300400 err = register_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100401 if (err)
402 goto err_out5;
403
Vladimir Oltean957e2232021-08-03 23:34:08 +0300404 err = br_netlink_init();
405 if (err)
406 goto err_out6;
407
Arnd Bergmannad2f99a2021-07-27 15:45:16 +0200408 brioctl_set(br_ioctl_stub);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Igor Maraviće6373c42011-12-12 02:58:25 +0000410#if IS_ENABLED(CONFIG_ATM_LANE)
Michał Mirosławda678292009-06-05 05:35:28 +0000411 br_fdb_test_addr_hook = br_fdb_test_addr;
412#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Stefan Agnerd4ef9f72016-09-28 15:05:28 -0700414#if IS_MODULE(CONFIG_BRIDGE_NETFILTER)
415 pr_info("bridge: filtering via arp/ip/ip6tables is no longer available "
416 "by default. Update your scripts to load br_netfilter if you "
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200417 "need this.\n");
Stefan Agnerd4ef9f72016-09-28 15:05:28 -0700418#endif
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return 0;
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200421
Vladimir Oltean957e2232021-08-03 23:34:08 +0300422err_out6:
423 unregister_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
Jiri Pirko3aeb6612015-01-15 23:49:37 +0100424err_out5:
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700425 unregister_switchdev_notifier(&br_switchdev_notifier);
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700426err_out4:
Thomas Graf32fe21c2007-03-22 11:59:03 -0700427 unregister_netdevice_notifier(&br_device_notifier);
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700428err_out3:
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200429 br_nf_core_fini();
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700430err_out2:
431 unregister_pernet_subsys(&br_net_ops);
Stephen Hemmingerc0909712006-05-25 15:59:33 -0700432err_out1:
Pavel Emelyanov17efdd42007-11-29 23:41:43 +1100433 br_fdb_fini();
434err_out:
Patrick McHardy7c85fbf2008-07-05 21:25:56 -0700435 stp_proto_unregister(&br_stp_proto);
Stephen Hemmingerc0909712006-05-25 15:59:33 -0700436 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437}
438
439static void __exit br_deinit(void)
440{
Patrick McHardy7c85fbf2008-07-05 21:25:56 -0700441 stp_proto_unregister(&br_stp_proto);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700442 br_netlink_fini();
Vladimir Oltean957e2232021-08-03 23:34:08 +0300443 unregister_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
Jiri Pirkoebb9a032015-05-10 09:47:46 -0700444 unregister_switchdev_notifier(&br_switchdev_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 unregister_netdevice_notifier(&br_device_notifier);
446 brioctl_set(NULL);
Alexey Dobriyan712d6952008-09-08 16:20:18 -0700447 unregister_pernet_subsys(&br_net_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Jesper Dangaard Brouer473c22d2009-06-26 10:45:48 +0000449 rcu_barrier(); /* Wait for completion of call_rcu()'s */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +0200451 br_nf_core_fini();
Igor Maraviće6373c42011-12-12 02:58:25 +0000452#if IS_ENABLED(CONFIG_ATM_LANE)
Michał Mirosławda678292009-06-05 05:35:28 +0000453 br_fdb_test_addr_hook = NULL;
454#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 br_fdb_fini();
456}
457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458module_init(br_init)
459module_exit(br_deinit)
460MODULE_LICENSE("GPL");
Stephen Hemminger8cbb512e2005-12-21 19:01:30 -0800461MODULE_VERSION(BR_VERSION);
stephen hemmingerbb900b22011-04-04 14:03:32 +0000462MODULE_ALIAS_RTNL_LINK("bridge");