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

Daniele Venturino venturino.daniele at gmail.com
Tue Sep 9 10:36:25 UTC 2014


Acked-by: Daniele Venturino <daniele.venturino at m3s.it>

2014-08-21 1:57 GMT+02:00 Jarno Rajahalme <jrajahalme at nicira.com>:

> 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
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>



More information about the dev mailing list