LCOV - code coverage report
Current view: top level - vnet/fib - fib_entry_src_adj.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 101 104 97.1 %
Date: 2023-10-26 01:39:38 Functions: 15 15 100.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 "fib_entry.h"
      17             : #include "fib_entry_src.h"
      18             : #include "fib_path_list.h"
      19             : #include "fib_table.h"
      20             : #include "fib_entry_cover.h"
      21             : #include "fib_attached_export.h"
      22             : #include "fib_path_ext.h"
      23             : 
      24             : /**
      25             :  * Source initialisation Function
      26             :  */
      27             : static void
      28        9495 : fib_entry_src_adj_init (fib_entry_src_t *src)
      29             : {
      30        9495 :     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
      31        9495 :     src->u.adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
      32        9495 : }
      33             : 
      34             : static void
      35          48 : fib_entry_src_adj_path_add (fib_entry_src_t *src,
      36             :                             const fib_entry_t *entry,
      37             :                             fib_path_list_flags_t pl_flags,
      38             :                             const fib_route_path_t *paths)
      39             : {
      40             :     const fib_route_path_t *rpath;
      41             : 
      42          48 :     if (FIB_NODE_INDEX_INVALID == src->fes_pl)
      43             :     {
      44          42 :         src->fes_pl = fib_path_list_create(pl_flags, paths);
      45             :     }
      46             :     else
      47             :     {
      48           6 :         src->fes_pl = fib_path_list_copy_and_path_add(src->fes_pl,
      49             :                                                       pl_flags,
      50             :                                                       paths);
      51             :     }
      52             : 
      53             :     /*
      54             :      * resolve the existing extensions
      55             :      */
      56          48 :     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
      57             : 
      58             :     /*
      59             :      * and new extensions
      60             :      */
      61          96 :     vec_foreach(rpath, paths)
      62             :     {
      63          48 :         fib_path_ext_list_insert(&src->fes_path_exts,
      64             :                                  src->fes_pl,
      65             :                                  FIB_PATH_EXT_ADJ,
      66             :                                  rpath);
      67             :     }
      68          48 : }
      69             : 
      70             : static void
      71        5523 : fib_entry_src_adj_path_remove (fib_entry_src_t *src,
      72             :                                fib_path_list_flags_t pl_flags,
      73             :                                const fib_route_path_t *rpaths)
      74             : {
      75             :     const fib_route_path_t *rpath;
      76             : 
      77        5523 :     if (FIB_NODE_INDEX_INVALID != src->fes_pl)
      78             :     {
      79        5523 :         src->fes_pl = fib_path_list_copy_and_path_remove(src->fes_pl,
      80             :                                                          pl_flags,
      81             :                                                          rpaths);
      82             :     }
      83             : 
      84             :     /*
      85             :      * remove the path-extension for the path
      86             :      */
      87       11046 :     vec_foreach(rpath, rpaths)
      88             :     {
      89        5523 :         fib_path_ext_list_remove(&src->fes_path_exts, FIB_PATH_EXT_ADJ, rpath);
      90             :     };
      91             :     /*
      92             :      * resolve the remaining extensions
      93             :      */
      94        5523 :     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
      95        5523 : }
      96             : 
      97             : static void
      98        9453 : fib_entry_src_adj_path_swap (fib_entry_src_t *src,
      99             :                              const fib_entry_t *entry,
     100             :                              fib_path_list_flags_t pl_flags,
     101             :                              const fib_route_path_t *paths)
     102             : {
     103             :     const fib_route_path_t *rpath;
     104             : 
     105             :     /*
     106             :      * flush all the old extensions before we create a brand new path-list
     107             :      */
     108        9453 :     fib_path_ext_list_flush(&src->fes_path_exts);
     109             : 
     110        9453 :     src->fes_pl = fib_path_list_create(pl_flags, paths);
     111             : 
     112             :     /*
     113             :      * and new extensions
     114             :      */
     115       18906 :     vec_foreach(rpath, paths)
     116             :     {
     117        9453 :         fib_path_ext_list_push_back(&src->fes_path_exts,
     118             :                                     src->fes_pl,
     119             :                                     FIB_PATH_EXT_ADJ,
     120             :                                     rpath);
     121             :     }
     122        9453 : }
     123             : 
     124             : static void
     125        5529 : fib_entry_src_adj_remove (fib_entry_src_t *src)
     126             : {
     127        5529 :     src->fes_pl = FIB_NODE_INDEX_INVALID;
     128             : 
     129        5529 :     if (FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover)
     130             :     {
     131           0 :         fib_entry_cover_untrack(fib_entry_get(src->u.adj.fesa_cover),
     132             :                                 src->u.adj.fesa_sibling);
     133             :     }
     134        5529 : }
     135             : 
     136             : /*
     137             :  * Add a path-extension indicating whether this path is resolved,
     138             :  * because it passed the refinement check
     139             :  */
     140             : static void
     141       23703 : fib_enty_src_adj_update_path_ext (fib_entry_src_t *src,
     142             :                                   fib_node_index_t path_index,
     143             :                                   fib_path_ext_adj_flags_t flags)
     144             : {
     145             :     fib_path_ext_t *path_ext;
     146             : 
     147       23703 :     path_ext = fib_path_ext_list_find_by_path_index(&src->fes_path_exts,
     148             :                                                     path_index);
     149             : 
     150       23703 :     if (NULL != path_ext)
     151             :     {
     152       23703 :         path_ext->fpe_adj_flags = flags;
     153             :     }
     154             :     else
     155             :     {
     156           0 :         ASSERT(!"no path extension");
     157             :     }
     158       23703 : }
     159             : 
     160             : typedef struct fib_entry_src_path_list_walk_cxt_t_
     161             : {
     162             :     fib_entry_src_t *src;
     163             :     u32 cover_itf;
     164             :     fib_path_ext_adj_flags_t flags;
     165             : } fib_entry_src_path_list_walk_cxt_t;
     166             : 
     167             : static fib_path_list_walk_rc_t
     168       23703 : fib_entry_src_adj_path_list_walk (fib_node_index_t pl_index,
     169             :                                   fib_node_index_t path_index,
     170             :                                   void *arg)
     171             : {
     172             :     fib_entry_src_path_list_walk_cxt_t *ctx;
     173             :     u32 adj_itf;
     174             : 
     175       23703 :     ctx = arg;
     176       23703 :     adj_itf = fib_path_get_resolving_interface(path_index);
     177             : 
     178       23703 :     if (ctx->cover_itf == adj_itf)
     179             :     {
     180       19126 :         fib_enty_src_adj_update_path_ext(ctx->src, path_index,
     181             :                                          FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
     182       19126 :         ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
     183             :     }
     184             :     else
     185             :     {
     186             :         /*
     187             :          * if the interface the adj is on is unnumbered to the
     188             :          * cover's, then allow that too.
     189             :          */
     190             :         vnet_sw_interface_t *swif;
     191             : 
     192        4577 :         swif = vnet_get_sw_interface (vnet_get_main(), adj_itf);
     193             : 
     194        4577 :         if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
     195           3 :             ctx->cover_itf == swif->unnumbered_sw_if_index)
     196             :         {
     197           2 :             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
     198             :                                              FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
     199           2 :             ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
     200             :         }
     201             :         else
     202             :         {
     203        4575 :             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
     204             :                                              FIB_PATH_EXT_ADJ_FLAG_NONE);
     205             :         }
     206             :     }
     207       23703 :     return (FIB_PATH_LIST_WALK_CONTINUE);
     208             : }
     209             : 
     210             : static int
     211       11659 : fib_entry_src_adj_activate (fib_entry_src_t *src,
     212             :                             const fib_entry_t *fib_entry)
     213             : {
     214             :     fib_entry_t *cover;
     215             : 
     216             :     /*
     217             :      * find the covering prefix. become a dependent thereof.
     218             :      * there should always be a cover, though it may be the default route.
     219             :      */
     220       11659 :     src->u.adj.fesa_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
     221             :                                                         &fib_entry->fe_prefix);
     222             : 
     223       11659 :     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
     224       11659 :     ASSERT(fib_entry_get_index(fib_entry) != src->u.adj.fesa_cover);
     225             : 
     226       11659 :     cover = fib_entry_get(src->u.adj.fesa_cover);
     227             : 
     228       11659 :     ASSERT(cover != fib_entry);
     229             : 
     230       11659 :     src->u.adj.fesa_sibling =
     231       11659 :         fib_entry_cover_track(cover,
     232             :                               fib_entry_get_index(fib_entry));
     233             : 
     234             :     /*
     235             :      * if the cover is attached on the same interface as this adj source then
     236             :      * install the FIB entry via the adj. otherwise install a drop.
     237             :      * This prevents ARP/ND entries that on interface X that do not belong
     238             :      * on X's subnet from being added to the FIB. To do so would allow
     239             :      * nefarious gratuitous ARP requests from attracting traffic to the sender.
     240             :      *
     241             :      * and yes, I really do mean attached and not connected.
     242             :      * this abomination;
     243             :      *   ip route add 10.0.0.0/24 Eth0
     244             :      * is attached. and we want adj-fibs to install on Eth0.
     245             :      */
     246       14115 :     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover) ||
     247        2456 :         (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_for_source(src->u.adj.fesa_cover,
     248             :                                                                   FIB_SOURCE_INTERFACE)))
     249             :     {
     250       18406 :         fib_entry_src_path_list_walk_cxt_t ctx = {
     251        9203 :             .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
     252             :             .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
     253             :             .src = src,
     254             :         };
     255             : 
     256        9203 :         fib_path_list_walk(src->fes_pl,
     257             :                            fib_entry_src_adj_path_list_walk,
     258             :                            &ctx);
     259             : 
     260             :         /*
     261             :          * active the entry is one of the paths refines the cover.
     262             :          */
     263        9203 :         return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
     264             :     }
     265        2456 :     return (0);
     266             : }
     267             : 
     268             : /*
     269             :  * Source re-activate.
     270             :  * Called when the source path lit has changed and the source is still
     271             :  * the best source
     272             :  */
     273             : static int
     274       14487 : fib_entry_src_adj_reactivate (fib_entry_src_t *src,
     275             :                               const fib_entry_t *fib_entry)
     276             : {
     277       28974 :     fib_entry_src_path_list_walk_cxt_t ctx = {
     278       14487 :         .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
     279             :         .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
     280             :         .src = src,
     281             :     };
     282             : 
     283       14487 :     fib_path_list_walk(src->fes_pl,
     284             :                        fib_entry_src_adj_path_list_walk,
     285             :                        &ctx);
     286             : 
     287       14487 :     return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
     288             : }
     289             : 
     290             : /*
     291             :  * Source Deactivate.
     292             :  * Called when the source is no longer best source on the entry
     293             :  */
     294             : static void
     295        7697 : fib_entry_src_adj_deactivate (fib_entry_src_t *src,
     296             :                               const fib_entry_t *fib_entry)
     297             : {
     298             :     fib_entry_t *cover;
     299             : 
     300             :     /*
     301             :      * remove the dependency on the covering entry
     302             :      */
     303        7697 :     if (FIB_NODE_INDEX_INVALID == src->u.adj.fesa_cover)
     304             :     {
     305             :         /*
     306             :          * this is the case if the entry is in the non-forwarding trie
     307             :          */
     308           0 :         return;
     309             :     }
     310             : 
     311        7697 :     cover = fib_entry_get(src->u.adj.fesa_cover);
     312        7697 :     fib_entry_cover_untrack(cover, src->u.adj.fesa_sibling);
     313             : 
     314             :     /*
     315             :      * tell the cover this entry no longer needs exporting
     316             :      */
     317        7697 :     fib_attached_export_covered_removed(cover, fib_entry_get_index(fib_entry));
     318             : 
     319        7697 :     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
     320        7697 :     src->u.adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
     321             : }
     322             : 
     323             : static u8*
     324           2 : fib_entry_src_adj_format (fib_entry_src_t *src,
     325             :                          u8* s)
     326             : {
     327           2 :     return (format(s, " cover:%d", src->u.adj.fesa_cover));
     328             : }
     329             : 
     330             : static void
     331        9626 : fib_entry_src_adj_installed (fib_entry_src_t *src,
     332             :                              const fib_entry_t *fib_entry)
     333             : {
     334             :     /*
     335             :      * The adj source now rules! poke our cover to get exported
     336             :      */
     337             :     fib_entry_t *cover;
     338             : 
     339        9626 :     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
     340        9626 :     cover = fib_entry_get(src->u.adj.fesa_cover);
     341             : 
     342        9626 :     fib_attached_export_covered_added(cover,
     343             :                                       fib_entry_get_index(fib_entry));
     344        9626 : }
     345             : 
     346             : static fib_entry_src_cover_res_t
     347        2116 : fib_entry_src_adj_cover_change (fib_entry_src_t *src,
     348             :                                 const fib_entry_t *fib_entry)
     349             : {
     350        2116 :     fib_entry_src_cover_res_t res = {
     351             :         .install = 0,
     352             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     353             :     };
     354             : 
     355             :     /*
     356             :      * not interested in a change to the cover if the cover
     357             :      * is not being tracked, i.e. the source is not active
     358             :      */
     359        2116 :     if (FIB_NODE_INDEX_INVALID == src->u.adj.fesa_cover)
     360           1 :         return res;
     361             : 
     362        2115 :     fib_entry_src_adj_deactivate(src, fib_entry);
     363             : 
     364        2115 :     res.install = fib_entry_src_adj_activate(src, fib_entry);
     365             : 
     366        2115 :     if (res.install) {
     367             :         /*
     368             :          * ADJ fib can install
     369             :          */
     370          92 :         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
     371             :     }
     372             : 
     373        2115 :     FIB_ENTRY_DBG(fib_entry, "adj-src-cover-changed");
     374        2115 :     return (res);
     375             : }
     376             : 
     377             : /*
     378             :  * fib_entry_src_adj_cover_update
     379             :  */
     380             : static fib_entry_src_cover_res_t
     381           6 : fib_entry_src_adj_cover_update (fib_entry_src_t *src,
     382             :                                 const fib_entry_t *fib_entry)
     383             : {
     384             :     /*
     385             :      * the cover has updated, i.e. its forwarding or flags
     386             :      * have changed. don't deactivate/activate here, since this
     387             :      * prefix is updated during the covers walk.
     388             :      */
     389           6 :     fib_entry_src_cover_res_t res = {
     390             :         .install = 0,
     391             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     392             :     };
     393             :     fib_entry_t *cover;
     394             : 
     395             :     /*
     396             :      * If there is no cover, then the source is not active and we can ignore
     397             :      * this update
     398             :      */
     399           6 :     if (FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover)
     400             :     {
     401           6 :         cover = fib_entry_get(src->u.adj.fesa_cover);
     402             : 
     403           6 :         res.install = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover));
     404             : 
     405           6 :         FIB_ENTRY_DBG(fib_entry, "adj-src-cover-updated");
     406             :     }
     407           6 :     return (res);
     408             : }
     409             : 
     410             : const static fib_entry_src_vft_t adj_src_vft = {
     411             :     .fesv_init = fib_entry_src_adj_init,
     412             :     .fesv_path_swap = fib_entry_src_adj_path_swap,
     413             :     .fesv_path_add = fib_entry_src_adj_path_add,
     414             :     .fesv_path_remove = fib_entry_src_adj_path_remove,
     415             :     .fesv_remove = fib_entry_src_adj_remove,
     416             :     .fesv_activate = fib_entry_src_adj_activate,
     417             :     .fesv_deactivate = fib_entry_src_adj_deactivate,
     418             :     .fesv_reactivate = fib_entry_src_adj_reactivate,
     419             :     .fesv_format = fib_entry_src_adj_format,
     420             :     .fesv_installed = fib_entry_src_adj_installed,
     421             :     .fesv_cover_change = fib_entry_src_adj_cover_change,
     422             :     .fesv_cover_update = fib_entry_src_adj_cover_update,
     423             : };
     424             : 
     425             : void
     426         575 : fib_entry_src_adj_register (void)
     427             : {
     428         575 :     fib_entry_src_behaviour_register(FIB_SOURCE_BH_ADJ, &adj_src_vft);
     429         575 : }

Generated by: LCOV version 1.14