LCOV - code coverage report
Current view: top level - lib - rstp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 547 634 86.3 %
Date: 2016-09-14 01:02:56 Functions: 71 79 89.9 %
Branches: 173 303 57.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2011-2015 M3S, Srl - Italy
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : /*
      18                 :            :  * Rapid Spanning Tree Protocol (IEEE 802.1D-2004) public interface.
      19                 :            :  *
      20                 :            :  * Authors:
      21                 :            :  *         Martino Fornasa <mf@fornasa.it>
      22                 :            :  *         Daniele Venturino <daniele.venturino@m3s.it>
      23                 :            :  *         Carlo Andreotti <c.andreotti@m3s.it>
      24                 :            :  *
      25                 :            :  * References to IEEE 802.1D-2004 standard are enclosed in square brackets.
      26                 :            :  * E.g. [17.3], [Table 17-1], etc.
      27                 :            :  *
      28                 :            :  */
      29                 :            : 
      30                 :            : #include <config.h>
      31                 :            : 
      32                 :            : #include "rstp.h"
      33                 :            : #include "rstp-common.h"
      34                 :            : #include "rstp-state-machines.h"
      35                 :            : #include <arpa/inet.h>
      36                 :            : #include <inttypes.h>
      37                 :            : #include <netinet/in.h>
      38                 :            : #include <stdlib.h>
      39                 :            : #include <sys/types.h>
      40                 :            : #include "byte-order.h"
      41                 :            : #include "connectivity.h"
      42                 :            : #include "openvswitch/ofpbuf.h"
      43                 :            : #include "ofproto/ofproto.h"
      44                 :            : #include "dp-packet.h"
      45                 :            : #include "packets.h"
      46                 :            : #include "seq.h"
      47                 :            : #include "unixctl.h"
      48                 :            : #include "util.h"
      49                 :            : #include "openvswitch/vlog.h"
      50                 :            : 
      51                 :       2462 : VLOG_DEFINE_THIS_MODULE(rstp);
      52                 :            : 
      53                 :            : struct ovs_mutex rstp_mutex = OVS_MUTEX_INITIALIZER;
      54                 :            : 
      55                 :            : static struct ovs_list all_rstps__ = OVS_LIST_INITIALIZER(&all_rstps__);
      56                 :            : static struct ovs_list *const all_rstps OVS_GUARDED_BY(rstp_mutex) = &all_rstps__;
      57                 :            : 
      58                 :            : /* Internal use only. */
      59                 :            : static void rstp_set_bridge_address__(struct rstp *, rstp_identifier)
      60                 :            :     OVS_REQUIRES(rstp_mutex);
      61                 :            : static void rstp_set_bridge_priority__(struct rstp *, int new_priority)
      62                 :            :     OVS_REQUIRES(rstp_mutex);
      63                 :            : static void rstp_set_bridge_ageing_time__(struct rstp *, int new_ageing_time)
      64                 :            :     OVS_REQUIRES(rstp_mutex);
      65                 :            : static void rstp_set_bridge_force_protocol_version__(struct rstp *,
      66                 :            :                                                      enum rstp_force_protocol_version)
      67                 :            :     OVS_REQUIRES(rstp_mutex);
      68                 :            : static void rstp_set_bridge_hello_time__(struct rstp *)
      69                 :            :     OVS_REQUIRES(rstp_mutex);
      70                 :            : static void rstp_set_bridge_max_age__(struct rstp *, int new_max_age)
      71                 :            :     OVS_REQUIRES(rstp_mutex);
      72                 :            : static void rstp_set_bridge_forward_delay__(struct rstp *, int new_forward_delay)
      73                 :            :     OVS_REQUIRES(rstp_mutex);
      74                 :            : static void rstp_set_bridge_transmit_hold_count__(struct rstp *,
      75                 :            :                                                   int new_transmit_hold_count)
      76                 :            :     OVS_REQUIRES(rstp_mutex);
      77                 :            : static void rstp_set_bridge_migrate_time__(struct rstp *)
      78                 :            :     OVS_REQUIRES(rstp_mutex);
      79                 :            : static void rstp_set_bridge_times__(struct rstp *, int new_forward_delay,
      80                 :            :                                     int new_hello_time, int new_max_age,
      81                 :            :                                     int new_message_age)
      82                 :            :     OVS_REQUIRES(rstp_mutex);
      83                 :            : 
      84                 :            : static struct rstp_port *rstp_get_port__(struct rstp *rstp,
      85                 :            :                                          uint16_t port_number)
      86                 :            :     OVS_REQUIRES(rstp_mutex);
      87                 :            : static void set_port_id__(struct rstp_port *)
      88                 :            :     OVS_REQUIRES(rstp_mutex);
      89                 :            : static void update_port_enabled__(struct rstp_port *)
      90                 :            :     OVS_REQUIRES(rstp_mutex);
      91                 :            : static void set_bridge_priority__(struct rstp *)
      92                 :            :     OVS_REQUIRES(rstp_mutex);
      93                 :            : static void reinitialize_rstp__(struct rstp *)
      94                 :            :     OVS_REQUIRES(rstp_mutex);
      95                 :            : static bool is_port_number_available__(struct rstp *, int, struct rstp_port *)
      96                 :            :     OVS_REQUIRES(rstp_mutex);
      97                 :            : static uint16_t rstp_first_free_number__(struct rstp *, struct rstp_port *)
      98                 :            :     OVS_REQUIRES(rstp_mutex);
      99                 :            : static void rstp_initialize_port_defaults__(struct rstp_port *)
     100                 :            :     OVS_REQUIRES(rstp_mutex);
     101                 :            : static void rstp_port_set_priority__(struct rstp_port *, int priority)
     102                 :            :     OVS_REQUIRES(rstp_mutex);
     103                 :            : static void rstp_port_set_port_number__(struct rstp_port *,
     104                 :            :                                         uint16_t port_number)
     105                 :            :     OVS_REQUIRES(rstp_mutex);
     106                 :            : static void rstp_port_set_path_cost__(struct rstp_port *, uint32_t path_cost)
     107                 :            :     OVS_REQUIRES(rstp_mutex);
     108                 :            : static void rstp_port_set_administrative_bridge_port__(struct rstp_port *,
     109                 :            :                                                        uint8_t admin_port_state,
     110                 :            :                                                        bool initializing)
     111                 :            :     OVS_REQUIRES(rstp_mutex);
     112                 :            : static void rstp_port_set_admin_edge__(struct rstp_port *, bool admin_edge)
     113                 :            :     OVS_REQUIRES(rstp_mutex);
     114                 :            : static void rstp_port_set_auto_edge__(struct rstp_port *, bool auto_edge)
     115                 :            :     OVS_REQUIRES(rstp_mutex);
     116                 :            : static void rstp_port_set_admin_point_to_point_mac__(struct rstp_port *,
     117                 :            :         enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state)
     118                 :            :     OVS_REQUIRES(rstp_mutex);
     119                 :            : static void rstp_port_set_mcheck__(struct rstp_port *, bool mcheck)
     120                 :            :     OVS_REQUIRES(rstp_mutex);
     121                 :            : static void reinitialize_port__(struct rstp_port *p)
     122                 :            :     OVS_REQUIRES(rstp_mutex);
     123                 :            : 
     124                 :            : const char *
     125                 :         34 : rstp_state_name(enum rstp_state state)
     126                 :            : {
     127   [ +  -  +  +  :         34 :     switch (state) {
                      - ]
     128                 :            :     case RSTP_DISABLED:
     129                 :          4 :         return "Disabled";
     130                 :            :     case RSTP_LEARNING:
     131                 :          0 :         return "Learning";
     132                 :            :     case RSTP_FORWARDING:
     133                 :          9 :         return "Forwarding";
     134                 :            :     case RSTP_DISCARDING:
     135                 :         21 :         return "Discarding";
     136                 :            :     default:
     137                 :          0 :         return "Unknown";
     138                 :            :     }
     139                 :            : }
     140                 :            : 
     141                 :            : const char *
     142                 :         22 : rstp_port_role_name(enum rstp_port_role role)
     143                 :            : {
     144   [ +  +  -  -  :         22 :     switch (role) {
                   +  - ]
     145                 :            :     case ROLE_ROOT:
     146                 :          2 :         return "Root";
     147                 :            :     case ROLE_DESIGNATED:
     148                 :         15 :         return "Designated";
     149                 :            :     case ROLE_ALTERNATE:
     150                 :          0 :         return "Alternate";
     151                 :            :     case ROLE_BACKUP:
     152                 :          0 :         return "Backup";
     153                 :            :     case ROLE_DISABLED:
     154                 :          5 :         return "Disabled";
     155                 :            :     default:
     156                 :          0 :         return "Unknown";
     157                 :            :     }
     158                 :            : }
     159                 :            : 
     160                 :            : /* Caller has to hold a reference to prevent 'rstp' from being deleted
     161                 :            :  * while taking a new reference. */
     162                 :            : struct rstp *
     163                 :         77 : rstp_ref(struct rstp *rstp)
     164                 :            :     OVS_EXCLUDED(rstp_mutex)
     165                 :            : {
     166         [ +  - ]:         77 :     if (rstp) {
     167                 :         77 :         ovs_refcount_ref(&rstp->ref_cnt);
     168                 :            :     }
     169                 :         77 :     return rstp;
     170                 :            : }
     171                 :            : 
     172                 :            : /* Frees RSTP struct when reference count reaches zero. */
     173                 :            : void
     174                 :      46565 : rstp_unref(struct rstp *rstp)
     175                 :            :     OVS_EXCLUDED(rstp_mutex)
     176                 :            : {
     177 [ +  + ][ +  + ]:      46565 :     if (rstp && ovs_refcount_unref_relaxed(&rstp->ref_cnt) == 1) {
     178                 :         26 :         ovs_mutex_lock(&rstp_mutex);
     179                 :            : 
     180                 :            :         /* Each RSTP port points back to struct rstp without holding a
     181                 :            :          * reference for that pointer.  This is OK as we never move
     182                 :            :          * ports from one bridge to another, and holders always
     183                 :            :          * release their ports before releasing the bridge.  This
     184                 :            :          * means that there should be not ports at this time. */
     185         [ -  + ]:         26 :         ovs_assert(hmap_is_empty(&rstp->ports));
     186                 :            : 
     187                 :         26 :         ovs_list_remove(&rstp->node);
     188                 :         26 :         ovs_mutex_unlock(&rstp_mutex);
     189                 :         26 :         hmap_destroy(&rstp->ports);
     190                 :         26 :         free(rstp->name);
     191                 :         26 :         free(rstp);
     192                 :            :     }
     193                 :      46565 : }
     194                 :            : 
     195                 :            : /* Returns the port number.  Mutex is needed to guard against
     196                 :            :  * concurrent reinitialization (which can temporarily clear the
     197                 :            :  * port_number). */
     198                 :            : int
     199                 :          0 : rstp_port_get_number(const struct rstp_port *p)
     200                 :            :     OVS_EXCLUDED(rstp_mutex)
     201                 :            : {
     202                 :            :     int number;
     203                 :            : 
     204                 :          0 :     ovs_mutex_lock(&rstp_mutex);
     205                 :          0 :     number = p->port_number;
     206                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
     207                 :            : 
     208                 :          0 :     return number;
     209                 :            : }
     210                 :            : 
     211                 :            : static void rstp_unixctl_tcn(struct unixctl_conn *, int argc,
     212                 :            :                              const char *argv[], void *aux);
     213                 :            : 
     214                 :            : /* Decrements the State Machines' timers. */
     215                 :            : void
     216                 :      10804 : rstp_tick_timers(struct rstp *rstp)
     217                 :            :     OVS_EXCLUDED(rstp_mutex)
     218                 :            : {
     219                 :      10804 :     ovs_mutex_lock(&rstp_mutex);
     220                 :      10804 :     decrease_rstp_port_timers__(rstp);
     221                 :      10804 :     ovs_mutex_unlock(&rstp_mutex);
     222                 :      10804 : }
     223                 :            : 
     224                 :            : /* Processes an incoming BPDU. */
     225                 :            : void
     226                 :       7069 : rstp_port_received_bpdu(struct rstp_port *rp, const void *bpdu,
     227                 :            :                         size_t bpdu_size)
     228                 :            :     OVS_EXCLUDED(rstp_mutex)
     229                 :            : {
     230                 :       7069 :     ovs_mutex_lock(&rstp_mutex);
     231                 :            :     /* Only process packets on ports that have RSTP enabled. */
     232 [ +  - ][ +  + ]:       7069 :     if (rp && rp->rstp_state != RSTP_DISABLED) {
     233                 :       6349 :         process_received_bpdu__(rp, bpdu, bpdu_size);
     234                 :            :     }
     235                 :       7069 :     ovs_mutex_unlock(&rstp_mutex);
     236                 :       7069 : }
     237                 :            : 
     238                 :            : void
     239                 :        617 : rstp_init(void)
     240                 :            :     OVS_EXCLUDED(rstp_mutex)
     241                 :            : {
     242                 :        617 :     unixctl_command_register("rstp/tcn", "[bridge]", 0, 1, rstp_unixctl_tcn,
     243                 :            :                              NULL);
     244                 :        617 : }
     245                 :            : 
     246                 :            : /* Creates and returns a new RSTP instance that initially has no ports. */
     247                 :            : struct rstp *
     248                 :         28 : rstp_create(const char *name, rstp_identifier bridge_address,
     249                 :            :             void (*send_bpdu)(struct dp_packet *bpdu, void *port_aux,
     250                 :            :                               void *rstp_aux),
     251                 :            :             void *aux)
     252                 :            :     OVS_EXCLUDED(rstp_mutex)
     253                 :            : {
     254                 :            :     struct rstp *rstp;
     255                 :            : 
     256         [ -  + ]:         28 :     VLOG_DBG("Creating RSTP instance");
     257                 :            : 
     258                 :         28 :     rstp = xzalloc(sizeof *rstp);
     259                 :         28 :     rstp->name = xstrdup(name);
     260                 :            : 
     261                 :            :     /* Initialize the ports map before calling any setters,
     262                 :            :      * so that the state machines will see an empty ports map. */
     263                 :         28 :     hmap_init(&rstp->ports);
     264                 :            : 
     265                 :         28 :     ovs_mutex_lock(&rstp_mutex);
     266                 :            :     /* Set bridge address. */
     267                 :         28 :     rstp_set_bridge_address__(rstp, bridge_address);
     268                 :            :     /* Set default parameters values. */
     269                 :         28 :     rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
     270                 :         28 :     rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
     271                 :         28 :     rstp_set_bridge_force_protocol_version__(rstp, FPV_DEFAULT);
     272                 :         28 :     rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
     273                 :         28 :     rstp_set_bridge_hello_time__(rstp);
     274                 :         28 :     rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
     275                 :         28 :     rstp_set_bridge_migrate_time__(rstp);
     276                 :         28 :     rstp_set_bridge_transmit_hold_count__(rstp,
     277                 :            :                                           RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
     278                 :         28 :     rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
     279                 :            :                             RSTP_BRIDGE_HELLO_TIME,
     280                 :            :                             RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
     281                 :         28 :     rstp->send_bpdu = send_bpdu;
     282                 :         28 :     rstp->aux = aux;
     283                 :         28 :     rstp->changes = false;
     284                 :         28 :     rstp->begin = true;
     285                 :         28 :     rstp->old_root_aux = NULL;
     286                 :         28 :     rstp->new_root_aux = NULL;
     287                 :            : 
     288                 :         28 :     ovs_refcount_init(&rstp->ref_cnt);
     289                 :            : 
     290                 :         28 :     ovs_list_push_back(all_rstps, &rstp->node);
     291                 :         28 :     ovs_mutex_unlock(&rstp_mutex);
     292                 :            : 
     293         [ -  + ]:         28 :     VLOG_DBG("RSTP instance creation done");
     294                 :         28 :     return rstp;
     295                 :            : }
     296                 :            : 
     297                 :            : /* Called by rstp_set_bridge_address() and rstp_set_bridge_priority(),
     298                 :            :  * it updates the bridge priority vector according to the values passed by
     299                 :            :  * those setters.
     300                 :            :  */
     301                 :            : static void
     302                 :        111 : set_bridge_priority__(struct rstp *rstp)
     303                 :            :     OVS_REQUIRES(rstp_mutex)
     304                 :            : {
     305                 :            :     struct rstp_port *p;
     306                 :            : 
     307                 :        111 :     rstp->bridge_priority.root_bridge_id = rstp->bridge_identifier;
     308                 :        111 :     rstp->bridge_priority.designated_bridge_id = rstp->bridge_identifier;
     309         [ -  + ]:        111 :     VLOG_DBG("%s: new bridge identifier: "RSTP_ID_FMT"", rstp->name,
     310                 :            :              RSTP_ID_ARGS(rstp->bridge_identifier));
     311                 :            : 
     312                 :            :     /* [17.13] When the bridge address changes, recalculates all priority
     313                 :            :      * vectors.
     314                 :            :      */
     315 [ +  + ][ -  + ]:        120 :     HMAP_FOR_EACH (p, node, &rstp->ports) {
     316                 :          9 :         p->selected = false;
     317                 :          9 :         p->reselect = true;
     318                 :            :     }
     319                 :        111 :     rstp->changes = true;
     320                 :        111 :     updt_roles_tree__(rstp);
     321                 :        111 : }
     322                 :            : 
     323                 :            : /* Sets the bridge address. */
     324                 :            : static void
     325                 :         68 : rstp_set_bridge_address__(struct rstp *rstp, rstp_identifier bridge_address)
     326                 :            :     OVS_REQUIRES(rstp_mutex)
     327                 :            : {
     328         [ -  + ]:         68 :     VLOG_DBG("%s: set bridge address to: "RSTP_ID_FMT"", rstp->name,
     329                 :            :              RSTP_ID_ARGS(bridge_address));
     330         [ +  + ]:         68 :     if (rstp->address != bridge_address) {
     331                 :         54 :         rstp->address = bridge_address;
     332                 :         54 :         rstp->bridge_identifier &= 0xffff000000000000ULL;
     333                 :         54 :         rstp->bridge_identifier |= bridge_address;
     334                 :         54 :         set_bridge_priority__(rstp);
     335                 :            :     }
     336                 :         68 : }
     337                 :            : 
     338                 :            : /* Sets the bridge address. */
     339                 :            : void
     340                 :         12 : rstp_set_bridge_address(struct rstp *rstp, rstp_identifier bridge_address)
     341                 :            :     OVS_EXCLUDED(rstp_mutex)
     342                 :            : {
     343                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     344                 :         12 :     rstp_set_bridge_address__(rstp, bridge_address);
     345                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     346                 :         12 : }
     347                 :            : 
     348                 :            : const char *
     349                 :          0 : rstp_get_name(const struct rstp *rstp)
     350                 :            :     OVS_EXCLUDED(rstp_mutex)
     351                 :            : {
     352                 :            :     char *name;
     353                 :            : 
     354                 :          0 :     ovs_mutex_lock(&rstp_mutex);
     355                 :          0 :     name = rstp->name;
     356                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
     357                 :          0 :     return name;
     358                 :            : }
     359                 :            : 
     360                 :            : rstp_identifier
     361                 :         25 : rstp_get_bridge_id(const struct rstp *rstp)
     362                 :            :     OVS_EXCLUDED(rstp_mutex)
     363                 :            : {
     364                 :            :     rstp_identifier bridge_id;
     365                 :            : 
     366                 :         25 :     ovs_mutex_lock(&rstp_mutex);
     367                 :         25 :     bridge_id = rstp->bridge_identifier;
     368                 :         25 :     ovs_mutex_unlock(&rstp_mutex);
     369                 :            : 
     370                 :         25 :     return bridge_id;
     371                 :            : }
     372                 :            : 
     373                 :            : /* Sets the bridge priority. */
     374                 :            : static void
     375                 :         69 : rstp_set_bridge_priority__(struct rstp *rstp, int new_priority)
     376                 :            :     OVS_REQUIRES(rstp_mutex)
     377                 :            : {
     378                 :         69 :     new_priority = ROUND_DOWN(new_priority, RSTP_PRIORITY_STEP);
     379                 :            : 
     380         [ +  + ]:         69 :     if (rstp->priority != new_priority
     381         [ +  - ]:         57 :         && new_priority >= RSTP_MIN_PRIORITY
     382         [ +  - ]:         57 :         && new_priority <= RSTP_MAX_PRIORITY) {
     383         [ -  + ]:         57 :         VLOG_DBG("%s: set bridge priority to %d", rstp->name, new_priority);
     384                 :            : 
     385                 :         57 :         rstp->priority = new_priority;
     386                 :         57 :         rstp->bridge_identifier &= 0x0000ffffffffffffULL;
     387                 :         57 :         rstp->bridge_identifier |= (uint64_t)new_priority << 48;
     388                 :         57 :         set_bridge_priority__(rstp);
     389                 :            :     }
     390                 :         69 : }
     391                 :            : 
     392                 :            : void
     393                 :         13 : rstp_set_bridge_priority(struct rstp *rstp, int new_priority)
     394                 :            :     OVS_EXCLUDED(rstp_mutex)
     395                 :            : {
     396                 :         13 :     ovs_mutex_lock(&rstp_mutex);
     397                 :         13 :     rstp_set_bridge_priority__(rstp, new_priority);
     398                 :         13 :     ovs_mutex_unlock(&rstp_mutex);
     399                 :         13 : }
     400                 :            : 
     401                 :            : /* Sets the bridge ageing time. */
     402                 :            : static void
     403                 :         68 : rstp_set_bridge_ageing_time__(struct rstp *rstp, int new_ageing_time)
     404                 :            :     OVS_REQUIRES(rstp_mutex)
     405                 :            : {
     406         [ +  - ]:         68 :     if (new_ageing_time >= RSTP_MIN_AGEING_TIME
     407         [ +  - ]:         68 :         && new_ageing_time <= RSTP_MAX_AGEING_TIME) {
     408         [ -  + ]:         68 :         VLOG_DBG("%s: set ageing time to %d", rstp->name, new_ageing_time);
     409                 :            : 
     410                 :         68 :         rstp->ageing_time = new_ageing_time;
     411                 :            :     }
     412                 :         68 : }
     413                 :            : 
     414                 :            : void
     415                 :         12 : rstp_set_bridge_ageing_time(struct rstp *rstp, int new_ageing_time)
     416                 :            :     OVS_EXCLUDED(rstp_mutex)
     417                 :            : {
     418                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     419                 :         12 :     rstp_set_bridge_ageing_time__(rstp, new_ageing_time);
     420                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     421                 :         12 : }
     422                 :            : 
     423                 :            : /* Reinitializes RSTP when switching from RSTP mode to STP mode
     424                 :            :  * or vice versa.
     425                 :            :  */
     426                 :            : static void
     427                 :         28 : reinitialize_rstp__(struct rstp *rstp)
     428                 :            :     OVS_REQUIRES(rstp_mutex)
     429                 :            : {
     430                 :            :     struct rstp temp;
     431                 :            :     static struct hmap ports;
     432                 :            :     struct rstp_port *p;
     433                 :            : 
     434                 :            :     /* Copy rstp in temp */
     435                 :         28 :     temp = *rstp;
     436                 :         28 :     ports = rstp->ports;
     437                 :            : 
     438                 :            :     /* stop and clear rstp */
     439                 :         28 :     memset(rstp, 0, sizeof(struct rstp));
     440                 :            : 
     441                 :            :     /* Initialize rstp. */
     442                 :         28 :     rstp->name = temp.name;
     443                 :            : 
     444                 :            :     /* Initialize the ports hmap before calling any setters,
     445                 :            :      * so that the state machines will see an empty ports list. */
     446                 :         28 :     hmap_init(&rstp->ports);
     447                 :            : 
     448                 :            :     /* Set bridge address. */
     449                 :         28 :     rstp_set_bridge_address__(rstp, temp.address);
     450                 :            :     /* Set default parameters values. */
     451                 :         28 :     rstp_set_bridge_priority__(rstp, RSTP_DEFAULT_PRIORITY);
     452                 :         28 :     rstp_set_bridge_ageing_time__(rstp, RSTP_DEFAULT_AGEING_TIME);
     453                 :         28 :     rstp_set_bridge_forward_delay__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY);
     454                 :         28 :     rstp_set_bridge_hello_time__(rstp);
     455                 :         28 :     rstp_set_bridge_max_age__(rstp, RSTP_DEFAULT_BRIDGE_MAX_AGE);
     456                 :         28 :     rstp_set_bridge_migrate_time__(rstp);
     457                 :         28 :     rstp_set_bridge_transmit_hold_count__(rstp,
     458                 :            :                                           RSTP_DEFAULT_TRANSMIT_HOLD_COUNT);
     459                 :         28 :     rstp_set_bridge_times__(rstp, RSTP_DEFAULT_BRIDGE_FORWARD_DELAY,
     460                 :            :                             RSTP_BRIDGE_HELLO_TIME,
     461                 :            :                             RSTP_DEFAULT_BRIDGE_MAX_AGE, 0);
     462                 :            : 
     463                 :         28 :     rstp->send_bpdu = temp.send_bpdu;
     464                 :         28 :     rstp->aux = temp.aux;
     465                 :         28 :     rstp->node = temp.node;
     466                 :         28 :     rstp->changes = false;
     467                 :         28 :     rstp->begin = true;
     468                 :            : 
     469                 :            :     /* Restore ports. */
     470                 :         28 :     rstp->ports = ports;
     471                 :            : 
     472 [ -  + ][ -  + ]:         28 :     HMAP_FOR_EACH (p, node, &rstp->ports) {
     473                 :          0 :         reinitialize_port__(p);
     474                 :            :     }
     475                 :            : 
     476                 :         28 :     rstp->ref_cnt = temp.ref_cnt;
     477                 :         28 : }
     478                 :            : 
     479                 :            : /* Sets the force protocol version parameter. */
     480                 :            : static void
     481                 :         40 : rstp_set_bridge_force_protocol_version__(struct rstp *rstp,
     482                 :            :                 enum rstp_force_protocol_version new_force_protocol_version)
     483                 :            :     OVS_REQUIRES(rstp_mutex)
     484                 :            : {
     485 [ +  + ][ +  - ]:         40 :     if (new_force_protocol_version != rstp->force_protocol_version &&
     486         [ +  - ]:         28 :             (new_force_protocol_version == FPV_STP_COMPATIBILITY ||
     487                 :            :              new_force_protocol_version == FPV_DEFAULT)) {
     488         [ -  + ]:         28 :         VLOG_DBG("%s: set bridge Force Protocol Version to %d", rstp->name,
     489                 :            :                  new_force_protocol_version);
     490                 :            : 
     491                 :            :         /* [17.13] The Spanning Tree Protocol Entity shall be reinitialized,
     492                 :            :          * as specified by the assertion of BEGIN (17.18.1) in the state
     493                 :            :          * machine specification.
     494                 :            :          */
     495                 :         28 :         reinitialize_rstp__(rstp);
     496                 :         28 :         rstp->force_protocol_version = new_force_protocol_version;
     497         [ -  + ]:         28 :         if (rstp->force_protocol_version < 2) {
     498                 :          0 :             rstp->stp_version = true;
     499                 :          0 :             rstp->rstp_version = false;
     500                 :            :         } else {
     501                 :         28 :             rstp->stp_version = false;
     502                 :         28 :             rstp->rstp_version = true;
     503                 :            :         }
     504                 :         28 :         rstp->changes = true;
     505                 :         28 :         move_rstp__(rstp);
     506                 :            :     }
     507                 :         40 : }
     508                 :            : 
     509                 :            : void
     510                 :         12 : rstp_set_bridge_force_protocol_version(struct rstp *rstp,
     511                 :            :                 enum rstp_force_protocol_version new_force_protocol_version)
     512                 :            :     OVS_EXCLUDED(rstp_mutex)
     513                 :            : {
     514                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     515                 :         12 :     rstp_set_bridge_force_protocol_version__(rstp, new_force_protocol_version);
     516                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     517                 :         12 : }
     518                 :            : 
     519                 :            : /* Sets the bridge Hello Time parameter. */
     520                 :            : static void
     521                 :         56 : rstp_set_bridge_hello_time__(struct rstp *rstp)
     522                 :            :     OVS_REQUIRES(rstp_mutex)
     523                 :            : {
     524         [ -  + ]:         56 :     VLOG_DBG("%s: set RSTP Hello Time to %d", rstp->name,
     525                 :            :              RSTP_BRIDGE_HELLO_TIME);
     526                 :            :     /* 2 is the only acceptable value. */
     527                 :         56 :     rstp->bridge_hello_time = RSTP_BRIDGE_HELLO_TIME;
     528                 :         56 : }
     529                 :            : 
     530                 :            : /* Sets the bridge max age parameter. */
     531                 :            : static void
     532                 :         68 : rstp_set_bridge_max_age__(struct rstp *rstp, int new_max_age)
     533                 :            :     OVS_REQUIRES(rstp_mutex)
     534                 :            : {
     535         [ +  + ]:         68 :     if (rstp->bridge_max_age != new_max_age
     536         [ +  - ]:         28 :         && new_max_age >= RSTP_MIN_BRIDGE_MAX_AGE
     537         [ +  - ]:         28 :         && new_max_age <= RSTP_MAX_BRIDGE_MAX_AGE) {
     538                 :            :         /* [17.13] */
     539         [ +  - ]:         28 :         if ((2 * (rstp->bridge_forward_delay - 1) >= new_max_age)
     540         [ +  - ]:         28 :             && (new_max_age >= 2 * rstp->bridge_hello_time)) {
     541         [ -  + ]:         28 :             VLOG_DBG("%s: set RSTP bridge Max Age to %d", rstp->name,
     542                 :            :                      new_max_age);
     543                 :            : 
     544                 :         28 :             rstp->bridge_max_age = new_max_age;
     545                 :         28 :             rstp->bridge_times.max_age = new_max_age;
     546                 :         28 :             rstp->changes = true;
     547                 :         28 :             updt_roles_tree__(rstp);
     548                 :            :         }
     549                 :            :     }
     550                 :         68 : }
     551                 :            : 
     552                 :            : void
     553                 :         12 : rstp_set_bridge_max_age(struct rstp *rstp, int new_max_age)
     554                 :            :     OVS_EXCLUDED(rstp_mutex)
     555                 :            : {
     556                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     557                 :         12 :     rstp_set_bridge_max_age__(rstp, new_max_age);
     558                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     559                 :         12 : }
     560                 :            : 
     561                 :            : /* Sets the bridge forward delay parameter. */
     562                 :            : static void
     563                 :         68 : rstp_set_bridge_forward_delay__(struct rstp *rstp, int new_forward_delay)
     564                 :            :     OVS_REQUIRES(rstp_mutex)
     565                 :            : {
     566         [ +  + ]:         68 :     if (rstp->bridge_forward_delay != new_forward_delay
     567         [ +  - ]:         28 :             && new_forward_delay >= RSTP_MIN_BRIDGE_FORWARD_DELAY
     568         [ +  - ]:         28 :             && new_forward_delay <= RSTP_MAX_BRIDGE_FORWARD_DELAY) {
     569         [ +  - ]:         28 :         if (2 * (new_forward_delay - 1) >= rstp->bridge_max_age) {
     570         [ -  + ]:         28 :             VLOG_DBG("%s: set RSTP Forward Delay to %d", rstp->name,
     571                 :            :                      new_forward_delay);
     572                 :         28 :             rstp->bridge_forward_delay = new_forward_delay;
     573                 :         28 :             rstp->bridge_times.forward_delay = new_forward_delay;
     574                 :         28 :             rstp->changes = true;
     575                 :         28 :             updt_roles_tree__(rstp);
     576                 :            :         }
     577                 :            :     }
     578                 :         68 : }
     579                 :            : 
     580                 :            : void
     581                 :         12 : rstp_set_bridge_forward_delay(struct rstp *rstp, int new_forward_delay)
     582                 :            :     OVS_EXCLUDED(rstp_mutex)
     583                 :            : {
     584                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     585                 :         12 :     rstp_set_bridge_forward_delay__(rstp, new_forward_delay);
     586                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     587                 :         12 : }
     588                 :            : 
     589                 :            : /* Sets the bridge transmit hold count parameter. */
     590                 :            : static void
     591                 :         68 : rstp_set_bridge_transmit_hold_count__(struct rstp *rstp,
     592                 :            :                                       int new_transmit_hold_count)
     593                 :            :     OVS_REQUIRES(rstp_mutex)
     594                 :            : {
     595         [ +  + ]:         68 :     if (rstp->transmit_hold_count != new_transmit_hold_count
     596         [ +  - ]:         28 :         && new_transmit_hold_count >= RSTP_MIN_TRANSMIT_HOLD_COUNT
     597         [ +  - ]:         28 :         && new_transmit_hold_count <= RSTP_MAX_TRANSMIT_HOLD_COUNT) {
     598                 :            :         struct rstp_port *p;
     599                 :            : 
     600         [ -  + ]:         28 :         VLOG_DBG("%s: set RSTP Transmit Hold Count to %d", rstp->name,
     601                 :            :                  new_transmit_hold_count);
     602                 :            :         /* Resetting txCount on all ports [17.13]. */
     603                 :            : 
     604                 :         28 :         rstp->transmit_hold_count = new_transmit_hold_count;
     605 [ -  + ][ -  + ]:         28 :         HMAP_FOR_EACH (p, node, &rstp->ports) {
     606                 :          0 :             p->tx_count = 0;
     607                 :            :         }
     608                 :            :     }
     609                 :         68 : }
     610                 :            : 
     611                 :            : void
     612                 :         12 : rstp_set_bridge_transmit_hold_count(struct rstp *rstp,
     613                 :            :                                     int new_transmit_hold_count)
     614                 :            :     OVS_EXCLUDED(rstp_mutex)
     615                 :            : {
     616                 :         12 :     ovs_mutex_lock(&rstp_mutex);
     617                 :         12 :     rstp_set_bridge_transmit_hold_count__(rstp, new_transmit_hold_count);
     618                 :         12 :     ovs_mutex_unlock(&rstp_mutex);
     619                 :         12 : }
     620                 :            : 
     621                 :            : /* Sets the bridge migrate time parameter. */
     622                 :            : static void
     623                 :         56 : rstp_set_bridge_migrate_time__(struct rstp *rstp)
     624                 :            :     OVS_REQUIRES(rstp_mutex)
     625                 :            : {
     626         [ -  + ]:         56 :     VLOG_DBG("%s: set RSTP Migrate Time to %d", rstp->name,
     627                 :            :              RSTP_MIGRATE_TIME);
     628                 :            :     /* 3 is the only acceptable value */
     629                 :         56 :     rstp->migrate_time = RSTP_MIGRATE_TIME;
     630                 :         56 : }
     631                 :            : 
     632                 :            : /* Sets the bridge times. */
     633                 :            : static void
     634                 :         56 : rstp_set_bridge_times__(struct rstp *rstp, int new_forward_delay,
     635                 :            :                         int new_hello_time, int new_max_age,
     636                 :            :                         int new_message_age)
     637                 :            :     OVS_REQUIRES(rstp_mutex)
     638                 :            : {
     639         [ -  + ]:         56 :     VLOG_DBG("%s: set RSTP times to (%d, %d, %d, %d)", rstp->name,
     640                 :            :              new_forward_delay, new_hello_time, new_max_age, new_message_age);
     641         [ +  - ]:         56 :     if (new_forward_delay >= RSTP_MIN_BRIDGE_FORWARD_DELAY
     642         [ +  - ]:         56 :         && new_forward_delay <= RSTP_MAX_BRIDGE_FORWARD_DELAY) {
     643                 :         56 :         rstp->bridge_times.forward_delay = new_forward_delay;
     644                 :            :     }
     645         [ +  - ]:         56 :     if (new_hello_time == RSTP_BRIDGE_HELLO_TIME) {
     646                 :         56 :         rstp->bridge_times.hello_time = new_hello_time;
     647                 :            :     }
     648         [ +  - ]:         56 :     if (new_max_age >= RSTP_MIN_BRIDGE_MAX_AGE
     649         [ +  - ]:         56 :         && new_max_age <= RSTP_MAX_BRIDGE_MAX_AGE) {
     650                 :         56 :         rstp->bridge_times.max_age = new_max_age;
     651                 :            :     }
     652                 :         56 :     rstp->bridge_times.message_age = new_message_age;
     653                 :         56 : }
     654                 :            : 
     655                 :            : /* Sets the port id, it is called by rstp_port_set_port_number__() or
     656                 :            :  * rstp_port_set_priority__().
     657                 :            :  */
     658                 :            : static void
     659                 :        473 : set_port_id__(struct rstp_port *p)
     660                 :            :     OVS_REQUIRES(rstp_mutex)
     661                 :            : {
     662                 :            :     struct rstp *rstp;
     663                 :            : 
     664                 :        473 :     rstp = p->rstp;
     665                 :            :     /* [9.2.7] Port identifier. */
     666                 :        473 :     p->port_id = p->port_number | (p->priority << 8);
     667         [ -  + ]:        473 :     VLOG_DBG("%s: new RSTP port id "RSTP_PORT_ID_FMT"", rstp->name,
     668                 :            :              p->port_id);
     669                 :        473 : }
     670                 :            : 
     671                 :            : /* Sets the port priority. */
     672                 :            : static void
     673                 :        246 : rstp_port_set_priority__(struct rstp_port *port, int priority)
     674                 :            :     OVS_REQUIRES(rstp_mutex)
     675                 :            : {
     676         [ +  + ]:        246 :     if (port->priority != priority
     677         [ +  - ]:        237 :         && priority >= RSTP_MIN_PORT_PRIORITY
     678         [ +  - ]:        237 :         && priority <= RSTP_MAX_PORT_PRIORITY) {
     679         [ -  + ]:        237 :         VLOG_DBG("%s, port %u: set RSTP port priority to %d", port->rstp->name,
     680                 :            :                  port->port_number, priority);
     681                 :            : 
     682                 :        237 :         priority -= priority % RSTP_STEP_PORT_PRIORITY;
     683                 :        237 :         port->priority = priority;
     684                 :        237 :         set_port_id__(port);
     685                 :        237 :         port->selected = false;
     686                 :        237 :         port->reselect = true;
     687                 :            :     }
     688                 :        246 : }
     689                 :            : 
     690                 :            : /* Checks if a port number is available. */
     691                 :            : static bool
     692                 :       1426 : is_port_number_available__(struct rstp *rstp, int n, struct rstp_port *port)
     693                 :            :     OVS_REQUIRES(rstp_mutex)
     694                 :            : {
     695 [ +  + ][ +  - ]:       1426 :     if (n >= 1 && n <= RSTP_MAX_PORTS) {
     696                 :       1181 :         struct rstp_port *p = rstp_get_port__(rstp, n);
     697                 :            : 
     698 [ +  + ][ +  + ]:       1181 :         return p == NULL || p == port;
     699                 :            :     }
     700                 :        245 :     return false;
     701                 :            : }
     702                 :            : 
     703                 :            : static uint16_t
     704                 :        245 : rstp_first_free_number__(struct rstp *rstp, struct rstp_port *rstp_port)
     705                 :            :     OVS_REQUIRES(rstp_mutex)
     706                 :            : {
     707                 :        245 :     int free_number = 1;
     708                 :            : 
     709         [ +  - ]:       1181 :     while (free_number <= RSTP_MAX_PORTS) {
     710         [ +  + ]:       1181 :         if (is_port_number_available__(rstp, free_number, rstp_port)) {
     711                 :        245 :             return free_number;
     712                 :            :         }
     713                 :        936 :         free_number++;
     714                 :            :     }
     715         [ #  # ]:          0 :     VLOG_DBG("%s, No free port number available.", rstp->name);
     716                 :          0 :     return 0;
     717                 :            : }
     718                 :            : 
     719                 :            : /* Sets the port number. */
     720                 :            : static void
     721                 :        245 : rstp_port_set_port_number__(struct rstp_port *port, uint16_t port_number)
     722                 :            :     OVS_REQUIRES(rstp_mutex)
     723                 :            : {
     724                 :        245 :     int old_port_number = port->port_number;
     725                 :            : 
     726                 :            :     /* If new_port_number is available, use it, otherwise use the first free
     727                 :            :      * available port number. */
     728 [ +  + ][ +  - ]:        245 :     if (port->port_number != port_number || port_number == 0) {
     729         [ -  + ]:        245 :         port->port_number =
     730                 :        245 :             is_port_number_available__(port->rstp, port_number, port)
     731                 :            :             ? port_number
     732                 :        245 :             : rstp_first_free_number__(port->rstp, port);
     733                 :            : 
     734         [ +  + ]:        245 :         if (port->port_number != old_port_number) {
     735                 :        236 :             set_port_id__(port);
     736                 :            :             /* [17.13] is not clear. I suppose that a port number change
     737                 :            :              * should trigger reselection like a port priority change. */
     738                 :        236 :             port->selected = false;
     739                 :        236 :             port->reselect = true;
     740                 :            : 
     741                 :            :             /* Adjust the ports hmap. */
     742         [ -  + ]:        236 :             if (!hmap_node_is_null(&port->node)) {
     743                 :          0 :                 hmap_remove(&port->rstp->ports, &port->node);
     744                 :            :             }
     745                 :        236 :             hmap_insert(&port->rstp->ports, &port->node,
     746                 :            :                         hash_int(port->port_number, 0));
     747                 :            : 
     748         [ -  + ]:        236 :             VLOG_DBG("%s: set new RSTP port number %d", port->rstp->name,
     749                 :            :                      port->port_number);
     750                 :            :         }
     751                 :            :     }
     752                 :        245 : }
     753                 :            : 
     754                 :            : /* Converts the link speed to a port path cost [Table 17-3]. */
     755                 :            : uint32_t
     756                 :          9 : rstp_convert_speed_to_cost(unsigned int speed)
     757                 :            : {
     758                 :            :     uint32_t value;
     759                 :            : 
     760 [ +  - ][ +  - ]:          9 :     value = speed >= 10000000 ? 2 /* 10 Tb/s. */
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
     761                 :            :           : speed >= 1000000 ? 20 /* 1 Tb/s. */
     762                 :            :           : speed >= 100000 ? 200 /* 100 Gb/s. */
     763                 :            :           : speed >= 10000 ? 2000 /* 10 Gb/s. */
     764                 :            :           : speed >= 1000 ? 20000 /* 1 Gb/s. */
     765                 :            :           : speed >= 100 ? 200000 /* 100 Mb/s. */
     766                 :            :           : speed >= 10 ? 2000000 /* 10 Mb/s. */
     767                 :            :           : speed >= 1 ? 20000000 /* 1 Mb/s. */
     768                 :            :           : RSTP_DEFAULT_PORT_PATH_COST; /* 100 Mb/s. */
     769                 :            : 
     770                 :          9 :     return value;
     771                 :            : }
     772                 :            : 
     773                 :            : /* Sets the port path cost. */
     774                 :            : static void
     775                 :        641 : rstp_port_set_path_cost__(struct rstp_port *port, uint32_t path_cost)
     776                 :            :     OVS_REQUIRES(rstp_mutex)
     777                 :            : {
     778         [ +  + ]:        641 :     if (port->port_path_cost != path_cost
     779         [ +  - ]:        525 :         && path_cost >= RSTP_MIN_PORT_PATH_COST
     780         [ +  - ]:        525 :         && path_cost <= RSTP_MAX_PORT_PATH_COST) {
     781         [ -  + ]:        525 :         VLOG_DBG("%s, port %u, set RSTP port path cost to %d",
     782                 :            :                  port->rstp->name, port->port_number, path_cost);
     783                 :            : 
     784                 :        525 :         port->port_path_cost = path_cost;
     785                 :        525 :         port->selected = false;
     786                 :        525 :         port->reselect = true;
     787                 :            :     }
     788                 :        641 : }
     789                 :            : 
     790                 :            : /* Gets the root path cost. */
     791                 :            : uint32_t
     792                 :         76 : rstp_get_root_path_cost(const struct rstp *rstp)
     793                 :            :     OVS_EXCLUDED(rstp_mutex)
     794                 :            : {
     795                 :            :     uint32_t cost;
     796                 :            : 
     797                 :         76 :     ovs_mutex_lock(&rstp_mutex);
     798                 :         76 :     cost = rstp->root_priority.root_path_cost;
     799                 :         76 :     ovs_mutex_unlock(&rstp_mutex);
     800                 :         76 :     return cost;
     801                 :            : }
     802                 :            : 
     803                 :            : /* Finds a port which needs to flush its own MAC learning table.  A NULL
     804                 :            :  * pointer is returned if no port needs to flush its MAC learning table.
     805                 :            :  * '*port' needs to be NULL in the first call to start the iteration.  If
     806                 :            :  * '*port' is passed as non-NULL, it must be the value set by the last
     807                 :            :  * invocation of this function.
     808                 :            :  *
     809                 :            :  * This function may only be called by the thread that creates and deletes
     810                 :            :  * ports.  Otherwise this function is not thread safe, as the returned
     811                 :            :  * '*port' could become stale before it is used in the next invocation. */
     812                 :            : void *
     813                 :        188 : rstp_check_and_reset_fdb_flush(struct rstp *rstp, struct rstp_port **port)
     814                 :            :     OVS_EXCLUDED(rstp_mutex)
     815                 :            : {
     816                 :        188 :     void *aux = NULL;
     817                 :            : 
     818                 :        188 :     ovs_mutex_lock(&rstp_mutex);
     819         [ +  + ]:        188 :     if (*port == NULL) {
     820                 :            :         struct rstp_port *p;
     821                 :            : 
     822 [ +  + ][ -  + ]:        328 :         HMAP_FOR_EACH (p, node, &rstp->ports) {
     823         [ +  + ]:        144 :             if (p->fdb_flush) {
     824                 :          2 :                 aux = p->aux;
     825                 :          2 :                 *port = p;
     826                 :          2 :                 goto out;
     827                 :            :             }
     828                 :            :         }
     829                 :            :     } else { /* continue */
     830                 :          2 :         struct rstp_port *p = *port;
     831                 :            : 
     832 [ -  + ][ -  + ]:          2 :         HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
     833         [ #  # ]:          0 :             if (p->fdb_flush) {
     834                 :          0 :                 aux = p->aux;
     835                 :          0 :                 *port = p;
     836                 :          0 :                 goto out;
     837                 :            :             }
     838                 :            :         }
     839                 :            :     }
     840                 :            :     /* No port needs flushing. */
     841                 :        186 :     *port = NULL;
     842                 :            : out:
     843                 :            :     /* fdb_flush should be reset by the filtering database
     844                 :            :      * once the entries are removed if rstp_version is TRUE, and
     845                 :            :      * immediately if stp_version is TRUE.*/
     846         [ +  + ]:        188 :     if (*port != NULL) {
     847                 :          2 :         (*port)->fdb_flush = false;
     848                 :            :     }
     849                 :        188 :     ovs_mutex_unlock(&rstp_mutex);
     850                 :            : 
     851                 :        188 :     return aux;
     852                 :            : }
     853                 :            : 
     854                 :            : /* Finds a port whose state has changed, and returns the aux pointer set for
     855                 :            :  * the port.  A NULL pointer is returned when no changed port is found.  On
     856                 :            :  * return '*portp' contains the pointer to the rstp port that changed, or NULL
     857                 :            :  * if no changed port can be found.
     858                 :            :  *
     859                 :            :  * If '*portp' is passed as non-NULL, it must be the value set by the last
     860                 :            :  * invocation of this function.
     861                 :            :  *
     862                 :            :  * This function may only be called by the thread that creates and deletes
     863                 :            :  * ports.  Otherwise this function is not thread safe, as the returned
     864                 :            :  * '*portp' could become stale before it is used in the next invocation. */
     865                 :            : void *
     866                 :        190 : rstp_get_next_changed_port_aux(struct rstp *rstp, struct rstp_port **portp)
     867                 :            : {
     868                 :        190 :     void *aux = NULL;
     869                 :            : 
     870                 :        190 :     ovs_mutex_lock(&rstp_mutex);
     871         [ +  + ]:        190 :     if (*portp == NULL) {
     872                 :            :         struct rstp_port *p;
     873                 :            : 
     874 [ +  + ][ -  + ]:        326 :         HMAP_FOR_EACH (p, node, &rstp->ports) {
     875         [ +  + ]:        144 :             if (p->state_changed) {
     876                 :          4 :                 p->state_changed = false;
     877                 :          4 :                 aux = p->aux;
     878                 :          4 :                 *portp = p;
     879                 :          4 :                 goto out;
     880                 :            :             }
     881                 :            :         }
     882                 :            :     } else { /* continue */
     883                 :          4 :         struct rstp_port *p = *portp;
     884                 :            : 
     885 [ -  + ][ -  + ]:          4 :         HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
     886         [ #  # ]:          0 :             if (p->state_changed) {
     887                 :          0 :                 p->state_changed = false;
     888                 :          0 :                 aux = p->aux;
     889                 :          0 :                 *portp = p;
     890                 :          0 :                 goto out;
     891                 :            :             }
     892                 :            :         }
     893                 :            :     }
     894                 :            :     /* No changed port found. */
     895                 :        186 :     *portp = NULL;
     896                 :            : out:
     897                 :        190 :     ovs_mutex_unlock(&rstp_mutex);
     898                 :            : 
     899                 :        190 :     return aux;
     900                 :            : }
     901                 :            : 
     902                 :            : bool
     903                 :        190 : rstp_shift_root_learned_address(struct rstp *rstp)
     904                 :            : {
     905                 :            :     bool ret;
     906                 :            : 
     907                 :        190 :     ovs_mutex_lock(&rstp_mutex);
     908                 :        190 :     ret = rstp->root_changed;
     909                 :        190 :     ovs_mutex_unlock(&rstp_mutex);
     910                 :            : 
     911                 :        190 :     return ret;
     912                 :            : }
     913                 :            : 
     914                 :            : void *
     915                 :          0 : rstp_get_old_root_aux(struct rstp *rstp)
     916                 :            : {
     917                 :            :     void *aux;
     918                 :            : 
     919                 :          0 :     ovs_mutex_lock(&rstp_mutex);
     920                 :          0 :     aux = rstp->old_root_aux;
     921                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
     922                 :            : 
     923                 :          0 :     return aux;
     924                 :            : }
     925                 :            : 
     926                 :            : void *
     927                 :          0 : rstp_get_new_root_aux(struct rstp *rstp)
     928                 :            : {
     929                 :            :     void *aux;
     930                 :            : 
     931                 :          0 :     ovs_mutex_lock(&rstp_mutex);
     932                 :          0 :     aux = rstp->new_root_aux;
     933                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
     934                 :            : 
     935                 :          0 :     return aux;
     936                 :            : }
     937                 :            : 
     938                 :            : void
     939                 :          0 : rstp_reset_root_changed(struct rstp *rstp)
     940                 :            : {
     941                 :          0 :     ovs_mutex_lock(&rstp_mutex);
     942                 :          0 :     rstp->root_changed = false;
     943                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
     944                 :          0 : }
     945                 :            : 
     946                 :            : /* Returns the port in 'rstp' with number 'port_number'.
     947                 :            :  *
     948                 :            :  * XXX: May only be called while concurrent deletion of ports is excluded. */
     949                 :            : static struct rstp_port *
     950                 :       9174 : rstp_get_port__(struct rstp *rstp, uint16_t port_number)
     951                 :            :     OVS_REQUIRES(rstp_mutex)
     952                 :            : {
     953                 :            :     struct rstp_port *port;
     954                 :            : 
     955 [ +  - ][ +  - ]:       9174 :     ovs_assert(rstp && port_number > 0 && port_number <= RSTP_MAX_PORTS);
         [ +  - ][ -  + ]
     956                 :            : 
     957 [ +  + ][ -  + ]:       9174 :     HMAP_FOR_EACH_WITH_HASH (port, node, hash_int(port_number, 0),
     958                 :            :                              &rstp->ports) {
     959         [ +  - ]:       8938 :         if (port->port_number == port_number) {
     960                 :       8938 :             return port;
     961                 :            :         }
     962                 :            :     }
     963                 :        236 :     return NULL;
     964                 :            : }
     965                 :            : 
     966                 :            : struct rstp_port *
     967                 :       7852 : rstp_get_port(struct rstp *rstp, uint16_t port_number)
     968                 :            :     OVS_EXCLUDED(rstp_mutex)
     969                 :            : {
     970                 :            :     struct rstp_port *p;
     971                 :            : 
     972                 :       7852 :     ovs_mutex_lock(&rstp_mutex);
     973                 :       7852 :     p = rstp_get_port__(rstp, port_number);
     974                 :       7852 :     ovs_mutex_unlock(&rstp_mutex);
     975                 :       7852 :     return p;
     976                 :            : }
     977                 :            : 
     978                 :            : void *
     979                 :        141 : rstp_get_port_aux__(struct rstp *rstp, uint16_t port_number)
     980                 :            :     OVS_REQUIRES(rstp_mutex)
     981                 :            : {
     982                 :            :     struct rstp_port *p;
     983                 :        141 :     p = rstp_get_port__(rstp, port_number);
     984         [ +  - ]:        141 :     if (p) {
     985                 :        141 :         return p->aux;
     986                 :            :     }
     987                 :          0 :     return NULL;
     988                 :            : }
     989                 :            : 
     990                 :            : /* Updates the port_enabled parameter. */
     991                 :            : static void
     992                 :       1394 : update_port_enabled__(struct rstp_port *p)
     993                 :            :     OVS_REQUIRES(rstp_mutex)
     994                 :            : {
     995 [ +  + ][ +  - ]:       1394 :     if (p->mac_operational && p->is_administrative_bridge_port
     996                 :            :         == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED) {
     997                 :        344 :         p->port_enabled = true;
     998                 :            :     } else {
     999                 :       1050 :         p->port_enabled = false;
    1000                 :            :     }
    1001                 :       1394 : }
    1002                 :            : 
    1003                 :            : /* Sets the port MAC_Operational parameter [6.4.2]. */
    1004                 :            : void
    1005                 :        535 : rstp_port_set_mac_operational(struct rstp_port *p, bool new_mac_operational)
    1006                 :            :     OVS_EXCLUDED(rstp_mutex)
    1007                 :            : {
    1008                 :            :     struct rstp *rstp;
    1009                 :            : 
    1010                 :        535 :     ovs_mutex_lock(&rstp_mutex);
    1011                 :        535 :     rstp = p->rstp;
    1012         [ +  + ]:        535 :     if (p->mac_operational != new_mac_operational) {
    1013                 :        346 :         p->mac_operational = new_mac_operational;
    1014                 :        346 :         update_port_enabled__(p);
    1015                 :        346 :         rstp->changes = true;
    1016                 :        346 :         move_rstp__(rstp);
    1017                 :            :     }
    1018                 :        535 :     ovs_mutex_unlock(&rstp_mutex);
    1019                 :        535 : }
    1020                 :            : 
    1021                 :            : /* Sets the port Administrative Bridge Port parameter. */
    1022                 :            : static void
    1023                 :        533 : rstp_port_set_administrative_bridge_port__(struct rstp_port *p,
    1024                 :            :                                            uint8_t admin_port_state,
    1025                 :            :                                            bool initializing)
    1026                 :            :     OVS_REQUIRES(rstp_mutex)
    1027                 :            : {
    1028         [ -  + ]:        533 :     VLOG_DBG("%s, port %u: set RSTP port admin-port-state to %d",
    1029                 :            :              p->rstp->name, p->port_number, admin_port_state);
    1030                 :            : 
    1031         [ +  + ]:        533 :     if (p->is_administrative_bridge_port != admin_port_state
    1032         [ +  - ]:        524 :         && (admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_DISABLED
    1033         [ +  - ]:        524 :             || admin_port_state == RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED)) {
    1034                 :        524 :         p->is_administrative_bridge_port = admin_port_state;
    1035                 :        524 :         update_port_enabled__(p);
    1036                 :            : 
    1037         [ -  + ]:        524 :         if (!initializing) {
    1038                 :          0 :             struct rstp *rstp = p->rstp;
    1039                 :            : 
    1040                 :          0 :             rstp->changes = true;
    1041                 :          0 :             move_rstp__(rstp);
    1042                 :            :         }
    1043                 :            :     }
    1044                 :        533 : }
    1045                 :            : 
    1046                 :            : /* Sets the port oper_point_to_point_mac parameter. */
    1047                 :            : static void
    1048                 :        526 : rstp_port_set_oper_point_to_point_mac__(struct rstp_port *p,
    1049                 :            :                                         uint8_t new_oper_p2p_mac)
    1050                 :            :     OVS_REQUIRES(rstp_mutex)
    1051                 :            : {
    1052         [ +  + ]:        526 :     if (p->oper_point_to_point_mac != new_oper_p2p_mac
    1053         [ +  - ]:        524 :         && (new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_DISABLED
    1054         [ +  - ]:        524 :             || new_oper_p2p_mac == RSTP_OPER_P2P_MAC_STATE_ENABLED)) {
    1055                 :            : 
    1056                 :        524 :         p->oper_point_to_point_mac = new_oper_p2p_mac;
    1057                 :        524 :         update_port_enabled__(p);
    1058                 :            :     }
    1059                 :        526 : }
    1060                 :            : 
    1061                 :            : /* Initializes a port with the defaults values for its parameters. */
    1062                 :            : static void
    1063                 :        524 : rstp_initialize_port_defaults__(struct rstp_port *p)
    1064                 :            :     OVS_REQUIRES(rstp_mutex)
    1065                 :            : {
    1066                 :        524 :     rstp_port_set_administrative_bridge_port__(p,
    1067                 :            :                                                RSTP_ADMIN_BRIDGE_PORT_STATE_ENABLED,
    1068                 :            :                                                true);
    1069                 :        524 :     rstp_port_set_oper_point_to_point_mac__(p,
    1070                 :            :                                          RSTP_OPER_P2P_MAC_STATE_ENABLED);
    1071                 :        524 :     rstp_port_set_path_cost__(p, RSTP_DEFAULT_PORT_PATH_COST);
    1072                 :        524 :     rstp_port_set_admin_edge__(p, false);
    1073                 :        524 :     rstp_port_set_auto_edge__(p, true);
    1074                 :        524 :     rstp_port_set_mcheck__(p, false);
    1075                 :            : 
    1076                 :            :     /* Initialize state machines. */
    1077                 :        524 :     p->port_receive_sm_state = PORT_RECEIVE_SM_INIT;
    1078                 :        524 :     p->port_protocol_migration_sm_state = PORT_PROTOCOL_MIGRATION_SM_INIT;
    1079                 :        524 :     p->bridge_detection_sm_state = BRIDGE_DETECTION_SM_INIT;
    1080                 :        524 :     p->port_transmit_sm_state = PORT_TRANSMIT_SM_INIT;
    1081                 :        524 :     p->port_information_sm_state = PORT_INFORMATION_SM_INIT;
    1082                 :        524 :     p->port_role_transition_sm_state = PORT_ROLE_TRANSITION_SM_INIT;
    1083                 :        524 :     p->port_state_transition_sm_state = PORT_STATE_TRANSITION_SM_INIT;
    1084                 :        524 :     p->topology_change_sm_state = TOPOLOGY_CHANGE_SM_INIT;
    1085                 :        524 :     p->uptime = 0;
    1086                 :            : 
    1087                 :        524 : }
    1088                 :            : 
    1089                 :            : static void
    1090                 :        288 : reinitialize_port__(struct rstp_port *p)
    1091                 :            :     OVS_REQUIRES(rstp_mutex)
    1092                 :            : {
    1093                 :            :     struct rstp_port temp_port;
    1094                 :            :     struct rstp *rstp;
    1095                 :            : 
    1096                 :        288 :     rstp = p->rstp;
    1097                 :        288 :     temp_port = *p;
    1098                 :        288 :     memset(p, 0, sizeof(struct rstp_port));
    1099                 :            : 
    1100                 :        288 :     p->ref_cnt = temp_port.ref_cnt;
    1101                 :        288 :     p->rstp = rstp;
    1102                 :        288 :     p->node = temp_port.node;
    1103                 :        288 :     p->aux = temp_port.aux;
    1104                 :        288 :     p->port_number = temp_port.port_number;
    1105                 :        288 :     p->port_priority = temp_port.port_priority;
    1106                 :        288 :     p->port_id = temp_port.port_id;
    1107                 :        288 :     p->rstp_state = RSTP_DISCARDING;
    1108                 :            : 
    1109                 :        288 :     rstp_initialize_port_defaults__(p);
    1110                 :            : 
    1111         [ -  + ]:        288 :     VLOG_DBG("%s: RSTP port "RSTP_PORT_ID_FMT" reinitialized.", rstp->name,
    1112                 :            :              p->port_id);
    1113                 :        288 : }
    1114                 :            : 
    1115                 :            : void
    1116                 :        288 : reinitialize_port(struct rstp_port *p)
    1117                 :            :     OVS_EXCLUDED(rstp_mutex)
    1118                 :            : {
    1119                 :        288 :     ovs_mutex_lock(&rstp_mutex);
    1120                 :        288 :     reinitialize_port__(p);
    1121                 :        288 :     ovs_mutex_unlock(&rstp_mutex);
    1122                 :        288 : }
    1123                 :            : 
    1124                 :            : /* Sets the port state. */
    1125                 :            : void
    1126                 :       1934 : rstp_port_set_state__(struct rstp_port *p, enum rstp_state state)
    1127                 :            :     OVS_REQUIRES(rstp_mutex)
    1128                 :            : {
    1129                 :            :     struct rstp *rstp;
    1130                 :            : 
    1131                 :       1934 :     rstp = p->rstp;
    1132         [ -  + ]:       1934 :     VLOG_DBG("%s, port %u: set RSTP port state %s -> %s", rstp->name,
    1133                 :            :              p->port_number,
    1134                 :            :              rstp_state_name(p->rstp_state), rstp_state_name(state));
    1135                 :            : 
    1136 [ +  + ][ +  + ]:       1934 :     if (state != p->rstp_state && !p->state_changed) {
    1137                 :        526 :         p->state_changed = true;
    1138                 :        526 :         seq_change(connectivity_seq_get());
    1139                 :            :     }
    1140                 :       1934 :     p->rstp_state = state;
    1141                 :       1934 : }
    1142                 :            : 
    1143                 :            : void
    1144                 :        524 : rstp_port_set_state(struct rstp_port *p, enum rstp_state state)
    1145                 :            :     OVS_EXCLUDED(rstp_mutex)
    1146                 :            : {
    1147                 :        524 :     ovs_mutex_lock(&rstp_mutex);
    1148                 :        524 :     rstp_port_set_state__(p, state);
    1149                 :        524 :     ovs_mutex_unlock(&rstp_mutex);
    1150                 :        524 : }
    1151                 :            : 
    1152                 :            : /* Adds a RSTP port. */
    1153                 :            : struct rstp_port *
    1154                 :        236 : rstp_add_port(struct rstp *rstp)
    1155                 :            :     OVS_EXCLUDED(rstp_mutex)
    1156                 :            : {
    1157                 :        236 :     struct rstp_port *p = xzalloc(sizeof *p);
    1158                 :            : 
    1159                 :        236 :     ovs_refcount_init(&p->ref_cnt);
    1160                 :        236 :     hmap_node_nullify(&p->node);
    1161                 :            : 
    1162                 :        236 :     ovs_mutex_lock(&rstp_mutex);
    1163                 :        236 :     p->rstp = rstp;
    1164                 :        236 :     rstp_port_set_priority__(p, RSTP_DEFAULT_PORT_PRIORITY);
    1165                 :        236 :     rstp_port_set_port_number__(p, 0);
    1166                 :        236 :     p->aux = NULL;
    1167                 :        236 :     rstp_initialize_port_defaults__(p);
    1168         [ -  + ]:        236 :     VLOG_DBG("%s: RSTP port "RSTP_PORT_ID_FMT" initialized.", rstp->name,
    1169                 :            :              p->port_id);
    1170                 :            : 
    1171                 :        236 :     rstp_port_set_state__(p, RSTP_DISCARDING);
    1172                 :        236 :     rstp->changes = true;
    1173                 :        236 :     move_rstp__(rstp);
    1174         [ -  + ]:        236 :     VLOG_DBG("%s: added port "RSTP_PORT_ID_FMT"", rstp->name, p->port_id);
    1175                 :        236 :     ovs_mutex_unlock(&rstp_mutex);
    1176                 :        236 :     return p;
    1177                 :            : }
    1178                 :            : 
    1179                 :            : /* Caller has to hold a reference to prevent 'rstp_port' from being deleted
    1180                 :            :  * while taking a new reference. */
    1181                 :            : struct rstp_port *
    1182                 :         60 : rstp_port_ref(const struct rstp_port *rp_)
    1183                 :            :     OVS_EXCLUDED(rstp_mutex)
    1184                 :            : {
    1185                 :         60 :     struct rstp_port *rp = CONST_CAST(struct rstp_port *, rp_);
    1186                 :            : 
    1187         [ +  - ]:         60 :     if (rp) {
    1188                 :         60 :         ovs_refcount_ref(&rp->ref_cnt);
    1189                 :            :     }
    1190                 :         60 :     return rp;
    1191                 :            : }
    1192                 :            : 
    1193                 :            : /* Frees RSTP struct.  This can be caller by any thread. */
    1194                 :            : void
    1195                 :     246793 : rstp_port_unref(struct rstp_port *rp)
    1196                 :            :     OVS_EXCLUDED(rstp_mutex)
    1197                 :            : {
    1198 [ +  + ][ +  + ]:     246793 :     if (rp && ovs_refcount_unref_relaxed(&rp->ref_cnt) == 1) {
    1199                 :            :         struct rstp *rstp;
    1200                 :            : 
    1201                 :        236 :         ovs_mutex_lock(&rstp_mutex);
    1202                 :        236 :         rstp = rp->rstp;
    1203                 :        236 :         rstp_port_set_state__(rp, RSTP_DISABLED);
    1204                 :        236 :         hmap_remove(&rstp->ports, &rp->node);
    1205         [ -  + ]:        236 :         VLOG_DBG("%s: removed port "RSTP_PORT_ID_FMT"", rstp->name,
    1206                 :            :                  rp->port_id);
    1207                 :        236 :         ovs_mutex_unlock(&rstp_mutex);
    1208                 :        236 :         free(rp);
    1209                 :            :     }
    1210                 :     246793 : }
    1211                 :            : 
    1212                 :            : /* Sets the port Admin Edge parameter. */
    1213                 :            : static void
    1214                 :        533 : rstp_port_set_admin_edge__(struct rstp_port *port, bool admin_edge)
    1215                 :            :      OVS_REQUIRES(rstp_mutex)
    1216                 :            : {
    1217         [ -  + ]:        533 :     if (port->admin_edge != admin_edge) {
    1218         [ #  # ]:          0 :         VLOG_DBG("%s, port %u: set RSTP Admin Edge to %d", port->rstp->name,
    1219                 :            :                  port->port_number, admin_edge);
    1220                 :            : 
    1221                 :          0 :         port->admin_edge = admin_edge;
    1222                 :            :     }
    1223                 :        533 : }
    1224                 :            : 
    1225                 :            : /* Sets the port Auto Edge parameter. */
    1226                 :            : static void
    1227                 :        533 : rstp_port_set_auto_edge__(struct rstp_port *port, bool auto_edge)
    1228                 :            :     OVS_REQUIRES(rstp_mutex)
    1229                 :            : {
    1230         [ +  + ]:        533 :     if (port->auto_edge != auto_edge) {
    1231         [ -  + ]:        524 :         VLOG_DBG("%s, port %u: set RSTP Auto Edge to %d", port->rstp->name,
    1232                 :            :                  port->port_number, auto_edge);
    1233                 :            : 
    1234                 :        524 :         port->auto_edge = auto_edge;
    1235                 :            :     }
    1236                 :        533 : }
    1237                 :            : 
    1238                 :            : /* Sets the port admin_point_to_point_mac parameter. */
    1239                 :          9 : static void rstp_port_set_admin_point_to_point_mac__(struct rstp_port *port,
    1240                 :            :         enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state)
    1241                 :            :     OVS_REQUIRES(rstp_mutex)
    1242                 :            : {
    1243         [ -  + ]:          9 :     VLOG_DBG("%s, port %u: set RSTP port admin-point-to-point-mac to %d",
    1244                 :            :             port->rstp->name, port->port_number, admin_p2p_mac_state);
    1245         [ +  + ]:          9 :     if (port->admin_point_to_point_mac != admin_p2p_mac_state) {
    1246         [ +  - ]:          2 :         if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_FORCE_TRUE) {
    1247                 :          2 :             port->admin_point_to_point_mac = admin_p2p_mac_state;
    1248                 :          2 :             rstp_port_set_oper_point_to_point_mac__(
    1249                 :            :                 port, RSTP_OPER_P2P_MAC_STATE_ENABLED);
    1250         [ #  # ]:          0 :         } else if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_FORCE_FALSE) {
    1251                 :          0 :             port->admin_point_to_point_mac = admin_p2p_mac_state;
    1252                 :          0 :             rstp_port_set_oper_point_to_point_mac__(
    1253                 :            :                 port, RSTP_OPER_P2P_MAC_STATE_DISABLED);
    1254         [ #  # ]:          0 :         } else if (admin_p2p_mac_state == RSTP_ADMIN_P2P_MAC_AUTO) {
    1255                 :            :             /* If adminPointToPointMAC is set to Auto, then the value of
    1256                 :            :              * operPointToPointMAC is determined in accordance with the
    1257                 :            :              * specific procedures defined for the MAC entity concerned, as
    1258                 :            :              * defined in 6.5. If these procedures determine that the MAC
    1259                 :            :              * entity is connected to a point-to-point LAN, then
    1260                 :            :              * operPointToPointMAC is set TRUE; otherwise it is set FALSE.
    1261                 :            :              * In the absence of a specific definition of how to determine
    1262                 :            :              * whether the MAC is connected to a point-to-point LAN or not,
    1263                 :            :              * the value of operPointToPointMAC shall be FALSE. */
    1264                 :          0 :             port->admin_point_to_point_mac = admin_p2p_mac_state;
    1265                 :          0 :             rstp_port_set_oper_point_to_point_mac__(
    1266                 :            :                 port, RSTP_OPER_P2P_MAC_STATE_DISABLED);
    1267                 :            :         }
    1268                 :            :     }
    1269                 :          9 : }
    1270                 :            : 
    1271                 :            : /* Sets the port mcheck parameter.
    1272                 :            :  * [17.19.13] May be set by management to force the Port Protocol Migration
    1273                 :            :  * state machine to transmit RST BPDUs for a MigrateTime (17.13.9) period, to
    1274                 :            :  * test whether all STP Bridges (17.4) on the attached LAN have been removed
    1275                 :            :  * and the Port can continue to transmit RSTP BPDUs. Setting mcheck has no
    1276                 :            :  * effect if stpVersion (17.20.12) is TRUE, i.e., the Bridge is operating in
    1277                 :            :  * STP Compatibility mode.
    1278                 :            :  */
    1279                 :            : static void
    1280                 :        533 : rstp_port_set_mcheck__(struct rstp_port *port, bool mcheck)
    1281                 :            :     OVS_REQUIRES(rstp_mutex)
    1282                 :            : {
    1283 [ -  + ][ #  # ]:        533 :     if (mcheck == true && port->rstp->force_protocol_version >= 2) {
    1284                 :          0 :         port->mcheck = true;
    1285                 :            : 
    1286         [ #  # ]:          0 :         VLOG_DBG("%s, port %u: set RSTP mcheck to %d", port->rstp->name,
    1287                 :            :                  port->port_number, mcheck);
    1288                 :            :     }
    1289                 :        533 : }
    1290                 :            : 
    1291                 :            : /* Returns the designated bridge id. */
    1292                 :            : rstp_identifier
    1293                 :         25 : rstp_get_designated_id(const struct rstp *rstp)
    1294                 :            :     OVS_EXCLUDED(rstp_mutex)
    1295                 :            : {
    1296                 :            :     rstp_identifier designated_id;
    1297                 :            : 
    1298                 :         25 :     ovs_mutex_lock(&rstp_mutex);
    1299                 :         25 :     designated_id = rstp->root_priority.designated_bridge_id;
    1300                 :         25 :     ovs_mutex_unlock(&rstp_mutex);
    1301                 :            : 
    1302                 :         25 :     return designated_id;
    1303                 :            : }
    1304                 :            : 
    1305                 :            : /* Returns the root bridge id. */
    1306                 :            : rstp_identifier
    1307                 :         25 : rstp_get_root_id(const struct rstp *rstp)
    1308                 :            :     OVS_EXCLUDED(rstp_mutex)
    1309                 :            : {
    1310                 :            :     rstp_identifier root_id;
    1311                 :            : 
    1312                 :         25 :     ovs_mutex_lock(&rstp_mutex);
    1313                 :         25 :     root_id = rstp->root_priority.root_bridge_id;
    1314                 :         25 :     ovs_mutex_unlock(&rstp_mutex);
    1315                 :            : 
    1316                 :         25 :     return root_id;
    1317                 :            : }
    1318                 :            : 
    1319                 :            : /* Returns the designated port id. */
    1320                 :            : uint16_t
    1321                 :         25 : rstp_get_designated_port_id(const struct rstp *rstp)
    1322                 :            :     OVS_EXCLUDED(rstp_mutex)
    1323                 :            : {
    1324                 :            :     uint16_t designated_port_id;
    1325                 :            : 
    1326                 :         25 :     ovs_mutex_lock(&rstp_mutex);
    1327                 :         25 :     designated_port_id = rstp->root_priority.designated_port_id;
    1328                 :         25 :     ovs_mutex_unlock(&rstp_mutex);
    1329                 :            : 
    1330                 :         25 :     return designated_port_id;
    1331                 :            : }
    1332                 :            : 
    1333                 :            : /* Return the bridge port id. */
    1334                 :            : uint16_t
    1335                 :         25 : rstp_get_bridge_port_id(const struct rstp *rstp)
    1336                 :            :     OVS_EXCLUDED(rstp_mutex)
    1337                 :            : {
    1338                 :            :     uint16_t bridge_port_id;
    1339                 :            : 
    1340                 :         25 :     ovs_mutex_lock(&rstp_mutex);
    1341                 :         25 :     bridge_port_id = rstp->root_priority.bridge_port_id;
    1342                 :         25 :     ovs_mutex_unlock(&rstp_mutex);
    1343                 :            : 
    1344                 :         25 :     return bridge_port_id;
    1345                 :            : }
    1346                 :            : 
    1347                 :            : /* Returns true if the bridge believes to the be root of the spanning tree,
    1348                 :            :  * false otherwise.
    1349                 :            :  */
    1350                 :            : bool
    1351                 :         11 : rstp_is_root_bridge(const struct rstp *rstp)
    1352                 :            :     OVS_EXCLUDED(rstp_mutex)
    1353                 :            : {
    1354                 :            :     bool is_root;
    1355                 :            : 
    1356                 :         11 :     ovs_mutex_lock(&rstp_mutex);
    1357                 :         22 :     is_root = rstp->bridge_identifier ==
    1358                 :         11 :                 rstp->root_priority.designated_bridge_id;
    1359                 :         11 :     ovs_mutex_unlock(&rstp_mutex);
    1360                 :            : 
    1361                 :         11 :     return is_root;
    1362                 :            : }
    1363                 :            : 
    1364                 :            : /* Returns the bridge ID of the bridge currently believed to be the root. */
    1365                 :            : rstp_identifier
    1366                 :          0 : rstp_get_designated_root(const struct rstp *rstp)
    1367                 :            :     OVS_EXCLUDED(rstp_mutex)
    1368                 :            : {
    1369                 :            :     rstp_identifier designated_root;
    1370                 :            : 
    1371                 :          0 :     ovs_mutex_lock(&rstp_mutex);
    1372                 :          0 :     designated_root = rstp->root_priority.designated_bridge_id;
    1373                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
    1374                 :            : 
    1375                 :          0 :     return designated_root;
    1376                 :            : }
    1377                 :            : 
    1378                 :            : /* Returns the port connecting 'rstp' to the root bridge, or a null pointer if
    1379                 :            :  * there is no such port.
    1380                 :            :  */
    1381                 :            : struct rstp_port *
    1382                 :        124 : rstp_get_root_port(struct rstp *rstp)
    1383                 :            :     OVS_EXCLUDED(rstp_mutex)
    1384                 :            : {
    1385                 :            :     struct rstp_port *p;
    1386                 :            : 
    1387                 :        124 :     ovs_mutex_lock(&rstp_mutex);
    1388 [ +  - ][ #  # ]:        616 :     HMAP_FOR_EACH (p, node, &rstp->ports) {
    1389         [ +  + ]:        616 :         if (p->port_id == rstp->root_port_id) {
    1390                 :        124 :             ovs_mutex_unlock(&rstp_mutex);
    1391                 :        124 :             return p;
    1392                 :            :         }
    1393                 :            :     }
    1394                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
    1395                 :          0 :     return NULL;
    1396                 :            : }
    1397                 :            : 
    1398                 :            : /* Returns the state of port 'p'. */
    1399                 :            : enum rstp_state
    1400                 :        193 : rstp_port_get_state(const struct rstp_port *p)
    1401                 :            :     OVS_EXCLUDED(rstp_mutex)
    1402                 :            : {
    1403                 :            :     enum rstp_state state;
    1404                 :            : 
    1405                 :        193 :     ovs_mutex_lock(&rstp_mutex);
    1406                 :        193 :     state = p->rstp_state;
    1407                 :        193 :     ovs_mutex_unlock(&rstp_mutex);
    1408                 :            : 
    1409                 :        193 :     return state;
    1410                 :            : }
    1411                 :            : 
    1412                 :            : /* Retrieves port status. */
    1413                 :            : void
    1414                 :         22 : rstp_port_get_status(const struct rstp_port *p, uint16_t *id,
    1415                 :            :                      enum rstp_state *state, enum rstp_port_role *role,
    1416                 :            :                      rstp_identifier *designated_bridge_id,
    1417                 :            :                      uint16_t *designated_port_id,
    1418                 :            :                      uint32_t *designated_path_cost, int *tx_count,
    1419                 :            :                      int *rx_count, int *error_count, int *uptime)
    1420                 :            :     OVS_EXCLUDED(rstp_mutex)
    1421                 :            : {
    1422                 :         22 :     ovs_mutex_lock(&rstp_mutex);
    1423                 :         22 :     *id = p->port_id;
    1424                 :         22 :     *state = p->rstp_state;
    1425                 :         22 :     *role = p->role;
    1426                 :            : 
    1427                 :         22 :     *designated_bridge_id = p->port_priority.designated_bridge_id;
    1428                 :         22 :     *designated_port_id = p->port_priority.designated_port_id;
    1429                 :         22 :     *designated_path_cost = p->port_priority.root_path_cost;
    1430                 :            : 
    1431                 :         22 :     *tx_count = p->tx_count;
    1432                 :         22 :     *rx_count = p->rx_rstp_bpdu_cnt;
    1433                 :         22 :     *error_count = p->error_count;
    1434                 :         22 :     *uptime = p->uptime;
    1435                 :         22 :     ovs_mutex_unlock(&rstp_mutex);
    1436                 :         22 : }
    1437                 :            : 
    1438                 :            : void
    1439                 :          9 : rstp_port_set(struct rstp_port *port, uint16_t port_num, int priority,
    1440                 :            :               uint32_t path_cost, bool is_admin_edge, bool is_auto_edge,
    1441                 :            :               enum rstp_admin_point_to_point_mac_state admin_p2p_mac_state,
    1442                 :            :               bool admin_port_state, bool do_mcheck, void *aux)
    1443                 :            :     OVS_EXCLUDED(rstp_mutex)
    1444                 :            : {
    1445                 :          9 :     ovs_mutex_lock(&rstp_mutex);
    1446                 :          9 :     port->aux = aux;
    1447                 :          9 :     rstp_port_set_priority__(port, priority);
    1448                 :          9 :     rstp_port_set_port_number__(port, port_num);
    1449                 :          9 :     rstp_port_set_path_cost__(port, path_cost);
    1450                 :          9 :     rstp_port_set_admin_edge__(port, is_admin_edge);
    1451                 :          9 :     rstp_port_set_auto_edge__(port, is_auto_edge);
    1452                 :          9 :     rstp_port_set_admin_point_to_point_mac__(port, admin_p2p_mac_state);
    1453                 :          9 :     rstp_port_set_administrative_bridge_port__(port, admin_port_state, false);
    1454                 :          9 :     rstp_port_set_mcheck__(port, do_mcheck);
    1455                 :          9 :     ovs_mutex_unlock(&rstp_mutex);
    1456                 :          9 : }
    1457                 :            : 
    1458                 :            : /* Individual setters only used by test-rstp.c. */
    1459                 :            : void
    1460                 :          1 : rstp_port_set_priority(struct rstp_port *port, int priority)
    1461                 :            :     OVS_EXCLUDED(rstp_mutex)
    1462                 :            : {
    1463                 :          1 :     ovs_mutex_lock(&rstp_mutex);
    1464                 :          1 :     rstp_port_set_priority__(port, priority);
    1465                 :          1 :     ovs_mutex_unlock(&rstp_mutex);
    1466                 :          1 : }
    1467                 :            : 
    1468                 :            : void
    1469                 :        108 : rstp_port_set_path_cost(struct rstp_port *port, uint32_t path_cost)
    1470                 :            :     OVS_EXCLUDED(rstp_mutex)
    1471                 :            : {
    1472                 :        108 :     ovs_mutex_lock(&rstp_mutex);
    1473                 :        108 :     rstp_port_set_path_cost__(port, path_cost);
    1474                 :        108 :     ovs_mutex_unlock(&rstp_mutex);
    1475                 :        108 : }
    1476                 :            : 
    1477                 :            : void
    1478                 :        236 : rstp_port_set_aux(struct rstp_port *port, void *aux)
    1479                 :            :     OVS_EXCLUDED(rstp_mutex)
    1480                 :            : {
    1481                 :        236 :     ovs_mutex_lock(&rstp_mutex);
    1482                 :        236 :     port->aux = aux;
    1483                 :        236 :     ovs_mutex_unlock(&rstp_mutex);
    1484                 :        236 : }
    1485                 :            : 
    1486                 :            : /* Unixctl. */
    1487                 :            : static struct rstp *
    1488                 :          0 : rstp_find(const char *name)
    1489                 :            :     OVS_REQUIRES(rstp_mutex)
    1490                 :            : {
    1491                 :            :     struct rstp *rstp;
    1492                 :            : 
    1493         [ #  # ]:          0 :     LIST_FOR_EACH (rstp, node, all_rstps) {
    1494         [ #  # ]:          0 :         if (!strcmp(rstp->name, name)) {
    1495                 :          0 :             return rstp;
    1496                 :            :         }
    1497                 :            :     }
    1498                 :          0 :     return NULL;
    1499                 :            : }
    1500                 :            : 
    1501                 :            : static void
    1502                 :          0 : rstp_unixctl_tcn(struct unixctl_conn *conn, int argc,
    1503                 :            :                  const char *argv[], void *aux OVS_UNUSED)
    1504                 :            :     OVS_EXCLUDED(rstp_mutex)
    1505                 :            : {
    1506                 :          0 :     ovs_mutex_lock(&rstp_mutex);
    1507         [ #  # ]:          0 :     if (argc > 1) {
    1508                 :          0 :         struct rstp *rstp = rstp_find(argv[1]);
    1509         [ #  # ]:          0 :         if (!rstp) {
    1510                 :          0 :             unixctl_command_reply_error(conn, "No such RSTP object");
    1511                 :          0 :             goto out;
    1512                 :            :         }
    1513                 :          0 :         rstp->changes = true;
    1514                 :          0 :         move_rstp__(rstp);
    1515                 :            :     } else {
    1516                 :            :         struct rstp *rstp;
    1517         [ #  # ]:          0 :         LIST_FOR_EACH (rstp, node, all_rstps) {
    1518                 :          0 :             rstp->changes = true;
    1519                 :          0 :             move_rstp__(rstp);
    1520                 :            :         }
    1521                 :            :     }
    1522                 :          0 :     unixctl_command_reply(conn, "OK");
    1523                 :            : 
    1524                 :            : out:
    1525                 :          0 :     ovs_mutex_unlock(&rstp_mutex);
    1526                 :          0 : }

Generated by: LCOV version 1.12