LCOV - code coverage report
Current view: top level - lib - bfd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 494 556 88.8 %
Date: 2016-09-14 01:02:56 Functions: 40 40 100.0 %
Branches: 229 317 72.2 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2013, 2014, 2015, 2016 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License. */
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : #include "bfd.h"
      17                 :            : 
      18                 :            : #include <sys/types.h>
      19                 :            : #include <arpa/inet.h>
      20                 :            : #include <netinet/in_systm.h>
      21                 :            : #include <netinet/ip.h>
      22                 :            : #include <sys/socket.h>
      23                 :            : 
      24                 :            : #include "byte-order.h"
      25                 :            : #include "connectivity.h"
      26                 :            : #include "csum.h"
      27                 :            : #include "dp-packet.h"
      28                 :            : #include "dpif.h"
      29                 :            : #include "openvswitch/dynamic-string.h"
      30                 :            : #include "flow.h"
      31                 :            : #include "hash.h"
      32                 :            : #include "openvswitch/hmap.h"
      33                 :            : #include "openvswitch/list.h"
      34                 :            : #include "netdev.h"
      35                 :            : #include "odp-util.h"
      36                 :            : #include "openvswitch/ofpbuf.h"
      37                 :            : #include "ovs-thread.h"
      38                 :            : #include "openvswitch/types.h"
      39                 :            : #include "packets.h"
      40                 :            : #include "poll-loop.h"
      41                 :            : #include "random.h"
      42                 :            : #include "seq.h"
      43                 :            : #include "smap.h"
      44                 :            : #include "timeval.h"
      45                 :            : #include "unaligned.h"
      46                 :            : #include "unixctl.h"
      47                 :            : #include "util.h"
      48                 :            : #include "openvswitch/vlog.h"
      49                 :            : 
      50                 :       1288 : VLOG_DEFINE_THIS_MODULE(bfd);
      51                 :            : 
      52                 :            : /* XXX Finish BFD.
      53                 :            :  *
      54                 :            :  * The goal of this module is to replace CFM with something both more flexible
      55                 :            :  * and standards compliant.  In service of this goal, the following needs to be
      56                 :            :  * done.
      57                 :            :  *
      58                 :            :  * - Compliance
      59                 :            :  *   * Implement Demand mode.
      60                 :            :  *   * Go through the RFC line by line and verify we comply.
      61                 :            :  *   * Test against a hardware implementation.  Preferably a popular one.
      62                 :            :  *   * Delete BFD packets with nw_ttl != 255 in the datapath to prevent DOS
      63                 :            :  *     attacks.
      64                 :            :  *
      65                 :            :  * - Unit tests.
      66                 :            :  *
      67                 :            :  * - Set TOS/PCP on the outer tunnel header when encapped.
      68                 :            :  *
      69                 :            :  * - Sending BFD messages should be in its own thread/process.
      70                 :            :  *
      71                 :            :  * - Scale testing.  How does it operate when there are large number of bfd
      72                 :            :  *   sessions?  Do we ever have random flaps?  What's the CPU utilization?
      73                 :            :  *
      74                 :            :  * - Rely on data traffic for liveness by using BFD demand mode.
      75                 :            :  *   If we're receiving traffic on a port, we can safely assume it's up (modulo
      76                 :            :  *   unidrectional failures).  BFD has a demand mode in which it can stay quiet
      77                 :            :  *   unless it feels the need to check the status of the port.  Using this, we
      78                 :            :  *   can implement a strategy in which BFD only sends control messages on dark
      79                 :            :  *   interfaces.
      80                 :            :  *
      81                 :            :  * - Depending on how one interprets the spec, it appears that a BFD session
      82                 :            :  *   can never change bfd.LocalDiag to "No Diagnostic".  We should verify that
      83                 :            :  *   this is what hardware implementations actually do.  Seems like "No
      84                 :            :  *   Diagnostic" should be set once a BFD session state goes UP. */
      85                 :            : 
      86                 :            : #define BFD_VERSION 1
      87                 :            : 
      88                 :            : enum flags {
      89                 :            :     FLAG_MULTIPOINT = 1 << 0,
      90                 :            :     FLAG_DEMAND = 1 << 1,
      91                 :            :     FLAG_AUTH = 1 << 2,
      92                 :            :     FLAG_CTL = 1 << 3,
      93                 :            :     FLAG_FINAL = 1 << 4,
      94                 :            :     FLAG_POLL = 1 << 5
      95                 :            : };
      96                 :            : 
      97                 :            : enum state {
      98                 :            :     STATE_ADMIN_DOWN = 0 << 6,
      99                 :            :     STATE_DOWN = 1 << 6,
     100                 :            :     STATE_INIT = 2 << 6,
     101                 :            :     STATE_UP = 3 << 6
     102                 :            : };
     103                 :            : 
     104                 :            : enum diag {
     105                 :            :     DIAG_NONE = 0,                /* No Diagnostic. */
     106                 :            :     DIAG_EXPIRED = 1,             /* Control Detection Time Expired. */
     107                 :            :     DIAG_ECHO_FAILED = 2,         /* Echo Function Failed. */
     108                 :            :     DIAG_RMT_DOWN = 3,            /* Neighbor Signaled Session Down. */
     109                 :            :     DIAG_FWD_RESET = 4,           /* Forwarding Plane Reset. */
     110                 :            :     DIAG_PATH_DOWN = 5,           /* Path Down. */
     111                 :            :     DIAG_CPATH_DOWN = 6,          /* Concatenated Path Down. */
     112                 :            :     DIAG_ADMIN_DOWN = 7,          /* Administratively Down. */
     113                 :            :     DIAG_RCPATH_DOWN = 8          /* Reverse Concatenated Path Down. */
     114                 :            : };
     115                 :            : 
     116                 :            : /* RFC 5880 Section 4.1
     117                 :            :  *  0                   1                   2                   3
     118                 :            :  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     119                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     120                 :            :  * |Vers |  Diag   |Sta|P|F|C|A|D|M|  Detect Mult  |    Length     |
     121                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     122                 :            :  * |                       My Discriminator                        |
     123                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     124                 :            :  * |                      Your Discriminator                       |
     125                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     126                 :            :  * |                    Desired Min TX Interval                    |
     127                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     128                 :            :  * |                   Required Min RX Interval                    |
     129                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     130                 :            :  * |                 Required Min Echo RX Interval                 |
     131                 :            :  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
     132                 :            : struct msg {
     133                 :            :     uint8_t vers_diag;    /* Version and diagnostic. */
     134                 :            :     uint8_t flags;        /* 2bit State field followed by flags. */
     135                 :            :     uint8_t mult;         /* Fault detection multiplier. */
     136                 :            :     uint8_t length;       /* Length of this BFD message. */
     137                 :            :     ovs_be32 my_disc;     /* My discriminator. */
     138                 :            :     ovs_be32 your_disc;   /* Your discriminator. */
     139                 :            :     ovs_be32 min_tx;      /* Desired minimum tx interval. */
     140                 :            :     ovs_be32 min_rx;      /* Required minimum rx interval. */
     141                 :            :     ovs_be32 min_rx_echo; /* Required minimum echo rx interval. */
     142                 :            : };
     143                 :            : BUILD_ASSERT_DECL(BFD_PACKET_LEN == sizeof(struct msg));
     144                 :            : 
     145                 :            : #define DIAG_MASK 0x1f
     146                 :            : #define VERS_SHIFT 5
     147                 :            : #define STATE_MASK 0xC0
     148                 :            : #define FLAGS_MASK 0x3f
     149                 :            : 
     150                 :            : struct bfd {
     151                 :            :     struct hmap_node node;        /* In 'all_bfds'. */
     152                 :            :     uint32_t disc;                /* bfd.LocalDiscr. Key in 'all_bfds' hmap. */
     153                 :            : 
     154                 :            :     char *name;                   /* Name used for logging. */
     155                 :            : 
     156                 :            :     bool cpath_down;              /* Concatenated Path Down. */
     157                 :            :     uint8_t mult;                 /* bfd.DetectMult. */
     158                 :            : 
     159                 :            :     struct netdev *netdev;
     160                 :            :     uint64_t rx_packets;          /* Packets received by 'netdev'. */
     161                 :            : 
     162                 :            :     enum state state;             /* bfd.SessionState. */
     163                 :            :     enum state rmt_state;         /* bfd.RemoteSessionState. */
     164                 :            : 
     165                 :            :     enum diag diag;               /* bfd.LocalDiag. */
     166                 :            :     enum diag rmt_diag;           /* Remote diagnostic. */
     167                 :            : 
     168                 :            :     enum flags flags;             /* Flags sent on messages. */
     169                 :            :     enum flags rmt_flags;         /* Flags last received. */
     170                 :            : 
     171                 :            :     bool oam;                     /* Set tunnel OAM flag if applicable. */
     172                 :            : 
     173                 :            :     uint32_t rmt_disc;            /* bfd.RemoteDiscr. */
     174                 :            : 
     175                 :            :     struct eth_addr local_eth_src; /* Local eth src address. */
     176                 :            :     struct eth_addr local_eth_dst; /* Local eth dst address. */
     177                 :            : 
     178                 :            :     struct eth_addr rmt_eth_dst;   /* Remote eth dst address. */
     179                 :            : 
     180                 :            :     ovs_be32 ip_src;              /* IPv4 source address. */
     181                 :            :     ovs_be32 ip_dst;              /* IPv4 destination address. */
     182                 :            : 
     183                 :            :     uint16_t udp_src;             /* UDP source port. */
     184                 :            : 
     185                 :            :     /* All timers in milliseconds. */
     186                 :            :     long long int rmt_min_rx;     /* bfd.RemoteMinRxInterval. */
     187                 :            :     long long int rmt_min_tx;     /* Remote minimum TX interval. */
     188                 :            : 
     189                 :            :     long long int cfg_min_tx;     /* Configured minimum TX rate. */
     190                 :            :     long long int cfg_min_rx;     /* Configured required minimum RX rate. */
     191                 :            :     long long int poll_min_tx;    /* Min TX negotating in a poll sequence. */
     192                 :            :     long long int poll_min_rx;    /* Min RX negotating in a poll sequence. */
     193                 :            :     long long int min_tx;         /* bfd.DesiredMinTxInterval. */
     194                 :            :     long long int min_rx;         /* bfd.RequiredMinRxInterval. */
     195                 :            : 
     196                 :            :     long long int last_tx;        /* Last TX time. */
     197                 :            :     long long int next_tx;        /* Next TX time. */
     198                 :            :     long long int detect_time;    /* RFC 5880 6.8.4 Detection time. */
     199                 :            : 
     200                 :            :     bool last_forwarding;         /* Last calculation of forwarding flag. */
     201                 :            :     int forwarding_override;      /* Manual override of 'forwarding' status. */
     202                 :            : 
     203                 :            :     atomic_bool check_tnl_key;    /* Verify tunnel key of inbound packets? */
     204                 :            :     struct ovs_refcount ref_cnt;
     205                 :            : 
     206                 :            :     /* When forward_if_rx is true, bfd_forwarding() will return
     207                 :            :      * true as long as there are incoming packets received.
     208                 :            :      * Note, forwarding_override still has higher priority. */
     209                 :            :     bool forwarding_if_rx;
     210                 :            :     long long int forwarding_if_rx_detect_time;
     211                 :            : 
     212                 :            :     /* When 'bfd->forwarding_if_rx' is set, at least one bfd control packet
     213                 :            :      * is required to be received every 100 * bfd->cfg_min_rx.  If bfd
     214                 :            :      * control packet is not received within this interval, even if data
     215                 :            :      * packets are received, the bfd->forwarding will still be false. */
     216                 :            :     long long int demand_rx_bfd_time;
     217                 :            : 
     218                 :            :     /* BFD decay related variables. */
     219                 :            :     bool in_decay;                /* True when bfd is in decay. */
     220                 :            :     int decay_min_rx;             /* min_rx is set to decay_min_rx when */
     221                 :            :                                   /* in decay. */
     222                 :            :     int decay_rx_ctl;             /* Count bfd packets received within decay */
     223                 :            :                                   /* detect interval. */
     224                 :            :     uint64_t decay_rx_packets;    /* Packets received by 'netdev'. */
     225                 :            :     long long int decay_detect_time; /* Decay detection time. */
     226                 :            : 
     227                 :            :     uint64_t flap_count;          /* Counts bfd forwarding flaps. */
     228                 :            : 
     229                 :            :     /* True when the variables returned by bfd_get_status() are changed
     230                 :            :      * since last check. */
     231                 :            :     bool status_changed;
     232                 :            : };
     233                 :            : 
     234                 :            : static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
     235                 :            : static struct hmap all_bfds__ = HMAP_INITIALIZER(&all_bfds__);
     236                 :            : static struct hmap *const all_bfds OVS_GUARDED_BY(mutex) = &all_bfds__;
     237                 :            : 
     238                 :            : static void bfd_lookup_ip(const char *host_name, ovs_be32 def, ovs_be32 *ip)
     239                 :            :     OVS_REQUIRES(mutex);
     240                 :            : static bool bfd_forwarding__(struct bfd *) OVS_REQUIRES(mutex);
     241                 :            : static bool bfd_in_poll(const struct bfd *) OVS_REQUIRES(mutex);
     242                 :            : static void bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex);
     243                 :            : static const char *bfd_diag_str(enum diag) OVS_REQUIRES(mutex);
     244                 :            : static const char *bfd_state_str(enum state) OVS_REQUIRES(mutex);
     245                 :            : static long long int bfd_min_tx(const struct bfd *) OVS_REQUIRES(mutex);
     246                 :            : static long long int bfd_tx_interval(const struct bfd *)
     247                 :            :     OVS_REQUIRES(mutex);
     248                 :            : static long long int bfd_rx_interval(const struct bfd *)
     249                 :            :     OVS_REQUIRES(mutex);
     250                 :            : static void bfd_set_next_tx(struct bfd *) OVS_REQUIRES(mutex);
     251                 :            : static void bfd_set_state(struct bfd *, enum state, enum diag)
     252                 :            :     OVS_REQUIRES(mutex);
     253                 :            : static uint32_t generate_discriminator(void) OVS_REQUIRES(mutex);
     254                 :            : static void bfd_put_details(struct ds *, const struct bfd *)
     255                 :            :     OVS_REQUIRES(mutex);
     256                 :            : static uint64_t bfd_rx_packets(const struct bfd *) OVS_REQUIRES(mutex);
     257                 :            : static void bfd_try_decay(struct bfd *) OVS_REQUIRES(mutex);
     258                 :            : static void bfd_decay_update(struct bfd *) OVS_REQUIRES(mutex);
     259                 :            : static void bfd_status_changed(struct bfd *) OVS_REQUIRES(mutex);
     260                 :            : 
     261                 :            : static void bfd_forwarding_if_rx_update(struct bfd *) OVS_REQUIRES(mutex);
     262                 :            : static void bfd_unixctl_show(struct unixctl_conn *, int argc,
     263                 :            :                              const char *argv[], void *aux OVS_UNUSED);
     264                 :            : static void bfd_unixctl_set_forwarding_override(struct unixctl_conn *,
     265                 :            :                                                 int argc, const char *argv[],
     266                 :            :                                                 void *aux OVS_UNUSED);
     267                 :            : static void log_msg(enum vlog_level, const struct msg *, const char *message,
     268                 :            :                     const struct bfd *) OVS_REQUIRES(mutex);
     269                 :            : 
     270                 :            : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 20);
     271                 :            : 
     272                 :            : /* Returns true if the interface on which 'bfd' is running may be used to
     273                 :            :  * forward traffic according to the BFD session state. */
     274                 :            : bool
     275                 :      20186 : bfd_forwarding(struct bfd *bfd) OVS_EXCLUDED(mutex)
     276                 :            : {
     277                 :            :     bool ret;
     278                 :            : 
     279                 :      20186 :     ovs_mutex_lock(&mutex);
     280                 :      20186 :     ret = bfd_forwarding__(bfd);
     281                 :      20186 :     ovs_mutex_unlock(&mutex);
     282                 :      20186 :     return ret;
     283                 :            : }
     284                 :            : 
     285                 :            : /* When forwarding_if_rx is enabled, if there are packets received,
     286                 :            :  * updates forwarding_if_rx_detect_time. */
     287                 :            : void
     288                 :       1564 : bfd_account_rx(struct bfd *bfd, const struct dpif_flow_stats *stats)
     289                 :            : {
     290 [ +  - ][ +  + ]:       1564 :     if (stats->n_packets && bfd->forwarding_if_rx) {
     291                 :        484 :         ovs_mutex_lock(&mutex);
     292                 :        484 :         bfd_forwarding__(bfd);
     293                 :        484 :         bfd_forwarding_if_rx_update(bfd);
     294                 :        484 :         bfd_forwarding__(bfd);
     295                 :        484 :         ovs_mutex_unlock(&mutex);
     296                 :            :     }
     297                 :       1564 : }
     298                 :            : 
     299                 :            : /* Returns and resets the 'bfd->status_changed'. */
     300                 :            : bool
     301                 :      20164 : bfd_check_status_change(struct bfd *bfd) OVS_EXCLUDED(mutex)
     302                 :            : {
     303                 :            :     bool ret;
     304                 :            : 
     305                 :      20164 :     ovs_mutex_lock(&mutex);
     306                 :      20164 :     ret = bfd->status_changed;
     307                 :      20164 :     bfd->status_changed = false;
     308                 :      20164 :     ovs_mutex_unlock(&mutex);
     309                 :            : 
     310                 :      20164 :     return ret;
     311                 :            : }
     312                 :            : 
     313                 :            : /* Returns a 'smap' of key value pairs representing the status of 'bfd'
     314                 :            :  * intended for the OVS database. */
     315                 :            : void
     316                 :      20105 : bfd_get_status(const struct bfd *bfd, struct smap *smap)
     317                 :            :     OVS_EXCLUDED(mutex)
     318                 :            : {
     319                 :      20105 :     ovs_mutex_lock(&mutex);
     320         [ +  + ]:      20105 :     smap_add(smap, "forwarding",
     321                 :      20105 :              bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
     322                 :            :              ? "true" : "false");
     323                 :      20105 :     smap_add(smap, "state", bfd_state_str(bfd->state));
     324                 :      20105 :     smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag));
     325                 :      20105 :     smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
     326                 :      20105 :     smap_add(smap, "remote_state", bfd_state_str(bfd->rmt_state));
     327                 :      20105 :     smap_add(smap, "remote_diagnostic", bfd_diag_str(bfd->rmt_diag));
     328                 :      20105 :     ovs_mutex_unlock(&mutex);
     329                 :      20105 : }
     330                 :            : 
     331                 :            : void
     332                 :        617 : bfd_init(void)
     333                 :            : {
     334                 :        617 :     unixctl_command_register("bfd/show", "[interface]", 0, 1,
     335                 :            :                              bfd_unixctl_show, NULL);
     336                 :        617 :     unixctl_command_register("bfd/set-forwarding",
     337                 :            :                              "[interface] normal|false|true", 1, 2,
     338                 :            :                              bfd_unixctl_set_forwarding_override, NULL);
     339                 :        617 : }
     340                 :            : 
     341                 :            : /* Initializes, destroys, or reconfigures the BFD session 'bfd' (named 'name'),
     342                 :            :  * according to the database configuration contained in 'cfg'.  Takes ownership
     343                 :            :  * of 'bfd', which may be NULL.  Returns a BFD object which may be used as a
     344                 :            :  * handle for the session, or NULL if BFD is not enabled according to 'cfg'.
     345                 :            :  * Also returns NULL if cfg is NULL. */
     346                 :            : struct bfd *
     347                 :      34526 : bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     348                 :            :               struct netdev *netdev) OVS_EXCLUDED(mutex)
     349                 :            : {
     350                 :            :     static atomic_count udp_src = ATOMIC_COUNT_INIT(0);
     351                 :            : 
     352                 :            :     int decay_min_rx;
     353                 :            :     long long int min_tx, min_rx;
     354                 :      34526 :     bool need_poll = false;
     355                 :      34526 :     bool cfg_min_rx_changed = false;
     356                 :            :     bool cpath_down, forwarding_if_rx;
     357                 :            : 
     358 [ +  + ][ +  + ]:      34526 :     if (!cfg || !smap_get_bool(cfg, "enable", false)) {
     359                 :      14530 :         bfd_unref(bfd);
     360                 :      14530 :         return NULL;
     361                 :            :     }
     362                 :            : 
     363                 :      19996 :     ovs_mutex_lock(&mutex);
     364         [ +  + ]:      19996 :     if (!bfd) {
     365                 :        234 :         bfd = xzalloc(sizeof *bfd);
     366                 :        234 :         bfd->name = xstrdup(name);
     367                 :        234 :         bfd->forwarding_override = -1;
     368                 :        234 :         bfd->disc = generate_discriminator();
     369                 :        234 :         hmap_insert(all_bfds, &bfd->node, bfd->disc);
     370                 :            : 
     371                 :        234 :         bfd->diag = DIAG_NONE;
     372                 :        234 :         bfd->min_tx = 1000;
     373                 :        234 :         bfd->mult = 3;
     374                 :        234 :         ovs_refcount_init(&bfd->ref_cnt);
     375                 :        234 :         bfd->netdev = netdev_ref(netdev);
     376                 :        234 :         bfd->rx_packets = bfd_rx_packets(bfd);
     377                 :        234 :         bfd->in_decay = false;
     378                 :        234 :         bfd->flap_count = 0;
     379                 :            : 
     380                 :            :         /* RFC 5881 section 4
     381                 :            :          * The source port MUST be in the range 49152 through 65535.  The same
     382                 :            :          * UDP source port number MUST be used for all BFD Control packets
     383                 :            :          * associated with a particular session.  The source port number SHOULD
     384                 :            :          * be unique among all BFD sessions on the system. */
     385                 :        234 :         bfd->udp_src = (atomic_count_inc(&udp_src) % 16384) + 49152;
     386                 :            : 
     387                 :        234 :         bfd_set_state(bfd, STATE_DOWN, DIAG_NONE);
     388                 :            : 
     389                 :        234 :         bfd_status_changed(bfd);
     390                 :            :     }
     391                 :            : 
     392                 :      19996 :     bfd->oam = smap_get_bool(cfg, "oam", false);
     393                 :            : 
     394                 :      19996 :     atomic_store_relaxed(&bfd->check_tnl_key,
     395                 :            :                          smap_get_bool(cfg, "check_tnl_key", false));
     396                 :      19996 :     min_tx = smap_get_int(cfg, "min_tx", 100);
     397                 :      19996 :     min_tx = MAX(min_tx, 1);
     398         [ +  + ]:      19996 :     if (bfd->cfg_min_tx != min_tx) {
     399                 :        237 :         bfd->cfg_min_tx = min_tx;
     400         [ +  + ]:        237 :         if (bfd->state != STATE_UP
     401 [ +  - ][ +  + ]:          3 :             || (!bfd_in_poll(bfd) && bfd->cfg_min_tx < bfd->min_tx)) {
     402                 :        235 :             bfd->min_tx = bfd->cfg_min_tx;
     403                 :            :         }
     404                 :        237 :         need_poll = true;
     405                 :            :     }
     406                 :            : 
     407                 :      19996 :     min_rx = smap_get_int(cfg, "min_rx", 1000);
     408                 :      19996 :     min_rx = MAX(min_rx, 1);
     409         [ +  + ]:      19996 :     if (bfd->cfg_min_rx != min_rx) {
     410                 :        235 :         bfd->cfg_min_rx = min_rx;
     411         [ +  + ]:        235 :         if (bfd->state != STATE_UP
     412 [ +  - ][ -  + ]:          1 :             || (!bfd_in_poll(bfd) && bfd->cfg_min_rx > bfd->min_rx)) {
     413                 :        234 :             bfd->min_rx = bfd->cfg_min_rx;
     414                 :            :         }
     415                 :        235 :         cfg_min_rx_changed = true;
     416                 :        235 :         need_poll = true;
     417                 :            :     }
     418                 :            : 
     419                 :      19996 :     decay_min_rx = smap_get_int(cfg, "decay_min_rx", 0);
     420 [ +  + ][ +  + ]:      19996 :     if (bfd->decay_min_rx != decay_min_rx || cfg_min_rx_changed) {
     421 [ +  + ][ -  + ]:        240 :         if (decay_min_rx > 0 && decay_min_rx < bfd->cfg_min_rx) {
     422         [ #  # ]:          0 :             VLOG_WARN("%s: decay_min_rx cannot be less than %lld ms",
     423                 :            :                       bfd->name, bfd->cfg_min_rx);
     424                 :          0 :             bfd->decay_min_rx = 0;
     425                 :            :         } else {
     426                 :        240 :             bfd->decay_min_rx = decay_min_rx;
     427                 :            :         }
     428                 :            :         /* Resets decay. */
     429                 :        240 :         bfd->in_decay = false;
     430                 :        240 :         bfd_decay_update(bfd);
     431                 :        240 :         need_poll = true;
     432                 :            :     }
     433                 :            : 
     434                 :      19996 :     cpath_down = smap_get_bool(cfg, "cpath_down", false);
     435         [ +  + ]:      19996 :     if (bfd->cpath_down != cpath_down) {
     436                 :          1 :         bfd->cpath_down = cpath_down;
     437                 :          1 :         bfd_set_state(bfd, bfd->state, DIAG_NONE);
     438                 :          1 :         need_poll = true;
     439                 :            :     }
     440                 :            : 
     441                 :      19996 :     eth_addr_from_string(smap_get_def(cfg, "bfd_local_src_mac", ""),
     442                 :            :                          &bfd->local_eth_src);
     443                 :      19996 :     eth_addr_from_string(smap_get_def(cfg, "bfd_local_dst_mac", ""),
     444                 :            :                          &bfd->local_eth_dst);
     445                 :      19996 :     eth_addr_from_string(smap_get_def(cfg, "bfd_remote_dst_mac", ""),
     446                 :            :                          &bfd->rmt_eth_dst);
     447                 :            : 
     448                 :      19996 :     bfd_lookup_ip(smap_get_def(cfg, "bfd_src_ip", ""),
     449                 :            :                   htonl(0xA9FE0101) /* 169.254.1.1 */, &bfd->ip_src);
     450                 :      19996 :     bfd_lookup_ip(smap_get_def(cfg, "bfd_dst_ip", ""),
     451                 :            :                   htonl(0xA9FE0100) /* 169.254.1.0 */, &bfd->ip_dst);
     452                 :            : 
     453                 :      19996 :     forwarding_if_rx = smap_get_bool(cfg, "forwarding_if_rx", false);
     454         [ +  + ]:      19996 :     if (bfd->forwarding_if_rx != forwarding_if_rx) {
     455                 :          8 :         bfd->forwarding_if_rx = forwarding_if_rx;
     456 [ +  + ][ +  - ]:          8 :         if (bfd->state == STATE_UP && bfd->forwarding_if_rx) {
     457                 :          3 :             bfd_forwarding_if_rx_update(bfd);
     458                 :            :         } else {
     459                 :          5 :             bfd->forwarding_if_rx_detect_time = 0;
     460                 :            :         }
     461                 :            :     }
     462                 :            : 
     463         [ +  + ]:      19996 :     if (need_poll) {
     464                 :        244 :         bfd_poll(bfd);
     465                 :            :     }
     466                 :      19996 :     ovs_mutex_unlock(&mutex);
     467                 :      19996 :     return bfd;
     468                 :            : }
     469                 :            : 
     470                 :            : struct bfd *
     471                 :     117274 : bfd_ref(const struct bfd *bfd_)
     472                 :            : {
     473                 :     117274 :     struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
     474         [ +  + ]:     117274 :     if (bfd) {
     475                 :      80660 :         ovs_refcount_ref(&bfd->ref_cnt);
     476                 :            :     }
     477                 :     117274 :     return bfd;
     478                 :            : }
     479                 :            : 
     480                 :            : void
     481                 :     341936 : bfd_unref(struct bfd *bfd) OVS_EXCLUDED(mutex)
     482                 :            : {
     483 [ +  + ][ +  + ]:     341936 :     if (bfd && ovs_refcount_unref_relaxed(&bfd->ref_cnt) == 1) {
     484                 :        234 :         ovs_mutex_lock(&mutex);
     485                 :        234 :         bfd_status_changed(bfd);
     486                 :        234 :         hmap_remove(all_bfds, &bfd->node);
     487                 :        234 :         netdev_close(bfd->netdev);
     488                 :        234 :         free(bfd->name);
     489                 :        234 :         free(bfd);
     490                 :        234 :         ovs_mutex_unlock(&mutex);
     491                 :            :     }
     492                 :     341936 : }
     493                 :            : 
     494                 :            : long long int
     495                 :      25410 : bfd_wait(const struct bfd *bfd) OVS_EXCLUDED(mutex)
     496                 :            : {
     497                 :      25410 :     long long int wake_time = bfd_wake_time(bfd);
     498                 :      25410 :     poll_timer_wait_until(wake_time);
     499                 :      25410 :     return wake_time;
     500                 :            : }
     501                 :            : 
     502                 :            : /* Returns the next wake up time. */
     503                 :            : long long int
     504                 :      25410 : bfd_wake_time(const struct bfd *bfd) OVS_EXCLUDED(mutex)
     505                 :            : {
     506                 :            :     long long int retval;
     507                 :            : 
     508         [ -  + ]:      25410 :     if (!bfd) {
     509                 :          0 :         return LLONG_MAX;
     510                 :            :     }
     511                 :            : 
     512                 :      25410 :     ovs_mutex_lock(&mutex);
     513         [ -  + ]:      25410 :     if (bfd->flags & FLAG_FINAL) {
     514                 :          0 :         retval = 0;
     515                 :            :     } else {
     516                 :      25410 :         retval = bfd->next_tx;
     517         [ +  + ]:      25410 :         if (bfd->state > STATE_DOWN) {
     518                 :       1641 :             retval = MIN(bfd->detect_time, retval);
     519                 :            :         }
     520                 :            :     }
     521                 :      25410 :     ovs_mutex_unlock(&mutex);
     522                 :      25410 :     return retval;
     523                 :            : }
     524                 :            : 
     525                 :            : void
     526                 :      25410 : bfd_run(struct bfd *bfd) OVS_EXCLUDED(mutex)
     527                 :            : {
     528                 :            :     long long int now;
     529                 :            :     bool old_in_decay;
     530                 :            : 
     531                 :      25410 :     ovs_mutex_lock(&mutex);
     532                 :      25410 :     now = time_msec();
     533                 :      25410 :     old_in_decay = bfd->in_decay;
     534                 :            : 
     535 [ +  + ][ +  + ]:      25410 :     if (bfd->state > STATE_DOWN && now >= bfd->detect_time) {
     536                 :         16 :         bfd_set_state(bfd, STATE_DOWN, DIAG_EXPIRED);
     537                 :            :     }
     538                 :      25410 :     bfd_forwarding__(bfd);
     539                 :            : 
     540                 :            :     /* Decay may only happen when state is STATE_UP, bfd->decay_min_rx is
     541                 :            :      * configured, and decay_detect_time is reached. */
     542 [ +  + ][ +  + ]:      25410 :     if (bfd->state == STATE_UP && bfd->decay_min_rx > 0
     543         [ +  + ]:        249 :         && now >= bfd->decay_detect_time) {
     544                 :         38 :         bfd_try_decay(bfd);
     545                 :            :     }
     546                 :            : 
     547         [ +  + ]:      25410 :     if (bfd->min_tx != bfd->cfg_min_tx
     548 [ +  + ][ +  + ]:      25406 :         || (bfd->min_rx != bfd->cfg_min_rx && bfd->min_rx != bfd->decay_min_rx)
     549         [ +  + ]:      25403 :         || bfd->in_decay != old_in_decay) {
     550                 :         17 :         bfd_poll(bfd);
     551                 :            :     }
     552                 :      25410 :     ovs_mutex_unlock(&mutex);
     553                 :      25410 : }
     554                 :            : 
     555                 :            : bool
     556                 :      26538 : bfd_should_send_packet(const struct bfd *bfd) OVS_EXCLUDED(mutex)
     557                 :            : {
     558                 :            :     bool ret;
     559                 :      26538 :     ovs_mutex_lock(&mutex);
     560 [ +  + ][ +  + ]:      26538 :     ret = bfd->flags & FLAG_FINAL || time_msec() >= bfd->next_tx;
     561                 :      26538 :     ovs_mutex_unlock(&mutex);
     562                 :      26538 :     return ret;
     563                 :            : }
     564                 :            : 
     565                 :            : void
     566                 :       5198 : bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
     567                 :            :                const struct eth_addr eth_src, bool *oam) OVS_EXCLUDED(mutex)
     568                 :            : {
     569                 :            :     long long int min_tx, min_rx;
     570                 :            :     struct udp_header *udp;
     571                 :            :     struct eth_header *eth;
     572                 :            :     struct ip_header *ip;
     573                 :            :     struct msg *msg;
     574                 :            : 
     575                 :       5198 :     ovs_mutex_lock(&mutex);
     576         [ +  + ]:       5198 :     if (bfd->next_tx) {
     577                 :       4945 :         long long int delay = time_msec() - bfd->next_tx;
     578                 :       4945 :         long long int interval = bfd_tx_interval(bfd);
     579         [ +  + ]:       4945 :         if (delay > interval * 3 / 2) {
     580         [ +  - ]:          4 :             VLOG_INFO("%s: long delay of %lldms (expected %lldms) sending BFD"
     581                 :            :                       " control message", bfd->name, delay, interval);
     582                 :            :         }
     583                 :            :     }
     584                 :            : 
     585                 :            :     /* RFC 5880 Section 6.5
     586                 :            :      * A BFD Control packet MUST NOT have both the Poll (P) and Final (F) bits
     587                 :            :      * set. */
     588 [ +  + ][ -  + ]:       5198 :     ovs_assert(!(bfd->flags & FLAG_POLL) || !(bfd->flags & FLAG_FINAL));
     589                 :            : 
     590                 :       5198 :     dp_packet_reserve(p, 2); /* Properly align after the ethernet header. */
     591                 :       5198 :     eth = dp_packet_put_uninit(p, sizeof *eth);
     592         [ +  - ]:       5198 :     eth->eth_src = eth_addr_is_zero(bfd->local_eth_src)
     593                 :            :         ? eth_src : bfd->local_eth_src;
     594         [ +  - ]:       5198 :     eth->eth_dst = eth_addr_is_zero(bfd->local_eth_dst)
     595                 :            :         ? eth_addr_bfd : bfd->local_eth_dst;
     596                 :       5198 :     eth->eth_type = htons(ETH_TYPE_IP);
     597                 :            : 
     598                 :       5198 :     ip = dp_packet_put_zeros(p, sizeof *ip);
     599                 :       5198 :     ip->ip_ihl_ver = IP_IHL_VER(5, 4);
     600                 :       5198 :     ip->ip_tot_len = htons(sizeof *ip + sizeof *udp + sizeof *msg);
     601                 :       5198 :     ip->ip_ttl = MAXTTL;
     602                 :       5198 :     ip->ip_tos = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
     603                 :       5198 :     ip->ip_proto = IPPROTO_UDP;
     604                 :       5198 :     put_16aligned_be32(&ip->ip_src, bfd->ip_src);
     605                 :       5198 :     put_16aligned_be32(&ip->ip_dst, bfd->ip_dst);
     606                 :            :     /* Checksum has already been zeroed by put_zeros call. */
     607                 :       5198 :     ip->ip_csum = csum(ip, sizeof *ip);
     608                 :            : 
     609                 :       5198 :     udp = dp_packet_put_zeros(p, sizeof *udp);
     610                 :       5198 :     udp->udp_src = htons(bfd->udp_src);
     611                 :       5198 :     udp->udp_dst = htons(BFD_DEST_PORT);
     612                 :       5198 :     udp->udp_len = htons(sizeof *udp + sizeof *msg);
     613                 :            : 
     614                 :       5198 :     msg = dp_packet_put_uninit(p, sizeof *msg);
     615                 :       5198 :     msg->vers_diag = (BFD_VERSION << 5) | bfd->diag;
     616                 :       5198 :     msg->flags = (bfd->state & STATE_MASK) | bfd->flags;
     617                 :            : 
     618                 :       5198 :     msg->mult = bfd->mult;
     619                 :       5198 :     msg->length = BFD_PACKET_LEN;
     620                 :       5198 :     msg->my_disc = htonl(bfd->disc);
     621                 :       5198 :     msg->your_disc = htonl(bfd->rmt_disc);
     622                 :       5198 :     msg->min_rx_echo = htonl(0);
     623                 :            : 
     624         [ +  + ]:       5198 :     if (bfd_in_poll(bfd)) {
     625                 :         18 :         min_tx = bfd->poll_min_tx;
     626                 :         18 :         min_rx = bfd->poll_min_rx;
     627                 :            :     } else {
     628                 :       5180 :         min_tx = bfd_min_tx(bfd);
     629                 :       5180 :         min_rx = bfd->min_rx;
     630                 :            :     }
     631                 :            : 
     632                 :       5198 :     msg->min_tx = htonl(min_tx * 1000);
     633                 :       5198 :     msg->min_rx = htonl(min_rx * 1000);
     634                 :            : 
     635                 :       5198 :     bfd->flags &= ~FLAG_FINAL;
     636                 :       5198 :     *oam = bfd->oam;
     637                 :            : 
     638                 :       5198 :     log_msg(VLL_DBG, msg, "Sending BFD Message", bfd);
     639                 :            : 
     640                 :       5198 :     bfd->last_tx = time_msec();
     641                 :       5198 :     bfd_set_next_tx(bfd);
     642                 :       5198 :     ovs_mutex_unlock(&mutex);
     643                 :       5198 : }
     644                 :            : 
     645                 :            : bool
     646                 :       1567 : bfd_should_process_flow(const struct bfd *bfd_, const struct flow *flow,
     647                 :            :                         struct flow_wildcards *wc)
     648                 :            : {
     649                 :       1567 :     struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
     650                 :            : 
     651         [ -  + ]:       1567 :     if (!eth_addr_is_zero(bfd->rmt_eth_dst)) {
     652                 :          0 :         memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
     653                 :            : 
     654         [ #  # ]:          0 :         if (!eth_addr_equals(bfd->rmt_eth_dst, flow->dl_dst)) {
     655                 :          0 :             return false;
     656                 :            :         }
     657                 :            :     }
     658                 :            : 
     659         [ +  + ]:       1567 :     if (flow->dl_type == htons(ETH_TYPE_IP)) {
     660                 :       1129 :         memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
     661         [ +  - ]:       1129 :         if (flow->nw_proto == IPPROTO_UDP) {
     662                 :       1129 :             memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
     663         [ +  - ]:       1129 :             if (flow->tp_dst == htons(BFD_DEST_PORT)) {
     664                 :            :                 bool check_tnl_key;
     665                 :            : 
     666                 :       1129 :                 atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key);
     667         [ +  + ]:       1129 :                 if (check_tnl_key) {
     668                 :          2 :                     memset(&wc->masks.tunnel.tun_id, 0xff,
     669                 :            :                            sizeof wc->masks.tunnel.tun_id);
     670                 :          2 :                     return flow->tunnel.tun_id == htonll(0);
     671                 :            :                 }
     672                 :       1129 :                 return true;
     673                 :            :             }
     674                 :            :         }
     675                 :            :     }
     676                 :        438 :     return false;
     677                 :            : }
     678                 :            : 
     679                 :            : void
     680                 :       1128 : bfd_process_packet(struct bfd *bfd, const struct flow *flow,
     681                 :            :                    const struct dp_packet *p) OVS_EXCLUDED(mutex)
     682                 :            : {
     683                 :            :     uint32_t rmt_min_rx, pkt_your_disc;
     684                 :            :     enum state rmt_state;
     685                 :            :     enum flags flags;
     686                 :            :     uint8_t version;
     687                 :            :     struct msg *msg;
     688                 :       1128 :     const uint8_t *l7 = dp_packet_get_udp_payload(p);
     689                 :            : 
     690         [ -  + ]:       1128 :     if (!l7) {
     691                 :          0 :         return; /* No UDP payload. */
     692                 :            :     }
     693                 :            : 
     694                 :            :     /* This function is designed to follow section RFC 5880 6.8.6 closely. */
     695                 :            : 
     696                 :       1128 :     ovs_mutex_lock(&mutex);
     697                 :            :     /* Increments the decay rx counter. */
     698                 :       1128 :     bfd->decay_rx_ctl++;
     699                 :            : 
     700                 :       1128 :     bfd_forwarding__(bfd);
     701                 :            : 
     702         [ -  + ]:       1128 :     if (flow->nw_ttl != 255) {
     703                 :            :         /* XXX Should drop in the kernel to prevent DOS. */
     704                 :          0 :         goto out;
     705                 :            :     }
     706                 :            : 
     707                 :       1128 :     msg = dp_packet_at(p, l7 - (uint8_t *)dp_packet_data(p), BFD_PACKET_LEN);
     708         [ +  + ]:       1128 :     if (!msg) {
     709         [ +  - ]:          2 :         VLOG_INFO_RL(&rl, "%s: Received too-short BFD control message (only "
     710                 :            :                      "%"PRIdPTR" bytes long, at least %d required).",
     711                 :            :                      bfd->name, (uint8_t *) dp_packet_tail(p) - l7,
     712                 :            :                      BFD_PACKET_LEN);
     713                 :          2 :         goto out;
     714                 :            :     }
     715                 :            : 
     716                 :            :     /* RFC 5880 Section 6.8.6
     717                 :            :      * If the Length field is greater than the payload of the encapsulating
     718                 :            :      * protocol, the packet MUST be discarded.
     719                 :            :      *
     720                 :            :      * Note that we make this check implicitly.  Above we use dp_packet_at() to
     721                 :            :      * ensure that there are at least BFD_PACKET_LEN bytes in the payload of
     722                 :            :      * the encapsulating protocol.  Below we require msg->length to be exactly
     723                 :            :      * BFD_PACKET_LEN bytes. */
     724                 :            : 
     725                 :       1126 :     flags = msg->flags & FLAGS_MASK;
     726                 :       1126 :     rmt_state = msg->flags & STATE_MASK;
     727                 :       1126 :     version = msg->vers_diag >> VERS_SHIFT;
     728                 :            : 
     729                 :       1126 :     log_msg(VLL_DBG, msg, "Received BFD control message", bfd);
     730                 :            : 
     731         [ -  + ]:       1126 :     if (version != BFD_VERSION) {
     732                 :          0 :         log_msg(VLL_WARN, msg, "Incorrect version", bfd);
     733                 :          0 :         goto out;
     734                 :            :     }
     735                 :            : 
     736                 :            :     /* Technically this should happen after the length check. We don't support
     737                 :            :      * authentication however, so it's simpler to do the check first. */
     738         [ -  + ]:       1126 :     if (flags & FLAG_AUTH) {
     739                 :          0 :         log_msg(VLL_WARN, msg, "Authenticated control message with"
     740                 :            :                    " authentication disabled", bfd);
     741                 :          0 :         goto out;
     742                 :            :     }
     743                 :            : 
     744         [ -  + ]:       1126 :     if (msg->length != BFD_PACKET_LEN) {
     745                 :          0 :         log_msg(VLL_WARN, msg, "Unexpected length", bfd);
     746         [ #  # ]:          0 :         if (msg->length < BFD_PACKET_LEN) {
     747                 :          0 :             goto out;
     748                 :            :         }
     749                 :            :     }
     750                 :            : 
     751         [ -  + ]:       1126 :     if (!msg->mult) {
     752                 :          0 :         log_msg(VLL_WARN, msg, "Zero multiplier", bfd);
     753                 :          0 :         goto out;
     754                 :            :     }
     755                 :            : 
     756         [ -  + ]:       1126 :     if (flags & FLAG_MULTIPOINT) {
     757                 :          0 :         log_msg(VLL_WARN, msg, "Unsupported multipoint flag", bfd);
     758                 :          0 :         goto out;
     759                 :            :     }
     760                 :            : 
     761         [ -  + ]:       1126 :     if (!msg->my_disc) {
     762                 :          0 :         log_msg(VLL_WARN, msg, "NULL my_disc", bfd);
     763                 :          0 :         goto out;
     764                 :            :     }
     765                 :            : 
     766                 :       1126 :     pkt_your_disc = ntohl(msg->your_disc);
     767         [ +  + ]:       1126 :     if (pkt_your_disc) {
     768                 :            :         /* Technically, we should use the your discriminator field to figure
     769                 :            :          * out which 'struct bfd' this packet is destined towards.  That way a
     770                 :            :          * bfd session could migrate from one interface to another
     771                 :            :          * transparently.  This doesn't fit in with the OVS structure very
     772                 :            :          * well, so in this respect, we are not compliant. */
     773         [ -  + ]:       1091 :        if (pkt_your_disc != bfd->disc) {
     774                 :          0 :            log_msg(VLL_WARN, msg, "Incorrect your_disc", bfd);
     775                 :          0 :            goto out;
     776                 :            :        }
     777         [ -  + ]:         35 :     } else if (rmt_state > STATE_DOWN) {
     778                 :          0 :         log_msg(VLL_WARN, msg, "Null your_disc", bfd);
     779                 :          0 :         goto out;
     780                 :            :     }
     781                 :            : 
     782         [ +  + ]:       1126 :     if (bfd->rmt_state != rmt_state) {
     783                 :         64 :         bfd_status_changed(bfd);
     784                 :            :     }
     785                 :            : 
     786                 :       1126 :     bfd->rmt_disc = ntohl(msg->my_disc);
     787                 :       1126 :     bfd->rmt_state = rmt_state;
     788                 :       1126 :     bfd->rmt_flags = flags;
     789                 :       1126 :     bfd->rmt_diag = msg->vers_diag & DIAG_MASK;
     790                 :            : 
     791 [ +  + ][ +  - ]:       1126 :     if (flags & FLAG_FINAL && bfd_in_poll(bfd)) {
     792                 :         18 :         bfd->min_tx = bfd->poll_min_tx;
     793                 :         18 :         bfd->min_rx = bfd->poll_min_rx;
     794                 :         18 :         bfd->flags &= ~FLAG_POLL;
     795                 :         18 :         log_msg(VLL_INFO, msg, "Poll sequence terminated", bfd);
     796                 :            :     }
     797                 :            : 
     798         [ +  + ]:       1126 :     if (flags & FLAG_POLL) {
     799                 :            :         /* RFC 5880 Section 6.5
     800                 :            :          * When the other system receives a Poll, it immediately transmits a
     801                 :            :          * BFD Control packet with the Final (F) bit set, independent of any
     802                 :            :          * periodic BFD Control packets it may be sending
     803                 :            :          * (see section 6.8.7). */
     804                 :         18 :         bfd->flags &= ~FLAG_POLL;
     805                 :         18 :         bfd->flags |= FLAG_FINAL;
     806                 :            :     }
     807                 :            : 
     808         [ +  - ]:       1126 :     rmt_min_rx = MAX(ntohl(msg->min_rx) / 1000, 1);
     809         [ +  + ]:       1126 :     if (bfd->rmt_min_rx != rmt_min_rx) {
     810                 :         56 :         bfd->rmt_min_rx = rmt_min_rx;
     811         [ +  + ]:         56 :         if (bfd->next_tx) {
     812                 :         55 :             bfd_set_next_tx(bfd);
     813                 :            :         }
     814                 :         56 :         log_msg(VLL_INFO, msg, "New remote min_rx", bfd);
     815                 :            :     }
     816                 :            : 
     817         [ +  - ]:       1126 :     bfd->rmt_min_tx = MAX(ntohl(msg->min_tx) / 1000, 1);
     818                 :       1126 :     bfd->detect_time = bfd_rx_interval(bfd) * bfd->mult + time_msec();
     819                 :            : 
     820         [ -  + ]:       1126 :     if (bfd->state == STATE_ADMIN_DOWN) {
     821         [ #  # ]:          0 :         VLOG_DBG_RL(&rl, "Administratively down, dropping control message.");
     822                 :          0 :         goto out;
     823                 :            :     }
     824                 :            : 
     825         [ -  + ]:       1126 :     if (rmt_state == STATE_ADMIN_DOWN) {
     826         [ #  # ]:          0 :         if (bfd->state != STATE_DOWN) {
     827                 :          0 :             bfd_set_state(bfd, STATE_DOWN, DIAG_RMT_DOWN);
     828                 :            :         }
     829                 :            :     } else {
     830   [ +  +  +  - ]:       1126 :         switch (bfd->state) {
     831                 :            :         case STATE_DOWN:
     832         [ +  + ]:         45 :             if (rmt_state == STATE_DOWN) {
     833                 :         23 :                 bfd_set_state(bfd, STATE_INIT, bfd->diag);
     834         [ +  - ]:         22 :             } else if (rmt_state == STATE_INIT) {
     835                 :         22 :                 bfd_set_state(bfd, STATE_UP, bfd->diag);
     836                 :            :             }
     837                 :         45 :             break;
     838                 :            :         case STATE_INIT:
     839         [ +  + ]:         30 :             if (rmt_state > STATE_DOWN) {
     840                 :         20 :                 bfd_set_state(bfd, STATE_UP, bfd->diag);
     841                 :            :             }
     842                 :         30 :             break;
     843                 :            :         case STATE_UP:
     844         [ +  + ]:       1051 :             if (rmt_state <= STATE_DOWN) {
     845                 :          2 :                 bfd_set_state(bfd, STATE_DOWN, DIAG_RMT_DOWN);
     846                 :          2 :                 log_msg(VLL_INFO, msg, "Remote signaled STATE_DOWN", bfd);
     847                 :            :             }
     848                 :       1051 :             break;
     849                 :            :         case STATE_ADMIN_DOWN:
     850                 :            :         default:
     851                 :          0 :             OVS_NOT_REACHED();
     852                 :            :         }
     853                 :            :     }
     854                 :            :     /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
     855                 :            : 
     856         [ +  + ]:       1126 :     if (bfd->forwarding_if_rx) {
     857                 :        106 :         bfd->demand_rx_bfd_time = time_msec() + 100 * bfd->cfg_min_rx;
     858                 :            :     }
     859                 :            : 
     860                 :            : out:
     861                 :       1128 :     bfd_forwarding__(bfd);
     862                 :       1128 :     ovs_mutex_unlock(&mutex);
     863                 :            : }
     864                 :            : 
     865                 :            : /* Must be called when the netdev owned by 'bfd' should change. */
     866                 :            : void
     867                 :          1 : bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev)
     868                 :            :     OVS_EXCLUDED(mutex)
     869                 :            : {
     870                 :          1 :     ovs_mutex_lock(&mutex);
     871         [ -  + ]:          1 :     if (bfd->netdev != netdev) {
     872                 :          0 :         netdev_close(bfd->netdev);
     873                 :          0 :         bfd->netdev = netdev_ref(netdev);
     874 [ #  # ][ #  # ]:          0 :         if (bfd->decay_min_rx && bfd->state == STATE_UP) {
     875                 :          0 :             bfd_decay_update(bfd);
     876                 :            :         }
     877 [ #  # ][ #  # ]:          0 :         if (bfd->forwarding_if_rx && bfd->state == STATE_UP) {
     878                 :          0 :             bfd_forwarding_if_rx_update(bfd);
     879                 :            :         }
     880                 :          0 :         bfd->rx_packets = bfd_rx_packets(bfd);
     881                 :            :     }
     882                 :          1 :     ovs_mutex_unlock(&mutex);
     883                 :          1 : }
     884                 :            : 
     885                 :            : 
     886                 :            : /* Updates the forwarding flag.  If override is not configured and
     887                 :            :  * the forwarding flag value changes, increments the flap count.
     888                 :            :  *
     889                 :            :  * Note this function may be called multiple times in a function
     890                 :            :  * (e.g. bfd_account_rx) before and after the bfd state or status
     891                 :            :  * change.  This is to capture any forwarding flag flap. */
     892                 :            : static bool
     893                 :      69450 : bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
     894                 :            : {
     895                 :      69450 :     long long int now = time_msec();
     896                 :            :     bool forwarding_if_rx;
     897                 :      69450 :     bool last_forwarding = bfd->last_forwarding;
     898                 :            : 
     899         [ +  + ]:      69450 :     if (bfd->forwarding_override != -1) {
     900                 :        174 :         return bfd->forwarding_override == 1;
     901                 :            :     }
     902                 :            : 
     903                 :     138552 :     forwarding_if_rx = bfd->forwarding_if_rx
     904         [ +  + ]:       1620 :                        && bfd->forwarding_if_rx_detect_time > now
     905 [ +  + ][ +  + ]:      70896 :                        && bfd->demand_rx_bfd_time > now;
     906                 :            : 
     907         [ +  + ]:      64884 :     bfd->last_forwarding = (bfd->state == STATE_UP || forwarding_if_rx)
     908         [ +  - ]:       4986 :                            && bfd->rmt_diag != DIAG_PATH_DOWN
     909         [ +  + ]:       4986 :                            && bfd->rmt_diag != DIAG_CPATH_DOWN
     910 [ +  + ][ +  - ]:     138552 :                            && bfd->rmt_diag != DIAG_RCPATH_DOWN;
     911         [ +  + ]:      69276 :     if (bfd->last_forwarding != last_forwarding) {
     912                 :         58 :         bfd->flap_count++;
     913                 :         58 :         bfd_status_changed(bfd);
     914                 :            :     }
     915                 :      69276 :     return bfd->last_forwarding;
     916                 :            : }
     917                 :            : 
     918                 :            : /* Helpers. */
     919                 :            : static void
     920                 :      39992 : bfd_lookup_ip(const char *host_name, ovs_be32 def, ovs_be32 *addr)
     921                 :            : {
     922         [ -  + ]:      39992 :     if (host_name[0]) {
     923         [ #  # ]:          0 :         if (ip_parse(host_name, addr)) {
     924                 :          0 :             return;
     925                 :            :         }
     926         [ #  # ]:          0 :         VLOG_ERR_RL(&rl, "\"%s\" is not a valid IP address", host_name);
     927                 :            :     }
     928                 :      39992 :     *addr = def;
     929                 :            : }
     930                 :            : 
     931                 :            : static bool
     932                 :       5245 : bfd_in_poll(const struct bfd *bfd) OVS_REQUIRES(mutex)
     933                 :            : {
     934                 :       5245 :     return (bfd->flags & FLAG_POLL) != 0;
     935                 :            : }
     936                 :            : 
     937                 :            : static void
     938                 :        261 : bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex)
     939                 :            : {
     940 [ +  + ][ +  + ]:        261 :     if (bfd->state > STATE_DOWN && !bfd_in_poll(bfd)
     941         [ +  - ]:         19 :         && !(bfd->flags & FLAG_FINAL)) {
     942                 :         19 :         bfd->poll_min_tx = bfd->cfg_min_tx;
     943         [ +  + ]:         19 :         bfd->poll_min_rx = bfd->in_decay ? bfd->decay_min_rx : bfd->cfg_min_rx;
     944                 :         19 :         bfd->flags |= FLAG_POLL;
     945                 :         19 :         bfd->next_tx = 0;
     946         [ +  - ]:         19 :         VLOG_INFO_RL(&rl, "%s: Initiating poll sequence", bfd->name);
     947                 :            :     }
     948                 :        261 : }
     949                 :            : 
     950                 :            : static long long int
     951                 :      16428 : bfd_min_tx(const struct bfd *bfd) OVS_REQUIRES(mutex)
     952                 :            : {
     953                 :            :     /* RFC 5880 Section 6.8.3
     954                 :            :      * When bfd.SessionState is not Up, the system MUST set
     955                 :            :      * bfd.DesiredMinTxInterval to a value of not less than one second
     956                 :            :      * (1,000,000 microseconds).  This is intended to ensure that the
     957                 :            :      * bandwidth consumed by BFD sessions that are not Up is negligible,
     958                 :            :      * particularly in the case where a neighbor may not be running BFD. */
     959         [ +  + ]:      16428 :     return (bfd->state == STATE_UP ? bfd->min_tx : MAX(bfd->min_tx, 1000));
     960                 :            : }
     961                 :            : 
     962                 :            : static long long int
     963                 :      10723 : bfd_tx_interval(const struct bfd *bfd) OVS_REQUIRES(mutex)
     964                 :            : {
     965                 :      10723 :     long long int interval = bfd_min_tx(bfd);
     966                 :      10723 :     return MAX(interval, bfd->rmt_min_rx);
     967                 :            : }
     968                 :            : 
     969                 :            : static long long int
     970                 :       2138 : bfd_rx_interval(const struct bfd *bfd) OVS_REQUIRES(mutex)
     971                 :            : {
     972                 :       2138 :     return MAX(bfd->min_rx, bfd->rmt_min_tx);
     973                 :            : }
     974                 :            : 
     975                 :            : static void
     976                 :       5253 : bfd_set_next_tx(struct bfd *bfd) OVS_REQUIRES(mutex)
     977                 :            : {
     978                 :       5253 :     long long int interval = bfd_tx_interval(bfd);
     979                 :       5253 :     interval -= interval * random_range(26) / 100;
     980                 :       5253 :     bfd->next_tx = bfd->last_tx + interval;
     981                 :       5253 : }
     982                 :            : 
     983                 :            : static const char *
     984                 :       1126 : bfd_flag_str(enum flags flags)
     985                 :            : {
     986                 :       1126 :     struct ds ds = DS_EMPTY_INITIALIZER;
     987                 :            :     static char flag_str[128];
     988                 :            : 
     989         [ +  + ]:       1126 :     if (!flags) {
     990                 :       1055 :         return "none";
     991                 :            :     }
     992                 :            : 
     993         [ -  + ]:         71 :     if (flags & FLAG_MULTIPOINT) {
     994                 :          0 :         ds_put_cstr(&ds, "multipoint ");
     995                 :            :     }
     996                 :            : 
     997         [ -  + ]:         71 :     if (flags & FLAG_DEMAND) {
     998                 :          0 :         ds_put_cstr(&ds, "demand ");
     999                 :            :     }
    1000                 :            : 
    1001         [ -  + ]:         71 :     if (flags & FLAG_AUTH) {
    1002                 :          0 :         ds_put_cstr(&ds, "auth ");
    1003                 :            :     }
    1004                 :            : 
    1005         [ -  + ]:         71 :     if (flags & FLAG_CTL) {
    1006                 :          0 :         ds_put_cstr(&ds, "ctl ");
    1007                 :            :     }
    1008                 :            : 
    1009         [ +  + ]:         71 :     if (flags & FLAG_FINAL) {
    1010                 :         49 :         ds_put_cstr(&ds, "final ");
    1011                 :            :     }
    1012                 :            : 
    1013         [ +  + ]:         71 :     if (flags & FLAG_POLL) {
    1014                 :         22 :         ds_put_cstr(&ds, "poll ");
    1015                 :            :     }
    1016                 :            : 
    1017                 :            :     /* Do not copy the trailing whitespace. */
    1018                 :         71 :     ds_chomp(&ds, ' ');
    1019                 :         71 :     ovs_strlcpy(flag_str, ds_cstr(&ds), sizeof flag_str);
    1020                 :         71 :     ds_destroy(&ds);
    1021                 :       1126 :     return flag_str;
    1022                 :            : }
    1023                 :            : 
    1024                 :            : static const char *
    1025                 :      41634 : bfd_state_str(enum state state)
    1026                 :            : {
    1027   [ +  +  +  +  :      41634 :     switch (state) {
                      - ]
    1028                 :        195 :     case STATE_ADMIN_DOWN: return "admin_down";
    1029                 :      40362 :     case STATE_DOWN: return "down";
    1030                 :        179 :     case STATE_INIT: return "init";
    1031                 :        898 :     case STATE_UP: return "up";
    1032                 :          0 :     default: return "invalid";
    1033                 :            :     }
    1034                 :            : }
    1035                 :            : 
    1036                 :            : static const char *
    1037                 :      41634 : bfd_diag_str(enum diag diag) {
    1038   [ +  +  -  +  :      41634 :     switch (diag) {
          -  -  +  -  -  
                      - ]
    1039                 :      41285 :     case DIAG_NONE: return "No Diagnostic";
    1040                 :        320 :     case DIAG_EXPIRED: return "Control Detection Time Expired";
    1041                 :          0 :     case DIAG_ECHO_FAILED: return "Echo Function Failed";
    1042                 :         24 :     case DIAG_RMT_DOWN: return "Neighbor Signaled Session Down";
    1043                 :          0 :     case DIAG_FWD_RESET: return "Forwarding Plane Reset";
    1044                 :          0 :     case DIAG_PATH_DOWN: return "Path Down";
    1045                 :          5 :     case DIAG_CPATH_DOWN: return "Concatenated Path Down";
    1046                 :          0 :     case DIAG_ADMIN_DOWN: return "Administratively Down";
    1047                 :          0 :     case DIAG_RCPATH_DOWN: return "Reverse Concatenated Path Down";
    1048                 :          0 :     default: return "Invalid Diagnostic";
    1049                 :            :     }
    1050                 :            : };
    1051                 :            : 
    1052                 :            : static void
    1053                 :       6400 : log_msg(enum vlog_level level, const struct msg *p, const char *message,
    1054                 :            :         const struct bfd *bfd) OVS_REQUIRES(mutex)
    1055                 :            : {
    1056                 :       6400 :     struct ds ds = DS_EMPTY_INITIALIZER;
    1057                 :            : 
    1058         [ +  + ]:       6400 :     if (vlog_should_drop(&this_module, level, &rl)) {
    1059                 :       6324 :         return;
    1060                 :            :     }
    1061                 :            : 
    1062                 :        228 :     ds_put_format(&ds,
    1063                 :            :                   "%s: %s."
    1064                 :            :                   "\n\tvers:%"PRIu8" diag:\"%s\" state:%s mult:%"PRIu8
    1065                 :            :                   " length:%"PRIu8
    1066                 :            :                   "\n\tflags: %s"
    1067                 :            :                   "\n\tmy_disc:0x%"PRIx32" your_disc:0x%"PRIx32
    1068                 :            :                   "\n\tmin_tx:%"PRIu32"us (%"PRIu32"ms)"
    1069                 :            :                   "\n\tmin_rx:%"PRIu32"us (%"PRIu32"ms)"
    1070                 :            :                   "\n\tmin_rx_echo:%"PRIu32"us (%"PRIu32"ms)",
    1071                 :         76 :                   bfd->name, message, p->vers_diag >> VERS_SHIFT,
    1072                 :         76 :                   bfd_diag_str(p->vers_diag & DIAG_MASK),
    1073                 :         76 :                   bfd_state_str(p->flags & STATE_MASK),
    1074                 :        228 :                   p->mult, p->length, bfd_flag_str(p->flags & FLAGS_MASK),
    1075                 :            :                   ntohl(p->my_disc), ntohl(p->your_disc),
    1076                 :         76 :                   ntohl(p->min_tx), ntohl(p->min_tx) / 1000,
    1077                 :         76 :                   ntohl(p->min_rx), ntohl(p->min_rx) / 1000,
    1078                 :         76 :                   ntohl(p->min_rx_echo), ntohl(p->min_rx_echo) / 1000);
    1079                 :         76 :     bfd_put_details(&ds, bfd);
    1080         [ +  - ]:         76 :     VLOG(level, "%s", ds_cstr(&ds));
    1081                 :         76 :     ds_destroy(&ds);
    1082                 :            : }
    1083                 :            : 
    1084                 :            : static void
    1085                 :        318 : bfd_set_state(struct bfd *bfd, enum state state, enum diag diag)
    1086                 :            :     OVS_REQUIRES(mutex)
    1087                 :            : {
    1088         [ +  + ]:        318 :     if (bfd->cpath_down) {
    1089                 :          1 :         diag = DIAG_CPATH_DOWN;
    1090                 :            :     }
    1091                 :            : 
    1092 [ +  + ][ +  - ]:        318 :     if (bfd->state != state || bfd->diag != diag) {
    1093         [ +  + ]:        318 :         if (!VLOG_DROP_INFO(&rl)) {
    1094                 :        149 :             struct ds ds = DS_EMPTY_INITIALIZER;
    1095                 :            : 
    1096                 :        149 :             ds_put_format(&ds, "%s: BFD state change: %s->%s"
    1097                 :            :                           " \"%s\"->\"%s\".\n",
    1098                 :            :                           bfd->name, bfd_state_str(bfd->state),
    1099                 :            :                           bfd_state_str(state), bfd_diag_str(bfd->diag),
    1100                 :            :                           bfd_diag_str(diag));
    1101                 :        149 :             bfd_put_details(&ds, bfd);
    1102         [ +  - ]:        149 :             VLOG_INFO("%s", ds_cstr(&ds));
    1103                 :        149 :             ds_destroy(&ds);
    1104                 :            :         }
    1105                 :            : 
    1106                 :        318 :         bfd->state = state;
    1107                 :        318 :         bfd->diag = diag;
    1108                 :            : 
    1109         [ +  + ]:        318 :         if (bfd->state <= STATE_DOWN) {
    1110                 :        252 :             bfd->rmt_state = STATE_DOWN;
    1111                 :        252 :             bfd->rmt_diag = DIAG_NONE;
    1112                 :        252 :             bfd->rmt_min_rx = 1;
    1113                 :        252 :             bfd->rmt_flags = 0;
    1114                 :        252 :             bfd->rmt_disc = 0;
    1115                 :        252 :             bfd->rmt_min_tx = 0;
    1116                 :            :             /* Resets the min_rx if in_decay. */
    1117         [ +  + ]:        252 :             if (bfd->in_decay) {
    1118                 :          2 :                 bfd->min_rx = bfd->cfg_min_rx;
    1119                 :          2 :                 bfd->in_decay = false;
    1120                 :            :             }
    1121                 :            :         }
    1122                 :            :         /* Resets the decay when state changes to STATE_UP
    1123                 :            :          * and decay_min_rx is configured. */
    1124 [ +  + ][ +  + ]:        318 :         if (bfd->state == STATE_UP && bfd->decay_min_rx) {
    1125                 :          3 :             bfd_decay_update(bfd);
    1126                 :            :         }
    1127                 :            : 
    1128                 :        318 :         bfd_status_changed(bfd);
    1129                 :            :     }
    1130                 :        318 : }
    1131                 :            : 
    1132                 :            : static uint64_t
    1133                 :        553 : bfd_rx_packets(const struct bfd *bfd) OVS_REQUIRES(mutex)
    1134                 :            : {
    1135                 :            :     struct netdev_stats stats;
    1136                 :            : 
    1137         [ +  - ]:        553 :     if (!netdev_get_stats(bfd->netdev, &stats)) {
    1138                 :        553 :         return stats.rx_packets;
    1139                 :            :     } else {
    1140                 :        553 :         return 0;
    1141                 :            :     }
    1142                 :            : }
    1143                 :            : 
    1144                 :            : /* Decays the bfd->min_rx to bfd->decay_min_rx when 'diff' is less than
    1145                 :            :  * the 'expect' value. */
    1146                 :            : static void
    1147                 :         38 : bfd_try_decay(struct bfd *bfd) OVS_REQUIRES(mutex)
    1148                 :            : {
    1149                 :            :     int64_t diff, expect;
    1150                 :            : 
    1151                 :            :     /* The 'diff' is the difference between current interface rx_packets
    1152                 :            :      * stats and last-time check.  The 'expect' is the recorded number of
    1153                 :            :      * bfd control packets received within an approximately decay_min_rx
    1154                 :            :      * (2000 ms if decay_min_rx is less than 2000 ms) interval.
    1155                 :            :      *
    1156                 :            :      * Since the update of rx_packets stats at interface happens
    1157                 :            :      * asynchronously to the bfd_rx_packets() function, the 'diff' value
    1158                 :            :      * can be jittered.  Thusly, we double the decay_rx_ctl to provide
    1159                 :            :      * more wiggle room. */
    1160                 :         38 :     diff = bfd_rx_packets(bfd) - bfd->decay_rx_packets;
    1161                 :         38 :     expect = 2 * MAX(bfd->decay_rx_ctl, 1);
    1162                 :         38 :     bfd->in_decay = diff <= expect ? true : false;
    1163                 :         38 :     bfd_decay_update(bfd);
    1164                 :         38 : }
    1165                 :            : 
    1166                 :            : /* Updates the rx_packets, decay_rx_ctl and decay_detect_time. */
    1167                 :            : static void
    1168                 :        281 : bfd_decay_update(struct bfd * bfd) OVS_REQUIRES(mutex)
    1169                 :            : {
    1170                 :        281 :     bfd->decay_rx_packets = bfd_rx_packets(bfd);
    1171                 :        281 :     bfd->decay_rx_ctl = 0;
    1172                 :        281 :     bfd->decay_detect_time = MAX(bfd->decay_min_rx, 2000) + time_msec();
    1173                 :        281 : }
    1174                 :            : 
    1175                 :            : /* Records the status change and changes the global connectivity seq. */
    1176                 :            : static void
    1177                 :        910 : bfd_status_changed(struct bfd *bfd) OVS_REQUIRES(mutex)
    1178                 :            : {
    1179                 :        910 :     seq_change(connectivity_seq_get());
    1180                 :        910 :     bfd->status_changed = true;
    1181                 :        910 : }
    1182                 :            : 
    1183                 :            : static void
    1184                 :        487 : bfd_forwarding_if_rx_update(struct bfd *bfd) OVS_REQUIRES(mutex)
    1185                 :            : {
    1186                 :        487 :     int64_t incr = bfd_rx_interval(bfd) * bfd->mult;
    1187                 :        487 :     bfd->forwarding_if_rx_detect_time = MAX(incr, 2000) + time_msec();
    1188                 :        487 : }
    1189                 :            : 
    1190                 :            : static uint32_t
    1191                 :        234 : generate_discriminator(void)
    1192                 :            : {
    1193                 :        234 :     uint32_t disc = 0;
    1194                 :            : 
    1195                 :            :     /* RFC 5880 Section 6.8.1
    1196                 :            :      * It SHOULD be set to a random (but still unique) value to improve
    1197                 :            :      * security.  The value is otherwise outside the scope of this
    1198                 :            :      * specification. */
    1199                 :            : 
    1200         [ +  + ]:        468 :     while (!disc) {
    1201                 :            :         struct bfd *bfd;
    1202                 :            : 
    1203                 :            :         /* 'disc' is by definition random, so there's no reason to waste time
    1204                 :            :          * hashing it. */
    1205                 :        234 :         disc = random_uint32();
    1206 [ +  + ][ -  + ]:        522 :         HMAP_FOR_EACH_IN_BUCKET (bfd, node, disc, all_bfds) {
    1207         [ -  + ]:        288 :             if (bfd->disc == disc) {
    1208                 :          0 :                 disc = 0;
    1209                 :          0 :                 break;
    1210                 :            :             }
    1211                 :            :         }
    1212                 :            :     }
    1213                 :            : 
    1214                 :        234 :     return disc;
    1215                 :            : }
    1216                 :            : 
    1217                 :            : static struct bfd *
    1218                 :        300 : bfd_find_by_name(const char *name) OVS_REQUIRES(mutex)
    1219                 :            : {
    1220                 :            :     struct bfd *bfd;
    1221                 :            : 
    1222 [ +  + ][ -  + ]:        383 :     HMAP_FOR_EACH (bfd, node, all_bfds) {
    1223         [ +  + ]:        381 :         if (!strcmp(bfd->name, name)) {
    1224                 :        298 :             return bfd;
    1225                 :            :         }
    1226                 :            :     }
    1227                 :          2 :     return NULL;
    1228                 :            : }
    1229                 :            : 
    1230                 :            : static void
    1231                 :        525 : bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex)
    1232                 :            : {
    1233         [ +  + ]:        525 :     ds_put_format(ds, "\tForwarding: %s\n",
    1234                 :        525 :                   bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
    1235                 :            :                   ? "true" : "false");
    1236                 :        525 :     ds_put_format(ds, "\tDetect Multiplier: %d\n", bfd->mult);
    1237         [ +  + ]:        525 :     ds_put_format(ds, "\tConcatenated Path Down: %s\n",
    1238                 :        525 :                   bfd->cpath_down ? "true" : "false");
    1239                 :        525 :     ds_put_format(ds, "\tTX Interval: Approx %lldms\n", bfd_tx_interval(bfd));
    1240                 :        525 :     ds_put_format(ds, "\tRX Interval: Approx %lldms\n", bfd_rx_interval(bfd));
    1241                 :        525 :     ds_put_format(ds, "\tDetect Time: now %+lldms\n",
    1242                 :        525 :                   time_msec() - bfd->detect_time);
    1243                 :        525 :     ds_put_format(ds, "\tNext TX Time: now %+lldms\n",
    1244                 :        525 :                   time_msec() - bfd->next_tx);
    1245                 :        525 :     ds_put_format(ds, "\tLast TX Time: now %+lldms\n",
    1246                 :        525 :                   time_msec() - bfd->last_tx);
    1247                 :            : 
    1248                 :        525 :     ds_put_cstr(ds, "\n");
    1249                 :            : 
    1250                 :        525 :     ds_put_format(ds, "\tLocal Flags: %s\n", bfd_flag_str(bfd->flags));
    1251                 :        525 :     ds_put_format(ds, "\tLocal Session State: %s\n",
    1252                 :            :                   bfd_state_str(bfd->state));
    1253                 :        525 :     ds_put_format(ds, "\tLocal Diagnostic: %s\n", bfd_diag_str(bfd->diag));
    1254                 :        525 :     ds_put_format(ds, "\tLocal Discriminator: 0x%"PRIx32"\n", bfd->disc);
    1255                 :        525 :     ds_put_format(ds, "\tLocal Minimum TX Interval: %lldms\n",
    1256                 :            :                   bfd_min_tx(bfd));
    1257                 :        525 :     ds_put_format(ds, "\tLocal Minimum RX Interval: %lldms\n", bfd->min_rx);
    1258                 :            : 
    1259                 :        525 :     ds_put_cstr(ds, "\n");
    1260                 :            : 
    1261                 :        525 :     ds_put_format(ds, "\tRemote Flags: %s\n", bfd_flag_str(bfd->rmt_flags));
    1262                 :        525 :     ds_put_format(ds, "\tRemote Session State: %s\n",
    1263                 :            :                   bfd_state_str(bfd->rmt_state));
    1264                 :        525 :     ds_put_format(ds, "\tRemote Diagnostic: %s\n",
    1265                 :            :                   bfd_diag_str(bfd->rmt_diag));
    1266                 :        525 :     ds_put_format(ds, "\tRemote Discriminator: 0x%"PRIx32"\n", bfd->rmt_disc);
    1267                 :        525 :     ds_put_format(ds, "\tRemote Minimum TX Interval: %lldms\n",
    1268                 :            :                   bfd->rmt_min_tx);
    1269                 :        525 :     ds_put_format(ds, "\tRemote Minimum RX Interval: %lldms\n",
    1270                 :            :                   bfd->rmt_min_rx);
    1271                 :        525 : }
    1272                 :            : 
    1273                 :            : static void
    1274                 :        301 : bfd_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
    1275                 :            :                  void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
    1276                 :            : {
    1277                 :        301 :     struct ds ds = DS_EMPTY_INITIALIZER;
    1278                 :            :     struct bfd *bfd;
    1279                 :            : 
    1280                 :        301 :     ovs_mutex_lock(&mutex);
    1281         [ +  + ]:        301 :     if (argc > 1) {
    1282                 :        298 :         bfd = bfd_find_by_name(argv[1]);
    1283         [ +  + ]:        298 :         if (!bfd) {
    1284                 :          2 :             unixctl_command_reply_error(conn, "no such bfd object");
    1285                 :          2 :             goto out;
    1286                 :            :         }
    1287                 :        296 :         bfd_put_details(&ds, bfd);
    1288                 :            :     } else {
    1289 [ +  + ][ -  + ]:          7 :         HMAP_FOR_EACH (bfd, node, all_bfds) {
    1290                 :          4 :             ds_put_format(&ds, "---- %s ----\n", bfd->name);
    1291                 :          4 :             bfd_put_details(&ds, bfd);
    1292                 :            :         }
    1293                 :            :     }
    1294                 :        299 :     unixctl_command_reply(conn, ds_cstr(&ds));
    1295                 :        299 :     ds_destroy(&ds);
    1296                 :            : 
    1297                 :            : out:
    1298                 :        301 :     ovs_mutex_unlock(&mutex);
    1299                 :        301 : }
    1300                 :            : 
    1301                 :            : 
    1302                 :            : static void
    1303                 :          2 : bfd_unixctl_set_forwarding_override(struct unixctl_conn *conn, int argc,
    1304                 :            :                                     const char *argv[], void *aux OVS_UNUSED)
    1305                 :            :     OVS_EXCLUDED(mutex)
    1306                 :            : {
    1307                 :          2 :     const char *forward_str = argv[argc - 1];
    1308                 :            :     int forwarding_override;
    1309                 :            :     struct bfd *bfd;
    1310                 :            : 
    1311                 :          2 :     ovs_mutex_lock(&mutex);
    1312         [ +  + ]:          2 :     if (!strcasecmp("true", forward_str)) {
    1313                 :          1 :         forwarding_override = 1;
    1314         [ -  + ]:          1 :     } else if (!strcasecmp("false", forward_str)) {
    1315                 :          0 :         forwarding_override = 0;
    1316         [ +  - ]:          1 :     } else if (!strcasecmp("normal", forward_str)) {
    1317                 :          1 :         forwarding_override = -1;
    1318                 :            :     } else {
    1319                 :          0 :         unixctl_command_reply_error(conn, "unknown fault string");
    1320                 :          0 :         goto out;
    1321                 :            :     }
    1322                 :            : 
    1323         [ +  - ]:          2 :     if (argc > 2) {
    1324                 :          2 :         bfd = bfd_find_by_name(argv[1]);
    1325         [ -  + ]:          2 :         if (!bfd) {
    1326                 :          0 :             unixctl_command_reply_error(conn, "no such BFD object");
    1327                 :          0 :             goto out;
    1328                 :            :         }
    1329                 :          2 :         bfd->forwarding_override = forwarding_override;
    1330                 :          2 :         bfd_status_changed(bfd);
    1331                 :            :     } else {
    1332 [ #  # ][ #  # ]:          0 :         HMAP_FOR_EACH (bfd, node, all_bfds) {
    1333                 :          0 :             bfd->forwarding_override = forwarding_override;
    1334                 :          0 :             bfd_status_changed(bfd);
    1335                 :            :         }
    1336                 :            :     }
    1337                 :            : 
    1338                 :          2 :     unixctl_command_reply(conn, "OK");
    1339                 :            : 
    1340                 :            : out:
    1341                 :          2 :     ovs_mutex_unlock(&mutex);
    1342                 :          2 : }

Generated by: LCOV version 1.12