LCOV - code coverage report
Current view: top level - lib - stp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 630 721 87.4 %
Date: 2016-09-14 01:02:56 Functions: 78 88 88.6 %
Branches: 224 306 73.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
       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                 :            : /* Based on sample implementation in 802.1D-1998.  Above copyright and license
      18                 :            :  * applies to all modifications. */
      19                 :            : 
      20                 :            : #include <config.h>
      21                 :            : 
      22                 :            : #include "stp.h"
      23                 :            : #include <sys/types.h>
      24                 :            : #include <netinet/in.h>
      25                 :            : #include <arpa/inet.h>
      26                 :            : #include <inttypes.h>
      27                 :            : #include <stdlib.h>
      28                 :            : #include "byte-order.h"
      29                 :            : #include "connectivity.h"
      30                 :            : #include "openvswitch/ofpbuf.h"
      31                 :            : #include "ovs-atomic.h"
      32                 :            : #include "dp-packet.h"
      33                 :            : #include "packets.h"
      34                 :            : #include "seq.h"
      35                 :            : #include "unixctl.h"
      36                 :            : #include "util.h"
      37                 :            : #include "openvswitch/vlog.h"
      38                 :            : 
      39                 :       2462 : VLOG_DEFINE_THIS_MODULE(stp);
      40                 :            : 
      41                 :            : static struct vlog_rate_limit stp_rl = VLOG_RATE_LIMIT_INIT(60, 60);
      42                 :            : 
      43                 :            : #define STP_PROTOCOL_ID 0x0000
      44                 :            : #define STP_PROTOCOL_VERSION 0x00
      45                 :            : #define STP_TYPE_CONFIG 0x00
      46                 :            : #define STP_TYPE_TCN 0x80
      47                 :            : 
      48                 :            : OVS_PACKED(
      49                 :            : struct stp_bpdu_header {
      50                 :            :     ovs_be16 protocol_id;       /* STP_PROTOCOL_ID. */
      51                 :            :     uint8_t protocol_version;   /* STP_PROTOCOL_VERSION. */
      52                 :            :     uint8_t bpdu_type;          /* One of STP_TYPE_*. */
      53                 :            : });
      54                 :            : BUILD_ASSERT_DECL(sizeof(struct stp_bpdu_header) == 4);
      55                 :            : 
      56                 :            : enum stp_config_bpdu_flags {
      57                 :            :     STP_CONFIG_TOPOLOGY_CHANGE_ACK = 0x80,
      58                 :            :     STP_CONFIG_TOPOLOGY_CHANGE = 0x01
      59                 :            : };
      60                 :            : 
      61                 :            : OVS_PACKED(
      62                 :            : struct stp_config_bpdu {
      63                 :            :     struct stp_bpdu_header header; /* Type STP_TYPE_CONFIG. */
      64                 :            :     uint8_t flags;                 /* STP_CONFIG_* flags. */
      65                 :            :     ovs_be64 root_id;              /* 8.5.1.1: Bridge believed to be root. */
      66                 :            :     ovs_be32 root_path_cost;       /* 8.5.1.2: Cost of path to root. */
      67                 :            :     ovs_be64 bridge_id;            /* 8.5.1.3: ID of transmitting bridge. */
      68                 :            :     ovs_be16 port_id;              /* 8.5.1.4: Port transmitting the BPDU. */
      69                 :            :     ovs_be16 message_age;          /* 8.5.1.5: Age of BPDU at tx time. */
      70                 :            :     ovs_be16 max_age;              /* 8.5.1.6: Timeout for received data. */
      71                 :            :     ovs_be16 hello_time;           /* 8.5.1.7: Time between BPDU generation. */
      72                 :            :     ovs_be16 forward_delay;        /* 8.5.1.8: State progression delay. */
      73                 :            : });
      74                 :            : BUILD_ASSERT_DECL(sizeof(struct stp_config_bpdu) == 35);
      75                 :            : 
      76                 :            : OVS_PACKED(
      77                 :            : struct stp_tcn_bpdu {
      78                 :            :     struct stp_bpdu_header header; /* Type STP_TYPE_TCN. */
      79                 :            : });
      80                 :            : BUILD_ASSERT_DECL(sizeof(struct stp_tcn_bpdu) == 4);
      81                 :            : 
      82                 :            : struct stp_timer {
      83                 :            :     bool active;                 /* Timer in use? */
      84                 :            :     int value;                   /* Current value of timer, counting up. */
      85                 :            : };
      86                 :            : 
      87                 :            : struct stp_port {
      88                 :            :     struct stp *stp;
      89                 :            :     char *port_name;                /* Human-readable name for log messages. */
      90                 :            :     void *aux;                      /* Auxiliary data the user may retrieve. */
      91                 :            :     int port_id;                    /* 8.5.5.1: Unique port identifier. */
      92                 :            :     enum stp_state state;           /* 8.5.5.2: Current state. */
      93                 :            :     int path_cost;                  /* 8.5.5.3: Cost of tx/rx on this port. */
      94                 :            :     stp_identifier designated_root; /* 8.5.5.4. */
      95                 :            :     int designated_cost;            /* 8.5.5.5: Path cost to root on port. */
      96                 :            :     stp_identifier designated_bridge; /* 8.5.5.6. */
      97                 :            :     int designated_port;            /* 8.5.5.7: Port to send config msgs on. */
      98                 :            :     bool topology_change_ack;       /* 8.5.5.8: Flag for next config BPDU. */
      99                 :            :     bool config_pending;            /* 8.5.5.9: Send BPDU when hold expires? */
     100                 :            :     bool change_detection_enabled;  /* 8.5.5.10: Detect topology changes? */
     101                 :            : 
     102                 :            :     struct stp_timer message_age_timer; /* 8.5.6.1: Age of received info. */
     103                 :            :     struct stp_timer forward_delay_timer; /* 8.5.6.2: State change timer. */
     104                 :            :     struct stp_timer hold_timer;        /* 8.5.6.3: BPDU rate limit timer. */
     105                 :            : 
     106                 :            :     int tx_count;                   /* Number of BPDUs transmitted. */
     107                 :            :     int rx_count;                   /* Number of valid BPDUs received. */
     108                 :            :     int error_count;                /* Number of bad BPDUs received. */
     109                 :            : 
     110                 :            :     bool state_changed;
     111                 :            : };
     112                 :            : 
     113                 :            : struct stp {
     114                 :            :     struct ovs_list node;           /* Node in all_stps list. */
     115                 :            : 
     116                 :            :     /* Static bridge data. */
     117                 :            :     char *name;                     /* Human-readable name for log messages. */
     118                 :            :     stp_identifier bridge_id;       /* 8.5.3.7: This bridge. */
     119                 :            :     int max_age;                    /* 8.5.3.4: Time to drop received data. */
     120                 :            :     int hello_time;                 /* 8.5.3.5: Time between sending BPDUs. */
     121                 :            :     int forward_delay;              /* 8.5.3.6: Delay between state changes. */
     122                 :            :     int bridge_max_age;             /* 8.5.3.8: max_age when we're root. */
     123                 :            :     int bridge_hello_time;          /* 8.5.3.9: hello_time as root. */
     124                 :            :     int bridge_forward_delay;       /* 8.5.3.10: forward_delay as root. */
     125                 :            :     int rq_max_age;                 /* User-requested max age, in ms. */
     126                 :            :     int rq_hello_time;              /* User-requested hello time, in ms. */
     127                 :            :     int rq_forward_delay;           /* User-requested forward delay, in ms. */
     128                 :            :     int elapsed_remainder;          /* Left-over msecs from last stp_tick(). */
     129                 :            : 
     130                 :            :     /* Dynamic bridge data. */
     131                 :            :     stp_identifier designated_root; /* 8.5.3.1: Bridge believed to be root. */
     132                 :            :     unsigned int root_path_cost;    /* 8.5.3.2: Cost of path to root. */
     133                 :            :     struct stp_port *root_port;     /* 8.5.3.3: Lowest cost port to root. */
     134                 :            :     bool topology_change_detected;  /* 8.5.3.11: Detected a topology change? */
     135                 :            :     bool topology_change;           /* 8.5.3.12: Received topology change? */
     136                 :            : 
     137                 :            :     /* Bridge timers. */
     138                 :            :     struct stp_timer hello_timer;   /* 8.5.4.1: Hello timer. */
     139                 :            :     struct stp_timer tcn_timer;     /* 8.5.4.2: Topology change timer. */
     140                 :            :     struct stp_timer topology_change_timer; /* 8.5.4.3. */
     141                 :            : 
     142                 :            :     /* Ports. */
     143                 :            :     struct stp_port ports[STP_MAX_PORTS];
     144                 :            : 
     145                 :            :     /* Interface to client. */
     146                 :            :     bool fdb_needs_flush;          /* MAC learning tables needs flushing. */
     147                 :            :     struct stp_port *first_changed_port;
     148                 :            :     void (*send_bpdu)(struct dp_packet *bpdu, int port_no, void *aux);
     149                 :            :     void *aux;
     150                 :            : 
     151                 :            :     struct ovs_refcount ref_cnt;
     152                 :            : };
     153                 :            : 
     154                 :            : static struct ovs_mutex mutex;
     155                 :            : static struct ovs_list all_stps__ = OVS_LIST_INITIALIZER(&all_stps__);
     156                 :            : static struct ovs_list *const all_stps OVS_GUARDED_BY(mutex) = &all_stps__;
     157                 :            : 
     158                 :            : #define FOR_EACH_ENABLED_PORT(PORT, STP)                        \
     159                 :            :     for ((PORT) = stp_next_enabled_port((STP), (STP)->ports);   \
     160                 :            :          (PORT);                                                \
     161                 :            :          (PORT) = stp_next_enabled_port((STP), (PORT) + 1))
     162                 :            : static struct stp_port *
     163                 :     310254 : stp_next_enabled_port(const struct stp *stp, const struct stp_port *port)
     164                 :            :     OVS_REQUIRES(mutex)
     165                 :            : {
     166         [ +  + ]:   17364206 :     for (; port < &stp->ports[ARRAY_SIZE(stp->ports)]; port++) {
     167         [ +  + ]:   17296378 :         if (port->state != STP_DISABLED) {
     168                 :     242426 :             return CONST_CAST(struct stp_port *, port);
     169                 :            :         }
     170                 :            :     }
     171                 :      67828 :     return NULL;
     172                 :            : }
     173                 :            : 
     174                 :            : #define MESSAGE_AGE_INCREMENT 1
     175                 :            : 
     176                 :            : static void stp_transmit_config(struct stp_port *) OVS_REQUIRES(mutex);
     177                 :            : static bool stp_supersedes_port_info(const struct stp_port *,
     178                 :            :                                      const struct stp_config_bpdu *)
     179                 :            :     OVS_REQUIRES(mutex);
     180                 :            : static void stp_record_config_information(struct stp_port *,
     181                 :            :                                           const struct stp_config_bpdu *)
     182                 :            :     OVS_REQUIRES(mutex);
     183                 :            : static void stp_record_config_timeout_values(struct stp *,
     184                 :            :                                              const struct stp_config_bpdu  *)
     185                 :            :     OVS_REQUIRES(mutex);
     186                 :            : static bool stp_is_designated_port(const struct stp_port *)
     187                 :            :     OVS_REQUIRES(mutex);
     188                 :            : static void stp_config_bpdu_generation(struct stp *) OVS_REQUIRES(mutex);
     189                 :            : static void stp_transmit_tcn(struct stp *) OVS_REQUIRES(mutex);
     190                 :            : static void stp_configuration_update(struct stp *) OVS_REQUIRES(mutex);
     191                 :            : static bool stp_supersedes_root(const struct stp_port *root,
     192                 :            :                                 const struct stp_port *) OVS_REQUIRES(mutex);
     193                 :            : static void stp_root_selection(struct stp *) OVS_REQUIRES(mutex);
     194                 :            : static void stp_designated_port_selection(struct stp *) OVS_REQUIRES(mutex);
     195                 :            : static void stp_become_designated_port(struct stp_port *)
     196                 :            :     OVS_REQUIRES(mutex);
     197                 :            : static void stp_port_state_selection(struct stp *) OVS_REQUIRES(mutex);
     198                 :            : static void stp_make_forwarding(struct stp_port *) OVS_REQUIRES(mutex);
     199                 :            : static void stp_make_blocking(struct stp_port *) OVS_REQUIRES(mutex);
     200                 :            : static void stp_set_port_state(struct stp_port *, enum stp_state)
     201                 :            :     OVS_REQUIRES(mutex);
     202                 :            : static void stp_topology_change_detection(struct stp *) OVS_REQUIRES(mutex);
     203                 :            : static void stp_topology_change_acknowledged(struct stp *)
     204                 :            :     OVS_REQUIRES(mutex);
     205                 :            : static void stp_acknowledge_topology_change(struct stp_port *)
     206                 :            :     OVS_REQUIRES(mutex);
     207                 :            : static void stp_received_config_bpdu(struct stp *, struct stp_port *,
     208                 :            :                                      const struct stp_config_bpdu *)
     209                 :            :     OVS_REQUIRES(mutex);
     210                 :            : static void stp_received_tcn_bpdu(struct stp *, struct stp_port *)
     211                 :            :     OVS_REQUIRES(mutex);
     212                 :            : static void stp_hello_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
     213                 :            : static void stp_message_age_timer_expiry(struct stp_port *)
     214                 :            :     OVS_REQUIRES(mutex);
     215                 :            : static bool stp_is_designated_for_some_port(const struct stp *)
     216                 :            :     OVS_REQUIRES(mutex);
     217                 :            : static void stp_forward_delay_timer_expiry(struct stp_port *)
     218                 :            :     OVS_REQUIRES(mutex);
     219                 :            : static void stp_tcn_timer_expiry(struct stp *) OVS_REQUIRES(mutex);
     220                 :            : static void stp_topology_change_timer_expiry(struct stp *)
     221                 :            :     OVS_REQUIRES(mutex);
     222                 :            : static void stp_hold_timer_expiry(struct stp_port *) OVS_REQUIRES(mutex);
     223                 :            : static void stp_initialize_port(struct stp_port *, enum stp_state)
     224                 :            :     OVS_REQUIRES(mutex);
     225                 :            : static void stp_become_root_bridge(struct stp *) OVS_REQUIRES(mutex);
     226                 :            : static void stp_update_bridge_timers(struct stp *) OVS_REQUIRES(mutex);
     227                 :            : 
     228                 :            : static int clamp(int x, int min, int max);
     229                 :            : static int ms_to_timer(int ms);
     230                 :            : static int timer_to_ms(int timer);
     231                 :            : static void stp_start_timer(struct stp_timer *, int value);
     232                 :            : static void stp_stop_timer(struct stp_timer *);
     233                 :            : static bool stp_timer_expired(struct stp_timer *, int elapsed, int timeout);
     234                 :            : 
     235                 :            : static void stp_send_bpdu(struct stp_port *, const void *, size_t)
     236                 :            :     OVS_REQUIRES(mutex);
     237                 :            : static void stp_unixctl_tcn(struct unixctl_conn *, int argc,
     238                 :            :                             const char *argv[], void *aux);
     239                 :            : 
     240                 :            : void
     241                 :        663 : stp_init(void)
     242                 :            : {
     243                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     244                 :            : 
     245         [ +  + ]:        663 :     if (ovsthread_once_start(&once)) {
     246                 :            :         /* We need a recursive mutex because stp_send_bpdu() could loop back
     247                 :            :          * into the stp module through a patch port.  This happens
     248                 :            :          * intentionally as part of the unit tests.  Ideally we'd ditch
     249                 :            :          * the call back function, but for now this is what we have. */
     250                 :        630 :         ovs_mutex_init_recursive(&mutex);
     251                 :            : 
     252                 :        630 :         unixctl_command_register("stp/tcn", "[bridge]", 0, 1, stp_unixctl_tcn,
     253                 :            :                                  NULL);
     254                 :        630 :         ovsthread_once_done(&once);
     255                 :            :     }
     256                 :        663 : }
     257                 :            : 
     258                 :            : /* Creates and returns a new STP instance that initially has no ports enabled.
     259                 :            :  *
     260                 :            :  * 'bridge_id' should be a 48-bit MAC address as returned by
     261                 :            :  * eth_addr_to_uint64().  'bridge_id' may also have a priority value in its top
     262                 :            :  * 16 bits; if those bits are set to 0, STP_DEFAULT_BRIDGE_PRIORITY is used.
     263                 :            :  * (This priority may be changed with stp_set_bridge_priority().)
     264                 :            :  *
     265                 :            :  * When the bridge needs to send out a BPDU, it calls 'send_bpdu'.  This
     266                 :            :  * callback may be called from stp_tick() or stp_received_bpdu().  The
     267                 :            :  * arguments to 'send_bpdu' are an STP BPDU encapsulated in 'bpdu',
     268                 :            :  * the spanning tree port number 'port_no' that should transmit the
     269                 :            :  * packet, and auxiliary data to be passed to the callback in 'aux'.
     270                 :            :  */
     271                 :            : struct stp *
     272                 :         46 : stp_create(const char *name, stp_identifier bridge_id,
     273                 :            :            void (*send_bpdu)(struct dp_packet *bpdu, int port_no, void *aux),
     274                 :            :            void *aux)
     275                 :            : {
     276                 :            :     struct stp *stp;
     277                 :            :     struct stp_port *p;
     278                 :            : 
     279                 :         46 :     stp_init();
     280                 :            : 
     281                 :         46 :     ovs_mutex_lock(&mutex);
     282                 :         46 :     stp = xzalloc(sizeof *stp);
     283                 :         46 :     stp->name = xstrdup(name);
     284                 :         46 :     stp->bridge_id = bridge_id;
     285         [ +  - ]:         46 :     if (!(stp->bridge_id >> 48)) {
     286                 :         46 :         stp->bridge_id |= (uint64_t) STP_DEFAULT_BRIDGE_PRIORITY << 48;
     287                 :            :     }
     288                 :            : 
     289                 :         46 :     stp->rq_max_age = STP_DEFAULT_MAX_AGE;
     290                 :         46 :     stp->rq_hello_time = STP_DEFAULT_HELLO_TIME;
     291                 :         46 :     stp->rq_forward_delay = STP_DEFAULT_FWD_DELAY;
     292                 :         46 :     stp_update_bridge_timers(stp);
     293                 :         46 :     stp->max_age = stp->bridge_max_age;
     294                 :         46 :     stp->hello_time = stp->bridge_hello_time;
     295                 :         46 :     stp->forward_delay = stp->bridge_forward_delay;
     296                 :            : 
     297                 :         46 :     stp->designated_root = stp->bridge_id;
     298                 :         46 :     stp->root_path_cost = 0;
     299                 :         46 :     stp->root_port = NULL;
     300                 :         46 :     stp->topology_change_detected = false;
     301                 :         46 :     stp->topology_change = false;
     302                 :            : 
     303                 :         46 :     stp_stop_timer(&stp->tcn_timer);
     304                 :         46 :     stp_stop_timer(&stp->topology_change_timer);
     305                 :         46 :     stp_start_timer(&stp->hello_timer, 0);
     306                 :            : 
     307                 :         46 :     stp->send_bpdu = send_bpdu;
     308                 :         46 :     stp->aux = aux;
     309                 :            : 
     310                 :         46 :     stp->first_changed_port = &stp->ports[ARRAY_SIZE(stp->ports)];
     311         [ +  + ]:      11776 :     for (p = stp->ports; p < &stp->ports[ARRAY_SIZE(stp->ports)]; p++) {
     312                 :      11730 :         p->stp = stp;
     313                 :      11730 :         p->port_id = (stp_port_no(p) + 1) | (STP_DEFAULT_PORT_PRIORITY << 8);
     314                 :      11730 :         p->path_cost = 19;      /* Recommended default for 100 Mb/s link. */
     315                 :      11730 :         stp_initialize_port(p, STP_DISABLED);
     316                 :            :     }
     317                 :         46 :     ovs_refcount_init(&stp->ref_cnt);
     318                 :            : 
     319                 :         46 :     ovs_list_push_back(all_stps, &stp->node);
     320                 :         46 :     ovs_mutex_unlock(&mutex);
     321                 :         46 :     return stp;
     322                 :            : }
     323                 :            : 
     324                 :            : struct stp *
     325                 :         64 : stp_ref(const struct stp *stp_)
     326                 :            : {
     327                 :         64 :     struct stp *stp = CONST_CAST(struct stp *, stp_);
     328         [ +  - ]:         64 :     if (stp) {
     329                 :         64 :         ovs_refcount_ref(&stp->ref_cnt);
     330                 :            :     }
     331                 :         64 :     return stp;
     332                 :            : }
     333                 :            : 
     334                 :            : /* Destroys 'stp'. */
     335                 :            : void
     336                 :      46572 : stp_unref(struct stp *stp)
     337                 :            : {
     338 [ +  + ][ +  + ]:      46572 :     if (stp && ovs_refcount_unref_relaxed(&stp->ref_cnt) == 1) {
     339                 :            :         size_t i;
     340                 :            : 
     341                 :         44 :         ovs_mutex_lock(&mutex);
     342                 :         44 :         ovs_list_remove(&stp->node);
     343                 :         44 :         ovs_mutex_unlock(&mutex);
     344                 :         44 :         free(stp->name);
     345                 :            : 
     346         [ +  + ]:      11264 :         for (i = 0; i < STP_MAX_PORTS; i++) {
     347                 :      11220 :             free(stp->ports[i].port_name);
     348                 :            :         }
     349                 :         44 :         free(stp);
     350                 :            :     }
     351                 :      46572 : }
     352                 :            : 
     353                 :            : /* Runs 'stp' given that 'ms' milliseconds have passed. */
     354                 :            : void
     355                 :      14462 : stp_tick(struct stp *stp, int ms)
     356                 :            : {
     357                 :            :     struct stp_port *p;
     358                 :            :     int elapsed;
     359                 :            : 
     360                 :      14462 :     ovs_mutex_lock(&mutex);
     361                 :            :     /* Convert 'ms' to STP timer ticks.  Preserve any leftover milliseconds
     362                 :            :      * from previous stp_tick() calls so that we don't lose STP ticks when we
     363                 :            :      * are called too frequently. */
     364                 :      14462 :     ms = clamp(ms, 0, INT_MAX - 1000) + stp->elapsed_remainder;
     365                 :      14462 :     elapsed = ms_to_timer(ms);
     366                 :      14462 :     stp->elapsed_remainder = ms - timer_to_ms(elapsed);
     367         [ +  + ]:      14462 :     if (!elapsed) {
     368                 :         15 :         goto out;
     369                 :            :     }
     370                 :            : 
     371         [ +  + ]:      14447 :     if (stp_timer_expired(&stp->hello_timer, elapsed, stp->hello_time)) {
     372                 :       2113 :         stp_hello_timer_expiry(stp);
     373                 :            :     }
     374         [ +  + ]:      14447 :     if (stp_timer_expired(&stp->tcn_timer, elapsed, stp->bridge_hello_time)) {
     375                 :          1 :         stp_tcn_timer_expiry(stp);
     376                 :            :     }
     377         [ +  + ]:      14447 :     if (stp_timer_expired(&stp->topology_change_timer, elapsed,
     378                 :      14447 :                           stp->max_age + stp->forward_delay)) {
     379                 :         21 :         stp_topology_change_timer_expiry(stp);
     380                 :            :     }
     381         [ +  + ]:      64163 :     FOR_EACH_ENABLED_PORT (p, stp) {
     382         [ +  + ]:      49716 :         if (stp_timer_expired(&p->message_age_timer, elapsed, stp->max_age)) {
     383                 :          2 :             stp_message_age_timer_expiry(p);
     384                 :            :         }
     385                 :            :     }
     386         [ +  + ]:      64163 :     FOR_EACH_ENABLED_PORT (p, stp) {
     387         [ +  + ]:      49716 :         if (stp_timer_expired(&p->forward_delay_timer, elapsed,
     388                 :            :                               stp->forward_delay)) {
     389                 :        270 :             stp_forward_delay_timer_expiry(p);
     390                 :            :         }
     391         [ +  + ]:      49716 :         if (stp_timer_expired(&p->hold_timer, elapsed, ms_to_timer(1000))) {
     392                 :      15146 :             stp_hold_timer_expiry(p);
     393                 :            :         }
     394                 :            :     }
     395                 :            : 
     396                 :            : out:
     397                 :      14462 :     ovs_mutex_unlock(&mutex);
     398                 :      14462 : }
     399                 :            : 
     400                 :            : static void
     401                 :         31 : set_bridge_id(struct stp *stp, stp_identifier new_bridge_id)
     402                 :            :     OVS_REQUIRES(mutex)
     403                 :            : {
     404         [ +  + ]:         31 :     if (new_bridge_id != stp->bridge_id) {
     405                 :            :         bool root;
     406                 :            :         struct stp_port *p;
     407                 :            : 
     408                 :         11 :         root = stp_is_root_bridge(stp);
     409         [ +  + ]:         39 :         FOR_EACH_ENABLED_PORT (p, stp) {
     410         [ +  + ]:         28 :             if (stp_is_designated_port(p)) {
     411                 :         12 :                 p->designated_bridge = new_bridge_id;
     412                 :            :             }
     413                 :            :         }
     414                 :         11 :         stp->bridge_id = new_bridge_id;
     415                 :         11 :         stp_configuration_update(stp);
     416                 :         11 :         stp_port_state_selection(stp);
     417 [ +  - ][ +  + ]:         11 :         if (stp_is_root_bridge(stp) && !root) {
     418                 :          6 :             stp_become_root_bridge(stp);
     419                 :            :         }
     420                 :            :     }
     421                 :         31 : }
     422                 :            : 
     423                 :            : void
     424                 :         10 : stp_set_bridge_id(struct stp *stp, stp_identifier bridge_id)
     425                 :            : {
     426                 :         10 :     const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
     427                 :         10 :     const uint64_t pri_bits = ~mac_bits;
     428                 :         10 :     ovs_mutex_lock(&mutex);
     429                 :         10 :     set_bridge_id(stp, (stp->bridge_id & pri_bits) | (bridge_id & mac_bits));
     430                 :         10 :     ovs_mutex_unlock(&mutex);
     431                 :         10 : }
     432                 :            : 
     433                 :            : void
     434                 :         21 : stp_set_bridge_priority(struct stp *stp, uint16_t new_priority)
     435                 :            : {
     436                 :         21 :     const uint64_t mac_bits = (UINT64_C(1) << 48) - 1;
     437                 :         21 :     ovs_mutex_lock(&mutex);
     438                 :         21 :     set_bridge_id(stp, ((stp->bridge_id & mac_bits)
     439                 :         21 :                         | ((uint64_t) new_priority << 48)));
     440                 :         21 :     ovs_mutex_unlock(&mutex);
     441                 :         21 : }
     442                 :            : 
     443                 :            : /* Sets the desired hello time for 'stp' to 'ms', in milliseconds.  The actual
     444                 :            :  * hello time is clamped to the range of 1 to 10 seconds and subject to the
     445                 :            :  * relationship (bridge_max_age >= 2 * (bridge_hello_time + 1 s)).  The bridge
     446                 :            :  * hello time is only used when 'stp' is the root bridge. */
     447                 :            : void
     448                 :         10 : stp_set_hello_time(struct stp *stp, int ms)
     449                 :            : {
     450                 :         10 :     ovs_mutex_lock(&mutex);
     451                 :         10 :     stp->rq_hello_time = ms;
     452                 :         10 :     stp_update_bridge_timers(stp);
     453                 :         10 :     ovs_mutex_unlock(&mutex);
     454                 :         10 : }
     455                 :            : 
     456                 :            : /* Sets the desired max age for 'stp' to 'ms', in milliseconds.  The actual max
     457                 :            :  * age is clamped to the range of 6 to 40 seconds and subject to the
     458                 :            :  * relationships (2 * (bridge_forward_delay - 1 s) >= bridge_max_age) and
     459                 :            :  * (bridge_max_age >= 2 * (bridge_hello_time + 1 s)).  The bridge max age is
     460                 :            :  * only used when 'stp' is the root bridge. */
     461                 :            : void
     462                 :         10 : stp_set_max_age(struct stp *stp, int ms)
     463                 :            : {
     464                 :         10 :     ovs_mutex_lock(&mutex);
     465                 :         10 :     stp->rq_max_age = ms;
     466                 :         10 :     stp_update_bridge_timers(stp);
     467                 :         10 :     ovs_mutex_unlock(&mutex);
     468                 :         10 : }
     469                 :            : 
     470                 :            : /* Sets the desired forward delay for 'stp' to 'ms', in milliseconds.  The
     471                 :            :  * actual forward delay is clamped to the range of 4 to 30 seconds and subject
     472                 :            :  * to the relationship (2 * (bridge_forward_delay - 1 s) >= bridge_max_age).
     473                 :            :  * The bridge forward delay is only used when 'stp' is the root bridge. */
     474                 :            : void
     475                 :         10 : stp_set_forward_delay(struct stp *stp, int ms)
     476                 :            : {
     477                 :         10 :     ovs_mutex_lock(&mutex);
     478                 :         10 :     stp->rq_forward_delay = ms;
     479                 :         10 :     stp_update_bridge_timers(stp);
     480                 :         10 :     ovs_mutex_unlock(&mutex);
     481                 :         10 : }
     482                 :            : 
     483                 :            : /* Returns the name given to 'stp' in the call to stp_create(). */
     484                 :            : const char *
     485                 :          0 : stp_get_name(const struct stp *stp)
     486                 :            : {
     487                 :            :     char *name;
     488                 :            : 
     489                 :          0 :     ovs_mutex_lock(&mutex);
     490                 :          0 :     name = stp->name;
     491                 :          0 :     ovs_mutex_unlock(&mutex);
     492                 :          0 :     return name;
     493                 :            : }
     494                 :            : 
     495                 :            : /* Returns the bridge ID for 'stp'. */
     496                 :            : stp_identifier
     497                 :         38 : stp_get_bridge_id(const struct stp *stp)
     498                 :            : {
     499                 :            :     stp_identifier bridge_id;
     500                 :            : 
     501                 :         38 :     ovs_mutex_lock(&mutex);
     502                 :         38 :     bridge_id = stp->bridge_id;
     503                 :         38 :     ovs_mutex_unlock(&mutex);
     504                 :         38 :     return bridge_id;
     505                 :            : }
     506                 :            : 
     507                 :            : /* Returns the bridge ID of the bridge currently believed to be the root. */
     508                 :            : stp_identifier
     509                 :         52 : stp_get_designated_root(const struct stp *stp)
     510                 :            : {
     511                 :            :     stp_identifier designated_root;
     512                 :            : 
     513                 :         52 :     ovs_mutex_lock(&mutex);
     514                 :         52 :     designated_root = stp->designated_root;
     515                 :         52 :     ovs_mutex_unlock(&mutex);
     516                 :         52 :     return designated_root;
     517                 :            : }
     518                 :            : 
     519                 :            : /* Returns true if 'stp' believes itself to the be root of the spanning tree,
     520                 :            :  * false otherwise. */
     521                 :            : bool
     522                 :      36660 : stp_is_root_bridge(const struct stp *stp)
     523                 :            : {
     524                 :            :     bool is_root;
     525                 :            : 
     526                 :      36660 :     ovs_mutex_lock(&mutex);
     527                 :      36660 :     is_root = stp->bridge_id == stp->designated_root;
     528                 :      36660 :     ovs_mutex_unlock(&mutex);
     529                 :      36660 :     return is_root;
     530                 :            : }
     531                 :            : 
     532                 :            : /* Returns the cost of the path from 'stp' to the root of the spanning tree. */
     533                 :            : int
     534                 :        116 : stp_get_root_path_cost(const struct stp *stp)
     535                 :            : {
     536                 :            :     int cost;
     537                 :            : 
     538                 :        116 :     ovs_mutex_lock(&mutex);
     539                 :        116 :     cost = stp->root_path_cost;
     540                 :        116 :     ovs_mutex_unlock(&mutex);
     541                 :        116 :     return cost;
     542                 :            : }
     543                 :            : 
     544                 :            : /* Returns the bridge hello time, in ms.  The returned value is not necessarily
     545                 :            :  * the value passed to stp_set_hello_time(): it is clamped to the valid range
     546                 :            :  * and quantized to the STP timer resolution.  */
     547                 :            : int
     548                 :          0 : stp_get_hello_time(const struct stp *stp)
     549                 :            : {
     550                 :            :     int time;
     551                 :            : 
     552                 :          0 :     ovs_mutex_lock(&mutex);
     553                 :          0 :     time = timer_to_ms(stp->bridge_hello_time);
     554                 :          0 :     ovs_mutex_unlock(&mutex);
     555                 :          0 :     return time;
     556                 :            : }
     557                 :            : 
     558                 :            : /* Returns the bridge max age, in ms.  The returned value is not necessarily
     559                 :            :  * the value passed to stp_set_max_age(): it is clamped to the valid range,
     560                 :            :  * quantized to the STP timer resolution, and adjusted to match the constraints
     561                 :            :  * due to the hello time.  */
     562                 :            : int
     563                 :          0 : stp_get_max_age(const struct stp *stp)
     564                 :            : {
     565                 :            :     int time;
     566                 :            : 
     567                 :          0 :     ovs_mutex_lock(&mutex);
     568                 :          0 :     time = timer_to_ms(stp->bridge_max_age);
     569                 :          0 :     ovs_mutex_unlock(&mutex);
     570                 :          0 :     return time;
     571                 :            : }
     572                 :            : 
     573                 :            : /* Returns the bridge forward delay, in ms.  The returned value is not
     574                 :            :  * necessarily the value passed to stp_set_forward_delay(): it is clamped to
     575                 :            :  * the valid range, quantized to the STP timer resolution, and adjusted to
     576                 :            :  * match the constraints due to the forward delay.  */
     577                 :            : int
     578                 :          0 : stp_get_forward_delay(const struct stp *stp)
     579                 :            : {
     580                 :            :     int time;
     581                 :            : 
     582                 :          0 :     ovs_mutex_lock(&mutex);
     583                 :          0 :     time = timer_to_ms(stp->bridge_forward_delay);
     584                 :          0 :     ovs_mutex_unlock(&mutex);
     585                 :          0 :     return time;
     586                 :            : }
     587                 :            : 
     588                 :            : /* Returns true if something has happened to 'stp' which necessitates flushing
     589                 :            :  * the client's MAC learning table.  Calling this function resets 'stp' so that
     590                 :            :  * future calls will return false until flushing is required again. */
     591                 :            : bool
     592                 :        244 : stp_check_and_reset_fdb_flush(struct stp *stp)
     593                 :            : {
     594                 :            :     bool needs_flush;
     595                 :            : 
     596                 :        244 :     ovs_mutex_lock(&mutex);
     597                 :        244 :     needs_flush = stp->fdb_needs_flush;
     598                 :        244 :     stp->fdb_needs_flush = false;
     599                 :        244 :     ovs_mutex_unlock(&mutex);
     600                 :        244 :     return needs_flush;
     601                 :            : }
     602                 :            : 
     603                 :            : /* Returns the port in 'stp' with index 'port_no', which must be between 0 and
     604                 :            :  * STP_MAX_PORTS. */
     605                 :            : struct stp_port *
     606                 :      39893 : stp_get_port(struct stp *stp, int port_no)
     607                 :            : {
     608                 :            :     struct stp_port *port;
     609                 :            : 
     610                 :      39893 :     ovs_mutex_lock(&mutex);
     611 [ +  - ][ -  + ]:      39893 :     ovs_assert(port_no >= 0 && port_no < ARRAY_SIZE(stp->ports));
     612                 :      39893 :     port = &stp->ports[port_no];
     613                 :      39893 :     ovs_mutex_unlock(&mutex);
     614                 :      39893 :     return port;
     615                 :            : }
     616                 :            : 
     617                 :            : /* Returns the port connecting 'stp' to the root bridge, or a null pointer if
     618                 :            :  * there is no such port. */
     619                 :            : struct stp_port *
     620                 :        165 : stp_get_root_port(struct stp *stp)
     621                 :            : {
     622                 :            :     struct stp_port *port;
     623                 :            : 
     624                 :        165 :     ovs_mutex_lock(&mutex);
     625                 :        165 :     port = stp->root_port;
     626                 :        165 :     ovs_mutex_unlock(&mutex);
     627                 :        165 :     return port;
     628                 :            : }
     629                 :            : 
     630                 :            : /* Finds a port whose state has changed.  If successful, stores the port whose
     631                 :            :  * state changed in '*portp' and returns true.  If no port has changed, stores
     632                 :            :  * NULL in '*portp' and returns false. */
     633                 :            : bool
     634                 :        250 : stp_get_changed_port(struct stp *stp, struct stp_port **portp)
     635                 :            : {
     636                 :            :     struct stp_port *end, *p;
     637                 :        250 :     bool changed = false;
     638                 :            : 
     639                 :        250 :     ovs_mutex_lock(&mutex);
     640                 :        250 :     end = &stp->ports[ARRAY_SIZE(stp->ports)];
     641         [ +  + ]:       1774 :     for (p = stp->first_changed_port; p < end; p++) {
     642         [ +  + ]:       1530 :         if (p->state_changed) {
     643                 :          6 :             p->state_changed = false;
     644                 :          6 :             stp->first_changed_port = p + 1;
     645                 :          6 :             *portp = p;
     646                 :          6 :             changed = true;
     647                 :          6 :             goto out;
     648                 :            :         }
     649                 :            :     }
     650                 :        244 :     stp->first_changed_port = end;
     651                 :        244 :     *portp = NULL;
     652                 :            : 
     653                 :            : out:
     654                 :        250 :     ovs_mutex_unlock(&mutex);
     655                 :        250 :     return changed;
     656                 :            : }
     657                 :            : 
     658                 :            : /* Returns the name for the given 'state' (for use in debugging and log
     659                 :            :  * messages). */
     660                 :            : const char *
     661                 :         50 : stp_state_name(enum stp_state state)
     662                 :            : {
     663   [ +  +  +  +  :         50 :     switch (state) {
                   -  - ]
     664                 :            :     case STP_DISABLED:
     665                 :          4 :         return "disabled";
     666                 :            :     case STP_LISTENING:
     667                 :         20 :         return "listening";
     668                 :            :     case STP_LEARNING:
     669                 :         16 :         return "learning";
     670                 :            :     case STP_FORWARDING:
     671                 :         10 :         return "forwarding";
     672                 :            :     case STP_BLOCKING:
     673                 :          0 :         return "blocking";
     674                 :            :     default:
     675                 :          0 :         OVS_NOT_REACHED();
     676                 :            :     }
     677                 :            : }
     678                 :            : 
     679                 :            : /* Returns true if 'state' is one in which packets received on a port should
     680                 :            :  * be forwarded, false otherwise.
     681                 :            :  */
     682                 :            : bool
     683                 :         26 : stp_forward_in_state(enum stp_state state)
     684                 :            : {
     685                 :         26 :     return (state & STP_FORWARDING) != 0;
     686                 :            : }
     687                 :            : 
     688                 :            : /* Returns true if 'state' is one in which MAC learning should be done on
     689                 :            :  * packets received on a port, false otherwise.
     690                 :            :  */
     691                 :            : bool
     692                 :         16 : stp_learn_in_state(enum stp_state state)
     693                 :            : {
     694                 :         16 :     return (state & (STP_LEARNING | STP_FORWARDING)) != 0;
     695                 :            : }
     696                 :            : 
     697                 :            : /* Returns true if 'state' is one in which bpdus should be forwarded on a
     698                 :            :  * port, false otherwise.
     699                 :            :  *
     700                 :            :  * Returns true if 'state' is STP_DISABLED, since in that case the port does
     701                 :            :  * not generate the bpdu and should just forward it (e.g. patch port on pif
     702                 :            :  * bridge). */
     703                 :            : bool
     704                 :         20 : stp_should_forward_bpdu(enum stp_state state)
     705                 :            : {
     706                 :         20 :     return (state &
     707                 :            :             ( STP_DISABLED | STP_LISTENING | STP_LEARNING
     708                 :            :               | STP_FORWARDING)) != 0;
     709                 :            : }
     710                 :            : 
     711                 :            : /* Returns the name for the given 'role' (for use in debugging and log
     712                 :            :  * messages). */
     713                 :            : const char *
     714                 :         34 : stp_role_name(enum stp_role role)
     715                 :            : {
     716   [ +  +  -  -  :         34 :     switch (role) {
                      - ]
     717                 :            :     case STP_ROLE_ROOT:
     718                 :         14 :         return "root";
     719                 :            :     case STP_ROLE_DESIGNATED:
     720                 :         20 :         return "designated";
     721                 :            :     case STP_ROLE_ALTERNATE:
     722                 :          0 :         return "alternate";
     723                 :            :     case STP_ROLE_DISABLED:
     724                 :          0 :         return "disabled";
     725                 :            :     default:
     726                 :          0 :         OVS_NOT_REACHED();
     727                 :            :     }
     728                 :            : }
     729                 :            : 
     730                 :            : /* Notifies the STP entity that bridge protocol data unit 'bpdu', which is
     731                 :            :  * 'bpdu_size' bytes in length, was received on port 'p'.
     732                 :            :  *
     733                 :            :  * This function may call the 'send_bpdu' function provided to stp_create(). */
     734                 :            : void
     735                 :      10595 : stp_received_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
     736                 :            : {
     737                 :      10595 :     struct stp *stp = p->stp;
     738                 :            :     const struct stp_bpdu_header *header;
     739                 :            : 
     740                 :      10595 :     ovs_mutex_lock(&mutex);
     741         [ +  + ]:      10595 :     if (p->state == STP_DISABLED) {
     742                 :         91 :         goto out;
     743                 :            :     }
     744                 :            : 
     745         [ -  + ]:      10504 :     if (bpdu_size < sizeof(struct stp_bpdu_header)) {
     746         [ #  # ]:          0 :         VLOG_WARN("%s: received runt %"PRIuSIZE"-byte BPDU", stp->name, bpdu_size);
     747                 :          0 :         p->error_count++;
     748                 :          0 :         goto out;
     749                 :            :     }
     750                 :            : 
     751                 :      10504 :     header = bpdu;
     752         [ -  + ]:      10504 :     if (header->protocol_id != htons(STP_PROTOCOL_ID)) {
     753         [ #  # ]:          0 :         VLOG_WARN("%s: received BPDU with unexpected protocol ID %"PRIu16,
     754                 :            :                   stp->name, ntohs(header->protocol_id));
     755                 :          0 :         p->error_count++;
     756                 :          0 :         goto out;
     757                 :            :     }
     758         [ -  + ]:      10504 :     if (header->protocol_version != STP_PROTOCOL_VERSION) {
     759         [ #  # ]:          0 :         VLOG_DBG("%s: received BPDU with unexpected protocol version %"PRIu8,
     760                 :            :                  stp->name, header->protocol_version);
     761                 :            :     }
     762                 :            : 
     763      [ +  +  - ]:      10504 :     switch (header->bpdu_type) {
     764                 :            :     case STP_TYPE_CONFIG:
     765         [ -  + ]:      10451 :         if (bpdu_size < sizeof(struct stp_config_bpdu)) {
     766         [ #  # ]:          0 :             VLOG_WARN("%s: received config BPDU with invalid size %"PRIuSIZE,
     767                 :            :                       stp->name, bpdu_size);
     768                 :          0 :             p->error_count++;
     769                 :          0 :             goto out;
     770                 :            :         }
     771                 :      10451 :         stp_received_config_bpdu(stp, p, bpdu);
     772                 :      10451 :         break;
     773                 :            : 
     774                 :            :     case STP_TYPE_TCN:
     775         [ -  + ]:         53 :         if (bpdu_size != sizeof(struct stp_tcn_bpdu)) {
     776         [ #  # ]:          0 :             VLOG_WARN("%s: received TCN BPDU with invalid size %"PRIuSIZE,
     777                 :            :                       stp->name, bpdu_size);
     778                 :          0 :             p->error_count++;
     779                 :          0 :             goto out;
     780                 :            :         }
     781                 :         53 :         stp_received_tcn_bpdu(stp, p);
     782                 :         53 :         break;
     783                 :            : 
     784                 :            :     default:
     785         [ #  # ]:          0 :         VLOG_WARN("%s: received BPDU of unexpected type %"PRIu8,
     786                 :            :                   stp->name, header->bpdu_type);
     787                 :          0 :         p->error_count++;
     788                 :          0 :         goto out;
     789                 :            :     }
     790                 :      10504 :     p->rx_count++;
     791                 :            : 
     792                 :            : out:
     793                 :      10595 :     ovs_mutex_unlock(&mutex);
     794                 :      10595 : }
     795                 :            : 
     796                 :            : /* Returns the STP entity in which 'p' is nested. */
     797                 :            : struct stp *
     798                 :          0 : stp_port_get_stp(struct stp_port *p)
     799                 :            : {
     800                 :            :     struct stp *stp;
     801                 :            : 
     802                 :          0 :     ovs_mutex_lock(&mutex);
     803                 :          0 :     stp = p->stp;
     804                 :          0 :     ovs_mutex_unlock(&mutex);
     805                 :          0 :     return stp;
     806                 :            : }
     807                 :            : 
     808                 :            : void
     809                 :          6 : stp_port_set_name(struct stp_port *p, const char *name)
     810                 :            : {
     811                 :            :     char *old;
     812                 :            : 
     813                 :          6 :     ovs_mutex_lock(&mutex);
     814                 :          6 :     old = p->port_name;
     815                 :          6 :     p->port_name = xstrdup(name);
     816                 :          6 :     free(old);
     817                 :          6 :     ovs_mutex_unlock(&mutex);
     818                 :          6 : }
     819                 :            : 
     820                 :            : /* Sets the 'aux' member of 'p'.
     821                 :            :  *
     822                 :            :  * The 'aux' member will be reset to NULL when stp_port_disable() is
     823                 :            :  * called or stp_port_enable() is called when the port is in a Disabled
     824                 :            :  * state. */
     825                 :            : void
     826                 :          6 : stp_port_set_aux(struct stp_port *p, void *aux)
     827                 :            : {
     828                 :          6 :     ovs_mutex_lock(&mutex);
     829                 :          6 :     p->aux = aux;
     830                 :          6 :     ovs_mutex_unlock(&mutex);
     831                 :          6 : }
     832                 :            : 
     833                 :            : /* Returns the 'aux' member of 'p'. */
     834                 :            : void *
     835                 :         19 : stp_port_get_aux(struct stp_port *p)
     836                 :            : {
     837                 :            :     void *aux;
     838                 :            : 
     839                 :         19 :     ovs_mutex_lock(&mutex);
     840                 :         19 :     aux = p->aux;
     841                 :         19 :     ovs_mutex_unlock(&mutex);
     842                 :         19 :     return aux;
     843                 :            : }
     844                 :            : 
     845                 :            : /* Returns the index of port 'p' within its bridge. */
     846                 :            : int
     847                 :      27001 : stp_port_no(const struct stp_port *p)
     848                 :            : {
     849                 :            :     struct stp *stp;
     850                 :            :     int index;
     851                 :            : 
     852                 :      27001 :     ovs_mutex_lock(&mutex);
     853                 :      27001 :     stp = p->stp;
     854 [ +  - ][ -  + ]:      27001 :     ovs_assert(p >= stp->ports && p < &stp->ports[ARRAY_SIZE(stp->ports)]);
     855                 :      27001 :     index = p - p->stp->ports;
     856                 :      27001 :     ovs_mutex_unlock(&mutex);
     857                 :      27001 :     return index;
     858                 :            : }
     859                 :            : 
     860                 :            : /* Returns the port ID for 'p'. */
     861                 :            : int
     862                 :         34 : stp_port_get_id(const struct stp_port *p)
     863                 :            : {
     864                 :            :     int port_id;
     865                 :            : 
     866                 :         34 :     ovs_mutex_lock(&mutex);
     867                 :         34 :     port_id = p->port_id;
     868                 :         34 :     ovs_mutex_unlock(&mutex);
     869                 :         34 :     return port_id;
     870                 :            : }
     871                 :            : 
     872                 :            : /* Returns the state of port 'p'. */
     873                 :            : enum stp_state
     874                 :      16197 : stp_port_get_state(const struct stp_port *p)
     875                 :            : {
     876                 :            :     enum stp_state state;
     877                 :            : 
     878                 :      16197 :     ovs_mutex_lock(&mutex);
     879                 :      16197 :     state = p->state;
     880                 :      16197 :     ovs_mutex_unlock(&mutex);
     881                 :      16197 :     return state;
     882                 :            : }
     883                 :            : 
     884                 :            : /* Returns the role of port 'p'. */
     885                 :            : enum stp_role
     886                 :         34 : stp_port_get_role(const struct stp_port *p)
     887                 :            : {
     888                 :            :     struct stp_port *root_port;
     889                 :            :     enum stp_role role;
     890                 :            : 
     891                 :         34 :     ovs_mutex_lock(&mutex);
     892                 :         34 :     root_port = p->stp->root_port;
     893 [ +  + ][ +  - ]:         34 :     if (root_port && root_port->port_id == p->port_id) {
     894                 :         14 :         role = STP_ROLE_ROOT;
     895         [ +  - ]:         20 :     } else if (stp_is_designated_port(p)) {
     896                 :         20 :         role = STP_ROLE_DESIGNATED;
     897         [ #  # ]:          0 :     } else if (p->state == STP_DISABLED) {
     898                 :          0 :         role = STP_ROLE_DISABLED;
     899                 :            :     } else {
     900                 :          0 :         role = STP_ROLE_ALTERNATE;
     901                 :            :     }
     902                 :         34 :     ovs_mutex_unlock(&mutex);
     903                 :         34 :     return role;
     904                 :            : }
     905                 :            : 
     906                 :            : /* Retrieves BPDU transmit and receive counts for 'p'. */
     907                 :            : void
     908                 :         10 : stp_port_get_counts(const struct stp_port *p,
     909                 :            :                     int *tx_count, int *rx_count, int *error_count)
     910                 :            : {
     911                 :         10 :     ovs_mutex_lock(&mutex);
     912                 :         10 :     *tx_count = p->tx_count;
     913                 :         10 :     *rx_count = p->rx_count;
     914                 :         10 :     *error_count = p->error_count;
     915                 :         10 :     ovs_mutex_unlock(&mutex);
     916                 :         10 : }
     917                 :            : 
     918                 :            : /* Disables STP on port 'p'. */
     919                 :            : void
     920                 :      12848 : stp_port_disable(struct stp_port *p)
     921                 :            : {
     922                 :            :     struct stp *stp;
     923                 :            : 
     924                 :      12848 :     ovs_mutex_lock(&mutex);
     925                 :      12848 :     stp = p->stp;
     926         [ +  + ]:      12848 :     if (p->state != STP_DISABLED) {
     927                 :          5 :         bool root = stp_is_root_bridge(stp);
     928                 :          5 :         stp_become_designated_port(p);
     929                 :          5 :         stp_set_port_state(p, STP_DISABLED);
     930                 :          5 :         p->topology_change_ack = false;
     931                 :          5 :         p->config_pending = false;
     932                 :          5 :         stp_stop_timer(&p->message_age_timer);
     933                 :          5 :         stp_stop_timer(&p->forward_delay_timer);
     934                 :          5 :         stp_configuration_update(stp);
     935                 :          5 :         stp_port_state_selection(stp);
     936 [ +  + ][ +  + ]:          5 :         if (stp_is_root_bridge(stp) && !root) {
     937                 :          1 :             stp_become_root_bridge(stp);
     938                 :            :         }
     939                 :          5 :         p->aux = NULL;
     940                 :            :     }
     941                 :      12848 :     ovs_mutex_unlock(&mutex);
     942                 :      12848 : }
     943                 :            : 
     944                 :            : /* Enables STP on port 'p'.  The port will initially be in "blocking" state. */
     945                 :            : void
     946                 :        156 : stp_port_enable(struct stp_port *p)
     947                 :            : {
     948                 :        156 :     ovs_mutex_lock(&mutex);
     949         [ +  + ]:        156 :     if (p->state == STP_DISABLED) {
     950                 :        138 :         stp_initialize_port(p, STP_BLOCKING);
     951                 :        138 :         stp_port_state_selection(p->stp);
     952                 :            :     }
     953                 :        156 :     ovs_mutex_unlock(&mutex);
     954                 :        156 : }
     955                 :            : 
     956                 :            : /* Sets the priority of port 'p' to 'new_priority'.  Lower numerical values
     957                 :            :  * are interpreted as higher priorities. */
     958                 :            : void
     959                 :          7 : stp_port_set_priority(struct stp_port *p, uint8_t new_priority)
     960                 :            : {
     961                 :            :     uint16_t new_port_id;
     962                 :            : 
     963                 :          7 :     ovs_mutex_lock(&mutex);
     964                 :          7 :     new_port_id  = (p->port_id & 0xff) | (new_priority << 8);
     965         [ +  + ]:          7 :     if (p->port_id != new_port_id) {
     966                 :          1 :         struct stp *stp = p->stp;
     967         [ -  + ]:          1 :         if (stp_is_designated_port(p)) {
     968                 :          0 :             p->designated_port = new_port_id;
     969                 :            :         }
     970                 :          1 :         p->port_id = new_port_id;
     971         [ -  + ]:          1 :         if (stp->bridge_id == p->designated_bridge
     972         [ #  # ]:          0 :             && p->port_id < p->designated_port) {
     973                 :          0 :             stp_become_designated_port(p);
     974                 :          0 :             stp_port_state_selection(stp);
     975                 :            :         }
     976                 :            :     }
     977                 :          7 :     ovs_mutex_unlock(&mutex);
     978                 :          7 : }
     979                 :            : 
     980                 :            : /* Convert 'speed' (measured in Mb/s) into the path cost. */
     981                 :            : uint16_t
     982                 :          6 : stp_convert_speed_to_cost(unsigned int speed)
     983                 :            : {
     984                 :            :     uint16_t ret;
     985                 :            : 
     986                 :          6 :     ovs_mutex_lock(&mutex);
     987 [ +  - ][ +  - ]:          6 :     ret = speed >= 10000 ? 2  /* 10 Gb/s. */
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
     988                 :            :         : speed >= 1000 ? 4 /* 1 Gb/s. */
     989                 :            :         : speed >= 100 ? 19 /* 100 Mb/s. */
     990                 :            :         : speed >= 16 ? 62  /* 16 Mb/s. */
     991                 :            :         : speed >= 10 ? 100 /* 10 Mb/s. */
     992                 :            :         : speed >= 4 ? 250  /* 4 Mb/s. */
     993                 :            :         : 19;             /* 100 Mb/s (guess). */
     994                 :          6 :     ovs_mutex_unlock(&mutex);
     995                 :          6 :     return ret;
     996                 :            : }
     997                 :            : 
     998                 :            : /* Sets the path cost of port 'p' to 'path_cost'.  Lower values are generally
     999                 :            :  * used to indicate faster links.  Use stp_port_set_speed() to automatically
    1000                 :            :  * generate a default path cost from a link speed. */
    1001                 :            : void
    1002                 :        156 : stp_port_set_path_cost(struct stp_port *p, uint16_t path_cost)
    1003                 :            : {
    1004                 :        156 :     ovs_mutex_lock(&mutex);
    1005         [ +  + ]:        156 :     if (p->path_cost != path_cost) {
    1006                 :        136 :         struct stp *stp = p->stp;
    1007                 :        136 :         p->path_cost = path_cost;
    1008                 :        136 :         stp_configuration_update(stp);
    1009                 :        136 :         stp_port_state_selection(stp);
    1010                 :            :     }
    1011                 :        156 :     ovs_mutex_unlock(&mutex);
    1012                 :        156 : }
    1013                 :            : 
    1014                 :            : /* Sets the path cost of port 'p' based on 'speed' (measured in Mb/s). */
    1015                 :            : void
    1016                 :          0 : stp_port_set_speed(struct stp_port *p, unsigned int speed)
    1017                 :            : {
    1018                 :          0 :     stp_port_set_path_cost(p, stp_convert_speed_to_cost(speed));
    1019                 :          0 : }
    1020                 :            : 
    1021                 :            : /* Enables topology change detection on port 'p'. */
    1022                 :            : void
    1023                 :          0 : stp_port_enable_change_detection(struct stp_port *p)
    1024                 :            : {
    1025                 :          0 :     p->change_detection_enabled = true;
    1026                 :          0 : }
    1027                 :            : 
    1028                 :            : /* Disables topology change detection on port 'p'. */
    1029                 :            : void
    1030                 :          0 : stp_port_disable_change_detection(struct stp_port *p)
    1031                 :            : {
    1032                 :          0 :     p->change_detection_enabled = false;
    1033                 :          0 : }
    1034                 :            : 
    1035                 :            : static void
    1036                 :      15562 : stp_transmit_config(struct stp_port *p) OVS_REQUIRES(mutex)
    1037                 :            : {
    1038                 :      15562 :     struct stp *stp = p->stp;
    1039                 :      15562 :     bool root = stp_is_root_bridge(stp);
    1040 [ +  + ][ -  + ]:      15562 :     if (!root && !stp->root_port) {
    1041                 :          0 :         return;
    1042                 :            :     }
    1043         [ +  + ]:      15562 :     if (p->hold_timer.active) {
    1044         [ -  + ]:        362 :         VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, transmit config bpdu pending",
    1045                 :            :                     stp->name, p->port_name);
    1046                 :        362 :         p->config_pending = true;
    1047                 :            :     } else {
    1048                 :            :         struct stp_config_bpdu config;
    1049                 :      15200 :         memset(&config, 0, sizeof config);
    1050                 :      15200 :         config.header.protocol_id = htons(STP_PROTOCOL_ID);
    1051                 :      15200 :         config.header.protocol_version = STP_PROTOCOL_VERSION;
    1052                 :      15200 :         config.header.bpdu_type = STP_TYPE_CONFIG;
    1053                 :      15200 :         config.flags = 0;
    1054         [ +  + ]:      15200 :         if (p->topology_change_ack) {
    1055                 :         49 :             config.flags |= STP_CONFIG_TOPOLOGY_CHANGE_ACK;
    1056                 :            :         }
    1057         [ +  + ]:      15200 :         if (stp->topology_change) {
    1058                 :       3404 :             config.flags |= STP_CONFIG_TOPOLOGY_CHANGE;
    1059                 :            :         }
    1060                 :      15200 :         config.root_id = htonll(stp->designated_root);
    1061                 :      15200 :         config.root_path_cost = htonl(stp->root_path_cost);
    1062                 :      15200 :         config.bridge_id = htonll(stp->bridge_id);
    1063                 :      15200 :         config.port_id = htons(p->port_id);
    1064         [ +  + ]:      15200 :         if (root) {
    1065                 :       5974 :             config.message_age = htons(0);
    1066                 :            :         } else {
    1067                 :       9226 :             config.message_age = htons(stp->root_port->message_age_timer.value
    1068                 :            :                                        + MESSAGE_AGE_INCREMENT);
    1069                 :            :         }
    1070                 :      15200 :         config.max_age = htons(stp->max_age);
    1071                 :      15200 :         config.hello_time = htons(stp->hello_time);
    1072                 :      15200 :         config.forward_delay = htons(stp->forward_delay);
    1073         [ +  - ]:      15200 :         if (ntohs(config.message_age) < stp->max_age) {
    1074                 :      15200 :             p->topology_change_ack = false;
    1075                 :      15200 :             p->config_pending = false;
    1076         [ -  + ]:      15200 :             VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, transmit config bpdu",
    1077                 :            :                         stp->name, p->port_name);
    1078                 :      15200 :             stp_send_bpdu(p, &config, sizeof config);
    1079                 :      15200 :             stp_start_timer(&p->hold_timer, 0);
    1080                 :            :         }
    1081                 :            :     }
    1082                 :            : }
    1083                 :            : 
    1084                 :            : static bool
    1085                 :      10451 : stp_supersedes_port_info(const struct stp_port *p,
    1086                 :            :                          const struct stp_config_bpdu *config)
    1087                 :            :      OVS_REQUIRES(mutex)
    1088                 :            : {
    1089         [ +  + ]:      10451 :     if (ntohll(config->root_id) != p->designated_root) {
    1090                 :        156 :         return ntohll(config->root_id) < p->designated_root;
    1091         [ +  + ]:      10295 :     } else if (ntohl(config->root_path_cost) != p->designated_cost) {
    1092                 :         65 :         return ntohl(config->root_path_cost) < p->designated_cost;
    1093         [ +  + ]:      10230 :     } else if (ntohll(config->bridge_id) != p->designated_bridge) {
    1094                 :         13 :         return ntohll(config->bridge_id) < p->designated_bridge;
    1095                 :            :     } else {
    1096                 :      20434 :         return (ntohll(config->bridge_id) != p->stp->bridge_id
    1097 [ +  + ][ +  + ]:      10217 :                 || ntohs(config->port_id) <= p->designated_port);
    1098                 :            :     }
    1099                 :            : }
    1100                 :            : 
    1101                 :            : static void
    1102                 :      10316 : stp_record_config_information(struct stp_port *p,
    1103                 :            :                               const struct stp_config_bpdu *config)
    1104                 :            :      OVS_REQUIRES(mutex)
    1105                 :            : {
    1106                 :      10316 :     p->designated_root = ntohll(config->root_id);
    1107                 :      10316 :     p->designated_cost = ntohl(config->root_path_cost);
    1108                 :      10316 :     p->designated_bridge = ntohll(config->bridge_id);
    1109                 :      10316 :     p->designated_port = ntohs(config->port_id);
    1110                 :      10316 :     stp_start_timer(&p->message_age_timer, ntohs(config->message_age));
    1111                 :      10316 : }
    1112                 :            : 
    1113                 :            : static void
    1114                 :       5244 : stp_record_config_timeout_values(struct stp *stp,
    1115                 :            :                                  const struct stp_config_bpdu  *config)
    1116                 :            :      OVS_REQUIRES(mutex)
    1117                 :            : {
    1118                 :       5244 :     stp->max_age = ntohs(config->max_age);
    1119                 :       5244 :     stp->hello_time = ntohs(config->hello_time);
    1120                 :       5244 :     stp->forward_delay = ntohs(config->forward_delay);
    1121                 :       5244 :     stp->topology_change = config->flags & STP_CONFIG_TOPOLOGY_CHANGE;
    1122                 :       5244 : }
    1123                 :            : 
    1124                 :            : static bool
    1125                 :     132807 : stp_is_designated_port(const struct stp_port *p) OVS_REQUIRES(mutex)
    1126                 :            : {
    1127                 :     132807 :     return (p->designated_bridge == p->stp->bridge_id
    1128 [ +  + ][ +  + ]:     132807 :             && p->designated_port == p->port_id);
    1129                 :            : }
    1130                 :            : 
    1131                 :            : static void
    1132                 :       7364 : stp_config_bpdu_generation(struct stp *stp) OVS_REQUIRES(mutex)
    1133                 :            : {
    1134                 :            :     struct stp_port *p;
    1135                 :            : 
    1136         [ +  + ]:      32753 :     FOR_EACH_ENABLED_PORT (p, stp) {
    1137         [ +  + ]:      25389 :         if (stp_is_designated_port(p)) {
    1138                 :      15147 :             stp_transmit_config(p);
    1139                 :            :         }
    1140                 :            :     }
    1141                 :       7364 : }
    1142                 :            : 
    1143                 :            : static void
    1144                 :         49 : stp_transmit_tcn(struct stp *stp) OVS_REQUIRES(mutex)
    1145                 :            : {
    1146                 :         49 :     struct stp_port *p = stp->root_port;
    1147                 :            :     struct stp_tcn_bpdu tcn_bpdu;
    1148                 :            : 
    1149         [ -  + ]:         49 :     if (!p) {
    1150                 :          0 :         return;
    1151                 :            :     }
    1152         [ -  + ]:         49 :     VLOG_DBG_RL(&stp_rl, "bridge: %s, root port: %s, transmit tcn", stp->name,
    1153                 :            :                 p->port_name);
    1154                 :         49 :     tcn_bpdu.header.protocol_id = htons(STP_PROTOCOL_ID);
    1155                 :         49 :     tcn_bpdu.header.protocol_version = STP_PROTOCOL_VERSION;
    1156                 :         49 :     tcn_bpdu.header.bpdu_type = STP_TYPE_TCN;
    1157                 :         49 :     stp_send_bpdu(p, &tcn_bpdu, sizeof tcn_bpdu);
    1158                 :            : }
    1159                 :            : 
    1160                 :            : static void
    1161                 :      10470 : stp_configuration_update(struct stp *stp) OVS_REQUIRES(mutex)
    1162                 :            : {
    1163                 :      10470 :     stp_root_selection(stp);
    1164                 :      10470 :     stp_designated_port_selection(stp);
    1165                 :      10470 :     seq_change(connectivity_seq_get());
    1166                 :      10470 : }
    1167                 :            : 
    1168                 :            : static bool
    1169                 :      13059 : stp_supersedes_root(const struct stp_port *root, const struct stp_port *p)
    1170                 :            :     OVS_REQUIRES(mutex)
    1171                 :            : {
    1172                 :      13059 :     int p_cost = p->designated_cost + p->path_cost;
    1173                 :      13059 :     int root_cost = root->designated_cost + root->path_cost;
    1174                 :            : 
    1175         [ +  + ]:      13059 :     if (p->designated_root != root->designated_root) {
    1176                 :         14 :         return p->designated_root < root->designated_root;
    1177         [ +  + ]:      13045 :     } else if (p_cost != root_cost) {
    1178                 :       2091 :         return p_cost < root_cost;
    1179         [ +  + ]:      10954 :     } else if (p->designated_bridge != root->designated_bridge) {
    1180                 :       5047 :         return p->designated_bridge < root->designated_bridge;
    1181         [ +  + ]:       5907 :     } else if (p->designated_port != root->designated_port) {
    1182                 :       5542 :         return p->designated_port < root->designated_port;
    1183                 :            :     } else {
    1184                 :        365 :         return p->port_id < root->port_id;
    1185                 :            :     }
    1186                 :            : }
    1187                 :            : 
    1188                 :            : static void
    1189                 :      10470 : stp_root_selection(struct stp *stp) OVS_REQUIRES(mutex)
    1190                 :            : {
    1191                 :            :     struct stp_port *p, *root;
    1192                 :            : 
    1193                 :      10470 :     root = NULL;
    1194         [ +  + ]:      49461 :     FOR_EACH_ENABLED_PORT (p, stp) {
    1195         [ +  + ]:      38991 :         if (stp_is_designated_port(p)
    1196         [ +  + ]:      23396 :             || p->designated_root >= stp->bridge_id) {
    1197                 :      15794 :             continue;
    1198                 :            :         }
    1199 [ +  + ][ +  + ]:      23197 :         if (root && !stp_supersedes_root(root, p)) {
    1200                 :       9919 :             continue;
    1201                 :            :         }
    1202                 :      13278 :         root = p;
    1203                 :            :     }
    1204                 :      10470 :     stp->root_port = root;
    1205         [ +  + ]:      10470 :     if (!root) {
    1206                 :        332 :         stp->designated_root = stp->bridge_id;
    1207                 :        332 :         stp->root_path_cost = 0;
    1208                 :            :     } else {
    1209                 :      10138 :         stp->designated_root = root->designated_root;
    1210                 :      10138 :         stp->root_path_cost = root->designated_cost + root->path_cost;
    1211                 :            :     }
    1212                 :      10470 : }
    1213                 :            : 
    1214                 :            : static void
    1215                 :      10470 : stp_designated_port_selection(struct stp *stp) OVS_REQUIRES(mutex)
    1216                 :            : {
    1217                 :            :     struct stp_port *p;
    1218                 :            : 
    1219         [ +  + ]:      49461 :     FOR_EACH_ENABLED_PORT (p, stp) {
    1220         [ +  + ]:      38991 :         if (stp_is_designated_port(p)
    1221         [ +  + ]:      23396 :             || p->designated_root != stp->designated_root
    1222         [ +  - ]:      23362 :             || stp->root_path_cost < p->designated_cost
    1223         [ +  + ]:      23362 :             || (stp->root_path_cost == p->designated_cost
    1224         [ +  - ]:       2090 :                 && (stp->bridge_id < p->designated_bridge
    1225         [ +  + ]:       2090 :                     || (stp->bridge_id == p->designated_bridge
    1226         [ -  + ]:        454 :                         && p->port_id <= p->designated_port))))
    1227                 :            :         {
    1228                 :      15629 :             stp_become_designated_port(p);
    1229                 :            :         }
    1230                 :            :     }
    1231                 :      10470 : }
    1232                 :            : 
    1233                 :            : static void
    1234                 :      27504 : stp_become_designated_port(struct stp_port *p) OVS_REQUIRES(mutex)
    1235                 :            : {
    1236                 :      27504 :     struct stp *stp = p->stp;
    1237                 :      27504 :     p->designated_root = stp->designated_root;
    1238                 :      27504 :     p->designated_cost = stp->root_path_cost;
    1239                 :      27504 :     p->designated_bridge = stp->bridge_id;
    1240                 :      27504 :     p->designated_port = p->port_id;
    1241                 :      27504 : }
    1242                 :            : 
    1243                 :            : static void
    1244                 :      10608 : stp_port_state_selection(struct stp *stp) OVS_REQUIRES(mutex)
    1245                 :            : {
    1246                 :            :     struct stp_port *p;
    1247                 :            : 
    1248         [ +  + ]:      49945 :     FOR_EACH_ENABLED_PORT (p, stp) {
    1249         [ +  + ]:      39337 :         if (p == stp->root_port) {
    1250                 :      10138 :             p->config_pending = false;
    1251                 :      10138 :             p->topology_change_ack = false;
    1252                 :      10138 :             stp_make_forwarding(p);
    1253         [ +  + ]:      29199 :         } else if (stp_is_designated_port(p)) {
    1254                 :      15975 :             stp_stop_timer(&p->message_age_timer);
    1255                 :      15975 :             stp_make_forwarding(p);
    1256                 :            :         } else {
    1257                 :      13224 :             p->config_pending = false;
    1258                 :      13224 :             p->topology_change_ack = false;
    1259                 :      13224 :             stp_make_blocking(p);
    1260                 :            :         }
    1261                 :            :     }
    1262                 :      10608 : }
    1263                 :            : 
    1264                 :            : static void
    1265                 :      26113 : stp_make_forwarding(struct stp_port *p) OVS_REQUIRES(mutex)
    1266                 :            : {
    1267         [ +  + ]:      26113 :     if (p->state == STP_BLOCKING) {
    1268                 :        167 :         stp_set_port_state(p, STP_LISTENING);
    1269                 :        167 :         stp_start_timer(&p->forward_delay_timer, 0);
    1270                 :            :     }
    1271                 :      26113 : }
    1272                 :            : 
    1273                 :            : static void
    1274                 :      13224 : stp_make_blocking(struct stp_port *p) OVS_REQUIRES(mutex)
    1275                 :            : {
    1276         [ +  + ]:      13224 :     if (!(p->state & (STP_DISABLED | STP_BLOCKING))) {
    1277         [ +  + ]:         50 :         if (p->state & (STP_FORWARDING | STP_LEARNING)) {
    1278         [ +  - ]:         18 :             if (p->change_detection_enabled) {
    1279                 :         18 :                 stp_topology_change_detection(p->stp);
    1280                 :            :             }
    1281                 :            :         }
    1282                 :         50 :         stp_set_port_state(p, STP_BLOCKING);
    1283                 :         50 :         stp_stop_timer(&p->forward_delay_timer);
    1284                 :            :     }
    1285                 :      13224 : }
    1286                 :            : 
    1287                 :            : static void
    1288                 :        630 : stp_set_port_state(struct stp_port *p, enum stp_state state)
    1289                 :            :     OVS_REQUIRES(mutex)
    1290                 :            : {
    1291 [ +  - ][ +  + ]:        630 :     if (state != p->state && !p->state_changed) {
    1292                 :        144 :         p->state_changed = true;
    1293         [ +  + ]:        144 :         if (p < p->stp->first_changed_port) {
    1294                 :         51 :             p->stp->first_changed_port = p;
    1295                 :            :         }
    1296                 :        144 :         seq_change(connectivity_seq_get());
    1297                 :            :     }
    1298                 :        630 :     p->state = state;
    1299                 :        630 : }
    1300                 :            : 
    1301                 :            : static void
    1302                 :        198 : stp_topology_change_detection(struct stp *stp) OVS_REQUIRES(mutex)
    1303                 :            : {
    1304                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
    1305                 :            : 
    1306         [ +  + ]:        198 :     if (stp_is_root_bridge(stp)) {
    1307                 :         80 :         stp->topology_change = true;
    1308                 :         80 :         stp_start_timer(&stp->topology_change_timer, 0);
    1309         [ +  + ]:        118 :     } else if (!stp->topology_change_detected) {
    1310                 :         46 :         stp_transmit_tcn(stp);
    1311                 :         46 :         stp_start_timer(&stp->tcn_timer, 0);
    1312                 :            :     }
    1313                 :        198 :     stp->fdb_needs_flush = true;
    1314                 :        198 :     stp->topology_change_detected = true;
    1315                 :        198 :     seq_change(connectivity_seq_get());
    1316         [ +  - ]:        198 :     VLOG_INFO_RL(&rl, "%s: detected topology change.", stp->name);
    1317                 :        198 : }
    1318                 :            : 
    1319                 :            : static void
    1320                 :         50 : stp_topology_change_acknowledged(struct stp *stp) OVS_REQUIRES(mutex)
    1321                 :            : {
    1322                 :         50 :     stp->topology_change_detected = false;
    1323                 :         50 :     stp_stop_timer(&stp->tcn_timer);
    1324                 :         50 : }
    1325                 :            : 
    1326                 :            : static void
    1327                 :         49 : stp_acknowledge_topology_change(struct stp_port *p) OVS_REQUIRES(mutex)
    1328                 :            : {
    1329                 :         49 :     p->topology_change_ack = true;
    1330                 :         49 :     stp_transmit_config(p);
    1331                 :         49 : }
    1332                 :            : 
    1333                 :            : static void
    1334                 :      10451 : stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
    1335                 :            :                          const struct stp_config_bpdu *config)
    1336                 :            :     OVS_REQUIRES(mutex)
    1337                 :            : {
    1338         [ -  + ]:      10451 :     if (ntohs(config->message_age) >= ntohs(config->max_age)) {
    1339         [ #  # ]:          0 :         VLOG_WARN("%s: received config BPDU with message age (%u) greater "
    1340                 :            :                   "than max age (%u)",
    1341                 :            :                   stp->name,
    1342                 :            :                   ntohs(config->message_age), ntohs(config->max_age));
    1343                 :          0 :         return;
    1344                 :            :     }
    1345         [ +  - ]:      10451 :     if (p->state != STP_DISABLED) {
    1346                 :      10451 :         bool root = stp_is_root_bridge(stp);
    1347         [ +  + ]:      10451 :         if (stp_supersedes_port_info(p, config)) {
    1348                 :      10316 :             stp_record_config_information(p, config);
    1349                 :      10316 :             stp_configuration_update(stp);
    1350                 :      10316 :             stp_port_state_selection(stp);
    1351 [ +  + ][ +  + ]:      10316 :             if (!stp_is_root_bridge(stp) && root) {
    1352                 :         38 :                 stp_stop_timer(&stp->hello_timer);
    1353         [ +  + ]:         38 :                 if (stp->topology_change_detected) {
    1354                 :          2 :                     stp_stop_timer(&stp->topology_change_timer);
    1355                 :          2 :                     stp_transmit_tcn(stp);
    1356                 :          2 :                     stp_start_timer(&stp->tcn_timer, 0);
    1357                 :            :                 }
    1358                 :            :             }
    1359         [ +  + ]:      10316 :             if (p == stp->root_port) {
    1360                 :       5244 :                 stp_record_config_timeout_values(stp, config);
    1361                 :       5244 :                 stp_config_bpdu_generation(stp);
    1362         [ +  + ]:       5244 :                 if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE_ACK) {
    1363                 :         50 :                     stp_topology_change_acknowledged(stp);
    1364                 :            :                 }
    1365         [ +  + ]:       5244 :                 if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE) {
    1366                 :      10316 :                     stp->fdb_needs_flush = true;
    1367                 :            :                 }
    1368                 :            :             }
    1369         [ +  + ]:        135 :         } else if (stp_is_designated_port(p)) {
    1370                 :        124 :             stp_transmit_config(p);
    1371                 :            :         }
    1372                 :            :     }
    1373                 :            : }
    1374                 :            : 
    1375                 :            : static void
    1376                 :         53 : stp_received_tcn_bpdu(struct stp *stp, struct stp_port *p)
    1377                 :            :     OVS_REQUIRES(mutex)
    1378                 :            : {
    1379         [ +  - ]:         53 :     if (p->state != STP_DISABLED) {
    1380         [ +  + ]:         53 :         if (stp_is_designated_port(p)) {
    1381                 :         49 :             stp_topology_change_detection(stp);
    1382                 :         49 :             stp_acknowledge_topology_change(p);
    1383                 :            :         }
    1384                 :            :     }
    1385                 :         53 : }
    1386                 :            : 
    1387                 :            : static void
    1388                 :       2113 : stp_hello_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
    1389                 :            : {
    1390                 :       2113 :     stp_config_bpdu_generation(stp);
    1391                 :       2113 :     stp_start_timer(&stp->hello_timer, 0);
    1392                 :       2113 : }
    1393                 :            : 
    1394                 :            : static void
    1395                 :          2 : stp_message_age_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
    1396                 :            : {
    1397                 :          2 :     struct stp *stp = p->stp;
    1398                 :          2 :     bool root = stp_is_root_bridge(stp);
    1399                 :            : 
    1400         [ -  + ]:          2 :     VLOG_DBG_RL(&stp_rl, "bridge: %s, port: %s, message age timer expired",
    1401                 :            :                 stp->name, p->port_name);
    1402                 :          2 :     stp_become_designated_port(p);
    1403                 :          2 :     stp_configuration_update(stp);
    1404                 :          2 :     stp_port_state_selection(stp);
    1405 [ -  + ][ #  # ]:          2 :     if (stp_is_root_bridge(stp) && !root) {
    1406                 :          0 :         stp->max_age = stp->bridge_max_age;
    1407                 :          0 :         stp->hello_time = stp->bridge_hello_time;
    1408                 :          0 :         stp->forward_delay = stp->bridge_forward_delay;
    1409                 :          0 :         stp_topology_change_detection(stp);
    1410                 :          0 :         stp_stop_timer(&stp->tcn_timer);
    1411                 :          0 :         stp_config_bpdu_generation(stp);
    1412                 :          0 :         stp_start_timer(&stp->hello_timer, 0);
    1413                 :            :     }
    1414                 :          2 : }
    1415                 :            : 
    1416                 :            : static bool
    1417                 :        135 : stp_is_designated_for_some_port(const struct stp *stp) OVS_REQUIRES(mutex)
    1418                 :            : {
    1419                 :            :     const struct stp_port *p;
    1420                 :            : 
    1421         [ +  + ]:        269 :     FOR_EACH_ENABLED_PORT (p, stp) {
    1422         [ +  + ]:        258 :         if (p->designated_bridge == stp->bridge_id) {
    1423                 :        124 :             return true;
    1424                 :            :         }
    1425                 :            :     }
    1426                 :         11 :     return false;
    1427                 :            : }
    1428                 :            : 
    1429                 :            : static void
    1430                 :        270 : stp_forward_delay_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
    1431                 :            : {
    1432         [ +  + ]:        270 :     if (p->state == STP_LISTENING) {
    1433                 :        135 :         stp_set_port_state(p, STP_LEARNING);
    1434                 :        135 :         stp_start_timer(&p->forward_delay_timer, 0);
    1435         [ +  - ]:        135 :     } else if (p->state == STP_LEARNING) {
    1436                 :        135 :         stp_set_port_state(p, STP_FORWARDING);
    1437         [ +  + ]:        135 :         if (stp_is_designated_for_some_port(p->stp)) {
    1438         [ +  - ]:        124 :             if (p->change_detection_enabled) {
    1439                 :        124 :                 stp_topology_change_detection(p->stp);
    1440                 :            :             }
    1441                 :            :         }
    1442                 :            :     }
    1443                 :        270 : }
    1444                 :            : 
    1445                 :            : static void
    1446                 :          1 : stp_tcn_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
    1447                 :            : {
    1448                 :          1 :     stp_transmit_tcn(stp);
    1449                 :          1 :     stp_start_timer(&stp->tcn_timer, 0);
    1450                 :          1 : }
    1451                 :            : 
    1452                 :            : static void
    1453                 :         21 : stp_topology_change_timer_expiry(struct stp *stp) OVS_REQUIRES(mutex)
    1454                 :            : {
    1455                 :         21 :     stp->topology_change_detected = false;
    1456                 :         21 :     stp->topology_change = false;
    1457                 :         21 : }
    1458                 :            : 
    1459                 :            : static void
    1460                 :      15146 : stp_hold_timer_expiry(struct stp_port *p) OVS_REQUIRES(mutex)
    1461                 :            : {
    1462         [ +  + ]:      15146 :     if (p->config_pending) {
    1463                 :        242 :         stp_transmit_config(p);
    1464                 :            :     }
    1465                 :      15146 : }
    1466                 :            : 
    1467                 :            : static void
    1468                 :      11868 : stp_initialize_port(struct stp_port *p, enum stp_state state)
    1469                 :            :     OVS_REQUIRES(mutex)
    1470                 :            : {
    1471         [ -  + ]:      11868 :     ovs_assert(state & (STP_DISABLED | STP_BLOCKING));
    1472                 :      11868 :     stp_become_designated_port(p);
    1473                 :            : 
    1474 [ +  + ][ +  - ]:      11868 :     if (!p->state && state == STP_DISABLED) {
    1475                 :      11730 :         p->state = state; /* Do not trigger state change when initializing. */
    1476                 :            :     } else {
    1477                 :        138 :         stp_set_port_state(p, state);
    1478                 :            :     }
    1479                 :      11868 :     p->topology_change_ack = false;
    1480                 :      11868 :     p->config_pending = false;
    1481                 :      11868 :     p->change_detection_enabled = true;
    1482                 :      11868 :     p->aux = NULL;
    1483                 :      11868 :     stp_stop_timer(&p->message_age_timer);
    1484                 :      11868 :     stp_stop_timer(&p->forward_delay_timer);
    1485                 :      11868 :     stp_stop_timer(&p->hold_timer);
    1486                 :      11868 :     p->tx_count = p->rx_count = p->error_count = 0;
    1487                 :      11868 : }
    1488                 :            : 
    1489                 :            : static void
    1490                 :          7 : stp_become_root_bridge(struct stp *stp) OVS_REQUIRES(mutex)
    1491                 :            : {
    1492                 :          7 :     stp->max_age = stp->bridge_max_age;
    1493                 :          7 :     stp->hello_time = stp->bridge_hello_time;
    1494                 :          7 :     stp->forward_delay = stp->bridge_forward_delay;
    1495                 :          7 :     stp_topology_change_detection(stp);
    1496                 :          7 :     stp_stop_timer(&stp->tcn_timer);
    1497                 :          7 :     stp_config_bpdu_generation(stp);
    1498                 :          7 :     stp_start_timer(&stp->hello_timer, 0);
    1499                 :          7 : }
    1500                 :            : 
    1501                 :            : static void
    1502                 :      28113 : stp_start_timer(struct stp_timer *timer, int value) OVS_REQUIRES(mutex)
    1503                 :            : {
    1504                 :      28113 :     timer->value = value;
    1505                 :      28113 :     timer->active = true;
    1506                 :      28113 : }
    1507                 :            : 
    1508                 :            : static void
    1509                 :      51828 : stp_stop_timer(struct stp_timer *timer) OVS_REQUIRES(mutex)
    1510                 :            : {
    1511                 :      51828 :     timer->active = false;
    1512                 :      51828 : }
    1513                 :            : 
    1514                 :            : static bool
    1515                 :     192489 : stp_timer_expired(struct stp_timer *timer, int elapsed, int timeout)
    1516                 :            :     OVS_REQUIRES(mutex)
    1517                 :            : {
    1518         [ +  + ]:     192489 :     if (timer->active) {
    1519                 :      44427 :         timer->value += elapsed;
    1520         [ +  + ]:      44427 :         if (timer->value >= timeout) {
    1521                 :      17553 :             timer->active = false;
    1522                 :      17553 :             return true;
    1523                 :            :         }
    1524                 :            :     }
    1525                 :     174936 :     return false;
    1526                 :            : }
    1527                 :            : 
    1528                 :            : /* Returns the number of whole STP timer ticks in 'ms' milliseconds.  There
    1529                 :            :  * are 256 STP timer ticks per second. */
    1530                 :            : static int
    1531                 :      64406 : ms_to_timer(int ms)
    1532                 :            : {
    1533                 :      64406 :     return ms * 0x100 / 1000;
    1534                 :            : }
    1535                 :            : 
    1536                 :            : /* Returns the number of whole milliseconds in 'timer' STP timer ticks.  There
    1537                 :            :  * are 256 STP timer ticks per second. */
    1538                 :            : static int
    1539                 :      14462 : timer_to_ms(int timer)
    1540                 :            : {
    1541                 :      14462 :     return timer * 1000 / 0x100;
    1542                 :            : }
    1543                 :            : 
    1544                 :            : static int
    1545                 :      14690 : clamp(int x, int min, int max)
    1546                 :            : {
    1547         [ +  + ]:      14690 :     return x < min ? min : x > max ? max : x;
    1548                 :            : }
    1549                 :            : 
    1550                 :            : static void
    1551                 :         76 : stp_update_bridge_timers(struct stp *stp) OVS_REQUIRES(mutex)
    1552                 :            : {
    1553                 :            :     int ht, ma, fd;
    1554                 :            : 
    1555                 :         76 :     ht = clamp(stp->rq_hello_time, 1000, 10000);
    1556                 :         76 :     ma = clamp(stp->rq_max_age, MAX(2 * (ht + 1000), 6000), 40000);
    1557                 :         76 :     fd = clamp(stp->rq_forward_delay, ma / 2 + 1000, 30000);
    1558                 :            : 
    1559                 :         76 :     stp->bridge_hello_time = ms_to_timer(ht);
    1560                 :         76 :     stp->bridge_max_age = ms_to_timer(ma);
    1561                 :         76 :     stp->bridge_forward_delay = ms_to_timer(fd);
    1562                 :            : 
    1563         [ +  + ]:         76 :     if (stp_is_root_bridge(stp)) {
    1564                 :         30 :         stp->max_age = stp->bridge_max_age;
    1565                 :         30 :         stp->hello_time = stp->bridge_hello_time;
    1566                 :         30 :         stp->forward_delay = stp->bridge_forward_delay;
    1567                 :            :     }
    1568                 :         76 : }
    1569                 :            : 
    1570                 :            : static void
    1571                 :      15249 : stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
    1572                 :            :     OVS_REQUIRES(mutex)
    1573                 :            : {
    1574                 :            :     struct eth_header *eth;
    1575                 :            :     struct llc_header *llc;
    1576                 :            :     struct dp_packet *pkt;
    1577                 :            : 
    1578                 :            :     /* Skeleton. */
    1579                 :      15249 :     pkt = dp_packet_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
    1580                 :      15249 :     eth = dp_packet_put_zeros(pkt, sizeof *eth);
    1581                 :      15249 :     llc = dp_packet_put_zeros(pkt, sizeof *llc);
    1582                 :      15249 :     dp_packet_reset_offsets(pkt);
    1583                 :      15249 :     dp_packet_set_l3(pkt, dp_packet_put(pkt, bpdu, bpdu_size));
    1584                 :            : 
    1585                 :            :     /* 802.2 header. */
    1586                 :      15249 :     eth->eth_dst = eth_addr_stp;
    1587                 :            :     /* p->stp->send_bpdu() must fill in source address. */
    1588                 :      15249 :     eth->eth_type = htons(dp_packet_size(pkt) - ETH_HEADER_LEN);
    1589                 :            : 
    1590                 :            :     /* LLC header. */
    1591                 :      15249 :     llc->llc_dsap = STP_LLC_DSAP;
    1592                 :      15249 :     llc->llc_ssap = STP_LLC_SSAP;
    1593                 :      15249 :     llc->llc_cntl = STP_LLC_CNTL;
    1594                 :            : 
    1595                 :      15249 :     p->stp->send_bpdu(pkt, stp_port_no(p), p->stp->aux);
    1596                 :      15249 :     p->tx_count++;
    1597                 :      15249 : }
    1598                 :            : 
    1599                 :            : /* Unixctl. */
    1600                 :            : 
    1601                 :            : static struct stp *
    1602                 :          0 : stp_find(const char *name) OVS_REQUIRES(mutex)
    1603                 :            : {
    1604                 :            :     struct stp *stp;
    1605                 :            : 
    1606         [ #  # ]:          0 :     LIST_FOR_EACH (stp, node, all_stps) {
    1607         [ #  # ]:          0 :         if (!strcmp(stp->name, name)) {
    1608                 :          0 :             return stp;
    1609                 :            :         }
    1610                 :            :     }
    1611                 :          0 :     return NULL;
    1612                 :            : }
    1613                 :            : 
    1614                 :            : static void
    1615                 :          0 : stp_unixctl_tcn(struct unixctl_conn *conn, int argc,
    1616                 :            :                 const char *argv[], void *aux OVS_UNUSED)
    1617                 :            : {
    1618                 :          0 :     ovs_mutex_lock(&mutex);
    1619         [ #  # ]:          0 :     if (argc > 1) {
    1620                 :          0 :         struct stp *stp = stp_find(argv[1]);
    1621                 :            : 
    1622         [ #  # ]:          0 :         if (!stp) {
    1623                 :          0 :             unixctl_command_reply_error(conn, "no such stp object");
    1624                 :          0 :             goto out;
    1625                 :            :         }
    1626                 :          0 :         stp_topology_change_detection(stp);
    1627                 :            :     } else {
    1628                 :            :         struct stp *stp;
    1629                 :            : 
    1630         [ #  # ]:          0 :         LIST_FOR_EACH (stp, node, all_stps) {
    1631                 :          0 :             stp_topology_change_detection(stp);
    1632                 :            :         }
    1633                 :            :     }
    1634                 :            : 
    1635                 :          0 :     unixctl_command_reply(conn, "OK");
    1636                 :            : 
    1637                 :            : out:
    1638                 :          0 :     ovs_mutex_unlock(&mutex);
    1639                 :          0 : }

Generated by: LCOV version 1.12