]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Generic parts | |
3 | * Linux ethernet bridge | |
4 | * | |
5 | * Authors: | |
6 | * Lennert Buytenhek <[email protected]> | |
7 | * | |
1da177e4 LT |
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. | |
12 | */ | |
13 | ||
1da177e4 LT |
14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | |
16 | #include <linux/netdevice.h> | |
17 | #include <linux/etherdevice.h> | |
18 | #include <linux/init.h> | |
cf0f02d0 SH |
19 | #include <linux/llc.h> |
20 | #include <net/llc.h> | |
7c85fbf0 | 21 | #include <net/stp.h> |
1da177e4 LT |
22 | |
23 | #include "br_private.h" | |
24 | ||
b1282726 CW |
25 | /* |
26 | * Handle changes in state of network devices enslaved to a bridge. | |
27 | * | |
28 | * Note: don't care about up/down if bridge itself is down, because | |
29 | * port state is checked when bridge is brought up. | |
30 | */ | |
31 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | |
32 | { | |
33 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | |
34 | struct net_bridge_port *p; | |
35 | struct net_bridge *br; | |
36 | bool changed_addr; | |
37 | int err; | |
38 | ||
39 | /* register of bridge completed, add sysfs entries */ | |
40 | if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) { | |
41 | br_sysfs_addbr(dev); | |
42 | return NOTIFY_DONE; | |
43 | } | |
44 | ||
45 | /* not a port of a bridge */ | |
46 | p = br_port_get_rtnl(dev); | |
47 | if (!p) | |
48 | return NOTIFY_DONE; | |
49 | ||
50 | br = p->br; | |
51 | ||
52 | switch (event) { | |
53 | case NETDEV_CHANGEMTU: | |
54 | dev_set_mtu(br->dev, br_min_mtu(br)); | |
55 | break; | |
56 | ||
57 | case NETDEV_CHANGEADDR: | |
58 | spin_lock_bh(&br->lock); | |
59 | br_fdb_changeaddr(p, dev->dev_addr); | |
60 | changed_addr = br_stp_recalculate_bridge_id(br); | |
61 | spin_unlock_bh(&br->lock); | |
62 | ||
63 | if (changed_addr) | |
64 | call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev); | |
65 | ||
66 | break; | |
67 | ||
68 | case NETDEV_CHANGE: | |
69 | br_port_carrier_check(p); | |
70 | break; | |
71 | ||
72 | case NETDEV_FEAT_CHANGE: | |
73 | netdev_update_features(br->dev); | |
74 | break; | |
75 | ||
76 | case NETDEV_DOWN: | |
77 | spin_lock_bh(&br->lock); | |
78 | if (br->dev->flags & IFF_UP) | |
79 | br_stp_disable_port(p); | |
80 | spin_unlock_bh(&br->lock); | |
81 | break; | |
82 | ||
83 | case NETDEV_UP: | |
84 | if (netif_running(br->dev) && netif_oper_up(dev)) { | |
85 | spin_lock_bh(&br->lock); | |
86 | br_stp_enable_port(p); | |
87 | spin_unlock_bh(&br->lock); | |
88 | } | |
89 | break; | |
90 | ||
91 | case NETDEV_UNREGISTER: | |
92 | br_del_if(br, dev); | |
93 | break; | |
94 | ||
95 | case NETDEV_CHANGENAME: | |
96 | err = br_sysfs_renameif(p); | |
97 | if (err) | |
98 | return notifier_from_errno(err); | |
99 | break; | |
100 | ||
101 | case NETDEV_PRE_TYPE_CHANGE: | |
102 | /* Forbid underlaying device to change its type. */ | |
103 | return NOTIFY_BAD; | |
104 | ||
105 | case NETDEV_RESEND_IGMP: | |
106 | /* Propagate to master device */ | |
107 | call_netdevice_notifiers(event, br->dev); | |
108 | break; | |
109 | } | |
110 | ||
111 | /* Events that may cause spanning tree to refresh */ | |
112 | if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || | |
113 | event == NETDEV_CHANGE || event == NETDEV_DOWN) | |
114 | br_ifinfo_notify(RTM_NEWLINK, p); | |
115 | ||
116 | return NOTIFY_DONE; | |
117 | } | |
118 | ||
119 | static struct notifier_block br_device_notifier = { | |
120 | .notifier_call = br_device_event | |
121 | }; | |
122 | ||
b86f81cc WC |
123 | static void __net_exit br_net_exit(struct net *net) |
124 | { | |
125 | struct net_device *dev; | |
126 | LIST_HEAD(list); | |
127 | ||
128 | rtnl_lock(); | |
129 | for_each_netdev(net, dev) | |
130 | if (dev->priv_flags & IFF_EBRIDGE) | |
131 | br_dev_delete(dev, &list); | |
132 | ||
133 | unregister_netdevice_many(&list); | |
134 | rtnl_unlock(); | |
135 | ||
136 | } | |
cf0f02d0 | 137 | |
712d6954 AD |
138 | static struct pernet_operations br_net_ops = { |
139 | .exit = br_net_exit, | |
140 | }; | |
141 | ||
b86f81cc WC |
142 | static const struct stp_proto br_stp_proto = { |
143 | .rcv = br_stp_rcv, | |
144 | }; | |
145 | ||
1da177e4 LT |
146 | static int __init br_init(void) |
147 | { | |
c0909713 SH |
148 | int err; |
149 | ||
7c85fbf0 PM |
150 | err = stp_proto_register(&br_stp_proto); |
151 | if (err < 0) { | |
28a16c97 | 152 | pr_err("bridge: can't register sap for STP\n"); |
7c85fbf0 | 153 | return err; |
cf0f02d0 SH |
154 | } |
155 | ||
87a596e0 AM |
156 | err = br_fdb_init(); |
157 | if (err) | |
17efdd45 | 158 | goto err_out; |
1da177e4 | 159 | |
712d6954 | 160 | err = register_pernet_subsys(&br_net_ops); |
c0909713 SH |
161 | if (err) |
162 | goto err_out1; | |
163 | ||
34666d46 | 164 | err = br_nf_core_init(); |
c0909713 SH |
165 | if (err) |
166 | goto err_out2; | |
167 | ||
712d6954 | 168 | err = register_netdevice_notifier(&br_device_notifier); |
32fe21c0 TG |
169 | if (err) |
170 | goto err_out3; | |
171 | ||
712d6954 AD |
172 | err = br_netlink_init(); |
173 | if (err) | |
174 | goto err_out4; | |
175 | ||
1da177e4 | 176 | brioctl_set(br_ioctl_deviceless_stub); |
1da177e4 | 177 | |
e6373c4c | 178 | #if IS_ENABLED(CONFIG_ATM_LANE) |
da678292 MM |
179 | br_fdb_test_addr_hook = br_fdb_test_addr; |
180 | #endif | |
1da177e4 | 181 | |
34666d46 PNA |
182 | pr_info("bridge: automatic filtering via arp/ip/ip6tables has been " |
183 | "deprecated. Update your scripts to load br_netfilter if you " | |
184 | "need this.\n"); | |
185 | ||
1da177e4 | 186 | return 0; |
34666d46 | 187 | |
712d6954 | 188 | err_out4: |
32fe21c0 | 189 | unregister_netdevice_notifier(&br_device_notifier); |
712d6954 | 190 | err_out3: |
34666d46 | 191 | br_nf_core_fini(); |
712d6954 AD |
192 | err_out2: |
193 | unregister_pernet_subsys(&br_net_ops); | |
c0909713 | 194 | err_out1: |
17efdd45 PE |
195 | br_fdb_fini(); |
196 | err_out: | |
7c85fbf0 | 197 | stp_proto_unregister(&br_stp_proto); |
c0909713 | 198 | return err; |
1da177e4 LT |
199 | } |
200 | ||
201 | static void __exit br_deinit(void) | |
202 | { | |
7c85fbf0 | 203 | stp_proto_unregister(&br_stp_proto); |
11dc1f36 | 204 | br_netlink_fini(); |
1da177e4 LT |
205 | unregister_netdevice_notifier(&br_device_notifier); |
206 | brioctl_set(NULL); | |
712d6954 | 207 | unregister_pernet_subsys(&br_net_ops); |
1da177e4 | 208 | |
473c22d7 | 209 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
1da177e4 | 210 | |
34666d46 | 211 | br_nf_core_fini(); |
e6373c4c | 212 | #if IS_ENABLED(CONFIG_ATM_LANE) |
da678292 MM |
213 | br_fdb_test_addr_hook = NULL; |
214 | #endif | |
1da177e4 LT |
215 | br_fdb_fini(); |
216 | } | |
217 | ||
1da177e4 LT |
218 | module_init(br_init) |
219 | module_exit(br_deinit) | |
220 | MODULE_LICENSE("GPL"); | |
8cbb512e | 221 | MODULE_VERSION(BR_VERSION); |
bb900b27 | 222 | MODULE_ALIAS_RTNL_LINK("bridge"); |