12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Generic parts
41da177e4SLinus Torvalds * Linux ethernet bridge
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Authors:
71da177e4SLinus Torvalds * Lennert Buytenhek <buytenh@gnu.org>
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/netdevice.h>
131da177e4SLinus Torvalds #include <linux/etherdevice.h>
141da177e4SLinus Torvalds #include <linux/init.h>
15cf0f02d0SStephen Hemminger #include <linux/llc.h>
16cf0f02d0SStephen Hemminger #include <net/llc.h>
177c85fbf0SPatrick McHardy #include <net/stp.h>
183aeb6617SJiri Pirko #include <net/switchdev.h>
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds #include "br_private.h"
211da177e4SLinus Torvalds
22b1282726SCong Wang /*
23b1282726SCong Wang * Handle changes in state of network devices enslaved to a bridge.
24b1282726SCong Wang *
25b1282726SCong Wang * Note: don't care about up/down if bridge itself is down, because
26b1282726SCong Wang * port state is checked when bridge is brought up.
27b1282726SCong Wang */
br_device_event(struct notifier_block * unused,unsigned long event,void * ptr)28b1282726SCong Wang static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
29b1282726SCong Wang {
30b89df65cSPetr Machata struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
31b89df65cSPetr Machata struct netdev_notifier_pre_changeaddr_info *prechaddr_info;
32b1282726SCong Wang struct net_device *dev = netdev_notifier_info_to_dev(ptr);
33b1282726SCong Wang struct net_bridge_port *p;
34b1282726SCong Wang struct net_bridge *br;
35faa1cd82SNikolay Aleksandrov bool notified = false;
36b1282726SCong Wang bool changed_addr;
37b1282726SCong Wang int err;
38b1282726SCong Wang
39254ec036SKyungrok Chung if (netif_is_bridge_master(dev)) {
40091adf9bSNikolay Aleksandrov err = br_vlan_bridge_event(dev, event, ptr);
41091adf9bSNikolay Aleksandrov if (err)
42091adf9bSNikolay Aleksandrov return notifier_from_errno(err);
43091adf9bSNikolay Aleksandrov
449c0ec2e7SMike Manning if (event == NETDEV_REGISTER) {
45b1282726SCong Wang /* register of bridge completed, add sysfs entries */
46989a1db0SWang Hai err = br_sysfs_addbr(dev);
47989a1db0SWang Hai if (err)
48989a1db0SWang Hai return notifier_from_errno(err);
49989a1db0SWang Hai
50b1282726SCong Wang return NOTIFY_DONE;
51b1282726SCong Wang }
529c0ec2e7SMike Manning }
53b1282726SCong Wang
54b1282726SCong Wang /* not a port of a bridge */
55b1282726SCong Wang p = br_port_get_rtnl(dev);
56b1282726SCong Wang if (!p)
57b1282726SCong Wang return NOTIFY_DONE;
58b1282726SCong Wang
59b1282726SCong Wang br = p->br;
60b1282726SCong Wang
61b1282726SCong Wang switch (event) {
62b1282726SCong Wang case NETDEV_CHANGEMTU:
63804b854dSNikolay Aleksandrov br_mtu_auto_adjust(br);
64b1282726SCong Wang break;
65b1282726SCong Wang
66b89df65cSPetr Machata case NETDEV_PRE_CHANGEADDR:
67b89df65cSPetr Machata if (br->dev->addr_assign_type == NET_ADDR_SET)
68b89df65cSPetr Machata break;
69b89df65cSPetr Machata prechaddr_info = ptr;
70b89df65cSPetr Machata err = dev_pre_changeaddr_notify(br->dev,
71b89df65cSPetr Machata prechaddr_info->dev_addr,
72b89df65cSPetr Machata extack);
73b89df65cSPetr Machata if (err)
74b89df65cSPetr Machata return notifier_from_errno(err);
75b89df65cSPetr Machata break;
76b89df65cSPetr Machata
77b1282726SCong Wang case NETDEV_CHANGEADDR:
78b1282726SCong Wang spin_lock_bh(&br->lock);
79b1282726SCong Wang br_fdb_changeaddr(p, dev->dev_addr);
80b1282726SCong Wang changed_addr = br_stp_recalculate_bridge_id(br);
81b1282726SCong Wang spin_unlock_bh(&br->lock);
82b1282726SCong Wang
83b1282726SCong Wang if (changed_addr)
84b1282726SCong Wang call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
85b1282726SCong Wang
86b1282726SCong Wang break;
87b1282726SCong Wang
88b1282726SCong Wang case NETDEV_CHANGE:
89faa1cd82SNikolay Aleksandrov br_port_carrier_check(p, ¬ified);
90b1282726SCong Wang break;
91b1282726SCong Wang
92b1282726SCong Wang case NETDEV_FEAT_CHANGE:
93b1282726SCong Wang netdev_update_features(br->dev);
94b1282726SCong Wang break;
95b1282726SCong Wang
96b1282726SCong Wang case NETDEV_DOWN:
97b1282726SCong Wang spin_lock_bh(&br->lock);
98faa1cd82SNikolay Aleksandrov if (br->dev->flags & IFF_UP) {
99b1282726SCong Wang br_stp_disable_port(p);
100faa1cd82SNikolay Aleksandrov notified = true;
101faa1cd82SNikolay Aleksandrov }
102b1282726SCong Wang spin_unlock_bh(&br->lock);
103b1282726SCong Wang break;
104b1282726SCong Wang
105b1282726SCong Wang case NETDEV_UP:
106b1282726SCong Wang if (netif_running(br->dev) && netif_oper_up(dev)) {
107b1282726SCong Wang spin_lock_bh(&br->lock);
108b1282726SCong Wang br_stp_enable_port(p);
109faa1cd82SNikolay Aleksandrov notified = true;
110b1282726SCong Wang spin_unlock_bh(&br->lock);
111b1282726SCong Wang }
112b1282726SCong Wang break;
113b1282726SCong Wang
114b1282726SCong Wang case NETDEV_UNREGISTER:
115b1282726SCong Wang br_del_if(br, dev);
116b1282726SCong Wang break;
117b1282726SCong Wang
118b1282726SCong Wang case NETDEV_CHANGENAME:
119b1282726SCong Wang err = br_sysfs_renameif(p);
120b1282726SCong Wang if (err)
121b1282726SCong Wang return notifier_from_errno(err);
122b1282726SCong Wang break;
123b1282726SCong Wang
124b1282726SCong Wang case NETDEV_PRE_TYPE_CHANGE:
125efb5b338SMenglong Dong /* Forbid underlying device to change its type. */
126b1282726SCong Wang return NOTIFY_BAD;
127b1282726SCong Wang
128b1282726SCong Wang case NETDEV_RESEND_IGMP:
129b1282726SCong Wang /* Propagate to master device */
130b1282726SCong Wang call_netdevice_notifiers(event, br->dev);
131b1282726SCong Wang break;
132b1282726SCong Wang }
133b1282726SCong Wang
134697cd36cSIdo Schimmel if (event != NETDEV_UNREGISTER)
1359c0ec2e7SMike Manning br_vlan_port_event(p, event);
1369c0ec2e7SMike Manning
137b1282726SCong Wang /* Events that may cause spanning tree to refresh */
138faa1cd82SNikolay Aleksandrov if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
139faa1cd82SNikolay Aleksandrov event == NETDEV_CHANGE || event == NETDEV_DOWN))
14092899063SNikolay Aleksandrov br_ifinfo_notify(RTM_NEWLINK, NULL, p);
141b1282726SCong Wang
142b1282726SCong Wang return NOTIFY_DONE;
143b1282726SCong Wang }
144b1282726SCong Wang
145b1282726SCong Wang static struct notifier_block br_device_notifier = {
146b1282726SCong Wang .notifier_call = br_device_event
147b1282726SCong Wang };
148b1282726SCong Wang
1490baa10ffSArkadi Sharshevsky /* called with RTNL or RCU */
br_switchdev_event(struct notifier_block * unused,unsigned long event,void * ptr)150ebb9a03aSJiri Pirko static int br_switchdev_event(struct notifier_block *unused,
1513aeb6617SJiri Pirko unsigned long event, void *ptr)
1523aeb6617SJiri Pirko {
153ebb9a03aSJiri Pirko struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
1543aeb6617SJiri Pirko struct net_bridge_port *p;
1553aeb6617SJiri Pirko struct net_bridge *br;
156ebb9a03aSJiri Pirko struct switchdev_notifier_fdb_info *fdb_info;
1573aeb6617SJiri Pirko int err = NOTIFY_DONE;
1583aeb6617SJiri Pirko
1590baa10ffSArkadi Sharshevsky p = br_port_get_rtnl_rcu(dev);
1603aeb6617SJiri Pirko if (!p)
1613aeb6617SJiri Pirko goto out;
1623aeb6617SJiri Pirko
1633aeb6617SJiri Pirko br = p->br;
1643aeb6617SJiri Pirko
1653aeb6617SJiri Pirko switch (event) {
1666b26b51bSArkadi Sharshevsky case SWITCHDEV_FDB_ADD_TO_BRIDGE:
1673aeb6617SJiri Pirko fdb_info = ptr;
1683aeb6617SJiri Pirko err = br_fdb_external_learn_add(br, p, fdb_info->addr,
16927fabd02SHans J. Schultz fdb_info->vid,
17027fabd02SHans J. Schultz fdb_info->locked, false);
1719fe8bcecSArkadi Sharshevsky if (err) {
1723aeb6617SJiri Pirko err = notifier_from_errno(err);
1733aeb6617SJiri Pirko break;
1749fe8bcecSArkadi Sharshevsky }
1759fe8bcecSArkadi Sharshevsky br_fdb_offloaded_set(br, p, fdb_info->addr,
1769baedc3cSIdo Schimmel fdb_info->vid, fdb_info->offloaded);
1779fe8bcecSArkadi Sharshevsky break;
1786b26b51bSArkadi Sharshevsky case SWITCHDEV_FDB_DEL_TO_BRIDGE:
1793aeb6617SJiri Pirko fdb_info = ptr;
1803aeb6617SJiri Pirko err = br_fdb_external_learn_del(br, p, fdb_info->addr,
181161d82deSPetr Machata fdb_info->vid, false);
1823aeb6617SJiri Pirko if (err)
1833aeb6617SJiri Pirko err = notifier_from_errno(err);
1843aeb6617SJiri Pirko break;
1859fe8bcecSArkadi Sharshevsky case SWITCHDEV_FDB_OFFLOADED:
1869fe8bcecSArkadi Sharshevsky fdb_info = ptr;
1879fe8bcecSArkadi Sharshevsky br_fdb_offloaded_set(br, p, fdb_info->addr,
188e9ba0fbcSIdo Schimmel fdb_info->vid, fdb_info->offloaded);
1899fe8bcecSArkadi Sharshevsky break;
190d05e8e68SAlexandra Winter case SWITCHDEV_FDB_FLUSH_TO_BRIDGE:
191d05e8e68SAlexandra Winter fdb_info = ptr;
192d05e8e68SAlexandra Winter /* Don't delete static entries */
193d05e8e68SAlexandra Winter br_fdb_delete_by_port(br, p, fdb_info->vid, 0);
194d05e8e68SAlexandra Winter break;
1953aeb6617SJiri Pirko }
1963aeb6617SJiri Pirko
1973aeb6617SJiri Pirko out:
1983aeb6617SJiri Pirko return err;
1993aeb6617SJiri Pirko }
2003aeb6617SJiri Pirko
201ebb9a03aSJiri Pirko static struct notifier_block br_switchdev_notifier = {
202ebb9a03aSJiri Pirko .notifier_call = br_switchdev_event,
2033aeb6617SJiri Pirko };
2043aeb6617SJiri Pirko
205957e2235SVladimir Oltean /* called under rtnl_mutex */
br_switchdev_blocking_event(struct notifier_block * nb,unsigned long event,void * ptr)206957e2235SVladimir Oltean static int br_switchdev_blocking_event(struct notifier_block *nb,
207957e2235SVladimir Oltean unsigned long event, void *ptr)
208957e2235SVladimir Oltean {
209957e2235SVladimir Oltean struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
210957e2235SVladimir Oltean struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
211957e2235SVladimir Oltean struct switchdev_notifier_brport_info *brport_info;
212957e2235SVladimir Oltean const struct switchdev_brport *b;
213957e2235SVladimir Oltean struct net_bridge_port *p;
214957e2235SVladimir Oltean int err = NOTIFY_DONE;
215957e2235SVladimir Oltean
216957e2235SVladimir Oltean p = br_port_get_rtnl(dev);
217957e2235SVladimir Oltean if (!p)
218957e2235SVladimir Oltean goto out;
219957e2235SVladimir Oltean
220957e2235SVladimir Oltean switch (event) {
221957e2235SVladimir Oltean case SWITCHDEV_BRPORT_OFFLOADED:
222957e2235SVladimir Oltean brport_info = ptr;
223957e2235SVladimir Oltean b = &brport_info->brport;
224957e2235SVladimir Oltean
225957e2235SVladimir Oltean err = br_switchdev_port_offload(p, b->dev, b->ctx,
226957e2235SVladimir Oltean b->atomic_nb, b->blocking_nb,
227957e2235SVladimir Oltean b->tx_fwd_offload, extack);
228957e2235SVladimir Oltean err = notifier_from_errno(err);
229957e2235SVladimir Oltean break;
230957e2235SVladimir Oltean case SWITCHDEV_BRPORT_UNOFFLOADED:
231957e2235SVladimir Oltean brport_info = ptr;
232957e2235SVladimir Oltean b = &brport_info->brport;
233957e2235SVladimir Oltean
234957e2235SVladimir Oltean br_switchdev_port_unoffload(p, b->ctx, b->atomic_nb,
235957e2235SVladimir Oltean b->blocking_nb);
236957e2235SVladimir Oltean break;
237*f2e2857bSPetr Machata case SWITCHDEV_BRPORT_REPLAY:
238*f2e2857bSPetr Machata brport_info = ptr;
239*f2e2857bSPetr Machata b = &brport_info->brport;
240*f2e2857bSPetr Machata
241*f2e2857bSPetr Machata err = br_switchdev_port_replay(p, b->dev, b->ctx, b->atomic_nb,
242*f2e2857bSPetr Machata b->blocking_nb, extack);
243*f2e2857bSPetr Machata err = notifier_from_errno(err);
244*f2e2857bSPetr Machata break;
245957e2235SVladimir Oltean }
246957e2235SVladimir Oltean
247957e2235SVladimir Oltean out:
248957e2235SVladimir Oltean return err;
249957e2235SVladimir Oltean }
250957e2235SVladimir Oltean
251957e2235SVladimir Oltean static struct notifier_block br_switchdev_blocking_notifier = {
252957e2235SVladimir Oltean .notifier_call = br_switchdev_blocking_event,
253957e2235SVladimir Oltean };
254957e2235SVladimir Oltean
255a428afe8SNikolay Aleksandrov /* br_boolopt_toggle - change user-controlled boolean option
256a428afe8SNikolay Aleksandrov *
257a428afe8SNikolay Aleksandrov * @br: bridge device
258a428afe8SNikolay Aleksandrov * @opt: id of the option to change
259a428afe8SNikolay Aleksandrov * @on: new option value
260a428afe8SNikolay Aleksandrov * @extack: extack for error messages
261a428afe8SNikolay Aleksandrov *
262a428afe8SNikolay Aleksandrov * Changes the value of the respective boolean option to @on taking care of
263a428afe8SNikolay Aleksandrov * any internal option value mapping and configuration.
264a428afe8SNikolay Aleksandrov */
br_boolopt_toggle(struct net_bridge * br,enum br_boolopt_id opt,bool on,struct netlink_ext_ack * extack)265a428afe8SNikolay Aleksandrov int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
266a428afe8SNikolay Aleksandrov struct netlink_ext_ack *extack)
267a428afe8SNikolay Aleksandrov {
268f4b7002aSNikolay Aleksandrov int err = 0;
269f4b7002aSNikolay Aleksandrov
270a428afe8SNikolay Aleksandrov switch (opt) {
27170e4272bSNikolay Aleksandrov case BR_BOOLOPT_NO_LL_LEARN:
27270e4272bSNikolay Aleksandrov br_opt_toggle(br, BROPT_NO_LL_LEARN, on);
27370e4272bSNikolay Aleksandrov break;
274f4b7002aSNikolay Aleksandrov case BR_BOOLOPT_MCAST_VLAN_SNOOPING:
275f4b7002aSNikolay Aleksandrov err = br_multicast_toggle_vlan_snooping(br, on, extack);
276f4b7002aSNikolay Aleksandrov break;
277ec7328b5STobias Waldekranz case BR_BOOLOPT_MST_ENABLE:
278ec7328b5STobias Waldekranz err = br_mst_set_enabled(br, on, extack);
279ec7328b5STobias Waldekranz break;
280a428afe8SNikolay Aleksandrov default:
281a428afe8SNikolay Aleksandrov /* shouldn't be called with unsupported options */
282a428afe8SNikolay Aleksandrov WARN_ON(1);
283a428afe8SNikolay Aleksandrov break;
284a428afe8SNikolay Aleksandrov }
285a428afe8SNikolay Aleksandrov
286f4b7002aSNikolay Aleksandrov return err;
287a428afe8SNikolay Aleksandrov }
288a428afe8SNikolay Aleksandrov
br_boolopt_get(const struct net_bridge * br,enum br_boolopt_id opt)289a428afe8SNikolay Aleksandrov int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
290a428afe8SNikolay Aleksandrov {
291a428afe8SNikolay Aleksandrov switch (opt) {
29270e4272bSNikolay Aleksandrov case BR_BOOLOPT_NO_LL_LEARN:
29370e4272bSNikolay Aleksandrov return br_opt_get(br, BROPT_NO_LL_LEARN);
294f4b7002aSNikolay Aleksandrov case BR_BOOLOPT_MCAST_VLAN_SNOOPING:
295f4b7002aSNikolay Aleksandrov return br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED);
296ec7328b5STobias Waldekranz case BR_BOOLOPT_MST_ENABLE:
297ec7328b5STobias Waldekranz return br_opt_get(br, BROPT_MST_ENABLED);
298a428afe8SNikolay Aleksandrov default:
299a428afe8SNikolay Aleksandrov /* shouldn't be called with unsupported options */
300a428afe8SNikolay Aleksandrov WARN_ON(1);
301a428afe8SNikolay Aleksandrov break;
302a428afe8SNikolay Aleksandrov }
303a428afe8SNikolay Aleksandrov
304a428afe8SNikolay Aleksandrov return 0;
305a428afe8SNikolay Aleksandrov }
306a428afe8SNikolay Aleksandrov
br_boolopt_multi_toggle(struct net_bridge * br,struct br_boolopt_multi * bm,struct netlink_ext_ack * extack)307a428afe8SNikolay Aleksandrov int br_boolopt_multi_toggle(struct net_bridge *br,
308a428afe8SNikolay Aleksandrov struct br_boolopt_multi *bm,
309a428afe8SNikolay Aleksandrov struct netlink_ext_ack *extack)
310a428afe8SNikolay Aleksandrov {
311a428afe8SNikolay Aleksandrov unsigned long bitmap = bm->optmask;
312a428afe8SNikolay Aleksandrov int err = 0;
313a428afe8SNikolay Aleksandrov int opt_id;
314a428afe8SNikolay Aleksandrov
315a428afe8SNikolay Aleksandrov for_each_set_bit(opt_id, &bitmap, BR_BOOLOPT_MAX) {
316a428afe8SNikolay Aleksandrov bool on = !!(bm->optval & BIT(opt_id));
317a428afe8SNikolay Aleksandrov
318a428afe8SNikolay Aleksandrov err = br_boolopt_toggle(br, opt_id, on, extack);
319a428afe8SNikolay Aleksandrov if (err) {
320a428afe8SNikolay Aleksandrov br_debug(br, "boolopt multi-toggle error: option: %d current: %d new: %d error: %d\n",
321a428afe8SNikolay Aleksandrov opt_id, br_boolopt_get(br, opt_id), on, err);
322a428afe8SNikolay Aleksandrov break;
323a428afe8SNikolay Aleksandrov }
324a428afe8SNikolay Aleksandrov }
325a428afe8SNikolay Aleksandrov
326a428afe8SNikolay Aleksandrov return err;
327a428afe8SNikolay Aleksandrov }
328a428afe8SNikolay Aleksandrov
br_boolopt_multi_get(const struct net_bridge * br,struct br_boolopt_multi * bm)329a428afe8SNikolay Aleksandrov void br_boolopt_multi_get(const struct net_bridge *br,
330a428afe8SNikolay Aleksandrov struct br_boolopt_multi *bm)
331a428afe8SNikolay Aleksandrov {
332a428afe8SNikolay Aleksandrov u32 optval = 0;
333a428afe8SNikolay Aleksandrov int opt_id;
334a428afe8SNikolay Aleksandrov
335a428afe8SNikolay Aleksandrov for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
336a428afe8SNikolay Aleksandrov optval |= (br_boolopt_get(br, opt_id) << opt_id);
337a428afe8SNikolay Aleksandrov
338a428afe8SNikolay Aleksandrov bm->optval = optval;
3391ed1ccb9SNikolay Aleksandrov bm->optmask = GENMASK((BR_BOOLOPT_MAX - 1), 0);
340a428afe8SNikolay Aleksandrov }
341a428afe8SNikolay Aleksandrov
342a428afe8SNikolay Aleksandrov /* private bridge options, controlled by the kernel */
br_opt_toggle(struct net_bridge * br,enum net_bridge_opts opt,bool on)343ae75767eSNikolay Aleksandrov void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
344ae75767eSNikolay Aleksandrov {
345ae75767eSNikolay Aleksandrov bool cur = !!br_opt_get(br, opt);
346ae75767eSNikolay Aleksandrov
347ae75767eSNikolay Aleksandrov br_debug(br, "toggle option: %d state: %d -> %d\n",
348ae75767eSNikolay Aleksandrov opt, cur, on);
349ae75767eSNikolay Aleksandrov
350ae75767eSNikolay Aleksandrov if (cur == on)
351ae75767eSNikolay Aleksandrov return;
352ae75767eSNikolay Aleksandrov
353ae75767eSNikolay Aleksandrov if (on)
354ae75767eSNikolay Aleksandrov set_bit(opt, &br->options);
355ae75767eSNikolay Aleksandrov else
356ae75767eSNikolay Aleksandrov clear_bit(opt, &br->options);
357ae75767eSNikolay Aleksandrov }
358ae75767eSNikolay Aleksandrov
br_net_exit_batch(struct list_head * net_list)35936a29fb6SEric Dumazet static void __net_exit br_net_exit_batch(struct list_head *net_list)
360b86f81ccSWANG Cong {
361b86f81ccSWANG Cong struct net_device *dev;
36236a29fb6SEric Dumazet struct net *net;
363b86f81ccSWANG Cong LIST_HEAD(list);
364b86f81ccSWANG Cong
365b86f81ccSWANG Cong rtnl_lock();
36636a29fb6SEric Dumazet
36736a29fb6SEric Dumazet list_for_each_entry(net, net_list, exit_list)
368b86f81ccSWANG Cong for_each_netdev(net, dev)
369254ec036SKyungrok Chung if (netif_is_bridge_master(dev))
370b86f81ccSWANG Cong br_dev_delete(dev, &list);
371b86f81ccSWANG Cong
372b86f81ccSWANG Cong unregister_netdevice_many(&list);
373b86f81ccSWANG Cong
37436a29fb6SEric Dumazet rtnl_unlock();
375b86f81ccSWANG Cong }
376cf0f02d0SStephen Hemminger
377712d6954SAlexey Dobriyan static struct pernet_operations br_net_ops = {
37836a29fb6SEric Dumazet .exit_batch = br_net_exit_batch,
379712d6954SAlexey Dobriyan };
380712d6954SAlexey Dobriyan
381b86f81ccSWANG Cong static const struct stp_proto br_stp_proto = {
382b86f81ccSWANG Cong .rcv = br_stp_rcv,
383b86f81ccSWANG Cong };
384b86f81ccSWANG Cong
br_init(void)3851da177e4SLinus Torvalds static int __init br_init(void)
3861da177e4SLinus Torvalds {
387c0909713SStephen Hemminger int err;
388c0909713SStephen Hemminger
389c593642cSPankaj Bharadiya BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > sizeof_field(struct sk_buff, cb));
39071e168b1SFlorian Westphal
3917c85fbf0SPatrick McHardy err = stp_proto_register(&br_stp_proto);
3927c85fbf0SPatrick McHardy if (err < 0) {
39328a16c97Sstephen hemminger pr_err("bridge: can't register sap for STP\n");
3947c85fbf0SPatrick McHardy return err;
395cf0f02d0SStephen Hemminger }
396cf0f02d0SStephen Hemminger
39787a596e0SAkinobu Mita err = br_fdb_init();
39887a596e0SAkinobu Mita if (err)
39917efdd45SPavel Emelyanov goto err_out;
4001da177e4SLinus Torvalds
401712d6954SAlexey Dobriyan err = register_pernet_subsys(&br_net_ops);
402c0909713SStephen Hemminger if (err)
403c0909713SStephen Hemminger goto err_out1;
404c0909713SStephen Hemminger
40534666d46SPablo Neira Ayuso err = br_nf_core_init();
406c0909713SStephen Hemminger if (err)
407c0909713SStephen Hemminger goto err_out2;
408c0909713SStephen Hemminger
409712d6954SAlexey Dobriyan err = register_netdevice_notifier(&br_device_notifier);
41032fe21c0SThomas Graf if (err)
41132fe21c0SThomas Graf goto err_out3;
41232fe21c0SThomas Graf
413ebb9a03aSJiri Pirko err = register_switchdev_notifier(&br_switchdev_notifier);
414712d6954SAlexey Dobriyan if (err)
415712d6954SAlexey Dobriyan goto err_out4;
416712d6954SAlexey Dobriyan
417957e2235SVladimir Oltean err = register_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
4183aeb6617SJiri Pirko if (err)
4193aeb6617SJiri Pirko goto err_out5;
4203aeb6617SJiri Pirko
421957e2235SVladimir Oltean err = br_netlink_init();
422957e2235SVladimir Oltean if (err)
423957e2235SVladimir Oltean goto err_out6;
424957e2235SVladimir Oltean
425ad2f99aeSArnd Bergmann brioctl_set(br_ioctl_stub);
4261da177e4SLinus Torvalds
427e6373c4cSIgor Maravić #if IS_ENABLED(CONFIG_ATM_LANE)
428da678292SMichał Mirosław br_fdb_test_addr_hook = br_fdb_test_addr;
429da678292SMichał Mirosław #endif
4301da177e4SLinus Torvalds
431d4ef9f72SStefan Agner #if IS_MODULE(CONFIG_BRIDGE_NETFILTER)
432d4ef9f72SStefan Agner pr_info("bridge: filtering via arp/ip/ip6tables is no longer available "
433d4ef9f72SStefan Agner "by default. Update your scripts to load br_netfilter if you "
43434666d46SPablo Neira Ayuso "need this.\n");
435d4ef9f72SStefan Agner #endif
43634666d46SPablo Neira Ayuso
4371da177e4SLinus Torvalds return 0;
43834666d46SPablo Neira Ayuso
439957e2235SVladimir Oltean err_out6:
440957e2235SVladimir Oltean unregister_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
4413aeb6617SJiri Pirko err_out5:
442ebb9a03aSJiri Pirko unregister_switchdev_notifier(&br_switchdev_notifier);
443712d6954SAlexey Dobriyan err_out4:
44432fe21c0SThomas Graf unregister_netdevice_notifier(&br_device_notifier);
445712d6954SAlexey Dobriyan err_out3:
44634666d46SPablo Neira Ayuso br_nf_core_fini();
447712d6954SAlexey Dobriyan err_out2:
448712d6954SAlexey Dobriyan unregister_pernet_subsys(&br_net_ops);
449c0909713SStephen Hemminger err_out1:
45017efdd45SPavel Emelyanov br_fdb_fini();
45117efdd45SPavel Emelyanov err_out:
4527c85fbf0SPatrick McHardy stp_proto_unregister(&br_stp_proto);
453c0909713SStephen Hemminger return err;
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds
br_deinit(void)4561da177e4SLinus Torvalds static void __exit br_deinit(void)
4571da177e4SLinus Torvalds {
4587c85fbf0SPatrick McHardy stp_proto_unregister(&br_stp_proto);
45911dc1f36SStephen Hemminger br_netlink_fini();
460957e2235SVladimir Oltean unregister_switchdev_blocking_notifier(&br_switchdev_blocking_notifier);
461ebb9a03aSJiri Pirko unregister_switchdev_notifier(&br_switchdev_notifier);
4621da177e4SLinus Torvalds unregister_netdevice_notifier(&br_device_notifier);
4631da177e4SLinus Torvalds brioctl_set(NULL);
464712d6954SAlexey Dobriyan unregister_pernet_subsys(&br_net_ops);
4651da177e4SLinus Torvalds
466473c22d7SJesper Dangaard Brouer rcu_barrier(); /* Wait for completion of call_rcu()'s */
4671da177e4SLinus Torvalds
46834666d46SPablo Neira Ayuso br_nf_core_fini();
469e6373c4cSIgor Maravić #if IS_ENABLED(CONFIG_ATM_LANE)
470da678292SMichał Mirosław br_fdb_test_addr_hook = NULL;
471da678292SMichał Mirosław #endif
4721da177e4SLinus Torvalds br_fdb_fini();
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds module_init(br_init)
4761da177e4SLinus Torvalds module_exit(br_deinit)
4771da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4788cbb512eSStephen Hemminger MODULE_VERSION(BR_VERSION);
479bb900b27Sstephen hemminger MODULE_ALIAS_RTNL_LINK("bridge");
480