LCOV - code coverage report
Current view: top level - vnet/fib - fib_entry_src_rr.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 84 84 100.0 %
Date: 2023-10-26 01:39:38 Functions: 9 9 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 <vlib/vlib.h>
      17             : #include <vnet/ip/format.h>
      18             : #include <vnet/ip/lookup.h>
      19             : #include <vnet/adj/adj.h>
      20             : #include <vnet/dpo/drop_dpo.h>
      21             : 
      22             : #include "fib_entry_src.h"
      23             : #include "fib_entry_src_rr.h"
      24             : #include "fib_entry_cover.h"
      25             : #include "fib_entry.h"
      26             : #include "fib_table.h"
      27             : #include "fib_path_ext.h"
      28             : 
      29             : /*
      30             :  * fib_entry_src_rr_resolve_via_connected
      31             :  *
      32             :  * Resolve via a connected cover.
      33             :  */
      34             : void
      35         270 : fib_entry_src_rr_resolve_via_connected (fib_entry_src_t *src,
      36             :                                         const fib_entry_t *fib_entry,
      37             :                                         const fib_entry_t *cover)
      38             : {
      39         810 :     const fib_route_path_t path = {
      40         270 :         .frp_proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto),
      41             :         .frp_addr = fib_entry->fe_prefix.fp_addr,
      42         270 :         .frp_sw_if_index = fib_entry_get_resolving_interface(
      43             :                                fib_entry_get_index(cover)),
      44             :         .frp_fib_index = ~0,
      45             :         .frp_weight = 1,
      46             :     };
      47         270 :     fib_route_path_t *paths = NULL;
      48         270 :     vec_add1(paths, path);
      49             : 
      50             :     /*
      51             :      * since the cover is connected, the address this entry corresponds
      52             :      * to is a peer (ARP-able for) on the interface to which the cover is
      53             :      * connected. The fact we resolve via the cover, just means this RR
      54             :      * source is the first SRC to use said peer. The ARP source will be along
      55             :      * shortly to over-rule this RR source.
      56             :      */
      57         270 :     src->fes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NONE, paths);
      58         270 :     src->fes_entry_flags |= (fib_entry_get_flags(fib_entry_get_index(cover)) &
      59             :                              FIB_ENTRY_FLAGS_RR_INHERITED);
      60             : 
      61         270 :     vec_free(paths);
      62         270 : }
      63             : 
      64             : 
      65             : /**
      66             :  * Source initialisation Function 
      67             :  */
      68             : static void
      69        4234 : fib_entry_src_rr_init (fib_entry_src_t *src)
      70             : {
      71        4234 :     src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
      72        4234 :     src->u.rr.fesr_sibling = FIB_NODE_INDEX_INVALID;
      73        4234 : }
      74             : 
      75             : 
      76             : /*
      77             :  * use the path-list of the cover, unless it would form a loop.
      78             :  * that is unless the cover is via this entry.
      79             :  * If a loop were to form it would be a 1 level loop (i.e. X via X),
      80             :  * and there would be 2 locks on the path-list; one since its used
      81             :  * by the cover, and 1 from here. The first lock will go when the
      82             :  * cover is removed, the second, and last, when the covered walk
      83             :  * occurs during the cover's removal - this is not a place where
      84             :  * we can handle last lock gone.
      85             :  * In short, don't let the loop form. The usual rules of 'we must
      86             :  * let it form so we know when it breaks' don't apply here, since
      87             :  * the loop will break when the cover changes, and this function
      88             :  * will be called again when that happens.
      89             :  */
      90             : void
      91         335 : fib_entry_src_rr_use_covers_pl (fib_entry_src_t *src,
      92             :                                 const fib_entry_t *fib_entry,
      93             :                                 const fib_entry_t *cover)
      94             : {
      95         335 :     fib_node_index_t *entries = NULL;
      96             :     dpo_proto_t proto;
      97             :     fib_entry_src_t *s;
      98             : 
      99         335 :     proto = fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto);
     100         335 :     vec_add1(entries, fib_entry_get_index(fib_entry));
     101             : 
     102         335 :     if (fib_path_list_recursive_loop_detect(cover->fe_parent,
     103             :                                             &entries))
     104             :     {
     105           4 :         src->fes_pl = fib_path_list_create_special(proto,
     106             :                                                    FIB_PATH_LIST_FLAG_DROP,
     107             :                                                    drop_dpo_get(proto));
     108             :     }
     109             :     else
     110             :     {
     111         331 :         src->fes_pl = cover->fe_parent;
     112         333 :         vec_foreach (s,cover->fe_srcs)
     113             :           {
     114         333 :             if (s->fes_pl != cover->fe_parent)
     115           2 :               continue;
     116             : 
     117         331 :             src->fes_path_exts.fpel_exts = vec_dup (s->fes_path_exts.fpel_exts);
     118         331 :             break;
     119             :           }
     120             :     }
     121         335 :     vec_free(entries);
     122         335 : }
     123             : 
     124             : /*
     125             :  * Source activation. Called when the source is the new best source on the entry
     126             :  */
     127             : static int
     128         597 : fib_entry_src_rr_activate (fib_entry_src_t *src,
     129             :                            const fib_entry_t *fib_entry)
     130             : {
     131             :     fib_entry_t *cover;
     132             : 
     133             :     /*
     134             :      * find the covering prefix. become a dependent thereof.
     135             :      * for IP there should always be a cover, though it may be the default route.
     136             :      * For MPLS there is never a cover.
     137             :      */
     138         597 :     if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
     139             :     {
     140           4 :         src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS,
     141             :                                                    FIB_PATH_LIST_FLAG_DROP,
     142             :                                                    NULL);
     143           4 :         fib_path_list_lock(src->fes_pl);
     144           4 :         return (!0);
     145             :     }
     146             : 
     147         593 :     src->u.rr.fesr_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
     148             :                                                      &fib_entry->fe_prefix);
     149             : 
     150         593 :     ASSERT(FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover);
     151             : 
     152         593 :     cover = fib_entry_get(src->u.rr.fesr_cover);
     153             : 
     154         593 :     src->u.rr.fesr_sibling =
     155         593 :         fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
     156             : 
     157             :     /*
     158             :      * if the cover is attached then install an attached-host path
     159             :      * (like an adj-fib). Otherwise inherit the forwarding from the cover
     160             :      */
     161         593 :     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
     162             :     {
     163         269 :         fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
     164             :     }
     165             :     else
     166             :     {
     167         324 :         fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
     168             :     }
     169         593 :     fib_path_list_lock(src->fes_pl);
     170             : 
     171             :     /*
     172             :      * return go for install
     173             :      */
     174         593 :     return (!0);
     175             : }
     176             : 
     177             : /**
     178             :  * Source Deactivate. 
     179             :  * Called when the source is no longer best source on the entry
     180             :  */
     181             : static void
     182         576 : fib_entry_src_rr_deactivate (fib_entry_src_t *src,
     183             :                              const fib_entry_t *fib_entry)
     184             : {
     185             :     fib_entry_t *cover;
     186             : 
     187             :     /*
     188             :      * remove the dependency on the covering entry
     189             :      */
     190         576 :     if (FIB_NODE_INDEX_INVALID != src->u.rr.fesr_cover)
     191             :     {
     192         572 :         fib_node_index_t *entries = NULL;
     193             : 
     194         572 :         cover = fib_entry_get(src->u.rr.fesr_cover);
     195         572 :         fib_entry_cover_untrack(cover, src->u.rr.fesr_sibling);
     196         572 :         src->u.rr.fesr_cover = FIB_NODE_INDEX_INVALID;
     197             : 
     198         572 :         if (FIB_NODE_INDEX_INVALID != cover->fe_parent)
     199             :         {
     200         491 :             fib_path_list_recursive_loop_detect(cover->fe_parent, &entries);
     201             : 
     202         491 :             vec_free(entries);
     203             :         }
     204             :     }
     205             : 
     206         576 :     fib_path_list_unlock(src->fes_pl);
     207         576 :     src->fes_pl = FIB_NODE_INDEX_INVALID;
     208         576 :     vec_free (src->fes_path_exts.fpel_exts);
     209         576 :     src->fes_entry_flags = FIB_ENTRY_FLAG_NONE;
     210         576 : }
     211             : 
     212             : fib_entry_src_cover_res_t
     213         179 : fib_entry_src_rr_cover_change (fib_entry_src_t *src,
     214             :                                const fib_entry_t *fib_entry)
     215             : {
     216         179 :     fib_entry_src_cover_res_t res = {
     217             :         .install = !0,
     218             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     219             :     };
     220             : 
     221         179 :     if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover)
     222             :     {
     223             :         /*
     224             :          * the source may be added, but it is not active
     225             :          * if it is not tracking the cover.
     226             :          */
     227          48 :         return (res);
     228             :     }
     229             : 
     230             :     /*
     231             :      * this function is called when this entry's cover has a more specific
     232             :      * entry inserted benaeth it. That does not necessarily mean that this
     233             :      * entry is covered by the new prefix. check that
     234             :      */
     235         131 :     if (src->u.rr.fesr_cover != fib_table_get_less_specific(fib_entry->fe_fib_index,
     236             :                                                           &fib_entry->fe_prefix))
     237             :     {
     238         131 :         fib_entry_src_rr_deactivate(src, fib_entry);
     239         131 :         fib_entry_src_rr_activate(src, fib_entry);
     240             : 
     241             :         /*
     242             :          * dependent children need to re-resolve to the new forwarding info
     243             :          */
     244         131 :         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
     245             :     }
     246         131 :     return (res);
     247             : }
     248             : 
     249             : /*
     250             :  * fib_entry_src_rr_cover_update
     251             :  *
     252             :  * This entry's cover has updated its forwarding info. This entry
     253             :  * will need to re-inheret.
     254             :  */
     255             : fib_entry_src_cover_res_t
     256           5 : fib_entry_src_rr_cover_update (fib_entry_src_t *src,
     257             :                                const fib_entry_t *fib_entry)
     258             : {
     259           5 :     fib_entry_src_cover_res_t res = {
     260             :         .install = !0,
     261             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     262             :     };
     263             :     fib_node_index_t old_path_list;
     264             :     fib_entry_t *cover;
     265             : 
     266           5 :     if (FIB_NODE_INDEX_INVALID == src->u.rr.fesr_cover)
     267             :     {
     268             :         /*
     269             :          * the source may be added, but it is not active
     270             :          * if it is not tracking the cover.
     271             :          */
     272           1 :         return (res);
     273             :     }
     274             : 
     275           4 :     cover = fib_entry_get(src->u.rr.fesr_cover);
     276           4 :     old_path_list = src->fes_pl;
     277             : 
     278             :     /*
     279             :      * if the ocver is attached then install an attached-host path
     280             :      * (like an adj-fib). Otherwise inherit the forwarding from the cover
     281             :      */
     282           4 :     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
     283             :     {
     284           1 :         fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
     285             :     }
     286             :     else
     287             :     {
     288           3 :         fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
     289             :     }
     290           4 :     fib_path_list_lock(src->fes_pl);
     291           4 :     fib_path_list_unlock(old_path_list);
     292             : 
     293             :     /*
     294             :      * dependent children need to re-resolve to the new forwarding info
     295             :      */
     296           4 :     res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
     297             : 
     298           4 :     return (res);
     299             : }
     300             : 
     301             : static u8*
     302           1 : fib_entry_src_rr_format (fib_entry_src_t *src,
     303             :                          u8* s)
     304             : {
     305           1 :     return (format(s, " cover:%d", src->u.rr.fesr_cover));
     306             : }
     307             : 
     308             : const static fib_entry_src_vft_t rr_src_vft = {
     309             :     .fesv_init = fib_entry_src_rr_init,
     310             :     .fesv_activate = fib_entry_src_rr_activate,
     311             :     .fesv_deactivate = fib_entry_src_rr_deactivate,
     312             :     .fesv_cover_change = fib_entry_src_rr_cover_change,
     313             :     .fesv_cover_update = fib_entry_src_rr_cover_update,
     314             :     .fesv_format = fib_entry_src_rr_format,
     315             : };
     316             : 
     317             : void
     318         575 : fib_entry_src_rr_register (void)
     319             : {
     320         575 :     fib_entry_src_behaviour_register(FIB_SOURCE_BH_RR, &rr_src_vft);
     321         575 : }

Generated by: LCOV version 1.14