[ovs-dev] [PATCH v6 13/18] lib/rstp: More robust thread safety.

Jarno Rajahalme jrajahalme at nicira.com
Wed Aug 20 23:57:25 UTC 2014


Current code expects there to be a single thread that is responsible
for creating rstp and creating and deleting rstp_port objects.  rstp
objects are also deleted from other threads, as managed by reference
counting.

rstp port objects are not reference counted, which means that
references to rstp ports may only be held while holding the rstp
mutex, or by the thread that creates and deletes them.

This patch adds reference counting to RSTP ports, which allows ports
to be passed from ofproto-dpif to ofproto-dpif-xlate without using the
RSTP port number.  This simplifies RSTP port reconfiguration, as the
port need not be resynchronized with xlate if just the port number
changes.  This also avoids lookups on the processing of RSTP BPDUs.

This patch also:

1. Exposes the rstp mutex so that related thread safety annotations
   can be used also within rstp-state-machines.c.

2. Internal variants of most setter an getter functions are defined,
   suffixed with two underscores.  These are annotated to be callable
   only when the mutex is held.

3. Port setters were only called in a specific pattern.  The new external
   port setter combines them in a single rspt_port_set() function.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/rstp-common.h            |  202 +++++-----
 lib/rstp-state-machines.c    |  111 ++++--
 lib/rstp-state-machines.h    |   12 +-
 lib/rstp.c                   |  884 +++++++++++++++++++++++++-----------------
 lib/rstp.h                   |  174 ++++++---
 ofproto/ofproto-dpif-xlate.c |   53 +--
 ofproto/ofproto-dpif-xlate.h |    3 +-
 ofproto/ofproto-dpif.c       |   90 ++---
 tests/test-rstp.c            |   36 +-
 9 files changed, 931 insertions(+), 634 deletions(-)

diff --git a/lib/rstp-common.h b/lib/rstp-common.h
index a67115b..6852263 100644
--- a/lib/rstp-common.h
+++ b/lib/rstp-common.h
@@ -261,10 +261,12 @@ enum rstp_rcvd_info {
 };
 
 struct rstp_port {
-    struct rstp *rstp;
-    struct list node; /* Node in rstp->ports list. */
-    void *aux;
-    struct rstp_bpdu received_bpdu_buffer;
+    struct ovs_refcount ref_cnt;
+
+    struct rstp *rstp OVS_GUARDED_BY(rstp_mutex);
+    struct list node OVS_GUARDED_BY(rstp_mutex); /* Node in rstp->ports list. */
+    void *aux OVS_GUARDED_BY(rstp_mutex);
+    struct rstp_bpdu received_bpdu_buffer OVS_GUARDED_BY(rstp_mutex);
     /*************************************************************************
      * MAC status parameters
      ************************************************************************/
@@ -273,10 +275,10 @@ struct rstp_port {
      * to transmit and/or receive frames, and its use is permitted by
      * management.
      */
-    bool mac_operational;
+    bool mac_operational OVS_GUARDED_BY(rstp_mutex);
 
     /* [14.8.2.2] Administrative Bridge Port State */
-    bool is_administrative_bridge_port;
+    bool is_administrative_bridge_port OVS_GUARDED_BY(rstp_mutex);
 
     /* [6.4.3 - operPointToPointMAC]
      *  a) True. The MAC is connected to a point-to-point LAN; i.e., there is
@@ -288,7 +290,7 @@ struct rstp_port {
      *  shall be set True. If adminPointToPointMAC is set to ForceFalse, then
      *  operPointToPointMAC shall be set False.
      */
-    bool oper_point_to_point_mac;
+    bool oper_point_to_point_mac OVS_GUARDED_BY(rstp_mutex);
 
     /* [6.4.3 - adminPointToPointMAC]
      *  a) ForceTrue. The administrator requires the MAC to be treated as if it
@@ -301,7 +303,7 @@ struct rstp_port {
      *     MAC to be determined in accordance with the specific MAC procedures
      *     defined in 6.5.
      */
-    enum rstp_admin_point_to_point_mac_state admin_point_to_point_mac;
+    enum rstp_admin_point_to_point_mac_state admin_point_to_point_mac OVS_GUARDED_BY(rstp_mutex);
 
 
     /*************************************************************************
@@ -312,12 +314,12 @@ struct rstp_port {
     /* [17.13.1 - Admin Edge Port]
      * The AdminEdgePort parameter for the Port (14.8.2).
      */
-    bool admin_edge;
+    bool admin_edge OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.3 - AutoEdge]
      *  The AutoEdgePort parameter for the Port (14.8.2).
      */
-    bool auto_edge;
+    bool auto_edge OVS_GUARDED_BY(rstp_mutex);
 
 
     /*************************************************************************
@@ -327,18 +329,18 @@ struct rstp_port {
     /* Port number and priority
      * >=1 (max 12 bits [9.2.7])
      */
-    uint16_t port_number;
+    uint16_t port_number OVS_GUARDED_BY(rstp_mutex);
 
     /* Port priority
      * Range: 0-240 in steps of 16 (table 17-2)
      */
-    uint8_t priority;
+    uint8_t priority OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.11 - PortPathCost]
      * The Port's contribution, when it is the Root Port, to the Root Path Cost
      * (17.3.1, 17.5, 17.6) for the Bridge.
      */
-    uint32_t port_path_cost;
+    uint32_t port_path_cost OVS_GUARDED_BY(rstp_mutex);
 
     /*************************************************************************
      * The following variables are defined in [17.17 - State machine timers]
@@ -347,19 +349,19 @@ struct rstp_port {
      * The Edge Delay timer. The time remaining, in the absence of a received
      * BPDU, before this port is identified as an operEdgePort.
      */
-    uint16_t edge_delay_while;
+    uint16_t edge_delay_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.2 - fdWhile]
      * The Forward Delay timer. Used to delay Port State transitions until
      * other Bridges have received spanning tree information.
      */
-    uint16_t fd_while;
+    uint16_t fd_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.3 - helloWhen]
      * The Hello timer. Used to ensure that at least one BPDU is transmitted by
      * a Designated Port in each HelloTime period.
      */
-    uint16_t hello_when;
+    uint16_t hello_when OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.4 - mdelayWhile]
      * The Migration Delay timer. Used by the Port Protocol Migration state
@@ -368,13 +370,13 @@ struct rstp_port {
      * BPDU can cause this Port to change the BPDU types it transmits.
      * Initialized to MigrateTime (17.13.9).
      */
-    uint16_t mdelay_while;
+    uint16_t mdelay_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.5 - rbWhile]
      * The Recent Backup timer. Maintained at its initial value, twice
      * HelloTime, while the Port is a Backup Port.
      */
-    uint16_t rb_while;
+    uint16_t rb_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.6 - rcvdInfoWhile]
      * The Received Info timer. The time remaining before the spanning tree
@@ -382,18 +384,18 @@ struct rstp_port {
      * (17.19.22)] is aged out if not refreshed by the receipt of a further
      * Configuration Message.
      */
-    uint16_t rcvd_info_while;
+    uint16_t rcvd_info_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.7 - rrWhile]
      * The Recent Root timer.
      */
-    uint16_t rr_while;
+    uint16_t rr_while OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.17.8 - tcWhile]
      * The Topology Change timer. TCN Messages are sent while this timer is
      * running.
      */
-    uint16_t tc_while;
+    uint16_t tc_while OVS_GUARDED_BY(rstp_mutex);
 
 
     /*************************************************************************
@@ -409,7 +411,7 @@ struct rstp_port {
      * fdbFlush (17.19.7) is set by the topology change state machine if
      * stpVersion (17.19.7) is TRUE.
      */
-    uint32_t ageing_time;
+    uint32_t ageing_time OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.2 - agree]
      * Set if synced is set for all other Ports. An RST BPDU with the Agreement
@@ -417,7 +419,7 @@ struct rstp_port {
      * and when proposed is set.
      * Initialized by Port Information state machine.
      */
-    bool agree;
+    bool agree OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.3 - agreed]
      * Set when an RST BPDU is received with a Port Role of Root, Alternate, or
@@ -427,7 +429,7 @@ struct rstp_port {
      * the Forwarding state without further delay.
      * Initialized by Port Information state machine.
      */
-    bool agreed;
+    bool agreed OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.4 - designatedPriority]
      * The first four components of the Port's designated priority vector
@@ -435,7 +437,7 @@ struct rstp_port {
      * priority vector value is portId (17.19.19).
      * (Fifth component of the structure must not be used)
      */
-    struct rstp_priority_vector designated_priority_vector;
+    struct rstp_priority_vector designated_priority_vector OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.5 - designatedTimes]
      * The designatedTimes variable comprises the set of timer parameter values
@@ -443,10 +445,10 @@ struct rstp_port {
      * update Port Times when updtInfo is set. Updated by the updtRolesTree()
      * procedure (17.21.25).
      */
-    struct rstp_times designated_times;
+    struct rstp_times designated_times OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.6 - disputed] */
-    bool disputed;
+    bool disputed OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.7 - fdbFlush]
      * A boolean. Set by the topology change state machine to instruct the
@@ -456,17 +458,17 @@ struct rstp_port {
      * entries are
      * removed if rstpVersion is TRUE, and immediately if stpVersion is TRUE.
      */
-    uint8_t fdb_flush;
+    uint8_t fdb_flush OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.8 - forward]
      * Initialized by Port State Transition state machine.
      */
-    bool forward;
+    bool forward OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.9 - forwarding]
      * Initialized by Port State Transition state machine.
      */
-    bool forwarding;
+    bool forwarding OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.10 - infoIs]
      * A variable that takes the values Mine, Aged, Received, or Disabled, to
@@ -487,17 +489,17 @@ struct rstp_port {
      *     received BPDU is specified.
      *  d) Finally if the port is disabled, infoIs is Disabled.
      */
-    enum rstp_info_is info_is;
+    enum rstp_info_is info_is OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.11 - learn]
      * Initialized by Port State Transition state machine.
      */
-    bool learn;
+    bool learn OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.12 - learning]
      * Initialized by Port State Transition state machine.
      */
-    bool learning;
+    bool learning OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.13 - mcheck]
      * A boolean. May be set by management to force the Port Protocol Migration
@@ -507,32 +509,32 @@ struct rstp_port {
      * has no effect if stpVersion (17.20.12) is TRUE, i.e., the Bridge is
      * operating in STP Compatibility mode.
      */
-    bool mcheck;
+    bool mcheck OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.14 - msgPriority]
      * The first four components of the message priority vector conveyed in a
      * received BPDU, as defined in 17.6.
      * (Fifth component of the structure must not be used).
      */
-    struct rstp_priority_vector msg_priority;
+    struct rstp_priority_vector msg_priority OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.15 - msgTimes]
      * The msgTimes variable comprises the timer parameter values (Message Age,
      * Max Age, Forward Delay, and Hello Time) conveyed in a received BPDU.
      */
-    struct rstp_times msg_times;
+    struct rstp_times msg_times OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.16 - newInfo]
      * A boolean. Set if a BPDU is to be transmitted. Reset by the Port
      * Transmit state machine.
      */
-    bool new_info;
+    bool new_info OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.17 - operEdge]
      * A boolean. The value of the operEdgePort parameter, as determined by the
      * operation of the Bridge Detection state machine (17.25).
      */
-    bool oper_edge;
+    bool oper_edge OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.18 - portEnabled]
      * A boolean. Set if the Bridge's MAC Relay Entity and Spanning Tree
@@ -545,41 +547,41 @@ struct rstp_port {
      *    c) AuthControlledPortStatus is Authorized [if the port is a network
      *       access port (IEEE Std 802.1X)].
      */
-    bool port_enabled;
+    bool port_enabled OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.19 - portId]
      * The Port Identifier. This variable forms the fifth component of the port
      * priority and designated priority vectors defined in 17.6.
      */
-    uint16_t port_id;
+    uint16_t port_id OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.21 - portPriority]
      * The first four components of the Port's port priority vector value, as
      * defined in 17.6.
      * (Fifth component of the structure must not be used)
      */
-    struct rstp_priority_vector port_priority;
+    struct rstp_priority_vector port_priority OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.22 - portTimes]
      * The portTimes variable comprises the Port's timer parameter values
      * (Message Age, Max Age, Forward Delay, and Hello Time). These timer
      * values are used in BPDUs transmitted from the Port.
      */
-    struct rstp_times port_times;
+    struct rstp_times port_times OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.23 - proposed]
      * Set when an RST BPDU with a Designated Port role and the Proposal flag
      * set is received. If agree is not set, proposed causes sync to be set for
      * all other Ports.of the Bridge.
      */
-    bool proposed;
+    bool proposed OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.24 - proposing]
      * Set by a Designated Port that is not Forwarding, and conveyed to the
      * Root Port or Alternate Port of a neighboring Bridge in the Proposal flag
      * of an RST BPDU (9.3.3).
      */
-    bool proposing;
+    bool proposing OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.25 - rcvdBPDU]
      * A boolean. Set by system dependent processes, this variable notifies the
@@ -587,84 +589,84 @@ struct rstp_port {
      * TCN, or RST BPDU (9.3.1, 9.3.2, 9.3.3) is received on the Port. Reset
      * by the Port Receive state machine.
      */
-    bool rcvd_bpdu;
+    bool rcvd_bpdu OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.26 - rcvdInfo]
      * Set to the result of the rcvInfo() procedure (17.21.8).
      */
-    enum rstp_rcvd_info rcvd_info;
+    enum rstp_rcvd_info rcvd_info OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.27 - rcvdMsg] */
-    bool rcvd_msg;
+    bool rcvd_msg OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.28 - rcvdRSTP] */
-    bool rcvd_rstp;
+    bool rcvd_rstp OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.29 - rcvdSTP] */
-    bool rcvd_stp;
+    bool rcvd_stp OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.30 - rcvdTc] */
-    bool rcvd_tc;
+    bool rcvd_tc OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.31 - rcvdTcAck] */
-    bool rcvd_tc_ack;
+    bool rcvd_tc_ack OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.32 - rcvdTcn] */
-    bool rcvd_tcn;
+    bool rcvd_tcn OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.33 - reRoot] */
-    bool re_root;
+    bool re_root OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.34 - reselect] */
-    bool reselect;
+    bool reselect OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.35 - role]
      * The assigned Port Role (17.7).
      */
-    enum rstp_port_role role;
+    enum rstp_port_role role OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.36 - selected]
      * A boolean. See 17.28, 17.21.16.
      */
-    bool selected;
+    bool selected OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.37 - selectedRole]
      * The newly computed role for the Port (17.7, 17.28, 17.21.25, 17.19.35).
      */
-    enum rstp_port_role selected_role;
+    enum rstp_port_role selected_role OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.38 - sendRSTP]
      * A boolean. See 17.24, 17.26.
      */
-    bool send_rstp;
+    bool send_rstp OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.39 - sync]
      * A boolean. See 17.10.
      */
-    bool sync;
+    bool sync OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.40 - synced]
      * A boolean. See 17.10.
      */
-    bool synced;
+    bool synced OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.41 - tcAck]
      * A boolean. Set if a Configuration Message with a topology change
      * acknowledge flag set is to be transmitted.
      */
-    bool tc_ack;
+    bool tc_ack OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.42 - tcProp]
      * A boolean. Set by the Topology Change state machine of any other Port,
      * to indicate that a topology change should be propagated through this
      * Port.
      */
-    bool tc_prop;
+    bool tc_prop OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.43 - tick]
      * A boolean. See 17.22.
      */
-    bool tick;
+    bool tick OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.44 - txCount]
      * A counter. Incremented by the Port Transmission (17.26) state machine on
@@ -672,58 +674,58 @@ struct rstp_port {
      * machine (17.22) once a second. Transmissions are delayed if txCount
      * reaches TxHoldCount (17.13.12).
      */
-    uint16_t tx_count;
+    uint16_t tx_count OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.19.45 - updtInfo]
      * A boolean. Set by the Port Role Selection state machine (17.28,
      * 17.21.25) to tell the Port Information state machine that it should copy
      * designatedPriority to portPriority and designatedTimes to portTimes.
      */
-    bool updt_info;
+    bool updt_info OVS_GUARDED_BY(rstp_mutex);
 
     /* Counter for RSTP received frames - for rstpd */
     uint32_t rx_rstp_bpdu_cnt;
 
     /* Counter for bad RSTP received frames */
-    uint32_t error_count;
+    uint32_t error_count OVS_GUARDED_BY(rstp_mutex);
 
     /* [14.8.2.1.3] Outputs
      * a) Uptime count in seconds of the time elapsed since the Port was last
      *    reset or initialized.
      */
-    uint32_t uptime;
+    uint32_t uptime OVS_GUARDED_BY(rstp_mutex);
 
-    enum rstp_state rstp_state;
-    bool state_changed;
+    enum rstp_state rstp_state OVS_GUARDED_BY(rstp_mutex);
+    bool state_changed OVS_GUARDED_BY(rstp_mutex);
 
     /* Per-port state machines state */
-    enum port_receive_state_machine port_receive_sm_state;
-    enum port_protocol_migration_state_machine port_protocol_migration_sm_state;
-    enum bridge_detection_state_machine bridge_detection_sm_state;
-    enum port_transmit_state_machine port_transmit_sm_state;
-    enum port_information_state_machine port_information_sm_state;
-    enum port_role_transition_state_machine port_role_transition_sm_state;
-    enum port_state_transition_state_machine port_state_transition_sm_state;
-    enum topology_change_state_machine topology_change_sm_state;
+    enum port_receive_state_machine port_receive_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum port_protocol_migration_state_machine port_protocol_migration_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum bridge_detection_state_machine bridge_detection_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum port_transmit_state_machine port_transmit_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum port_information_state_machine port_information_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum port_role_transition_state_machine port_role_transition_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum port_state_transition_state_machine port_state_transition_sm_state OVS_GUARDED_BY(rstp_mutex);
+    enum topology_change_state_machine topology_change_sm_state OVS_GUARDED_BY(rstp_mutex);
 };
 
 struct rstp {
-    struct list node;   /* Node in rstp instances list */
+    struct list node OVS_GUARDED_BY(rstp_mutex);   /* In rstp instances list */
     char *name;     /* Bridge name. */
 
     /* Changes in last SM execution. */
-    bool changes;
+    bool changes OVS_GUARDED_BY(rstp_mutex);
 
     /* Per-bridge state machines state */
-    enum port_role_selection_state_machine port_role_selection_sm_state;
+    enum port_role_selection_state_machine port_role_selection_sm_state OVS_GUARDED_BY(rstp_mutex);
 
     /* Bridge MAC address
      * (stored in the least significant 48 bits of rstp_identifier).
      */
-    rstp_identifier address; /* [7.12.5] */
+    rstp_identifier address OVS_GUARDED_BY(rstp_mutex); /* [7.12.5] */
 
     /* Bridge priority */
-    uint16_t priority;      /* Valid values: 0-61440 in steps of 4096 */
+    uint16_t priority OVS_GUARDED_BY(rstp_mutex);      /* Valid values: 0-61440 in steps of 4096 */
 
     /*************************************************************************
      * [17.3 - RSTP performance parameters]
@@ -755,45 +757,45 @@ struct rstp {
     /* [17.13.2 - Ageing Time]
      * The Ageing Time parameter for the Bridge (7.9.2, Table 7-5).
      */
-    uint32_t ageing_time;
+    uint32_t ageing_time OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.4 - Force Protocol Version]
      * The Force Protocol Version parameter for the Bridge (17.4, 14.8.1).
      * This can take the value 0 (STP Compatibility mode) or 2 (the default,
      * normal operation).
      */
-    enum rstp_force_protocol_version force_protocol_version;
+    enum rstp_force_protocol_version force_protocol_version OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.5 - Bridge Forward Delay]
      *  The delay used by STP Bridges (17.4) to transition Root and Designated
      * Ports to Forwarding (Table 17-1).
      */
-    uint16_t bridge_forward_delay;
+    uint16_t bridge_forward_delay OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.6 - Bridge Hello Time]
      *  The interval between periodic transmissions of Configuration Messages
      * by Designated Ports (Table 17-1).
      */
-    uint16_t bridge_hello_time;
+    uint16_t bridge_hello_time OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.8 - Bridge Max Age]
      * The maximum age of the information transmitted by the Bridge when it is
      * the Root Bridge (Table 17-1).
      */
-    uint16_t bridge_max_age;
+    uint16_t bridge_max_age OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.9 - Migrate Time]
      * The initial value of the mdelayWhile and edgeDelayWhile timers (17.17.4,
      * 17.17.1), fixed for all RSTP implementations conforming to this
      * specification (Table 17-1).
      */
-    uint16_t migrate_time;
+    uint16_t migrate_time OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.13.12 - Transmit Hold Count]
      * The Transmit Hold Count (Table 17-1) used by the Port Transmit state
      * machine to limit transmission rate.
      */
-    uint16_t transmit_hold_count;
+    uint16_t transmit_hold_count OVS_GUARDED_BY(rstp_mutex);
 
 
     /*************************************************************************
@@ -805,7 +807,7 @@ struct rstp {
      * causes all state machines, including per Port state machines, to
      * continuously execute their initial state.
      */
-    bool begin;
+    bool begin OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.18.2 BridgeIdentifier]
      * The unique Bridge Identifier assigned to this Bridge, comprising two
@@ -815,33 +817,33 @@ struct rstp {
      * Address (7.12.5), which guarantees uniqueness of the Bridge Identifiers
      * of different Bridges.
      */
-    rstp_identifier bridge_identifier;
+    rstp_identifier bridge_identifier OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.8.3 BridgePriority]
      * The bridge priority vector, as defined in 17.6. The first (RootBridgeID)
      * and third (DesignatedBridgeID) components are both equal to the value
      * of the Bridge Identifier (17.18.2). The other components are zero.
      */
-    struct rstp_priority_vector bridge_priority;
+    struct rstp_priority_vector bridge_priority OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.18.4 - BridgeTimes]
      * BridgeTimes comprises four components: the current values of Bridge
      * Forward Delay, Bridge Hello Time, Bridge Max Age (17.13, Table 17-1),
      * and a Message Age of zero.
      */
-    struct rstp_times bridge_times;
+    struct rstp_times bridge_times OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.18.6 - rootPriority]
      * The first four components of the Bridge's root priority vector, as
      * defined in 17.6.
      */
-    struct rstp_priority_vector root_priority;
+    struct rstp_priority_vector root_priority OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.18.5 - rootPortId]
      * The Port Identifier of the Root Port. This is the fifth component of
      * the root priority vector, as defined in 17.6.
      */
-    uint16_t root_port_id;
+    uint16_t root_port_id OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.18.7 - rootTimes]
      * The rootTimes variable comprises the Bridge's operational timer
@@ -849,23 +851,23 @@ struct rstp {
      * derived from the values stored in portTimes (17.19.22) for the Root Port
      * or from BridgeTimes (17.18.4).
      */
-    struct rstp_times root_times;
+    struct rstp_times root_times OVS_GUARDED_BY(rstp_mutex);
 
     /* 17.20 State machine conditions and parameters */
 
     /* [17.20.11] rstpVersion
      * TRUE if Force Protocol Version (17.13.4) is greater than or equal to 2.
      */
-    bool rstp_version;
+    bool rstp_version OVS_GUARDED_BY(rstp_mutex);
 
     /* [17.20.12] stpVersion
      * TRUE if Force Protocol Version (17.13.4) is less than 2.
      */
-    bool stp_version;
+    bool stp_version OVS_GUARDED_BY(rstp_mutex);
 
     /* Ports */
-    struct list ports;
-    uint16_t ports_count;
+    struct list ports OVS_GUARDED_BY(rstp_mutex);
+    uint16_t ports_count OVS_GUARDED_BY(rstp_mutex);
 
     struct ovs_refcount ref_cnt;
 
diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c
index b70b9da..297f7ea 100644
--- a/lib/rstp-state-machines.c
+++ b/lib/rstp-state-machines.c
@@ -69,8 +69,10 @@ 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
@@ -79,20 +81,31 @@ compare_rstp_priority_vector(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;
 
@@ -108,9 +121,9 @@ 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("%s, port %u: Bad BPDU received", p->rstp->name,
+        VLOG_DBG("%s, port %u: Bad RSTP BPDU received", p->rstp->name,
                  p->port_number);
         p->error_count++;
     }
@@ -118,6 +131,7 @@ process_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
 
 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;
@@ -154,8 +168,8 @@ validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
 }
 
 /*
- * 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
@@ -164,7 +178,8 @@ validate_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
  */
 #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;
@@ -198,7 +213,8 @@ 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;
 
@@ -217,7 +233,7 @@ void decrease_rstp_port_timers(struct rstp *r)
         }
     }
     r->changes = true;
-    move_rstp(r);
+    move_rstp__(r);
 }
 
 static void
@@ -233,6 +249,7 @@ decrement_timer(uint16_t *timer)
 
 static void
 updt_role_disabled_tree(struct rstp *r)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
 
@@ -245,6 +262,7 @@ updt_role_disabled_tree(struct rstp *r)
 
 static void
 clear_reselect_tree(struct rstp *r)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
 
@@ -256,7 +274,8 @@ clear_reselect_tree(struct rstp *r)
 }
 
 void
-updt_roles_tree(struct rstp *r)
+updt_roles_tree__(struct rstp *r)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
     int vsel;
@@ -363,6 +382,7 @@ updt_roles_tree(struct rstp *r)
 
 static void
 set_selected_tree(struct rstp *r)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
 
@@ -380,6 +400,7 @@ set_selected_tree(struct rstp *r)
 
 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;
@@ -402,7 +423,7 @@ 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;
@@ -436,6 +457,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:
@@ -455,6 +477,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;
@@ -507,6 +530,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;
@@ -582,6 +606,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;
@@ -631,6 +656,7 @@ 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;
@@ -652,11 +678,12 @@ rstp_send_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
     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->port_number, p->rstp->aux);
 }
 
 static void
 record_agreement(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *r;
 
@@ -672,6 +699,7 @@ 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
@@ -695,6 +723,7 @@ set_tc_flags(struct rstp_port *p)
 
 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;
@@ -704,6 +733,7 @@ record_dispute(struct rstp_port *p)
 
 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;
@@ -715,6 +745,7 @@ record_proposal(struct rstp_port *p)
 
 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;
@@ -725,6 +756,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) {
@@ -734,6 +766,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,
@@ -766,6 +799,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;
 
@@ -795,6 +829,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;
 
@@ -852,6 +887,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;
 
@@ -865,6 +901,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;
@@ -971,6 +1008,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;
@@ -1048,6 +1086,7 @@ rcv_info(struct rstp_port *p)
 
 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 &&
@@ -1060,6 +1099,7 @@ better_or_same_info(struct rstp_port *p, int new_info_is)
 
 static int
 port_information_sm(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex)
 {
     enum port_information_state_machine old_state;
     struct rstp *r;
@@ -1237,6 +1277,7 @@ 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;
@@ -1251,6 +1292,7 @@ set_re_root_tree(struct rstp_port *p)
 
 static void
 set_sync_tree(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *r;
     struct rstp_port *p1;
@@ -1265,18 +1307,21 @@ set_sync_tree(struct rstp_port *p)
 
 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);
@@ -1287,6 +1332,7 @@ forward_delay(struct rstp_port *p)
 
 static int
 edge_delay(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *r;
 
@@ -1300,6 +1346,7 @@ 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)) {
@@ -1335,6 +1382,7 @@ 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;
@@ -1352,6 +1400,7 @@ re_rooted(struct rstp_port *p)
 
 static int
 all_synced(struct rstp *r)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
 
@@ -1368,6 +1417,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;
@@ -1689,50 +1739,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;
@@ -1805,6 +1860,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;
 
@@ -1823,6 +1879,7 @@ 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;
@@ -1842,12 +1899,14 @@ set_tc_prop_tree(struct rstp_port *p)
 
 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;
diff --git a/lib/rstp-state-machines.h b/lib/rstp-state-machines.h
index 7b9f8bc..c43e83f 100644
--- a/lib/rstp-state-machines.h
+++ b/lib/rstp-state-machines.h
@@ -33,10 +33,14 @@
 #include "rstp-common.h"
 
 /* Methods called by the Forwarding Layer, through functions of rstp.h. */
-int move_rstp(struct rstp *);
-void decrease_rstp_port_timers(struct rstp *);
-void process_received_bpdu(struct rstp_port *, const void *, size_t);
+int move_rstp__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+void decrease_rstp_port_timers__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+void process_received_bpdu__(struct rstp_port *, const void *, size_t)
+    OVS_REQUIRES(rstp_mutex);
 
-void updt_roles_tree(struct rstp *);
+void updt_roles_tree__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
 
 #endif /* rstp-state-machines.h */
diff --git a/lib/rstp.c b/lib/rstp.c
index 80479fb..72b5f38 100644
--- a/lib/rstp.c
+++ b/lib/rstp.c
@@ -48,19 +48,72 @@
 
 VLOG_DEFINE_THIS_MODULE(rstp);
 
-static struct ovs_mutex mutex;
+struct ovs_mutex rstp_mutex;
+
 static struct list all_rstps__ = LIST_INITIALIZER(&all_rstps__);
-static struct list *const all_rstps OVS_GUARDED_BY(mutex) = &all_rstps__;
-
-/* Internal use only */
-static void set_port_id__(struct rstp_port *);
-static void update_port_enabled__(struct rstp_port *);
-static void set_bridge_priority__(struct rstp *);
-static void reinitialize_rstp__(struct rstp *);
-static bool is_port_number_available__(struct rstp *, int, struct rstp_port *);
-static uint16_t rstp_first_free_number__(struct rstp *, struct rstp_port *);
-static void rstp_initialize_port_defaults__(struct rstp_port *);
-static void reinitialize_port__(struct rstp_port *);
+static struct list *const all_rstps OVS_GUARDED_BY(rstp_mutex) = &all_rstps__;
+
+/* Internal use only. */
+static void rstp_set_bridge_address__(struct rstp *, rstp_identifier)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_priority__(struct rstp *, int new_priority)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_ageing_time__(struct rstp *, int new_ageing_time)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_force_protocol_version__(struct rstp *,
+                                                     enum rstp_force_protocol_version)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_hello_time__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_max_age__(struct rstp *, int new_max_age)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_forward_delay__(struct rstp *, int new_forward_delay)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_transmit_hold_count__(struct rstp *,
+                                                  int new_transmit_hold_count)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_migrate_time__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_set_bridge_times__(struct rstp *, int new_forward_delay,
+                                    int new_hello_time, int new_max_age,
+                                    int new_message_age)
+    OVS_REQUIRES(rstp_mutex);
+
+static struct rstp_port *rstp_get_port__(struct rstp *rstp,
+                                         uint16_t port_number)
+    OVS_REQUIRES(rstp_mutex);
+static void set_port_id__(struct rstp_port *)
+    OVS_REQUIRES(rstp_mutex);
+static void update_port_enabled__(struct rstp_port *)
+    OVS_REQUIRES(rstp_mutex);
+static void set_bridge_priority__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+static void reinitialize_rstp__(struct rstp *)
+    OVS_REQUIRES(rstp_mutex);
+static bool is_port_number_available__(struct rstp *, int, struct rstp_port *)
+    OVS_REQUIRES(rstp_mutex);
+static uint16_t rstp_first_free_number__(struct rstp *, struct rstp_port *)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_initialize_port_defaults__(struct rstp_port *)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_priority__(struct rstp_port *, int priority)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_port_number__(struct rstp_port *,
+                                        uint16_t port_number)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_path_cost__(struct rstp_port *, uint32_t path_cost)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_administrative_bridge_port__(struct rstp_port *,
+                                                       uint8_t admin_port_state)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_admin_edge__(struct rstp_port *, bool admin_edge)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_auto_edge__(struct rstp_port *, bool auto_edge)
+    OVS_REQUIRES(rstp_mutex);
+static void rstp_port_set_mcheck__(struct rstp_port *, bool mcheck)
+    OVS_REQUIRES(rstp_mutex);
+void reinitialize_port__(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex);
 
 const char *
 rstp_state_name(enum rstp_state state)
@@ -99,9 +152,10 @@ rstp_port_role_name(enum rstp_port_role role)
 }
 
 /* Caller has to hold a reference to prevent 'rstp' from being deleted
- * while we are taking a new reference. */
+ * while taking a new reference. */
 struct rstp *
 rstp_ref(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     if (rstp) {
         ovs_refcount_ref(&rstp->ref_cnt);
@@ -109,21 +163,23 @@ rstp_ref(struct rstp *rstp)
     return rstp;
 }
 
-/* Frees RSTP struct */
+/* Frees RSTP struct when reference count reaches zero. */
 void
 rstp_unref(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     if (rstp && ovs_refcount_unref(&rstp->ref_cnt) == 1) {
-        ovs_mutex_lock(&mutex);
-        if (rstp->ports_count > 0) {
-            struct rstp_port *p;
+        ovs_mutex_lock(&rstp_mutex);
+
+        /* Each RSTP port poits back to struct rstp without holding a
+         * reference for that pointer.  This is OK as we never move
+         * ports from one bridge to another, and holders always
+         * release their ports before releasing the bridge.  This
+         * means that there should be not ports at this time. */
+        ovs_assert(rstp->ports_count == 0);
 
-            LIST_FOR_EACH (p, node, &rstp->ports) {
-                rstp_delete_port(p);
-            }
-        }
         list_remove(&rstp->node);
-        ovs_mutex_unlock(&mutex);
+        ovs_mutex_unlock(&rstp_mutex);
         free(rstp->name);
         free(rstp);
     }
@@ -133,13 +189,15 @@ rstp_unref(struct rstp *rstp)
  * concurrent reinitialization (which can temporarily clear the
  * port_number). */
 int
-rstp_port_number(const struct rstp_port *p)
+rstp_port_get_number(const struct rstp_port *p)
+    OVS_EXCLUDED(rstp_mutex)
 {
     int number;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     number = p->port_number;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
+
     return number;
 }
 
@@ -149,24 +207,33 @@ static void rstp_unixctl_tcn(struct unixctl_conn *, int argc,
 /* Decrements the State Machines' timers. */
 void
 rstp_tick_timers(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
-    decrease_rstp_port_timers(rstp);
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
+    decrease_rstp_port_timers__(rstp);
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 /* Processes an incoming BPDU. */
 void
-rstp_received_bpdu(struct rstp_port *p, const void *bpdu, size_t bpdu_size)
+rstp_port_received_bpdu(struct rstp_port *rp, const void *bpdu,
+                        size_t bpdu_size)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
-    process_received_bpdu(p, bpdu, bpdu_size);
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
+    /* Only process packets on ports that have RSTP enabled. */
+    if (rp && rp->rstp_state != RSTP_DISABLED) {
+        process_received_bpdu__(rp, bpdu, bpdu_size);
+    }
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 void
 rstp_init(void)
+    OVS_EXCLUDED(rstp_mutex)
 {
+    ovs_mutex_init_recursive(&rstp_mutex);
+
     unixctl_command_register("rstp/tcn", "[bridge]", 0, 1, rstp_unixctl_tcn,
                              NULL);
 }
@@ -176,33 +243,31 @@ struct rstp *
 rstp_create(const char *name, rstp_identifier bridge_address,
             void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux),
             void *aux)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     struct rstp *rstp;
 
     VLOG_DBG("Creating RSTP instance");
-    if (ovsthread_once_start(&once)) {
-        ovs_mutex_init_recursive(&mutex);
-        ovsthread_once_done(&once);
-    }
 
     rstp = xzalloc(sizeof *rstp);
     rstp->name = xstrdup(name);
+
+    ovs_mutex_lock(&rstp_mutex);
     /* Set bridge address. */
-    rstp_set_bridge_address(rstp, bridge_address);
+    rstp_set_bridge_address__(rstp, bridge_address);
     /* Set default parameters values. */
-    rstp_set_bridge_priority(rstp, RSTP_DEFAULT_PRIORITY);
-    rstp_set_bridge_ageing_time(rstp, RSTP_DEFAULT_AGEING_TIME);
-    rstp_set_bridge_force_protocol_version(rstp, FPV_DEFAULT);
-    rstp_set_bridge_forward_delay(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
-    rstp_set_bridge_hello_time(rstp);
-    rstp_set_bridge_max_age(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
-    rstp_set_bridge_migrate_time(rstp);
-    rstp_set_bridge_transmit_hold_count(rstp,
-                                        RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
-    rstp_set_bridge_times(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
-                          RSTP_BRIDGE_HELLO_TIME, RSTP_DEFAULT_BRIDGE_MAX_AGE,
-                          0);
+    rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
+    rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
+    rstp_set_bridge_force_protocol_version__(rstp, FPV_DEFAULT);
+    rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
+    rstp_set_bridge_hello_time__(rstp);
+    rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
+    rstp_set_bridge_migrate_time__(rstp);
+    rstp_set_bridge_transmit_hold_count__(rstp,
+                                          RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
+    rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
+                            RSTP_BRIDGE_HELLO_TIME,
+                            RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
     rstp->send_bpdu = send_bpdu;
     rstp->aux = aux;
     rstp->changes = false;
@@ -212,9 +277,8 @@ rstp_create(const char *name, rstp_identifier bridge_address,
     list_init(&rstp->ports);
     ovs_refcount_init(&rstp->ref_cnt);
 
-    ovs_mutex_lock(&mutex);
     list_push_back(all_rstps, &rstp->node);
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     VLOG_DBG("RSTP instance creation done");
     return rstp;
@@ -226,7 +290,7 @@ rstp_create(const char *name, rstp_identifier bridge_address,
  */
 static void
 set_bridge_priority__(struct rstp *rstp)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     rstp->bridge_priority.root_bridge_id = rstp->bridge_identifier;
     rstp->bridge_priority.designated_bridge_id = rstp->bridge_identifier;
@@ -245,48 +309,61 @@ set_bridge_priority__(struct rstp *rstp)
         }
     }
     rstp->changes = true;
-    updt_roles_tree(rstp);
+    updt_roles_tree__(rstp);
 }
 
 /* Sets the bridge address. */
 void
-rstp_set_bridge_address(struct rstp *rstp, rstp_identifier bridge_address)
+rstp_set_bridge_address__(struct rstp *rstp, rstp_identifier bridge_address)
+    OVS_REQUIRES(rstp_mutex)
 {
     VLOG_DBG("%s: set bridge address to: "RSTP_ID_FMT"", rstp->name,
              RSTP_ID_ARGS(bridge_address));
 
-    ovs_mutex_lock(&mutex);
     rstp->address = bridge_address;
     rstp->bridge_identifier = bridge_address;
     set_bridge_priority__(rstp);
-    ovs_mutex_unlock(&mutex);
+}
+
+/* Sets the bridge address. */
+void
+rstp_set_bridge_address(struct rstp *rstp, rstp_identifier bridge_address)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_address__(rstp, bridge_address);
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 const char *
 rstp_get_name(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     char *name;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     name = rstp->name;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
     return name;
 }
 
 rstp_identifier
 rstp_get_bridge_id(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     rstp_identifier bridge_id;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     bridge_id = rstp->bridge_identifier;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
+
     return bridge_id;
 }
 
 /* Sets the bridge priority. */
-void
-rstp_set_bridge_priority(struct rstp *rstp, int new_priority)
+static void
+rstp_set_bridge_priority__(struct rstp *rstp, int new_priority)
+    OVS_REQUIRES(rstp_mutex)
 {
     new_priority = ROUND_DOWN(new_priority, RSTP_PRIORITY_STEP);
 
@@ -294,35 +371,50 @@ rstp_set_bridge_priority(struct rstp *rstp, int new_priority)
         && new_priority <= RSTP_MAX_PRIORITY) {
         VLOG_DBG("%s: set bridge priority to %d", rstp->name, new_priority);
 
-        ovs_mutex_lock(&mutex);
         rstp->priority = new_priority;
         rstp->bridge_identifier &= 0x0000ffffffffffffULL;
         rstp->bridge_identifier |= (uint64_t)new_priority << 48;
         set_bridge_priority__(rstp);
-        ovs_mutex_unlock(&mutex);
     }
 }
 
+void
+rstp_set_bridge_priority(struct rstp *rstp, int new_priority)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_priority__(rstp, new_priority);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
 /* Sets the bridge ageing time. */
 void
-rstp_set_bridge_ageing_time(struct rstp *rstp, int new_ageing_time)
+rstp_set_bridge_ageing_time__(struct rstp *rstp, int new_ageing_time)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (new_ageing_time >= RSTP_MIN_AGEING_TIME
         && new_ageing_time <= RSTP_MAX_AGEING_TIME) {
         VLOG_DBG("%s: set ageing time to %d", rstp->name, new_ageing_time);
 
-        ovs_mutex_lock(&mutex);
         rstp->ageing_time = new_ageing_time;
-        ovs_mutex_unlock(&mutex);
     }
 }
 
+void
+rstp_set_bridge_ageing_time(struct rstp *rstp, int new_ageing_time)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_ageing_time__(rstp, new_ageing_time);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
 /* Reinitializes RSTP when switching from RSTP mode to STP mode
  * or vice versa.
  */
 static void
 reinitialize_rstp__(struct rstp *rstp)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp temp;
     static struct list ports;
@@ -337,19 +429,19 @@ reinitialize_rstp__(struct rstp *rstp)
     /* Initialize rstp. */
     rstp->name = temp.name;
     /* Set bridge address. */
-    rstp_set_bridge_address(rstp, temp.address);
+    rstp_set_bridge_address__(rstp, temp.address);
     /* Set default parameters values. */
-    rstp_set_bridge_priority(rstp, RSTP_DEFAULT_PRIORITY);
-    rstp_set_bridge_ageing_time(rstp, RSTP_DEFAULT_AGEING_TIME);
-    rstp_set_bridge_forward_delay(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
-    rstp_set_bridge_hello_time(rstp);
-    rstp_set_bridge_max_age(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
-    rstp_set_bridge_migrate_time(rstp);
-    rstp_set_bridge_transmit_hold_count(rstp,
-                                        RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
-    rstp_set_bridge_times(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
-                          RSTP_BRIDGE_HELLO_TIME, RSTP_DEFAULT_BRIDGE_MAX_AGE,
-                          0);
+    rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
+    rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
+    rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
+    rstp_set_bridge_hello_time__(rstp);
+    rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
+    rstp_set_bridge_migrate_time__(rstp);
+    rstp_set_bridge_transmit_hold_count__(rstp,
+                                          RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
+    rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
+                            RSTP_BRIDGE_HELLO_TIME,
+                            RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
 
     rstp->send_bpdu = temp.send_bpdu;
     rstp->aux = temp.aux;
@@ -370,16 +462,17 @@ reinitialize_rstp__(struct rstp *rstp)
 }
 
 /* Sets the force protocol version parameter. */
-void
-rstp_set_bridge_force_protocol_version(struct rstp *rstp,
+static void
+rstp_set_bridge_force_protocol_version__(struct rstp *rstp,
                 enum rstp_force_protocol_version new_force_protocol_version)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (new_force_protocol_version != rstp->force_protocol_version &&
             (new_force_protocol_version == FPV_STP_COMPATIBILITY ||
              new_force_protocol_version == FPV_DEFAULT)) {
         VLOG_DBG("%s: set bridge Force Protocol Version to %d", rstp->name,
                  new_force_protocol_version);
-        ovs_mutex_lock(&mutex);
+
         /* [17.13] The Spanning Tree Protocol Entity shall be reinitialized,
          * as specified by the assertion of BEGIN (17.18.1) in the state
          * machine specification.
@@ -394,26 +487,35 @@ rstp_set_bridge_force_protocol_version(struct rstp *rstp,
             rstp->rstp_version = true;
         }
         rstp->changes = true;
-        move_rstp(rstp);
-        ovs_mutex_unlock(&mutex);
+        move_rstp__(rstp);
     }
 }
 
-/* Sets the bridge Hello Time parameter. */
 void
-rstp_set_bridge_hello_time(struct rstp *rstp)
+rstp_set_bridge_force_protocol_version(struct rstp *rstp,
+                enum rstp_force_protocol_version new_force_protocol_version)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_force_protocol_version__(rstp, new_force_protocol_version);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
+/* Sets the bridge Hello Time parameter. */
+static void
+rstp_set_bridge_hello_time__(struct rstp *rstp)
+    OVS_REQUIRES(rstp_mutex)
 {
     VLOG_DBG("%s: set RSTP Hello Time to %d", rstp->name,
              RSTP_BRIDGE_HELLO_TIME);
     /* 2 is the only acceptable value. */
-    ovs_mutex_lock(&mutex);
     rstp->bridge_hello_time = RSTP_BRIDGE_HELLO_TIME;
-    ovs_mutex_unlock(&mutex);
 }
 
 /* Sets the bridge max age parameter. */
-void
-rstp_set_bridge_max_age(struct rstp *rstp, int new_max_age)
+static void
+rstp_set_bridge_max_age__(struct rstp *rstp, int new_max_age)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (new_max_age >= RSTP_MIN_BRIDGE_MAX_AGE &&
         new_max_age <= RSTP_MAX_BRIDGE_MAX_AGE) {
@@ -422,35 +524,52 @@ rstp_set_bridge_max_age(struct rstp *rstp, int new_max_age)
             && (new_max_age >= 2 * rstp->bridge_hello_time)) {
             VLOG_DBG("%s: set RSTP bridge Max Age to %d", rstp->name,
                      new_max_age);
-            ovs_mutex_lock(&mutex);
+
             rstp->bridge_max_age = new_max_age;
             rstp->bridge_times.max_age = new_max_age;
-            ovs_mutex_unlock(&mutex);
         }
     }
 }
 
-/* Sets the bridge forward delay parameter. */
 void
-rstp_set_bridge_forward_delay(struct rstp *rstp, int new_forward_delay)
+rstp_set_bridge_max_age(struct rstp *rstp, int new_max_age)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_max_age__(rstp, new_max_age);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
+/* Sets the bridge forward delay parameter. */
+static void
+rstp_set_bridge_forward_delay__(struct rstp *rstp, int new_forward_delay)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (new_forward_delay >= RSTP_MIN_BRIDGE_FORWARD_DELAY
         && new_forward_delay <= RSTP_MAX_BRIDGE_FORWARD_DELAY) {
         if (2 * (new_forward_delay - 1) >= rstp->bridge_max_age) {
             VLOG_DBG("%s: set RSTP Forward Delay to %d", rstp->name,
                      new_forward_delay);
-            ovs_mutex_lock(&mutex);
             rstp->bridge_forward_delay = new_forward_delay;
             rstp->bridge_times.forward_delay = new_forward_delay;
-            ovs_mutex_unlock(&mutex);
         }
     }
 }
 
-/* Sets the bridge transmit hold count parameter. */
 void
-rstp_set_bridge_transmit_hold_count(struct rstp *rstp,
-                                    int new_transmit_hold_count)
+rstp_set_bridge_forward_delay(struct rstp *rstp, int new_forward_delay)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_forward_delay__(rstp, new_forward_delay);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
+/* Sets the bridge transmit hold count parameter. */
+static void
+rstp_set_bridge_transmit_hold_count__(struct rstp *rstp,
+                                      int new_transmit_hold_count)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
 
@@ -459,34 +578,43 @@ rstp_set_bridge_transmit_hold_count(struct rstp *rstp,
         VLOG_DBG("%s: set RSTP Transmit Hold Count to %d", rstp->name,
                  new_transmit_hold_count);
         /* Resetting txCount on all ports [17.13]. */
-        ovs_mutex_lock(&mutex);
+
         rstp->transmit_hold_count = new_transmit_hold_count;
         if (rstp->ports_count > 0) {
             LIST_FOR_EACH (p, node, &rstp->ports) {
                 p->tx_count = 0;
             }
         }
-        ovs_mutex_unlock(&mutex);
     }
 }
 
-/* Sets the bridge migrate time parameter. */
 void
-rstp_set_bridge_migrate_time(struct rstp *rstp)
+rstp_set_bridge_transmit_hold_count(struct rstp *rstp,
+                                    int new_transmit_hold_count)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_set_bridge_transmit_hold_count__(rstp, new_transmit_hold_count);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
+/* Sets the bridge migrate time parameter. */
+static void
+rstp_set_bridge_migrate_time__(struct rstp *rstp)
+    OVS_REQUIRES(rstp_mutex)
 {
     VLOG_DBG("%s: set RSTP Migrate Time to %d", rstp->name,
              RSTP_MIGRATE_TIME);
     /* 3 is the only acceptable value */
-    ovs_mutex_lock(&mutex);
     rstp->migrate_time = RSTP_MIGRATE_TIME;
-    ovs_mutex_unlock(&mutex);
 }
 
 /* Sets the bridge times. */
-void
-rstp_set_bridge_times(struct rstp *rstp, int new_forward_delay,
-                      int new_hello_time, int new_max_age,
-                      int new_message_age)
+static void
+rstp_set_bridge_times__(struct rstp *rstp, int new_forward_delay,
+                        int new_hello_time, int new_max_age,
+                        int new_message_age)
+    OVS_REQUIRES(rstp_mutex)
 {
     VLOG_DBG("%s: set RSTP times to (%d, %d, %d, %d)", rstp->name,
              new_forward_delay, new_hello_time, new_max_age, new_message_age);
@@ -504,11 +632,12 @@ rstp_set_bridge_times(struct rstp *rstp, int new_forward_delay,
     rstp->bridge_times.message_age = new_message_age;
 }
 
-/* Sets the port id, it is called by rstp_port_set_port_number() or
- * rstp_port_set_priority().
+/* Sets the port id, it is called by rstp_port_set_port_number__() or
+ * rstp_port_set_priority__().
  */
 static void
 set_port_id__(struct rstp_port *p)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *rstp;
 
@@ -520,32 +649,30 @@ set_port_id__(struct rstp_port *p)
 }
 
 /* Sets the port priority. */
-void
-rstp_port_set_priority(struct rstp_port *rstp_port, int new_port_priority)
+static void
+rstp_port_set_priority__(struct rstp_port *port, int priority)
+    OVS_REQUIRES(rstp_mutex)
 {
-    struct rstp *rstp;
-
-    rstp = rstp_port->rstp;
-    if (new_port_priority >= RSTP_MIN_PORT_PRIORITY
-        && new_port_priority <= RSTP_MAX_PORT_PRIORITY) {
-        VLOG_DBG("%s, port %u: set RSTP port priority to %d", rstp->name,
-                 rstp_port->port_number, new_port_priority);
-        ovs_mutex_lock(&mutex);
-        new_port_priority -= new_port_priority % RSTP_STEP_PORT_PRIORITY;
-        rstp_port->priority = new_port_priority;
-        set_port_id__(rstp_port);
-        rstp_port->selected = false;
-        rstp_port->reselect = true;
-        ovs_mutex_unlock(&mutex);
+    if (priority >= RSTP_MIN_PORT_PRIORITY
+        && priority <= RSTP_MAX_PORT_PRIORITY) {
+        VLOG_DBG("%s, port %u: set RSTP port priority to %d", port->rstp->name,
+                 port->port_number, priority);
+
+        priority -= priority % RSTP_STEP_PORT_PRIORITY;
+        port->priority = priority;
+        set_port_id__(port);
+        port->selected = false;
+        port->reselect = true;
     }
 }
 
 /* Checks if a port number is available. */
 static bool
 is_port_number_available__(struct rstp *rstp, int n, struct rstp_port *port)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (n >= 1 && n <= RSTP_MAX_PORTS) {
-        struct rstp_port *p = rstp_get_port(rstp, n);
+        struct rstp_port *p = rstp_get_port__(rstp, n);
 
         return p == NULL || p == port;
     }
@@ -554,46 +681,40 @@ is_port_number_available__(struct rstp *rstp, int n, struct rstp_port *port)
 
 static uint16_t
 rstp_first_free_number__(struct rstp *rstp, struct rstp_port *rstp_port)
+    OVS_REQUIRES(rstp_mutex)
 {
     int free_number = 1;
 
-    ovs_mutex_lock(&mutex);
     while (free_number <= RSTP_MAX_PORTS) {
         if (is_port_number_available__(rstp, free_number, rstp_port)) {
-            ovs_mutex_unlock(&mutex);
             return free_number;
         }
         free_number++;
     }
-    ovs_mutex_unlock(&mutex);
     VLOG_DBG("%s, No free port number available.", rstp->name);
     return 0;
 }
 
 /* Sets the port number. */
-void
-rstp_port_set_port_number(struct rstp_port *rstp_port,
-                          uint16_t new_port_number)
+static void
+rstp_port_set_port_number__(struct rstp_port *port, uint16_t port_number)
+    OVS_REQUIRES(rstp_mutex)
 {
-    struct rstp *rstp;
-
-    ovs_mutex_lock(&mutex);
-    rstp = rstp_port->rstp;
     /* If new_port_number is available, use it, otherwise use the first free
      * available port number. */
-    rstp_port->port_number =
-        is_port_number_available__(rstp_port->rstp, new_port_number, rstp_port)
-        ? new_port_number
-        : rstp_first_free_number__(rstp, rstp_port);
+    port->port_number =
+        is_port_number_available__(port->rstp, port_number, port)
+        ? port_number
+        : rstp_first_free_number__(port->rstp, port);
 
-    set_port_id__(rstp_port);
+    set_port_id__(port);
     /* [17.13] is not clear. I suppose that a port number change
      * should trigger reselection like a port priority change. */
-    rstp_port->selected = false;
-    rstp_port->reselect = true;
-    ovs_mutex_unlock(&mutex);
-    VLOG_DBG("%s: set new RSTP port number %d", rstp->name,
-             rstp_port->port_number);
+    port->selected = false;
+    port->reselect = true;
+
+    VLOG_DBG("%s: set new RSTP port number %d", port->rstp->name,
+             port->port_number);
 }
 
 /* Converts the link speed to a port path cost [Table 17-3]. */
@@ -616,34 +737,31 @@ rstp_convert_speed_to_cost(unsigned int speed)
 }
 
 /* Sets the port path cost. */
-void
-rstp_port_set_path_cost(struct rstp_port *rstp_port,
-                        uint32_t new_port_path_cost)
+static void
+rstp_port_set_path_cost__(struct rstp_port *port, uint32_t path_cost)
+    OVS_REQUIRES(rstp_mutex)
 {
-    if (new_port_path_cost >= RSTP_MIN_PORT_PATH_COST &&
-            new_port_path_cost <= RSTP_MAX_PORT_PATH_COST) {
-        struct rstp *rstp;
-
-        ovs_mutex_lock(&mutex);
-        rstp = rstp_port->rstp;
-        VLOG_DBG("%s, port %u, set RSTP port path cost to %d", rstp->name,
-                 rstp_port->port_number, new_port_path_cost);
-        rstp_port->port_path_cost = new_port_path_cost;
-        rstp_port->selected = false;
-        rstp_port->reselect = true;
-        ovs_mutex_unlock(&mutex);
+    if (path_cost >= RSTP_MIN_PORT_PATH_COST
+        && path_cost <= RSTP_MAX_PORT_PATH_COST) {
+        VLOG_DBG("%s, port %u, set RSTP port path cost to %d",
+                 port->rstp->name, port->port_number, path_cost);
+
+        port->port_path_cost = path_cost;
+        port->selected = false;
+        port->reselect = true;
     }
 }
 
 /* Gets the root path cost. */
 uint32_t
 rstp_get_root_path_cost(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     uint32_t cost;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     cost = rstp->root_priority.root_path_cost;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
     return cost;
 }
 
@@ -652,13 +770,14 @@ rstp_get_root_path_cost(const struct rstp *rstp)
  */
 bool
 rstp_check_and_reset_fdb_flush(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     bool needs_flush;
     struct rstp_port *p;
 
     needs_flush = false;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     if (rstp->ports_count > 0){
         LIST_FOR_EACH (p, node, &rstp->ports) {
             if (p->fdb_flush) {
@@ -670,67 +789,108 @@ rstp_check_and_reset_fdb_flush(struct rstp *rstp)
             }
         }
     }
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
     return needs_flush;
 }
 
-/* Finds a port whose state has changed.  If successful, stores the port whose
- * state changed in '*portp' and returns true.  If no port has changed, stores
- * NULL in '*portp' and returns false.
+/* Finds a port whose state has changed, and returns the aux pointer set for
+ * the port.  A NULL pointer is returned when no changed port is found.  On
+ * return '*portp' contains the pointer to the rstp port that changed, or NULL
+ * if no changed port can be found.
  *
- * XXX: This function is only called by the main thread, which is also the one
- * that creates and deletes ports.  Otherwise this function is not thread safe,
- * as the returned '*portp' could become stale before it is referenced by the
- * caller. */
-bool
-rstp_get_changed_port(struct rstp *rstp, struct rstp_port **portp)
+ * If '*portp' is passed as non-NULL, it must be the value set by the last
+ * invocation of this function.
+ *
+ * This function may only be called by the thread that creates and deletes
+ * ports.  Otherwise this function is not thread safe, as the returned
+ * '*portp' could become stale before it is used in the next invocation. */
+void *
+rstp_get_next_changed_port_aux(struct rstp *rstp, struct rstp_port **portp)
 {
-    bool changed = false;
+    void *aux = NULL;
 
-    ovs_mutex_lock(&mutex);
-    if (rstp->ports_count > 0) {
+    ovs_mutex_lock(&rstp_mutex);
+    if (*portp == NULL) {
         struct rstp_port *p;
 
         LIST_FOR_EACH (p, node, &rstp->ports) {
             if (p->state_changed) {
                 p->state_changed = false;
+                aux = p->aux;
+                *portp = p;
+                goto out;
+            }
+        }
+    } else { /* continue */
+        struct rstp_port *p = *portp;
+
+        LIST_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
+            if (p->state_changed) {
+                p->state_changed = false;
+                aux = p->aux;
                 *portp = p;
-                changed = true;
-                ovs_mutex_unlock(&mutex);
-                return changed;
+                goto out;
             }
         }
     }
+    /* No changed port found. */
     *portp = NULL;
-    ovs_mutex_unlock(&mutex);
-    return changed;
+out:
+    ovs_mutex_unlock(&rstp_mutex);
+    return aux;
 }
 
 /* Returns the port in 'rstp' with number 'port_number'.
  *
  * XXX: May only be called while concurrent deletion of ports is excluded. */
-struct rstp_port *
-rstp_get_port(struct rstp *rstp, int port_number)
+static struct rstp_port *
+rstp_get_port__(struct rstp *rstp, uint16_t port_number)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *port;
 
-    ovs_mutex_lock(&mutex);
+    ovs_assert(rstp && port_number > 0 && port_number <= RSTP_MAX_PORTS);
+
     if (rstp->ports_count > 0) {
         LIST_FOR_EACH (port, node, &rstp->ports) {
             if (port->port_number == port_number) {
-                ovs_mutex_unlock(&mutex);
                 return port;
             }
         }
     }
-    ovs_mutex_unlock(&mutex);
     return NULL;
 }
 
+struct rstp_port *
+rstp_get_port(struct rstp *rstp, uint16_t port_number)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    struct rstp_port *p;
+
+    ovs_mutex_lock(&rstp_mutex);
+    p = rstp_get_port__(rstp, port_number);
+    ovs_mutex_unlock(&rstp_mutex);
+    return p;
+}
+
+void *
+rstp_get_port_aux(struct rstp *rstp, uint16_t port_number)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    struct rstp_port *p;
+    void *aux;
+
+    ovs_mutex_lock(&rstp_mutex);
+    p = rstp_get_port__(rstp, port_number);
+    aux = p->aux;
+    ovs_mutex_unlock(&rstp_mutex);
+    return aux;
+}
+
 /* Updates the port_enabled parameter. */
 static void
 update_port_enabled__(struct rstp_port *p)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (p->mac_operational && p->is_administrative_bridge_port
         == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED) {
@@ -743,68 +903,61 @@ update_port_enabled__(struct rstp_port *p)
 /* Sets the port MAC_Operational parameter [6.4.2]. */
 void
 rstp_port_set_mac_operational(struct rstp_port *p, bool new_mac_operational)
+    OVS_EXCLUDED(rstp_mutex)
 {
     struct rstp *rstp;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     rstp = p->rstp;
-    p->mac_operational = new_mac_operational;
-    update_port_enabled__(p);
-    rstp->changes = true;
-    move_rstp(rstp);
-    ovs_mutex_unlock(&mutex);
-}
-
-/* Gets the port MAC_Operational parameter [6.4.2]. */
-bool
-rstp_port_get_mac_operational(struct rstp_port *p)
-{
-    bool value;
-
-    ovs_mutex_lock(&mutex);
-    value = p->mac_operational;
-    ovs_mutex_unlock(&mutex);
-    return value;
+    if (p->mac_operational != new_mac_operational) {
+        p->mac_operational = new_mac_operational;
+        update_port_enabled__(p);
+        rstp->changes = true;
+        move_rstp__(rstp);
+    }
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 /* Sets the port Administrative Bridge Port parameter. */
-void
-rstp_port_set_administrative_bridge_port(struct rstp_port *p,
-                                         uint8_t new_admin_port_state)
+static void
+rstp_port_set_administrative_bridge_port__(struct rstp_port *p,
+                                           uint8_t admin_port_state)
+    OVS_REQUIRES(rstp_mutex)
 {
-    if (new_admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED
-        || new_admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED) {
-        ovs_mutex_lock(&mutex);
-        p->is_administrative_bridge_port = new_admin_port_state;
+    if (admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED
+        || admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED) {
+
+        p->is_administrative_bridge_port = admin_port_state;
         update_port_enabled__(p);
-        ovs_mutex_unlock(&mutex);
     }
 }
 
 /* Sets the port oper_point_to_point_mac parameter. */
-void
-rstp_port_set_oper_point_to_point_mac(struct rstp_port *p,
-                                      uint8_t new_oper_p2p_mac)
+static void
+rstp_port_set_oper_point_to_point_mac__(struct rstp_port *p,
+                                        uint8_t new_oper_p2p_mac)
+    OVS_REQUIRES(rstp_mutex)
 {
     if (new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_DISABLED
         || new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_ENABLED) {
-        ovs_mutex_lock(&mutex);
+
         p->oper_point_to_point_mac = new_oper_p2p_mac;
         update_port_enabled__(p);
-        ovs_mutex_unlock(&mutex);
     }
 }
 
 /* Initializes a port with the defaults values for its parameters. */
 static void
 rstp_initialize_port_defaults__(struct rstp_port *p)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
-    rstp_port_set_administrative_bridge_port(p,
-        RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED);
-    rstp_port_set_oper_point_to_point_mac(p, 1);
-    rstp_port_set_path_cost(p, RSTP_DEFAULT_PORT_PATH_COST);
-    rstp_port_set_auto_edge(p, true);
+    rstp_port_set_administrative_bridge_port__(p,
+                                         RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED);
+    rstp_port_set_oper_point_to_point_mac__(p, 1);
+    rstp_port_set_path_cost__(p, RSTP_DEFAULT_PORT_PATH_COST);
+    rstp_port_set_admin_edge__(p, false);
+    rstp_port_set_auto_edge__(p, true);
+    rstp_port_set_mcheck__(p, false);
 
     /* Initialize state machines. */
     p->port_receive_sm_state = PORT_RECEIVE_SM_INIT;
@@ -821,7 +974,7 @@ rstp_initialize_port_defaults__(struct rstp_port *p)
 
 void
 reinitialize_port__(struct rstp_port *p)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port temp_port;
     struct rstp *rstp;
@@ -829,6 +982,8 @@ reinitialize_port__(struct rstp_port *p)
     rstp = p->rstp;
     temp_port = *p;
     memset(p, 0, sizeof(struct rstp_port));
+
+    p->ref_cnt = temp_port.ref_cnt;
     p->rstp = rstp;
     p->node = temp_port.node;
     p->aux = temp_port.aux;
@@ -845,16 +1000,17 @@ reinitialize_port__(struct rstp_port *p)
 
 void
 reinitialize_port(struct rstp_port *p)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     reinitialize_port__(p);
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 /* Sets the port state. */
 void
-rstp_port_set_state(struct rstp_port *p, enum rstp_state state)
-OVS_REQUIRES(mutex)
+rstp_port_set_state__(struct rstp_port *p, enum rstp_state state)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *rstp;
 
@@ -870,76 +1026,99 @@ OVS_REQUIRES(mutex)
     p->rstp_state = state;
 }
 
+void
+rstp_port_set_state(struct rstp_port *p, enum rstp_state state)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_port_set_state__(p, state);
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
 /* Adds a RSTP port. */
 struct rstp_port *
 rstp_add_port(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     struct rstp_port *p = xzalloc(sizeof *p);
 
-    ovs_mutex_lock(&mutex);
+    ovs_refcount_init(&p->ref_cnt);
+
+    ovs_mutex_lock(&rstp_mutex);
     p->rstp = rstp;
-    rstp_port_set_priority(p, RSTP_DEFAULT_PORT_PRIORITY);
-    rstp_port_set_port_number(p, 0);
+    rstp_port_set_priority__(p, RSTP_DEFAULT_PORT_PRIORITY);
+    rstp_port_set_port_number__(p, 0);
     p->aux = NULL;
     rstp_initialize_port_defaults__(p);
     VLOG_DBG("%s: RSTP port "RSTP_PORT_ID_FMT" initialized.", rstp->name,
              p->port_id);
 
-    rstp_port_set_state(p, RSTP_DISCARDING);
+    rstp_port_set_state__(p, RSTP_DISCARDING);
     list_push_back(&rstp->ports, &p->node);
     rstp->ports_count++;
     rstp->changes = true;
-    move_rstp(rstp);
-    ovs_mutex_unlock(&mutex);
+    move_rstp__(rstp);
     VLOG_DBG("%s: added port "RSTP_PORT_ID_FMT"", rstp->name, p->port_id);
+    ovs_mutex_unlock(&rstp_mutex);
     return p;
 }
 
-/* Deletes a RSTP port. */
-void
-rstp_delete_port(struct rstp_port *p)
+/* Caller has to hold a reference to prevent 'rstp_port' from being deleted
+ * while taking a new reference. */
+struct rstp_port *
+rstp_port_ref(const struct rstp_port *rp_)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    struct rstp *rstp;
+    struct rstp_port *rp = CONST_CAST(struct rstp_port *, rp_);
 
-    ovs_mutex_lock(&mutex);
-    rstp = p->rstp;
-    rstp_port_set_state(p, RSTP_DISABLED);
-    list_remove(&p->node);
-    rstp->ports_count--;
-    VLOG_DBG("%s: removed port "RSTP_PORT_ID_FMT"", rstp->name, p->port_id);
-    ovs_mutex_unlock(&mutex);
-    free(p);
+    if (rp) {
+        ovs_refcount_ref(&rp->ref_cnt);
+    }
+    return rp;
 }
 
-/* Sets the port Admin Edge parameter. */
+/* Frees RSTP struct.  This can be caller by any thread. */
 void
-rstp_port_set_admin_edge(struct rstp_port *rstp_port, bool new_admin_edge)
+rstp_port_unref(struct rstp_port *rp)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    if (rstp_port->admin_edge != new_admin_edge) {
+    if (rp && ovs_refcount_unref(&rp->ref_cnt) == 1) {
         struct rstp *rstp;
 
-        ovs_mutex_lock(&mutex);
-        rstp = rstp_port->rstp;
-        VLOG_DBG("%s, port %u: set RSTP Admin Edge to %d", rstp->name,
-                 rstp_port->port_number, new_admin_edge);
-        rstp_port->admin_edge = new_admin_edge;
-        ovs_mutex_unlock(&mutex);
+        ovs_mutex_lock(&rstp_mutex);
+        rstp = rp->rstp;
+        rstp_port_set_state__(rp, RSTP_DISABLED);
+        list_remove(&rp->node);
+        rstp->ports_count--;
+        VLOG_DBG("%s: removed port "RSTP_PORT_ID_FMT"", rstp->name, rp->port_id);
+        ovs_mutex_unlock(&rstp_mutex);
+        free(rp);
+    }
+}
+
+/* Sets the port Admin Edge parameter. */
+static void
+rstp_port_set_admin_edge__(struct rstp_port *port, bool admin_edge)
+     OVS_REQUIRES(rstp_mutex)
+{
+    if (port->admin_edge != admin_edge) {
+        VLOG_DBG("%s, port %u: set RSTP Admin Edge to %d", port->rstp->name,
+                 port->port_number, admin_edge);
+
+        port->admin_edge = admin_edge;
     }
 }
 
 /* Sets the port Auto Edge parameter. */
-void
-rstp_port_set_auto_edge(struct rstp_port *rstp_port, bool new_auto_edge)
+static void
+rstp_port_set_auto_edge__(struct rstp_port *port, bool auto_edge)
+    OVS_REQUIRES(rstp_mutex)
 {
-    if (rstp_port->auto_edge != new_auto_edge) {
-        struct rstp *rstp;
+    if (port->auto_edge != auto_edge) {
+        VLOG_DBG("%s, port %u: set RSTP Auto Edge to %d", port->rstp->name,
+                 port->port_number, auto_edge);
 
-        ovs_mutex_lock(&mutex);
-        rstp = rstp_port->rstp;
-        VLOG_DBG("%s, port %u: set RSTP Auto Edge to %d", rstp->name,
-                 rstp_port->port_number, new_auto_edge);
-        rstp_port->auto_edge = new_auto_edge;
-        ovs_mutex_unlock(&mutex);
+        port->auto_edge = auto_edge;
     }
 }
 
@@ -949,32 +1128,32 @@ rstp_port_set_auto_edge(struct rstp_port *rstp_port, bool new_auto_edge)
  * test whether all STP Bridges (17.4) on the attached LAN have been removed
  * and the Port can continue to transmit RSTP BPDUs. Setting mcheck has no
  * effect if stpVersion (17.20.12) is TRUE, i.e., the Bridge is operating in
- * STP Compatibility. mode.
+ * STP Compatibility mode.
  */
-void
-rstp_port_set_mcheck(struct rstp_port *rstp_port, bool new_mcheck)
+static void
+rstp_port_set_mcheck__(struct rstp_port *port, bool mcheck)
+    OVS_REQUIRES(rstp_mutex)
 {
-    struct rstp *rstp;
+    /* XXX: Should we also support setting this to false, i.e., when port
+     * configuration is changed? */
+    if (mcheck == true && port->rstp->force_protocol_version >= 2) {
+        port->mcheck = true;
 
-    ovs_mutex_lock(&mutex);
-    rstp = rstp_port->rstp;
-    if (new_mcheck == true && rstp_port->rstp->force_protocol_version >= 2) {
-        rstp_port->mcheck = true;
+        VLOG_DBG("%s, port %u: set RSTP mcheck to %d", port->rstp->name,
+                 port->port_number, mcheck);
     }
-    VLOG_DBG("%s, port %u: set RSTP mcheck to %d", rstp->name,
-             rstp_port->port_number, new_mcheck);
-    ovs_mutex_unlock(&mutex);
 }
 
 /* Returns the designated bridge id. */
 rstp_identifier
 rstp_get_designated_id(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     rstp_identifier designated_id;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     designated_id = rstp->root_priority.designated_bridge_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return designated_id;
 }
@@ -982,12 +1161,13 @@ rstp_get_designated_id(const struct rstp *rstp)
 /* Returns the root bridge id. */
 rstp_identifier
 rstp_get_root_id(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     rstp_identifier root_id;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     root_id = rstp->root_priority.root_bridge_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return root_id;
 }
@@ -995,12 +1175,13 @@ rstp_get_root_id(const struct rstp *rstp)
 /* Returns the designated port id. */
 uint16_t
 rstp_get_designated_port_id(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     uint16_t designated_port_id;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     designated_port_id = rstp->root_priority.designated_port_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return designated_port_id;
 }
@@ -1008,12 +1189,13 @@ rstp_get_designated_port_id(const struct rstp *rstp)
 /* Return the bridge port id. */
 uint16_t
 rstp_get_bridge_port_id(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     uint16_t bridge_port_id;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     bridge_port_id = rstp->root_priority.bridge_port_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return bridge_port_id;
 }
@@ -1023,13 +1205,14 @@ rstp_get_bridge_port_id(const struct rstp *rstp)
  */
 bool
 rstp_is_root_bridge(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     bool is_root;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     is_root = rstp->bridge_identifier ==
                 rstp->root_priority.designated_bridge_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return is_root;
 }
@@ -1037,12 +1220,13 @@ rstp_is_root_bridge(const struct rstp *rstp)
 /* Returns the bridge ID of the bridge currently believed to be the root. */
 rstp_identifier
 rstp_get_designated_root(const struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     rstp_identifier designated_root;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     designated_root = rstp->root_priority.designated_bridge_id;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return designated_root;
 }
@@ -1052,98 +1236,105 @@ rstp_get_designated_root(const struct rstp *rstp)
  */
 struct rstp_port *
 rstp_get_root_port(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex)
 {
     struct rstp_port *p;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     if (rstp->ports_count > 0){
         LIST_FOR_EACH (p, node, &rstp->ports) {
             if (p->port_id == rstp->root_port_id) {
-                ovs_mutex_unlock(&mutex);
+                ovs_mutex_unlock(&rstp_mutex);
                 return p;
             }
         }
     }
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
     return NULL;
 }
 
-/* Returns the port ID for 'p'. */
-uint16_t
-rstp_port_get_id(const struct rstp_port *p)
-{
-    uint16_t port_id;
-
-    ovs_mutex_lock(&mutex);
-    port_id = p->port_id;
-    ovs_mutex_unlock(&mutex);
-
-    return port_id;
-}
-
 /* Returns the state of port 'p'. */
 enum rstp_state
 rstp_port_get_state(const struct rstp_port *p)
 {
     enum rstp_state state;
 
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     state = p->rstp_state;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 
     return state;
 }
 
-/* Returns the role of port 'p'. */
-enum rstp_port_role
-rstp_port_get_role(const struct rstp_port *p)
-{
-    enum rstp_port_role role;
-
-    ovs_mutex_lock(&mutex);
-    role = p->role;
-    ovs_mutex_unlock(&mutex);
-
-    return role;
-}
-
-/* Retrieves BPDU transmit and receive counts for 'p'. */
+/* Retrieves port status. */
 void
-rstp_port_get_counts(const struct rstp_port *p,
-        int *tx_count, int *rx_count, int *error_count, int *uptime)
+rstp_port_get_status(const struct rstp_port *p, uint16_t *id,
+                     enum rstp_state *state, enum rstp_port_role *role,
+                     int *tx_count, int *rx_count, int *error_count,
+                     int *uptime)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
+    *id = p->port_id;
+    *state = p->rstp_state;
+    *role = p->role;
+
     *tx_count = p->tx_count;
     *rx_count = p->rx_rstp_bpdu_cnt;
     *error_count = p->error_count;
     *uptime = p->uptime;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 void
-rstp_port_set_aux(struct rstp_port *p, void *aux)
+rstp_port_set(struct rstp_port *port, uint16_t port_num, int priority,
+              uint32_t path_cost, bool is_admin_edge, bool is_auto_edge,
+              bool do_mcheck, void *aux)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
-    p->aux = aux;
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
+    port->aux = aux;
+    rstp_port_set_priority__(port, priority);
+    rstp_port_set_port_number__(port, port_num);
+    rstp_port_set_path_cost__(port, path_cost);
+    rstp_port_set_admin_edge__(port, is_admin_edge);
+    rstp_port_set_auto_edge__(port, is_auto_edge);
+    rstp_port_set_mcheck__(port, do_mcheck);
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
-void *
-rstp_port_get_aux(struct rstp_port *p)
+/* Individual setters only used by test-rstp.c. */
+void
+rstp_port_set_priority(struct rstp_port *port, int priority)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    void *aux;
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_port_set_priority__(port, priority);
+    ovs_mutex_unlock(&rstp_mutex);
+}
 
-    ovs_mutex_lock(&mutex);
-    aux = p->aux;
-    ovs_mutex_unlock(&mutex);
+void
+rstp_port_set_path_cost(struct rstp_port *port, uint32_t path_cost)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    rstp_port_set_path_cost__(port, path_cost);
+    ovs_mutex_unlock(&rstp_mutex);
+}
 
-    return aux;
+void
+rstp_port_set_aux(struct rstp_port *port, void *aux)
+    OVS_EXCLUDED(rstp_mutex)
+{
+    ovs_mutex_lock(&rstp_mutex);
+    port->aux = aux;
+    ovs_mutex_unlock(&rstp_mutex);
 }
 
 /* Unixctl. */
 static struct rstp *
 rstp_find(const char *name)
-    OVS_REQUIRES(mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp *rstp;
 
@@ -1158,8 +1349,9 @@ rstp_find(const char *name)
 static void
 rstp_unixctl_tcn(struct unixctl_conn *conn, int argc,
                  const char *argv[], void *aux OVS_UNUSED)
+    OVS_EXCLUDED(rstp_mutex)
 {
-    ovs_mutex_lock(&mutex);
+    ovs_mutex_lock(&rstp_mutex);
     if (argc > 1) {
         struct rstp *rstp = rstp_find(argv[1]);
         if (!rstp) {
@@ -1167,16 +1359,16 @@ rstp_unixctl_tcn(struct unixctl_conn *conn, int argc,
             goto out;
         }
         rstp->changes = true;
-        move_rstp(rstp);
+        move_rstp__(rstp);
     } else {
         struct rstp *rstp;
         LIST_FOR_EACH (rstp, node, all_rstps) {
             rstp->changes = true;
-            move_rstp(rstp);
+            move_rstp__(rstp);
         }
     }
     unixctl_command_reply(conn, "OK");
 
 out:
-    ovs_mutex_unlock(&mutex);
+    ovs_mutex_unlock(&rstp_mutex);
 }
diff --git a/lib/rstp.h b/lib/rstp.h
index 0e8d101..c6c4a71 100644
--- a/lib/rstp.h
+++ b/lib/rstp.h
@@ -35,6 +35,12 @@
 #include "compiler.h"
 #include "util.h"
 
+/* Thread Safety: Callers passing in RSTP and RSTP port object
+ * pointers must hold a reference to the passed object to ensure that
+ * the object does not become stale while it is being accessed. */
+
+extern struct ovs_mutex rstp_mutex;
+
 #define RSTP_MAX_PORTS 4095
 
 struct ofpbuf;
@@ -119,86 +125,134 @@ struct rstp_port;
 struct ofproto_rstp_settings;
 
 const char *rstp_state_name(enum rstp_state);
+const char *rstp_port_role_name(enum rstp_port_role);
 static inline bool rstp_forward_in_state(enum rstp_state);
 static inline bool rstp_learn_in_state(enum rstp_state);
 static inline bool rstp_should_manage_bpdu(enum rstp_state state);
-const char *rstp_port_role_name(enum rstp_port_role);
 
-void rstp_init(void);
+/* Must be called before any other rstp function is called. */
+void rstp_init(void)
+    OVS_EXCLUDED(rstp_mutex);
 
 struct rstp * rstp_create(const char *, rstp_identifier bridge_id,
                           void (*send_bpdu)(struct ofpbuf *, int port_no,
                                             void *aux),
-                          void *aux);
+                          void *aux)
+    OVS_EXCLUDED(rstp_mutex);
 
-struct rstp *rstp_ref(struct rstp *);
-void rstp_unref(struct rstp *);
+struct rstp *rstp_ref(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_unref(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
 
 /* Functions used outside RSTP, to call functions defined in
    rstp-state-machines.h */
-void rstp_tick_timers(struct rstp *);
-void rstp_received_bpdu(struct rstp_port *, const void *, size_t);
-
-bool rstp_check_and_reset_fdb_flush(struct rstp *);
-bool rstp_get_changed_port(struct rstp *, struct rstp_port **);
+void rstp_tick_timers(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_received_bpdu(struct rstp_port *, const void *bpdu,
+                             size_t bpdu_size)
+    OVS_EXCLUDED(rstp_mutex);
+bool rstp_check_and_reset_fdb_flush(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+void *rstp_get_next_changed_port_aux(struct rstp *, struct rstp_port **)
+    OVS_EXCLUDED(rstp_mutex);
 void rstp_port_set_mac_operational(struct rstp_port *,
-                                   bool new_mac_operational);
-bool rstp_port_get_mac_operational(struct rstp_port *);
+                                   bool new_mac_operational)
+    OVS_EXCLUDED(rstp_mutex);
 
 /* Bridge setters */
-void rstp_set_bridge_address(struct rstp *, rstp_identifier bridge_address);
-void rstp_set_bridge_priority(struct rstp *, int new_priority);
-void rstp_set_bridge_ageing_time(struct rstp *, int new_ageing_time);
+void rstp_set_bridge_address(struct rstp *, rstp_identifier bridge_address)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_set_bridge_priority(struct rstp *, int new_priority)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_set_bridge_ageing_time(struct rstp *, int new_ageing_time)
+    OVS_EXCLUDED(rstp_mutex);
 void rstp_set_bridge_force_protocol_version(struct rstp *,
-                                            enum rstp_force_protocol_version);
-void rstp_set_bridge_hello_time(struct rstp *);
-void rstp_set_bridge_max_age(struct rstp *, int new_max_age);
-void rstp_set_bridge_forward_delay(struct rstp *, int new_forward_delay);
+                                            enum rstp_force_protocol_version)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_set_bridge_max_age(struct rstp *, int new_max_age)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_set_bridge_forward_delay(struct rstp *, int new_forward_delay)
+    OVS_EXCLUDED(rstp_mutex);
 void rstp_set_bridge_transmit_hold_count(struct rstp *,
-                                         int new_transmit_hold_count);
-void rstp_set_bridge_migrate_time(struct rstp *);
-void rstp_set_bridge_times(struct rstp *, int new_forward_delay,
-                           int new_hello_time, int new_max_age,
-                           int new_message_age);
-
-struct rstp_port * rstp_add_port(struct rstp *);
-void reinitialize_port(struct rstp_port *p);
-void rstp_delete_port(struct rstp_port *);
-/* Port setters */
-void rstp_port_set_priority(struct rstp_port *, int new_port_priority);
-void rstp_port_set_port_number(struct rstp_port *, uint16_t new_port_number);
-uint32_t rstp_convert_speed_to_cost(unsigned int speed);
-void rstp_port_set_path_cost(struct rstp_port *, uint32_t new_port_path_cost);
-void rstp_port_set_admin_edge(struct rstp_port *, bool new_admin_edge);
-void rstp_port_set_auto_edge(struct rstp_port *, bool new_auto_edge);
-void rstp_port_set_state(struct rstp_port *, enum rstp_state new_state);
-void rstp_port_set_aux(struct rstp_port *, void *aux);
-void rstp_port_set_administrative_bridge_port(struct rstp_port *, uint8_t);
-void rstp_port_set_oper_point_to_point_mac(struct rstp_port *, uint8_t);
-void rstp_port_set_mcheck(struct rstp_port *, bool new_mcheck);
+                                         int new_transmit_hold_count)
+    OVS_EXCLUDED(rstp_mutex);
 
 /* Bridge getters */
-const char * rstp_get_name(const struct rstp *);
-rstp_identifier rstp_get_root_id(const struct rstp *);
-rstp_identifier rstp_get_bridge_id(const struct rstp *);
-rstp_identifier rstp_get_designated_id(const struct rstp *);
-uint32_t rstp_get_root_path_cost(const struct rstp *);
-uint16_t rstp_get_designated_port_id(const struct rstp *);
-uint16_t rstp_get_bridge_port_id(const struct rstp *);
-struct rstp_port * rstp_get_root_port(struct rstp *);
-rstp_identifier rstp_get_designated_root(const struct rstp *);
-bool rstp_is_root_bridge(const struct rstp *);
-
-/* Port getters */
-int rstp_port_number(const struct rstp_port *);
-struct rstp_port *rstp_get_port(struct rstp *, int port_no);
-uint16_t rstp_port_get_id(const struct rstp_port *);
-enum rstp_state rstp_port_get_state(const struct rstp_port *);
-enum rstp_port_role rstp_port_get_role(const struct rstp_port *);
-void rstp_port_get_counts(const struct rstp_port *, int *tx_count,
-                          int *rx_count, int *error_count, int *uptime);
-void * rstp_port_get_aux(struct rstp_port *);
+const char * rstp_get_name(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+rstp_identifier rstp_get_root_id(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+rstp_identifier rstp_get_bridge_id(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+rstp_identifier rstp_get_designated_id(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+uint32_t rstp_get_root_path_cost(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+uint16_t rstp_get_designated_port_id(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+uint16_t rstp_get_bridge_port_id(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+struct rstp_port * rstp_get_root_port(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+rstp_identifier rstp_get_designated_root(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+bool rstp_is_root_bridge(const struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+
+/* RSTP ports */
+struct rstp_port * rstp_add_port(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+struct rstp_port *rstp_port_ref(const struct rstp_port *)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_unref(struct rstp_port *)
+    OVS_EXCLUDED(rstp_mutex);
+
+uint32_t rstp_convert_speed_to_cost(unsigned int speed);
 
+void rstp_port_set(struct rstp_port *, uint16_t port_num, int priority,
+                   uint32_t path_cost, bool is_admin_edge, bool is_auto_edge,
+                   bool do_mcheck, void *aux)
+    OVS_EXCLUDED(rstp_mutex);
+
+enum rstp_state rstp_port_get_state(const struct rstp_port *)
+    OVS_EXCLUDED(rstp_mutex);
+
+void rstp_port_get_status(const struct rstp_port *, uint16_t *id,
+                          enum rstp_state *state, enum rstp_port_role *role,
+                          int *tx_count, int *rx_count, int *error_count,
+                          int *uptime)
+    OVS_EXCLUDED(rstp_mutex);
+
+void * rstp_get_port_aux(struct rstp *rstp, uint16_t port_number)
+    OVS_EXCLUDED(rstp_mutex);
+
+
+/* Internal API for rstp-state-machines.c */
+
+void rstp_port_set_state__(struct rstp_port *, enum rstp_state state)
+    OVS_REQUIRES(rstp_mutex);
+
+
+/* Internal API for test-rstp.c */
+
+struct rstp_port *rstp_get_port(struct rstp *rstp, uint16_t port_number)
+    OVS_EXCLUDED(rstp_mutex);
+void reinitialize_port(struct rstp_port *p)
+    OVS_EXCLUDED(rstp_mutex);
+
+int rstp_port_get_number(const struct rstp_port *)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_set_priority(struct rstp_port *port, int priority)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_set_aux(struct rstp_port *p, void *aux)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_set_path_cost(struct rstp_port *port, uint32_t path_cost)
+    OVS_EXCLUDED(rstp_mutex);
+void rstp_port_set_state(struct rstp_port *p, enum rstp_state state)
+    OVS_EXCLUDED(rstp_mutex);
+
+
 /* Inline functions. */
 /* Returns true if 'state' is one in which BPDU packets should be received
  * and transmitted on a port, false otherwise.
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 187a3a4..f4d8de2 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -150,7 +150,7 @@ struct xport {
     enum ofputil_port_config config; /* OpenFlow port configuration. */
     enum ofputil_port_state state;   /* OpenFlow port state. */
     int stp_port_no;                 /* STP port number or -1 if not in use. */
-    int rstp_port_no;                /* RSTP port number or -1 if not in use. */
+    struct rstp_port *rstp_port;     /* RSTP port or null. */
 
     struct hmap skb_priorities;      /* Map of 'skb_priority_to_dscp's. */
 
@@ -376,7 +376,7 @@ static void xlate_xbundle_set(struct xbundle *xbundle,
 static void xlate_xport_set(struct xport *xport, odp_port_t odp_port,
                             const struct netdev *netdev, const struct cfm *cfm,
                             const struct bfd *bfd, int stp_port_no,
-                            int rstp_port_no,
+                            const struct rstp_port *rstp_port,
                             enum ofputil_port_config config,
                             enum ofputil_port_state state, bool is_tunnel,
                             bool may_enable);
@@ -514,18 +514,23 @@ xlate_xbundle_set(struct xbundle *xbundle,
 static void
 xlate_xport_set(struct xport *xport, odp_port_t odp_port,
                 const struct netdev *netdev, const struct cfm *cfm,
-                const struct bfd *bfd, int stp_port_no, int rstp_port_no,
+                const struct bfd *bfd, int stp_port_no,
+                const struct rstp_port* rstp_port,
                 enum ofputil_port_config config, enum ofputil_port_state state,
                 bool is_tunnel, bool may_enable)
 {
     xport->config = config;
     xport->state = state;
     xport->stp_port_no = stp_port_no;
-    xport->rstp_port_no = rstp_port_no;
     xport->is_tunnel = is_tunnel;
     xport->may_enable = may_enable;
     xport->odp_port = odp_port;
 
+    if (xport->rstp_port != rstp_port) {
+        rstp_port_unref(xport->rstp_port);
+        xport->rstp_port = rstp_port_ref(rstp_port);
+    }
+
     if (xport->cfm != cfm) {
         cfm_unref(xport->cfm);
         xport->cfm = cfm_ref(cfm);
@@ -604,7 +609,7 @@ xlate_xport_copy(struct xbridge *xbridge, struct xbundle *xbundle,
     xlate_xport_init(new_xcfg, new_xport);
 
     xlate_xport_set(new_xport, xport->odp_port, xport->netdev, xport->cfm,
-                    xport->bfd, xport->stp_port_no, xport->rstp_port_no,
+                    xport->bfd, xport->stp_port_no, xport->rstp_port,
                     xport->config, xport->state, xport->is_tunnel,
                     xport->may_enable);
 
@@ -843,7 +848,8 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
                  struct ofport_dpif *ofport, ofp_port_t ofp_port,
                  odp_port_t odp_port, const struct netdev *netdev,
                  const struct cfm *cfm, const struct bfd *bfd,
-                 struct ofport_dpif *peer, int stp_port_no, int rstp_port_no,
+                 struct ofport_dpif *peer, int stp_port_no,
+                 const struct rstp_port *rstp_port,
                  const struct ofproto_port_queue *qdscp_list, size_t n_qdscp,
                  enum ofputil_port_config config,
                  enum ofputil_port_state state, bool is_tunnel,
@@ -867,7 +873,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
     ovs_assert(xport->ofp_port == ofp_port);
 
     xlate_xport_set(xport, odp_port, netdev, cfm, bfd, stp_port_no,
-                    rstp_port_no, config, state, is_tunnel, may_enable);
+                    rstp_port, config, state, is_tunnel, may_enable);
 
     if (xport->peer) {
         xport->peer->peer = NULL;
@@ -1121,45 +1127,40 @@ stp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
     }
 }
 
-static struct rstp_port *
-xport_get_rstp_port(const struct xport *xport)
+static enum rstp_state
+xport_get_rstp_port_state(const struct xport *xport)
 {
-    return xport->xbridge->rstp && xport->rstp_port_no != -1
-        ? rstp_get_port(xport->xbridge->rstp, xport->rstp_port_no)
-        : NULL;
+    return xport->rstp_port
+        ? rstp_port_get_state(xport->rstp_port)
+        : RSTP_DISABLED;
 }
 
 static bool
 xport_rstp_learn_state(const struct xport *xport)
 {
-    struct rstp_port *rp = xport_get_rstp_port(xport);
-    return !rp || rstp_learn_in_state(rstp_port_get_state(rp));
+    return rstp_learn_in_state(xport_get_rstp_port_state(xport));
 }
 
 static bool
 xport_rstp_forward_state(const struct xport *xport)
 {
-    struct rstp_port *rp = xport_get_rstp_port(xport);
-    return !rp || rstp_forward_in_state(rstp_port_get_state(rp));
+    return rstp_forward_in_state(xport_get_rstp_port_state(xport));
 }
 
 static bool
 xport_rstp_should_manage_bpdu(const struct xport *xport)
 {
-    struct rstp_port *rp = xport_get_rstp_port(xport);
-    return rp && rstp_should_manage_bpdu(rstp_port_get_state(rp));
+    return rstp_should_manage_bpdu(xport_get_rstp_port_state(xport));
 }
 
 static void
 rstp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
 {
-    struct rstp_port *rp = xport_get_rstp_port(xport);
     struct ofpbuf payload = *packet;
     struct eth_header *eth = ofpbuf_data(&payload);
 
-    /* Sink packets on ports that have RSTP disabled when the bridge has
-     * RSTP enabled. */
-    if (!rp || rstp_port_get_state(rp) == RSTP_DISABLED) {
+    /* Sink packets on ports that have no RSTP. */
+    if (!xport->rstp_port) {
         return;
     }
 
@@ -1169,7 +1170,8 @@ rstp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
     }
 
     if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
-        rstp_received_bpdu(rp, ofpbuf_data(&payload), ofpbuf_size(&payload));
+        rstp_port_received_bpdu(xport->rstp_port, ofpbuf_data(&payload),
+                                ofpbuf_size(&payload));
     }
 }
 
@@ -2410,8 +2412,9 @@ process_special(struct xlate_ctx *ctx, const struct flow *flow,
     } else if ((xbridge->stp || xbridge->rstp) &&
                stp_should_process_flow(flow, wc)) {
         if (packet) {
-            xbridge->stp ? stp_process_packet(xport, packet) :
-                           rstp_process_packet(xport, packet);
+            xbridge->stp
+                ? stp_process_packet(xport, packet)
+                : rstp_process_packet(xport, packet);
         }
         return SLOW_STP;
     } else {
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 9962629..3edb620 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -167,7 +167,8 @@ void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
                       struct ofport_dpif *, ofp_port_t, odp_port_t,
                       const struct netdev *, const struct cfm *,
                       const struct bfd *, struct ofport_dpif *peer,
-                      int stp_port_no, int rstp_port_no,
+                      int stp_port_no,
+                      const struct rstp_port *rstp_port,
                       const struct ofproto_port_queue *qdscp,
                       size_t n_qdscp, enum ofputil_port_config,
                       enum ofputil_port_state, bool is_tunnel,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 5d5aa09..207de1d 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -631,16 +631,14 @@ type_run(const char *type)
                 int stp_port = ofport->stp_port
                     ? stp_port_no(ofport->stp_port)
                     : -1;
-                int rstp_port = ofport->rstp_port
-                    ? rstp_port_number(ofport->rstp_port)
-                    : -1;
                 xlate_ofport_set(ofproto, ofport->bundle, ofport,
                                  ofport->up.ofp_port, ofport->odp_port,
                                  ofport->up.netdev, ofport->cfm,
                                  ofport->bfd, ofport->peer, stp_port,
-                                 rstp_port, ofport->qdscp, ofport->n_qdscp,
-                                 ofport->up.pp.config, ofport->up.pp.state,
-                                 ofport->is_tunnel, ofport->may_enable);
+                                 ofport->rstp_port, ofport->qdscp,
+                                 ofport->n_qdscp, ofport->up.pp.config,
+                                 ofport->up.pp.state, ofport->is_tunnel,
+                                 ofport->may_enable);
             }
             xlate_txn_commit();
         }
@@ -1682,9 +1680,7 @@ port_destruct(struct ofport *port_)
     if (port->stp_port) {
         stp_port_disable(port->stp_port);
     }
-    if (port->rstp_port) {
-        rstp_delete_port(port->rstp_port);
-    }
+    set_rstp_port(port_, NULL);
     if (ofproto->sflow) {
         dpif_sflow_del_port(ofproto->sflow, port->odp_port);
     }
@@ -1911,10 +1907,9 @@ static void
 rstp_send_bpdu_cb(struct ofpbuf *pkt, int port_num, void *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_;
-    struct rstp_port *rp = rstp_get_port(ofproto->rstp, port_num);
     struct ofport_dpif *ofport;
 
-    ofport = rstp_port_get_aux(rp);
+    ofport = rstp_get_port_aux(ofproto->rstp, port_num);
     if (!ofport) {
         VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown RSTP port %d",
                      ofproto->up.name, port_num);
@@ -2065,17 +2060,16 @@ rstp_run(struct ofproto_dpif *ofproto)
         long long int now = time_msec();
         long long int elapsed = now - ofproto->rstp_last_tick;
         struct rstp_port *rp;
+        struct ofport_dpif *ofport;
 
         /* Every second, decrease the values of the timers. */
         if (elapsed >= 1000) {
             rstp_tick_timers(ofproto->rstp);
             ofproto->rstp_last_tick = now;
         }
-        while (rstp_get_changed_port(ofproto->rstp, &rp)) {
-            struct ofport_dpif *ofport = rstp_port_get_aux(rp);
-            if (ofport) {
-                update_rstp_port_state(ofport);
-            }
+        rp = NULL;
+        while ((ofport = rstp_get_next_changed_port_aux(ofproto->rstp, &rp))) {
+            update_rstp_port_state(ofport);
         }
         /* FIXME: This check should be done on-event (i.e., when setting
          * p->fdb_flush) and not periodically.
@@ -2213,7 +2207,7 @@ set_stp_port(struct ofport *ofport_,
         }
         return 0;
     } else if (sp && stp_port_no(sp) != s->port_num
-            && ofport == stp_port_get_aux(sp)) {
+               && ofport == stp_port_get_aux(sp)) {
         /* The port-id changed, so disable the old one if it's not
          * already in use by another port. */
         stp_port_disable(sp);
@@ -2323,59 +2317,23 @@ set_rstp_port(struct ofport *ofport_,
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
     struct rstp_port *rp = ofport->rstp_port;
-    int stp_port;
 
     if (!s || !s->enable) {
         if (rp) {
+            rstp_port_unref(rp);
             ofport->rstp_port = NULL;
-            rstp_delete_port(rp);
             update_rstp_port_state(ofport);
         }
         return;
-    } else if (rp && rstp_port_number(rp) != s->port_num
-                  && ofport == rstp_port_get_aux(rp)) {
-        /* The port-id changed, so disable the old one if it's not
-         * already in use by another port. */
-        if (s->port_num != 0) {
-            xlate_txn_start();
-            stp_port = ofport->stp_port ? stp_port_no(ofport->stp_port) : -1;
-            xlate_ofport_set(ofproto, ofport->bundle, ofport,
-                    ofport->up.ofp_port, ofport->odp_port,
-                    ofport->up.netdev, ofport->cfm,
-                    ofport->bfd, ofport->peer, stp_port,
-                    s->port_num,
-                    ofport->qdscp, ofport->n_qdscp,
-                    ofport->up.pp.config, ofport->up.pp.state,
-                    ofport->is_tunnel, ofport->may_enable);
-            xlate_txn_commit();
-        }
-
-        rstp_port_set_aux(rp, ofport);
-        rstp_port_set_priority(rp, s->priority);
-        rstp_port_set_port_number(rp, s->port_num);
-        rstp_port_set_path_cost(rp, s->path_cost);
-        rstp_port_set_admin_edge(rp, s->admin_edge_port);
-        rstp_port_set_auto_edge(rp, s->auto_edge);
-        rstp_port_set_mcheck(rp, s->mcheck);
-
-        update_rstp_port_state(ofport);
-
-        return;
     }
-    rp = ofport->rstp_port = rstp_get_port(ofproto->rstp, s->port_num);
-    /* Enable RSTP on port */
+
+    /* Check if need to add a new port. */
     if (!rp) {
         rp = ofport->rstp_port = rstp_add_port(ofproto->rstp);
     }
-    /* Setters */
-    rstp_port_set_aux(rp, ofport);
-    rstp_port_set_priority(rp, s->priority);
-    rstp_port_set_port_number(rp, s->port_num);
-    rstp_port_set_path_cost(rp, s->path_cost);
-    rstp_port_set_admin_edge(rp, s->admin_edge_port);
-    rstp_port_set_auto_edge(rp, s->auto_edge);
-    rstp_port_set_mcheck(rp, s->mcheck);
 
+    rstp_port_set(rp, s->port_num, s->priority, s->path_cost,
+                  s->admin_edge_port, s->auto_edge, s->mcheck, ofport);
     update_rstp_port_state(ofport);
 }
 
@@ -2393,11 +2351,8 @@ get_rstp_port_status(struct ofport *ofport_,
     }
 
     s->enabled = true;
-    s->port_id = rstp_port_get_id(rp);
-    s->state = rstp_port_get_state(rp);
-    s->role = rstp_port_get_role(rp);
-    rstp_port_get_counts(rp, &s->tx_count, &s->rx_count,
-                         &s->error_count, &s->uptime);
+    rstp_port_get_status(rp, &s->port_id, &s->state, &s->role, &s->tx_count,
+                         &s->rx_count, &s->error_count, &s->uptime);
 }
 
 
@@ -3133,16 +3088,15 @@ port_run(struct ofport_dpif *ofport)
 
     if (ofport->may_enable != enable) {
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
-        ofproto->backer->need_revalidate = REV_PORT_TOGGLED;
-    }
 
-    ofport->may_enable = enable;
+        ofproto->backer->need_revalidate = REV_PORT_TOGGLED;
 
-    if (ofport->rstp_port) {
-        if (rstp_port_get_mac_operational(ofport->rstp_port) != enable) {
+        if (ofport->rstp_port) {
             rstp_port_set_mac_operational(ofport->rstp_port, enable);
         }
     }
+
+    ofport->may_enable = enable;
 }
 
 static int
diff --git a/tests/test-rstp.c b/tests/test-rstp.c
index ad71f04..a365423 100644
--- a/tests/test-rstp.c
+++ b/tests/test-rstp.c
@@ -66,6 +66,7 @@ static struct test_case *
 new_test_case(void)
 {
     struct test_case *tc = xmalloc(sizeof *tc);
+
     tc->n_bridges = 0;
     tc->n_lans = 0;
     return tc;
@@ -86,9 +87,11 @@ send_bpdu(struct ofpbuf *pkt, int port_no, void *b_)
 
         for (i = 0; i < lan->n_conns; i++) {
             struct lan_conn *conn = &lan->conns[i];
+
             if (conn->bridge != b || conn->port_no != port_no) {
                 struct bridge *dst = conn->bridge;
                 struct bpdu *bpdu = &dst->rxq[dst->rxq_head++ % RXQ_SIZE];
+
                 assert(dst->rxq_head - dst->rxq_tail <= RXQ_SIZE);
                 bpdu->data = xmemdup(data, size);
                 bpdu->size = size;
@@ -154,6 +157,7 @@ reconnect_port(struct bridge *b, int port_no, struct lan *new_lan)
     if (old_lan) {
         for (j = 0; j < old_lan->n_conns; j++) {
             struct lan_conn *c = &old_lan->conns[j];
+
             if (c->bridge == b && c->port_no == port_no) {
                 memmove(c, c + 1, sizeof *c * (old_lan->n_conns - j - 1));
                 old_lan->n_conns--;
@@ -166,6 +170,7 @@ reconnect_port(struct bridge *b, int port_no, struct lan *new_lan)
     b->ports[port_no] = new_lan;
     if (new_lan) {
         int conn_no = new_lan->n_conns++;
+
         assert(conn_no < ARRAY_SIZE(new_lan->conns));
         new_lan->conns[conn_no].bridge = b;
         new_lan->conns[conn_no].port_no = port_no;
@@ -241,6 +246,7 @@ dump_bridge_tree(struct test_case *tc, struct bridge *b, int level)
     for (i = 0; i < b->n_ports; i++) {
         struct lan *lan = b->ports[i];
         struct rstp_port *p = rstp_get_port(b->rstp, i);
+
         if (rstp_port_get_state(p) == RSTP_FORWARDING && lan) {
             dump_lan_tree(tc, lan, level + 1);
         }
@@ -262,6 +268,7 @@ dump_lan_tree(struct test_case *tc, struct lan *lan, int level)
     printf("%s\n", lan->name);
     for (i = 0; i < lan->n_conns; i++) {
         struct bridge *b = lan->conns[i].bridge;
+
         dump_bridge_tree(tc, b, level + 1);
     }
 }
@@ -273,15 +280,18 @@ tree(struct test_case *tc)
 
     for (i = 0; i < tc->n_bridges; i++) {
         struct bridge *b = tc->bridges[i];
+
         b->reached = false;
     }
     for (i = 0; i < tc->n_lans; i++) {
         struct lan *lan = tc->lans[i];
+
         lan->reached = false;
     }
     for (i = 0; i < tc->n_bridges; i++) {
         struct bridge *b = tc->bridges[i];
         struct rstp *rstp = b->rstp;
+
         if (rstp_is_root_bridge(rstp)) {
             dump_bridge_tree(tc, b, 0);
         }
@@ -292,6 +302,7 @@ static void
 simulate(struct test_case *tc, int granularity)
 {
     int time, i, round_trips;
+
     for (time = 0; time < 1000 * 180; time += granularity) {
 
         for (i = 0; i < tc->n_bridges; i++) {
@@ -299,12 +310,16 @@ simulate(struct test_case *tc, int granularity)
         }
         for (round_trips = 0; round_trips < granularity; round_trips++) {
             bool any = false;
+
             for (i = 0; i < tc->n_bridges; i++) {
                 struct bridge *b = tc->bridges[i];
+
                 for (; b->rxq_tail != b->rxq_head; b->rxq_tail++) {
                     struct bpdu *bpdu = &b->rxq[b->rxq_tail % RXQ_SIZE];
-                    rstp_received_bpdu(rstp_get_port(b->rstp, bpdu->port_no),
-                            bpdu->data, bpdu->size);
+
+                    rstp_port_received_bpdu(rstp_get_port(b->rstp,
+                                                          bpdu->port_no),
+                                            bpdu->data, bpdu->size);
                     free(bpdu->data);
                     any = true;
                 }
@@ -396,6 +411,7 @@ static bool
 get_int(int *intp)
 {
     char *save_pos = pos;
+
     if (token && isdigit((unsigned char) *token)) {
         *intp = strtol(token, NULL, 0);
         get_token();
@@ -421,6 +437,7 @@ static int
 must_get_int(void)
 {
     int x;
+
     if (!get_int(&x)) {
         err("expected integer");
     }
@@ -442,6 +459,8 @@ test_rstp_main(int argc, char *argv[])
     FILE *input_file;
     int i;
 
+    rstp_init();
+
     vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m");
     vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF);
 
@@ -458,6 +477,7 @@ test_rstp_main(int argc, char *argv[])
     tc = new_test_case();
     for (i = 0; i < 26; i++) {
         char name[2];
+
         name[0] = 'a' + i;
         name[1] = '\0';
         new_lan(tc, name);
@@ -499,6 +519,7 @@ test_rstp_main(int argc, char *argv[])
             if (match("=")) {
                 for (port_no = 1; port_no < MAX_PORTS; port_no++) {
                     struct rstp_port *p = rstp_get_port(bridge->rstp, port_no);
+
                     if (!token || match("X")) {
                         /* Disable port. */
                         reinitialize_port(p);
@@ -565,6 +586,7 @@ test_rstp_main(int argc, char *argv[])
 
             if (match("rootid")) {
                 uint64_t rootid;
+
                 must_match(":");
                 rootid = must_get_int();
                 if (match("^")) {
@@ -594,6 +616,7 @@ test_rstp_main(int argc, char *argv[])
                 for (port_no = 1; port_no < b->n_active_ports; port_no++) {
                     struct rstp_port *p = rstp_get_port(rstp, port_no);
                     enum rstp_state state = rstp_port_get_state(p);
+
                     if (state != RSTP_DISABLED && state != RSTP_FORWARDING) {
                         warn("%s: root port %d in state %s",
                              rstp_get_name(b->rstp), port_no,
@@ -604,6 +627,7 @@ test_rstp_main(int argc, char *argv[])
                 for (port_no = 1; port_no < b->n_active_ports; port_no++) {
                     struct rstp_port *p = rstp_get_port(rstp, port_no);
                     enum rstp_state state;
+
                     if (token == NULL || match("D")) {
                         state = RSTP_DISABLED;
                     } else if (match("Di")) {
@@ -625,8 +649,10 @@ test_rstp_main(int argc, char *argv[])
                     }
                     if (state == RSTP_FORWARDING) {
                         struct rstp_port *root_port = rstp_get_root_port(rstp);
+
                         if (match(":")) {
                             int root_path_cost = must_get_int();
+
                             if (p != root_port) {
                                 warn("%s: port %d is not the root port",
                                      rstp_get_name(rstp), port_no);
@@ -636,7 +662,7 @@ test_rstp_main(int argc, char *argv[])
                                 } else {
                                     warn("%s: (port %d is the root port)",
                                          rstp_get_name(rstp),
-                                         rstp_port_number(root_port));
+                                         rstp_port_get_number(root_port));
                                 }
                             } else if (cost_value != root_path_cost) {
                                 warn("%s: root path cost is %d, should be %d",
@@ -666,14 +692,16 @@ test_rstp_main(int argc, char *argv[])
 
     for (i = 0; i < tc->n_lans; i++) {
         struct lan *lan = tc->lans[i];
+
         free(CONST_CAST(char *, lan->name));
         free(lan);
     }
     for (i = 0; i < tc->n_bridges; i++) {
         struct bridge *bridge = tc->bridges[i];
         int j;
+
         for (j = 1; j < MAX_PORTS; j++) {
-            rstp_delete_port(rstp_get_port(bridge->rstp, j));
+            rstp_port_unref(rstp_get_port(bridge->rstp, j));
         }
         rstp_unref(bridge->rstp);
         free(bridge);
-- 
1.7.10.4




More information about the dev mailing list