2 * Copyright (c) 2011-2014 M3S, Srl - Italy
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.
18 * Rapid Spanning Tree Protocol (IEEE 802.1D-2004) state machines
22 * Martino Fornasa <mf@fornasa.it>
23 * Daniele Venturino <daniele.venturino@m3s.it>
25 * References to IEEE 802.1D-2004 standard are enclosed in square brackets.
26 * E.g. [17.3], [Table 17-1], etc.
32 #include "rstp-state-machines.h"
33 #include <arpa/inet.h>
35 #include <netinet/in.h>
37 #include <sys/types.h>
38 #include "byte-order.h"
39 #include "connectivity.h"
47 VLOG_DEFINE_THIS_MODULE(rstp_sm
);
49 #define ROLE_FLAG_MASK 0xC
50 #define ROLE_FLAG_SHIFT 2
60 CONFIGURATION_BPDU_SIZE
= 35,
61 TOPOLOGY_CHANGE_NOTIFICATION_BPDU_SIZE
= 4,
62 RAPID_SPANNING_TREE_BPDU_SIZE
= 36
65 /* Same is a subset of SUPERIOR, so can be used as a boolean when the
66 * distinction is not significant. */
67 enum vector_comparison
{
73 static void decrement_timer(uint16_t *);
74 static void rstp_send_bpdu(struct rstp_port
*, const void *, size_t)
75 OVS_REQUIRES(rstp_mutex
);
76 static int validate_received_bpdu(struct rstp_port
*, const void *, size_t)
77 OVS_REQUIRES(rstp_mutex
);
78 static ovs_be16
time_encode(uint8_t);
79 static uint8_t time_decode(ovs_be16
);
80 static enum vector_comparison
81 compare_rstp_priority_vectors(const struct rstp_priority_vector
*,
82 const struct rstp_priority_vector
*);
83 static bool rstp_times_equal(struct rstp_times
*, struct rstp_times
*);
85 /* Per-Bridge State Machine */
86 static int port_role_selection_sm(struct rstp
*)
87 OVS_REQUIRES(rstp_mutex
);
88 /* Per-Port State Machines */
89 static int port_receive_sm(struct rstp_port
*)
90 OVS_REQUIRES(rstp_mutex
);
91 static int port_protocol_migration_sm(struct rstp_port
*)
92 OVS_REQUIRES(rstp_mutex
);
93 static int bridge_detection_sm(struct rstp_port
*)
94 OVS_REQUIRES(rstp_mutex
);
95 static int port_transmit_sm(struct rstp_port
*)
96 OVS_REQUIRES(rstp_mutex
);
97 static int port_information_sm(struct rstp_port
*)
98 OVS_REQUIRES(rstp_mutex
);
99 static int port_role_transition_sm(struct rstp_port
*)
100 OVS_REQUIRES(rstp_mutex
);
101 static int port_state_transition_sm(struct rstp_port
*)
102 OVS_REQUIRES(rstp_mutex
);
103 static int topology_change_sm(struct rstp_port
*)
104 OVS_REQUIRES(rstp_mutex
);
105 /* port_timers_sm() not defined as a state machine */
108 process_received_bpdu__(struct rstp_port
*p
, const void *bpdu_
,
110 OVS_REQUIRES(rstp_mutex
)
112 struct rstp
*rstp
= p
->rstp
;
113 struct rstp_bpdu
*bpdu
= (struct rstp_bpdu
*)bpdu_
;
115 if (!p
->port_enabled
) {
122 /* [9.2.9 Encoding of Port Role values]
123 * NOTE. If the Unknown value of the Port Role parameter is received, the
124 * state machines will effectively treat the RST BPDU as if it were a
125 * Configuration BPDU.
127 if (bpdu
->bpdu_type
== RAPID_SPANNING_TREE_BPDU
) {
128 uint8_t role
= (bpdu
->flags
& ROLE_FLAG_MASK
) >> ROLE_FLAG_SHIFT
;
130 if (role
== PORT_UNKN
) {
131 bpdu
->bpdu_type
= CONFIGURATION_BPDU
;
135 if (validate_received_bpdu(p
, bpdu
, bpdu_size
) == 0) {
137 p
->rx_rstp_bpdu_cnt
++;
139 memcpy(&p
->received_bpdu_buffer
, bpdu
, sizeof(struct rstp_bpdu
));
141 rstp
->changes
= true;
144 VLOG_DBG("%s, port %u: Bad STP or RSTP BPDU received", p
->rstp
->name
,
150 /* Returns 0 on success. */
152 validate_received_bpdu(struct rstp_port
*p
, const void *bpdu
, size_t bpdu_size
)
153 OVS_REQUIRES(rstp_mutex
)
155 /* Validation of received BPDU, see [9.3.4]. */
156 const struct rstp_bpdu
*temp
;
159 if (bpdu_size
< TOPOLOGY_CHANGE_NOTIFICATION_BPDU_SIZE
||
160 ntohs(temp
->protocol_identifier
) != 0) {
163 if (temp
->bpdu_type
== CONFIGURATION_BPDU
164 && bpdu_size
>= CONFIGURATION_BPDU_SIZE
165 && (time_decode(temp
->message_age
) < time_decode(temp
->max_age
))) {
166 if ((ntohll(temp
->designated_bridge_id
) !=
167 p
->rstp
->bridge_identifier
)
168 || ((ntohll(temp
->designated_bridge_id
) ==
169 p
->rstp
->bridge_identifier
)
170 && (ntohs(temp
->designated_port_id
) != p
->port_id
))) {
175 } else if (temp
->bpdu_type
== TOPOLOGY_CHANGE_NOTIFICATION_BPDU
) {
177 } else if (temp
->bpdu_type
== RAPID_SPANNING_TREE_BPDU
&&
178 bpdu_size
>= RAPID_SPANNING_TREE_BPDU_SIZE
) {
188 * This method is invoked to move the State Machines. The SMs move only if the
189 * boolean 'changes' is true, meaning that something changed and the SMs need
190 * to work to process this change.
191 * The boolean 'changes' is set every time a SM modifies its state, a BPDU is
192 * received, a timer expires or port down event is detected. If a parameter is
193 * set by management, then 'changes' is set.
195 #define MAX_RSTP_ITERATIONS 1000 /* safeguard */
197 move_rstp__(struct rstp
*rstp
)
198 OVS_REQUIRES(rstp_mutex
)
203 while (rstp
->changes
== true && num_iterations
< MAX_RSTP_ITERATIONS
) {
206 VLOG_DBG("%s: move_rstp()", rstp
->name
);
208 rstp
->changes
= false;
209 port_role_selection_sm(rstp
);
210 HMAP_FOR_EACH (p
, node
, &rstp
->ports
) {
211 if (p
->rstp_state
!= RSTP_DISABLED
) {
213 bridge_detection_sm(p
);
214 port_information_sm(p
);
215 port_role_transition_sm(p
);
216 port_state_transition_sm(p
);
217 topology_change_sm(p
);
219 port_protocol_migration_sm(p
);
223 seq_change(connectivity_seq_get());
225 if (num_iterations
>= MAX_RSTP_ITERATIONS
) {
226 VLOG_ERR("%s: move_rstp() reached the iteration safeguard limit!",
232 void decrease_rstp_port_timers__(struct rstp
*r
)
233 OVS_REQUIRES(rstp_mutex
)
237 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
238 decrement_timer(&p
->hello_when
);
239 decrement_timer(&p
->tc_while
);
240 decrement_timer(&p
->fd_while
);
241 decrement_timer(&p
->rcvd_info_while
);
242 decrement_timer(&p
->rr_while
);
243 decrement_timer(&p
->rb_while
);
244 decrement_timer(&p
->mdelay_while
);
245 decrement_timer(&p
->edge_delay_while
);
246 decrement_timer(&p
->tx_count
);
254 decrement_timer(uint16_t *timer
)
261 /* Bridge State Machine. */
262 /* [17.28] Port Role Selection state machine. */
265 updt_role_disabled_tree(struct rstp
*r
)
266 OVS_REQUIRES(rstp_mutex
)
270 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
271 p
->selected_role
= ROLE_DISABLED
;
276 clear_reselect_tree(struct rstp
*r
)
277 OVS_REQUIRES(rstp_mutex
)
281 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
287 updt_roles_tree__(struct rstp
*r
)
288 OVS_REQUIRES(rstp_mutex
)
292 struct rstp_priority_vector best_vector
, candidate_vector
;
295 best_vector
= r
->bridge_priority
;
297 r
->root_times
= r
->bridge_times
;
298 /* Letters a) b) c) */
299 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
300 uint32_t old_root_path_cost
;
301 uint32_t root_path_cost
;
303 if (p
->info_is
!= INFO_IS_RECEIVED
) {
307 candidate_vector
= p
->port_priority
;
308 candidate_vector
.bridge_port_id
= p
->port_id
;
309 old_root_path_cost
= candidate_vector
.root_path_cost
;
310 root_path_cost
= old_root_path_cost
+ p
->port_path_cost
;
311 candidate_vector
.root_path_cost
= root_path_cost
;
313 if ((candidate_vector
.designated_bridge_id
& 0xffffffffffffULL
) ==
314 (r
->bridge_priority
.designated_bridge_id
& 0xffffffffffffULL
)) {
317 if (compare_rstp_priority_vectors(&candidate_vector
,
318 &best_vector
) == SUPERIOR
) {
319 best_vector
= candidate_vector
;
320 r
->root_times
= p
->port_times
;
321 r
->root_times
.message_age
++;
322 vsel
= p
->port_number
;
325 r
->root_priority
= best_vector
;
326 r
->root_port_id
= best_vector
.bridge_port_id
;
327 VLOG_DBG("%s: new Root is "RSTP_ID_FMT
, r
->name
,
328 RSTP_ID_ARGS(r
->root_priority
.root_bridge_id
));
330 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
331 p
->designated_priority_vector
.root_bridge_id
=
332 r
->root_priority
.root_bridge_id
;
333 p
->designated_priority_vector
.root_path_cost
=
334 r
->root_priority
.root_path_cost
;
335 p
->designated_priority_vector
.designated_bridge_id
=
336 r
->bridge_identifier
;
337 p
->designated_priority_vector
.designated_port_id
=
339 p
->designated_times
= r
->root_times
;
340 p
->designated_times
.hello_time
= r
->bridge_times
.hello_time
;
342 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
343 switch (p
->info_is
) {
344 case INFO_IS_DISABLED
:
345 p
->selected_role
= ROLE_DISABLED
;
349 p
->selected_role
= ROLE_DESIGNATED
;
352 p
->selected_role
= ROLE_DESIGNATED
;
353 if (compare_rstp_priority_vectors(
354 &p
->port_priority
, &p
->designated_priority_vector
) != SAME
355 || !rstp_times_equal(&p
->designated_times
, &r
->root_times
)) {
359 case INFO_IS_RECEIVED
:
360 if (vsel
== p
->port_number
) { /* Letter i) */
361 p
->selected_role
= ROLE_ROOT
;
362 p
->updt_info
= false;
363 } else if (compare_rstp_priority_vectors(
364 &p
->designated_priority_vector
,
365 &p
->port_priority
) == INFERIOR
) {
366 if (p
->port_priority
.designated_bridge_id
!=
367 r
->bridge_identifier
) {
368 p
->selected_role
= ROLE_ALTERNATE
;
369 p
->updt_info
= false;
371 p
->selected_role
= ROLE_BACKUP
;
372 p
->updt_info
= false;
375 p
->selected_role
= ROLE_DESIGNATED
;
384 seq_change(connectivity_seq_get());
388 set_selected_tree(struct rstp
*r
)
389 OVS_REQUIRES(rstp_mutex
)
393 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
398 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
404 port_role_selection_sm(struct rstp
*r
)
405 OVS_REQUIRES(rstp_mutex
)
407 enum port_role_selection_state_machine old_state
;
410 old_state
= r
->port_role_selection_sm_state
;
412 switch (r
->port_role_selection_sm_state
) {
413 case PORT_ROLE_SELECTION_SM_INIT
:
415 r
->port_role_selection_sm_state
=
416 PORT_ROLE_SELECTION_SM_INIT_BRIDGE_EXEC
;
419 case PORT_ROLE_SELECTION_SM_INIT_BRIDGE_EXEC
:
420 updt_role_disabled_tree(r
);
421 r
->port_role_selection_sm_state
= PORT_ROLE_SELECTION_SM_INIT_BRIDGE
;
423 case PORT_ROLE_SELECTION_SM_INIT_BRIDGE
:
424 r
->port_role_selection_sm_state
=
425 PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC
;
427 case PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC
:
428 clear_reselect_tree(r
);
429 updt_roles_tree__(r
);
430 set_selected_tree(r
);
431 r
->port_role_selection_sm_state
=
432 PORT_ROLE_SELECTION_SM_ROLE_SELECTION
;
434 case PORT_ROLE_SELECTION_SM_ROLE_SELECTION
:
435 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
437 r
->port_role_selection_sm_state
=
438 PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC
;
447 if (old_state
!= r
->port_role_selection_sm_state
) {
449 VLOG_DBG("%s: Port_role_selection_sm %d -> %d", r
->name
,
450 old_state
, r
->port_role_selection_sm_state
);
455 /* Port State Machines */
457 /* [17.23 - Port receive state machine] */
460 updt_bpdu_version(struct rstp_port
*p
) /* [17.21.22] */
461 OVS_REQUIRES(rstp_mutex
)
463 switch (p
->received_bpdu_buffer
.bpdu_type
) {
464 case CONFIGURATION_BPDU
:
465 case TOPOLOGY_CHANGE_NOTIFICATION_BPDU
:
466 p
->rcvd_rstp
= false;
469 case RAPID_SPANNING_TREE_BPDU
:
480 port_receive_sm(struct rstp_port
*p
)
481 OVS_REQUIRES(rstp_mutex
)
483 enum port_receive_state_machine old_state
;
486 old_state
= p
->port_receive_sm_state
;
489 switch (p
->port_receive_sm_state
) {
490 case PORT_RECEIVE_SM_INIT
:
491 if (r
->begin
|| ((p
->rcvd_bpdu
|| (p
->edge_delay_while
!=
492 r
->migrate_time
)) && !p
->port_enabled
)) {
493 p
->port_receive_sm_state
= PORT_RECEIVE_SM_DISCARD_EXEC
;
496 case PORT_RECEIVE_SM_DISCARD_EXEC
:
497 p
->rcvd_bpdu
= p
->rcvd_rstp
= p
->rcvd_stp
= false;
499 p
->edge_delay_while
= r
->migrate_time
;
500 p
->port_receive_sm_state
= PORT_RECEIVE_SM_DISCARD
;
502 case PORT_RECEIVE_SM_DISCARD
:
503 if (p
->rcvd_bpdu
&& p
->port_enabled
) {
504 p
->port_receive_sm_state
= PORT_RECEIVE_SM_RECEIVE_EXEC
;
507 case PORT_RECEIVE_SM_RECEIVE_EXEC
:
508 updt_bpdu_version(p
);
509 p
->oper_edge
= p
->rcvd_bpdu
= false;
511 p
->edge_delay_while
= r
->migrate_time
;
512 p
->port_receive_sm_state
= PORT_RECEIVE_SM_RECEIVE
;
514 case PORT_RECEIVE_SM_RECEIVE
:
515 if (p
->rcvd_bpdu
&& p
->port_enabled
&& !p
->rcvd_msg
) {
516 p
->port_receive_sm_state
= PORT_RECEIVE_SM_RECEIVE_EXEC
;
523 if (old_state
!= p
->port_receive_sm_state
) {
525 VLOG_DBG("%s, port %u: Port_receive_sm %d -> %d", p
->rstp
->name
,
526 p
->port_number
, old_state
, p
->port_receive_sm_state
);
531 /* [17.24 - Port Protocol Migration state machine] */
533 port_protocol_migration_sm(struct rstp_port
*p
)
534 OVS_REQUIRES(rstp_mutex
)
536 enum port_protocol_migration_state_machine old_state
;
539 old_state
= p
->port_protocol_migration_sm_state
;
542 switch (p
->port_protocol_migration_sm_state
) {
543 case PORT_PROTOCOL_MIGRATION_SM_INIT
:
544 p
->port_protocol_migration_sm_state
=
545 PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC
;
547 case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC
:
549 p
->send_rstp
= r
->rstp_version
;
550 p
->mdelay_while
= r
->migrate_time
;
551 p
->port_protocol_migration_sm_state
=
552 PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP
;
554 case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP
:
555 if (p
->mdelay_while
== 0) {
556 p
->port_protocol_migration_sm_state
=
557 PORT_PROTOCOL_MIGRATION_SM_SENSING_EXEC
;
558 } else if ((p
->mdelay_while
!= r
->migrate_time
) && !p
->port_enabled
) {
559 p
->port_protocol_migration_sm_state
=
560 PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC
;
563 case PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP_EXEC
:
564 p
->send_rstp
= false;
565 p
->mdelay_while
= r
->migrate_time
;
566 p
->port_protocol_migration_sm_state
=
567 PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP
;
569 case PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP
:
570 if ((p
->mdelay_while
== 0) || (!p
->port_enabled
) || p
->mcheck
) {
571 p
->port_protocol_migration_sm_state
=
572 PORT_PROTOCOL_MIGRATION_SM_SENSING_EXEC
;
575 case PORT_PROTOCOL_MIGRATION_SM_SENSING_EXEC
:
576 p
->rcvd_rstp
= false;
578 p
->port_protocol_migration_sm_state
=
579 PORT_PROTOCOL_MIGRATION_SM_SENSING
;
581 case PORT_PROTOCOL_MIGRATION_SM_SENSING
:
582 if (!p
->port_enabled
|| p
->mcheck
|| ((r
->rstp_version
) &&
583 !p
->send_rstp
&& p
->rcvd_rstp
)) {
584 p
->port_protocol_migration_sm_state
=
585 PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC
;
586 } else if (p
->send_rstp
&& p
->rcvd_stp
) {
587 p
->port_protocol_migration_sm_state
=
588 PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP_EXEC
;
595 if (old_state
!= p
->port_protocol_migration_sm_state
) {
597 VLOG_DBG("%s, port %u: port_protocol_migration_sm %d -> %d",
598 p
->rstp
->name
, p
->port_number
, old_state
,
599 p
->port_protocol_migration_sm_state
);
605 /* [17.25 - Bridge Detection state machine] */
607 bridge_detection_sm(struct rstp_port
*p
)
608 OVS_REQUIRES(rstp_mutex
)
610 enum bridge_detection_state_machine old_state
;
613 old_state
= p
->bridge_detection_sm_state
;
616 switch (p
->bridge_detection_sm_state
) {
617 case BRIDGE_DETECTION_SM_INIT
:
618 if (r
->begin
&& p
->admin_edge
) {
619 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_EDGE_EXEC
;
620 } else if (r
->begin
&& !p
->admin_edge
) {
621 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_NOT_EDGE_EXEC
;
624 case BRIDGE_DETECTION_SM_EDGE_EXEC
:
626 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_EDGE
;
628 case BRIDGE_DETECTION_SM_EDGE
:
629 if ((!p
->port_enabled
&& !p
->admin_edge
) || !p
->oper_edge
) {
630 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_NOT_EDGE_EXEC
;
633 case BRIDGE_DETECTION_SM_NOT_EDGE_EXEC
:
634 p
->oper_edge
= false;
635 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_NOT_EDGE
;
637 case BRIDGE_DETECTION_SM_NOT_EDGE
:
638 if ((!p
->port_enabled
&& p
->admin_edge
)
639 || ((p
->edge_delay_while
== 0) && p
->auto_edge
&& p
->send_rstp
641 p
->bridge_detection_sm_state
= BRIDGE_DETECTION_SM_EDGE_EXEC
;
648 if (old_state
!= p
->bridge_detection_sm_state
) {
650 VLOG_DBG("%s, port %u: bridge_detection_sm %d -> %d", p
->rstp
->name
,
651 p
->port_number
, old_state
, p
->bridge_detection_sm_state
);
656 /* [17.26 - Port Transmit state machine] */
658 rstp_send_bpdu(struct rstp_port
*p
, const void *bpdu
, size_t bpdu_size
)
659 OVS_REQUIRES(rstp_mutex
)
661 struct eth_header
*eth
;
662 struct llc_header
*llc
;
666 pkt
= ofpbuf_new(ETH_HEADER_LEN
+ LLC_HEADER_LEN
+ bpdu_size
);
667 eth
= ofpbuf_put_zeros(pkt
, sizeof *eth
);
668 llc
= ofpbuf_put_zeros(pkt
, sizeof *llc
);
669 ofpbuf_set_frame(pkt
, eth
);
670 ofpbuf_set_l3(pkt
, ofpbuf_put(pkt
, bpdu
, bpdu_size
));
673 memcpy(eth
->eth_dst
, eth_addr_stp
, ETH_ADDR_LEN
);
674 /* p->rstp->send_bpdu() must fill in source address. */
675 eth
->eth_type
= htons(ofpbuf_size(pkt
) - ETH_HEADER_LEN
);
678 llc
->llc_dsap
= STP_LLC_DSAP
;
679 llc
->llc_ssap
= STP_LLC_SSAP
;
680 llc
->llc_cntl
= STP_LLC_CNTL
;
681 p
->rstp
->send_bpdu(pkt
, p
->aux
, p
->rstp
->aux
);
685 record_agreement(struct rstp_port
*p
)
686 OVS_REQUIRES(rstp_mutex
)
691 if (r
->rstp_version
&& p
->oper_point_to_point_mac
&&
692 ((p
->received_bpdu_buffer
.flags
& BPDU_FLAG_AGREEMENT
))) {
694 p
->proposing
= false;
701 set_tc_flags(struct rstp_port
*p
)
702 OVS_REQUIRES(rstp_mutex
)
704 /* Sets rcvd_tc and/or rcvd_tc_ack if the Topology Change and/or Topology
705 * Change Acknowledgment flags, respectively, are set in a ConfigBPDU or
708 if (p
->received_bpdu_buffer
.bpdu_type
== CONFIGURATION_BPDU
||
709 p
->received_bpdu_buffer
.bpdu_type
== RAPID_SPANNING_TREE_BPDU
) {
710 if ((p
->received_bpdu_buffer
.flags
& BPDU_FLAG_TOPCHANGE
) != 0) {
713 if ((p
->received_bpdu_buffer
.flags
& BPDU_FLAG_TOPCHANGEACK
) != 0) {
714 p
->rcvd_tc_ack
= true;
717 /* Sets rcvd_tcn true if the BPDU is a TCN BPDU. */
718 if (p
->received_bpdu_buffer
.bpdu_type
719 == TOPOLOGY_CHANGE_NOTIFICATION_BPDU
) {
725 record_dispute(struct rstp_port
*p
)
726 OVS_REQUIRES(rstp_mutex
)
728 if ((p
->received_bpdu_buffer
.flags
& BPDU_FLAG_LEARNING
) != 0) {
730 p
->proposing
= false;
735 record_proposal(struct rstp_port
*p
)
736 OVS_REQUIRES(rstp_mutex
)
738 enum port_flag role
=
739 ((p
->received_bpdu_buffer
.flags
) & ROLE_FLAG_MASK
) >> ROLE_FLAG_SHIFT
;
741 if ((role
== PORT_DES
)
742 && ((p
->received_bpdu_buffer
.flags
& BPDU_FLAG_PROPOSAL
) != 0)) {
748 record_priority(struct rstp_port
*p
)
749 OVS_REQUIRES(rstp_mutex
)
751 p
->port_priority
.root_bridge_id
= p
->msg_priority
.root_bridge_id
;
752 p
->port_priority
.root_path_cost
= p
->msg_priority
.root_path_cost
;
753 p
->port_priority
.designated_bridge_id
=
754 p
->msg_priority
.designated_bridge_id
;
755 p
->port_priority
.designated_port_id
= p
->msg_priority
.designated_port_id
;
759 record_times(struct rstp_port
*p
)
760 OVS_REQUIRES(rstp_mutex
)
762 p
->port_times
= p
->msg_times
;
763 if (p
->msg_times
.hello_time
== 0) {
764 p
->port_times
.hello_time
= 1;
769 updt_rcvd_info_while(struct rstp_port
*p
)
770 OVS_REQUIRES(rstp_mutex
)
773 * The value assigned to rcvdInfoWhile is the three times the Hello Time,
774 * if Message Age, incremented by 1 second and rounded to the nearest whole
775 * second, does not exceed Max Age, and is zero otherwise.
777 if (p
->port_times
.message_age
< p
->port_times
.max_age
) {
778 p
->rcvd_info_while
= p
->port_times
.hello_time
* 3;
780 p
->rcvd_info_while
= 0;
784 /* Times are internally held in seconds, while the protocol uses 1/256 seconds.
785 * time_encode() is used to convert time values sent in bpdus, while
786 * time_decode() is used to convert time values received in bpdus.
789 time_encode(uint8_t value
)
791 return htons(value
* 256);
795 time_decode(ovs_be16 encoded
)
797 return ntohs(encoded
) / 256;
802 tx_config(struct rstp_port
*p
)
803 OVS_REQUIRES(rstp_mutex
)
805 struct rstp_bpdu bpdu
;
807 bpdu
.protocol_identifier
= htons(0);
808 bpdu
.protocol_version_identifier
= 0;
809 bpdu
.bpdu_type
= CONFIGURATION_BPDU
;
810 bpdu
.root_bridge_id
= htonll(p
->designated_priority_vector
.root_bridge_id
);
811 bpdu
.root_path_cost
= htonl(p
->designated_priority_vector
.root_path_cost
);
812 bpdu
.designated_bridge_id
=
813 htonll(p
->designated_priority_vector
.designated_bridge_id
);
814 bpdu
.designated_port_id
=
815 htons(p
->designated_priority_vector
.designated_port_id
);
816 bpdu
.message_age
= time_encode(p
->designated_times
.message_age
);
817 bpdu
.max_age
= time_encode(p
->designated_times
.max_age
);
818 bpdu
.hello_time
= time_encode(p
->designated_times
.hello_time
);
819 bpdu
.forward_delay
= time_encode(p
->designated_times
.forward_delay
);
821 if (p
->tc_while
!= 0) {
822 bpdu
.flags
|= BPDU_FLAG_TOPCHANGE
;
824 if (p
->tc_ack
!= 0) {
825 bpdu
.flags
|= BPDU_FLAG_TOPCHANGEACK
;
827 rstp_send_bpdu(p
, &bpdu
, sizeof(struct rstp_bpdu
));
832 tx_rstp(struct rstp_port
*p
)
833 OVS_REQUIRES(rstp_mutex
)
835 struct rstp_bpdu bpdu
;
837 bpdu
.protocol_identifier
= htons(0);
838 bpdu
.protocol_version_identifier
= 2;
839 bpdu
.bpdu_type
= RAPID_SPANNING_TREE_BPDU
;
840 bpdu
.root_bridge_id
= htonll(p
->designated_priority_vector
.root_bridge_id
);
841 bpdu
.root_path_cost
= htonl(p
->designated_priority_vector
.root_path_cost
);
842 bpdu
.designated_bridge_id
=
843 htonll(p
->designated_priority_vector
.designated_bridge_id
);
844 bpdu
.designated_port_id
=
845 htons(p
->designated_priority_vector
.designated_port_id
);
846 bpdu
.message_age
= time_encode(p
->designated_times
.message_age
);
847 bpdu
.max_age
= time_encode(p
->designated_times
.max_age
);
848 bpdu
.hello_time
= time_encode(p
->designated_times
.hello_time
);
849 bpdu
.forward_delay
= time_encode(p
->designated_times
.forward_delay
);
854 bpdu
.flags
= PORT_ROOT
<< ROLE_FLAG_SHIFT
;
856 case ROLE_DESIGNATED
:
857 bpdu
.flags
= PORT_DES
<< ROLE_FLAG_SHIFT
;
861 bpdu
.flags
= PORT_ALT_BACK
<< ROLE_FLAG_SHIFT
;
864 /* Should not happen! */
865 VLOG_ERR("%s transmitting bpdu in disabled role on port "
866 RSTP_PORT_ID_FMT
, p
->rstp
->name
, p
->port_id
);
870 bpdu
.flags
|= BPDU_FLAG_AGREEMENT
;
873 bpdu
.flags
|= BPDU_FLAG_PROPOSAL
;
875 if (p
->tc_while
!= 0) {
876 bpdu
.flags
|= BPDU_FLAG_TOPCHANGE
;
879 bpdu
.flags
|= BPDU_FLAG_LEARNING
;
882 bpdu
.flags
|= BPDU_FLAG_FORWARDING
;
884 bpdu
.version1_length
= 0;
885 rstp_send_bpdu(p
, &bpdu
, sizeof(struct rstp_bpdu
));
890 tx_tcn(struct rstp_port
*p
)
891 OVS_REQUIRES(rstp_mutex
)
893 struct rstp_bpdu bpdu
;
895 memset(&bpdu
, 0, sizeof(struct rstp_bpdu
));
897 bpdu
.protocol_identifier
= htons(0);
898 bpdu
.protocol_version_identifier
= 0;
899 bpdu
.bpdu_type
= TOPOLOGY_CHANGE_NOTIFICATION_BPDU
;
900 rstp_send_bpdu(p
, &bpdu
, sizeof(struct rstp_bpdu
));
904 port_transmit_sm(struct rstp_port
*p
)
905 OVS_REQUIRES(rstp_mutex
)
907 enum port_transmit_state_machine old_state
;
910 old_state
= p
->port_transmit_sm_state
;
913 switch (p
->port_transmit_sm_state
) {
914 case PORT_TRANSMIT_SM_INIT
:
916 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_INIT_EXEC
;
919 case PORT_TRANSMIT_SM_TRANSMIT_INIT_EXEC
:
922 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_INIT
;
924 case PORT_TRANSMIT_SM_TRANSMIT_INIT
:
925 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE_EXEC
;
927 case PORT_TRANSMIT_SM_TRANSMIT_PERIODIC_EXEC
:
928 p
->new_info
= p
->new_info
|| (p
->role
== ROLE_DESIGNATED
||
929 (p
->role
== ROLE_ROOT
&& p
->tc_while
!= 0));
930 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_PERIODIC
;
932 case PORT_TRANSMIT_SM_TRANSMIT_PERIODIC
:
933 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE_EXEC
;
935 case PORT_TRANSMIT_SM_IDLE_EXEC
:
936 p
->hello_when
= r
->bridge_hello_time
;
937 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE
;
939 case PORT_TRANSMIT_SM_IDLE
:
940 if (p
->role
== ROLE_DISABLED
) {
941 VLOG_DBG("%s, port %u: port_transmit_sm ROLE == DISABLED.",
942 p
->rstp
->name
, p
->port_number
);
944 } else if (p
->send_rstp
&& p
->new_info
945 && p
->tx_count
< r
->transmit_hold_count
946 && p
->hello_when
!= 0 && p
->selected
&& !p
->updt_info
) {
947 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_RSTP_EXEC
;
948 } else if (p
->hello_when
== 0 && p
->selected
&& !p
->updt_info
) {
949 p
->port_transmit_sm_state
=
950 PORT_TRANSMIT_SM_TRANSMIT_PERIODIC_EXEC
;
951 } else if (!p
->send_rstp
&& p
->new_info
&& p
->role
== ROLE_ROOT
952 && p
->tx_count
< r
->transmit_hold_count
953 && p
->hello_when
!= 0 && p
->selected
&& !p
->updt_info
) {
954 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_TCN_EXEC
;
955 } else if (!p
->send_rstp
&& p
->new_info
&& p
->role
== ROLE_DESIGNATED
956 && p
->tx_count
< r
->transmit_hold_count
957 && p
->hello_when
!= 0 && p
->selected
&& !p
->updt_info
) {
958 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_CONFIG_EXEC
;
961 case PORT_TRANSMIT_SM_TRANSMIT_CONFIG_EXEC
:
966 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_CONFIG
;
968 case PORT_TRANSMIT_SM_TRANSMIT_CONFIG
:
969 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE_EXEC
;
971 case PORT_TRANSMIT_SM_TRANSMIT_TCN_EXEC
:
975 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_TCN
;
977 case PORT_TRANSMIT_SM_TRANSMIT_TCN
:
978 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE_EXEC
;
980 case PORT_TRANSMIT_SM_TRANSMIT_RSTP_EXEC
:
985 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_TRANSMIT_RSTP
;
987 case PORT_TRANSMIT_SM_TRANSMIT_RSTP
:
988 p
->port_transmit_sm_state
= PORT_TRANSMIT_SM_IDLE_EXEC
;
994 if (old_state
!= p
->port_transmit_sm_state
) {
996 VLOG_DBG("%s, port %u: port_transmit_sm %d -> %d", p
->rstp
->name
,
997 p
->port_number
, old_state
, p
->port_transmit_sm_state
);
1002 /* [17.27 Port Information state machine] */
1007 rcv_info(struct rstp_port
*p
)
1008 OVS_REQUIRES(rstp_mutex
)
1010 enum vector_comparison cp
;
1012 enum port_flag role
;
1014 p
->msg_priority
.root_bridge_id
=
1015 ntohll(p
->received_bpdu_buffer
.root_bridge_id
);
1016 p
->msg_priority
.root_path_cost
=
1017 ntohl(p
->received_bpdu_buffer
.root_path_cost
);
1018 p
->msg_priority
.designated_bridge_id
=
1019 ntohll(p
->received_bpdu_buffer
.designated_bridge_id
);
1020 p
->msg_priority
.designated_port_id
=
1021 ntohs(p
->received_bpdu_buffer
.designated_port_id
);
1023 p
->msg_times
.forward_delay
=
1024 time_decode(p
->received_bpdu_buffer
.forward_delay
);
1025 p
->msg_times
.hello_time
= time_decode(p
->received_bpdu_buffer
.hello_time
);
1026 p
->msg_times
.max_age
= time_decode(p
->received_bpdu_buffer
.max_age
);
1027 p
->msg_times
.message_age
=
1028 time_decode(p
->received_bpdu_buffer
.message_age
);
1030 cp
= compare_rstp_priority_vectors(&p
->msg_priority
, &p
->port_priority
);
1031 ct
= rstp_times_equal(&p
->port_times
, &p
->msg_times
);
1033 (p
->received_bpdu_buffer
.flags
& ROLE_FLAG_MASK
) >> ROLE_FLAG_SHIFT
;
1035 /* Returns SuperiorDesignatedInfo if:
1036 * a) The received message conveys a Designated Port Role, and
1037 * 1) The message priority is superior (17.6) to the Port.s port priority
1039 * 2) The message priority vector is the same as the Port.s port priority
1040 * vector, and any of the received timer parameter values (msg_times.
1041 * 17.19.15) differ from those already held for the Port (port_times
1043 * NOTE: Configuration BPDU explicitly conveys a Designated Port Role.
1045 if ((role
== PORT_DES
1046 || p
->received_bpdu_buffer
.bpdu_type
== CONFIGURATION_BPDU
)
1047 && (cp
== SUPERIOR
|| (cp
== SAME
&& ct
== false))) {
1048 return SUPERIOR_DESIGNATED_INFO
;
1050 /* Returns RepeatedDesignatedInfo if:
1051 * b) The received message conveys Designated Port Role, and a message
1052 * priority vector and timer parameters that are the same as the
1053 * Port's port priority vector or timer values. */
1054 } else if (role
== PORT_DES
&& cp
== SAME
&& ct
== true) {
1055 return REPEATED_DESIGNATED_INFO
;
1057 /* Returns InferiorDesignatedInfo if:
1058 * c) The received message conveys a Designated Port Role, and a
1059 * message priority vector that is worse than the Port's port
1060 * priority vector. */
1061 } else if (role
== PORT_DES
&& cp
== INFERIOR
) {
1062 return INFERIOR_DESIGNATED_INFO
;
1064 /* Returns InferiorRootAlternateInfo if:
1065 * d) The received message conveys a Root Port, Alternate Port, or
1066 * Backup Port Role and a message priority that is the same as or
1067 * worse than the port priority vector. */
1068 } else if ((role
== PORT_ROOT
|| role
== PORT_ALT_BACK
) &&
1069 (cp
== INFERIOR
|| cp
== SAME
)) {
1070 return INFERIOR_ROOT_ALTERNATE_INFO
;
1072 /* Otherwise, returns OtherInfo. */
1079 better_or_same_info(struct rstp_port
*p
, int new_info_is
)
1080 OVS_REQUIRES(rstp_mutex
)
1083 (new_info_is
== RECEIVED
&& p
->info_is
== INFO_IS_RECEIVED
1084 && compare_rstp_priority_vectors(&p
->msg_priority
,
1086 || (new_info_is
== MINE
&& p
->info_is
== INFO_IS_MINE
1087 && compare_rstp_priority_vectors(&p
->designated_priority_vector
,
1088 &p
->port_priority
));
1092 port_information_sm(struct rstp_port
*p
)
1093 OVS_REQUIRES(rstp_mutex
)
1095 enum port_information_state_machine old_state
;
1098 old_state
= p
->port_information_sm_state
;
1101 if (!p
->port_enabled
&& p
->info_is
!= INFO_IS_DISABLED
) {
1102 p
->port_information_sm_state
= PORT_INFORMATION_SM_DISABLED_EXEC
;
1104 switch (p
->port_information_sm_state
) {
1105 case PORT_INFORMATION_SM_INIT
:
1107 p
->port_information_sm_state
= PORT_INFORMATION_SM_DISABLED_EXEC
;
1110 case PORT_INFORMATION_SM_DISABLED_EXEC
:
1111 p
->rcvd_msg
= false;
1112 p
->proposing
= p
->proposed
= p
->agree
= p
->agreed
= false;
1113 p
->rcvd_info_while
= 0;
1114 p
->info_is
= INFO_IS_DISABLED
;
1116 p
->selected
= false;
1117 p
->port_information_sm_state
= PORT_INFORMATION_SM_DISABLED
;
1119 case PORT_INFORMATION_SM_DISABLED
:
1120 if (p
->port_enabled
) {
1121 p
->port_information_sm_state
= PORT_INFORMATION_SM_AGED_EXEC
;
1122 } else if (p
->rcvd_msg
) {
1123 p
->port_information_sm_state
= PORT_INFORMATION_SM_DISABLED_EXEC
;
1126 case PORT_INFORMATION_SM_AGED_EXEC
:
1127 p
->info_is
= INFO_IS_AGED
;
1129 p
->selected
= false;
1130 p
->port_information_sm_state
= PORT_INFORMATION_SM_AGED
;
1132 case PORT_INFORMATION_SM_AGED
:
1133 if (p
->selected
&& p
->updt_info
) {
1134 p
->port_information_sm_state
= PORT_INFORMATION_SM_UPDATE_EXEC
;
1137 case PORT_INFORMATION_SM_UPDATE_EXEC
:
1138 p
->proposing
= p
->proposed
= false;
1139 /* MINE is not specified in Standard 802.1D-2004. */
1140 p
->agreed
= p
->agreed
&& better_or_same_info(p
, MINE
);
1141 p
->synced
= p
->synced
&& p
->agreed
;
1142 p
->port_priority
.root_bridge_id
=
1143 p
->designated_priority_vector
.root_bridge_id
;
1144 p
->port_priority
.root_path_cost
=
1145 p
->designated_priority_vector
.root_path_cost
;
1146 p
->port_priority
.designated_bridge_id
=
1147 p
->designated_priority_vector
.designated_bridge_id
;
1148 p
->port_priority
.designated_port_id
=
1149 p
->designated_priority_vector
.designated_port_id
;
1150 p
->port_times
= p
->designated_times
;
1151 p
->updt_info
= false;
1152 p
->info_is
= INFO_IS_MINE
;
1154 p
->port_information_sm_state
= PORT_INFORMATION_SM_UPDATE
;
1156 case PORT_INFORMATION_SM_UPDATE
:
1157 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1159 case PORT_INFORMATION_SM_CURRENT_EXEC
:
1160 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT
;
1162 case PORT_INFORMATION_SM_CURRENT
:
1163 if (p
->rcvd_msg
&& !p
->updt_info
) {
1164 p
->port_information_sm_state
= PORT_INFORMATION_SM_RECEIVE_EXEC
;
1165 } else if (p
->selected
&& p
->updt_info
) {
1166 p
->port_information_sm_state
= PORT_INFORMATION_SM_UPDATE_EXEC
;
1167 } else if ((p
->info_is
== INFO_IS_RECEIVED
) &&
1168 (p
->rcvd_info_while
== 0) && !p
->updt_info
&&
1170 p
->port_information_sm_state
= PORT_INFORMATION_SM_AGED_EXEC
;
1173 case PORT_INFORMATION_SM_RECEIVE_EXEC
:
1174 p
->rcvd_info
= rcv_info(p
);
1175 p
->port_information_sm_state
= PORT_INFORMATION_SM_RECEIVE
;
1177 case PORT_INFORMATION_SM_RECEIVE
:
1178 switch (p
->rcvd_info
) {
1179 case SUPERIOR_DESIGNATED_INFO
:
1180 p
->port_information_sm_state
=
1181 PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC
;
1183 case REPEATED_DESIGNATED_INFO
:
1184 p
->port_information_sm_state
=
1185 PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC
;
1187 case INFERIOR_DESIGNATED_INFO
:
1188 p
->port_information_sm_state
=
1189 PORT_INFORMATION_SM_INFERIOR_DESIGNATED_EXEC
;
1191 case INFERIOR_ROOT_ALTERNATE_INFO
:
1192 p
->port_information_sm_state
=
1193 PORT_INFORMATION_SM_NOT_DESIGNATED_EXEC
;
1196 p
->port_information_sm_state
= PORT_INFORMATION_SM_OTHER_EXEC
;
1203 case PORT_INFORMATION_SM_OTHER_EXEC
:
1204 p
->rcvd_msg
= false;
1205 p
->port_information_sm_state
= PORT_INFORMATION_SM_OTHER
;
1207 case PORT_INFORMATION_SM_OTHER
:
1208 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1210 case PORT_INFORMATION_SM_NOT_DESIGNATED_EXEC
:
1211 record_agreement(p
);
1213 p
->rcvd_msg
= false;
1214 p
->port_information_sm_state
= PORT_INFORMATION_SM_NOT_DESIGNATED
;
1216 case PORT_INFORMATION_SM_NOT_DESIGNATED
:
1217 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1219 case PORT_INFORMATION_SM_INFERIOR_DESIGNATED_EXEC
:
1221 p
->rcvd_msg
= false;
1222 p
->port_information_sm_state
= PORT_INFORMATION_SM_INFERIOR_DESIGNATED
;
1224 case PORT_INFORMATION_SM_INFERIOR_DESIGNATED
:
1225 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1227 case PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC
:
1230 updt_rcvd_info_while(p
);
1231 p
->rcvd_msg
= false;
1232 p
->port_information_sm_state
= PORT_INFORMATION_SM_REPEATED_DESIGNATED
;
1234 case PORT_INFORMATION_SM_REPEATED_DESIGNATED
:
1235 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1237 case PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC
:
1238 p
->agreed
= p
->proposing
= false;
1241 /* RECEIVED is not specified in Standard 802.1D-2004. */
1242 p
->agree
= p
->agree
&& better_or_same_info(p
, RECEIVED
);
1245 updt_rcvd_info_while(p
);
1246 p
->info_is
= INFO_IS_RECEIVED
;
1248 p
->selected
= false;
1249 p
->rcvd_msg
= false;
1250 p
->port_information_sm_state
= PORT_INFORMATION_SM_SUPERIOR_DESIGNATED
;
1252 case PORT_INFORMATION_SM_SUPERIOR_DESIGNATED
:
1253 p
->port_information_sm_state
= PORT_INFORMATION_SM_CURRENT_EXEC
;
1259 if (old_state
!= p
->port_information_sm_state
) {
1261 VLOG_DBG("%s, port %u: Port_information_sm %d -> %d", p
->rstp
->name
,
1262 p
->port_number
, old_state
, p
->port_information_sm_state
);
1267 /* [17.29 Port Role Transitions state machine] */
1270 set_re_root_tree(struct rstp_port
*p
)
1271 OVS_REQUIRES(rstp_mutex
)
1274 struct rstp_port
*p1
;
1277 HMAP_FOR_EACH (p1
, node
, &r
->ports
) {
1283 set_sync_tree(struct rstp_port
*p
)
1284 OVS_REQUIRES(rstp_mutex
)
1287 struct rstp_port
*p1
;
1290 HMAP_FOR_EACH (p1
, node
, &r
->ports
) {
1296 hello_time(struct rstp_port
*p
)
1297 OVS_REQUIRES(rstp_mutex
)
1299 return p
->designated_times
.hello_time
;
1303 fwd_delay(struct rstp_port
*p
)
1304 OVS_REQUIRES(rstp_mutex
)
1306 return p
->designated_times
.forward_delay
;
1310 forward_delay(struct rstp_port
*p
)
1311 OVS_REQUIRES(rstp_mutex
)
1314 return hello_time(p
);
1316 return fwd_delay(p
);
1321 edge_delay(struct rstp_port
*p
)
1322 OVS_REQUIRES(rstp_mutex
)
1327 if (p
->oper_point_to_point_mac
== 1) {
1328 return r
->migrate_time
;
1330 return p
->designated_times
.max_age
;
1335 check_selected_role_change(struct rstp_port
*p
, int current_role_state
)
1336 OVS_REQUIRES(rstp_mutex
)
1338 if (p
->selected
&& !p
->updt_info
&& p
->role
!= p
->selected_role
1339 && p
->selected_role
!= current_role_state
) {
1340 VLOG_DBG("%s, port %u: case: current = %s role = %s selected = %d",
1341 p
->rstp
->name
, p
->port_number
,
1342 rstp_port_role_name(current_role_state
),
1343 rstp_port_role_name(p
->role
), p
->selected_role
);
1344 switch (p
->selected_role
) {
1346 p
->port_role_transition_sm_state
=
1347 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1349 case ROLE_DESIGNATED
:
1350 p
->port_role_transition_sm_state
=
1351 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1353 case ROLE_ALTERNATE
:
1354 p
->port_role_transition_sm_state
=
1355 PORT_ROLE_TRANSITION_SM_BLOCK_PORT_EXEC
;
1358 p
->port_role_transition_sm_state
=
1359 PORT_ROLE_TRANSITION_SM_BLOCK_PORT_EXEC
;
1362 p
->port_role_transition_sm_state
=
1363 PORT_ROLE_TRANSITION_SM_DISABLE_PORT_EXEC
;
1371 re_rooted(struct rstp_port
*p
)
1372 OVS_REQUIRES(rstp_mutex
)
1375 struct rstp_port
*p1
;
1378 HMAP_FOR_EACH (p1
, node
, &r
->ports
) {
1379 if ((p1
!= p
) && (p1
->rr_while
!= 0)) {
1387 all_synced(struct rstp
*r
)
1388 OVS_REQUIRES(rstp_mutex
)
1390 struct rstp_port
*p
;
1392 HMAP_FOR_EACH (p
, node
, &r
->ports
) {
1393 if (!(p
->selected
&& p
->role
== p
->selected_role
&&
1394 (p
->role
== ROLE_ROOT
|| p
->synced
== true))) {
1402 port_role_transition_sm(struct rstp_port
*p
)
1403 OVS_REQUIRES(rstp_mutex
)
1405 enum port_role_transition_state_machine old_state
;
1407 enum rstp_port_role last_role
;
1409 old_state
= p
->port_role_transition_sm_state
;
1411 last_role
= p
->role
;
1413 switch (p
->port_role_transition_sm_state
) {
1414 case PORT_ROLE_TRANSITION_SM_INIT
:
1416 p
->port_role_transition_sm_state
=
1417 PORT_ROLE_TRANSITION_SM_INIT_PORT_EXEC
;
1420 case PORT_ROLE_TRANSITION_SM_INIT_PORT_EXEC
:
1421 p
->role
= ROLE_DISABLED
;
1422 p
->learn
= p
->forward
= false;
1424 p
->sync
= p
->re_root
= true;
1425 p
->rr_while
= p
->designated_times
.forward_delay
;
1426 p
->fd_while
= p
->designated_times
.max_age
;
1428 p
->port_role_transition_sm_state
=
1429 PORT_ROLE_TRANSITION_SM_DISABLE_PORT_EXEC
;
1431 case PORT_ROLE_TRANSITION_SM_DISABLE_PORT_EXEC
:
1432 p
->role
= p
->selected_role
;
1433 p
->learn
= p
->forward
= false;
1434 p
->port_role_transition_sm_state
=
1435 PORT_ROLE_TRANSITION_SM_DISABLE_PORT
;
1437 case PORT_ROLE_TRANSITION_SM_DISABLE_PORT
:
1438 if (check_selected_role_change(p
, ROLE_DISABLED
)) {
1440 } else if (p
->selected
&& !p
->updt_info
&& !p
->learning
1441 && !p
->forwarding
) {
1442 p
->port_role_transition_sm_state
=
1443 PORT_ROLE_TRANSITION_SM_DISABLED_PORT_EXEC
;
1446 case PORT_ROLE_TRANSITION_SM_DISABLED_PORT_EXEC
:
1447 p
->fd_while
= p
->designated_times
.max_age
;
1450 p
->sync
= p
->re_root
= false;
1451 p
->port_role_transition_sm_state
=
1452 PORT_ROLE_TRANSITION_SM_DISABLED_PORT
;
1454 case PORT_ROLE_TRANSITION_SM_DISABLED_PORT
:
1455 if (check_selected_role_change(p
, ROLE_DISABLED
)) {
1457 } else if (p
->selected
&& !p
->updt_info
1458 && (p
->fd_while
!= p
->designated_times
.max_age
|| p
->sync
1459 || p
->re_root
|| !p
->synced
)) {
1460 p
->port_role_transition_sm_state
=
1461 PORT_ROLE_TRANSITION_SM_DISABLED_PORT_EXEC
;
1464 case PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
:
1465 p
->role
= ROLE_ROOT
;
1466 p
->rr_while
= p
->designated_times
.forward_delay
;
1467 p
->port_role_transition_sm_state
= PORT_ROLE_TRANSITION_SM_ROOT_PORT
;
1469 case PORT_ROLE_TRANSITION_SM_ROOT_PORT
:
1470 if (check_selected_role_change(p
, ROLE_ROOT
)) {
1472 } else if (p
->selected
&& !p
->updt_info
) {
1473 if (p
->rr_while
!= p
->designated_times
.forward_delay
) {
1474 p
->port_role_transition_sm_state
=
1475 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1477 } else if (p
->re_root
&& p
->forward
) {
1478 p
->port_role_transition_sm_state
=
1479 PORT_ROLE_TRANSITION_SM_REROOTED_EXEC
;
1481 } else if ((p
->fd_while
== 0
1482 || ((re_rooted(p
) && p
->rb_while
== 0)
1483 && r
->rstp_version
)) && !p
->learn
) {
1484 p
->port_role_transition_sm_state
=
1485 PORT_ROLE_TRANSITION_SM_ROOT_LEARN_EXEC
;
1487 } else if ((p
->fd_while
== 0
1488 || ((re_rooted(p
) && p
->rb_while
== 0)
1489 && r
->rstp_version
)) && p
->learn
&& !p
->forward
) {
1490 p
->port_role_transition_sm_state
=
1491 PORT_ROLE_TRANSITION_SM_ROOT_FORWARD_EXEC
;
1493 } else if (p
->proposed
&& !p
->agree
) {
1494 p
->port_role_transition_sm_state
=
1495 PORT_ROLE_TRANSITION_SM_ROOT_PROPOSED_EXEC
;
1497 } else if ((all_synced(r
) && !p
->agree
) ||
1498 (p
->proposed
&& p
->agree
)) {
1499 p
->port_role_transition_sm_state
=
1500 PORT_ROLE_TRANSITION_SM_ROOT_AGREED_EXEC
;
1502 } else if (!p
->forward
&& !p
->re_root
) {
1503 p
->port_role_transition_sm_state
=
1504 PORT_ROLE_TRANSITION_SM_REROOT_EXEC
;
1509 case PORT_ROLE_TRANSITION_SM_REROOT_EXEC
:
1510 set_re_root_tree(p
);
1511 p
->port_role_transition_sm_state
=
1512 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1514 case PORT_ROLE_TRANSITION_SM_ROOT_AGREED_EXEC
:
1515 p
->proposed
= p
->sync
= false;
1516 p
->agree
= p
->new_info
= true;
1517 p
->port_role_transition_sm_state
=
1518 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1520 case PORT_ROLE_TRANSITION_SM_ROOT_PROPOSED_EXEC
:
1522 p
->proposed
= false;
1523 p
->port_role_transition_sm_state
=
1524 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1526 case PORT_ROLE_TRANSITION_SM_ROOT_FORWARD_EXEC
:
1529 p
->port_role_transition_sm_state
=
1530 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1532 case PORT_ROLE_TRANSITION_SM_ROOT_LEARN_EXEC
:
1533 p
->fd_while
= forward_delay(p
);
1535 p
->port_role_transition_sm_state
=
1536 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1538 case PORT_ROLE_TRANSITION_SM_REROOTED_EXEC
:
1540 p
->port_role_transition_sm_state
=
1541 PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC
;
1543 case PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
:
1544 p
->role
= ROLE_DESIGNATED
;
1545 p
->port_role_transition_sm_state
=
1546 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT
;
1548 case PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT
:
1549 if (check_selected_role_change(p
, ROLE_DESIGNATED
)) {
1551 } else if (p
->selected
&& !p
->updt_info
) {
1552 if (((p
->sync
&& !p
->synced
)
1553 || (p
->re_root
&& p
->rr_while
!= 0) || p
->disputed
)
1554 && !p
->oper_edge
&& (p
->learn
|| p
->forward
)) {
1555 p
->port_role_transition_sm_state
=
1556 PORT_ROLE_TRANSITION_SM_DESIGNATED_DISCARD_EXEC
;
1557 } else if ((p
->fd_while
== 0 || p
->agreed
|| p
->oper_edge
)
1558 && (p
->rr_while
== 0 || !p
->re_root
)
1559 && !p
->sync
&& !p
->learn
) {
1560 p
->port_role_transition_sm_state
=
1561 PORT_ROLE_TRANSITION_SM_DESIGNATED_LEARN_EXEC
;
1562 } else if ((p
->fd_while
== 0 || p
->agreed
|| p
->oper_edge
)
1563 && (p
->rr_while
== 0 || !p
->re_root
)
1564 && !p
->sync
&& (p
->learn
&& !p
->forward
)) {
1565 p
->port_role_transition_sm_state
=
1566 PORT_ROLE_TRANSITION_SM_DESIGNATED_FORWARD_EXEC
;
1567 } else if (!p
->forward
&& !p
->agreed
&& !p
->proposing
&&
1569 p
->port_role_transition_sm_state
=
1570 PORT_ROLE_TRANSITION_SM_DESIGNATED_PROPOSE_EXEC
;
1571 } else if ((!p
->learning
&& !p
->forwarding
&& !p
->synced
)
1572 || (p
->agreed
&& !p
->synced
)
1573 || (p
->oper_edge
&& !p
->synced
)
1574 || (p
->sync
&& p
->synced
)) {
1575 p
->port_role_transition_sm_state
=
1576 PORT_ROLE_TRANSITION_SM_DESIGNATED_SYNCED_EXEC
;
1577 } else if (p
->rr_while
== 0 && p
->re_root
) {
1578 p
->port_role_transition_sm_state
=
1579 PORT_ROLE_TRANSITION_SM_DESIGNATED_RETIRED_EXEC
;
1583 case PORT_ROLE_TRANSITION_SM_DESIGNATED_RETIRED_EXEC
:
1585 p
->port_role_transition_sm_state
=
1586 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1588 case PORT_ROLE_TRANSITION_SM_DESIGNATED_SYNCED_EXEC
:
1592 p
->port_role_transition_sm_state
=
1593 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1595 case PORT_ROLE_TRANSITION_SM_DESIGNATED_PROPOSE_EXEC
:
1596 p
->proposing
= true;
1597 p
->edge_delay_while
= edge_delay(p
);
1599 p
->port_role_transition_sm_state
=
1600 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1602 case PORT_ROLE_TRANSITION_SM_DESIGNATED_FORWARD_EXEC
:
1605 p
->agreed
= p
->send_rstp
;
1606 p
->port_role_transition_sm_state
=
1607 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1609 case PORT_ROLE_TRANSITION_SM_DESIGNATED_LEARN_EXEC
:
1611 p
->fd_while
= forward_delay(p
);
1612 p
->port_role_transition_sm_state
=
1613 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1615 case PORT_ROLE_TRANSITION_SM_DESIGNATED_DISCARD_EXEC
:
1616 p
->learn
= p
->forward
= p
->disputed
= false;
1617 p
->fd_while
= forward_delay(p
);
1618 p
->port_role_transition_sm_state
=
1619 PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC
;
1621 case PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
:
1622 p
->fd_while
= p
->designated_times
.forward_delay
;
1625 p
->sync
= p
->re_root
= false;
1626 p
->port_role_transition_sm_state
=
1627 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT
;
1629 case PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT
:
1630 if (check_selected_role_change(p
, ROLE_ALTERNATE
)) {
1632 } else if (p
->selected
&& !p
->updt_info
) {
1633 if (p
->rb_while
!= 2 * p
->designated_times
.hello_time
1634 && p
->role
== ROLE_BACKUP
) {
1635 p
->port_role_transition_sm_state
=
1636 PORT_ROLE_TRANSITION_SM_BACKUP_PORT_EXEC
;
1637 } else if ((p
->fd_while
!= forward_delay(p
)) || p
->sync
1638 || p
->re_root
|| !p
->synced
) {
1639 p
->port_role_transition_sm_state
=
1640 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
;
1641 } else if (p
->proposed
&& !p
->agree
) {
1642 p
->port_role_transition_sm_state
=
1643 PORT_ROLE_TRANSITION_SM_ALTERNATE_PROPOSED_EXEC
;
1644 } else if ((all_synced(r
) && !p
->agree
)
1645 || (p
->proposed
&& p
->agree
)) {
1646 p
->port_role_transition_sm_state
=
1647 PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED
;
1651 case PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED
:
1652 p
->proposed
= false;
1655 p
->port_role_transition_sm_state
=
1656 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
;
1658 case PORT_ROLE_TRANSITION_SM_ALTERNATE_PROPOSED_EXEC
:
1660 p
->proposed
= false;
1661 p
->port_role_transition_sm_state
=
1662 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
;
1664 case PORT_ROLE_TRANSITION_SM_BLOCK_PORT_EXEC
:
1665 p
->role
= p
->selected_role
;
1666 p
->learn
= p
->forward
= false;
1667 p
->port_role_transition_sm_state
= PORT_ROLE_TRANSITION_SM_BLOCK_PORT
;
1669 case PORT_ROLE_TRANSITION_SM_BLOCK_PORT
:
1670 if (check_selected_role_change(p
, ROLE_ALTERNATE
)) {
1672 } else if (p
->selected
&& !p
->updt_info
&& !p
->learning
&&
1674 p
->port_role_transition_sm_state
=
1675 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
;
1678 case PORT_ROLE_TRANSITION_SM_BACKUP_PORT_EXEC
:
1679 p
->rb_while
= 2 * p
->designated_times
.hello_time
;
1680 p
->port_role_transition_sm_state
=
1681 PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC
;
1687 if (old_state
!= p
->port_role_transition_sm_state
) {
1689 VLOG_DBG("%s, port %u: Port_role_transition_sm %d -> %d",
1690 p
->rstp
->name
, p
->port_number
, old_state
,
1691 p
->port_role_transition_sm_state
);
1693 if (last_role
!= p
->role
) {
1694 last_role
= p
->role
;
1695 VLOG_DBG("%s, port %u, port role ["RSTP_PORT_ID_FMT
"] = %s",
1696 p
->rstp
->name
, p
->port_number
, p
->port_id
,
1697 rstp_port_role_name(p
->role
));
1702 /* [17.30 - Port state transition state machine] */
1705 enable_learning(struct rstp_port
*p
)
1706 OVS_REQUIRES(rstp_mutex
)
1708 /* [17.21.6 enableLearning()] An implementation dependent procedure that
1709 * causes the Learning Process (7.8) to start learning from frames received
1710 * on the Port. The procedure does not complete until learning has been
1713 rstp_port_set_state__(p
, RSTP_LEARNING
);
1717 enable_forwarding(struct rstp_port
*p
)
1718 OVS_REQUIRES(rstp_mutex
)
1720 /* [17.21.5 enableForwarding()] An implementation dependent procedure that
1721 * causes the Forwarding Process (7.7) to start forwarding frames through
1722 * the Port. The procedure does not complete until forwarding has been
1725 rstp_port_set_state__(p
, RSTP_FORWARDING
);
1729 disable_learning(struct rstp_port
*p
)
1730 OVS_REQUIRES(rstp_mutex
)
1732 /* [17.21.4 - disableLearning()] An implementation dependent procedure that
1733 * causes the Learning Process (7.8) to stop learning from the source
1734 * address of frames received on the Port. The procedure does not complete
1735 * until learning has stopped.
1737 rstp_port_set_state__(p
, RSTP_DISCARDING
);
1741 disable_forwarding(struct rstp_port
*p
)
1742 OVS_REQUIRES(rstp_mutex
)
1744 /* [17.21.3 - disableForwarding()] An implementation dependent procedure
1745 * that causes the Forwarding Process (7.7) to stop forwarding frames
1746 * through the Port. The procedure does not complete until forwarding has
1749 rstp_port_set_state__(p
, RSTP_DISCARDING
);
1753 port_state_transition_sm(struct rstp_port
*p
)
1754 OVS_REQUIRES(rstp_mutex
)
1756 enum port_state_transition_state_machine old_state
;
1759 old_state
= p
->port_state_transition_sm_state
;
1762 switch (p
->port_state_transition_sm_state
) {
1763 case PORT_STATE_TRANSITION_SM_INIT
:
1765 p
->port_state_transition_sm_state
=
1766 PORT_STATE_TRANSITION_SM_DISCARDING_EXEC
;
1769 case PORT_STATE_TRANSITION_SM_DISCARDING_EXEC
:
1770 disable_learning(p
);
1771 p
->learning
= false;
1772 disable_forwarding(p
);
1773 p
->forwarding
= false;
1774 p
->port_state_transition_sm_state
=
1775 PORT_STATE_TRANSITION_SM_DISCARDING
;
1777 case PORT_STATE_TRANSITION_SM_DISCARDING
:
1779 p
->port_state_transition_sm_state
=
1780 PORT_STATE_TRANSITION_SM_LEARNING_EXEC
;
1783 case PORT_STATE_TRANSITION_SM_LEARNING_EXEC
:
1786 p
->port_state_transition_sm_state
= PORT_STATE_TRANSITION_SM_LEARNING
;
1788 case PORT_STATE_TRANSITION_SM_LEARNING
:
1790 p
->port_state_transition_sm_state
=
1791 PORT_STATE_TRANSITION_SM_DISCARDING_EXEC
;
1792 } else if (p
->forward
) {
1793 p
->port_state_transition_sm_state
=
1794 PORT_STATE_TRANSITION_SM_FORWARDING_EXEC
;
1797 case PORT_STATE_TRANSITION_SM_FORWARDING_EXEC
:
1798 enable_forwarding(p
);
1799 p
->forwarding
= true;
1800 p
->port_state_transition_sm_state
=
1801 PORT_STATE_TRANSITION_SM_FORWARDING
;
1803 case PORT_STATE_TRANSITION_SM_FORWARDING
:
1805 p
->port_state_transition_sm_state
=
1806 PORT_STATE_TRANSITION_SM_DISCARDING_EXEC
;
1813 if (old_state
!= p
->port_state_transition_sm_state
) {
1815 VLOG_DBG("%s, port %u: Port_state_transition_sm %d -> %d",
1816 p
->rstp
->name
, p
->port_number
, old_state
,
1817 p
->port_state_transition_sm_state
);
1822 /* [17.31 - Topology Change state machine] */
1825 new_tc_while(struct rstp_port
*p
)
1826 OVS_REQUIRES(rstp_mutex
)
1831 if (p
->tc_while
== 0 && p
->send_rstp
== true) {
1832 p
->tc_while
= r
->bridge_hello_time
+ 1;
1834 } else if (p
->tc_while
== 0 && p
->send_rstp
== false) {
1835 p
->tc_while
= r
->bridge_max_age
+ r
->bridge_forward_delay
;
1839 /* [17.21.18 setTcPropTree()]
1840 * Sets tcprop for all Ports except the Port that called the procedure.
1843 set_tc_prop_tree(struct rstp_port
*p
)
1844 OVS_REQUIRES(rstp_mutex
)
1847 struct rstp_port
*p1
;
1850 HMAP_FOR_EACH (p1
, node
, &r
->ports
) {
1851 /* Set tc_prop on every port, except the one calling this
1853 if (p1
->port_number
!= p
->port_number
) {
1860 set_tc_prop_bridge(struct rstp_port
*p
) /* not specified in 802.1D-2004. */
1861 OVS_REQUIRES(rstp_mutex
)
1863 set_tc_prop_tree(p
); /* see 802.1w-2001. */
1867 topology_change_sm(struct rstp_port
*p
)
1868 OVS_REQUIRES(rstp_mutex
)
1870 enum topology_change_state_machine old_state
;
1873 old_state
= p
->topology_change_sm_state
;
1876 switch (p
->topology_change_sm_state
) {
1877 case TOPOLOGY_CHANGE_SM_INIT
:
1879 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_INACTIVE_EXEC
;
1882 case TOPOLOGY_CHANGE_SM_INACTIVE_EXEC
:
1883 p
->fdb_flush
= true;
1886 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_INACTIVE
;
1888 case TOPOLOGY_CHANGE_SM_INACTIVE
:
1889 if (p
->learn
&& !p
->fdb_flush
) {
1890 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_LEARNING_EXEC
;
1893 case TOPOLOGY_CHANGE_SM_LEARNING_EXEC
:
1894 p
->rcvd_tc
= p
->rcvd_tcn
= p
->rcvd_tc_ack
= false;
1895 p
->tc_prop
= p
->rcvd_tc_ack
= false;
1896 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_LEARNING
;
1898 case TOPOLOGY_CHANGE_SM_LEARNING
:
1899 if (p
->role
!= ROLE_ROOT
&& p
->role
!= ROLE_DESIGNATED
&&
1900 !(p
->learn
|| p
->learning
) && !(p
->rcvd_tc
|| p
->rcvd_tcn
||
1901 p
->rcvd_tc_ack
|| p
->tc_prop
)) {
1902 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_INACTIVE_EXEC
;
1903 } else if (p
->rcvd_tc
|| p
->rcvd_tcn
|| p
->rcvd_tc_ack
|| p
->tc_prop
) {
1904 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_LEARNING_EXEC
;
1905 } else if ((p
->role
== ROLE_ROOT
|| p
->role
== ROLE_DESIGNATED
)
1906 && p
->forward
&& !p
->oper_edge
) {
1907 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_DETECTED_EXEC
;
1910 case TOPOLOGY_CHANGE_SM_DETECTED_EXEC
:
1912 set_tc_prop_tree(p
);
1914 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACTIVE_EXEC
;
1916 case TOPOLOGY_CHANGE_SM_ACTIVE_EXEC
:
1917 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACTIVE
;
1919 case TOPOLOGY_CHANGE_SM_ACTIVE
:
1920 if ((p
->role
!= ROLE_ROOT
&& p
->role
!= ROLE_DESIGNATED
)
1922 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_LEARNING_EXEC
;
1923 } else if (p
->rcvd_tcn
) {
1924 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_NOTIFIED_TCN_EXEC
;
1925 } else if (p
->rcvd_tc
) {
1926 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_NOTIFIED_TC_EXEC
;
1927 } else if (p
->tc_prop
&& !p
->oper_edge
) {
1928 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_PROPAGATING_EXEC
;
1929 } else if (p
->rcvd_tc_ack
) {
1930 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACKNOWLEDGED_EXEC
;
1933 case TOPOLOGY_CHANGE_SM_ACKNOWLEDGED_EXEC
:
1935 p
->rcvd_tc_ack
= false;
1936 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACTIVE
;
1938 case TOPOLOGY_CHANGE_SM_PROPAGATING_EXEC
:
1940 p
->fdb_flush
= true;
1942 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACTIVE
;
1944 case TOPOLOGY_CHANGE_SM_NOTIFIED_TC_EXEC
:
1945 p
->rcvd_tcn
= p
->rcvd_tc
= false;
1946 if (p
->role
== ROLE_DESIGNATED
) {
1949 set_tc_prop_bridge(p
);
1950 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_ACTIVE
;
1952 case TOPOLOGY_CHANGE_SM_NOTIFIED_TCN_EXEC
:
1954 p
->topology_change_sm_state
= TOPOLOGY_CHANGE_SM_NOTIFIED_TC_EXEC
;
1960 if (old_state
!= p
->topology_change_sm_state
) {
1962 VLOG_DBG("%s, port %u: Topology_change_sm %d -> %d", p
->rstp
->name
,
1963 p
->port_number
, old_state
, p
->topology_change_sm_state
);
1968 /****************************************************************************
1969 * [17.6] Priority vector calculation helper functions
1970 ****************************************************************************/
1972 /* compare_rstp_priority_vectors() compares two struct rstp_priority_vectors
1973 * and returns a value indicating if the first rstp_priority_vector is
1974 * superior, same or inferior to the second one.
1976 * Zero return value indicates INFERIOR, a non-zero return value indicates
1977 * SUPERIOR. When it makes a difference the non-zero return value SAME
1978 * indicates the priority vectors are identical (a subset of SUPERIOR).
1980 static enum vector_comparison
1981 compare_rstp_priority_vectors(const struct rstp_priority_vector
*v1
,
1982 const struct rstp_priority_vector
*v2
)
1984 VLOG_DBG("v1: "RSTP_ID_FMT
", %u, "RSTP_ID_FMT
", %d, %d",
1985 RSTP_ID_ARGS(v1
->root_bridge_id
), v1
->root_path_cost
,
1986 RSTP_ID_ARGS(v1
->designated_bridge_id
), v1
->designated_port_id
,
1987 v1
->bridge_port_id
);
1988 VLOG_DBG("v2: "RSTP_ID_FMT
", %u, "RSTP_ID_FMT
", %d, %d",
1989 RSTP_ID_ARGS(v2
->root_bridge_id
), v2
->root_path_cost
,
1990 RSTP_ID_ARGS(v2
->designated_bridge_id
), v2
->designated_port_id
,
1991 v2
->bridge_port_id
);
1994 * This message priority vector is superior to the port priority vector and
1995 * will replace it if, and only if, the message priority vector is better
1996 * than the port priority vector, or the message has been transmitted from
1997 * the same Designated Bridge and Designated Port as the port priority
1998 * vector, i.e., if the following is true:
2000 * ((RD < RootBridgeID)) ||
2001 * ((RD == RootBridgeID) && (RPCD < RootPathCost)) ||
2002 * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
2003 * (D < designated_bridge_id)) ||
2004 * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
2005 * (D == designated_bridge_id) && (PD < designated_port_id)) ||
2006 * ((D == designated_bridge_id.BridgeAddress) &&
2007 * (PD == designated_port_id.PortNumber))
2009 if ((v1
->root_bridge_id
< v2
->root_bridge_id
)
2010 || (v1
->root_bridge_id
== v2
->root_bridge_id
2011 && v1
->root_path_cost
< v2
->root_path_cost
)
2012 || (v1
->root_bridge_id
== v2
->root_bridge_id
2013 && v1
->root_path_cost
== v2
->root_path_cost
2014 && v1
->designated_bridge_id
< v2
->designated_bridge_id
)
2015 || (v1
->root_bridge_id
== v2
->root_bridge_id
2016 && v1
->root_path_cost
== v2
->root_path_cost
2017 && v1
->designated_bridge_id
== v2
->designated_bridge_id
2018 && v1
->designated_port_id
< v2
->designated_port_id
)
2019 || (v1
->designated_bridge_id
== v2
->designated_bridge_id
2020 && v1
->designated_port_id
== v2
->designated_port_id
)) {
2021 /* SAME is a subset of SUPERIOR. */
2022 if (v1
->root_bridge_id
== v2
->root_bridge_id
2023 && v1
->root_path_cost
== v2
->root_path_cost
2024 && v1
->designated_bridge_id
== v2
->designated_bridge_id
2025 && v1
->designated_port_id
== v2
->designated_port_id
) {
2026 if (v1
->bridge_port_id
< v2
->bridge_port_id
) {
2027 VLOG_DBG("superior");
2030 else if (v1
->bridge_port_id
> v2
->bridge_port_id
) {
2031 VLOG_DBG("inferior");
2034 VLOG_DBG("superior_same");
2037 VLOG_DBG("superior");
2041 VLOG_DBG("inferior");
2046 rstp_times_equal(struct rstp_times
*t1
, struct rstp_times
*t2
)
2048 return t1
->forward_delay
== t2
->forward_delay
2049 && t1
->hello_time
== t2
->hello_time
2050 && t1
->max_age
== t2
->max_age
2051 && t1
->message_age
== t2
->message_age
;