2 * Copyright (c) 2008-2014, 2016-2017 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /* Based on sample implementation in 802.1D-1998. Above copyright and license
18 * applies to all modifications. */
23 #include <sys/types.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
28 #include "byte-order.h"
29 #include "connectivity.h"
30 #include "openvswitch/ofpbuf.h"
31 #include "ovs-atomic.h"
32 #include "dp-packet.h"
37 #include "openvswitch/vlog.h"
39 VLOG_DEFINE_THIS_MODULE(stp
);
41 static struct vlog_rate_limit stp_rl
= VLOG_RATE_LIMIT_INIT(60, 60);
43 #define STP_PROTOCOL_ID 0x0000
44 #define STP_PROTOCOL_VERSION 0x00
45 #define STP_TYPE_CONFIG 0x00
46 #define STP_TYPE_TCN 0x80
48 struct stp_bpdu_header
{
49 ovs_be16 protocol_id
; /* STP_PROTOCOL_ID. */
50 uint8_t protocol_version
; /* STP_PROTOCOL_VERSION. */
51 uint8_t bpdu_type
; /* One of STP_TYPE_*. */
53 BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header
) == 4);
55 enum stp_config_bpdu_flags
{
56 STP_CONFIG_TOPOLOGY_CHANGE_ACK
= 0x80,
57 STP_CONFIG_TOPOLOGY_CHANGE
= 0x01
61 struct stp_config_bpdu
{
62 struct stp_bpdu_header header
; /* Type STP_TYPE_CONFIG. */
63 uint8_t flags
; /* STP_CONFIG_* flags. */
64 ovs_be64 root_id
; /* 8.5.1.1: Bridge believed to be root. */
65 ovs_be32 root_path_cost
; /* 8.5.1.2: Cost of path to root. */
66 ovs_be64 bridge_id
; /* 8.5.1.3: ID of transmitting bridge. */
67 ovs_be16 port_id
; /* 8.5.1.4: Port transmitting the BPDU. */
68 ovs_be16 message_age
; /* 8.5.1.5: Age of BPDU at tx time. */
69 ovs_be16 max_age
; /* 8.5.1.6: Timeout for received data. */
70 ovs_be16 hello_time
; /* 8.5.1.7: Time between BPDU generation. */
71 ovs_be16 forward_delay
; /* 8.5.1.8: State progression delay. */
73 BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu
) == 35);
76 struct stp_bpdu_header header
; /* Type STP_TYPE_TCN. */
78 BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu
) == 4);
81 bool active
; /* Timer in use? */
82 int value
; /* Current value of timer, counting up. */
87 char *port_name
; /* Human-readable name for log messages. */
88 void *aux
; /* Auxiliary data the user may retrieve. */
89 int port_id
; /* 8.5.5.1: Unique port identifier. */
90 enum stp_state state
; /* 8.5.5.2: Current state. */
91 int path_cost
; /* 8.5.5.3: Cost of tx/rx on this port. */
92 stp_identifier designated_root
; /* 8.5.5.4. */
93 int designated_cost
; /* 8.5.5.5: Path cost to root on port. */
94 stp_identifier designated_bridge
; /* 8.5.5.6. */
95 int designated_port
; /* 8.5.5.7: Port to send config msgs on. */
96 bool topology_change_ack
; /* 8.5.5.8: Flag for next config BPDU. */
97 bool config_pending
; /* 8.5.5.9: Send BPDU when hold expires? */
98 bool change_detection_enabled
; /* 8.5.5.10: Detect topology changes? */
100 struct stp_timer message_age_timer
; /* 8.5.6.1: Age of received info. */
101 struct stp_timer forward_delay_timer
; /* 8.5.6.2: State change timer. */
102 struct stp_timer hold_timer
; /* 8.5.6.3: BPDU rate limit timer. */
104 int tx_count
; /* Number of BPDUs transmitted. */
105 int rx_count
; /* Number of valid BPDUs received. */
106 int error_count
; /* Number of bad BPDUs received. */
112 struct ovs_list node
; /* Node in all_stps list. */
114 /* Static bridge data. */
115 char *name
; /* Human-readable name for log messages. */
116 stp_identifier bridge_id
; /* 8.5.3.7: This bridge. */
117 int max_age
; /* 8.5.3.4: Time to drop received data. */
118 int hello_time
; /* 8.5.3.5: Time between sending BPDUs. */
119 int forward_delay
; /* 8.5.3.6: Delay between state changes. */
120 int bridge_max_age
; /* 8.5.3.8: max_age when we're root. */
121 int bridge_hello_time
; /* 8.5.3.9: hello_time as root. */
122 int bridge_forward_delay
; /* 8.5.3.10: forward_delay as root. */
123 int rq_max_age
; /* User-requested max age, in ms. */
124 int rq_hello_time
; /* User-requested hello time, in ms. */
125 int rq_forward_delay
; /* User-requested forward delay, in ms. */
126 int elapsed_remainder
; /* Left-over msecs from last stp_tick(). */
128 /* Dynamic bridge data. */
129 stp_identifier designated_root
; /* 8.5.3.1: Bridge believed to be root. */
130 unsigned int root_path_cost
; /* 8.5.3.2: Cost of path to root. */
131 struct stp_port
*root_port
; /* 8.5.3.3: Lowest cost port to root. */
132 bool topology_change_detected
; /* 8.5.3.11: Detected a topology change? */
133 bool topology_change
; /* 8.5.3.12: Received topology change? */
136 struct stp_timer hello_timer
; /* 8.5.4.1: Hello timer. */
137 struct stp_timer tcn_timer
; /* 8.5.4.2: Topology change timer. */
138 struct stp_timer topology_change_timer
; /* 8.5.4.3. */
141 struct stp_port ports
[STP_MAX_PORTS
];
143 /* Interface to client. */
144 bool fdb_needs_flush
; /* MAC learning tables needs flushing. */
145 struct stp_port
*first_changed_port
;
146 void (*send_bpdu
)(struct dp_packet
*bpdu
, int port_no
, void *aux
);
149 struct ovs_refcount ref_cnt
;
152 static struct ovs_mutex mutex
;
153 static struct ovs_list all_stps__
= OVS_LIST_INITIALIZER(&all_stps__
);
154 static struct ovs_list
*const all_stps
OVS_GUARDED_BY(mutex
) = &all_stps__
;
156 #define FOR_EACH_ENABLED_PORT(PORT, STP) \
157 for ((PORT) = stp_next_enabled_port((STP), (STP)->ports); \
159 (PORT) = stp_next_enabled_port((STP), (PORT) + 1))
160 static struct stp_port
*
161 stp_next_enabled_port(const struct stp
*stp
, const struct stp_port
*port
)
164 for (; port
< &stp
->ports
[ARRAY_SIZE(stp
->ports
)]; port
++) {
165 if (port
->state
!= STP_DISABLED
) {
166 return CONST_CAST(struct stp_port
*, port
);
172 #define MESSAGE_AGE_INCREMENT 1
174 static void stp_transmit_config(struct stp_port
*) OVS_REQUIRES(mutex
);
175 static bool stp_supersedes_port_info(const struct stp_port
*,
176 const struct stp_config_bpdu
*)
178 static void stp_record_config_information(struct stp_port
*,
179 const struct stp_config_bpdu
*)
181 static void stp_record_config_timeout_values(struct stp
*,
182 const struct stp_config_bpdu
*)
184 static bool stp_is_designated_port(const struct stp_port
*)
186 static void stp_config_bpdu_generation(struct stp
*) OVS_REQUIRES(mutex
);
187 static void stp_transmit_tcn(struct stp
*) OVS_REQUIRES(mutex
);
188 static void stp_configuration_update(struct stp
*) OVS_REQUIRES(mutex
);
189 static bool stp_supersedes_root(const struct stp_port
*root
,
190 const struct stp_port
*) OVS_REQUIRES(mutex
);
191 static void stp_root_selection(struct stp
*) OVS_REQUIRES(mutex
);
192 static void stp_designated_port_selection(struct stp
*) OVS_REQUIRES(mutex
);
193 static void stp_become_designated_port(struct stp_port
*)
195 static void stp_port_state_selection(struct stp
*) OVS_REQUIRES(mutex
);
196 static void stp_make_forwarding(struct stp_port
*) OVS_REQUIRES(mutex
);
197 static void stp_make_blocking(struct stp_port
*) OVS_REQUIRES(mutex
);
198 static void stp_set_port_state(struct stp_port
*, enum stp_state
)
200 static void stp_topology_change_detection(struct stp
*) OVS_REQUIRES(mutex
);
201 static void stp_topology_change_acknowledged(struct stp
*)
203 static void stp_acknowledge_topology_change(struct stp_port
*)
205 static void stp_received_config_bpdu(struct stp
*, struct stp_port
*,
206 const struct stp_config_bpdu
*)
208 static void stp_received_tcn_bpdu(struct stp
*, struct stp_port
*)
210 static void stp_hello_timer_expiry(struct stp
*) OVS_REQUIRES(mutex
);
211 static void stp_message_age_timer_expiry(struct stp_port
*)
213 static bool stp_is_designated_for_some_port(const struct stp
*)
215 static void stp_forward_delay_timer_expiry(struct stp_port
*)
217 static void stp_tcn_timer_expiry(struct stp
*) OVS_REQUIRES(mutex
);
218 static void stp_topology_change_timer_expiry(struct stp
*)
220 static void stp_hold_timer_expiry(struct stp_port
*) OVS_REQUIRES(mutex
);
221 static void stp_initialize_port(struct stp_port
*, enum stp_state
)
223 static void stp_become_root_bridge(struct stp
*) OVS_REQUIRES(mutex
);
224 static void stp_update_bridge_timers(struct stp
*) OVS_REQUIRES(mutex
);
226 static int clamp(int x
, int min
, int max
);
227 static int ms_to_timer(int ms
);
228 static int timer_to_ms(int timer
);
229 static void stp_start_timer(struct stp_timer
*, int value
);
230 static void stp_stop_timer(struct stp_timer
*);
231 static bool stp_timer_expired(struct stp_timer
*, int elapsed
, int timeout
);
233 static void stp_send_bpdu(struct stp_port
*, const void *, size_t)
235 static void stp_unixctl_tcn(struct unixctl_conn
*, int argc
,
236 const char *argv
[], void *aux
);
237 static void stp_unixctl_show(struct unixctl_conn
*, int argc
,
238 const char *argv
[], void *aux
);
243 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
245 if (ovsthread_once_start(&once
)) {
246 /* We need a recursive mutex because stp_send_bpdu() could loop back
247 * into the stp module through a patch port. This happens
248 * intentionally as part of the unit tests. Ideally we'd ditch
249 * the call back function, but for now this is what we have. */
250 ovs_mutex_init_recursive(&mutex
);
252 unixctl_command_register("stp/tcn", "[bridge]", 0, 1, stp_unixctl_tcn
,
254 unixctl_command_register("stp/show", "[bridge]", 0, 1,
255 stp_unixctl_show
, NULL
);
256 ovsthread_once_done(&once
);
260 /* Creates and returns a new STP instance that initially has no ports enabled.
262 * 'bridge_id' should be a 48-bit MAC address as returned by
263 * eth_addr_to_uint64(). 'bridge_id' may also have a priority value in its top
264 * 16 bits; if those bits are set to 0, STP_DEFAULT_BRIDGE_PRIORITY is used.
265 * (This priority may be changed with stp_set_bridge_priority().)
267 * When the bridge needs to send out a BPDU, it calls 'send_bpdu'. This
268 * callback may be called from stp_tick() or stp_received_bpdu(). The
269 * arguments to 'send_bpdu' are an STP BPDU encapsulated in 'bpdu',
270 * the spanning tree port number 'port_no' that should transmit the
271 * packet, and auxiliary data to be passed to the callback in 'aux'.
274 stp_create(const char *name
, stp_identifier bridge_id
,
275 void (*send_bpdu
)(struct dp_packet
*bpdu
, int port_no
, void *aux
),
283 ovs_mutex_lock(&mutex
);
284 stp
= xzalloc(sizeof *stp
);
285 stp
->name
= xstrdup(name
);
286 stp
->bridge_id
= bridge_id
;
287 if (!(stp
->bridge_id
>> 48)) {
288 stp
->bridge_id
|= (uint64_t) STP_DEFAULT_BRIDGE_PRIORITY
<< 48;
291 stp
->rq_max_age
= STP_DEFAULT_MAX_AGE
;
292 stp
->rq_hello_time
= STP_DEFAULT_HELLO_TIME
;
293 stp
->rq_forward_delay
= STP_DEFAULT_FWD_DELAY
;
294 stp_update_bridge_timers(stp
);
295 stp
->max_age
= stp
->bridge_max_age
;
296 stp
->hello_time
= stp
->bridge_hello_time
;
297 stp
->forward_delay
= stp
->bridge_forward_delay
;
299 stp
->designated_root
= stp
->bridge_id
;
300 stp
->root_path_cost
= 0;
301 stp
->root_port
= NULL
;
302 stp
->topology_change_detected
= false;
303 stp
->topology_change
= false;
305 stp_stop_timer(&stp
->tcn_timer
);
306 stp_stop_timer(&stp
->topology_change_timer
);
307 stp_start_timer(&stp
->hello_timer
, stp
->hello_time
);
309 stp
->send_bpdu
= send_bpdu
;
312 stp
->first_changed_port
= &stp
->ports
[ARRAY_SIZE(stp
->ports
)];
313 for (p
= stp
->ports
; p
< &stp
->ports
[ARRAY_SIZE(stp
->ports
)]; p
++) {
315 p
->port_id
= (stp_port_no(p
) + 1) | (STP_DEFAULT_PORT_PRIORITY
<< 8);
316 p
->path_cost
= 19; /* Recommended default for 100 Mb/s link. */
317 stp_initialize_port(p
, STP_DISABLED
);
319 ovs_refcount_init(&stp
->ref_cnt
);
321 ovs_list_push_back(all_stps
, &stp
->node
);
322 ovs_mutex_unlock(&mutex
);
327 stp_ref(const struct stp
*stp_
)
329 struct stp
*stp
= CONST_CAST(struct stp
*, stp_
);
331 ovs_refcount_ref(&stp
->ref_cnt
);
336 /* Destroys 'stp'. */
338 stp_unref(struct stp
*stp
)
340 if (stp
&& ovs_refcount_unref_relaxed(&stp
->ref_cnt
) == 1) {
343 ovs_mutex_lock(&mutex
);
344 ovs_list_remove(&stp
->node
);
345 ovs_mutex_unlock(&mutex
);
348 for (i
= 0; i
< STP_MAX_PORTS
; i
++) {
349 free(stp
->ports
[i
].port_name
);
355 /* Runs 'stp' given that 'ms' milliseconds have passed. */
357 stp_tick(struct stp
*stp
, int ms
)
362 ovs_mutex_lock(&mutex
);
363 /* Convert 'ms' to STP timer ticks. Preserve any leftover milliseconds
364 * from previous stp_tick() calls so that we don't lose STP ticks when we
365 * are called too frequently. */
366 ms
= clamp(ms
, 0, INT_MAX
- 1000) + stp
->elapsed_remainder
;
367 elapsed
= ms_to_timer(ms
);
368 stp
->elapsed_remainder
= ms
- timer_to_ms(elapsed
);
373 if (stp_timer_expired(&stp
->hello_timer
, elapsed
, stp
->hello_time
)) {
374 stp_hello_timer_expiry(stp
);
376 if (stp_timer_expired(&stp
->tcn_timer
, elapsed
, stp
->bridge_hello_time
)) {
377 stp_tcn_timer_expiry(stp
);
379 if (stp_timer_expired(&stp
->topology_change_timer
, elapsed
,
380 stp
->max_age
+ stp
->forward_delay
)) {
381 stp_topology_change_timer_expiry(stp
);
383 FOR_EACH_ENABLED_PORT (p
, stp
) {
384 if (stp_timer_expired(&p
->message_age_timer
, elapsed
, stp
->max_age
)) {
385 stp_message_age_timer_expiry(p
);
388 FOR_EACH_ENABLED_PORT (p
, stp
) {
389 if (stp_timer_expired(&p
->forward_delay_timer
, elapsed
,
390 stp
->forward_delay
)) {
391 stp_forward_delay_timer_expiry(p
);
393 if (stp_timer_expired(&p
->hold_timer
, elapsed
, ms_to_timer(1000))) {
394 stp_hold_timer_expiry(p
);
399 ovs_mutex_unlock(&mutex
);
403 set_bridge_id(struct stp
*stp
, stp_identifier new_bridge_id
)
406 if (new_bridge_id
!= stp
->bridge_id
) {
410 root
= stp_is_root_bridge(stp
);
411 FOR_EACH_ENABLED_PORT (p
, stp
) {
412 if (stp_is_designated_port(p
)) {
413 p
->designated_bridge
= new_bridge_id
;
416 stp
->bridge_id
= new_bridge_id
;
417 stp_configuration_update(stp
);
418 stp_port_state_selection(stp
);
419 if (stp_is_root_bridge(stp
) && !root
) {
420 stp_become_root_bridge(stp
);
426 stp_set_bridge_id(struct stp
*stp
, stp_identifier bridge_id
)
428 const uint64_t mac_bits
= (UINT64_C(1) << 48) - 1;
429 const uint64_t pri_bits
= ~mac_bits
;
430 ovs_mutex_lock(&mutex
);
431 set_bridge_id(stp
, (stp
->bridge_id
& pri_bits
) | (bridge_id
& mac_bits
));
432 ovs_mutex_unlock(&mutex
);
436 stp_set_bridge_priority(struct stp
*stp
, uint16_t new_priority
)
438 const uint64_t mac_bits
= (UINT64_C(1) << 48) - 1;
439 ovs_mutex_lock(&mutex
);
440 set_bridge_id(stp
, ((stp
->bridge_id
& mac_bits
)
441 | ((uint64_t) new_priority
<< 48)));
442 ovs_mutex_unlock(&mutex
);
445 /* Sets the desired hello time for 'stp' to 'ms', in milliseconds. The actual
446 * hello time is clamped to the range of 1 to 10 seconds and subject to the
447 * relationship (bridge_max_age >= 2 * (bridge_hello_time + 1 s)). The bridge
448 * hello time is only used when 'stp' is the root bridge. */
450 stp_set_hello_time(struct stp
*stp
, int ms
)
452 ovs_mutex_lock(&mutex
);
453 stp
->rq_hello_time
= ms
;
454 stp_update_bridge_timers(stp
);
455 ovs_mutex_unlock(&mutex
);
458 /* Sets the desired max age for 'stp' to 'ms', in milliseconds. The actual max
459 * age is clamped to the range of 6 to 40 seconds and subject to the
460 * relationships (2 * (bridge_forward_delay - 1 s) >= bridge_max_age) and
461 * (bridge_max_age >= 2 * (bridge_hello_time + 1 s)). The bridge max age is
462 * only used when 'stp' is the root bridge. */
464 stp_set_max_age(struct stp
*stp
, int ms
)
466 ovs_mutex_lock(&mutex
);
467 stp
->rq_max_age
= ms
;
468 stp_update_bridge_timers(stp
);
469 ovs_mutex_unlock(&mutex
);
472 /* Sets the desired forward delay for 'stp' to 'ms', in milliseconds. The
473 * actual forward delay is clamped to the range of 4 to 30 seconds and subject
474 * to the relationship (2 * (bridge_forward_delay - 1 s) >= bridge_max_age).
475 * The bridge forward delay is only used when 'stp' is the root bridge. */
477 stp_set_forward_delay(struct stp
*stp
, int ms
)
479 ovs_mutex_lock(&mutex
);
480 stp
->rq_forward_delay
= ms
;
481 stp_update_bridge_timers(stp
);
482 ovs_mutex_unlock(&mutex
);
485 /* Returns the name given to 'stp' in the call to stp_create(). */
487 stp_get_name(const struct stp
*stp
)
491 ovs_mutex_lock(&mutex
);
493 ovs_mutex_unlock(&mutex
);
497 /* Returns the bridge ID for 'stp'. */
499 stp_get_bridge_id(const struct stp
*stp
)
501 stp_identifier bridge_id
;
503 ovs_mutex_lock(&mutex
);
504 bridge_id
= stp
->bridge_id
;
505 ovs_mutex_unlock(&mutex
);
509 /* Returns the bridge ID of the bridge currently believed to be the root. */
511 stp_get_designated_root(const struct stp
*stp
)
513 stp_identifier designated_root
;
515 ovs_mutex_lock(&mutex
);
516 designated_root
= stp
->designated_root
;
517 ovs_mutex_unlock(&mutex
);
518 return designated_root
;
521 /* Returns true if 'stp' believes itself to the be root of the spanning tree,
522 * false otherwise. */
524 stp_is_root_bridge(const struct stp
*stp
)
528 ovs_mutex_lock(&mutex
);
529 is_root
= stp
->bridge_id
== stp
->designated_root
;
530 ovs_mutex_unlock(&mutex
);
534 /* Returns the cost of the path from 'stp' to the root of the spanning tree. */
536 stp_get_root_path_cost(const struct stp
*stp
)
540 ovs_mutex_lock(&mutex
);
541 cost
= stp
->root_path_cost
;
542 ovs_mutex_unlock(&mutex
);
546 /* Returns the bridge hello time, in ms. The returned value is not necessarily
547 * the value passed to stp_set_hello_time(): it is clamped to the valid range
548 * and quantized to the STP timer resolution. */
550 stp_get_hello_time(const struct stp
*stp
)
554 ovs_mutex_lock(&mutex
);
555 time
= timer_to_ms(stp
->bridge_hello_time
);
556 ovs_mutex_unlock(&mutex
);
560 /* Returns the bridge max age, in ms. The returned value is not necessarily
561 * the value passed to stp_set_max_age(): it is clamped to the valid range,
562 * quantized to the STP timer resolution, and adjusted to match the constraints
563 * due to the hello time. */
565 stp_get_max_age(const struct stp
*stp
)
569 ovs_mutex_lock(&mutex
);
570 time
= timer_to_ms(stp
->bridge_max_age
);
571 ovs_mutex_unlock(&mutex
);
575 /* Returns the bridge forward delay, in ms. The returned value is not
576 * necessarily the value passed to stp_set_forward_delay(): it is clamped to
577 * the valid range, quantized to the STP timer resolution, and adjusted to
578 * match the constraints due to the forward delay. */
580 stp_get_forward_delay(const struct stp
*stp
)
584 ovs_mutex_lock(&mutex
);
585 time
= timer_to_ms(stp
->bridge_forward_delay
);
586 ovs_mutex_unlock(&mutex
);
590 /* Returns true if something has happened to 'stp' which necessitates flushing
591 * the client's MAC learning table. Calling this function resets 'stp' so that
592 * future calls will return false until flushing is required again. */
594 stp_check_and_reset_fdb_flush(struct stp
*stp
)
598 ovs_mutex_lock(&mutex
);
599 needs_flush
= stp
->fdb_needs_flush
;
600 stp
->fdb_needs_flush
= false;
601 ovs_mutex_unlock(&mutex
);
605 /* Returns the port in 'stp' with index 'port_no', which must be between 0 and
608 stp_get_port(struct stp
*stp
, int port_no
)
610 struct stp_port
*port
;
612 ovs_mutex_lock(&mutex
);
613 ovs_assert(port_no
>= 0 && port_no
< ARRAY_SIZE(stp
->ports
));
614 port
= &stp
->ports
[port_no
];
615 ovs_mutex_unlock(&mutex
);
619 /* Returns the port connecting 'stp' to the root bridge, or a null pointer if
620 * there is no such port. */
622 stp_get_root_port(struct stp
*stp
)
624 struct stp_port
*port
;
626 ovs_mutex_lock(&mutex
);
627 port
= stp
->root_port
;
628 ovs_mutex_unlock(&mutex
);
632 /* Finds a port whose state has changed. If successful, stores the port whose
633 * state changed in '*portp' and returns true. If no port has changed, stores
634 * NULL in '*portp' and returns false. */
636 stp_get_changed_port(struct stp
*stp
, struct stp_port
**portp
)
638 struct stp_port
*end
, *p
;
639 bool changed
= false;
641 ovs_mutex_lock(&mutex
);
642 end
= &stp
->ports
[ARRAY_SIZE(stp
->ports
)];
643 for (p
= stp
->first_changed_port
; p
< end
; p
++) {
644 if (p
->state_changed
) {
645 p
->state_changed
= false;
646 stp
->first_changed_port
= p
+ 1;
652 stp
->first_changed_port
= end
;
656 ovs_mutex_unlock(&mutex
);
660 /* Returns the name for the given 'state' (for use in debugging and log
663 stp_state_name(enum stp_state state
)
681 /* Returns true if 'state' is one in which packets received on a port should
682 * be forwarded, false otherwise.
685 stp_forward_in_state(enum stp_state state
)
687 return (state
& STP_FORWARDING
) != 0;
690 /* Returns true if 'state' is one in which MAC learning should be done on
691 * packets received on a port, false otherwise.
694 stp_learn_in_state(enum stp_state state
)
696 return (state
& (STP_LEARNING
| STP_FORWARDING
)) != 0;
699 /* Returns true if 'state' is one in which bpdus should be forwarded on a
700 * port, false otherwise.
702 * Returns true if 'state' is STP_DISABLED, since in that case the port does
703 * not generate the bpdu and should just forward it (e.g. patch port on pif
706 stp_should_forward_bpdu(enum stp_state state
)
709 ( STP_DISABLED
| STP_LISTENING
| STP_LEARNING
710 | STP_FORWARDING
)) != 0;
713 /* Returns the name for the given 'role' (for use in debugging and log
716 stp_role_name(enum stp_role role
)
721 case STP_ROLE_DESIGNATED
:
723 case STP_ROLE_ALTERNATE
:
725 case STP_ROLE_DISABLED
:
732 /* Notifies the STP entity that bridge protocol data unit 'bpdu', which is
733 * 'bpdu_size' bytes in length, was received on port 'p'.
735 * This function may call the 'send_bpdu' function provided to stp_create(). */
737 stp_received_bpdu(struct stp_port
*p
, const void *bpdu
, size_t bpdu_size
)
739 struct stp
*stp
= p
->stp
;
740 const struct stp_bpdu_header
*header
;
742 ovs_mutex_lock(&mutex
);
743 if (p
->state
== STP_DISABLED
) {
747 if (bpdu_size
< sizeof(struct stp_bpdu_header
)) {
748 VLOG_WARN("%s: received runt %"PRIuSIZE
"-byte BPDU", stp
->name
, bpdu_size
);
754 if (header
->protocol_id
!= htons(STP_PROTOCOL_ID
)) {
755 VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16
,
756 stp
->name
, ntohs(header
->protocol_id
));
760 if (header
->protocol_version
!= STP_PROTOCOL_VERSION
) {
761 VLOG_DBG("%s: received BPDU with unexpected protocol version %"PRIu8
,
762 stp
->name
, header
->protocol_version
);
765 switch (header
->bpdu_type
) {
766 case STP_TYPE_CONFIG
:
767 if (bpdu_size
< sizeof(struct stp_config_bpdu
)) {
768 VLOG_WARN("%s: received config BPDU with invalid size %"PRIuSIZE
,
769 stp
->name
, bpdu_size
);
773 stp_received_config_bpdu(stp
, p
, bpdu
);
777 if (bpdu_size
!= sizeof(struct stp_tcn_bpdu
)) {
778 VLOG_WARN("%s: received TCN BPDU with invalid size %"PRIuSIZE
,
779 stp
->name
, bpdu_size
);
783 stp_received_tcn_bpdu(stp
, p
);
787 VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8
,
788 stp
->name
, header
->bpdu_type
);
795 ovs_mutex_unlock(&mutex
);
798 /* Returns the STP entity in which 'p' is nested. */
800 stp_port_get_stp(struct stp_port
*p
)
804 ovs_mutex_lock(&mutex
);
806 ovs_mutex_unlock(&mutex
);
811 stp_port_set_name(struct stp_port
*p
, const char *name
)
815 ovs_mutex_lock(&mutex
);
817 p
->port_name
= xstrdup(name
);
819 ovs_mutex_unlock(&mutex
);
822 /* Sets the 'aux' member of 'p'.
824 * The 'aux' member will be reset to NULL when stp_port_disable() is
825 * called or stp_port_enable() is called when the port is in a Disabled
828 stp_port_set_aux(struct stp_port
*p
, void *aux
)
830 ovs_mutex_lock(&mutex
);
832 ovs_mutex_unlock(&mutex
);
835 /* Returns the 'aux' member of 'p'. */
837 stp_port_get_aux(struct stp_port
*p
)
841 ovs_mutex_lock(&mutex
);
843 ovs_mutex_unlock(&mutex
);
847 /* Returns the index of port 'p' within its bridge. */
849 stp_port_no(const struct stp_port
*p
)
854 ovs_mutex_lock(&mutex
);
856 ovs_assert(p
>= stp
->ports
&& p
< &stp
->ports
[ARRAY_SIZE(stp
->ports
)]);
857 index
= p
- p
->stp
->ports
;
858 ovs_mutex_unlock(&mutex
);
862 /* Returns the state of port 'p'. */
864 stp_port_get_state(const struct stp_port
*p
)
866 enum stp_state state
;
868 ovs_mutex_lock(&mutex
);
870 ovs_mutex_unlock(&mutex
);
874 /* Returns the role of port 'p'. */
876 stp_port_get_role(const struct stp_port
*p
) OVS_REQUIRES(mutex
)
878 struct stp_port
*root_port
;
881 root_port
= p
->stp
->root_port
;
882 if (root_port
&& root_port
->port_id
== p
->port_id
) {
883 role
= STP_ROLE_ROOT
;
884 } else if (stp_is_designated_port(p
)) {
885 role
= STP_ROLE_DESIGNATED
;
886 } else if (p
->state
== STP_DISABLED
) {
887 role
= STP_ROLE_DISABLED
;
889 role
= STP_ROLE_ALTERNATE
;
894 /* Retrieves BPDU transmit and receive counts for 'p'. */
896 stp_port_get_counts(const struct stp_port
*p
,
897 int *tx_count
, int *rx_count
, int *error_count
)
899 ovs_mutex_lock(&mutex
);
900 *tx_count
= p
->tx_count
;
901 *rx_count
= p
->rx_count
;
902 *error_count
= p
->error_count
;
903 ovs_mutex_unlock(&mutex
);
907 stp_port_get_status(const struct stp_port
*p
,
908 int *port_id
, enum stp_state
*state
, enum stp_role
*role
)
910 ovs_mutex_lock(&mutex
);
911 *port_id
= p
->port_id
;
913 *role
= stp_port_get_role(p
);
914 ovs_mutex_unlock(&mutex
);
917 /* Disables STP on port 'p'. */
919 stp_port_disable(struct stp_port
*p
)
923 ovs_mutex_lock(&mutex
);
925 if (p
->state
!= STP_DISABLED
) {
926 bool root
= stp_is_root_bridge(stp
);
927 stp_become_designated_port(p
);
928 stp_set_port_state(p
, STP_DISABLED
);
929 p
->topology_change_ack
= false;
930 p
->config_pending
= false;
931 stp_stop_timer(&p
->message_age_timer
);
932 stp_stop_timer(&p
->forward_delay_timer
);
933 stp_configuration_update(stp
);
934 stp_port_state_selection(stp
);
935 if (stp_is_root_bridge(stp
) && !root
) {
936 stp_become_root_bridge(stp
);
940 ovs_mutex_unlock(&mutex
);
943 /* Enables STP on port 'p'. The port will initially be in "blocking" state. */
945 stp_port_enable(struct stp_port
*p
)
947 ovs_mutex_lock(&mutex
);
948 if (p
->state
== STP_DISABLED
) {
949 stp_initialize_port(p
, STP_BLOCKING
);
950 stp_port_state_selection(p
->stp
);
952 ovs_mutex_unlock(&mutex
);
955 /* Sets the priority of port 'p' to 'new_priority'. Lower numerical values
956 * are interpreted as higher priorities. */
958 stp_port_set_priority(struct stp_port
*p
, uint8_t new_priority
)
960 uint16_t new_port_id
;
962 ovs_mutex_lock(&mutex
);
963 new_port_id
= (p
->port_id
& 0xff) | (new_priority
<< 8);
964 if (p
->port_id
!= new_port_id
) {
965 struct stp
*stp
= p
->stp
;
966 if (stp_is_designated_port(p
)) {
967 p
->designated_port
= new_port_id
;
969 p
->port_id
= new_port_id
;
970 if (stp
->bridge_id
== p
->designated_bridge
971 && p
->port_id
< p
->designated_port
) {
972 stp_become_designated_port(p
);
973 stp_port_state_selection(stp
);
976 ovs_mutex_unlock(&mutex
);
979 /* Convert 'speed' (measured in Mb/s) into the path cost. */
981 stp_convert_speed_to_cost(unsigned int speed
)
985 ovs_mutex_lock(&mutex
);
986 ret
= speed
>= 10000 ? 2 /* 10 Gb/s. */
987 : speed
>= 1000 ? 4 /* 1 Gb/s. */
988 : speed
>= 100 ? 19 /* 100 Mb/s. */
989 : speed
>= 16 ? 62 /* 16 Mb/s. */
990 : speed
>= 10 ? 100 /* 10 Mb/s. */
991 : speed
>= 4 ? 250 /* 4 Mb/s. */
992 : 19; /* 100 Mb/s (guess). */
993 ovs_mutex_unlock(&mutex
);
997 /* Sets the path cost of port 'p' to 'path_cost'. Lower values are generally
998 * used to indicate faster links. Use stp_port_set_speed() to automatically
999 * generate a default path cost from a link speed. */
1001 stp_port_set_path_cost(struct stp_port
*p
, uint16_t path_cost
)
1003 ovs_mutex_lock(&mutex
);
1004 if (p
->path_cost
!= path_cost
) {
1005 struct stp
*stp
= p
->stp
;
1006 p
->path_cost
= path_cost
;
1007 stp_configuration_update(stp
);
1008 stp_port_state_selection(stp
);
1010 ovs_mutex_unlock(&mutex
);
1013 /* Sets the path cost of port 'p' based on 'speed' (measured in Mb/s). */
1015 stp_port_set_speed(struct stp_port
*p
, unsigned int speed
)
1017 stp_port_set_path_cost(p
, stp_convert_speed_to_cost(speed
));
1020 /* Enables topology change detection on port 'p'. */
1022 stp_port_enable_change_detection(struct stp_port
*p
)
1024 p
->change_detection_enabled
= true;
1027 /* Disables topology change detection on port 'p'. */
1029 stp_port_disable_change_detection(struct stp_port
*p
)
1031 p
->change_detection_enabled
= false;
1035 stp_transmit_config(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1037 struct stp
*stp
= p
->stp
;
1038 bool root
= stp_is_root_bridge(stp
);
1039 if (!root
&& !stp
->root_port
) {
1042 if (p
->hold_timer
.active
) {
1043 VLOG_DBG_RL(&stp_rl
, "bridge: %s, port: %s, transmit config bpdu pending",
1044 stp
->name
, p
->port_name
);
1045 p
->config_pending
= true;
1047 struct stp_config_bpdu config
;
1048 memset(&config
, 0, sizeof config
);
1049 config
.header
.protocol_id
= htons(STP_PROTOCOL_ID
);
1050 config
.header
.protocol_version
= STP_PROTOCOL_VERSION
;
1051 config
.header
.bpdu_type
= STP_TYPE_CONFIG
;
1053 if (p
->topology_change_ack
) {
1054 config
.flags
|= STP_CONFIG_TOPOLOGY_CHANGE_ACK
;
1056 if (stp
->topology_change
) {
1057 config
.flags
|= STP_CONFIG_TOPOLOGY_CHANGE
;
1059 config
.root_id
= htonll(stp
->designated_root
);
1060 config
.root_path_cost
= htonl(stp
->root_path_cost
);
1061 config
.bridge_id
= htonll(stp
->bridge_id
);
1062 config
.port_id
= htons(p
->port_id
);
1064 config
.message_age
= htons(0);
1066 config
.message_age
= htons(stp
->root_port
->message_age_timer
.value
1067 + MESSAGE_AGE_INCREMENT
);
1069 config
.max_age
= htons(stp
->max_age
);
1070 config
.hello_time
= htons(stp
->hello_time
);
1071 config
.forward_delay
= htons(stp
->forward_delay
);
1072 if (ntohs(config
.message_age
) < stp
->max_age
) {
1073 p
->topology_change_ack
= false;
1074 p
->config_pending
= false;
1075 VLOG_DBG_RL(&stp_rl
, "bridge: %s, port: %s, transmit config bpdu",
1076 stp
->name
, p
->port_name
);
1077 stp_send_bpdu(p
, &config
, sizeof config
);
1078 stp_start_timer(&p
->hold_timer
, 0);
1084 stp_supersedes_port_info(const struct stp_port
*p
,
1085 const struct stp_config_bpdu
*config
)
1088 if (ntohll(config
->root_id
) != p
->designated_root
) {
1089 return ntohll(config
->root_id
) < p
->designated_root
;
1090 } else if (ntohl(config
->root_path_cost
) != p
->designated_cost
) {
1091 return ntohl(config
->root_path_cost
) < p
->designated_cost
;
1092 } else if (ntohll(config
->bridge_id
) != p
->designated_bridge
) {
1093 return ntohll(config
->bridge_id
) < p
->designated_bridge
;
1095 return (ntohll(config
->bridge_id
) != p
->stp
->bridge_id
1096 || ntohs(config
->port_id
) <= p
->designated_port
);
1101 stp_record_config_information(struct stp_port
*p
,
1102 const struct stp_config_bpdu
*config
)
1105 p
->designated_root
= ntohll(config
->root_id
);
1106 p
->designated_cost
= ntohl(config
->root_path_cost
);
1107 p
->designated_bridge
= ntohll(config
->bridge_id
);
1108 p
->designated_port
= ntohs(config
->port_id
);
1109 stp_start_timer(&p
->message_age_timer
, ntohs(config
->message_age
));
1113 stp_record_config_timeout_values(struct stp
*stp
,
1114 const struct stp_config_bpdu
*config
)
1117 stp
->max_age
= ntohs(config
->max_age
);
1118 stp
->hello_time
= ntohs(config
->hello_time
);
1119 stp
->forward_delay
= ntohs(config
->forward_delay
);
1120 stp
->topology_change
= config
->flags
& STP_CONFIG_TOPOLOGY_CHANGE
;
1124 stp_is_designated_port(const struct stp_port
*p
) OVS_REQUIRES(mutex
)
1126 return (p
->designated_bridge
== p
->stp
->bridge_id
1127 && p
->designated_port
== p
->port_id
);
1131 stp_config_bpdu_generation(struct stp
*stp
) OVS_REQUIRES(mutex
)
1135 FOR_EACH_ENABLED_PORT (p
, stp
) {
1136 if (stp_is_designated_port(p
)) {
1137 stp_transmit_config(p
);
1143 stp_transmit_tcn(struct stp
*stp
) OVS_REQUIRES(mutex
)
1145 struct stp_port
*p
= stp
->root_port
;
1146 struct stp_tcn_bpdu tcn_bpdu
;
1151 VLOG_DBG_RL(&stp_rl
, "bridge: %s, root port: %s, transmit tcn", stp
->name
,
1153 tcn_bpdu
.header
.protocol_id
= htons(STP_PROTOCOL_ID
);
1154 tcn_bpdu
.header
.protocol_version
= STP_PROTOCOL_VERSION
;
1155 tcn_bpdu
.header
.bpdu_type
= STP_TYPE_TCN
;
1156 stp_send_bpdu(p
, &tcn_bpdu
, sizeof tcn_bpdu
);
1160 stp_configuration_update(struct stp
*stp
) OVS_REQUIRES(mutex
)
1162 stp_root_selection(stp
);
1163 stp_designated_port_selection(stp
);
1164 seq_change(connectivity_seq_get());
1168 stp_supersedes_root(const struct stp_port
*root
, const struct stp_port
*p
)
1171 int p_cost
= p
->designated_cost
+ p
->path_cost
;
1172 int root_cost
= root
->designated_cost
+ root
->path_cost
;
1174 if (p
->designated_root
!= root
->designated_root
) {
1175 return p
->designated_root
< root
->designated_root
;
1176 } else if (p_cost
!= root_cost
) {
1177 return p_cost
< root_cost
;
1178 } else if (p
->designated_bridge
!= root
->designated_bridge
) {
1179 return p
->designated_bridge
< root
->designated_bridge
;
1180 } else if (p
->designated_port
!= root
->designated_port
) {
1181 return p
->designated_port
< root
->designated_port
;
1183 return p
->port_id
< root
->port_id
;
1188 stp_root_selection(struct stp
*stp
) OVS_REQUIRES(mutex
)
1190 struct stp_port
*p
, *root
;
1193 FOR_EACH_ENABLED_PORT (p
, stp
) {
1194 if (stp_is_designated_port(p
)
1195 || p
->designated_root
>= stp
->bridge_id
) {
1198 if (root
&& !stp_supersedes_root(root
, p
)) {
1203 stp
->root_port
= root
;
1205 stp
->designated_root
= stp
->bridge_id
;
1206 stp
->root_path_cost
= 0;
1208 stp
->designated_root
= root
->designated_root
;
1209 stp
->root_path_cost
= root
->designated_cost
+ root
->path_cost
;
1214 stp_designated_port_selection(struct stp
*stp
) OVS_REQUIRES(mutex
)
1218 FOR_EACH_ENABLED_PORT (p
, stp
) {
1219 if (stp_is_designated_port(p
)
1220 || p
->designated_root
!= stp
->designated_root
1221 || stp
->root_path_cost
< p
->designated_cost
1222 || (stp
->root_path_cost
== p
->designated_cost
1223 && (stp
->bridge_id
< p
->designated_bridge
1224 || (stp
->bridge_id
== p
->designated_bridge
1225 && p
->port_id
<= p
->designated_port
))))
1227 stp_become_designated_port(p
);
1233 stp_become_designated_port(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1235 struct stp
*stp
= p
->stp
;
1236 p
->designated_root
= stp
->designated_root
;
1237 p
->designated_cost
= stp
->root_path_cost
;
1238 p
->designated_bridge
= stp
->bridge_id
;
1239 p
->designated_port
= p
->port_id
;
1243 stp_port_state_selection(struct stp
*stp
) OVS_REQUIRES(mutex
)
1247 FOR_EACH_ENABLED_PORT (p
, stp
) {
1248 if (p
== stp
->root_port
) {
1249 p
->config_pending
= false;
1250 p
->topology_change_ack
= false;
1251 stp_make_forwarding(p
);
1252 } else if (stp_is_designated_port(p
)) {
1253 stp_stop_timer(&p
->message_age_timer
);
1254 stp_make_forwarding(p
);
1256 p
->config_pending
= false;
1257 p
->topology_change_ack
= false;
1258 stp_make_blocking(p
);
1264 stp_make_forwarding(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1266 if (p
->state
== STP_BLOCKING
) {
1267 stp_set_port_state(p
, STP_LISTENING
);
1268 stp_start_timer(&p
->forward_delay_timer
, 0);
1273 stp_make_blocking(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1275 if (!(p
->state
& (STP_DISABLED
| STP_BLOCKING
))) {
1276 if (p
->state
& (STP_FORWARDING
| STP_LEARNING
)) {
1277 if (p
->change_detection_enabled
) {
1278 stp_topology_change_detection(p
->stp
);
1281 stp_set_port_state(p
, STP_BLOCKING
);
1282 stp_stop_timer(&p
->forward_delay_timer
);
1287 stp_set_port_state(struct stp_port
*p
, enum stp_state state
)
1290 if (state
!= p
->state
&& !p
->state_changed
) {
1291 p
->state_changed
= true;
1292 if (p
< p
->stp
->first_changed_port
) {
1293 p
->stp
->first_changed_port
= p
;
1295 seq_change(connectivity_seq_get());
1301 stp_topology_change_detection(struct stp
*stp
) OVS_REQUIRES(mutex
)
1303 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
1305 if (stp_is_root_bridge(stp
)) {
1306 stp
->topology_change
= true;
1307 stp_start_timer(&stp
->topology_change_timer
, 0);
1308 } else if (!stp
->topology_change_detected
) {
1309 stp_transmit_tcn(stp
);
1310 stp_start_timer(&stp
->tcn_timer
, 0);
1312 stp
->fdb_needs_flush
= true;
1313 stp
->topology_change_detected
= true;
1314 seq_change(connectivity_seq_get());
1315 VLOG_INFO_RL(&rl
, "%s: detected topology change.", stp
->name
);
1319 stp_topology_change_acknowledged(struct stp
*stp
) OVS_REQUIRES(mutex
)
1321 stp
->topology_change_detected
= false;
1322 stp_stop_timer(&stp
->tcn_timer
);
1326 stp_acknowledge_topology_change(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1328 p
->topology_change_ack
= true;
1329 stp_transmit_config(p
);
1333 stp_received_config_bpdu(struct stp
*stp
, struct stp_port
*p
,
1334 const struct stp_config_bpdu
*config
)
1337 if (ntohs(config
->message_age
) >= ntohs(config
->max_age
)) {
1338 VLOG_WARN("%s: received config BPDU with message age (%u) greater "
1339 "than max age (%u)",
1341 ntohs(config
->message_age
), ntohs(config
->max_age
));
1344 if (p
->state
!= STP_DISABLED
) {
1345 bool root
= stp_is_root_bridge(stp
);
1346 if (stp_supersedes_port_info(p
, config
)) {
1347 stp_record_config_information(p
, config
);
1348 stp_configuration_update(stp
);
1349 stp_port_state_selection(stp
);
1350 if (!stp_is_root_bridge(stp
) && root
) {
1351 stp_stop_timer(&stp
->hello_timer
);
1352 if (stp
->topology_change_detected
) {
1353 stp_stop_timer(&stp
->topology_change_timer
);
1354 stp_transmit_tcn(stp
);
1355 stp_start_timer(&stp
->tcn_timer
, 0);
1358 if (p
== stp
->root_port
) {
1359 stp_record_config_timeout_values(stp
, config
);
1360 stp_config_bpdu_generation(stp
);
1361 if (config
->flags
& STP_CONFIG_TOPOLOGY_CHANGE_ACK
) {
1362 stp_topology_change_acknowledged(stp
);
1364 if (config
->flags
& STP_CONFIG_TOPOLOGY_CHANGE
) {
1365 stp
->fdb_needs_flush
= true;
1368 } else if (stp_is_designated_port(p
)) {
1369 stp_transmit_config(p
);
1375 stp_received_tcn_bpdu(struct stp
*stp
, struct stp_port
*p
)
1378 if (p
->state
!= STP_DISABLED
) {
1379 if (stp_is_designated_port(p
)) {
1380 stp_topology_change_detection(stp
);
1381 stp_acknowledge_topology_change(p
);
1387 stp_hello_timer_expiry(struct stp
*stp
) OVS_REQUIRES(mutex
)
1389 stp_config_bpdu_generation(stp
);
1390 stp_start_timer(&stp
->hello_timer
, 0);
1394 stp_message_age_timer_expiry(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1396 struct stp
*stp
= p
->stp
;
1397 bool root
= stp_is_root_bridge(stp
);
1399 VLOG_DBG_RL(&stp_rl
, "bridge: %s, port: %s, message age timer expired",
1400 stp
->name
, p
->port_name
);
1401 stp_become_designated_port(p
);
1402 stp_configuration_update(stp
);
1403 stp_port_state_selection(stp
);
1404 if (stp_is_root_bridge(stp
) && !root
) {
1405 stp
->max_age
= stp
->bridge_max_age
;
1406 stp
->hello_time
= stp
->bridge_hello_time
;
1407 stp
->forward_delay
= stp
->bridge_forward_delay
;
1408 stp_topology_change_detection(stp
);
1409 stp_stop_timer(&stp
->tcn_timer
);
1410 stp_config_bpdu_generation(stp
);
1411 stp_start_timer(&stp
->hello_timer
, 0);
1416 stp_is_designated_for_some_port(const struct stp
*stp
) OVS_REQUIRES(mutex
)
1418 const struct stp_port
*p
;
1420 FOR_EACH_ENABLED_PORT (p
, stp
) {
1421 if (p
->designated_bridge
== stp
->bridge_id
) {
1429 stp_forward_delay_timer_expiry(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1431 if (p
->state
== STP_LISTENING
) {
1432 stp_set_port_state(p
, STP_LEARNING
);
1433 stp_start_timer(&p
->forward_delay_timer
, 0);
1434 } else if (p
->state
== STP_LEARNING
) {
1435 stp_set_port_state(p
, STP_FORWARDING
);
1436 if (stp_is_designated_for_some_port(p
->stp
)) {
1437 if (p
->change_detection_enabled
) {
1438 stp_topology_change_detection(p
->stp
);
1445 stp_tcn_timer_expiry(struct stp
*stp
) OVS_REQUIRES(mutex
)
1447 stp_transmit_tcn(stp
);
1448 stp_start_timer(&stp
->tcn_timer
, 0);
1452 stp_topology_change_timer_expiry(struct stp
*stp
) OVS_REQUIRES(mutex
)
1454 stp
->topology_change_detected
= false;
1455 stp
->topology_change
= false;
1459 stp_hold_timer_expiry(struct stp_port
*p
) OVS_REQUIRES(mutex
)
1461 if (p
->config_pending
) {
1462 stp_transmit_config(p
);
1467 stp_initialize_port(struct stp_port
*p
, enum stp_state state
)
1470 ovs_assert(state
& (STP_DISABLED
| STP_BLOCKING
));
1471 stp_become_designated_port(p
);
1473 if (!p
->state
&& state
== STP_DISABLED
) {
1474 p
->state
= state
; /* Do not trigger state change when initializing. */
1476 stp_set_port_state(p
, state
);
1478 p
->topology_change_ack
= false;
1479 p
->config_pending
= false;
1480 p
->change_detection_enabled
= true;
1482 stp_stop_timer(&p
->message_age_timer
);
1483 stp_stop_timer(&p
->forward_delay_timer
);
1484 stp_stop_timer(&p
->hold_timer
);
1485 p
->tx_count
= p
->rx_count
= p
->error_count
= 0;
1489 stp_become_root_bridge(struct stp
*stp
) OVS_REQUIRES(mutex
)
1491 stp
->max_age
= stp
->bridge_max_age
;
1492 stp
->hello_time
= stp
->bridge_hello_time
;
1493 stp
->forward_delay
= stp
->bridge_forward_delay
;
1494 stp_topology_change_detection(stp
);
1495 stp_stop_timer(&stp
->tcn_timer
);
1496 stp_config_bpdu_generation(stp
);
1497 stp_start_timer(&stp
->hello_timer
, 0);
1501 stp_start_timer(struct stp_timer
*timer
, int value
) OVS_REQUIRES(mutex
)
1503 timer
->value
= value
;
1504 timer
->active
= true;
1508 stp_stop_timer(struct stp_timer
*timer
) OVS_REQUIRES(mutex
)
1510 timer
->active
= false;
1514 stp_timer_expired(struct stp_timer
*timer
, int elapsed
, int timeout
)
1517 if (timer
->active
) {
1518 timer
->value
+= elapsed
;
1519 if (timer
->value
>= timeout
) {
1520 timer
->active
= false;
1527 /* Returns the number of whole STP timer ticks in 'ms' milliseconds. There
1528 * are 256 STP timer ticks per second. */
1532 return ms
* 0x100 / 1000;
1535 /* Returns the number of whole milliseconds in 'timer' STP timer ticks. There
1536 * are 256 STP timer ticks per second. */
1538 timer_to_ms(int timer
)
1540 return timer
* 1000 / 0x100;
1544 clamp(int x
, int min
, int max
)
1546 return x
< min
? min
: x
> max
? max
: x
;
1550 stp_update_bridge_timers(struct stp
*stp
) OVS_REQUIRES(mutex
)
1554 ht
= clamp(stp
->rq_hello_time
, 1000, 10000);
1555 ma
= clamp(stp
->rq_max_age
, MAX(2 * (ht
+ 1000), 6000), 40000);
1556 fd
= clamp(stp
->rq_forward_delay
, ma
/ 2 + 1000, 30000);
1558 stp
->bridge_hello_time
= ms_to_timer(ht
);
1559 stp
->bridge_max_age
= ms_to_timer(ma
);
1560 stp
->bridge_forward_delay
= ms_to_timer(fd
);
1562 if (stp_is_root_bridge(stp
)) {
1563 stp
->max_age
= stp
->bridge_max_age
;
1564 stp
->hello_time
= stp
->bridge_hello_time
;
1565 stp
->forward_delay
= stp
->bridge_forward_delay
;
1570 stp_send_bpdu(struct stp_port
*p
, const void *bpdu
, size_t bpdu_size
)
1573 struct eth_header
*eth
;
1574 struct llc_header
*llc
;
1575 struct dp_packet
*pkt
;
1578 pkt
= dp_packet_new(ETH_HEADER_LEN
+ LLC_HEADER_LEN
+ bpdu_size
);
1579 eth
= dp_packet_put_zeros(pkt
, sizeof *eth
);
1580 llc
= dp_packet_put_zeros(pkt
, sizeof *llc
);
1581 dp_packet_reset_offsets(pkt
);
1582 dp_packet_set_l3(pkt
, dp_packet_put(pkt
, bpdu
, bpdu_size
));
1585 eth
->eth_dst
= eth_addr_stp
;
1586 /* p->stp->send_bpdu() must fill in source address. */
1587 eth
->eth_type
= htons(dp_packet_size(pkt
) - ETH_HEADER_LEN
);
1590 llc
->llc_dsap
= STP_LLC_DSAP
;
1591 llc
->llc_ssap
= STP_LLC_SSAP
;
1592 llc
->llc_cntl
= STP_LLC_CNTL
;
1594 p
->stp
->send_bpdu(pkt
, stp_port_no(p
), p
->stp
->aux
);
1601 stp_find(const char *name
) OVS_REQUIRES(mutex
)
1605 LIST_FOR_EACH (stp
, node
, all_stps
) {
1606 if (!strcmp(stp
->name
, name
)) {
1614 stp_unixctl_tcn(struct unixctl_conn
*conn
, int argc
,
1615 const char *argv
[], void *aux OVS_UNUSED
)
1617 ovs_mutex_lock(&mutex
);
1619 struct stp
*stp
= stp_find(argv
[1]);
1622 unixctl_command_reply_error(conn
, "no such stp object");
1625 stp_topology_change_detection(stp
);
1629 LIST_FOR_EACH (stp
, node
, all_stps
) {
1630 stp_topology_change_detection(stp
);
1634 unixctl_command_reply(conn
, "OK");
1637 ovs_mutex_unlock(&mutex
);
1641 stp_bridge_id_details(struct ds
*ds
, const stp_identifier bridge_id
,
1642 const int hello_time
, const int max_age
,
1643 const int forward_delay
)
1646 uint16_t priority
= bridge_id
>> 48;
1647 ds_put_format(ds
, " stp-priority %"PRIu16
"\n", priority
);
1649 struct eth_addr mac
;
1650 const uint64_t mac_bits
= (UINT64_C(1) << 48) - 1;
1651 eth_addr_from_uint64(bridge_id
& mac_bits
, &mac
);
1652 ds_put_format(ds
, " stp-system-id "ETH_ADDR_FMT
"\n",
1653 ETH_ADDR_ARGS(mac
));
1654 ds_put_format(ds
, " stp-hello-time %ds\n",
1655 timer_to_ms(hello_time
) / 1000);
1656 ds_put_format(ds
, " stp-max-age %ds\n", timer_to_ms(max_age
) / 1000);
1657 ds_put_format(ds
, " stp-fwd-delay %ds\n",
1658 timer_to_ms(forward_delay
) / 1000);
1662 stp_print_details(struct ds
*ds
, const struct stp
*stp
)
1665 const uint16_t port_no_bits
= (UINT16_C(1) << 8) - 1;
1667 ds_put_format(ds
, "---- %s ----\n", stp
->name
);
1668 ds_put_cstr(ds
, "Root ID:\n");
1670 stp_bridge_id_details(ds
, stp
->designated_root
, stp
->bridge_hello_time
,
1671 stp
->bridge_max_age
, stp
->bridge_forward_delay
);
1673 if (stp_is_root_bridge(stp
)) {
1674 ds_put_cstr(ds
, " This bridge is the root\n");
1676 ds_put_format(ds
, " root-port %s\n", stp
->root_port
->port_name
);
1677 ds_put_format(ds
, " root-path-cost %u\n", stp
->root_path_cost
);
1680 ds_put_cstr(ds
, "\n");
1682 ds_put_cstr(ds
, "Bridge ID:\n");
1683 stp_bridge_id_details(ds
, stp
->bridge_id
, stp
->hello_time
,
1684 stp
->max_age
, stp
->forward_delay
);
1686 ds_put_cstr(ds
, "\n");
1688 const struct stp_port
*p
;
1689 ds_put_format(ds
, " %-11.10s%-11.10s%-11.10s%-6.5s%-8.7s\n",
1690 "Interface", "Role", "State", "Cost", "Pri.Nbr");
1691 ds_put_cstr(ds
, " ---------- ---------- ---------- ----- -------\n");
1692 FOR_EACH_ENABLED_PORT (p
, stp
) {
1693 ds_put_format(ds
, " %-11.10s", p
->port_name
);
1694 ds_put_format(ds
, "%-11.10s", stp_role_name(stp_port_get_role(p
)));
1695 ds_put_format(ds
, "%-11.10s", stp_state_name(p
->state
));
1696 ds_put_format(ds
, "%-6d", p
->path_cost
);
1697 ds_put_format(ds
, "%d.%d\n", p
->port_id
>> 8,
1698 p
->port_id
& port_no_bits
);
1701 ds_put_cstr(ds
, "\n");
1705 stp_unixctl_show(struct unixctl_conn
*conn
, int argc
,
1706 const char *argv
[], void *aux OVS_UNUSED
)
1708 struct ds ds
= DS_EMPTY_INITIALIZER
;
1710 ovs_mutex_lock(&mutex
);
1712 struct stp
*stp
= stp_find(argv
[1]);
1715 unixctl_command_reply_error(conn
, "no such stp object");
1719 stp_print_details(&ds
, stp
);
1723 LIST_FOR_EACH (stp
, node
, all_stps
) {
1724 stp_print_details(&ds
, stp
);
1728 unixctl_command_reply(conn
, ds_cstr(&ds
));
1732 ovs_mutex_unlock(&mutex
);