xref: /openbmc/linux/net/bridge/br.c (revision f2e2857b)
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, &notified);
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