LCOV - code coverage report
Current view: top level - vnet/adj - adj_bfd.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 55 69 79.7 %
Date: 2023-07-05 22:20:52 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 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             : #include <vnet/bfd/bfd_main.h>
      17             : 
      18             : #include <vnet/adj/adj_delegate.h>
      19             : #include <vnet/adj/adj_nbr.h>
      20             : #include <vnet/fib/fib_walk.h>
      21             : 
      22             : /**
      23             :  * Distillation of the BFD session states into a go/no-go for using
      24             :  * the associated tracked adjacency
      25             :  */
      26             : typedef enum adj_bfd_state_t_
      27             : {
      28             :     ADJ_BFD_STATE_DOWN,
      29             :     ADJ_BFD_STATE_UP,
      30             : } adj_bfd_state_t;
      31             : 
      32             : #define ADJ_BFD_STATES {                        \
      33             :     [ADJ_BFD_STATE_DOWN] = "down",              \
      34             :     [ADJ_BFD_STATE_UP]   = "up",                \
      35             : }
      36             : 
      37             : static const char *adj_bfd_state_names[] = ADJ_BFD_STATES;
      38             : 
      39             : /**
      40             :  * BFD delegate daa
      41             :  */
      42             : typedef struct adj_bfd_delegate_t_
      43             : {
      44             :     /**
      45             :      * BFD session state
      46             :      */
      47             :     adj_bfd_state_t abd_state;
      48             : 
      49             :     /**
      50             :      * BFD session index
      51             :      */
      52             :     u32 abd_index;
      53             : } adj_bfd_delegate_t;
      54             : 
      55             : /**
      56             :  * Pool of delegates
      57             : */
      58             : static adj_bfd_delegate_t *abd_pool;
      59             : 
      60             : static inline adj_bfd_delegate_t*
      61       13097 : adj_bfd_from_base (adj_delegate_t *ad)
      62             : {
      63       13097 :     if (NULL != ad)
      64             :     {
      65         466 :         return (pool_elt_at_index(abd_pool, ad->ad_index));
      66             :     }
      67       12631 :     return (NULL);
      68             : }
      69             : 
      70             : static inline const adj_bfd_delegate_t*
      71           0 : adj_bfd_from_const_base (const adj_delegate_t *ad)
      72             : {
      73           0 :     if (NULL != ad)
      74             :     {
      75           0 :         return (pool_elt_at_index(abd_pool, ad->ad_index));
      76             :     }
      77           0 :     return (NULL);
      78             : }
      79             : 
      80             : static adj_bfd_state_t
      81         130 : adj_bfd_bfd_state_to_fib (bfd_state_e bstate)
      82             : {
      83         130 :     switch (bstate)
      84             :     {
      85          76 :     case BFD_STATE_up:
      86          76 :         return (ADJ_BFD_STATE_UP);
      87          54 :     case BFD_STATE_down:
      88             :     case BFD_STATE_admin_down:
      89             :     case BFD_STATE_init:
      90          54 :         return (ADJ_BFD_STATE_DOWN);
      91             :     }
      92           0 :     return (ADJ_BFD_STATE_DOWN);
      93             : }
      94             : 
      95             : static void
      96         340 : adj_bfd_update_walk (adj_index_t ai)
      97             : {
      98             :     /*
      99             :      * initiate a backwalk of dependent children
     100             :      * to notify of the state change of this adj.
     101             :      */
     102         340 :     fib_node_back_walk_ctx_t ctx = {
     103             :         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
     104             :     };
     105         340 :     fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &ctx);
     106         340 : }
     107             : 
     108             : /**
     109             :  * @brief Callback function registered with BFD module to receive notifications
     110             :  * of the CRUD of BFD sessions
     111             :  * would be static but for the fact it's called from the unit-tests
     112             :  */
     113             : void
     114         341 : adj_bfd_notify (bfd_listen_event_e event,
     115             :                 const bfd_session_t *session)
     116             : {
     117             :     adj_bfd_delegate_t *abd;
     118             :     adj_delegate_t *aed;
     119             :     adj_index_t ai;
     120             : 
     121         341 :     if (BFD_HOP_TYPE_SINGLE != session->hop_type)
     122             :     {
     123             :         /*
     124             :          * multi-hop BFD sessions attach directly to the FIB entry
     125             :          * single-hop adj to the associate adjacency.
     126             :          */
     127           0 :         return;
     128             :     }
     129             : 
     130         341 :     switch (session->transport)
     131             :     {
     132         341 :     case BFD_TRANSPORT_UDP4:
     133             :     case BFD_TRANSPORT_UDP6:
     134             :         /*
     135             :          * pick up the same adjacency that the BFD session is using
     136             :          * to send. The BFD session is holding a lock on this adj.
     137             :          */
     138         341 :         ai = session->udp.adj_index;
     139         341 :         break;
     140           0 :     default:
     141             :         /*
     142             :          * Don't know what adj this session uses
     143             :          */
     144           0 :         return;
     145             :     }
     146             : 
     147         341 :     if (INDEX_INVALID == ai)
     148             :     {
     149             :         /* No associated Adjacency with the session */
     150           0 :         return;
     151             :     }
     152             : 
     153         341 :     switch (event)
     154             :     {
     155         105 :     case BFD_LISTEN_EVENT_CREATE:
     156             :         /*
     157             :          * The creation of a new session
     158             :          */
     159         210 :         if ((ADJ_INDEX_INVALID != ai) &&
     160         105 :             (aed = adj_delegate_get(adj_get(ai),
     161             :                                     ADJ_DELEGATE_BFD)))
     162             :         {
     163             :             /*
     164             :              * already got state for this adj
     165             :              */
     166             :         }
     167             :         else
     168             :         {
     169             :             /*
     170             :              * allocate and init a new delegate struct
     171             :              */
     172         105 :             pool_get(abd_pool, abd);
     173             : 
     174             :             /*
     175             :              * it would be best here if we could ignore this create and just
     176             :              * wait for the first update, but this is not possible because
     177             :              * BFD sessions are created in the down state, and can remain this
     178             :              * way without transitioning to another state if the peer is
     179             :              * unresponsive. So we have to assume down and wait for up.
     180             :              */
     181         105 :             abd->abd_state = ADJ_BFD_STATE_DOWN;
     182         105 :             abd->abd_index = session->bs_idx;
     183             : 
     184         105 :             adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, abd - abd_pool);
     185         105 :             adj_bfd_update_walk(ai);
     186             :         }
     187         105 :         break;
     188             : 
     189         130 :     case BFD_LISTEN_EVENT_UPDATE:
     190             :         /*
     191             :          * state change up/down and
     192             :          */
     193         130 :         abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     194             : 
     195         130 :         if (NULL != abd)
     196             :         {
     197         130 :             abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state);
     198         130 :             adj_bfd_update_walk(ai);
     199             :         }
     200             :         /*
     201             :          * else
     202             :          *   not an adj with BFD state
     203             :          */
     204         130 :         break;
     205             : 
     206         106 :     case BFD_LISTEN_EVENT_DELETE:
     207             :         /*
     208             :          * session has been removed.
     209             :          */
     210         106 :         abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     211             : 
     212         106 :         if (NULL != abd)
     213             :         {
     214             :             /*
     215             :              * has an associated BFD tracking delegate
     216             :              * remove the BFD tracking delegate, update children
     217             :              */
     218         105 :             adj_delegate_remove(ai, ADJ_DELEGATE_BFD);
     219         105 :             pool_put(abd_pool, abd);
     220             : 
     221         105 :             adj_bfd_update_walk(ai);
     222             :         }
     223             :         /*
     224             :          * else
     225             :          *  no BFD associated state
     226             :          */
     227         106 :         break;
     228             :     }
     229         341 : }
     230             : 
     231             : int
     232       12861 : adj_bfd_is_up (adj_index_t ai)
     233             : {
     234             :     const adj_bfd_delegate_t *abd;
     235             : 
     236       12861 :     abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     237             : 
     238       12861 :     if (NULL == abd)
     239             :     {
     240             :         /*
     241             :          * no BFD tracking - resolved
     242             :          */
     243       12630 :         return (!0);
     244             :     }
     245             :     else
     246             :     {
     247             :         /*
     248             :          * defer to the state of the BFD tracking
     249             :          */
     250         231 :         return (ADJ_BFD_STATE_UP == abd->abd_state);
     251             :     }
     252             : }
     253             : 
     254             : /**
     255             :  * Print a delegate that represents BFD tracking
     256             :  */
     257             : static u8 *
     258           0 : adj_delegate_fmt_bfd (const adj_delegate_t *aed, u8 *s)
     259             : {
     260           0 :     const adj_bfd_delegate_t *abd = adj_bfd_from_const_base(aed);
     261             : 
     262           0 :     s = format(s, "BFD:[state:%s index:%d]",
     263           0 :                adj_bfd_state_names[abd->abd_state],
     264             :                abd->abd_index);
     265             : 
     266           0 :     return (s);
     267             : }
     268             : 
     269             : const static adj_delegate_vft_t adj_delegate_vft = {
     270             :   .adv_format = adj_delegate_fmt_bfd,
     271             : };
     272             : 
     273             : static clib_error_t *
     274         559 : adj_bfd_main_init (vlib_main_t * vm)
     275             : {
     276         559 :     bfd_register_listener(adj_bfd_notify);
     277             : 
     278         559 :     adj_delegate_register_type (ADJ_DELEGATE_BFD, &adj_delegate_vft);
     279             : 
     280         559 :     return (0);
     281             : }
     282             : 
     283             : /* *INDENT-OFF* */
     284       82879 : VLIB_INIT_FUNCTION (adj_bfd_main_init)=
     285             : {
     286             :     .runs_after = VLIB_INITS("bfd_main_init"),
     287             : };
     288             : /* *INDENT-ON* */

Generated by: LCOV version 1.14