LCOV - code coverage report
Current view: top level - ofproto - ofproto-dpif-monitor.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 116 122 95.1 %
Date: 2016-09-14 01:02:56 Functions: 11 11 100.0 %
Branches: 61 76 80.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "ofproto-dpif-monitor.h"
      19                 :            : 
      20                 :            : #include <string.h>
      21                 :            : 
      22                 :            : #include "bfd.h"
      23                 :            : #include "cfm.h"
      24                 :            : #include "dp-packet.h"
      25                 :            : #include "guarded-list.h"
      26                 :            : #include "hash.h"
      27                 :            : #include "heap.h"
      28                 :            : #include "openvswitch/hmap.h"
      29                 :            : #include "latch.h"
      30                 :            : #include "openvswitch/ofpbuf.h"
      31                 :            : #include "ofproto-dpif.h"
      32                 :            : #include "ovs-lldp.h"
      33                 :            : #include "ovs-thread.h"
      34                 :            : #include "poll-loop.h"
      35                 :            : #include "seq.h"
      36                 :            : #include "timeval.h"
      37                 :            : #include "util.h"
      38                 :            : #include "openvswitch/vlog.h"
      39                 :            : 
      40                 :       1288 : VLOG_DEFINE_THIS_MODULE(ofproto_dpif_monitor);
      41                 :            : 
      42                 :            : /* Converts the time in millisecond to heap priority. */
      43                 :            : #define MSEC_TO_PRIO(TIME) (LLONG_MAX - (TIME))
      44                 :            : /* Converts the heap priority to time in millisecond. */
      45                 :            : #define PRIO_TO_MSEC(PRIO) (LLONG_MAX - (PRIO))
      46                 :            : 
      47                 :            : /* Monitored port.  It owns references to ofport, bfd, cfm, and lldp structs. */
      48                 :            : struct mport {
      49                 :            :     struct hmap_node hmap_node;       /* In monitor_hmap. */
      50                 :            :     struct heap_node heap_node;       /* In monitor_heap. */
      51                 :            :     const struct ofport_dpif *ofport; /* The corresponding ofport. */
      52                 :            : 
      53                 :            :     struct cfm *cfm;                  /* Reference to cfm. */
      54                 :            :     struct bfd *bfd;                  /* Reference to bfd. */
      55                 :            :     struct lldp *lldp;                /* Reference to lldp. */
      56                 :            :     struct eth_addr hw_addr;          /* Hardware address. */
      57                 :            : };
      58                 :            : 
      59                 :            : /* Entry of the 'send_soon' list.  Contains the pointer to the
      60                 :            :  * 'ofport_dpif'.  Note, the pointed object is not protected, so
      61                 :            :  * users should always use the mport_find() to convert it to 'mport'. */
      62                 :            : struct send_soon_entry {
      63                 :            :     struct ovs_list list_node;        /* In send_soon. */
      64                 :            :     const struct ofport_dpif *ofport;
      65                 :            : };
      66                 :            : 
      67                 :            : /* hmap that contains "struct mport"s. */
      68                 :            : static struct hmap monitor_hmap = HMAP_INITIALIZER(&monitor_hmap);
      69                 :            : 
      70                 :            : /* heap for ordering mport based on bfd/cfm wakeup time. */
      71                 :            : static struct heap monitor_heap;
      72                 :            : 
      73                 :            : /* guarded-list for storing the mports that need to send bfd/cfm control
      74                 :            :  * packet soon. */
      75                 :            : static struct guarded_list send_soon = GUARDED_OVS_LIST_INITIALIZER(&send_soon);
      76                 :            : 
      77                 :            : /* The monitor thread id. */
      78                 :            : static pthread_t monitor_tid;
      79                 :            : /* True if the monitor thread is running. */
      80                 :            : static bool monitor_running;
      81                 :            : 
      82                 :            : static struct latch monitor_exit_latch;
      83                 :            : static struct ovs_mutex monitor_mutex = OVS_MUTEX_INITIALIZER;
      84                 :            : 
      85                 :            : static void *monitor_main(void *);
      86                 :            : static void monitor_check_send_soon(struct dp_packet *);
      87                 :            : static void monitor_run(void);
      88                 :            : static void monitor_mport_run(struct mport *, struct dp_packet *);
      89                 :            : 
      90                 :            : static void mport_register(const struct ofport_dpif *, struct bfd *,
      91                 :            :                            struct cfm *, struct lldp *,
      92                 :            :                            const struct eth_addr *)
      93                 :            :     OVS_REQUIRES(monitor_mutex);
      94                 :            : static void mport_unregister(const struct ofport_dpif *)
      95                 :            :     OVS_REQUIRES(monitor_mutex);
      96                 :            : static void mport_update(struct mport *, struct bfd *, struct cfm *,
      97                 :            :                          struct lldp *, const struct eth_addr *)
      98                 :            :     OVS_REQUIRES(monitor_mutex);
      99                 :            : static struct mport *mport_find(const struct ofport_dpif *)
     100                 :            :     OVS_REQUIRES(monitor_mutex);
     101                 :            : 
     102                 :            : /* Tries finding and returning the 'mport' from the monitor_hmap.
     103                 :            :  * If there is no such 'mport', returns NULL. */
     104                 :            : static struct mport *
     105                 :     111721 : mport_find(const struct ofport_dpif *ofport) OVS_REQUIRES(monitor_mutex)
     106                 :            : {
     107                 :            :     struct mport *node;
     108                 :            : 
     109 [ +  + ][ -  + ]:     111721 :     HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_pointer(ofport, 0),
     110                 :            :                              &monitor_hmap) {
     111         [ +  - ]:      60739 :         if (node->ofport == ofport) {
     112                 :      60739 :             return node;
     113                 :            :         }
     114                 :            :     }
     115                 :      50982 :     return NULL;
     116                 :            : }
     117                 :            : 
     118                 :            : /* Creates a new mport and inserts it into monitor_hmap and monitor_heap,
     119                 :            :  * if it doesn't exist.  Otherwise, just updates its fields. */
     120                 :            : static void
     121                 :      60290 : mport_register(const struct ofport_dpif *ofport, struct bfd *bfd,
     122                 :            :                struct cfm *cfm, struct lldp *lldp,
     123                 :            :                const struct eth_addr *hw_addr)
     124                 :            :     OVS_REQUIRES(monitor_mutex)
     125                 :            : {
     126                 :      60290 :     struct mport *mport = mport_find(ofport);
     127                 :            : 
     128         [ +  + ]:      60290 :     if (!mport) {
     129                 :        247 :         mport = xzalloc(sizeof *mport);
     130                 :        247 :         mport->ofport = ofport;
     131                 :        247 :         hmap_insert(&monitor_hmap, &mport->hmap_node, hash_pointer(ofport, 0));
     132                 :        247 :         heap_insert(&monitor_heap, &mport->heap_node, 0);
     133                 :            :     }
     134                 :      60290 :     mport_update(mport, bfd, cfm, lldp, hw_addr);
     135                 :      60290 : }
     136                 :            : 
     137                 :            : /* Removes mport from monitor_hmap and monitor_heap and frees it. */
     138                 :            : static void
     139                 :      50982 : mport_unregister(const struct ofport_dpif *ofport)
     140                 :            :     OVS_REQUIRES(monitor_mutex)
     141                 :            : {
     142                 :      50982 :     struct mport *mport = mport_find(ofport);
     143                 :            : 
     144         [ +  + ]:      50982 :     if (mport) {
     145                 :        247 :         mport_update(mport, NULL, NULL, NULL, NULL);
     146                 :        247 :         hmap_remove(&monitor_hmap, &mport->hmap_node);
     147                 :        247 :         heap_remove(&monitor_heap, &mport->heap_node);
     148                 :        247 :         free(mport);
     149                 :            :     }
     150                 :      50982 : }
     151                 :            : 
     152                 :            : /* Updates the fields of an existing mport struct. */
     153                 :            : static void
     154                 :      60537 : mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm,
     155                 :            :              struct lldp *lldp, const struct eth_addr *hw_addr)
     156                 :            :     OVS_REQUIRES(monitor_mutex)
     157                 :            : {
     158         [ -  + ]:      60537 :     ovs_assert(mport);
     159                 :            : 
     160         [ +  + ]:      60537 :     if (mport->cfm != cfm) {
     161                 :         32 :         cfm_unref(mport->cfm);
     162                 :         32 :         mport->cfm = cfm_ref(cfm);
     163                 :            :     }
     164         [ +  + ]:      60537 :     if (mport->bfd != bfd) {
     165                 :        468 :         bfd_unref(mport->bfd);
     166                 :        468 :         mport->bfd = bfd_ref(bfd);
     167                 :            :     }
     168         [ -  + ]:      60537 :     if (mport->lldp != lldp) {
     169                 :          0 :         lldp_unref(mport->lldp);
     170                 :          0 :         mport->lldp = lldp_ref(lldp);
     171                 :            :     }
     172 [ +  + ][ +  + ]:      60537 :     if (hw_addr && !eth_addr_equals(mport->hw_addr, *hw_addr)) {
     173                 :        247 :         mport->hw_addr = *hw_addr;
     174                 :            :     }
     175                 :            :     /* If bfd/cfm/lldp is added or reconfigured, move the mport on top of the heap
     176                 :            :      * so that the monitor thread can run the mport next time it wakes up. */
     177 [ +  + ][ +  + ]:      60537 :     if (mport->bfd || mport->cfm || mport->lldp) {
                 [ -  + ]
     178                 :      60290 :         heap_change(&monitor_heap, &mport->heap_node, LLONG_MAX);
     179                 :            :     }
     180                 :      60537 : }
     181                 :            : 
     182                 :            : 
     183                 :            : /* The 'main' function for the monitor thread. */
     184                 :            : static void *
     185                 :         22 : monitor_main(void * args OVS_UNUSED)
     186                 :            : {
     187         [ +  - ]:         22 :     VLOG_INFO("monitor thread created");
     188         [ +  + ]:       9006 :     while (!latch_is_set(&monitor_exit_latch)) {
     189                 :       8984 :         monitor_run();
     190                 :       8984 :         latch_wait(&monitor_exit_latch);
     191                 :       8984 :         poll_block();
     192                 :            :     }
     193         [ +  - ]:         22 :     VLOG_INFO("monitor thread terminated");
     194                 :         22 :     return NULL;
     195                 :            : }
     196                 :            : 
     197                 :            : /* The monitor thread should wake up this often to ensure that newly added or
     198                 :            :  * reconfigured monitoring ports are run in a timely manner. */
     199                 :            : #define MONITOR_INTERVAL_MSEC 100
     200                 :            : 
     201                 :            : /* Checks the 'send_soon' list and the heap for mports that have timed
     202                 :            :  * out bfd/cfm sessions. */
     203                 :            : static void
     204                 :       8984 : monitor_run(void)
     205                 :            : {
     206                 :            :     uint32_t stub[512 / 4];
     207                 :            :     long long int prio_now;
     208                 :            :     struct dp_packet packet;
     209                 :            : 
     210                 :       8984 :     dp_packet_use_stub(&packet, stub, sizeof stub);
     211                 :       8984 :     ovs_mutex_lock(&monitor_mutex);
     212                 :            : 
     213                 :            :     /* The monitor_check_send_soon() needs to be run twice.  The first
     214                 :            :      * time is for preventing the same 'mport' from being processed twice
     215                 :            :      * (i.e. once from heap, the other from the 'send_soon' array).
     216                 :            :      * The second run is to cover the case when the control packet is sent
     217                 :            :      * via patch port and the other end needs to send back immediately. */
     218                 :       8984 :     monitor_check_send_soon(&packet);
     219                 :            : 
     220                 :       8984 :     prio_now = MSEC_TO_PRIO(time_msec());
     221                 :            :     /* Peeks the top of heap and checks if we should run this mport. */
     222         [ +  - ]:      35299 :     while (!heap_is_empty(&monitor_heap)
     223         [ +  + ]:      35299 :            && heap_max(&monitor_heap)->priority >= prio_now) {
     224                 :            :         struct mport *mport;
     225                 :            : 
     226                 :      26315 :         mport = CONTAINER_OF(heap_max(&monitor_heap), struct mport, heap_node);
     227                 :      26315 :         monitor_mport_run(mport, &packet);
     228                 :            :     }
     229                 :            : 
     230                 :       8984 :     monitor_check_send_soon(&packet);
     231                 :            : 
     232                 :            :     /* Waits on the earliest next wakeup time. */
     233         [ +  - ]:       8984 :     if (!heap_is_empty(&monitor_heap)) {
     234                 :            :         long long int next_timeout, next_mport_wakeup;
     235                 :            : 
     236                 :       8984 :         next_timeout = time_msec() + MONITOR_INTERVAL_MSEC;
     237                 :       8984 :         next_mport_wakeup = PRIO_TO_MSEC(heap_max(&monitor_heap)->priority);
     238                 :       8984 :         poll_timer_wait_until(MIN(next_timeout, next_mport_wakeup));
     239                 :            :     }
     240                 :       8984 :     ovs_mutex_unlock(&monitor_mutex);
     241                 :       8984 :     dp_packet_uninit(&packet);
     242                 :       8984 : }
     243                 :            : 
     244                 :            : /* Checks the 'send_soon' list for any mport that needs to send cfm/bfd
     245                 :            :  * control packet immediately, and calls monitor_mport_run(). */
     246                 :            : static void
     247                 :      17968 : monitor_check_send_soon(struct dp_packet *packet)
     248                 :            :     OVS_REQUIRES(monitor_mutex)
     249                 :            : {
     250         [ +  + ]:      18417 :     while (!guarded_list_is_empty(&send_soon)) {
     251                 :            :         struct send_soon_entry *entry;
     252                 :            :         struct mport *mport;
     253                 :            : 
     254                 :        449 :         entry = CONTAINER_OF(guarded_list_pop_front(&send_soon),
     255                 :            :                              struct send_soon_entry, list_node);
     256                 :        449 :         mport = mport_find(entry->ofport);
     257         [ +  - ]:        449 :         if (mport) {
     258                 :        449 :             monitor_mport_run(mport, packet);
     259                 :            :         }
     260                 :        449 :         free(entry);
     261                 :            :     }
     262                 :      17968 : }
     263                 :            : 
     264                 :            : /* Checks the sending of control packet on 'mport'.  Sends the control
     265                 :            :  * packet if needed.  Executes bfd and cfm periodic functions (run, wait)
     266                 :            :  * on 'mport'.  And changes the location of 'mport' in heap based on next
     267                 :            :  * timeout. */
     268                 :            : static void
     269                 :      26764 : monitor_mport_run(struct mport *mport, struct dp_packet *packet)
     270                 :            :     OVS_REQUIRES(monitor_mutex)
     271                 :            : {
     272                 :            :     long long int next_wake_time;
     273                 :      26764 :     long long int bfd_wake_time = LLONG_MAX;
     274                 :      26764 :     long long int cfm_wake_time = LLONG_MAX;
     275                 :      26764 :     long long int lldp_wake_time = LLONG_MAX;
     276                 :            : 
     277 [ +  + ][ +  + ]:      26764 :     if (mport->cfm && cfm_should_send_ccm(mport->cfm)) {
     278                 :       1234 :         dp_packet_clear(packet);
     279                 :       1234 :         cfm_compose_ccm(mport->cfm, packet, mport->hw_addr);
     280                 :       1234 :         ofproto_dpif_send_packet(mport->ofport, false, packet);
     281                 :            :     }
     282 [ +  + ][ +  + ]:      26764 :     if (mport->bfd && bfd_should_send_packet(mport->bfd)) {
     283                 :            :         bool oam;
     284                 :            : 
     285                 :       5198 :         dp_packet_clear(packet);
     286                 :       5198 :         bfd_put_packet(mport->bfd, packet, mport->hw_addr, &oam);
     287                 :       5198 :         ofproto_dpif_send_packet(mport->ofport, oam, packet);
     288                 :            :     }
     289 [ -  + ][ #  # ]:      26764 :     if (mport->lldp && lldp_should_send_packet(mport->lldp)) {
     290                 :          0 :         dp_packet_clear(packet);
     291                 :          0 :         lldp_put_packet(mport->lldp, packet, mport->hw_addr);
     292                 :          0 :         ofproto_dpif_send_packet(mport->ofport, false, packet);
     293                 :            :     }
     294                 :            : 
     295         [ +  + ]:      26764 :     if (mport->cfm) {
     296                 :       1388 :         cfm_run(mport->cfm);
     297                 :       1388 :         cfm_wake_time = cfm_wait(mport->cfm);
     298                 :            :     }
     299         [ +  + ]:      26764 :     if (mport->bfd) {
     300                 :      25410 :         bfd_run(mport->bfd);
     301                 :      25410 :         bfd_wake_time = bfd_wait(mport->bfd);
     302                 :            :     }
     303         [ -  + ]:      26764 :     if (mport->lldp) {
     304                 :          0 :         lldp_wake_time = lldp_wait(mport->lldp);
     305                 :            :     }
     306                 :            :     /* Computes the next wakeup time for this mport. */
     307                 :      26764 :     next_wake_time = MIN(bfd_wake_time,
     308                 :            :                          cfm_wake_time);
     309                 :      26764 :     next_wake_time = MIN(next_wake_time, lldp_wake_time);
     310                 :      26764 :     heap_change(&monitor_heap, &mport->heap_node,
     311                 :      26764 :                 MSEC_TO_PRIO(next_wake_time));
     312                 :      26764 : }
     313                 :            : 
     314                 :            : 
     315                 :            : /* Creates the mport in monitor module if either bfd or cfm
     316                 :            :  * is configured.  Otherwise, deletes the mport.
     317                 :            :  * Also checks whether the monitor thread should be started
     318                 :            :  * or terminated. */
     319                 :            : void
     320                 :     111272 : ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport,
     321                 :            :                                  struct bfd *bfd, struct cfm *cfm,
     322                 :            :                                  struct lldp *lldp,
     323                 :            :                                  const struct eth_addr *hw_addr)
     324                 :            : {
     325                 :     111272 :     ovs_mutex_lock(&monitor_mutex);
     326 [ +  + ][ +  + ]:     111272 :     if (!cfm && !bfd && !lldp) {
                 [ +  - ]
     327                 :      50982 :         mport_unregister(ofport);
     328                 :            :     } else {
     329                 :      60290 :         mport_register(ofport, bfd, cfm, lldp, hw_addr);
     330                 :            :     }
     331                 :     111272 :     ovs_mutex_unlock(&monitor_mutex);
     332                 :            : 
     333                 :            :     /* If the monitor thread is not running and the hmap
     334                 :            :      * is not empty, starts it.  If it is and the hmap is empty,
     335                 :            :      * terminates it. */
     336 [ +  + ][ +  + ]:     111272 :     if (!monitor_running && !hmap_is_empty(&monitor_hmap))  {
     337                 :         22 :         latch_init(&monitor_exit_latch);
     338                 :         22 :         monitor_tid = ovs_thread_create("monitor", monitor_main, NULL);
     339                 :         22 :         monitor_running = true;
     340 [ +  + ][ +  + ]:     111250 :     } else if (monitor_running && hmap_is_empty(&monitor_hmap))  {
     341                 :         22 :         latch_set(&monitor_exit_latch);
     342                 :         22 :         xpthread_join(monitor_tid, NULL);
     343                 :         22 :         latch_destroy(&monitor_exit_latch);
     344                 :         22 :         monitor_running = false;
     345                 :            :     }
     346                 :     111272 : }
     347                 :            : 
     348                 :            : /* Registers the 'ofport' in the 'send_soon' list.  We cannot directly
     349                 :            :  * insert the corresponding mport to the 'send_soon' list, since the
     350                 :            :  * 'send_soon' list is not updated when the mport is removed.
     351                 :            :  *
     352                 :            :  * Reader of the 'send_soon' list is responsible for freeing the entry. */
     353                 :            : void
     354                 :        449 : ofproto_dpif_monitor_port_send_soon(const struct ofport_dpif *ofport)
     355                 :            : {
     356                 :        449 :     struct send_soon_entry *entry = xzalloc(sizeof *entry);
     357                 :        449 :     entry->ofport = ofport;
     358                 :            : 
     359                 :        449 :     guarded_list_push_back(&send_soon, &entry->list_node, SIZE_MAX);
     360                 :        449 : }

Generated by: LCOV version 1.12