2 * Spanning tree protocol; generic parts
3 * Linux ethernet bridge
6 * Lennert Buytenhek <buytenh@gnu.org>
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.
13 #include <linux/kernel.h>
14 #include <linux/rculist.h>
16 #include "br_private.h"
17 #include "br_private_stp.h"
19 /* since time values in bpdu are in jiffies and then scaled (1/256)
20 * before sending, make sure that is at least one.
22 #define MESSAGE_AGE_INCR ((HZ < 256) ? 1 : (HZ/256))
24 static const char *const br_port_state_names
[] = {
25 [BR_STATE_DISABLED
] = "disabled",
26 [BR_STATE_LISTENING
] = "listening",
27 [BR_STATE_LEARNING
] = "learning",
28 [BR_STATE_FORWARDING
] = "forwarding",
29 [BR_STATE_BLOCKING
] = "blocking",
32 void br_log_state(const struct net_bridge_port
*p
)
34 br_info(p
->br
, "port %u(%s) entering %s state\n",
35 (unsigned) p
->port_no
, p
->dev
->name
,
36 br_port_state_names
[p
->state
]);
39 /* called under bridge lock */
40 struct net_bridge_port
*br_get_port(struct net_bridge
*br
, u16 port_no
)
42 struct net_bridge_port
*p
;
44 list_for_each_entry_rcu(p
, &br
->port_list
, list
) {
45 if (p
->port_no
== port_no
)
52 /* called under bridge lock */
53 static int br_should_become_root_port(const struct net_bridge_port
*p
,
56 struct net_bridge
*br
;
57 struct net_bridge_port
*rp
;
61 if (p
->state
== BR_STATE_DISABLED
||
62 br_is_designated_port(p
))
65 if (memcmp(&br
->bridge_id
, &p
->designated_root
, 8) <= 0)
71 rp
= br_get_port(br
, root_port
);
73 t
= memcmp(&p
->designated_root
, &rp
->designated_root
, 8);
79 if (p
->designated_cost
+ p
->path_cost
<
80 rp
->designated_cost
+ rp
->path_cost
)
82 else if (p
->designated_cost
+ p
->path_cost
>
83 rp
->designated_cost
+ rp
->path_cost
)
86 t
= memcmp(&p
->designated_bridge
, &rp
->designated_bridge
, 8);
92 if (p
->designated_port
< rp
->designated_port
)
94 else if (p
->designated_port
> rp
->designated_port
)
97 if (p
->port_id
< rp
->port_id
)
103 /* called under bridge lock */
104 static void br_root_selection(struct net_bridge
*br
)
106 struct net_bridge_port
*p
;
109 list_for_each_entry(p
, &br
->port_list
, list
) {
110 if (br_should_become_root_port(p
, root_port
))
111 root_port
= p
->port_no
;
114 br
->root_port
= root_port
;
117 br
->designated_root
= br
->bridge_id
;
118 br
->root_path_cost
= 0;
120 p
= br_get_port(br
, root_port
);
121 br
->designated_root
= p
->designated_root
;
122 br
->root_path_cost
= p
->designated_cost
+ p
->path_cost
;
126 /* called under bridge lock */
127 void br_become_root_bridge(struct net_bridge
*br
)
129 br
->max_age
= br
->bridge_max_age
;
130 br
->hello_time
= br
->bridge_hello_time
;
131 br
->forward_delay
= br
->bridge_forward_delay
;
132 br_topology_change_detection(br
);
133 del_timer(&br
->tcn_timer
);
135 if (br
->dev
->flags
& IFF_UP
) {
136 br_config_bpdu_generation(br
);
137 mod_timer(&br
->hello_timer
, jiffies
+ br
->hello_time
);
141 /* called under bridge lock */
142 void br_transmit_config(struct net_bridge_port
*p
)
144 struct br_config_bpdu bpdu
;
145 struct net_bridge
*br
;
147 if (timer_pending(&p
->hold_timer
)) {
148 p
->config_pending
= 1;
154 bpdu
.topology_change
= br
->topology_change
;
155 bpdu
.topology_change_ack
= p
->topology_change_ack
;
156 bpdu
.root
= br
->designated_root
;
157 bpdu
.root_path_cost
= br
->root_path_cost
;
158 bpdu
.bridge_id
= br
->bridge_id
;
159 bpdu
.port_id
= p
->port_id
;
160 if (br_is_root_bridge(br
))
161 bpdu
.message_age
= 0;
163 struct net_bridge_port
*root
164 = br_get_port(br
, br
->root_port
);
165 bpdu
.message_age
= (jiffies
- root
->designated_age
)
168 bpdu
.max_age
= br
->max_age
;
169 bpdu
.hello_time
= br
->hello_time
;
170 bpdu
.forward_delay
= br
->forward_delay
;
172 if (bpdu
.message_age
< br
->max_age
) {
173 br_send_config_bpdu(p
, &bpdu
);
174 p
->topology_change_ack
= 0;
175 p
->config_pending
= 0;
176 mod_timer(&p
->hold_timer
,
177 round_jiffies(jiffies
+ BR_HOLD_TIME
));
181 /* called under bridge lock */
182 static void br_record_config_information(struct net_bridge_port
*p
,
183 const struct br_config_bpdu
*bpdu
)
185 p
->designated_root
= bpdu
->root
;
186 p
->designated_cost
= bpdu
->root_path_cost
;
187 p
->designated_bridge
= bpdu
->bridge_id
;
188 p
->designated_port
= bpdu
->port_id
;
189 p
->designated_age
= jiffies
+ bpdu
->message_age
;
191 mod_timer(&p
->message_age_timer
, jiffies
192 + (p
->br
->max_age
- bpdu
->message_age
));
195 /* called under bridge lock */
196 static void br_record_config_timeout_values(struct net_bridge
*br
,
197 const struct br_config_bpdu
*bpdu
)
199 br
->max_age
= bpdu
->max_age
;
200 br
->hello_time
= bpdu
->hello_time
;
201 br
->forward_delay
= bpdu
->forward_delay
;
202 br
->topology_change
= bpdu
->topology_change
;
205 /* called under bridge lock */
206 void br_transmit_tcn(struct net_bridge
*br
)
208 br_send_tcn_bpdu(br_get_port(br
, br
->root_port
));
211 /* called under bridge lock */
212 static int br_should_become_designated_port(const struct net_bridge_port
*p
)
214 struct net_bridge
*br
;
218 if (br_is_designated_port(p
))
221 if (memcmp(&p
->designated_root
, &br
->designated_root
, 8))
224 if (br
->root_path_cost
< p
->designated_cost
)
226 else if (br
->root_path_cost
> p
->designated_cost
)
229 t
= memcmp(&br
->bridge_id
, &p
->designated_bridge
, 8);
235 if (p
->port_id
< p
->designated_port
)
241 /* called under bridge lock */
242 static void br_designated_port_selection(struct net_bridge
*br
)
244 struct net_bridge_port
*p
;
246 list_for_each_entry(p
, &br
->port_list
, list
) {
247 if (p
->state
!= BR_STATE_DISABLED
&&
248 br_should_become_designated_port(p
))
249 br_become_designated_port(p
);
254 /* called under bridge lock */
255 static int br_supersedes_port_info(const struct net_bridge_port
*p
,
256 const struct br_config_bpdu
*bpdu
)
260 t
= memcmp(&bpdu
->root
, &p
->designated_root
, 8);
266 if (bpdu
->root_path_cost
< p
->designated_cost
)
268 else if (bpdu
->root_path_cost
> p
->designated_cost
)
271 t
= memcmp(&bpdu
->bridge_id
, &p
->designated_bridge
, 8);
277 if (memcmp(&bpdu
->bridge_id
, &p
->br
->bridge_id
, 8))
280 if (bpdu
->port_id
<= p
->designated_port
)
286 /* called under bridge lock */
287 static void br_topology_change_acknowledged(struct net_bridge
*br
)
289 br
->topology_change_detected
= 0;
290 del_timer(&br
->tcn_timer
);
293 /* called under bridge lock */
294 void br_topology_change_detection(struct net_bridge
*br
)
296 int isroot
= br_is_root_bridge(br
);
298 if (br
->stp_enabled
!= BR_KERNEL_STP
)
301 br_info(br
, "topology change detected, %s\n",
302 isroot
? "propagating" : "sending tcn bpdu");
305 br
->topology_change
= 1;
306 mod_timer(&br
->topology_change_timer
, jiffies
307 + br
->bridge_forward_delay
+ br
->bridge_max_age
);
308 } else if (!br
->topology_change_detected
) {
310 mod_timer(&br
->tcn_timer
, jiffies
+ br
->bridge_hello_time
);
313 br
->topology_change_detected
= 1;
316 /* called under bridge lock */
317 void br_config_bpdu_generation(struct net_bridge
*br
)
319 struct net_bridge_port
*p
;
321 list_for_each_entry(p
, &br
->port_list
, list
) {
322 if (p
->state
!= BR_STATE_DISABLED
&&
323 br_is_designated_port(p
))
324 br_transmit_config(p
);
328 /* called under bridge lock */
329 static void br_reply(struct net_bridge_port
*p
)
331 br_transmit_config(p
);
334 /* called under bridge lock */
335 void br_configuration_update(struct net_bridge
*br
)
337 br_root_selection(br
);
338 br_designated_port_selection(br
);
341 /* called under bridge lock */
342 void br_become_designated_port(struct net_bridge_port
*p
)
344 struct net_bridge
*br
;
347 p
->designated_root
= br
->designated_root
;
348 p
->designated_cost
= br
->root_path_cost
;
349 p
->designated_bridge
= br
->bridge_id
;
350 p
->designated_port
= p
->port_id
;
354 /* called under bridge lock */
355 static void br_make_blocking(struct net_bridge_port
*p
)
357 if (p
->state
!= BR_STATE_DISABLED
&&
358 p
->state
!= BR_STATE_BLOCKING
) {
359 if (p
->state
== BR_STATE_FORWARDING
||
360 p
->state
== BR_STATE_LEARNING
)
361 br_topology_change_detection(p
->br
);
363 p
->state
= BR_STATE_BLOCKING
;
365 br_ifinfo_notify(RTM_NEWLINK
, p
);
367 del_timer(&p
->forward_delay_timer
);
371 /* called under bridge lock */
372 static void br_make_forwarding(struct net_bridge_port
*p
)
374 struct net_bridge
*br
= p
->br
;
376 if (p
->state
!= BR_STATE_BLOCKING
)
379 if (br
->stp_enabled
== BR_NO_STP
|| br
->forward_delay
== 0) {
380 p
->state
= BR_STATE_FORWARDING
;
381 br_topology_change_detection(br
);
382 del_timer(&p
->forward_delay_timer
);
383 } else if (br
->stp_enabled
== BR_KERNEL_STP
)
384 p
->state
= BR_STATE_LISTENING
;
386 p
->state
= BR_STATE_LEARNING
;
388 br_multicast_enable_port(p
);
390 br_ifinfo_notify(RTM_NEWLINK
, p
);
392 if (br
->forward_delay
!= 0)
393 mod_timer(&p
->forward_delay_timer
, jiffies
+ br
->forward_delay
);
396 /* called under bridge lock */
397 void br_port_state_selection(struct net_bridge
*br
)
399 struct net_bridge_port
*p
;
400 unsigned int liveports
= 0;
402 list_for_each_entry(p
, &br
->port_list
, list
) {
403 if (p
->state
== BR_STATE_DISABLED
)
406 /* Don't change port states if userspace is handling STP */
407 if (br
->stp_enabled
!= BR_USER_STP
) {
408 if (p
->port_no
== br
->root_port
) {
409 p
->config_pending
= 0;
410 p
->topology_change_ack
= 0;
411 br_make_forwarding(p
);
412 } else if (br_is_designated_port(p
)) {
413 del_timer(&p
->message_age_timer
);
414 br_make_forwarding(p
);
416 p
->config_pending
= 0;
417 p
->topology_change_ack
= 0;
422 if (p
->state
== BR_STATE_FORWARDING
)
427 netif_carrier_off(br
->dev
);
429 netif_carrier_on(br
->dev
);
432 /* called under bridge lock */
433 static void br_topology_change_acknowledge(struct net_bridge_port
*p
)
435 p
->topology_change_ack
= 1;
436 br_transmit_config(p
);
439 /* called under bridge lock */
440 void br_received_config_bpdu(struct net_bridge_port
*p
,
441 const struct br_config_bpdu
*bpdu
)
443 struct net_bridge
*br
;
447 was_root
= br_is_root_bridge(br
);
449 if (br_supersedes_port_info(p
, bpdu
)) {
450 br_record_config_information(p
, bpdu
);
451 br_configuration_update(br
);
452 br_port_state_selection(br
);
454 if (!br_is_root_bridge(br
) && was_root
) {
455 del_timer(&br
->hello_timer
);
456 if (br
->topology_change_detected
) {
457 del_timer(&br
->topology_change_timer
);
460 mod_timer(&br
->tcn_timer
,
461 jiffies
+ br
->bridge_hello_time
);
465 if (p
->port_no
== br
->root_port
) {
466 br_record_config_timeout_values(br
, bpdu
);
467 br_config_bpdu_generation(br
);
468 if (bpdu
->topology_change_ack
)
469 br_topology_change_acknowledged(br
);
471 } else if (br_is_designated_port(p
)) {
476 /* called under bridge lock */
477 void br_received_tcn_bpdu(struct net_bridge_port
*p
)
479 if (br_is_designated_port(p
)) {
480 br_info(p
->br
, "port %u(%s) received tcn bpdu\n",
481 (unsigned) p
->port_no
, p
->dev
->name
);
483 br_topology_change_detection(p
->br
);
484 br_topology_change_acknowledge(p
);
488 /* Change bridge STP parameter */
489 int br_set_hello_time(struct net_bridge
*br
, unsigned long val
)
491 unsigned long t
= clock_t_to_jiffies(val
);
493 if (t
< BR_MIN_HELLO_TIME
|| t
> BR_MAX_HELLO_TIME
)
496 spin_lock_bh(&br
->lock
);
497 br
->bridge_hello_time
= t
;
498 if (br_is_root_bridge(br
))
499 br
->hello_time
= br
->bridge_hello_time
;
500 spin_unlock_bh(&br
->lock
);
504 int br_set_max_age(struct net_bridge
*br
, unsigned long val
)
506 unsigned long t
= clock_t_to_jiffies(val
);
508 if (t
< BR_MIN_MAX_AGE
|| t
> BR_MAX_MAX_AGE
)
511 spin_lock_bh(&br
->lock
);
512 br
->bridge_max_age
= t
;
513 if (br_is_root_bridge(br
))
514 br
->max_age
= br
->bridge_max_age
;
515 spin_unlock_bh(&br
->lock
);
520 int br_set_forward_delay(struct net_bridge
*br
, unsigned long val
)
522 unsigned long t
= clock_t_to_jiffies(val
);
524 if (br
->stp_enabled
!= BR_NO_STP
&&
525 (t
< BR_MIN_FORWARD_DELAY
|| t
> BR_MAX_FORWARD_DELAY
))
528 spin_lock_bh(&br
->lock
);
529 br
->bridge_forward_delay
= t
;
530 if (br_is_root_bridge(br
))
531 br
->forward_delay
= br
->bridge_forward_delay
;
532 spin_unlock_bh(&br
->lock
);