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-10-26 01:39:38 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       13105 : adj_bfd_from_base (adj_delegate_t *ad)
      62             : {
      63       13105 :     if (NULL != ad)
      64             :     {
      65         328 :         return (pool_elt_at_index(abd_pool, ad->ad_index));
      66             :     }
      67       12777 :     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          87 : adj_bfd_bfd_state_to_fib (bfd_state_e bstate)
      82             : {
      83          87 :     switch (bstate)
      84             :     {
      85          52 :     case BFD_STATE_up:
      86          52 :         return (ADJ_BFD_STATE_UP);
      87          35 :     case BFD_STATE_down:
      88             :     case BFD_STATE_admin_down:
      89             :     case BFD_STATE_init:
      90          35 :         return (ADJ_BFD_STATE_DOWN);
      91             :     }
      92           0 :     return (ADJ_BFD_STATE_DOWN);
      93             : }
      94             : 
      95             : static void
      96         243 : 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         243 :     fib_node_back_walk_ctx_t ctx = {
     103             :         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
     104             :     };
     105         243 :     fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &ctx);
     106         243 : }
     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         244 : 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         244 :     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         244 :     switch (session->transport)
     131             :     {
     132         244 :     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         244 :         ai = session->udp.adj_index;
     139         244 :         break;
     140           0 :     default:
     141             :         /*
     142             :          * Don't know what adj this session uses
     143             :          */
     144           0 :         return;
     145             :     }
     146             : 
     147         244 :     if (INDEX_INVALID == ai)
     148             :     {
     149             :         /* No associated Adjacency with the session */
     150           0 :         return;
     151             :     }
     152             : 
     153         244 :     switch (event)
     154             :     {
     155          78 :     case BFD_LISTEN_EVENT_CREATE:
     156             :         /*
     157             :          * The creation of a new session
     158             :          */
     159         156 :         if ((ADJ_INDEX_INVALID != ai) &&
     160          78 :             (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          78 :             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          78 :             abd->abd_state = ADJ_BFD_STATE_DOWN;
     182          78 :             abd->abd_index = session->bs_idx;
     183             : 
     184          78 :             adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, abd - abd_pool);
     185          78 :             adj_bfd_update_walk(ai);
     186             :         }
     187          78 :         break;
     188             : 
     189          87 :     case BFD_LISTEN_EVENT_UPDATE:
     190             :         /*
     191             :          * state change up/down and
     192             :          */
     193          87 :         abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     194             : 
     195          87 :         if (NULL != abd)
     196             :         {
     197          87 :             abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state);
     198          87 :             adj_bfd_update_walk(ai);
     199             :         }
     200             :         /*
     201             :          * else
     202             :          *   not an adj with BFD state
     203             :          */
     204          87 :         break;
     205             : 
     206          79 :     case BFD_LISTEN_EVENT_DELETE:
     207             :         /*
     208             :          * session has been removed.
     209             :          */
     210          79 :         abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     211             : 
     212          79 :         if (NULL != abd)
     213             :         {
     214             :             /*
     215             :              * has an associated BFD tracking delegate
     216             :              * remove the BFD tracking delegate, update children
     217             :              */
     218          78 :             adj_delegate_remove(ai, ADJ_DELEGATE_BFD);
     219          78 :             pool_put(abd_pool, abd);
     220             : 
     221          78 :             adj_bfd_update_walk(ai);
     222             :         }
     223             :         /*
     224             :          * else
     225             :          *  no BFD associated state
     226             :          */
     227          79 :         break;
     228             :     }
     229         244 : }
     230             : 
     231             : int
     232       12939 : adj_bfd_is_up (adj_index_t ai)
     233             : {
     234             :     const adj_bfd_delegate_t *abd;
     235             : 
     236       12939 :     abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
     237             : 
     238       12939 :     if (NULL == abd)
     239             :     {
     240             :         /*
     241             :          * no BFD tracking - resolved
     242             :          */
     243       12776 :         return (!0);
     244             :     }
     245             :     else
     246             :     {
     247             :         /*
     248             :          * defer to the state of the BFD tracking
     249             :          */
     250         163 :         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         575 : adj_bfd_main_init (vlib_main_t * vm)
     275             : {
     276         575 :     bfd_register_listener(adj_bfd_notify);
     277             : 
     278         575 :     adj_delegate_register_type (ADJ_DELEGATE_BFD, &adj_delegate_vft);
     279             : 
     280         575 :     return (0);
     281             : }
     282             : 
     283             : /* *INDENT-OFF* */
     284       84671 : 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