1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Spanning tree protocol; interface code |
4 | * Linux ethernet bridge |
5 | * |
6 | * Authors: |
7 | * Lennert Buytenhek <buytenh@gnu.org> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/kmod.h> |
12 | #include <linux/etherdevice.h> |
13 | #include <linux/rtnetlink.h> |
14 | #include <net/switchdev.h> |
15 | |
16 | #include "br_private.h" |
17 | #include "br_private_stp.h" |
18 | |
19 | |
20 | /* Port id is composed of priority and port number. |
21 | * NB: some bits of priority are dropped to |
22 | * make room for more ports. |
23 | */ |
24 | static inline port_id br_make_port_id(__u8 priority, __u16 port_no) |
25 | { |
26 | return ((u16)priority << BR_PORT_BITS) |
27 | | (port_no & ((1<<BR_PORT_BITS)-1)); |
28 | } |
29 | |
30 | #define BR_MAX_PORT_PRIORITY ((u16)~0 >> BR_PORT_BITS) |
31 | |
32 | /* called under bridge lock */ |
33 | void br_init_port(struct net_bridge_port *p) |
34 | { |
35 | int err; |
36 | |
37 | p->port_id = br_make_port_id(priority: p->priority, port_no: p->port_no); |
38 | br_become_designated_port(p); |
39 | br_set_state(p, BR_STATE_BLOCKING); |
40 | p->topology_change_ack = 0; |
41 | p->config_pending = 0; |
42 | |
43 | err = __set_ageing_time(dev: p->dev, t: p->br->ageing_time); |
44 | if (err) |
45 | netdev_err(dev: p->dev, format: "failed to offload ageing time\n" ); |
46 | } |
47 | |
48 | /* NO locks held */ |
49 | void br_stp_enable_bridge(struct net_bridge *br) |
50 | { |
51 | struct net_bridge_port *p; |
52 | |
53 | spin_lock_bh(lock: &br->lock); |
54 | if (br->stp_enabled == BR_KERNEL_STP) |
55 | mod_timer(timer: &br->hello_timer, expires: jiffies + br->hello_time); |
56 | mod_delayed_work(wq: system_long_wq, dwork: &br->gc_work, HZ / 10); |
57 | |
58 | br_config_bpdu_generation(br); |
59 | |
60 | list_for_each_entry(p, &br->port_list, list) { |
61 | if (netif_running(dev: p->dev) && netif_oper_up(dev: p->dev)) |
62 | br_stp_enable_port(p); |
63 | |
64 | } |
65 | spin_unlock_bh(lock: &br->lock); |
66 | } |
67 | |
68 | /* NO locks held */ |
69 | void br_stp_disable_bridge(struct net_bridge *br) |
70 | { |
71 | struct net_bridge_port *p; |
72 | |
73 | spin_lock_bh(lock: &br->lock); |
74 | list_for_each_entry(p, &br->port_list, list) { |
75 | if (p->state != BR_STATE_DISABLED) |
76 | br_stp_disable_port(p); |
77 | |
78 | } |
79 | |
80 | __br_set_topology_change(br, val: 0); |
81 | br->topology_change_detected = 0; |
82 | spin_unlock_bh(lock: &br->lock); |
83 | |
84 | del_timer_sync(timer: &br->hello_timer); |
85 | del_timer_sync(timer: &br->topology_change_timer); |
86 | del_timer_sync(timer: &br->tcn_timer); |
87 | cancel_delayed_work_sync(dwork: &br->gc_work); |
88 | } |
89 | |
90 | /* called under bridge lock */ |
91 | void br_stp_enable_port(struct net_bridge_port *p) |
92 | { |
93 | br_init_port(p); |
94 | br_port_state_selection(p->br); |
95 | br_ifinfo_notify(RTM_NEWLINK, NULL, port: p); |
96 | } |
97 | |
98 | /* called under bridge lock */ |
99 | void br_stp_disable_port(struct net_bridge_port *p) |
100 | { |
101 | struct net_bridge *br = p->br; |
102 | int wasroot; |
103 | |
104 | wasroot = br_is_root_bridge(br); |
105 | br_become_designated_port(p); |
106 | br_set_state(p, BR_STATE_DISABLED); |
107 | p->topology_change_ack = 0; |
108 | p->config_pending = 0; |
109 | |
110 | br_ifinfo_notify(RTM_NEWLINK, NULL, port: p); |
111 | |
112 | del_timer(timer: &p->message_age_timer); |
113 | del_timer(timer: &p->forward_delay_timer); |
114 | del_timer(timer: &p->hold_timer); |
115 | |
116 | if (!rcu_access_pointer(p->backup_port)) |
117 | br_fdb_delete_by_port(br, p, vid: 0, do_all: 0); |
118 | br_multicast_disable_port(port: p); |
119 | |
120 | br_configuration_update(br); |
121 | |
122 | br_port_state_selection(br); |
123 | |
124 | if (br_is_root_bridge(br) && !wasroot) |
125 | br_become_root_bridge(br); |
126 | } |
127 | |
128 | static int br_stp_call_user(struct net_bridge *br, char *arg) |
129 | { |
130 | char *argv[] = { BR_STP_PROG, br->dev->name, arg, NULL }; |
131 | char *envp[] = { NULL }; |
132 | int rc; |
133 | |
134 | /* call userspace STP and report program errors */ |
135 | rc = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); |
136 | if (rc > 0) { |
137 | if (rc & 0xff) |
138 | br_debug(br, BR_STP_PROG " received signal %d\n" , |
139 | rc & 0x7f); |
140 | else |
141 | br_debug(br, BR_STP_PROG " exited with code %d\n" , |
142 | (rc >> 8) & 0xff); |
143 | } |
144 | |
145 | return rc; |
146 | } |
147 | |
148 | static void br_stp_start(struct net_bridge *br) |
149 | { |
150 | int err = -ENOENT; |
151 | |
152 | if (net_eq(net1: dev_net(dev: br->dev), net2: &init_net)) |
153 | err = br_stp_call_user(br, arg: "start" ); |
154 | |
155 | if (err && err != -ENOENT) |
156 | br_err(br, "failed to start userspace STP (%d)\n" , err); |
157 | |
158 | spin_lock_bh(lock: &br->lock); |
159 | |
160 | if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY) |
161 | __br_set_forward_delay(br, BR_MIN_FORWARD_DELAY); |
162 | else if (br->bridge_forward_delay > BR_MAX_FORWARD_DELAY) |
163 | __br_set_forward_delay(br, BR_MAX_FORWARD_DELAY); |
164 | |
165 | if (!err) { |
166 | br->stp_enabled = BR_USER_STP; |
167 | br_debug(br, "userspace STP started\n" ); |
168 | } else { |
169 | br->stp_enabled = BR_KERNEL_STP; |
170 | br_debug(br, "using kernel STP\n" ); |
171 | |
172 | /* To start timers on any ports left in blocking */ |
173 | if (br->dev->flags & IFF_UP) |
174 | mod_timer(timer: &br->hello_timer, expires: jiffies + br->hello_time); |
175 | br_port_state_selection(br); |
176 | } |
177 | |
178 | spin_unlock_bh(lock: &br->lock); |
179 | } |
180 | |
181 | static void br_stp_stop(struct net_bridge *br) |
182 | { |
183 | int err; |
184 | |
185 | if (br->stp_enabled == BR_USER_STP) { |
186 | err = br_stp_call_user(br, arg: "stop" ); |
187 | if (err) |
188 | br_err(br, "failed to stop userspace STP (%d)\n" , err); |
189 | |
190 | /* To start timers on any ports left in blocking */ |
191 | spin_lock_bh(lock: &br->lock); |
192 | br_port_state_selection(br); |
193 | spin_unlock_bh(lock: &br->lock); |
194 | } |
195 | |
196 | br->stp_enabled = BR_NO_STP; |
197 | } |
198 | |
199 | int br_stp_set_enabled(struct net_bridge *br, unsigned long val, |
200 | struct netlink_ext_ack *extack) |
201 | { |
202 | ASSERT_RTNL(); |
203 | |
204 | if (br_mrp_enabled(br)) { |
205 | NL_SET_ERR_MSG_MOD(extack, |
206 | "STP can't be enabled if MRP is already enabled" ); |
207 | return -EINVAL; |
208 | } |
209 | |
210 | if (val) { |
211 | if (br->stp_enabled == BR_NO_STP) |
212 | br_stp_start(br); |
213 | } else { |
214 | if (br->stp_enabled != BR_NO_STP) |
215 | br_stp_stop(br); |
216 | } |
217 | |
218 | return 0; |
219 | } |
220 | |
221 | /* called under bridge lock */ |
222 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) |
223 | { |
224 | /* should be aligned on 2 bytes for ether_addr_equal() */ |
225 | unsigned short oldaddr_aligned[ETH_ALEN >> 1]; |
226 | unsigned char *oldaddr = (unsigned char *)oldaddr_aligned; |
227 | struct net_bridge_port *p; |
228 | int wasroot; |
229 | |
230 | wasroot = br_is_root_bridge(br); |
231 | |
232 | br_fdb_change_mac_address(br, newaddr: addr); |
233 | |
234 | memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN); |
235 | memcpy(br->bridge_id.addr, addr, ETH_ALEN); |
236 | eth_hw_addr_set(dev: br->dev, addr); |
237 | |
238 | list_for_each_entry(p, &br->port_list, list) { |
239 | if (ether_addr_equal(addr1: p->designated_bridge.addr, addr2: oldaddr)) |
240 | memcpy(p->designated_bridge.addr, addr, ETH_ALEN); |
241 | |
242 | if (ether_addr_equal(addr1: p->designated_root.addr, addr2: oldaddr)) |
243 | memcpy(p->designated_root.addr, addr, ETH_ALEN); |
244 | } |
245 | |
246 | br_configuration_update(br); |
247 | br_port_state_selection(br); |
248 | if (br_is_root_bridge(br) && !wasroot) |
249 | br_become_root_bridge(br); |
250 | } |
251 | |
252 | /* should be aligned on 2 bytes for ether_addr_equal() */ |
253 | static const unsigned short br_mac_zero_aligned[ETH_ALEN >> 1]; |
254 | |
255 | /* called under bridge lock */ |
256 | bool br_stp_recalculate_bridge_id(struct net_bridge *br) |
257 | { |
258 | const unsigned char *br_mac_zero = |
259 | (const unsigned char *)br_mac_zero_aligned; |
260 | const unsigned char *addr = br_mac_zero; |
261 | struct net_bridge_port *p; |
262 | |
263 | /* user has chosen a value so keep it */ |
264 | if (br->dev->addr_assign_type == NET_ADDR_SET) |
265 | return false; |
266 | |
267 | list_for_each_entry(p, &br->port_list, list) { |
268 | if (addr == br_mac_zero || |
269 | memcmp(p: p->dev->dev_addr, q: addr, ETH_ALEN) < 0) |
270 | addr = p->dev->dev_addr; |
271 | |
272 | } |
273 | |
274 | if (ether_addr_equal(addr1: br->bridge_id.addr, addr2: addr)) |
275 | return false; /* no change */ |
276 | |
277 | br_stp_change_bridge_id(br, addr); |
278 | return true; |
279 | } |
280 | |
281 | /* Acquires and releases bridge lock */ |
282 | void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) |
283 | { |
284 | struct net_bridge_port *p; |
285 | int wasroot; |
286 | |
287 | spin_lock_bh(lock: &br->lock); |
288 | wasroot = br_is_root_bridge(br); |
289 | |
290 | list_for_each_entry(p, &br->port_list, list) { |
291 | if (p->state != BR_STATE_DISABLED && |
292 | br_is_designated_port(p)) { |
293 | p->designated_bridge.prio[0] = (newprio >> 8) & 0xFF; |
294 | p->designated_bridge.prio[1] = newprio & 0xFF; |
295 | } |
296 | |
297 | } |
298 | |
299 | br->bridge_id.prio[0] = (newprio >> 8) & 0xFF; |
300 | br->bridge_id.prio[1] = newprio & 0xFF; |
301 | br_configuration_update(br); |
302 | br_port_state_selection(br); |
303 | if (br_is_root_bridge(br) && !wasroot) |
304 | br_become_root_bridge(br); |
305 | spin_unlock_bh(lock: &br->lock); |
306 | } |
307 | |
308 | /* called under bridge lock */ |
309 | int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio) |
310 | { |
311 | port_id new_port_id; |
312 | |
313 | if (newprio > BR_MAX_PORT_PRIORITY) |
314 | return -ERANGE; |
315 | |
316 | new_port_id = br_make_port_id(priority: newprio, port_no: p->port_no); |
317 | if (br_is_designated_port(p)) |
318 | p->designated_port = new_port_id; |
319 | |
320 | p->port_id = new_port_id; |
321 | p->priority = newprio; |
322 | if (!memcmp(p: &p->br->bridge_id, q: &p->designated_bridge, size: 8) && |
323 | p->port_id < p->designated_port) { |
324 | br_become_designated_port(p); |
325 | br_port_state_selection(p->br); |
326 | } |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | /* called under bridge lock */ |
332 | int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost) |
333 | { |
334 | if (path_cost < BR_MIN_PATH_COST || |
335 | path_cost > BR_MAX_PATH_COST) |
336 | return -ERANGE; |
337 | |
338 | p->flags |= BR_ADMIN_COST; |
339 | p->path_cost = path_cost; |
340 | br_configuration_update(p->br); |
341 | br_port_state_selection(p->br); |
342 | return 0; |
343 | } |
344 | |
345 | ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id) |
346 | { |
347 | return sprintf(buf, fmt: "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n" , |
348 | id->prio[0], id->prio[1], |
349 | id->addr[0], id->addr[1], id->addr[2], |
350 | id->addr[3], id->addr[4], id->addr[5]); |
351 | } |
352 | |