X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Frstp-state-machines.c;h=f55221f3f9ab0cc1a058bd9638593693356acda1;hb=6f17821ed39b7cc54320295621bbe4ff88d55881;hp=4aea49de27a909c886708bc65955cf76c1278e4d;hpb=9efd308e957c26ab42a5210cc9fc7300c7d021f0;p=cascardo%2Fovs.git diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c index 4aea49de2..f55221f3f 100644 --- a/lib/rstp-state-machines.c +++ b/lib/rstp-state-machines.c @@ -38,11 +38,12 @@ #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); @@ -62,6 +63,8 @@ enum bpdu_size { 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, @@ -69,37 +72,66 @@ enum vector_comparison { }; static void decrement_timer(uint16_t *); -static void rstp_send_bpdu(struct rstp_port *, const void *, size_t); -static int validate_received_bpdu(struct rstp_port *, const void *, size_t); +static void rstp_send_bpdu(struct rstp_port *, const void *, size_t) + OVS_REQUIRES(rstp_mutex); +static int validate_received_bpdu(struct rstp_port *, const void *, size_t) + OVS_REQUIRES(rstp_mutex); 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 */ -static int port_role_selection_sm(struct rstp *); +static int port_role_selection_sm(struct rstp *) + OVS_REQUIRES(rstp_mutex); /* Per-Port State Machines */ -static int port_receive_sm(struct rstp_port *); -static int port_protocol_migration_sm(struct rstp_port *); -static int bridge_detection_sm(struct rstp_port *); -static int port_transmit_sm(struct rstp_port *); -static int port_information_sm(struct rstp_port *); -static int port_role_transition_sm(struct rstp_port *); -static int port_state_transition_sm(struct rstp_port *); -static int topology_change_sm(struct rstp_port *); +static int port_receive_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int port_protocol_migration_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int bridge_detection_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int port_transmit_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int port_information_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int port_role_transition_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int port_state_transition_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); +static int topology_change_sm(struct rstp_port *) + OVS_REQUIRES(rstp_mutex); /* port_timers_sm() not defined as a state machine */ void -process_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) +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; @@ -108,15 +140,18 @@ process_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) memcpy(&p->received_bpdu_buffer, bpdu, sizeof(struct rstp_bpdu)); rstp->changes = true; - move_rstp(rstp); + move_rstp__(rstp); } else { - VLOG_DBG("Bad BPDU received"); + VLOG_DBG("%s, port %u: Bad STP or RSTP BPDU received", p->rstp->name, + p->port_number); p->error_count++; } } +/* Returns 0 on success. */ static int validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) + OVS_REQUIRES(rstp_mutex) { /* Validation of received BPDU, see [9.3.4]. */ const struct rstp_bpdu *temp; @@ -126,18 +161,16 @@ validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) 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) { @@ -145,46 +178,46 @@ validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) } else if (temp->bpdu_type == RAPID_SPANNING_TREE_BPDU && bpdu_size >= RAPID_SPANNING_TREE_BPDU_SIZE) { return 0; - } - else { + } else { return -1; } } } /* - * move_rstp() - * This method is invoked to move the State Machines. The SMs move only if the + * move_rstp__() + * This method is invoked to move the State Machines. The SMs move only if the * 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 */ int -move_rstp(struct rstp *rstp) +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++; @@ -197,26 +230,25 @@ move_rstp(struct rstp *rstp) return 0; } -void decrease_rstp_port_timers(struct rstp *r) +void decrease_rstp_port_timers__(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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); + move_rstp__(r); } static void @@ -232,129 +264,143 @@ decrement_timer(uint16_t *timer) static void updt_role_disabled_tree(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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; } } static void clear_reselect_tree(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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; } } void -updt_roles_tree(struct rstp *r) +updt_roles_tree__(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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, + 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()); @@ -362,23 +408,23 @@ updt_roles_tree(struct rstp *r) static void set_selected_tree(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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 port_role_selection_sm(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { enum port_role_selection_state_machine old_state; struct rstp_port *p; @@ -387,9 +433,10 @@ port_role_selection_sm(struct rstp *r) 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); @@ -401,19 +448,17 @@ port_role_selection_sm(struct rstp *r) break; case PORT_ROLE_SELECTION_SM_ROLE_SELECTION_EXEC: clear_reselect_tree(r); - updt_roles_tree(r); + updt_roles_tree__(r); set_selected_tree(r); r->port_role_selection_sm_state = 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; @@ -423,8 +468,8 @@ port_role_selection_sm(struct rstp *r) } if (old_state != r->port_role_selection_sm_state) { r->changes = true; - VLOG_DBG("Port_role_selection_sm %d -> %d", old_state, - r->port_role_selection_sm_state); + VLOG_DBG("%s: Port_role_selection_sm %d -> %d", r->name, + old_state, r->port_role_selection_sm_state); } return 0; } @@ -435,6 +480,7 @@ port_role_selection_sm(struct rstp *r) static void updt_bpdu_version(struct rstp_port *p) /* [17.21.22] */ + OVS_REQUIRES(rstp_mutex) { switch (p->received_bpdu_buffer.bpdu_type) { case CONFIGURATION_BPDU: @@ -454,6 +500,7 @@ updt_bpdu_version(struct rstp_port *p) /* [17.21.22] */ static int port_receive_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum port_receive_state_machine old_state; struct rstp *r; @@ -475,7 +522,11 @@ port_receive_sm(struct rstp_port *p) 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; @@ -487,7 +538,11 @@ port_receive_sm(struct rstp_port *p) 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; @@ -506,6 +561,7 @@ port_receive_sm(struct rstp_port *p) /* [17.24 - Port Protocol Migration state machine] */ static int port_protocol_migration_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum port_protocol_migration_state_machine old_state; struct rstp *r; @@ -515,8 +571,8 @@ port_protocol_migration_sm(struct rstp_port *p) 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; @@ -527,16 +583,15 @@ port_protocol_migration_sm(struct rstp_port *p) /* 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; @@ -555,11 +610,10 @@ port_protocol_migration_sm(struct rstp_port *p) /* 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; } @@ -581,6 +635,7 @@ port_protocol_migration_sm(struct rstp_port *p) /* [17.25 - Bridge Detection state machine] */ static int bridge_detection_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum bridge_detection_state_machine old_state; struct rstp *r; @@ -610,8 +665,9 @@ bridge_detection_sm(struct rstp_port *p) 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; @@ -630,38 +686,40 @@ bridge_detection_sm(struct rstp_port *p) /* [17.26 - Port Transmit state machine] */ static void rstp_send_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size) + OVS_REQUIRES(rstp_mutex) { 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); /* 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, rstp_port_number(p), p->rstp->aux); + p->rstp->send_bpdu(pkt, p->aux, p->rstp->aux); } static void record_agreement(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; 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 { @@ -671,13 +729,14 @@ record_agreement(struct rstp_port *p) static void set_tc_flags(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* Sets rcvd_tc and/or rcvd_tc_ack if the Topology Change and/or Topology * Change Acknowledgment flags, respectively, are set in a ConfigBPDU or * 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; } @@ -686,34 +745,41 @@ set_tc_flags(struct rstp_port *p) } } /* 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; } } static void record_dispute(struct rstp_port *p) + 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; } } static void record_proposal(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { 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; } } static void record_priority(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { p->port_priority.root_bridge_id = p->msg_priority.root_bridge_id; p->port_priority.root_path_cost = p->msg_priority.root_path_cost; @@ -724,6 +790,7 @@ record_priority(struct rstp_port *p) static void record_times(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { p->port_times = p->msg_times; if (p->msg_times.hello_time == 0) { @@ -733,6 +800,7 @@ record_times(struct rstp_port *p) static void updt_rcvd_info_while(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* [17.21.23] * The value assigned to rcvdInfoWhile is the three times the Hello Time, @@ -741,9 +809,9 @@ updt_rcvd_info_while(struct rstp_port *p) */ 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. @@ -765,6 +833,7 @@ time_decode(ovs_be16 encoded) /* [17.21.19] */ static void tx_config(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp_bpdu bpdu; @@ -794,6 +863,7 @@ tx_config(struct rstp_port *p) /* [17.21.20] */ static void tx_rstp(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp_bpdu bpdu; @@ -811,6 +881,7 @@ tx_rstp(struct rstp_port *p) 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; @@ -823,10 +894,9 @@ tx_rstp(struct rstp_port *p) bpdu.flags = PORT_ALT_BACK << ROLE_FLAG_SHIFT; break; case ROLE_DISABLED: - /* should not happen! */ + /* Should not happen! */ VLOG_ERR("%s transmitting bpdu in disabled role on port " - ""RSTP_PORT_ID_FMT"", p->rstp->name, p->port_id); - OVS_NOT_REACHED(); + RSTP_PORT_ID_FMT, p->rstp->name, p->port_id); break; } if (p->agree) { @@ -851,6 +921,7 @@ tx_rstp(struct rstp_port *p) /* [17.21.21] */ static void tx_tcn(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp_bpdu bpdu; @@ -864,6 +935,7 @@ tx_tcn(struct rstp_port *p) static int port_transmit_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum port_transmit_state_machine old_state; struct rstp *r; @@ -899,25 +971,23 @@ port_transmit_sm(struct rstp_port *p) /* no break */ case PORT_TRANSMIT_SM_IDLE: if (p->role == ROLE_DISABLED) { + 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; @@ -968,6 +1038,7 @@ port_transmit_sm(struct rstp_port *p) static int rcv_info(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum vector_comparison cp; bool ct; @@ -989,10 +1060,23 @@ rcv_info(struct rstp_port *p) 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 @@ -1004,72 +1088,65 @@ rcv_info(struct rstp_port *p) * 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; } } static int 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 port_information_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { 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; @@ -1083,11 +1160,13 @@ port_information_sm(struct rstp_port *p) 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; + } else if (p->rcvd_msg) { + p->port_information_sm_state = PORT_INFORMATION_SM_DISABLED_EXEC; } break; case PORT_INFORMATION_SM_AGED_EXEC: @@ -1097,7 +1176,10 @@ port_information_sm(struct rstp_port *p) 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; @@ -1121,13 +1203,21 @@ port_information_sm(struct rstp_port *p) 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; @@ -1142,29 +1232,47 @@ port_information_sm(struct rstp_port *p) 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: @@ -1172,7 +1280,12 @@ port_information_sm(struct rstp_port *p) 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); @@ -1181,7 +1294,12 @@ port_information_sm(struct rstp_port *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); @@ -1189,17 +1307,30 @@ port_information_sm(struct rstp_port *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; @@ -1207,6 +1338,10 @@ port_information_sm(struct rstp_port *p) 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); @@ -1217,7 +1352,12 @@ port_information_sm(struct rstp_port *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(); @@ -1225,8 +1365,8 @@ port_information_sm(struct rstp_port *p) } if (old_state != p->port_information_sm_state) { r->changes = true; - VLOG_DBG("Port_information_sm %d -> %d", old_state, - p->port_information_sm_state); + VLOG_DBG("%s, port %u: Port_information_sm %d -> %d", p->rstp->name, + p->port_number, old_state, p->port_information_sm_state); } return 0; } @@ -1235,46 +1375,47 @@ port_information_sm(struct rstp_port *p) static void set_re_root_tree(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; 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; } } static void set_sync_tree(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; 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; } } static int hello_time(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { return p->designated_times.hello_time; } static int fwd_delay(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { return p->designated_times.forward_delay; } static int forward_delay(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { if (p->send_rstp) { return hello_time(p); @@ -1285,6 +1426,7 @@ forward_delay(struct rstp_port *p) static int edge_delay(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; @@ -1298,9 +1440,10 @@ edge_delay(struct rstp_port *p) static int 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), @@ -1333,16 +1476,15 @@ check_selected_role_change(struct rstp_port *p, int current_role_state) static int re_rooted(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; 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; @@ -1350,15 +1492,14 @@ re_rooted(struct rstp_port *p) static int all_synced(struct rstp *r) + OVS_REQUIRES(rstp_mutex) { 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; @@ -1366,6 +1507,7 @@ all_synced(struct rstp *r) static int port_role_transition_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum port_role_transition_state_machine old_state; struct rstp *r; @@ -1401,10 +1543,9 @@ port_role_transition_sm(struct rstp_port *p) /* 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; } @@ -1419,11 +1560,10 @@ port_role_transition_sm(struct rstp_port *p) /* 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; } @@ -1435,84 +1575,101 @@ port_role_transition_sm(struct rstp_port *p) /* 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; @@ -1521,39 +1678,34 @@ port_role_transition_sm(struct rstp_port *p) /* 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; } @@ -1561,41 +1713,65 @@ port_role_transition_sm(struct rstp_port *p) 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; @@ -1607,42 +1783,46 @@ port_role_transition_sm(struct rstp_port *p) /* 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; @@ -1651,18 +1831,21 @@ port_role_transition_sm(struct rstp_port *p) /* 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(); @@ -1675,7 +1858,6 @@ port_role_transition_sm(struct rstp_port *p) 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)); @@ -1687,50 +1869,55 @@ port_role_transition_sm(struct rstp_port *p) static void enable_learning(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* [17.21.6 enableLearning()] An implementation dependent procedure that * causes the Learning Process (7.8) to start learning from frames received * on the Port. The procedure does not complete until learning has been * enabled. */ - rstp_port_set_state(p, RSTP_LEARNING); + rstp_port_set_state__(p, RSTP_LEARNING); } static void enable_forwarding(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* [17.21.5 enableForwarding()] An implementation dependent procedure that * causes the Forwarding Process (7.7) to start forwarding frames through * the Port. The procedure does not complete until forwarding has been * enabled. */ - rstp_port_set_state(p, RSTP_FORWARDING); + rstp_port_set_state__(p, RSTP_FORWARDING); } static void disable_learning(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* [17.21.4 - disableLearning()] An implementation dependent procedure that * causes the Learning Process (7.8) to stop learning from the source * address of frames received on the Port. The procedure does not complete * until learning has stopped. */ - rstp_port_set_state(p, RSTP_DISCARDING); + rstp_port_set_state__(p, RSTP_DISCARDING); } static void disable_forwarding(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { /* [17.21.3 - disableForwarding()] An implementation dependent procedure * that causes the Forwarding Process (7.7) to stop forwarding frames * through the Port. The procedure does not complete until forwarding has * stopped. */ - rstp_port_set_state(p, RSTP_DISCARDING); + rstp_port_set_state__(p, RSTP_DISCARDING); } static int port_state_transition_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum port_state_transition_state_machine old_state; struct rstp *r; @@ -1768,8 +1955,7 @@ port_state_transition_sm(struct rstp_port *p) 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; } @@ -1803,6 +1989,7 @@ port_state_transition_sm(struct rstp_port *p) static void new_tc_while(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; @@ -1810,8 +1997,7 @@ new_tc_while(struct rstp_port *p) 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; } } @@ -1821,31 +2007,31 @@ new_tc_while(struct rstp_port *p) */ static void set_tc_prop_tree(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { struct rstp *r; 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; } } } static void set_tc_prop_bridge(struct rstp_port *p) /* not specified in 802.1D-2004. */ + OVS_REQUIRES(rstp_mutex) { set_tc_prop_tree(p); /* see 802.1w-2001. */ } static int topology_change_sm(struct rstp_port *p) + OVS_REQUIRES(rstp_mutex) { enum topology_change_state_machine old_state; struct rstp *r; @@ -1876,16 +2062,14 @@ topology_change_sm(struct rstp_port *p) 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; @@ -1899,20 +2083,16 @@ topology_change_sm(struct rstp_port *p) 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; @@ -1937,7 +2117,7 @@ topology_change_sm(struct rstp_port *p) 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(); @@ -1945,8 +2125,8 @@ topology_change_sm(struct rstp_port *p) } if (old_state != p->topology_change_sm_state) { r->changes = true; - VLOG_DBG("Topology_change_sm %d -> %d",old_state, - p->topology_change_sm_state); + VLOG_DBG("%s, port %u: Topology_change_sm %d -> %d", p->rstp->name, + p->port_number, old_state, p->topology_change_sm_state); } return 0; } @@ -1955,82 +2135,84 @@ topology_change_sm(struct rstp_port *p) * [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; }