/*
- * Copyright (c) 2011-2014 M3S, Srl - Italy
+ * Copyright (c) 2011-2015 M3S, Srl - Italy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* Authors:
* Martino Fornasa <mf@fornasa.it>
* Daniele Venturino <daniele.venturino@m3s.it>
+ * Carlo Andreotti <c.andreotti@m3s.it>
*
* References to IEEE 802.1D-2004 standard are enclosed in square brackets.
* E.g. [17.3], [Table 17-1], etc.
#include <config.h>
#include "rstp.h"
#include "rstp-state-machines.h"
+#include <sys/types.h>
+#include <netinet/in.h>
#include <arpa/inet.h>
#include <inttypes.h>
-#include <netinet/in.h>
#include <stdlib.h>
-#include <sys/types.h>
#include "byte-order.h"
#include "connectivity.h"
-#include "ofpbuf.h"
+#include "openvswitch/ofpbuf.h"
+#include "dp-packet.h"
#include "packets.h"
#include "seq.h"
#include "unixctl.h"
#include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(rstp_sm);
struct rstp_port *p;
int vsel;
struct rstp_priority_vector best_vector, candidate_vector;
+ enum rstp_port_role new_root_old_role = ROLE_DESIGNATED;
+ uint16_t old_root_port_number = 0;
+ uint16_t new_root_port_number = 0;
+ old_root_port_number = r->root_port_id & 0x00ff;
+ if (old_root_port_number) {
+ r->old_root_aux = rstp_get_port_aux__(r, old_root_port_number);
+ }
vsel = -1;
best_vector = r->bridge_priority;
/* Letter c1) */
r->root_times = p->port_times;
r->root_times.message_age++;
vsel = p->port_number;
+ new_root_old_role = p->role;
}
}
r->root_priority = best_vector;
r->root_port_id = best_vector.bridge_port_id;
VLOG_DBG("%s: new Root is "RSTP_ID_FMT, r->name,
RSTP_ID_ARGS(r->root_priority.root_bridge_id));
+ new_root_port_number = r->root_port_id & 0x00ff;
+ if (new_root_port_number) {
+ r->new_root_aux = rstp_get_port_aux__(r, new_root_port_number);
+ }
+ /* Shift learned MAC addresses from an old Root Port to an existing
+ * Alternate Port. */
+ if (!r->root_changed
+ && new_root_old_role == ROLE_ALTERNATE
+ && new_root_port_number
+ && old_root_port_number
+ && new_root_port_number != old_root_port_number) {
+ r->root_changed = true;
+ }
/* Letters d) e) */
HMAP_FOR_EACH (p, node, &r->ports) {
p->designated_priority_vector.root_bridge_id =
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
}
seq_change(connectivity_seq_get());
case PORT_ROLE_SELECTION_SM_INIT_BRIDGE_EXEC:
updt_role_disabled_tree(r);
r->port_role_selection_sm_state = PORT_ROLE_SELECTION_SM_INIT_BRIDGE;
- /* no break */
+ /* fall through */
case PORT_ROLE_SELECTION_SM_INIT_BRIDGE:
r->port_role_selection_sm_state =
PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC;
set_selected_tree(r);
r->port_role_selection_sm_state =
PORT_ROLE_SELECTION_SM_ROLE_SELECTION;
- /* no break */
+ /* fall through */
case PORT_ROLE_SELECTION_SM_ROLE_SELECTION:
HMAP_FOR_EACH (p, node, &r->ports) {
if (p->reselect) {
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != r->port_role_selection_sm_state) {
r->changes = true;
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
}
p->rcvd_msg = false;
p->edge_delay_while = r->migrate_time;
p->port_receive_sm_state = PORT_RECEIVE_SM_DISCARD;
- /* no break */
+ /* fall through */
case PORT_RECEIVE_SM_DISCARD:
- if (p->rcvd_bpdu && p->port_enabled) {
+ if ((p->rcvd_bpdu || (p->edge_delay_while != r->migrate_time))
+ && !p->port_enabled) {
+ /* Global transition. */
+ p->port_receive_sm_state = PORT_RECEIVE_SM_DISCARD_EXEC;
+ } else if (p->rcvd_bpdu && p->port_enabled) {
p->port_receive_sm_state = PORT_RECEIVE_SM_RECEIVE_EXEC;
}
break;
p->rcvd_msg = true;
p->edge_delay_while = r->migrate_time;
p->port_receive_sm_state = PORT_RECEIVE_SM_RECEIVE;
- /* no break */
+ /* fall through */
case PORT_RECEIVE_SM_RECEIVE:
- if (p->rcvd_bpdu && p->port_enabled && !p->rcvd_msg) {
+ if ((p->rcvd_bpdu || (p->edge_delay_while != r->migrate_time))
+ && !p->port_enabled) {
+ /* Global transition. */
+ p->port_receive_sm_state = PORT_RECEIVE_SM_DISCARD_EXEC;
+ } else if (p->rcvd_bpdu && p->port_enabled && !p->rcvd_msg) {
p->port_receive_sm_state = PORT_RECEIVE_SM_RECEIVE_EXEC;
}
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_receive_sm_state) {
r->changes = true;
case PORT_PROTOCOL_MIGRATION_SM_INIT:
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC;
- /* no break */
+ /* fall through */
case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC:
p->mcheck = false;
p->send_rstp = r->rstp_version;
p->mdelay_while = r->migrate_time;
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP;
- /* no break */
+ /* fall through */
case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP:
if (p->mdelay_while == 0) {
p->port_protocol_migration_sm_state =
p->mdelay_while = r->migrate_time;
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP;
- /* no break */
+ /* fall through */
case PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP:
if ((p->mdelay_while == 0) || (!p->port_enabled) || p->mcheck) {
p->port_protocol_migration_sm_state =
p->rcvd_stp = false;
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_SENSING;
- /* no break */
+ /* fall through */
case PORT_PROTOCOL_MIGRATION_SM_SENSING:
if (!p->port_enabled || p->mcheck || ((r->rstp_version) &&
!p->send_rstp && p->rcvd_rstp)) {
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_protocol_migration_sm_state) {
r->changes = true;
case BRIDGE_DETECTION_SM_EDGE_EXEC:
p->oper_edge = true;
p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_EDGE;
- /* no break */
+ /* fall through */
case BRIDGE_DETECTION_SM_EDGE:
if ((!p->port_enabled && !p->admin_edge) || !p->oper_edge) {
p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_NOT_EDGE_EXEC;
case BRIDGE_DETECTION_SM_NOT_EDGE_EXEC:
p->oper_edge = false;
p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_NOT_EDGE;
- /* no break */
+ /* fall through */
case BRIDGE_DETECTION_SM_NOT_EDGE:
if ((!p->port_enabled && p->admin_edge)
|| ((p->edge_delay_while == 0) && p->auto_edge && p->send_rstp
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->bridge_detection_sm_state) {
r->changes = true;
{
struct eth_header *eth;
struct llc_header *llc;
- struct ofpbuf *pkt;
+ struct dp_packet *pkt;
/* Skeleton. */
- pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
- eth = ofpbuf_put_zeros(pkt, sizeof *eth);
- llc = ofpbuf_put_zeros(pkt, sizeof *llc);
- ofpbuf_set_frame(pkt, eth);
- ofpbuf_set_l3(pkt, ofpbuf_put(pkt, bpdu, bpdu_size));
+ pkt = dp_packet_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
+ eth = dp_packet_put_zeros(pkt, sizeof *eth);
+ llc = dp_packet_put_zeros(pkt, sizeof *llc);
+ dp_packet_reset_offsets(pkt);
+ dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size));
/* 802.2 header. */
- memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
+ eth->eth_dst = eth_addr_stp;
/* p->rstp->send_bpdu() must fill in source address. */
- eth->eth_type = htons(ofpbuf_size(pkt) - ETH_HEADER_LEN);
+ eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN);
/* LLC header. */
llc->llc_dsap = STP_LLC_DSAP;
OVS_REQUIRES(rstp_mutex)
{
if ((p->received_bpdu_buffer.flags & BPDU_FLAG_LEARNING) != 0) {
- p->agreed = true;
- p->proposing = false;
+ /* 802.1D-2004 says to set the agreed flag and to clear the proposing
+ * flag. 802.1q-2008 instead says to set the disputed variable and to
+ * clear the agreed variable. */
+ p->disputed = true;
+ p->agreed = false;
}
}
{
struct rstp_bpdu bpdu;
+ memset(&bpdu, 0, sizeof bpdu);
bpdu.protocol_identifier = htons(0);
bpdu.protocol_version_identifier = 0;
bpdu.bpdu_type = CONFIGURATION_BPDU;
{
struct rstp_bpdu bpdu;
+ memset(&bpdu, 0, sizeof bpdu);
bpdu.protocol_identifier = htons(0);
bpdu.protocol_version_identifier = 2;
bpdu.bpdu_type = RAPID_SPANNING_TREE_BPDU;
p->new_info = true;
p->tx_count = 0;
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_INIT;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_TRANSMIT_INIT:
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE_EXEC;
break;
p->new_info = p->new_info || (p->role == ROLE_DESIGNATED ||
(p->role == ROLE_ROOT && p->tc_while != 0));
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_PERIODIC;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_TRANSMIT_PERIODIC:
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE_EXEC;
break;
case PORT_TRANSMIT_SM_IDLE_EXEC:
p->hello_when = r->bridge_hello_time;
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_IDLE:
if (p->role == ROLE_DISABLED) {
VLOG_DBG("%s, port %u: port_transmit_sm ROLE == DISABLED.",
p->tx_count += 1;
p->tc_ack = false;
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_CONFIG;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_TRANSMIT_CONFIG:
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE_EXEC;
break;
tx_tcn(p);
p->tx_count += 1;
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_TCN;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_TRANSMIT_TCN:
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE_EXEC;
break;
p->tx_count += 1;
p->tc_ack = false;
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_RSTP;
- /* no break */
+ /* fall through */
case PORT_TRANSMIT_SM_TRANSMIT_RSTP:
p->port_transmit_sm_state = PORT_TRANSMIT_SM_IDLE_EXEC;
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_transmit_sm_state) {
r->changes = true;
cp = compare_rstp_priority_vectors(&p->msg_priority, &p->port_priority);
ct = rstp_times_equal(&p->port_times, &p->msg_times);
- role =
- (p->received_bpdu_buffer.flags & ROLE_FLAG_MASK) >> ROLE_FLAG_SHIFT;
+ /* Configuration BPDU conveys a Designated Port Role. */
+ if (p->received_bpdu_buffer.bpdu_type == CONFIGURATION_BPDU) {
+ role = PORT_DES;
+ } else {
+ role =
+ (p->received_bpdu_buffer.flags & ROLE_FLAG_MASK) >> ROLE_FLAG_SHIFT;
+ }
+
+ /* 802.1D-2004 does not report this behaviour.
+ * 802.1Q-2008 says set rcvdTcn. */
+ if (p->received_bpdu_buffer.bpdu_type ==
+ TOPOLOGY_CHANGE_NOTIFICATION_BPDU) {
+ p->rcvd_tcn = true;
+ return OTHER_INFO;
+ }
/* Returns SuperiorDesignatedInfo if:
* a) The received message conveys a Designated Port Role, and
* 17.19.22).
* NOTE: Configuration BPDU explicitly conveys a Designated Port Role.
*/
- if ((role == PORT_DES
- || p->received_bpdu_buffer.bpdu_type == CONFIGURATION_BPDU)
- && (cp == SUPERIOR || (cp == SAME && ct == false))) {
+ if (role == PORT_DES && (cp == SUPERIOR || (cp == SAME && ct == false))) {
return SUPERIOR_DESIGNATED_INFO;
/* Returns RepeatedDesignatedInfo if:
{
enum port_information_state_machine old_state;
struct rstp *r;
+ struct rstp_port *p1;
old_state = p->port_information_sm_state;
r = p->rstp;
- if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
- p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
- }
switch (p->port_information_sm_state) {
case PORT_INFORMATION_SM_INIT:
- if (r->begin) {
+ if (r->begin
+ || (!p->port_enabled && p->info_is != INFO_IS_DISABLED)) {
p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
}
break;
p->reselect = true;
p->selected = false;
p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_DISABLED:
- if (p->port_enabled) {
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else if (p->port_enabled) {
p->port_information_sm_state = PORT_INFORMATION_SM_AGED_EXEC;
} else if (p->rcvd_msg) {
p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
p->reselect = true;
p->selected = false;
p->port_information_sm_state = PORT_INFORMATION_SM_AGED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_AGED:
- if (p->selected && p->updt_info) {
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else if (p->selected && p->updt_info) {
p->port_information_sm_state = PORT_INFORMATION_SM_UPDATE_EXEC;
}
break;
p->info_is = INFO_IS_MINE;
p->new_info = true;
p->port_information_sm_state = PORT_INFORMATION_SM_UPDATE;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_UPDATE:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
case PORT_INFORMATION_SM_CURRENT_EXEC:
p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_CURRENT:
- if (p->rcvd_msg && !p->updt_info) {
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else if (p->rcvd_msg && !p->updt_info) {
p->port_information_sm_state = PORT_INFORMATION_SM_RECEIVE_EXEC;
} else if (p->selected && p->updt_info) {
p->port_information_sm_state = PORT_INFORMATION_SM_UPDATE_EXEC;
case PORT_INFORMATION_SM_RECEIVE_EXEC:
p->rcvd_info = rcv_info(p);
p->port_information_sm_state = PORT_INFORMATION_SM_RECEIVE;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_RECEIVE:
- switch (p->rcvd_info) {
- case SUPERIOR_DESIGNATED_INFO:
- p->port_information_sm_state =
- PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC;
- break;
- case REPEATED_DESIGNATED_INFO:
- p->port_information_sm_state =
- PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC;
- break;
- case INFERIOR_DESIGNATED_INFO:
- p->port_information_sm_state =
- PORT_INFORMATION_SM_INFERIOR_DESIGNATED_EXEC;
- break;
- case INFERIOR_ROOT_ALTERNATE_INFO:
- p->port_information_sm_state =
- PORT_INFORMATION_SM_NOT_DESIGNATED_EXEC;
- break;
- case OTHER_INFO:
- p->port_information_sm_state = PORT_INFORMATION_SM_OTHER_EXEC;
- break;
- default:
- OVS_NOT_REACHED();
- /* no break */
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ switch (p->rcvd_info) {
+ case SUPERIOR_DESIGNATED_INFO:
+ /* 802.1q-2008 has a checkBPDUConsistency() function, called on
+ * a BPDU reception. checkBPDUConsistency() clears the agreed
+ * variable if the received message priority vector is superior
+ * to the port priority vector, the BPDU is an ST BPDU or an
+ * RST BPDU, its port role is Designated and its Learning flag
+ * is set. */
+ if (p->received_bpdu_buffer.flags & BPDU_FLAG_LEARNING) {
+ HMAP_FOR_EACH (p1, node, &r->ports) {
+ if (p1->port_number != p->port_number) {
+ p1->agreed = false;
+ }
+ }
+ }
+ p->port_information_sm_state =
+ PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC;
+ break;
+ case REPEATED_DESIGNATED_INFO:
+ p->port_information_sm_state =
+ PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC;
+ break;
+ case INFERIOR_DESIGNATED_INFO:
+ p->port_information_sm_state =
+ PORT_INFORMATION_SM_INFERIOR_DESIGNATED_EXEC;
+ break;
+ case INFERIOR_ROOT_ALTERNATE_INFO:
+ p->port_information_sm_state =
+ PORT_INFORMATION_SM_NOT_DESIGNATED_EXEC;
+ break;
+ case OTHER_INFO:
+ p->port_information_sm_state = PORT_INFORMATION_SM_OTHER_EXEC;
+ break;
+ default:
+ OVS_NOT_REACHED();
+ /* fall through */
+ }
}
break;
case PORT_INFORMATION_SM_OTHER_EXEC:
p->rcvd_msg = false;
p->port_information_sm_state = PORT_INFORMATION_SM_OTHER;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_OTHER:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
case PORT_INFORMATION_SM_NOT_DESIGNATED_EXEC:
record_agreement(p);
set_tc_flags(p);
p->rcvd_msg = false;
p->port_information_sm_state = PORT_INFORMATION_SM_NOT_DESIGNATED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_NOT_DESIGNATED:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
case PORT_INFORMATION_SM_INFERIOR_DESIGNATED_EXEC:
record_dispute(p);
p->rcvd_msg = false;
p->port_information_sm_state = PORT_INFORMATION_SM_INFERIOR_DESIGNATED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_INFERIOR_DESIGNATED:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
case PORT_INFORMATION_SM_REPEATED_DESIGNATED_EXEC:
record_proposal(p);
set_tc_flags(p);
+ /* This record_agreement() is missing in 802.1D-2004, but it's present
+ * in 802.1q-2008. */
+ record_agreement(p);
updt_rcvd_info_while(p);
p->rcvd_msg = false;
p->port_information_sm_state = PORT_INFORMATION_SM_REPEATED_DESIGNATED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_REPEATED_DESIGNATED:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
case PORT_INFORMATION_SM_SUPERIOR_DESIGNATED_EXEC:
p->agreed = p->proposing = false;
set_tc_flags(p);
/* RECEIVED is not specified in Standard 802.1D-2004. */
p->agree = p->agree && better_or_same_info(p, RECEIVED);
+ /* This record_agreement() and the synced assignment are missing in
+ * 802.1D-2004, but they're present in 802.1q-2008. */
+ record_agreement(p);
+ p->synced = p->synced && p->agreed;
record_priority(p);
record_times(p);
updt_rcvd_info_while(p);
p->selected = false;
p->rcvd_msg = false;
p->port_information_sm_state = PORT_INFORMATION_SM_SUPERIOR_DESIGNATED;
- /* no break */
+ /* fall through */
case PORT_INFORMATION_SM_SUPERIOR_DESIGNATED:
- p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ if (!p->port_enabled && p->info_is != INFO_IS_DISABLED) {
+ /* Global transition. */
+ p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC;
+ } else {
+ p->port_information_sm_state = PORT_INFORMATION_SM_CURRENT_EXEC;
+ }
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_information_sm_state) {
r->changes = true;
p->learn = p->forward = false;
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DISABLE_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_DISABLE_PORT:
if (check_selected_role_change(p, ROLE_DISABLED)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info && !p->learning
&& !p->forwarding) {
p->port_role_transition_sm_state =
p->sync = p->re_root = false;
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DISABLED_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_DISABLED_PORT:
if (check_selected_role_change(p, ROLE_DISABLED)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info
&& (p->fd_while != p->designated_times.max_age || p->sync
|| p->re_root || !p->synced)) {
p->role = ROLE_ROOT;
p->rr_while = p->designated_times.forward_delay;
p->port_role_transition_sm_state = PORT_ROLE_TRANSITION_SM_ROOT_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_ROOT_PORT:
if (check_selected_role_change(p, ROLE_ROOT)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info) {
if (p->rr_while != p->designated_times.forward_delay) {
p->port_role_transition_sm_state =
break;
}
}
- break;
+ break;
case PORT_ROLE_TRANSITION_SM_REROOT_EXEC:
- set_re_root_tree(p);
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ set_re_root_tree(p);
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ROOT_AGREED_EXEC:
- p->proposed = p->sync = false;
- p->agree = p->new_info = true;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ p->proposed = p->sync = false;
+ p->agree = p->new_info = true;
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ROOT_PROPOSED_EXEC:
set_sync_tree(p);
p->proposed = false;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ROOT_FORWARD_EXEC:
p->fd_while = 0;
p->forward = true;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ROOT_LEARN_EXEC:
p->fd_while = forward_delay(p);
p->learn = true;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_REROOTED_EXEC:
p->re_root = false;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ROOT)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC:
p->role = ROLE_DESIGNATED;
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT:
if (check_selected_role_change(p, ROLE_DESIGNATED)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info) {
if (((p->sync && !p->synced)
|| (p->re_root && p->rr_while != 0) || p->disputed)
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_RETIRED_EXEC:
p->re_root = false;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_SYNCED_EXEC:
p->rr_while = 0;
p->synced = true;
p->sync = false;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_PROPOSE_EXEC:
p->proposing = true;
p->edge_delay_while = edge_delay(p);
p->new_info = true;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_FORWARD_EXEC:
p->forward = true;
p->fd_while = 0;
p->agreed = p->send_rstp;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_LEARN_EXEC:
p->learn = true;
p->fd_while = forward_delay(p);
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_DESIGNATED_DISCARD_EXEC:
p->learn = p->forward = p->disputed = false;
p->fd_while = forward_delay(p);
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_DESIGNATED)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC:
p->fd_while = p->designated_times.forward_delay;
p->sync = p->re_root = false;
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT:
if (check_selected_role_change(p, ROLE_ALTERNATE)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info) {
if (p->rb_while != 2 * p->designated_times.hello_time
&& p->role == ROLE_BACKUP) {
p->proposed = false;
p->agree = true;
p->new_info = true;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ALTERNATE)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_ALTERNATE_PROPOSED_EXEC:
set_sync_tree(p);
p->proposed = false;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ALTERNATE)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ }
break;
case PORT_ROLE_TRANSITION_SM_BLOCK_PORT_EXEC:
p->role = p->selected_role;
p->learn = p->forward = false;
p->port_role_transition_sm_state = PORT_ROLE_TRANSITION_SM_BLOCK_PORT;
- /* no break */
+ /* fall through */
case PORT_ROLE_TRANSITION_SM_BLOCK_PORT:
if (check_selected_role_change(p, ROLE_ALTERNATE)) {
- break;
+ /* Global transition. */
} else if (p->selected && !p->updt_info && !p->learning &&
!p->forwarding) {
p->port_role_transition_sm_state =
break;
case PORT_ROLE_TRANSITION_SM_BACKUP_PORT_EXEC:
p->rb_while = 2 * p->designated_times.hello_time;
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ if (check_selected_role_change(p, ROLE_ALTERNATE)) {
+ /* Global transition. */
+ } else {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
+ }
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_role_transition_sm_state) {
r->changes = true;
p->port_role_transition_sm_state);
}
if (last_role != p->role) {
- last_role = p->role;
VLOG_DBG("%s, port %u, port role ["RSTP_PORT_ID_FMT"] = %s",
p->rstp->name, p->port_number, p->port_id,
rstp_port_role_name(p->role));
p->forwarding = false;
p->port_state_transition_sm_state =
PORT_STATE_TRANSITION_SM_DISCARDING;
- /* no break */
+ /* fall through */
case PORT_STATE_TRANSITION_SM_DISCARDING:
if (p->learn) {
p->port_state_transition_sm_state =
enable_learning(p);
p->learning = true;
p->port_state_transition_sm_state = PORT_STATE_TRANSITION_SM_LEARNING;
- /* no break */
+ /* fall through */
case PORT_STATE_TRANSITION_SM_LEARNING:
if (!p->learn) {
p->port_state_transition_sm_state =
p->forwarding = true;
p->port_state_transition_sm_state =
PORT_STATE_TRANSITION_SM_FORWARDING;
- /* no break */
+ /* fall through */
case PORT_STATE_TRANSITION_SM_FORWARDING:
if (!p->forward) {
p->port_state_transition_sm_state =
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->port_state_transition_sm_state) {
r->changes = true;
p->tc_while = 0;
p->tc_ack = false;
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_INACTIVE;
- /* no break */
+ /* fall through */
case TOPOLOGY_CHANGE_SM_INACTIVE:
if (p->learn && !p->fdb_flush) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_LEARNING_EXEC;
p->rcvd_tc = p->rcvd_tcn = p->rcvd_tc_ack = false;
p->tc_prop = p->rcvd_tc_ack = false;
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_LEARNING;
- /* no break */
+ /* fall through */
case TOPOLOGY_CHANGE_SM_LEARNING:
if (p->role != ROLE_ROOT && p->role != ROLE_DESIGNATED &&
!(p->learn || p->learning) && !(p->rcvd_tc || p->rcvd_tcn ||
set_tc_prop_tree(p);
p->new_info = true;
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_ACTIVE_EXEC;
- /* no break */
+ /* fall through */
case TOPOLOGY_CHANGE_SM_ACTIVE_EXEC:
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_ACTIVE;
- /* no break */
+ /* fall through */
case TOPOLOGY_CHANGE_SM_ACTIVE:
if ((p->role != ROLE_ROOT && p->role != ROLE_DESIGNATED)
|| p->oper_edge) {
break;
default:
OVS_NOT_REACHED();
- /* no break */
+ /* fall through */
}
if (old_state != p->topology_change_sm_state) {
r->changes = true;