LCOV - code coverage report
Current view: top level - plugins/lldp - lldp_node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 23 93 24.7 %
Date: 2023-10-26 01:39:38 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2011-2016 Cisco and/or its affiliates.
       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             : /**
      16             :  * @file
      17             :  * @brief LLDP nodes implementation
      18             :  */
      19             : #include <lldp/lldp_node.h>
      20             : #include <vnet/ethernet/ethernet.h>
      21             : #include <vnet/ethernet/packet.h>
      22             : 
      23             : /* set this to 1 to turn on debug prints via clib_warning() */
      24             : #define LLDP_DEBUG (0)
      25             : 
      26             : static vlib_node_registration_t lldp_process_node;
      27             : 
      28             : #define F(sym, string) static char LLDP_ERR_##sym##_STR[] = string;
      29             : foreach_lldp_error (F);
      30             : #undef F
      31             : 
      32             : /*
      33             :  * packet counter strings
      34             :  * Dump these counters via the "show error" CLI command
      35             :  */
      36             : static char *lldp_error_strings[] = {
      37             : #define F(sym, string) LLDP_ERR_##sym##_STR,
      38             :   foreach_lldp_error (F)
      39             : #undef F
      40             : };
      41             : 
      42             : /*
      43             :  * We actually send all lldp pkts to the "error" node after scanning
      44             :  * them, so the graph node has only one next-index. The "error-drop"
      45             :  * node automatically bumps our per-node packet counters for us.
      46             :  */
      47             : typedef enum
      48             : {
      49             :   LLDP_INPUT_NEXT_NORMAL,
      50             :   LLDP_INPUT_N_NEXT,
      51             : } lldp_next_t;
      52             : 
      53             : /*
      54             :  * Process a frame of lldp packets
      55             :  * Expect 1 packet / frame
      56             :  */
      57             : static uword
      58           0 : lldp_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
      59             :               vlib_frame_t * frame)
      60             : {
      61             :   u32 n_left_from, *from;
      62             :   lldp_input_trace_t *t0;
      63             : 
      64           0 :   from = vlib_frame_vector_args (frame);        /* array of buffer indices */
      65           0 :   n_left_from = frame->n_vectors;    /* number of buffer indices */
      66             : 
      67           0 :   while (n_left_from > 0)
      68             :     {
      69             :       u32 bi0;
      70             :       vlib_buffer_t *b0;
      71             :       u32 next0, error0;
      72             : 
      73           0 :       bi0 = from[0];
      74           0 :       b0 = vlib_get_buffer (vm, bi0);
      75             : 
      76           0 :       next0 = LLDP_INPUT_NEXT_NORMAL;
      77             : 
      78             :       /* scan this lldp pkt. error0 is the counter index to bump */
      79           0 :       error0 = lldp_input (vm, b0, bi0);
      80           0 :       b0->error = node->errors[error0];
      81             : 
      82             :       /* If this pkt is traced, snapshot the data */
      83           0 :       if (b0->flags & VLIB_BUFFER_IS_TRACED)
      84             :         {
      85             :           int len;
      86           0 :           t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
      87           0 :           len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
      88           0 :             : sizeof (t0->data);
      89           0 :           t0->len = len;
      90           0 :           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0), len);
      91             :         }
      92             :       /* push this pkt to the next graph node, always error-drop */
      93           0 :       vlib_set_next_frame_buffer (vm, node, next0, bi0);
      94             : 
      95           0 :       from += 1;
      96           0 :       n_left_from -= 1;
      97             :     }
      98             : 
      99           0 :   return frame->n_vectors;
     100             : }
     101             : 
     102             : /*
     103             :  * lldp input graph node declaration
     104             :  */
     105             : /* *INDENT-OFF* */
     106       95066 : VLIB_REGISTER_NODE(lldp_input_node, static) = {
     107             :   .function = lldp_node_fn,
     108             :   .name = "lldp-input",
     109             :   .vector_size = sizeof(u32),
     110             :   .type = VLIB_NODE_TYPE_INTERNAL,
     111             : 
     112             :   .n_errors = LLDP_N_ERROR,
     113             :   .error_strings = lldp_error_strings,
     114             : 
     115             :   .format_trace = lldp_input_format_trace,
     116             : 
     117             :   .n_next_nodes = LLDP_INPUT_N_NEXT,
     118             :   .next_nodes =
     119             :       {
     120             :               [LLDP_INPUT_NEXT_NORMAL] = "error-drop",
     121             :       },
     122             : };
     123             : /* *INDENT-ON* */
     124             : 
     125             : /*
     126             :  * lldp process node function
     127             :  */
     128             : static uword
     129         575 : lldp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
     130             : {
     131         575 :   lldp_main_t *lm = &lldp_main;
     132         575 :   f64 timeout = 0;
     133         575 :   uword event_type, *event_data = 0;
     134             : 
     135             :   /* So we can send events to the lldp process */
     136         575 :   lm->lldp_process_node_index = lldp_process_node.index;
     137             : 
     138             :   /* with ethernet input */
     139         575 :   ethernet_register_input_type (vm, ETHERNET_TYPE_802_1_LLDP /* LLDP */ ,
     140             :                                 lldp_input_node.index);
     141             : 
     142             :   while (1)
     143           0 :     {
     144         575 :       if (vec_len (lm->intfs_timeouts))
     145             :         {
     146             : #if LLDP_DEBUG
     147             :           clib_warning ("DEBUG: wait for event with timeout %f", timeout);
     148             : #endif
     149           0 :           (void) vlib_process_wait_for_event_or_clock (vm, timeout);
     150             :         }
     151             :       else
     152             :         {
     153             : #if LLDP_DEBUG
     154             :           clib_warning ("DEBUG: wait for event without timeout");
     155             : #endif
     156         575 :           (void) vlib_process_wait_for_event (vm);
     157             :         }
     158           0 :       event_type = vlib_process_get_events (vm, &event_data);
     159           0 :       switch (event_type)
     160             :         {
     161           0 :         case ~0:                /* no events => timeout */
     162             :           /* nothing to do here */
     163           0 :           break;
     164           0 :         case LLDP_EVENT_RESCHEDULE:
     165             :           /* nothing to do here - reschedule is done automatically after
     166             :            * each event or timeout */
     167           0 :           break;
     168           0 :         default:
     169           0 :           clib_warning ("BUG: event type 0x%wx", event_type);
     170           0 :           break;
     171             :         }
     172           0 :       if (!vec_len (lm->intfs_timeouts))
     173             :         {
     174           0 :           continue;
     175             :         }
     176             :       /* send packet(s) and schedule another timeout */
     177           0 :       const f64 now = vlib_time_now (lm->vlib_main);
     178             :       while (1)
     179           0 :         {
     180           0 :           lldp_intf_t *n = pool_elt_at_index (lm->intfs,
     181             :                                               lm->intfs_timeouts
     182             :                                               [lm->intfs_timeouts_idx]);
     183           0 :           if (n->last_sent < 0.01 || now > n->last_sent + lm->msg_tx_interval)
     184             :             {
     185             : #if LLDP_DEBUG
     186             :               clib_warning ("send packet to lldp %p, if idx %d", n,
     187             :                             n->hw_if_index);
     188             : #endif
     189           0 :               lldp_send_ethernet (lm, n, 0);
     190           0 :               ++lm->intfs_timeouts_idx;
     191           0 :               if (lm->intfs_timeouts_idx >= vec_len (lm->intfs_timeouts))
     192             :                 {
     193           0 :                   lm->intfs_timeouts_idx = 0;
     194             :                 }
     195           0 :               continue;
     196             :             }
     197             :           else
     198             :             {
     199           0 :               timeout = n->last_sent + lm->msg_tx_interval - now;
     200           0 :               break;
     201             :             }
     202             :         }
     203             : #if LLDP_DEBUG
     204             :       clib_warning ("DEBUG: timeout set to %f", timeout);
     205             :       u8 *s = NULL;
     206             :       u32 i;
     207             :       vec_foreach_index (i, lm->intfs_timeouts)
     208             :       {
     209             :         if (i == lm->intfs_timeouts_idx)
     210             :           {
     211             :             s = format (s, " [%d]", lm->intfs_timeouts[i]);
     212             :           }
     213             :         else
     214             :           {
     215             :             s = format (s, " %d", lm->intfs_timeouts[i]);
     216             :           }
     217             :       }
     218             :       clib_warning ("DEBUG: timeout schedule: %s", s);
     219             :       vec_free (s);
     220             : #endif
     221           0 :       if (event_data)
     222             :         {
     223           0 :           vec_set_len (event_data, 0);
     224             :         }
     225             :     }
     226             : 
     227             :   return 0;
     228             : }
     229             : 
     230             : /*
     231             :  * lldp process node declaration
     232             :  */
     233             : /* *INDENT-OFF* */
     234       95066 : VLIB_REGISTER_NODE(lldp_process_node, static) = {
     235             :   .function = lldp_process,
     236             :   .type = VLIB_NODE_TYPE_PROCESS,
     237             :   .name = "lldp-process",
     238             : };
     239             : /* *INDENT-ON* */
     240             : 
     241             : void
     242           0 : lldp_schedule_intf (lldp_main_t * lm, lldp_intf_t * n)
     243             : {
     244           0 :   const int idx = n - lm->intfs;
     245             :   u32 v;
     246           0 :   vec_foreach_index (v, lm->intfs_timeouts)
     247             :   {
     248           0 :     if (lm->intfs_timeouts[v] == idx)
     249             :       {
     250             :         /* already scheduled */
     251           0 :         return;
     252             :       }
     253             :   }
     254           0 :   n->last_sent = 0;          /* ensure that a packet is sent out immediately */
     255             :   /* put the interface at the current position in the timeouts - it
     256             :    * will timeout immediately */
     257           0 :   vec_insert (lm->intfs_timeouts, 1, lm->intfs_timeouts_idx);
     258           0 :   lm->intfs_timeouts[lm->intfs_timeouts_idx] = n - lm->intfs;
     259           0 :   vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
     260             :                              LLDP_EVENT_RESCHEDULE, 0);
     261             : #if LLDP_DEBUG
     262             :   clib_warning ("DEBUG: schedule interface %p, if idx %d", n, n->hw_if_index);
     263             : #endif
     264             : }
     265             : 
     266             : void
     267           0 : lldp_unschedule_intf (lldp_main_t * lm, lldp_intf_t * n)
     268             : {
     269           0 :   if (!n)
     270             :     {
     271           0 :       return;
     272             :     }
     273             : #if LLDP_DEBUG
     274             :   clib_warning ("DEBUG: unschedule interface %p, if idx %d", n,
     275             :                 n->hw_if_index);
     276             : #endif
     277           0 :   const int idx = n - lm->intfs;
     278             :   u32 v;
     279             :   /* remove intf index from timeouts vector */
     280           0 :   vec_foreach_index (v, lm->intfs_timeouts)
     281             :   {
     282           0 :     if (lm->intfs_timeouts[v] == idx)
     283             :       {
     284           0 :         vec_delete (lm->intfs_timeouts, 1, v);
     285           0 :         break;
     286             :       }
     287             :   }
     288             :   /* wrap current timeout index to first element if needed */
     289           0 :   if (lm->intfs_timeouts_idx >= vec_len (lm->intfs_timeouts))
     290             :     {
     291           0 :       lm->intfs_timeouts_idx = 0;
     292             :     }
     293           0 :   vlib_process_signal_event (lm->vlib_main, lm->lldp_process_node_index,
     294             :                              LLDP_EVENT_RESCHEDULE, 0);
     295             : }
     296             : 
     297             : static clib_error_t *
     298       13514 : lldp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
     299             : {
     300       13514 :   lldp_main_t *lm = &lldp_main;
     301       13514 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     302       13514 :   lldp_intf_t *n = lldp_get_intf (lm, hi->hw_if_index);
     303       13514 :   if (n)
     304             :     {
     305           0 :       if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
     306             :         {
     307             :           /* FIXME - the packet sent here isn't send properly - need to find a
     308             :            * way to send the packet before interface goes down */
     309           0 :           lldp_send_ethernet (lm, n, 1);
     310           0 :           lldp_unschedule_intf (lm, n);
     311             :         }
     312             :     }
     313       13514 :   return 0;
     314             : }
     315             : 
     316        1151 : VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (lldp_sw_interface_up_down);
     317             : 
     318             : static clib_error_t *
     319       13336 : lldp_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     320             : {
     321       13336 :   lldp_main_t *lm = &lldp_main;
     322       13336 :   lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
     323       13336 :   if (n)
     324             :     {
     325           0 :       if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
     326             :         {
     327           0 :           lldp_schedule_intf (lm, n);
     328             :         }
     329             :     }
     330       13336 :   return 0;
     331             : }
     332             : 
     333        1151 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lldp_hw_interface_up_down);
     334             : 
     335             : /*
     336             :  * fd.io coding-style-patch-verification: ON
     337             :  *
     338             :  * Local Variables:
     339             :  * eval: (c-set-style "gnu")
     340             :  * End:
     341             :  */

Generated by: LCOV version 1.14