[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