/*
- * 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 "byte-order.h"
#include "connectivity.h"
#include "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);
RAPID_SPANNING_TREE_BPDU_SIZE = 36
};
+/* Same is a subset of SUPERIOR, so can be used as a boolean when the
+ * distinction is not significant. */
enum vector_comparison {
INFERIOR = 0,
SUPERIOR = 1,
static ovs_be16 time_encode(uint8_t);
static uint8_t time_decode(ovs_be16);
static enum vector_comparison
-compare_rstp_priority_vector(struct rstp_priority_vector *,
- struct rstp_priority_vector *);
+compare_rstp_priority_vectors(const struct rstp_priority_vector *,
+ const struct rstp_priority_vector *);
static bool rstp_times_equal(struct rstp_times *, struct rstp_times *);
/* Per-Bridge State Machine */
/* port_timers_sm() not defined as a state machine */
void
-process_received_bpdu__(struct rstp_port *p, const void *bpdu,
+process_received_bpdu__(struct rstp_port *p, const void *bpdu_,
size_t bpdu_size)
OVS_REQUIRES(rstp_mutex)
{
- struct rstp *rstp = p->rstp;
+ struct rstp *rstp = p->rstp;
+ struct rstp_bpdu *bpdu = (struct rstp_bpdu *)bpdu_;
- if (!p->port_enabled)
+ if (!p->port_enabled) {
return;
- if (p->rcvd_bpdu)
+ }
+ if (p->rcvd_bpdu) {
return;
+ }
+
+ /* [9.2.9 Encoding of Port Role values]
+ * NOTE. If the Unknown value of the Port Role parameter is received, the
+ * state machines will effectively treat the RST BPDU as if it were a
+ * Configuration BPDU.
+ */
+ if (bpdu->bpdu_type == RAPID_SPANNING_TREE_BPDU) {
+ uint8_t role = (bpdu->flags & ROLE_FLAG_MASK) >> ROLE_FLAG_SHIFT;
+
+ if (role == PORT_UNKN) {
+ bpdu->bpdu_type = CONFIGURATION_BPDU;
+ }
+ }
if (validate_received_bpdu(p, bpdu, bpdu_size) == 0) {
p->rcvd_bpdu = true;
}
}
+/* Returns 0 on success. */
static int
validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
OVS_REQUIRES(rstp_mutex)
ntohs(temp->protocol_identifier) != 0) {
return -1;
} else {
- if (temp->bpdu_type == CONFIGURATION_BPDU &&
- bpdu_size >= CONFIGURATION_BPDU_SIZE &&
- (time_decode(temp->message_age) < time_decode(temp->max_age)))
- {
+ if (temp->bpdu_type == CONFIGURATION_BPDU
+ && bpdu_size >= CONFIGURATION_BPDU_SIZE
+ && (time_decode(temp->message_age) < time_decode(temp->max_age))) {
if ((ntohll(temp->designated_bridge_id) !=
- p->rstp->bridge_identifier) ||
- ((ntohll(temp->designated_bridge_id) ==
- p->rstp->bridge_identifier) &&
- (ntohs(temp->designated_port_id) != p->port_id))) {
+ p->rstp->bridge_identifier)
+ || ((ntohll(temp->designated_bridge_id) ==
+ p->rstp->bridge_identifier)
+ && (ntohs(temp->designated_port_id) != p->port_id))) {
return 0;
- }
- else {
+ } else {
return -1;
}
} else if (temp->bpdu_type == TOPOLOGY_CHANGE_NOTIFICATION_BPDU) {
} else if (temp->bpdu_type == RAPID_SPANNING_TREE_BPDU &&
bpdu_size >= RAPID_SPANNING_TREE_BPDU_SIZE) {
return 0;
- }
- else {
+ } else {
return -1;
}
}
* boolean 'changes' is true, meaning that something changed and the SMs need
* to work to process this change.
* The boolean 'changes' is set every time a SM modifies its state, a BPDU is
- * received, a timer expires or port down event is detected. If a parameter is
+ * received, a timer expires or port down event is detected. If a parameter is
* set by management, then 'changes' is set.
*/
#define MAX_RSTP_ITERATIONS 1000 /* safeguard */
move_rstp__(struct rstp *rstp)
OVS_REQUIRES(rstp_mutex)
{
- struct rstp_port *p;
int num_iterations;
num_iterations = 0;
while (rstp->changes == true && num_iterations < MAX_RSTP_ITERATIONS) {
+ struct rstp_port *p;
+
VLOG_DBG("%s: move_rstp()", rstp->name);
+
rstp->changes = false;
port_role_selection_sm(rstp);
- if (rstp->ports_count > 0) {
- LIST_FOR_EACH (p, node, &rstp->ports) {
- if (p->rstp_state != RSTP_DISABLED) {
- port_receive_sm(p);
- bridge_detection_sm(p);
- port_information_sm(p);
- port_role_transition_sm(p);
- port_state_transition_sm(p);
- topology_change_sm(p);
- port_transmit_sm(p);
- port_protocol_migration_sm(p);
- }
+ HMAP_FOR_EACH (p, node, &rstp->ports) {
+ if (p->rstp_state != RSTP_DISABLED) {
+ port_receive_sm(p);
+ bridge_detection_sm(p);
+ port_information_sm(p);
+ port_role_transition_sm(p);
+ port_state_transition_sm(p);
+ topology_change_sm(p);
+ port_transmit_sm(p);
+ port_protocol_migration_sm(p);
}
}
num_iterations++;
{
struct rstp_port *p;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- decrement_timer(&p->hello_when);
- decrement_timer(&p->tc_while);
- decrement_timer(&p->fd_while);
- decrement_timer(&p->rcvd_info_while);
- decrement_timer(&p->rr_while);
- decrement_timer(&p->rb_while);
- decrement_timer(&p->mdelay_while);
- decrement_timer(&p->edge_delay_while);
- decrement_timer(&p->tx_count);
- p->uptime+=1;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ decrement_timer(&p->hello_when);
+ decrement_timer(&p->tc_while);
+ decrement_timer(&p->fd_while);
+ decrement_timer(&p->rcvd_info_while);
+ decrement_timer(&p->rr_while);
+ decrement_timer(&p->rb_while);
+ decrement_timer(&p->mdelay_while);
+ decrement_timer(&p->edge_delay_while);
+ decrement_timer(&p->tx_count);
+ p->uptime += 1;
}
r->changes = true;
move_rstp__(r);
{
struct rstp_port *p;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- p->selected_role = ROLE_DISABLED;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ p->selected_role = ROLE_DISABLED;
}
}
{
struct rstp_port *p;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- p->reselect = false;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ p->reselect = false;
}
}
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 = r->bridge_times;
/* Letters a) b) c) */
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- uint32_t old_root_path_cost;
- uint32_t root_path_cost;
- if (p->info_is != INFO_IS_RECEIVED) {
- continue;
- }
- /* [17.6] */
- candidate_vector = p->port_priority;
- candidate_vector.bridge_port_id = p->port_id;
- old_root_path_cost = candidate_vector.root_path_cost;
- root_path_cost = old_root_path_cost + p->port_path_cost;
- candidate_vector.root_path_cost = root_path_cost;
-
- if ((candidate_vector.designated_bridge_id & 0xffffffffffffULL) ==
- (r->bridge_priority.designated_bridge_id & 0xffffffffffffULL))
- {
- break;
- }
- if (compare_rstp_priority_vector(&candidate_vector, &best_vector)
- == SUPERIOR) {
- best_vector = candidate_vector;
- r->root_times = p->port_times;
- r->root_times.message_age++;
- vsel = p->port_number;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ uint32_t old_root_path_cost;
+ uint32_t root_path_cost;
+
+ if (p->info_is != INFO_IS_RECEIVED) {
+ continue;
+ }
+ /* [17.6] */
+ candidate_vector = p->port_priority;
+ candidate_vector.bridge_port_id = p->port_id;
+ old_root_path_cost = candidate_vector.root_path_cost;
+ root_path_cost = old_root_path_cost + p->port_path_cost;
+ candidate_vector.root_path_cost = root_path_cost;
+
+ if ((candidate_vector.designated_bridge_id & 0xffffffffffffULL) ==
+ (r->bridge_priority.designated_bridge_id & 0xffffffffffffULL)) {
+ continue;
+ }
+ if (compare_rstp_priority_vectors(&candidate_vector,
+ &best_vector) == SUPERIOR) {
+ best_vector = candidate_vector;
+ 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) */
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- p->designated_priority_vector.root_bridge_id =
- r->root_priority.root_bridge_id;
- p->designated_priority_vector.root_path_cost =
- r->root_priority.root_path_cost;
- p->designated_priority_vector.designated_bridge_id =
- r->bridge_identifier;
- p->designated_priority_vector.designated_port_id =
- p->port_id;
- p->designated_times = r->root_times;
- p->designated_times.hello_time = r->bridge_times.hello_time;
- }
- }
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- switch (p->info_is) {
- case INFO_IS_DISABLED:
- p->selected_role = ROLE_DISABLED;
- break;
- case INFO_IS_AGED:
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ p->designated_priority_vector.root_bridge_id =
+ r->root_priority.root_bridge_id;
+ p->designated_priority_vector.root_path_cost =
+ r->root_priority.root_path_cost;
+ p->designated_priority_vector.designated_bridge_id =
+ r->bridge_identifier;
+ p->designated_priority_vector.designated_port_id =
+ p->port_id;
+ p->designated_times = r->root_times;
+ p->designated_times.hello_time = r->bridge_times.hello_time;
+ }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ switch (p->info_is) {
+ case INFO_IS_DISABLED:
+ p->selected_role = ROLE_DISABLED;
+ break;
+ case INFO_IS_AGED:
+ p->updt_info = true;
+ p->selected_role = ROLE_DESIGNATED;
+ break;
+ case INFO_IS_MINE:
+ p->selected_role = ROLE_DESIGNATED;
+ if (compare_rstp_priority_vectors(
+ &p->port_priority, &p->designated_priority_vector) != SAME
+ || !rstp_times_equal(&p->designated_times, &r->root_times)) {
p->updt_info = true;
- p->selected_role = ROLE_DESIGNATED;
- break;
- case INFO_IS_MINE:
- p->selected_role = ROLE_DESIGNATED;
- if ((compare_rstp_priority_vector(&p->port_priority,
- &p->designated_priority_vector) != SAME) ||
- !rstp_times_equal(&p->designated_times, &r->root_times)) {
- p->updt_info = true;
- }
- break;
- case INFO_IS_RECEIVED:
- if (vsel == p->port_number) { /* Letter i) */
- p->selected_role = ROLE_ROOT;
+ }
+ break;
+ case INFO_IS_RECEIVED:
+ if (vsel == p->port_number) { /* Letter i) */
+ p->selected_role = ROLE_ROOT;
+ p->updt_info = false;
+ } else if (compare_rstp_priority_vectors(
+ &p->designated_priority_vector,
+ &p->port_priority) == INFERIOR) {
+ if (p->port_priority.designated_bridge_id !=
+ r->bridge_identifier) {
+ p->selected_role = ROLE_ALTERNATE;
p->updt_info = false;
- } else if (compare_rstp_priority_vector(
- &p->designated_priority_vector, &p->port_priority)
- == INFERIOR) {
- if (p->port_priority.designated_bridge_id !=
- r->bridge_identifier) {
- p->selected_role = ROLE_ALTERNATE;
- p->updt_info = false;
- } else {
- p->selected_role = ROLE_BACKUP;
- p->updt_info = false;
- }
} else {
- p->selected_role = ROLE_DESIGNATED;
- p->updt_info = true;
+ p->selected_role = ROLE_BACKUP;
+ p->updt_info = false;
}
- break;
- default:
- OVS_NOT_REACHED();
- /* no break */
+ } else {
+ p->selected_role = ROLE_DESIGNATED;
+ p->updt_info = true;
}
+ break;
+ default:
+ OVS_NOT_REACHED();
+ /* no break */
}
}
seq_change(connectivity_seq_get());
{
struct rstp_port *p;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- if (p->reselect) {
- return;
- }
- }
- LIST_FOR_EACH (p, node, &r->ports) {
- p->selected = true;
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ if (p->reselect) {
+ return;
}
}
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ p->selected = true;
+ }
}
static int
switch (r->port_role_selection_sm_state) {
case PORT_ROLE_SELECTION_SM_INIT:
- if (r->begin)
+ if (r->begin) {
r->port_role_selection_sm_state =
PORT_ROLE_SELECTION_SM_INIT_BRIDGE_EXEC;
+ }
break;
case PORT_ROLE_SELECTION_SM_INIT_BRIDGE_EXEC:
updt_role_disabled_tree(r);
PORT_ROLE_SELECTION_SM_ROLE_SELECTION;
/* no break */
case PORT_ROLE_SELECTION_SM_ROLE_SELECTION:
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- if (p->reselect) {
- r->port_role_selection_sm_state =
- PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC;
- break;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ if (p->reselect) {
+ r->port_role_selection_sm_state =
+ PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC;
+ break;
}
}
break;
p->port_receive_sm_state = PORT_RECEIVE_SM_DISCARD;
/* no break */
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->port_receive_sm_state = PORT_RECEIVE_SM_RECEIVE;
/* no break */
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;
switch (p->port_protocol_migration_sm_state) {
case PORT_PROTOCOL_MIGRATION_SM_INIT:
- p->port_protocol_migration_sm_state =
- PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC;
+ p->port_protocol_migration_sm_state =
+ PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC;
/* no break */
case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC:
p->mcheck = false;
/* no break */
case PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP:
if (p->mdelay_while == 0) {
- p->port_protocol_migration_sm_state =
- PORT_PROTOCOL_MIGRATION_SM_SENSING_EXEC;
- }
- else if ((p->mdelay_while != r->migrate_time) && !p->port_enabled) {
+ p->port_protocol_migration_sm_state =
+ PORT_PROTOCOL_MIGRATION_SM_SENSING_EXEC;
+ } else if ((p->mdelay_while != r->migrate_time) && !p->port_enabled) {
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC;
}
break;
case PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP_EXEC:
- p->send_rstp = false;
+ p->send_rstp = false;
p->mdelay_while = r->migrate_time;
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP;
/* no break */
case PORT_PROTOCOL_MIGRATION_SM_SENSING:
if (!p->port_enabled || p->mcheck || ((r->rstp_version) &&
- !p->send_rstp && p->rcvd_rstp)) {
+ !p->send_rstp && p->rcvd_rstp)) {
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_CHECKING_RSTP_EXEC;
- }
- else if (p->send_rstp && p->rcvd_stp) {
+ } else if (p->send_rstp && p->rcvd_stp) {
p->port_protocol_migration_sm_state =
PORT_PROTOCOL_MIGRATION_SM_SELECTING_STP_EXEC;
}
p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_NOT_EDGE;
/* no break */
case BRIDGE_DETECTION_SM_NOT_EDGE:
- if ((!p->port_enabled && p->admin_edge) || ((p->edge_delay_while == 0)
- && p->auto_edge && p->send_rstp && p->proposing)) {
+ if ((!p->port_enabled && p->admin_edge)
+ || ((p->edge_delay_while == 0) && p->auto_edge && p->send_rstp
+ && p->proposing)) {
p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_EDGE_EXEC;
}
break;
{
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;
llc->llc_ssap = STP_LLC_SSAP;
llc->llc_cntl = STP_LLC_CNTL;
- p->rstp->send_bpdu(pkt, p->port_number, p->rstp->aux);
+ p->rstp->send_bpdu(pkt, p->aux, p->rstp->aux);
}
static void
r = p->rstp;
if (r->rstp_version && p->oper_point_to_point_mac &&
- ((p->received_bpdu_buffer.flags & BPDU_FLAG_AGREEMENT))) {
+ ((p->received_bpdu_buffer.flags & BPDU_FLAG_AGREEMENT))) {
p->agreed = true;
p->proposing = false;
} else {
* RST BPDU.
*/
if (p->received_bpdu_buffer.bpdu_type == CONFIGURATION_BPDU ||
- p->received_bpdu_buffer.bpdu_type == RAPID_SPANNING_TREE_BPDU) {
+ p->received_bpdu_buffer.bpdu_type == RAPID_SPANNING_TREE_BPDU) {
if ((p->received_bpdu_buffer.flags & BPDU_FLAG_TOPCHANGE) != 0) {
p->rcvd_tc = true;
}
}
}
/* Sets rcvd_tcn true if the BPDU is a TCN BPDU. */
- if (p->received_bpdu_buffer.bpdu_type ==
- TOPOLOGY_CHANGE_NOTIFICATION_BPDU) {
+ if (p->received_bpdu_buffer.bpdu_type
+ == TOPOLOGY_CHANGE_NOTIFICATION_BPDU) {
p->rcvd_tcn = true;
}
}
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;
}
}
{
enum port_flag role =
((p->received_bpdu_buffer.flags) & ROLE_FLAG_MASK) >> ROLE_FLAG_SHIFT;
- if ((role == PORT_DES) &&
- ((p->received_bpdu_buffer.flags & BPDU_FLAG_PROPOSAL) != 0)) {
+
+ if ((role == PORT_DES)
+ && ((p->received_bpdu_buffer.flags & BPDU_FLAG_PROPOSAL) != 0)) {
p->proposed = true;
}
}
*/
if (p->port_times.message_age < p->port_times.max_age) {
p->rcvd_info_while = p->port_times.hello_time * 3;
- } else {
+ } else {
p->rcvd_info_while = 0;
- }
+ }
}
/* Times are internally held in seconds, while the protocol uses 1/256 seconds.
bpdu.hello_time = time_encode(p->designated_times.hello_time);
bpdu.forward_delay = time_encode(p->designated_times.forward_delay);
bpdu.flags = 0;
+
switch (p->role) {
case ROLE_ROOT:
bpdu.flags = PORT_ROOT << ROLE_FLAG_SHIFT;
VLOG_DBG("%s, port %u: port_transmit_sm ROLE == DISABLED.",
p->rstp->name, p->port_number);
break;
- }
- else if (p->send_rstp && p->new_info &&
- (p->tx_count < r->transmit_hold_count) && (p->hello_when != 0)
- && p->selected && !p->updt_info) {
+ } else if (p->send_rstp && p->new_info
+ && p->tx_count < r->transmit_hold_count
+ && p->hello_when != 0 && p->selected && !p->updt_info) {
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_RSTP_EXEC;
- }
- else if (p->hello_when == 0 && p->selected && !p->updt_info) {
+ } else if (p->hello_when == 0 && p->selected && !p->updt_info) {
p->port_transmit_sm_state =
PORT_TRANSMIT_SM_TRANSMIT_PERIODIC_EXEC;
- }
- else if (!p->send_rstp && p->new_info && (p->role == ROLE_ROOT) &&
- (p->tx_count < r->transmit_hold_count) && (p->hello_when != 0)
- && p->selected && !p->updt_info) {
+ } else if (!p->send_rstp && p->new_info && p->role == ROLE_ROOT
+ && p->tx_count < r->transmit_hold_count
+ && p->hello_when != 0 && p->selected && !p->updt_info) {
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_TCN_EXEC;
- }
- else if (!p->send_rstp && p->new_info && (p->role == ROLE_DESIGNATED)
- && (p->tx_count < r->transmit_hold_count) &&
- (p->hello_when != 0) && p->selected && !p->updt_info) {
+ } else if (!p->send_rstp && p->new_info && p->role == ROLE_DESIGNATED
+ && p->tx_count < r->transmit_hold_count
+ && p->hello_when != 0 && p->selected && !p->updt_info) {
p->port_transmit_sm_state = PORT_TRANSMIT_SM_TRANSMIT_CONFIG_EXEC;
}
break;
p->msg_times.message_age =
time_decode(p->received_bpdu_buffer.message_age);
- cp = compare_rstp_priority_vector(&p->msg_priority, &p->port_priority);
+ 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:
- * b) The received message conveys Designated Port Role, and a message
- * priority vector and timer parameters that are the same as the Port's
- * port priority vector or timer values.
- */
- else if ((role == PORT_DES) && (cp == SAME) && (ct == true)) {
+ /* Returns RepeatedDesignatedInfo if:
+ * b) The received message conveys Designated Port Role, and a message
+ * priority vector and timer parameters that are the same as the
+ * Port's port priority vector or timer values. */
+ } else if (role == PORT_DES && cp == SAME && ct == true) {
return REPEATED_DESIGNATED_INFO;
- }
- /* Returns InferiorDesignatedInfo if:
- * c) The received message conveys a Designated Port Role, and a message
- * priority vector that is worse than the Port's port priority vector.
- */
- else if ((role == PORT_DES) && (cp == INFERIOR)) {
+ /* Returns InferiorDesignatedInfo if:
+ * c) The received message conveys a Designated Port Role, and a
+ * message priority vector that is worse than the Port's port
+ * priority vector. */
+ } else if (role == PORT_DES && cp == INFERIOR) {
return INFERIOR_DESIGNATED_INFO;
- }
- /* Returns InferiorRootAlternateInfo if:
- * d) The received message conveys a Root Port, Alternate Port, or Backup
- * Port Role and a message priority that is the same as or worse than
- * the port priority vector.
- */
- else if ((role == PORT_ROOT || role == PORT_ALT_BACK) &&
- (cp == INFERIOR || cp == SAME)) {
+ /* Returns InferiorRootAlternateInfo if:
+ * d) The received message conveys a Root Port, Alternate Port, or
+ * Backup Port Role and a message priority that is the same as or
+ * worse than the port priority vector. */
+ } else if ((role == PORT_ROOT || role == PORT_ALT_BACK) &&
+ (cp == INFERIOR || cp == SAME)) {
return INFERIOR_ROOT_ALTERNATE_INFO;
- }
- /* Otherwise, returns OtherInfo. */
- else {
+ /* Otherwise, returns OtherInfo. */
+ } else {
return OTHER_INFO;
}
}
better_or_same_info(struct rstp_port *p, int new_info_is)
OVS_REQUIRES(rstp_mutex)
{
- /* >= SUPERIOR means that the vector is better or the same. */
- return ((new_info_is == RECEIVED && p->info_is == INFO_IS_RECEIVED &&
- compare_rstp_priority_vector(&p->msg_priority,
- &p->port_priority) >= SUPERIOR) ||
- (new_info_is == MINE && p->info_is == INFO_IS_MINE &&
- compare_rstp_priority_vector(&p->designated_priority_vector,
- &p->port_priority) >= SUPERIOR));
+ return
+ (new_info_is == RECEIVED && p->info_is == INFO_IS_RECEIVED
+ && compare_rstp_priority_vectors(&p->msg_priority,
+ &p->port_priority))
+ || (new_info_is == MINE && p->info_is == INFO_IS_MINE
+ && compare_rstp_priority_vectors(&p->designated_priority_vector,
+ &p->port_priority));
}
static int
{
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->port_information_sm_state = PORT_INFORMATION_SM_DISABLED;
/* no break */
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->port_information_sm_state = PORT_INFORMATION_SM_AGED;
/* no break */
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->port_information_sm_state = PORT_INFORMATION_SM_UPDATE;
/* no break */
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 */
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;
p->port_information_sm_state = PORT_INFORMATION_SM_RECEIVE;
/* no break */
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();
+ /* no break */
+ }
}
break;
case PORT_INFORMATION_SM_OTHER_EXEC:
p->port_information_sm_state = PORT_INFORMATION_SM_OTHER;
/* no break */
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);
p->port_information_sm_state = PORT_INFORMATION_SM_NOT_DESIGNATED;
/* no break */
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->port_information_sm_state = PORT_INFORMATION_SM_INFERIOR_DESIGNATED;
/* no break */
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 */
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->port_information_sm_state = PORT_INFORMATION_SM_SUPERIOR_DESIGNATED;
/* no break */
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();
struct rstp_port *p1;
r = p->rstp;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p1, node, &r->ports) {
- p1->re_root = true;
- }
+ HMAP_FOR_EACH (p1, node, &r->ports) {
+ p1->re_root = true;
}
}
struct rstp_port *p1;
r = p->rstp;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p1, node, &r->ports) {
- p1->sync = true;
- }
+ HMAP_FOR_EACH (p1, node, &r->ports) {
+ p1->sync = true;
}
}
check_selected_role_change(struct rstp_port *p, int current_role_state)
OVS_REQUIRES(rstp_mutex)
{
- if (p->selected && !p->updt_info && (p->role != p->selected_role) &&
- (p->selected_role != current_role_state)) {
+ if (p->selected && !p->updt_info && p->role != p->selected_role
+ && p->selected_role != current_role_state) {
VLOG_DBG("%s, port %u: case: current = %s role = %s selected = %d",
p->rstp->name, p->port_number,
rstp_port_role_name(current_role_state),
struct rstp_port *p1;
r = p->rstp;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p1, node, &r->ports) {
- if ((p1 != p) && (p1->rr_while != 0)) {
- return false;
- }
+ HMAP_FOR_EACH (p1, node, &r->ports) {
+ if ((p1 != p) && (p1->rr_while != 0)) {
+ return false;
}
}
return true;
{
struct rstp_port *p;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p, node, &r->ports) {
- if (!(p->selected && p->role == p->selected_role &&
- (p->role == ROLE_ROOT || p->synced == true))) {
- return false;
- }
+ HMAP_FOR_EACH (p, node, &r->ports) {
+ if (!(p->selected && p->role == p->selected_role &&
+ (p->role == ROLE_ROOT || p->synced == true))) {
+ return false;
}
}
return true;
/* no break */
case PORT_ROLE_TRANSITION_SM_DISABLE_PORT:
if (check_selected_role_change(p, ROLE_DISABLED)) {
- break;
- }
- else if (p->selected && !p->updt_info && !p->learning &&
- !p->forwarding) {
+ /* Global transition. */
+ } else if (p->selected && !p->updt_info && !p->learning
+ && !p->forwarding) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DISABLED_PORT_EXEC;
}
/* no break */
case PORT_ROLE_TRANSITION_SM_DISABLED_PORT:
if (check_selected_role_change(p, ROLE_DISABLED)) {
- break;
- }
- else if (p->selected && !p->updt_info &&
- ((p->fd_while != p->designated_times.max_age) || p->sync ||
- p->re_root || !p->synced)) {
+ /* 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->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DISABLED_PORT_EXEC;
}
/* no break */
case PORT_ROLE_TRANSITION_SM_ROOT_PORT:
if (check_selected_role_change(p, ROLE_ROOT)) {
- break;
- }
- else if (p->selected && !p->updt_info) {
+ /* Global transition. */
+ } else if (p->selected && !p->updt_info) {
if (p->rr_while != p->designated_times.forward_delay) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ROOT_PORT_EXEC;
break;
- }
- else if (p->re_root && p->forward) {
+ } else if (p->re_root && p->forward) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_REROOTED_EXEC;
break;
- }
- else if (((p->fd_while == 0) || ((re_rooted(p) &&
- (p->rb_while == 0)) &&
- (r->rstp_version))) && !p->learn) {
+ } else if ((p->fd_while == 0
+ || ((re_rooted(p) && p->rb_while == 0)
+ && r->rstp_version)) && !p->learn) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ROOT_LEARN_EXEC;
break;
- }
- else if (((p->fd_while == 0) || ((re_rooted(p) &&
- (p->rb_while == 0)) &&
- (r->rstp_version))) && p->learn && !p->forward) {
+ } else if ((p->fd_while == 0
+ || ((re_rooted(p) && p->rb_while == 0)
+ && r->rstp_version)) && p->learn && !p->forward) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ROOT_FORWARD_EXEC;
break;
- }
- else if (p->proposed && !p->agree) {
+ } else if (p->proposed && !p->agree) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ROOT_PROPOSED_EXEC;
break;
- }
- else if ((all_synced(r) && !p->agree) ||
- (p->proposed && p->agree)) {
+ } else if ((all_synced(r) && !p->agree) ||
+ (p->proposed && p->agree)) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ROOT_AGREED_EXEC;
break;
- }
- else if (!p->forward && !p->re_root) {
+ } else if (!p->forward && !p->re_root) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_REROOT_EXEC;
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;
/* no break */
case PORT_ROLE_TRANSITION_SM_DESIGNATED_PORT:
if (check_selected_role_change(p, ROLE_DESIGNATED)) {
- break;
- }
- else if (p->selected && !p->updt_info) {
- if (((p->sync && !p->synced) || (p->re_root &&
- (p->rr_while != 0)) || p->disputed) &&
- !p->oper_edge && (p->learn || p->forward)) {
- p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_DESIGNATED_DISCARD_EXEC;
- }
- else if (((p->fd_while == 0)|| p->agreed || p->oper_edge) &&
- ((p->rr_while == 0) || !p->re_root) &&
- !p->sync && !p->learn) {
+ /* Global transition. */
+ } else if (p->selected && !p->updt_info) {
+ if (((p->sync && !p->synced)
+ || (p->re_root && p->rr_while != 0) || p->disputed)
+ && !p->oper_edge && (p->learn || p->forward)) {
+ p->port_role_transition_sm_state =
+ PORT_ROLE_TRANSITION_SM_DESIGNATED_DISCARD_EXEC;
+ } else if ((p->fd_while == 0 || p->agreed || p->oper_edge)
+ && (p->rr_while == 0 || !p->re_root)
+ && !p->sync && !p->learn) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_LEARN_EXEC;
- }
- else if (((p->fd_while == 0) || p->agreed || p->oper_edge) &&
- ((p->rr_while == 0) || !p->re_root) &&
- !p->sync && (p->learn && !p->forward)) {
+ } else if ((p->fd_while == 0 || p->agreed || p->oper_edge)
+ && (p->rr_while == 0 || !p->re_root)
+ && !p->sync && (p->learn && !p->forward)) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_FORWARD_EXEC;
- }
- else if (!p->forward && !p->agreed && !p->proposing &&
- !p->oper_edge) {
+ } else if (!p->forward && !p->agreed && !p->proposing &&
+ !p->oper_edge) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_PROPOSE_EXEC;
- }
- else if ((!p->learning && !p->forwarding && !p->synced) ||
- (p->agreed && !p->synced) || (p->oper_edge && !p->synced) ||
- (p->sync && p->synced)) {
+ } else if ((!p->learning && !p->forwarding && !p->synced)
+ || (p->agreed && !p->synced)
+ || (p->oper_edge && !p->synced)
+ || (p->sync && p->synced)) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_SYNCED_EXEC;
- }
- else if ((p->rr_while == 0) && p->re_root) {
+ } else if (p->rr_while == 0 && p->re_root) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_DESIGNATED_RETIRED_EXEC;
}
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;
/* no break */
case PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT:
if (check_selected_role_change(p, ROLE_ALTERNATE)) {
- break;
- }
- else if (p->selected && !p->updt_info) {
- if ((p->rb_while != (2 * p->designated_times.hello_time)) &&
- (p->role == ROLE_BACKUP)) {
+ /* Global transition. */
+ } else if (p->selected && !p->updt_info) {
+ if (p->rb_while != 2 * p->designated_times.hello_time
+ && p->role == ROLE_BACKUP) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_BACKUP_PORT_EXEC;
- }
- else if ((p->fd_while != forward_delay(p)) || p->sync ||
- p->re_root || !p->synced) {
+ } else if ((p->fd_while != forward_delay(p)) || p->sync
+ || p->re_root || !p->synced) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
- }
- else if (p->proposed && !p->agree) {
+ } else if (p->proposed && !p->agree) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ALTERNATE_PROPOSED_EXEC;
- }
- else if (( all_synced(r) && !p->agree) ||
- (p->proposed && p->agree)) {
+ } else if ((all_synced(r) && !p->agree)
+ || (p->proposed && p->agree)) {
p->port_role_transition_sm_state =
- PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED;
+ PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED_EXEC;
}
}
break;
- case PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED:
+ case PORT_ROLE_TRANSITION_SM_ALTERNATE_AGREED_EXEC:
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;
/* no break */
case PORT_ROLE_TRANSITION_SM_BLOCK_PORT:
if (check_selected_role_change(p, ROLE_ALTERNATE)) {
- break;
- }
- else if (p->selected && !p->updt_info && !p->learning &&
- !p->forwarding) {
+ /* Global transition. */
+ } else if (p->selected && !p->updt_info && !p->learning &&
+ !p->forwarding) {
p->port_role_transition_sm_state =
PORT_ROLE_TRANSITION_SM_ALTERNATE_PORT_EXEC;
}
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();
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));
if (!p->learn) {
p->port_state_transition_sm_state =
PORT_STATE_TRANSITION_SM_DISCARDING_EXEC;
- }
- else if (p->forward) {
+ } else if (p->forward) {
p->port_state_transition_sm_state =
PORT_STATE_TRANSITION_SM_FORWARDING_EXEC;
}
if (p->tc_while == 0 && p->send_rstp == true) {
p->tc_while = r->bridge_hello_time + 1;
p->new_info = true;
- }
- else if (p->tc_while == 0 && p->send_rstp == false) {
+ } else if (p->tc_while == 0 && p->send_rstp == false) {
p->tc_while = r->bridge_max_age + r->bridge_forward_delay;
}
}
struct rstp_port *p1;
r = p->rstp;
- if (r->ports_count > 0) {
- LIST_FOR_EACH (p1, node, &r->ports) {
- /* Set tc_prop on every port, except the one calling this
- * function.
- */
- if (p1->port_number != p->port_number) {
- p1->tc_prop = true;
- }
+ HMAP_FOR_EACH (p1, node, &r->ports) {
+ /* Set tc_prop on every port, except the one calling this
+ * function. */
+ if (p1->port_number != p->port_number) {
+ p1->tc_prop = true;
}
}
}
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_LEARNING;
/* no break */
case TOPOLOGY_CHANGE_SM_LEARNING:
- if ((p->role != ROLE_ROOT) && (p->role != ROLE_DESIGNATED) &&
+ if (p->role != ROLE_ROOT && p->role != ROLE_DESIGNATED &&
!(p->learn || p->learning) && !(p->rcvd_tc || p->rcvd_tcn ||
- p->rcvd_tc_ack || p->tc_prop)) {
+ p->rcvd_tc_ack || p->tc_prop)) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_INACTIVE_EXEC;
- }
- else if (p->rcvd_tc || p->rcvd_tcn || p->rcvd_tc_ack || p->tc_prop) {
+ } else if (p->rcvd_tc || p->rcvd_tcn || p->rcvd_tc_ack || p->tc_prop) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_LEARNING_EXEC;
- }
- else if (((p->role == ROLE_ROOT) || (p->role == ROLE_DESIGNATED)) &&
- p->forward && !p->oper_edge) {
+ } else if ((p->role == ROLE_ROOT || p->role == ROLE_DESIGNATED)
+ && p->forward && !p->oper_edge) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_DETECTED_EXEC;
}
break;
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_ACTIVE;
/* no break */
case TOPOLOGY_CHANGE_SM_ACTIVE:
- if (((p->role != ROLE_ROOT) && (p->role != ROLE_DESIGNATED)) ||
- p->oper_edge) {
+ if ((p->role != ROLE_ROOT && p->role != ROLE_DESIGNATED)
+ || p->oper_edge) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_LEARNING_EXEC;
- }
- else if (p->rcvd_tcn) {
+ } else if (p->rcvd_tcn) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_NOTIFIED_TCN_EXEC;
- }
- else if (p->rcvd_tc) {
+ } else if (p->rcvd_tc) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_NOTIFIED_TC_EXEC;
- }
- else if (p->tc_prop && !p->oper_edge) {
+ } else if (p->tc_prop && !p->oper_edge) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_PROPAGATING_EXEC;
- }
- else if (p->rcvd_tc_ack) {
+ } else if (p->rcvd_tc_ack) {
p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_ACKNOWLEDGED_EXEC;
}
break;
break;
case TOPOLOGY_CHANGE_SM_NOTIFIED_TCN_EXEC:
new_tc_while(p);
- p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_ACTIVE;
+ p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_NOTIFIED_TC_EXEC;
break;
default:
OVS_NOT_REACHED();
* [17.6] Priority vector calculation helper functions
****************************************************************************/
-/* [17.6]
- * This message priority vector is superior to the port priority vector and
- * will replace it if, and only if, the message priority vector is better
- * than the port priority vector, or the message has been transmitted from the
- * same Designated Bridge and Designated Port as the port priority vector,
- * i.e.,if the following is true:
- * ((RD < RootBridgeID)) ||
- * ((RD == RootBridgeID) && (RPCD < RootPathCost)) ||
- * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
- * (D < designated_bridge_id)) ||
- * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
- * (D == designated_bridge_id) && (PD < designated_port_id)) ||
- * ((D == designated_bridge_id.BridgeAddress) &&
- * (PD == designated_port_id.PortNumber))
- */
-
-/* compare_rstp_priority_vector() compares two struct rstp_priority_vector and
- * returns a value indicating if the first rstp_priority_vector is superior,
- * same or inferior to the second one.
+/* compare_rstp_priority_vectors() compares two struct rstp_priority_vectors
+ * and returns a value indicating if the first rstp_priority_vector is
+ * superior, same or inferior to the second one.
+ *
+ * Zero return value indicates INFERIOR, a non-zero return value indicates
+ * SUPERIOR. When it makes a difference the non-zero return value SAME
+ * indicates the priority vectors are identical (a subset of SUPERIOR).
*/
static enum vector_comparison
-compare_rstp_priority_vector(struct rstp_priority_vector *v1,
- struct rstp_priority_vector *v2)
+compare_rstp_priority_vectors(const struct rstp_priority_vector *v1,
+ const struct rstp_priority_vector *v2)
{
- VLOG_DBG("v1: "RSTP_ID_FMT", %u, "RSTP_ID_FMT", %d",
+ VLOG_DBG("v1: "RSTP_ID_FMT", %u, "RSTP_ID_FMT", %d, %d",
RSTP_ID_ARGS(v1->root_bridge_id), v1->root_path_cost,
- RSTP_ID_ARGS(v1->designated_bridge_id), v1->designated_port_id);
- VLOG_DBG("v2: "RSTP_ID_FMT", %u, "RSTP_ID_FMT", %d",
+ RSTP_ID_ARGS(v1->designated_bridge_id), v1->designated_port_id,
+ v1->bridge_port_id);
+ VLOG_DBG("v2: "RSTP_ID_FMT", %u, "RSTP_ID_FMT", %d, %d",
RSTP_ID_ARGS(v2->root_bridge_id), v2->root_path_cost,
- RSTP_ID_ARGS(v2->designated_bridge_id), v2->designated_port_id);
-
- if ((v1->root_bridge_id < v2->root_bridge_id) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost < v2->root_path_cost)) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost == v2->root_path_cost) &&
- (v1->designated_bridge_id < v2->designated_bridge_id)) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost == v2->root_path_cost) &&
- (v1->designated_bridge_id == v2->designated_bridge_id) &&
- (v1->designated_port_id < v2->designated_port_id))) {
- VLOG_DBG("superior_absolute");
- return SUPERIOR;
- }
- else if (((v1->root_bridge_id > v2->root_bridge_id) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost > v2->root_path_cost)) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost == v2->root_path_cost) &&
- (v1->designated_bridge_id > v2->designated_bridge_id)) ||
- ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost == v2->root_path_cost) &&
- (v1->designated_bridge_id == v2->designated_bridge_id) &&
- (v1->designated_port_id > v2->designated_port_id))) &&
- (v1->designated_bridge_id == v2->designated_bridge_id) &&
- (v1->designated_port_id == v2->designated_port_id)) {
- VLOG_DBG("superior_same_des");
+ RSTP_ID_ARGS(v2->designated_bridge_id), v2->designated_port_id,
+ v2->bridge_port_id);
+
+ /* [17.6]
+ * This message priority vector is superior to the port priority vector and
+ * will replace it if, and only if, the message priority vector is better
+ * than the port priority vector, or the message has been transmitted from
+ * the same Designated Bridge and Designated Port as the port priority
+ * vector, i.e., if the following is true:
+ *
+ * ((RD < RootBridgeID)) ||
+ * ((RD == RootBridgeID) && (RPCD < RootPathCost)) ||
+ * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
+ * (D < designated_bridge_id)) ||
+ * ((RD == RootBridgeID) && (RPCD == RootPathCost) &&
+ * (D == designated_bridge_id) && (PD < designated_port_id)) ||
+ * ((D == designated_bridge_id.BridgeAddress) &&
+ * (PD == designated_port_id.PortNumber))
+ */
+ if ((v1->root_bridge_id < v2->root_bridge_id)
+ || (v1->root_bridge_id == v2->root_bridge_id
+ && v1->root_path_cost < v2->root_path_cost)
+ || (v1->root_bridge_id == v2->root_bridge_id
+ && v1->root_path_cost == v2->root_path_cost
+ && v1->designated_bridge_id < v2->designated_bridge_id)
+ || (v1->root_bridge_id == v2->root_bridge_id
+ && v1->root_path_cost == v2->root_path_cost
+ && v1->designated_bridge_id == v2->designated_bridge_id
+ && v1->designated_port_id < v2->designated_port_id)
+ || (v1->designated_bridge_id == v2->designated_bridge_id
+ && v1->designated_port_id == v2->designated_port_id)) {
+ /* SAME is a subset of SUPERIOR. */
+ if (v1->root_bridge_id == v2->root_bridge_id
+ && v1->root_path_cost == v2->root_path_cost
+ && v1->designated_bridge_id == v2->designated_bridge_id
+ && v1->designated_port_id == v2->designated_port_id) {
+ if (v1->bridge_port_id < v2->bridge_port_id) {
+ VLOG_DBG("superior");
+ return SUPERIOR;
+ }
+ else if (v1->bridge_port_id > v2->bridge_port_id) {
+ VLOG_DBG("inferior");
+ return INFERIOR;
+ }
+ VLOG_DBG("superior_same");
+ return SAME;
+ }
+ VLOG_DBG("superior");
return SUPERIOR;
}
- else if ((v1->root_bridge_id == v2->root_bridge_id) &&
- (v1->root_path_cost == v2->root_path_cost) &&
- (v1->designated_bridge_id == v2->designated_bridge_id) &&
- (v1->designated_port_id == v2->designated_port_id)) {
- VLOG_DBG("same");
- return SAME;
- }
- else {
- VLOG_DBG("inferior");
- return INFERIOR;
- }
+
+ VLOG_DBG("inferior");
+ return INFERIOR;
}
static bool
-rstp_times_equal(struct rstp_times *t1, struct rstp_times *t2) {
- return ((t1->forward_delay == t2->forward_delay) &&
- (t1->hello_time == t2->hello_time) &&
- (t1->max_age == t2->max_age) &&
- (t1->message_age == t2->message_age));
+rstp_times_equal(struct rstp_times *t1, struct rstp_times *t2)
+{
+ return t1->forward_delay == t2->forward_delay
+ && t1->hello_time == t2->hello_time
+ && t1->max_age == t2->max_age
+ && t1->message_age == t2->message_age;
}