LCOV - code coverage report
Current view: top level - lib/lldp - lldpd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 295 4.7 %
Date: 2016-09-14 01:02:56 Functions: 3 14 21.4 %
Branches: 1 282 0.4 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: c; c-file-style: "openbsd" -*- */
       2                 :            : /*
       3                 :            :  * Copyright (c) 2015 Nicira, Inc.
       4                 :            :  * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
       5                 :            :  *
       6                 :            :  * Permission to use, copy, modify, and/or distribute this software for any
       7                 :            :  * purpose with or without fee is hereby granted, provided that the above
       8                 :            :  * copyright notice and this permission notice appear in all copies.
       9                 :            :  *
      10                 :            :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11                 :            :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12                 :            :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13                 :            :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14                 :            :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15                 :            :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16                 :            :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17                 :            :  */
      18                 :            : 
      19                 :            : #include <config.h>
      20                 :            : #include "lldpd.h"
      21                 :            : #include <arpa/inet.h>
      22                 :            : #include <errno.h>
      23                 :            : #include <fcntl.h>
      24                 :            : #include <inttypes.h>
      25                 :            : #include <signal.h>
      26                 :            : #include <stdio.h>
      27                 :            : #include <sys/ioctl.h>
      28                 :            : #include <sys/socket.h>
      29                 :            : #include <sys/stat.h>
      30                 :            : #include <sys/time.h>
      31                 :            : #include <sys/types.h>
      32                 :            : #include <sys/wait.h>
      33                 :            : #include <unistd.h>
      34                 :            : #ifndef _WIN32
      35                 :            : #include <grp.h>
      36                 :            : #include <libgen.h>
      37                 :            : #include <pwd.h>
      38                 :            : #include <sys/select.h>
      39                 :            : #include <sys/utsname.h>
      40                 :            : #endif
      41                 :            : #include "compiler.h"
      42                 :            : #include "openvswitch/list.h"
      43                 :            : #include "packets.h"
      44                 :            : #include "timeval.h"
      45                 :            : 
      46                 :       2462 : VLOG_DEFINE_THIS_MODULE(lldpd);
      47                 :            : 
      48                 :            : static struct protocol protos[] =
      49                 :            : {
      50                 :            :     { LLDPD_MODE_LLDP, 1, "LLDP", 'l', lldp_send, lldp_decode, NULL,
      51                 :            :       LLDP_MULTICAST_ADDR },
      52                 :            :     { 0, 0, "any", ' ', NULL, NULL, NULL,
      53                 :            :       { { { 0,0,0,0,0,0 } } } }
      54                 :            : };
      55                 :            : 
      56                 :          1 : void lldpd_assign_cfg_to_protocols(struct lldpd *cfg)
      57                 :            : {
      58                 :          1 :     cfg->g_protocols = protos;
      59                 :          1 : }
      60                 :            : 
      61                 :            : struct lldpd_hardware *
      62                 :          0 : lldpd_get_hardware(struct lldpd *cfg, char *name, int index,
      63                 :            :                    struct lldpd_ops *ops)
      64                 :            : {
      65                 :            :     struct lldpd_hardware *hw;
      66                 :            : 
      67         [ #  # ]:          0 :     LIST_FOR_EACH (hw, h_entries, &cfg->g_hardware) {
      68 [ #  # ][ #  # ]:          0 :         if (!strcmp(hw->h_ifname, name) && hw->h_ifindex == index
      69 [ #  # ][ #  # ]:          0 :             && (!ops || ops == hw->h_ops)) {
      70                 :          0 :             return hw;
      71                 :            :         }
      72                 :            :     }
      73                 :            : 
      74                 :          0 :     return NULL;
      75                 :            : }
      76                 :            : 
      77                 :            : struct lldpd_hardware *
      78                 :          1 : lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index)
      79                 :            : {
      80                 :            :     struct lldpd_hardware *hw;
      81                 :            : 
      82         [ -  + ]:          1 :     VLOG_DBG("allocate a new local hardware interface (%s)", name);
      83                 :            : 
      84                 :          1 :     hw = xzalloc(sizeof *hw);
      85                 :          1 :     hw->h_cfg = cfg;
      86                 :          1 :     ovs_strlcpy(hw->h_ifname, name, sizeof hw->h_ifname);
      87                 :          1 :     hw->h_ifindex = index;
      88                 :          1 :     hw->h_lport.p_chassis = CONTAINER_OF(ovs_list_front(&cfg->g_chassis),
      89                 :            :                                          struct lldpd_chassis, list);
      90                 :          1 :     hw->h_lport.p_chassis->c_refcount++;
      91                 :          1 :     ovs_list_init(&hw->h_rports);
      92                 :            : 
      93                 :          1 :     return hw;
      94                 :            : }
      95                 :            : 
      96                 :            : struct lldpd_mgmt *
      97                 :          0 : lldpd_alloc_mgmt(int family, void *addrptr, size_t addrsize, u_int32_t iface)
      98                 :            : {
      99                 :            :     struct lldpd_mgmt *mgmt;
     100                 :            : 
     101         [ #  # ]:          0 :     VLOG_DBG("allocate a new management address (family: %d)", family);
     102                 :            : 
     103 [ #  # ][ #  # ]:          0 :     if (family <= LLDPD_AF_UNSPEC || family >= LLDPD_AF_LAST) {
     104                 :          0 :         errno = EAFNOSUPPORT;
     105                 :          0 :         return NULL;
     106                 :            :     }
     107         [ #  # ]:          0 :     if (addrsize > LLDPD_MGMT_MAXADDRSIZE) {
     108                 :          0 :         errno = EOVERFLOW;
     109                 :          0 :         return NULL;
     110                 :            :     }
     111                 :          0 :     mgmt = xzalloc(sizeof *mgmt);
     112                 :          0 :     mgmt->m_family = family;
     113                 :          0 :     memcpy(&mgmt->m_addr, addrptr, addrsize);
     114                 :          0 :     mgmt->m_addrsize = addrsize;
     115                 :          0 :     mgmt->m_iface = iface;
     116                 :            : 
     117                 :          0 :     return mgmt;
     118                 :            : }
     119                 :            : 
     120                 :            : void
     121                 :          0 : lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
     122                 :            : {
     123         [ #  # ]:          0 :     VLOG_DBG("cleanup hardware port %s", hardware->h_ifname);
     124                 :            : 
     125                 :          0 :     lldpd_port_cleanup(&hardware->h_lport, true);
     126 [ #  # ][ #  # ]:          0 :     if (hardware->h_ops && hardware->h_ops->cleanup) {
     127                 :          0 :         hardware->h_ops->cleanup(cfg, hardware);
     128                 :            :     }
     129                 :          0 :     free(hardware);
     130                 :          0 : }
     131                 :            : 
     132                 :            : void
     133                 :          0 : lldpd_cleanup(struct lldpd *cfg)
     134                 :            : {
     135                 :            :     struct lldpd_hardware *hw, *hw_next;
     136                 :            :     struct lldpd_chassis *chassis, *chassis_next;
     137                 :            : 
     138         [ #  # ]:          0 :     VLOG_DBG("cleanup all ports");
     139                 :            : 
     140 [ #  # ][ #  # ]:          0 :     LIST_FOR_EACH_SAFE (hw, hw_next, h_entries, &cfg->g_hardware) {
     141         [ #  # ]:          0 :         if (!hw->h_flags) {
     142                 :          0 :             ovs_list_remove(&hw->h_entries);
     143                 :          0 :             lldpd_remote_cleanup(hw, NULL, true);
     144                 :          0 :             lldpd_hardware_cleanup(cfg, hw);
     145                 :            :         } else {
     146                 :          0 :             lldpd_remote_cleanup(hw, NULL, false);
     147                 :            :         }
     148                 :            :     }
     149                 :            : 
     150         [ #  # ]:          0 :     VLOG_DBG("cleanup all chassis");
     151                 :            : 
     152 [ #  # ][ #  # ]:          0 :     LIST_FOR_EACH_SAFE (chassis, chassis_next, list, &cfg->g_chassis) {
     153         [ #  # ]:          0 :         if (chassis->c_refcount == 0) {
     154                 :          0 :             ovs_list_remove(&chassis->list);
     155                 :          0 :             lldpd_chassis_cleanup(chassis, 1);
     156                 :            :         }
     157                 :            :     }
     158                 :          0 : }
     159                 :            : 
     160                 :            : /* Update chassis `ochassis' with values from `chassis'. The later one is not
     161                 :            :  * expected to be part of a list! It will also be wiped from memory.
     162                 :            :  */
     163                 :            : static void
     164                 :          0 : lldpd_move_chassis(struct lldpd_chassis *ochassis,
     165                 :            :     struct lldpd_chassis *chassis)
     166                 :            : {
     167                 :            :     struct lldpd_mgmt *mgmt;
     168                 :          0 :     int refcount = ochassis->c_refcount;
     169                 :          0 :     int index = ochassis->c_index;
     170                 :            :     struct ovs_list listcopy;
     171                 :            : 
     172                 :            :     /* We want to keep refcount, index and list stuff from the current chassis
     173                 :            :      */
     174                 :          0 :     memcpy(&listcopy, &ochassis->list, sizeof listcopy);
     175                 :          0 :     lldpd_chassis_cleanup(ochassis, 0);
     176                 :            : 
     177                 :            :     /* Make the copy. */
     178                 :            :     /* WARNING: this is a kludgy hack, we need in-place copy and cannot use
     179                 :            :      * marshaling.
     180                 :            :      */
     181                 :          0 :     memcpy(ochassis, chassis, sizeof *ochassis);
     182                 :          0 :     ovs_list_init(&ochassis->c_mgmt);
     183                 :            : 
     184                 :            :     /* Copy of management addresses */
     185         [ #  # ]:          0 :     LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) {
     186                 :          0 :         ovs_list_insert(&ochassis->c_mgmt, &mgmt->m_entries);
     187                 :            :     }
     188                 :            : 
     189                 :            :     /* Restore saved values */
     190                 :          0 :     ochassis->c_refcount = refcount;
     191                 :          0 :     ochassis->c_index = index;
     192                 :          0 :     memcpy(&ochassis->list, &listcopy, sizeof ochassis->list);
     193                 :            : 
     194                 :            :     /* Get rid of the new chassis */
     195                 :          0 :     free(chassis);
     196                 :          0 : }
     197                 :            : 
     198                 :            : static int
     199                 :          0 : lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
     200                 :            : {
     201                 :            :     int i;
     202                 :            : 
     203         [ #  # ]:          0 :     if (s < ETH_ADDR_LEN) {
     204                 :          0 :         return -1;
     205                 :            :     }
     206                 :            : 
     207         [ #  # ]:          0 :     for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
     208         [ #  # ]:          0 :         if (!cfg->g_protocols[i].enabled) {
     209                 :          0 :             continue;
     210                 :            :         }
     211         [ #  # ]:          0 :         if (cfg->g_protocols[i].guess == NULL) {
     212         [ #  # ]:          0 :             if (memcmp(frame, &cfg->g_protocols[i].mac, ETH_ADDR_LEN) == 0) {
     213         [ #  # ]:          0 :                 VLOG_DBG("guessed protocol is %s (from MAC address)",
     214                 :            :                     cfg->g_protocols[i].name);
     215                 :          0 :                 return cfg->g_protocols[i].mode;
     216                 :            :             }
     217                 :            :         } else {
     218         [ #  # ]:          0 :             if (cfg->g_protocols[i].guess(frame, s)) {
     219         [ #  # ]:          0 :                 VLOG_DBG("guessed protocol is %s (from detector function)",
     220                 :            :                     cfg->g_protocols[i].name);
     221                 :          0 :                 return cfg->g_protocols[i].mode;
     222                 :            :             }
     223                 :            :         }
     224                 :            :     }
     225                 :            : 
     226                 :          0 :     return -1;
     227                 :            : }
     228                 :            : 
     229                 :            : static void
     230                 :          0 : lldpd_decode(struct lldpd *cfg, char *frame, int s,
     231                 :            :              struct lldpd_hardware *hw)
     232                 :            : {
     233                 :            :     size_t listsize, i;
     234                 :          0 :     struct lldpd_chassis *chassis, *ochassis = NULL;
     235                 :            :     struct lldpd_port *port, *oport;
     236                 :          0 :     int guess = LLDPD_MODE_LLDP;
     237                 :            :     struct eth_header eheader;
     238                 :          0 :     int count = 0;
     239                 :          0 :     bool found = false;
     240                 :            : 
     241         [ #  # ]:          0 :     VLOG_DBG("decode a received frame on %s size %d", hw->h_ifname,s);
     242                 :            : 
     243         [ #  # ]:          0 :     if (s < sizeof(struct eth_header) + 4) {
     244                 :            :         /* Too short, just discard it */
     245                 :          0 :         return;
     246                 :            :     }
     247                 :            : 
     248                 :            :     /* Decapsulate VLAN frames */
     249                 :          0 :     memcpy(&eheader, frame, sizeof eheader);
     250         [ #  # ]:          0 :     if (eheader.eth_type == htons(ETH_TYPE_VLAN)) {
     251                 :            :         /* VLAN decapsulation means to shift 4 bytes left the frame from
     252                 :            :          * offset 2 * ETH_ADDR_LEN
     253                 :            :          */
     254                 :          0 :         memmove(frame + 2 * ETH_ADDR_LEN, frame + 2 * ETH_ADDR_LEN + 4,
     255                 :          0 :                 s - 2 * ETH_ADDR_LEN);
     256                 :          0 :         s -= 4;
     257                 :            :     }
     258                 :            : 
     259         [ #  # ]:          0 :     LIST_FOR_EACH (oport, p_entries, &hw->h_rports) {
     260 [ #  # ][ #  # ]:          0 :         if (oport->p_lastframe &&
     261         [ #  # ]:          0 :             oport->p_lastframe->size == s &&
     262                 :          0 :             !memcmp(oport->p_lastframe->frame, frame, s)) {
     263                 :            :             /* Already received the same frame */
     264         [ #  # ]:          0 :             VLOG_DBG("duplicate frame, no need to decode");
     265                 :          0 :             oport->p_lastupdate = time_now();
     266                 :          0 :             return;
     267                 :            :         }
     268                 :            :     }
     269                 :            : 
     270                 :          0 :     guess = lldpd_guess_type(cfg, frame, s);
     271         [ #  # ]:          0 :     VLOG_DBG("guessed %d enabled:%d", guess, cfg->g_protocols[0].enabled);
     272                 :            : 
     273         [ #  # ]:          0 :     for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
     274         [ #  # ]:          0 :         if (!cfg->g_protocols[i].enabled) {
     275                 :          0 :             continue;
     276                 :            :         }
     277         [ #  # ]:          0 :         if (cfg->g_protocols[i].mode == guess) {
     278         [ #  # ]:          0 :             VLOG_DBG("using decode function for %s protocol",
     279                 :            :                 cfg->g_protocols[i].name);
     280         [ #  # ]:          0 :             if (cfg->g_protocols[i].decode(cfg, frame, s, hw, &chassis, &port)
     281                 :            :                     == -1) {
     282         [ #  # ]:          0 :                 VLOG_DBG("function for %s protocol did not "
     283                 :            :                          "decode this frame",
     284                 :            :                          cfg->g_protocols[i].name);
     285                 :          0 :                 return;
     286                 :            :             }
     287                 :          0 :             chassis->c_protocol = port->p_protocol = cfg->g_protocols[i].mode;
     288                 :          0 :             break;
     289                 :            :       }
     290         [ #  # ]:          0 :       VLOG_DBG(" %"PRIuSIZE "mode:%d enabled:%d",
     291                 :            :                i, cfg->g_protocols[i].mode, cfg->g_protocols[i].enabled);
     292                 :            :     }
     293         [ #  # ]:          0 :     if (cfg->g_protocols[i].mode == 0) {
     294         [ #  # ]:          0 :         VLOG_DBG("unable to guess frame type on %s", hw->h_ifname);
     295                 :          0 :         return;
     296                 :            :     }
     297                 :            : 
     298                 :            :     /* Do we already have the same MSAP somewhere? */
     299         [ #  # ]:          0 :     VLOG_DBG("search for the same MSAP");
     300                 :            : 
     301         [ #  # ]:          0 :     LIST_FOR_EACH (oport, p_entries, &hw->h_rports) {
     302         [ #  # ]:          0 :         if (port->p_protocol == oport->p_protocol) {
     303                 :          0 :             count++;
     304 [ #  # ][ #  # ]:          0 :             if (port->p_id_subtype == oport->p_id_subtype &&
     305         [ #  # ]:          0 :                 port->p_id_len == oport->p_id_len &&
     306         [ #  # ]:          0 :                 !memcmp(port->p_id, oport->p_id, port->p_id_len) &&
     307         [ #  # ]:          0 :                 chassis->c_id_subtype == oport->p_chassis->c_id_subtype &&
     308         [ #  # ]:          0 :                 chassis->c_id_len == oport->p_chassis->c_id_len &&
     309                 :          0 :                 !memcmp(chassis->c_id, oport->p_chassis->c_id,
     310                 :          0 :                         chassis->c_id_len)) {
     311                 :          0 :                 ochassis = oport->p_chassis;
     312         [ #  # ]:          0 :                 VLOG_DBG("MSAP is already known");
     313                 :          0 :                 found = true;
     314                 :          0 :                 break;
     315                 :            :             }
     316                 :            :         }
     317                 :            :     }
     318                 :            : 
     319         [ #  # ]:          0 :     if (!found) {
     320                 :          0 :        oport = NULL;
     321                 :            :     }
     322                 :            : 
     323                 :            :     /* Do we have room for a new MSAP? */
     324 [ #  # ][ #  # ]:          0 :     if (!oport && cfg->g_config.c_max_neighbors) {
     325         [ #  # ]:          0 :         if (count == (cfg->g_config.c_max_neighbors - 1)) {
     326         [ #  # ]:          0 :             VLOG_DBG("max neighbors %d reached for port %s, "
     327                 :            :                      "dropping any new ones silently",
     328                 :            :                      cfg->g_config.c_max_neighbors,
     329                 :            :                      hw->h_ifname);
     330         [ #  # ]:          0 :         } else if (count > cfg->g_config.c_max_neighbors - 1) {
     331         [ #  # ]:          0 :             VLOG_DBG("too many neighbors for port %s, drop this new one",
     332                 :            :                      hw->h_ifname);
     333                 :          0 :             lldpd_port_cleanup(port, true);
     334                 :          0 :             lldpd_chassis_cleanup(chassis, true);
     335                 :          0 :             free(port);
     336                 :          0 :             return;
     337                 :            :         }
     338                 :            :     }
     339                 :            : 
     340                 :            :     /* No, but do we already know the system? */
     341         [ #  # ]:          0 :     if (!oport) {
     342                 :          0 :         bool found = false;
     343         [ #  # ]:          0 :         VLOG_DBG("MSAP is unknown, search for the chassis");
     344                 :            : 
     345         [ #  # ]:          0 :         LIST_FOR_EACH (ochassis, list, &cfg->g_chassis) {
     346 [ #  # ][ #  # ]:          0 :                 if ((chassis->c_protocol == ochassis->c_protocol) &&
     347         [ #  # ]:          0 :                     (chassis->c_id_subtype == ochassis->c_id_subtype) &&
     348         [ #  # ]:          0 :                     (chassis->c_id_len == ochassis->c_id_len) &&
     349                 :          0 :                     (memcmp(chassis->c_id, ochassis->c_id,
     350                 :          0 :                     chassis->c_id_len) == 0)) {
     351                 :          0 :                     found = true;
     352                 :          0 :                     break;
     353                 :            :                 }
     354                 :            :         }
     355                 :            : 
     356         [ #  # ]:          0 :         if (!found) {
     357                 :          0 :             ochassis = NULL;
     358                 :            :         }
     359                 :            :     }
     360                 :            : 
     361         [ #  # ]:          0 :     if (oport) {
     362                 :            :         /* The port is known, remove it before adding it back */
     363                 :          0 :         ovs_list_remove(&oport->p_entries);
     364                 :          0 :         lldpd_port_cleanup(oport, 1);
     365                 :          0 :         free(oport);
     366                 :            :     }
     367                 :            : 
     368         [ #  # ]:          0 :     if (ochassis) {
     369                 :          0 :         lldpd_move_chassis(ochassis, chassis);
     370                 :          0 :         chassis = ochassis;
     371                 :            :     } else {
     372                 :            :         /* Chassis not known, add it */
     373         [ #  # ]:          0 :         VLOG_DBG("unknown chassis, add it to the list");
     374                 :          0 :         chassis->c_index = ++cfg->g_lastrid;
     375                 :          0 :         chassis->c_refcount = 0;
     376                 :          0 :         ovs_list_push_back(&cfg->g_chassis, &chassis->list);
     377                 :          0 :         listsize = ovs_list_size(&cfg->g_chassis);
     378         [ #  # ]:          0 :         VLOG_DBG("%"PRIuSIZE " different systems are known", listsize);
     379                 :            :     }
     380                 :            : 
     381                 :            :     /* Add port */
     382                 :          0 :     port->p_lastchange = port->p_lastupdate = time_now();
     383                 :          0 :     port->p_lastframe = xmalloc(s + sizeof(struct lldpd_frame));
     384                 :          0 :     port->p_lastframe->size = s;
     385                 :          0 :     memcpy(port->p_lastframe->frame, frame, s);
     386                 :          0 :     ovs_list_insert(&hw->h_rports, &port->p_entries);
     387                 :            : 
     388                 :          0 :     port->p_chassis = chassis;
     389                 :          0 :     port->p_chassis->c_refcount++;
     390                 :            :     /* Several cases are possible :
     391                 :            :      *   1. chassis is new, its refcount was 0. It is now attached
     392                 :            :      *      to this port, its refcount is 1.
     393                 :            :      *   2. chassis already exists and was attached to another
     394                 :            :      *      port, we increase its refcount accordingly.
     395                 :            :      *   3. chassis already exists and was attached to the same
     396                 :            :      *      port, its refcount was decreased with
     397                 :            :      *      lldpd_port_cleanup() and is now increased again.
     398                 :            :      *
     399                 :            :      * In all cases, if the port already existed, it has been
     400                 :            :      * freed with lldpd_port_cleanup() and therefore, the refcount
     401                 :            :      * of the chassis that was attached to it is decreased.
     402                 :            :      */
     403                 :          0 :     i = ovs_list_size(&hw->h_rports);
     404         [ #  # ]:          0 :     VLOG_DBG("%"PRIuSIZE " neighbors for %s", i, hw->h_ifname);
     405                 :            : 
     406         [ #  # ]:          0 :     if (!oport)  {
     407                 :          0 :         hw->h_insert_cnt++;
     408                 :            :     }
     409                 :            : 
     410                 :          0 :     return;
     411                 :            : }
     412                 :            : 
     413                 :            : static void
     414                 :          0 : lldpd_hide_ports(struct lldpd *cfg,
     415                 :            :                  struct lldpd_hardware *hw,
     416                 :            :                  int mask) {
     417                 :            :     struct lldpd_port *port;
     418                 :            :     int protocols[LLDPD_MODE_MAX + 1];
     419                 :            :     char buffer[256];
     420                 :          0 :     bool found = false;
     421                 :            :     int i, j, k;
     422                 :            :     unsigned int min;
     423                 :            : 
     424         [ #  # ]:          0 :     VLOG_DBG("apply smart filter for port %s", hw->h_ifname);
     425                 :            : 
     426                 :            :     /* Compute the number of occurrences of each protocol */
     427         [ #  # ]:          0 :     for (i = 0; i <= LLDPD_MODE_MAX; i++) {
     428                 :          0 :         protocols[i] = 0;
     429                 :            :     }
     430                 :            : 
     431         [ #  # ]:          0 :     LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
     432                 :          0 :         protocols[port->p_protocol]++;
     433                 :            :     }
     434                 :            : 
     435                 :            :     /* Turn the protocols[] array into an array of
     436                 :            :      * enabled/disabled protocols. 1 means enabled, 0
     437                 :            :      * means disabled.
     438                 :            :      */
     439                 :          0 :     min = (unsigned int) - 1;
     440         [ #  # ]:          0 :     for (i = 0; i <= LLDPD_MODE_MAX; i++) {
     441 [ #  # ][ #  # ]:          0 :         if (protocols[i] && (protocols[i] < min)) {
     442                 :          0 :             min = protocols[i];
     443                 :            :         }
     444                 :            :     }
     445         [ #  # ]:          0 :     for (i = 0; i <= LLDPD_MODE_MAX; i++) {
     446 [ #  # ][ #  # ]:          0 :         if (protocols[i] == min && !found) {
     447                 :            :             /* If we need a tie breaker, we take the first protocol only */
     448         [ #  # ]:          0 :             if (cfg->g_config.c_smart & mask &
     449                 :            :                 (SMART_OUTGOING_ONE_PROTO | SMART_INCOMING_ONE_PROTO)) {
     450                 :          0 :                 found = true;
     451                 :            :             }
     452                 :          0 :             protocols[i] = 1;
     453                 :            :         } else {
     454                 :          0 :             protocols[i] = 0;
     455                 :            :         }
     456                 :            :     }
     457                 :            : 
     458                 :            :     /* We set the p_hidden flag to 1 if the protocol is disabled */
     459         [ #  # ]:          0 :     LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
     460         [ #  # ]:          0 :         if (mask == SMART_OUTGOING) {
     461                 :          0 :             port->p_hidden_out = protocols[port->p_protocol] ? false : true;
     462                 :            :         } else {
     463                 :          0 :             port->p_hidden_in = protocols[port->p_protocol] ? false : true;
     464                 :            :         }
     465                 :            :     }
     466                 :            : 
     467                 :            :     /* If we want only one neighbor, we take the first one */
     468         [ #  # ]:          0 :     if (cfg->g_config.c_smart & mask &
     469                 :            :         (SMART_OUTGOING_ONE_NEIGH | SMART_INCOMING_ONE_NEIGH)) {
     470                 :          0 :         found = false;
     471                 :            : 
     472         [ #  # ]:          0 :         LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
     473         [ #  # ]:          0 :             if (mask == SMART_OUTGOING) {
     474         [ #  # ]:          0 :                 if (found) {
     475                 :          0 :                     port->p_hidden_out = true;
     476                 :            :                 }
     477         [ #  # ]:          0 :                 if (!port->p_hidden_out) {
     478                 :          0 :                     found = true;
     479                 :            :                 }
     480                 :            :             }
     481         [ #  # ]:          0 :             if (mask == SMART_INCOMING) {
     482         [ #  # ]:          0 :                 if (found) {
     483                 :          0 :                     port->p_hidden_in = true;
     484                 :            :                 }
     485         [ #  # ]:          0 :                 if (!port->p_hidden_in) {
     486                 :          0 :                     found = true;
     487                 :            :                 }
     488                 :            :             }
     489                 :            :         }
     490                 :            :     }
     491                 :            : 
     492                 :            :     /* Print a debug message summarizing the operation */
     493         [ #  # ]:          0 :     for (i = 0; i <= LLDPD_MODE_MAX; i++) {
     494                 :          0 :         protocols[i] = 0;
     495                 :            :     }
     496                 :            : 
     497                 :          0 :     k = j = 0;
     498         [ #  # ]:          0 :     LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
     499 [ #  # ][ #  # ]:          0 :         if (!((mask == SMART_OUTGOING && port->p_hidden_out) ||
                 [ #  # ]
     500         [ #  # ]:          0 :               (mask == SMART_INCOMING && port->p_hidden_in))) {
     501                 :          0 :             k++;
     502                 :          0 :             protocols[port->p_protocol] = 1;
     503                 :            :         }
     504                 :          0 :         j++;
     505                 :            :     }
     506                 :            : 
     507                 :          0 :     buffer[0] = '\0';
     508         [ #  # ]:          0 :     for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
     509 [ #  # ][ #  # ]:          0 :         if (cfg->g_protocols[i].enabled &&
     510                 :          0 :             protocols[cfg->g_protocols[i].mode]) {
     511         [ #  # ]:          0 :             if (strlen(buffer) +
     512                 :          0 :                 strlen(cfg->g_protocols[i].name) + 3 > sizeof(buffer)) {
     513                 :            :                 /* Unlikely, our buffer is too small */
     514                 :          0 :                 memcpy(buffer + sizeof(buffer) - 4, "...", 4);
     515                 :          0 :                 break;
     516                 :            :             }
     517         [ #  # ]:          0 :             if (buffer[0]) {
     518                 :          0 :                 strncat(buffer, ", ", 2);
     519                 :          0 :                 strncat(buffer, cfg->g_protocols[i].name,
     520                 :          0 :                 strlen(cfg->g_protocols[i].name));
     521                 :            :             }
     522                 :            :         }
     523                 :            :     }
     524 [ #  # ][ #  # ]:          0 :     VLOG_DBG("%s: %s: %d visible neighbors (out of %d)",
     525                 :            :              hw->h_ifname,
     526                 :            :              (mask == SMART_OUTGOING) ? "out filter" : "in filter",
     527                 :            :              k, j);
     528 [ #  # ][ #  # ]:          0 :     VLOG_DBG("%s: protocols: %s",
     529                 :            :              hw->h_ifname, buffer[0] ? buffer : "(none)");
     530                 :          0 : }
     531                 :            : 
     532                 :            : /* Hide unwanted ports depending on smart mode set by the user */
     533                 :            : static void
     534                 :          0 : lldpd_hide_all(struct lldpd *cfg)
     535                 :            : {
     536                 :            :     struct lldpd_hardware *hw;
     537                 :            : 
     538         [ #  # ]:          0 :     if (!cfg->g_config.c_smart) {
     539                 :          0 :         return;
     540                 :            :     }
     541                 :            : 
     542         [ #  # ]:          0 :     VLOG_DBG("apply smart filter results on all ports");
     543                 :            : 
     544         [ #  # ]:          0 :     LIST_FOR_EACH (hw, h_entries, &cfg->g_hardware) {
     545         [ #  # ]:          0 :         if (cfg->g_config.c_smart & SMART_INCOMING_FILTER) {
     546                 :          0 :             lldpd_hide_ports(cfg, hw, SMART_INCOMING);
     547                 :            :         }
     548         [ #  # ]:          0 :         if (cfg->g_config.c_smart & SMART_OUTGOING_FILTER) {
     549                 :          0 :             lldpd_hide_ports(cfg, hw, SMART_OUTGOING);
     550                 :            :         }
     551                 :            :     }
     552                 :            : }
     553                 :            : 
     554                 :            : void
     555                 :          0 : lldpd_recv(struct lldpd *cfg,
     556                 :            :            struct lldpd_hardware *hw,
     557                 :            :            char *buffer,
     558                 :            :            size_t bufSize)
     559                 :            : {
     560                 :          0 :     int n = bufSize;
     561                 :            : 
     562         [ #  # ]:          0 :     VLOG_DBG("receive a frame on %s", hw->h_ifname);
     563         [ #  # ]:          0 :     if (cfg->g_config.c_paused) {
     564         [ #  # ]:          0 :         VLOG_DBG("paused, ignore the frame on %s", hw->h_ifname);
     565                 :          0 :         return;
     566                 :            :     }
     567                 :          0 :     hw->h_rx_cnt++;
     568         [ #  # ]:          0 :     VLOG_DBG("decode received frame on %s h_rx_cnt=%" PRIu64,
     569                 :            :              hw->h_ifname, hw->h_rx_cnt);
     570                 :          0 :     lldpd_decode(cfg, buffer, n, hw);
     571                 :          0 :     lldpd_hide_all(cfg); /* Immediatly hide */
     572                 :            : }
     573                 :            : 
     574                 :            : uint32_t
     575                 :          0 : lldpd_send(struct lldpd_hardware *hw, struct dp_packet *p)
     576                 :            : {
     577                 :          0 :     struct lldpd *cfg = hw->h_cfg;
     578                 :            :     struct lldpd_port *port;
     579                 :          0 :     int i, sent = 0;
     580                 :          0 :     int lldp_size = 0;
     581                 :            : 
     582 [ #  # ][ #  # ]:          0 :     if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) {
     583                 :          0 :         return 0;
     584                 :            :     }
     585                 :            : #ifndef _WIN32
     586         [ #  # ]:          0 :     if ((hw->h_flags & IFF_RUNNING) == 0) {
     587                 :          0 :         return 0;
     588                 :            :     }
     589                 :            : #endif
     590                 :            : 
     591         [ #  # ]:          0 :     for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
     592         [ #  # ]:          0 :         if (!cfg->g_protocols[i].enabled) {
     593                 :          0 :             continue;
     594                 :            :         }
     595                 :            : 
     596                 :            :         /* We send only if we have at least one remote system
     597                 :            :          * speaking this protocol or if the protocol is forced */
     598         [ #  # ]:          0 :         if (cfg->g_protocols[i].enabled > 1) {
     599         [ #  # ]:          0 :             if ((lldp_size = cfg->g_protocols[i].send(cfg, hw, p)) != -E2BIG) {
     600                 :          0 :                 sent++;
     601                 :          0 :                 continue;
     602                 :            :             } else {
     603         [ #  # ]:          0 :                 VLOG_DBG("send PDU on %s failed E2BIG", hw->h_ifname);
     604                 :          0 :                 continue;
     605                 :            :             }
     606                 :            :         }
     607                 :            : 
     608         [ #  # ]:          0 :         LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
     609                 :            :             /* If this remote port is disabled, we don't consider it */
     610         [ #  # ]:          0 :             if (port->p_hidden_out) {
     611                 :          0 :                 continue;
     612                 :            :             }
     613         [ #  # ]:          0 :             if (port->p_protocol == cfg->g_protocols[i].mode) {
     614         [ #  # ]:          0 :                 VLOG_DBG("send PDU on %s with protocol %s",
     615                 :            :                          hw->h_ifname, cfg->g_protocols[i].name);
     616                 :          0 :                 lldp_size = cfg->g_protocols[i].send(cfg, hw, p);
     617                 :          0 :                 sent++;
     618                 :          0 :                 break;
     619                 :            :             }
     620                 :            :         }
     621                 :            :     }
     622                 :            : 
     623         [ #  # ]:          0 :     if (!sent) {
     624                 :            :         /* Nothing was sent for this port, let's speak the first
     625                 :            :          * available protocol.
     626                 :            :          */
     627         [ #  # ]:          0 :         for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
     628         [ #  # ]:          0 :             if (!cfg->g_protocols[i].enabled) {
     629                 :          0 :                 continue;
     630                 :            :             }
     631         [ #  # ]:          0 :             VLOG_DBG("fallback to protocol %s for %s",
     632                 :            :                      cfg->g_protocols[i].name, hw->h_ifname);
     633                 :          0 :             lldp_size = cfg->g_protocols[i].send(cfg, hw, p);
     634                 :          0 :             break;
     635                 :            :         }
     636         [ #  # ]:          0 :         if (cfg->g_protocols[i].mode == 0) {
     637         [ #  # ]:          0 :             VLOG_WARN("no protocol enabled, dunno what to send");
     638                 :            :         }
     639                 :            :     }
     640                 :            : 
     641                 :          0 :     return lldp_size;
     642                 :            : }

Generated by: LCOV version 1.12