LCOV - code coverage report
Current view: top level - vnet/fib - fib_entry_src.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 569 613 92.8 %
Date: 2023-10-26 01:39:38 Functions: 54 57 94.7 %

          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/adj/adj.h>
      17             : #include <vnet/dpo/load_balance.h>
      18             : #include <vnet/dpo/mpls_label_dpo.h>
      19             : #include <vnet/dpo/drop_dpo.h>
      20             : #include <vnet/dpo/replicate_dpo.h>
      21             : 
      22             : #include <vnet/fib/fib_entry_src.h>
      23             : #include <vnet/fib/fib_table.h>
      24             : #include <vnet/fib/fib_path_ext.h>
      25             : #include <vnet/fib/fib_urpf_list.h>
      26             : #include <vnet/fib/fib_entry_delegate.h>
      27             : 
      28             : /*
      29             :  * per-source type vft
      30             :  */
      31             : static fib_entry_src_vft_t fib_entry_src_bh_vft[FIB_SOURCE_BH_MAX];
      32             : 
      33             : /**
      34             :  * Get the VFT for a given source. This is a combination of the source
      35             :  * enum and the interposer flags
      36             :  */
      37             : const fib_entry_src_vft_t*
      38      568212 : fib_entry_src_get_vft (const fib_entry_src_t *esrc)
      39             : {
      40             :     fib_source_behaviour_t bh;
      41             : 
      42      568212 :     bh = fib_source_get_behaviour(esrc->fes_src);
      43             : 
      44      568212 :     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE)
      45             :     {
      46         429 :         return (&fib_entry_src_bh_vft[FIB_SOURCE_BH_INTERPOSE]);
      47             :     }
      48             : 
      49      567783 :     ASSERT(bh < FIB_SOURCE_BH_MAX);
      50      567783 :     return (&fib_entry_src_bh_vft[bh]);
      51             : }
      52             : 
      53             : static void
      54          17 : fib_entry_src_copy_default (const fib_entry_src_t *orig_src,
      55             :                             const fib_entry_t *fib_entry,
      56             :                             fib_entry_src_t *copy_src)
      57             : {
      58          17 :     clib_memcpy(&copy_src->u, &orig_src->u, sizeof(copy_src->u));
      59          17 : }
      60             : 
      61             : void
      62        5175 : fib_entry_src_behaviour_register (fib_source_behaviour_t bh,
      63             :                                   const fib_entry_src_vft_t *vft)
      64             : {
      65        5175 :     fib_entry_src_bh_vft[bh] = *vft;
      66             : 
      67        5175 :     if (NULL == fib_entry_src_bh_vft[bh].fesv_copy)
      68             :     {
      69        4600 :         fib_entry_src_bh_vft[bh].fesv_copy = fib_entry_src_copy_default;
      70             :     }
      71        5175 : }
      72             : 
      73             : static int
      74        4499 : fib_entry_src_cmp_for_sort (void * v1,
      75             :                             void * v2)
      76             : {
      77        4499 :     fib_entry_src_t *esrc1 = v1, *esrc2 = v2;
      78             : 
      79        4499 :     return (fib_source_get_prio(esrc1->fes_src) -
      80        4499 :             fib_source_get_prio(esrc2->fes_src));
      81             : }
      82             : 
      83             : static void
      84       45365 : fib_entry_src_action_init (fib_entry_t *fib_entry,
      85             :                            fib_source_t source,
      86             :                            fib_entry_flag_t flags)
      87             : {
      88       45365 :     fib_entry_src_t esrc = {
      89             :         .fes_pl = FIB_NODE_INDEX_INVALID,
      90             :         .fes_flags = FIB_ENTRY_SRC_FLAG_NONE,
      91             :         .fes_src = source,
      92             :         .fes_entry_flags = flags,
      93             :     };
      94             : 
      95       45365 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, &esrc, fesv_init, (&esrc));
      96             : 
      97       45365 :     vec_add1(fib_entry->fe_srcs, esrc);
      98       45365 :     vec_sort_with_function(fib_entry->fe_srcs,
      99             :                            fib_entry_src_cmp_for_sort);
     100       45365 : }
     101             : 
     102             : static fib_entry_src_t *
     103      665523 : fib_entry_src_find_i (const fib_entry_t *fib_entry,
     104             :                       fib_source_t source,
     105             :                       u32 *index)
     106             : 
     107             : {
     108             :     fib_entry_src_t *esrc;
     109             :     int ii;
     110             : 
     111      665523 :     ii = 0;
     112      819613 :     vec_foreach(esrc, fib_entry->fe_srcs)
     113             :     {
     114      644243 :         if (esrc->fes_src == source)
     115             :         {
     116      490153 :             if (NULL != index)
     117             :             {
     118       35297 :                 *index = ii;
     119             :             }
     120      490153 :             return (esrc);
     121             :         }
     122             :         else
     123             :         {
     124      154090 :             ii++;
     125             :         }
     126             :     }
     127             : 
     128      175370 :     return (NULL);
     129             : }
     130             : 
     131             : fib_entry_src_t *
     132      630226 : fib_entry_src_find (const fib_entry_t *fib_entry,
     133             :                     fib_source_t source)
     134             : 
     135             : {
     136      630226 :     return (fib_entry_src_find_i(fib_entry, source, NULL));
     137             : }
     138             : 
     139             : int
     140      176908 : fib_entry_is_sourced (fib_node_index_t fib_entry_index,
     141             :                       fib_source_t source)
     142             : {
     143             :     fib_entry_t *fib_entry;
     144             : 
     145      176908 :     fib_entry = fib_entry_get(fib_entry_index);
     146             : 
     147      176908 :     return (NULL != fib_entry_src_find(fib_entry, source));
     148             : }
     149             : 
     150             : int
     151         552 : fib_entry_is_marked (fib_node_index_t fib_entry_index,
     152             :                       fib_source_t source)
     153             : {
     154             :     fib_entry_t *fib_entry;
     155             :     fib_entry_src_t *esrc;
     156             : 
     157         552 :     fib_entry = fib_entry_get(fib_entry_index);
     158             : 
     159         552 :     esrc = fib_entry_src_find(fib_entry, source);
     160             : 
     161         552 :     if (NULL == esrc)
     162             :     {
     163          84 :         return (0);
     164             :     }
     165             :     else
     166             :     {
     167         468 :         return (!!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_STALE));
     168             :     }
     169             : }
     170             : 
     171             : void
     172         468 : fib_entry_mark (fib_node_index_t fib_entry_index,
     173             :                 fib_source_t source)
     174             : {
     175             :     fib_entry_t *fib_entry;
     176             :     fib_entry_src_t *esrc;
     177             : 
     178         468 :     fib_entry = fib_entry_get(fib_entry_index);
     179             : 
     180         468 :     esrc = fib_entry_src_find(fib_entry, source);
     181             : 
     182         468 :     if (NULL != esrc)
     183             :     {
     184         468 :         esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_STALE;
     185             :     }
     186         468 : }
     187             : 
     188             : static fib_entry_src_t *
     189       47283 : fib_entry_src_find_or_create (fib_entry_t *fib_entry,
     190             :                               fib_source_t source,
     191             :                               fib_entry_flag_t flags)
     192             : {
     193             :     fib_entry_src_t *esrc;
     194             : 
     195       47283 :     esrc = fib_entry_src_find(fib_entry, source);
     196             : 
     197       47283 :     if (NULL == esrc)
     198             :     {
     199       45365 :         fib_entry_src_action_init(fib_entry, source, flags);
     200             :     }
     201             : 
     202       47283 :     return (fib_entry_src_find(fib_entry, source));
     203             : }
     204             : 
     205             : static void
     206       35297 : fib_entry_src_action_deinit (fib_entry_t *fib_entry,
     207             :                              fib_source_t source)
     208             : 
     209             : {
     210             :     fib_entry_src_t *esrc;
     211       35297 :     u32 index = ~0;
     212             : 
     213       35297 :     esrc = fib_entry_src_find_i(fib_entry, source, &index);
     214             : 
     215       35297 :     ASSERT(NULL != esrc);
     216             : 
     217       35297 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deinit, (esrc));
     218             : 
     219       35297 :     fib_path_ext_list_flush(&esrc->fes_path_exts);
     220       35297 :     vec_del1(fib_entry->fe_srcs, index);
     221       35297 :     vec_sort_with_function(fib_entry->fe_srcs,
     222             :                            fib_entry_src_cmp_for_sort);
     223       35297 : }
     224             : 
     225             : fib_entry_src_cover_res_t
     226        4289 : fib_entry_src_action_cover_change (fib_entry_t *fib_entry,
     227             :                                    fib_entry_src_t *esrc)
     228             : {
     229        4289 :     FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_change,
     230             :                                         (esrc, fib_entry));
     231             : 
     232          12 :     fib_entry_src_cover_res_t res = {
     233             :         .install = !0,
     234             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     235             :     };
     236          12 :     return (res);
     237             : }
     238             : 
     239             : fib_entry_src_cover_res_t
     240          15 : fib_entry_src_action_cover_update (fib_entry_t *fib_entry,
     241             :                                    fib_entry_src_t *esrc)
     242             : {
     243          15 :     FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_cover_update,
     244             :                                         (esrc, fib_entry));
     245             : 
     246           4 :     fib_entry_src_cover_res_t res = {
     247             :         .install = !0,
     248             :         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
     249             :     };
     250           4 :     return (res);
     251             : }
     252             : 
     253             : typedef struct fib_entry_src_collect_forwarding_ctx_t_
     254             : {
     255             :     load_balance_path_t *next_hops;
     256             :     const fib_entry_t *fib_entry;
     257             :     i32 start_source_index, end_source_index;
     258             :     fib_forward_chain_type_t fct;
     259             :     int n_recursive_constrained;
     260             :     u16 preference;
     261             :     dpo_proto_t payload_proto;
     262             : } fib_entry_src_collect_forwarding_ctx_t;
     263             : 
     264             : /**
     265             :  * @brief Determine whether this FIB entry should use a load-balance MAP
     266             :  * to support PIC edge fast convergence
     267             :  */
     268             : static load_balance_flags_t
     269       79876 : fib_entry_calc_lb_flags (fib_entry_src_collect_forwarding_ctx_t *ctx,
     270             :                          const fib_entry_src_t *esrc)
     271             : {
     272             :     /**
     273             :      * We'll use a LB map if the path-list has multiple recursive paths.
     274             :      * recursive paths implies BGP, and hence scale.
     275             :      */
     276       82501 :     if (ctx->n_recursive_constrained > 1 &&
     277        2625 :         fib_path_list_is_popular(esrc->fes_pl))
     278             :     {
     279        1931 :         return (LOAD_BALANCE_FLAG_USES_MAP);
     280             :     }
     281       77945 :     return (LOAD_BALANCE_FLAG_NONE);
     282             : }
     283             : 
     284             : static int
     285        1457 : fib_entry_src_valid_out_label (mpls_label_t label)
     286             : {
     287        1457 :     return ((MPLS_LABEL_IS_REAL(label) ||
     288          32 :              MPLS_LABEL_POP == label ||
     289          32 :              MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL == label ||
     290        2914 :              MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL == label ||
     291             :              MPLS_IETF_IMPLICIT_NULL_LABEL == label));
     292             : }
     293             : 
     294             : static dpo_proto_t
     295       80209 : fib_prefix_get_payload_proto (const fib_prefix_t *pfx)
     296             : {
     297       80209 :     switch (pfx->fp_proto)
     298             :     {
     299       44694 :     case FIB_PROTOCOL_IP4:
     300       44694 :         return (DPO_PROTO_IP4);
     301       34784 :     case FIB_PROTOCOL_IP6:
     302       34784 :         return (DPO_PROTO_IP6);
     303         731 :     case FIB_PROTOCOL_MPLS:
     304         731 :         return (pfx->fp_payload_proto);
     305             :     }
     306             : 
     307           0 :     ASSERT(0);
     308           0 :     return (DPO_PROTO_IP4);
     309             : }
     310             : 
     311             : static void
     312       72595 : fib_entry_src_get_path_forwarding (fib_node_index_t path_index,
     313             :                                    fib_entry_src_collect_forwarding_ctx_t *ctx)
     314             : {
     315             :     load_balance_path_t *nh;
     316             : 
     317             :     /*
     318             :      * no extension => no out-going label for this path. that's OK
     319             :      * in the case of an IP or EOS chain, but not for non-EOS
     320             :      */
     321       72595 :     switch (ctx->fct)
     322             :     {
     323       69208 :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
     324             :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
     325             :     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
     326             :     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
     327             :     case FIB_FORW_CHAIN_TYPE_BIER:
     328             :         /*
     329             :          * EOS traffic with no label to stack, we need the IP Adj
     330             :          */
     331       69208 :         vec_add2(ctx->next_hops, nh, 1);
     332             : 
     333       69208 :         nh->path_index = path_index;
     334       69208 :         nh->path_weight = fib_path_get_weight(path_index);
     335       69208 :         fib_path_contribute_forwarding(path_index, ctx->fct,
     336       69208 :                                        ctx->payload_proto, &nh->path_dpo);
     337             : 
     338       69208 :         break;
     339        1667 :     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
     340        3046 :         if (fib_path_is_exclusive(path_index) ||
     341        1379 :             fib_path_is_deag(path_index))
     342             :         {
     343         290 :             vec_add2(ctx->next_hops, nh, 1);
     344             : 
     345         290 :             nh->path_index = path_index;
     346         290 :             nh->path_weight = fib_path_get_weight(path_index);
     347         290 :             fib_path_contribute_forwarding(path_index,
     348             :                                            FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
     349         290 :                                            ctx->payload_proto,
     350         290 :                                            &nh->path_dpo);
     351             :         }
     352        1667 :         break;
     353        1720 :     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
     354             :         {
     355             :             /*
     356             :              * no label. we need a chain based on the payload. fixup.
     357             :              */
     358        1720 :             vec_add2(ctx->next_hops, nh, 1);
     359             : 
     360        1720 :             nh->path_index = path_index;
     361        1720 :             nh->path_weight = fib_path_get_weight(path_index);
     362        1720 :             fib_path_contribute_forwarding(path_index,
     363        1720 :                                            ctx->fct,
     364        1720 :                                            ctx->payload_proto,
     365        1720 :                                            &nh->path_dpo);
     366        1720 :             fib_path_stack_mpls_disp(path_index,
     367        1720 :                                      ctx->payload_proto,
     368             :                                      FIB_MPLS_LSP_MODE_PIPE,
     369        1720 :                                      &nh->path_dpo);
     370             : 
     371        1720 :             break;
     372             :         }
     373           0 :     case FIB_FORW_CHAIN_TYPE_ETHERNET:
     374             :     case FIB_FORW_CHAIN_TYPE_NSH:
     375           0 :         ASSERT(0);
     376           0 :         break;
     377             :     }
     378       72595 : }
     379             : 
     380             : static fib_path_list_walk_rc_t
     381      113696 : fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
     382             :                                   fib_node_index_t path_index,
     383             :                                   void *arg)
     384             : {
     385             :     fib_entry_src_collect_forwarding_ctx_t *ctx;
     386             :     const fib_entry_src_t *esrc;
     387             :     fib_path_ext_t *path_ext;
     388             :     u32 n_nhs;
     389             : 
     390      113696 :     ctx = arg;
     391      113696 :     n_nhs = vec_len(ctx->next_hops);
     392             : 
     393             :     /*
     394             :      * walk the paths and extension of the best non-interpose source
     395             :      */
     396      113696 :     esrc = &ctx->fib_entry->fe_srcs[ctx->end_source_index];
     397             : 
     398             :     /*
     399             :      * if the path is not resolved, don't include it.
     400             :      */
     401      113696 :     if (!fib_path_is_resolved(path_index))
     402             :     {
     403       33124 :         return (FIB_PATH_LIST_WALK_CONTINUE);
     404             :     }
     405             : 
     406       80572 :     if (fib_path_is_recursive_constrained(path_index))
     407             :     {
     408       15154 :         ctx->n_recursive_constrained += 1;
     409             :     }
     410       80572 :     if (0xffff == ctx->preference)
     411             :     {
     412             :         /*
     413             :          * not set a preference yet, so the first path we encounter
     414             :          * sets the preference we are collecting.
     415             :          */
     416       57713 :         ctx->preference = fib_path_get_preference(path_index);
     417             :     }
     418       22859 :     else if (ctx->preference != fib_path_get_preference(path_index))
     419             :     {
     420             :         /*
     421             :          * this path does not belong to the same preference as the
     422             :          * previous paths encountered. we are done now.
     423             :          */
     424        6510 :         return (FIB_PATH_LIST_WALK_STOP);
     425             :     }
     426             : 
     427             :     /*
     428             :      * get the matching path-extension for the path being visited.
     429             :      */
     430       74062 :     path_ext = fib_path_ext_list_find_by_path_index(&esrc->fes_path_exts,
     431             :                                                     path_index);
     432             : 
     433       74062 :     if (NULL != path_ext)
     434             :     {
     435       17109 :         switch (path_ext->fpe_type)
     436             :         {
     437        1457 :         case FIB_PATH_EXT_MPLS:
     438        1457 :             if (fib_entry_src_valid_out_label(path_ext->fpe_label_stack[0].fml_value))
     439             :             {
     440             :                 /*
     441             :                  * found a matching extension. stack it to obtain the forwarding
     442             :                  * info for this path.
     443             :                  */
     444        1457 :                 ctx->next_hops =
     445        1457 :                     fib_path_ext_stack(path_ext,
     446        1457 :                                        ctx->payload_proto,
     447        1457 :                                        ctx->fct,
     448             :                                        ctx->next_hops);
     449             :             }
     450             :             else
     451             :             {
     452           0 :                 fib_entry_src_get_path_forwarding(path_index, ctx);
     453             :             }
     454        1457 :             break;
     455       15652 :         case FIB_PATH_EXT_ADJ:
     456       15652 :             if (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & path_ext->fpe_adj_flags)
     457             :             {
     458       15642 :                 fib_entry_src_get_path_forwarding(path_index, ctx);
     459             :             }
     460             :             /*
     461             :              * else
     462             :              *  the path does not refine the cover, meaning that
     463             :              *  the adjacency does/does not match the sub-net on the link.
     464             :              *  So this path does not contribute forwarding.
     465             :              */
     466       15652 :             break;
     467             :         }
     468       17109 :     }
     469             :     else
     470             :     {
     471       56953 :         fib_entry_src_get_path_forwarding(path_index, ctx);
     472             :     }
     473             : 
     474             :     /*
     475             :      * a this point 'ctx' has the DPO the path contributed, plus
     476             :      * any labels from path extensions.
     477             :      * check if there are any interpose sources that want to contribute
     478             :      */
     479       74062 :     if (n_nhs < vec_len(ctx->next_hops))
     480             :     {
     481             :         /*
     482             :          * the path contributed a new choice.
     483             :          */
     484             :         const fib_entry_src_vft_t *vft;
     485             : 
     486             :         /*
     487             :          * roll up the sources that are interposes
     488             :          */
     489             :         i32 index;
     490             : 
     491       72673 :         for (index = ctx->end_source_index;
     492      145391 :              index >= ctx->start_source_index;
     493       72718 :              index--)
     494             :         {
     495             :             const dpo_id_t *interposer;
     496             : 
     497       72718 :             esrc = &ctx->fib_entry->fe_srcs[index];
     498       72718 :             vft = fib_entry_src_get_vft(esrc);
     499             : 
     500       72718 :             if (!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING) ||
     501       72718 :                 !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_INTERPOSE))
     502       72671 :                 continue;
     503             : 
     504          47 :             ASSERT(vft->fesv_contribute_interpose);
     505          47 :             interposer = vft->fesv_contribute_interpose(esrc, ctx->fib_entry);
     506             : 
     507          47 :             if (NULL != interposer)
     508             :             {
     509          47 :                 dpo_id_t clone = DPO_INVALID;
     510             : 
     511          47 :                 dpo_mk_interpose(interposer,
     512          47 :                                  &ctx->next_hops[n_nhs].path_dpo,
     513             :                                  &clone);
     514             : 
     515          47 :                 dpo_copy(&ctx->next_hops[n_nhs].path_dpo, &clone);
     516          47 :                 dpo_reset(&clone);
     517             :             }
     518             :         }
     519             :     }
     520             : 
     521       74062 :     return (FIB_PATH_LIST_WALK_CONTINUE);
     522             : }
     523             : 
     524             : void
     525       80209 : fib_entry_src_mk_lb (fib_entry_t *fib_entry,
     526             :                      fib_source_t source,
     527             :                      fib_forward_chain_type_t fct,
     528             :                      dpo_id_t *dpo_lb)
     529             : {
     530             :     const fib_entry_src_t *esrc;
     531             :     dpo_proto_t lb_proto;
     532             :     u32 start, end;
     533             : 
     534             :     /*
     535             :      * The source passed here is the 'best', i.e. the one the client
     536             :      * wants. however, if it's an interpose then it does not contribute
     537             :      * the forwarding, the next best source that is not an interpose does.
     538             :      * So roll down the sources, to find the best non-interpose
     539             :      */
     540       80209 :     vec_foreach_index (start, fib_entry->fe_srcs)
     541             :     {
     542       80209 :         if (source == fib_entry->fe_srcs[start].fes_src)
     543       80209 :             break;
     544             :     }
     545       80266 :     for (end = start; end < vec_len (fib_entry->fe_srcs); end++)
     546             :     {
     547       80260 :         if (!(fib_entry->fe_srcs[end].fes_entry_flags &
     548       80203 :               FIB_ENTRY_FLAG_INTERPOSE) &&
     549       80203 :             (fib_entry->fe_srcs[end].fes_flags &
     550             :              FIB_ENTRY_SRC_FLAG_CONTRIBUTING))
     551       80203 :             break;
     552             :     }
     553       80209 :     if (end == vec_len(fib_entry->fe_srcs))
     554             :     {
     555             :         /* didn't find any contributing non-interpose sources */
     556           6 :         end = start;
     557             :     }
     558             : 
     559       80209 :     esrc = &fib_entry->fe_srcs[end];
     560             : 
     561             :     /*
     562             :      * If the entry has path extensions then we construct a load-balance
     563             :      * by stacking the extensions on the forwarding chains of the paths.
     564             :      * Otherwise we use the load-balance of the path-list
     565             :      */
     566      160418 :     fib_entry_src_collect_forwarding_ctx_t ctx = {
     567             :         .fib_entry = fib_entry,
     568             :         .next_hops = NULL,
     569             :         .n_recursive_constrained = 0,
     570             :         .fct = fct,
     571             :         .preference = 0xffff,
     572             :         .start_source_index = start,
     573             :         .end_source_index = end,
     574       80209 :         .payload_proto = fib_prefix_get_payload_proto(&fib_entry->fe_prefix),
     575             :     };
     576             : 
     577             :     /*
     578             :      * As an optimisation we allocate the vector of next-hops to be sized
     579             :      * equal to the maximum number of paths we will need, which is also the
     580             :      * most likely number we will need, since in most cases the paths are 'up'.
     581             :      */
     582       80209 :     vec_validate(ctx.next_hops, fib_path_list_get_n_paths(esrc->fes_pl));
     583       80209 :     vec_reset_length(ctx.next_hops);
     584             : 
     585       80209 :     lb_proto = fib_forw_chain_type_to_dpo_proto(fct);
     586             : 
     587       80209 :     fib_path_list_walk(esrc->fes_pl,
     588             :                        fib_entry_src_collect_forwarding,
     589             :                        &ctx);
     590             : 
     591       80209 :     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_EXCLUSIVE)
     592             :     {
     593             :         /*
     594             :          * the client provided the DPO that the entry should link to.
     595             :          * all entries must link to a LB, so if it is an LB already
     596             :          * then we can use it.
     597             :          */
     598        1112 :         if ((1 == vec_len(ctx.next_hops)) &&
     599        1112 :             (DPO_LOAD_BALANCE == ctx.next_hops[0].path_dpo.dpoi_type))
     600             :         {
     601         308 :             dpo_copy(dpo_lb, &ctx.next_hops[0].path_dpo);
     602         308 :             dpo_reset(&ctx.next_hops[0].path_dpo);
     603         308 :             return;
     604             :         }
     605             :     }
     606             : 
     607       79901 :     if (!dpo_id_is_valid(dpo_lb))
     608             :     {
     609             :         /*
     610             :          * first time create
     611             :          */
     612       40658 :         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
     613             :         {
     614           6 :             dpo_set(dpo_lb,
     615             :                     DPO_REPLICATE,
     616             :                     lb_proto,
     617           6 :                     MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
     618             :         }
     619             :         else
     620             :         {
     621             :             fib_protocol_t flow_hash_proto;
     622             :             flow_hash_config_t fhc;
     623             : 
     624             :             /*
     625             :              * if the protocol for the LB we are building does not match that
     626             :              * of the fib_entry (i.e. we are build the [n]EOS LB for an IPv[46]
     627             :              * then the fib_index is not an index that relates to the table
     628             :              * type we need. So get the default flow-hash config instead.
     629             :              */
     630       40652 :             flow_hash_proto = dpo_proto_to_fib(lb_proto);
     631       40652 :             if (fib_entry->fe_prefix.fp_proto != flow_hash_proto)
     632             :             {
     633         375 :                 fhc = fib_table_get_default_flow_hash_config(flow_hash_proto);
     634             :             }
     635             :             else
     636             :             {
     637       40277 :                 fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
     638             :                                                      flow_hash_proto);
     639             :             }
     640             : 
     641       40652 :             dpo_set(dpo_lb,
     642             :                     DPO_LOAD_BALANCE,
     643             :                     lb_proto,
     644             :                     load_balance_create(0, lb_proto, fhc));
     645             :         }
     646             :     }
     647             : 
     648       79901 :     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
     649             :     {
     650             :         /*
     651             :          * MPLS multicast
     652             :          */
     653          25 :         replicate_multipath_update(dpo_lb, ctx.next_hops);
     654             :     }
     655             :     else
     656             :     {
     657       79876 :         load_balance_multipath_update(dpo_lb,
     658       79876 :                                       ctx.next_hops,
     659       79876 :                                       fib_entry_calc_lb_flags(&ctx, esrc));
     660       79876 :         vec_free(ctx.next_hops);
     661             : 
     662             :         /*
     663             :          * if this entry is sourced by the uRPF-exempt source then we
     664             :          * append the always present local0 interface (index 0) to the
     665             :          * uRPF list so it is not empty. that way packets pass the loose check.
     666             :          */
     667       79876 :         index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
     668             : 
     669       79876 :         if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
     670       79875 :                                   FIB_SOURCE_URPF_EXEMPT) ||
     671       84960 :              (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
     672        5085 :             (0 == fib_urpf_check_size(ui)))
     673             :         {
     674             :             /*
     675             :              * The uRPF list we get from the path-list is shared by all
     676             :              * other users of the list, but the uRPF exemption applies
     677             :              * only to this prefix. So we need our own list.
     678             :              */
     679        5085 :             ui = fib_urpf_list_alloc_and_lock();
     680        5085 :             fib_urpf_list_append(ui, 0);
     681        5085 :             fib_urpf_list_bake(ui);
     682        5085 :             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
     683        5085 :             fib_urpf_list_unlock(ui);
     684             :         }
     685             :         else
     686             :         {
     687       74791 :             load_balance_set_urpf(dpo_lb->dpoi_index, ui);
     688             :         }
     689       79876 :         load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
     690       79876 :                                          fib_entry_get_flags_i(fib_entry));
     691             :     }
     692             : }
     693             : 
     694             : void
     695       77739 : fib_entry_src_action_install (fib_entry_t *fib_entry,
     696             :                               fib_source_t source)
     697             : {
     698             :     /*
     699             :      * Install the forwarding chain for the given source into the forwarding
     700             :      * tables
     701             :      */
     702             :     fib_forward_chain_type_t fct;
     703             :     int insert;
     704             : 
     705       77739 :     fct = fib_entry_get_default_chain_type(fib_entry);
     706             : 
     707             :     /*
     708             :      * Every entry has its own load-balance object. All changes to the entry's
     709             :      * forwarding result in an inplace modify of the load-balance. This means
     710             :      * the load-balance object only needs to be added to the forwarding
     711             :      * DB once, when it is created.
     712             :      */
     713       77739 :     insert = !dpo_id_is_valid(&fib_entry->fe_lb);
     714             : 
     715       77739 :     fib_entry_src_mk_lb(fib_entry, source, fct, &fib_entry->fe_lb);
     716             : 
     717       77739 :     ASSERT(dpo_id_is_valid(&fib_entry->fe_lb));
     718       77739 :     FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb);
     719             : 
     720             :     /*
     721             :      * insert the adj into the data-plane forwarding trie
     722             :      */
     723       77739 :     if (insert)
     724             :     {
     725       40613 :        fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
     726             :                                    &fib_entry->fe_prefix,
     727       40613 :                                    &fib_entry->fe_lb);
     728             :     }
     729             : 
     730             :     /*
     731             :      * if any of the other chain types are already created they will need
     732             :      * updating too
     733             :      */
     734             :     fib_entry_delegate_type_t fdt;
     735             :     fib_entry_delegate_t *fed;
     736             : 
     737      777390 :     FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,
     738             :     {
     739             :         fib_entry_src_mk_lb(fib_entry, source,
     740             :                             fib_entry_delegate_type_to_chain_type(fdt),
     741             :                             &fed->fd_dpo);
     742             :     });
     743       77739 : }
     744             : 
     745             : void
     746       37879 : fib_entry_src_action_uninstall (fib_entry_t *fib_entry)
     747             : {
     748             :     /*
     749             :      * uninstall the forwarding chain from the forwarding tables
     750             :      */
     751       37879 :     FIB_ENTRY_DBG(fib_entry, "uninstall");
     752             : 
     753       37879 :     if (dpo_id_is_valid(&fib_entry->fe_lb))
     754             :     {
     755       30572 :         fib_table_fwding_dpo_remove(
     756             :             fib_entry->fe_fib_index,
     757             :             &fib_entry->fe_prefix,
     758       30572 :             &fib_entry->fe_lb);
     759             : 
     760       30572 :         dpo_reset(&fib_entry->fe_lb);
     761             :     }
     762       37879 : }
     763             : 
     764             : static void
     765       78412 : fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
     766             : {
     767       78412 :     fib_node_index_t *entries = NULL;
     768             : 
     769       78412 :     fib_path_list_recursive_loop_detect(path_list_index, &entries);
     770             : 
     771       78412 :     vec_free(entries);
     772       78412 : }
     773             : 
     774             : /*
     775             :  * fib_entry_src_action_copy
     776             :  *
     777             :  * copy a source data from another entry to this one
     778             :  */
     779             : static fib_entry_t *
     780          21 : fib_entry_src_action_copy (fib_entry_t *fib_entry,
     781             :                            const fib_entry_src_t *orig_src)
     782             : {
     783             :     fib_entry_src_t *esrc;
     784             : 
     785          21 :     esrc = fib_entry_src_find_or_create(fib_entry,
     786          21 :                                         orig_src->fes_src,
     787          21 :                                         orig_src->fes_entry_flags);
     788             : 
     789          21 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_copy,
     790             :                              (orig_src, fib_entry, esrc));
     791             : 
     792          21 :     fib_path_list_unlock(esrc->fes_pl);
     793             : 
     794             :     /*
     795             :      * copy over all the data ...
     796             :      */
     797          21 :     esrc->fes_flags = orig_src->fes_flags;
     798          21 :     esrc->fes_pl = orig_src->fes_pl;
     799             : 
     800             :     /*
     801             :      *  ... then update
     802             :      */
     803          21 :     esrc->fes_ref_count = 1;
     804          21 :     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_INHERITED;
     805          21 :     esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
     806             :                          FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
     807          21 :     esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
     808             : 
     809             :     /*
     810             :      * the source owns a lock on the entry
     811             :      */
     812          21 :     fib_path_list_lock(esrc->fes_pl);
     813          21 :     fib_entry_lock(fib_entry_get_index(fib_entry));
     814             : 
     815          21 :     return (fib_entry);
     816             : }
     817             : 
     818             : /*
     819             :  * fib_entry_src_action_update
     820             :  *
     821             :  * copy a source data from another entry to this one
     822             :  */
     823             : static fib_entry_src_t *
     824          35 : fib_entry_src_action_update_from_cover (fib_entry_t *fib_entry,
     825             :                                         const fib_entry_src_t *orig_src)
     826             : {
     827             :     fib_entry_src_t *esrc;
     828             : 
     829          35 :     esrc = fib_entry_src_find_or_create(fib_entry,
     830          35 :                                         orig_src->fes_src,
     831          35 :                                         orig_src->fes_entry_flags);
     832             : 
     833             :     /*
     834             :      * the source owns a lock on the entry
     835             :      */
     836          35 :     fib_path_list_unlock(esrc->fes_pl);
     837          35 :     esrc->fes_pl = orig_src->fes_pl;
     838          35 :     fib_path_list_lock(esrc->fes_pl);
     839             : 
     840          35 :     return (esrc);
     841             : }
     842             : 
     843             : static fib_table_walk_rc_t
     844         106 : fib_entry_src_covered_inherit_add_i (fib_entry_t *fib_entry,
     845             :                                      const fib_entry_src_t *cover_src)
     846             : {
     847             :     fib_entry_src_t *esrc;
     848             : 
     849         106 :     esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
     850             : 
     851         106 :     if (cover_src == esrc)
     852             :     {
     853          49 :         return (FIB_TABLE_WALK_CONTINUE);
     854             :     }
     855             : 
     856          57 :     if (NULL != esrc)
     857             :     {
     858             :         /*
     859             :          * the covered entry already has this source.
     860             :          */
     861          36 :         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
     862             :         {
     863             :             /*
     864             :              * the covered source is itself a COVERED_INHERIT, i.e.
     865             :              * it also pushes this source down the sub-tree.
     866             :              * We consider this more specific covered to be the owner
     867             :              * of the sub-tree from this point down.
     868             :              */
     869           2 :             return (FIB_TABLE_WALK_SUB_TREE_STOP);
     870             :         }
     871          34 :         if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
     872             :         {
     873             :             /*
     874             :              * The covered's source data has been inherited, presumably
     875             :              * from this cover, i.e. this is a modify.
     876             :              */
     877          34 :             esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
     878          34 :             fib_entry_source_change(fib_entry, esrc->fes_src, esrc->fes_src);
     879             :         }
     880             :         else
     881             :         {
     882             :             /*
     883             :              * The covered's source was not inherited and it is also
     884             :              * not inheriting. Nevertheless, it still owns the sub-tree from
     885             :              * this point down.
     886             :              */
     887           0 :             return (FIB_TABLE_WALK_SUB_TREE_STOP);
     888             :         }
     889             :     }
     890             :     else
     891             :     {
     892             :         /*
     893             :          * The covered does not have this source - add it.
     894             :          */
     895             :         fib_source_t best_source;
     896             : 
     897          21 :         best_source = fib_entry_get_best_source(
     898             :             fib_entry_get_index(fib_entry));
     899             : 
     900          21 :         fib_entry_src_action_copy(fib_entry, cover_src);
     901          21 :         fib_entry_source_change(fib_entry, best_source, cover_src->fes_src);
     902             : 
     903             :     }
     904          55 :     return (FIB_TABLE_WALK_CONTINUE);
     905             : }
     906             : 
     907             : static fib_table_walk_rc_t
     908         104 : fib_entry_src_covered_inherit_walk_add (fib_node_index_t fei,
     909             :                                         void *ctx)
     910             : {
     911         104 :     return (fib_entry_src_covered_inherit_add_i(fib_entry_get(fei), ctx));
     912             : }
     913             : 
     914             : static fib_table_walk_rc_t
     915          24 : fib_entry_src_covered_inherit_walk_remove (fib_node_index_t fei,
     916             :                                            void *ctx)
     917             : {
     918             :     fib_entry_src_t *cover_src, *esrc;
     919             :     fib_entry_t *fib_entry;
     920             : 
     921          24 :     fib_entry = fib_entry_get(fei);
     922             : 
     923          24 :     cover_src = ctx;
     924          24 :     esrc = fib_entry_src_find(fib_entry, cover_src->fes_src);
     925             : 
     926          24 :     if (cover_src == esrc)
     927             :     {
     928           8 :         return (FIB_TABLE_WALK_CONTINUE);
     929             :     }
     930             : 
     931          16 :     if (NULL != esrc)
     932             :     {
     933             :         /*
     934             :          * the covered entry already has this source.
     935             :          */
     936          15 :         if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
     937             :         {
     938             :             /*
     939             :              * the covered source is itself a COVERED_INHERIT, i.e.
     940             :              * it also pushes this source down the sub-tree.
     941             :              * We consider this more specific covered to be the owner
     942             :              * of the sub-tree from this point down.
     943             :              */
     944           1 :             return (FIB_TABLE_WALK_SUB_TREE_STOP);
     945             :         }
     946          14 :         if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED)
     947             :         {
     948             :             /*
     949             :              * The covered's source data has been inherited, presumably
     950             :              * from this cover
     951             :              */
     952             :             fib_entry_src_flag_t remaining;
     953             : 
     954          14 :             remaining = fib_entry_special_remove(fei, cover_src->fes_src);
     955             : 
     956          14 :             ASSERT(FIB_ENTRY_SRC_FLAG_ADDED == remaining);
     957             :         }
     958             :         else
     959             :         {
     960             :             /*
     961             :              * The covered's source was not inherited and it is also
     962             :              * not inheriting. Nevertheless, it still owns the sub-tree from
     963             :              * this point down.
     964             :              */
     965           0 :             return (FIB_TABLE_WALK_SUB_TREE_STOP);
     966             :         }
     967             :     }
     968             :     else
     969             :     {
     970             :         /*
     971             :          * The covered does not have this source - that's an error,
     972             :          * since it should have inherited, but there is nothing we can do
     973             :          * about it now.
     974             :          */
     975             :     }
     976          15 :     return (FIB_TABLE_WALK_CONTINUE);
     977             : }
     978             : 
     979             : void
     980       36564 : fib_entry_src_inherit (const fib_entry_t *cover,
     981             :                        fib_entry_t *covered)
     982             : {
     983             :     CLIB_UNUSED(fib_source_t source);
     984             :     const fib_entry_src_t *src;
     985             : 
     986       73197 :     FOR_EACH_SRC_ADDED(cover, src, source,
     987             :     ({
     988             :         if ((src->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
     989             :             (src->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
     990             :         {
     991             :             fib_entry_src_covered_inherit_add_i(covered, src);
     992             :         }
     993             :     }))
     994       36564 : }
     995             : 
     996             : static void
     997       44216 : fib_entry_src_covered_inherit_add (fib_entry_t *fib_entry,
     998             :                                    fib_source_t source)
     999             : 
    1000             : {
    1001             :     fib_entry_src_t *esrc;
    1002             : 
    1003       44216 :     esrc = fib_entry_src_find(fib_entry, source);
    1004             : 
    1005       44216 :     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
    1006             : 
    1007       44216 :     if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) ||
    1008       44202 :         (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
    1009             :     {
    1010          54 :         fib_table_sub_tree_walk(fib_entry->fe_fib_index,
    1011          54 :                                 fib_entry->fe_prefix.fp_proto,
    1012             :                                 &fib_entry->fe_prefix,
    1013             :                                 fib_entry_src_covered_inherit_walk_add,
    1014             :                                 esrc);
    1015             :     }
    1016       44216 : }
    1017             : 
    1018             : static void
    1019       31479 : fib_entry_src_covered_inherit_remove (fib_entry_t *fib_entry,
    1020             :                                       fib_entry_src_t *esrc)
    1021             : 
    1022             : {
    1023       31479 :     ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
    1024             : 
    1025       31479 :     if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT)
    1026             :     {
    1027           8 :         fib_table_sub_tree_walk(fib_entry->fe_fib_index,
    1028           8 :                                 fib_entry->fe_prefix.fp_proto,
    1029             :                                 &fib_entry->fe_prefix,
    1030             :                                 fib_entry_src_covered_inherit_walk_remove,
    1031             :                                 esrc);
    1032             :     }
    1033       31479 : }
    1034             : 
    1035             : void
    1036       41497 : fib_entry_src_action_activate (fib_entry_t *fib_entry,
    1037             :                                fib_source_t source)
    1038             : 
    1039             : {
    1040             :     int houston_we_are_go_for_install;
    1041             :     const fib_entry_src_vft_t *vft;
    1042             :     fib_entry_src_t *esrc;
    1043             : 
    1044       41497 :     esrc = fib_entry_src_find(fib_entry, source);
    1045             : 
    1046       41497 :     ASSERT(!(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE));
    1047       41497 :     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
    1048             : 
    1049       41497 :     esrc->fes_flags |= (FIB_ENTRY_SRC_FLAG_ACTIVE |
    1050             :                         FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
    1051       41497 :     vft = fib_entry_src_get_vft(esrc);
    1052             : 
    1053       41497 :     if (NULL != vft->fesv_activate)
    1054             :     {
    1055       24404 :         houston_we_are_go_for_install = vft->fesv_activate(esrc, fib_entry);
    1056             :     }
    1057             :     else
    1058             :     {
    1059             :         /*
    1060             :          * the source is not providing an activate function, we'll assume
    1061             :          * therefore it has no objection to installing the entry
    1062             :          */
    1063       17093 :         houston_we_are_go_for_install = !0;
    1064             :     }
    1065             : 
    1066             :     /*
    1067             :      * link to the path-list provided by the source, and go check
    1068             :      * if that forms any loops in the graph.
    1069             :      */
    1070       41497 :     fib_entry->fe_parent = esrc->fes_pl;
    1071       41497 :     fib_entry->fe_sibling =
    1072       41497 :         fib_path_list_child_add(fib_entry->fe_parent,
    1073             :                                 FIB_NODE_TYPE_ENTRY,
    1074             :                                 fib_entry_get_index(fib_entry));
    1075             : 
    1076       41497 :     fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
    1077             : 
    1078       41497 :     FIB_ENTRY_DBG(fib_entry, "activate: %d",
    1079             :                   fib_entry->fe_parent);
    1080             : 
    1081             :     /*
    1082             :      * If this source should push its state to covered prefixs, do that now.
    1083             :      */
    1084       41497 :     fib_entry_src_covered_inherit_add(fib_entry, source);
    1085             : 
    1086       41497 :     if (0 != houston_we_are_go_for_install)
    1087             :     {
    1088       41061 :         fib_entry_src_action_install(fib_entry, source);
    1089             :     }
    1090             :     else
    1091             :     {
    1092         436 :         fib_entry_src_action_uninstall(fib_entry);
    1093             :     }
    1094       41497 : }
    1095             : 
    1096             : void
    1097       31479 : fib_entry_src_action_deactivate (fib_entry_t *fib_entry,
    1098             :                                  fib_source_t source)
    1099             : 
    1100             : {
    1101             :     fib_node_index_t path_list_index;
    1102             :     fib_entry_src_t *esrc;
    1103             : 
    1104       31479 :     esrc = fib_entry_src_find(fib_entry, source);
    1105             : 
    1106       31479 :     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
    1107             : 
    1108       31479 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
    1109             :                              (esrc, fib_entry));
    1110             : 
    1111       31479 :     esrc->fes_flags &= ~(FIB_ENTRY_SRC_FLAG_ACTIVE |
    1112             :                          FIB_ENTRY_SRC_FLAG_CONTRIBUTING);
    1113             : 
    1114       31479 :     FIB_ENTRY_DBG(fib_entry, "deactivate: %d", fib_entry->fe_parent);
    1115             : 
    1116             :     /*
    1117             :      * If this source should pull its state from covered prefixs, do that now.
    1118             :      * If this source also has the INHERITED flag set then it has a cover
    1119             :      * that wants to push down forwarding. We only want the covereds to see
    1120             :      * one update.
    1121             :      */
    1122       31479 :     fib_entry_src_covered_inherit_remove(fib_entry, esrc);
    1123             : 
    1124             :     /*
    1125             :      * un-link from an old path-list. Check for any loops this will clear
    1126             :      */
    1127       31479 :     path_list_index = fib_entry->fe_parent;
    1128       31479 :     fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
    1129             : 
    1130       31479 :     fib_entry_recursive_loop_detect_i(path_list_index);
    1131             : 
    1132             :     /*
    1133             :      * this will unlock the path-list, so it may be invalid thereafter.
    1134             :      */
    1135       31479 :     fib_path_list_child_remove(path_list_index, fib_entry->fe_sibling);
    1136       31479 :     fib_entry->fe_sibling = FIB_NODE_INDEX_INVALID;
    1137       31479 : }
    1138             : 
    1139             : static void
    1140       88558 : fib_entry_src_action_fwd_update (const fib_entry_t *fib_entry,
    1141             :                                  fib_source_t source)
    1142             : {
    1143             :     fib_entry_src_t *esrc;
    1144             : 
    1145      185297 :     vec_foreach(esrc, fib_entry->fe_srcs)
    1146             :     {
    1147       96739 :         FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_fwd_update,
    1148             :                                  (esrc, fib_entry, source));
    1149             :     }
    1150       88558 : }
    1151             : 
    1152             : void
    1153       41237 : fib_entry_src_action_reactivate (fib_entry_t *fib_entry,
    1154             :                                  fib_source_t source)
    1155             : {
    1156             :     fib_node_index_t path_list_index;
    1157             :     const fib_entry_src_vft_t *vft;
    1158             :     fib_entry_src_t *esrc;
    1159             :     int remain_installed;
    1160             : 
    1161       41237 :     esrc = fib_entry_src_find(fib_entry, source);
    1162             : 
    1163       41237 :     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE);
    1164             : 
    1165       41237 :     FIB_ENTRY_DBG(fib_entry, "reactivate: %d to %d",
    1166             :                   fib_entry->fe_parent,
    1167             :                   esrc->fes_pl);
    1168             : 
    1169             :     /*
    1170             :      * call the source to reactive and get the go/no-go to remain installed
    1171             :      */
    1172       41237 :     vft = fib_entry_src_get_vft(esrc);
    1173             : 
    1174       41237 :     if (NULL != vft->fesv_reactivate)
    1175             :     {
    1176       14501 :         remain_installed = vft->fesv_reactivate(esrc, fib_entry);
    1177             :     }
    1178             :     else
    1179             :     {
    1180       26736 :         remain_installed = 1;
    1181             :     }
    1182             : 
    1183       41237 :     if (fib_entry->fe_parent != esrc->fes_pl)
    1184             :     {
    1185             :         /*
    1186             :          * un-link from an old path-list. Check for any loops this will clear
    1187             :          */
    1188        2718 :         path_list_index = fib_entry->fe_parent;
    1189        2718 :         fib_entry->fe_parent = FIB_NODE_INDEX_INVALID;
    1190             : 
    1191             :         /*
    1192             :          * temporary lock so it doesn't get deleted when this entry is no
    1193             :          * longer a child.
    1194             :          */
    1195        2718 :         fib_path_list_lock(path_list_index);
    1196             : 
    1197             :         /*
    1198             :          * this entry is no longer a child. after unlinking check if any loops
    1199             :          * were broken
    1200             :          */
    1201        2718 :         fib_path_list_child_remove(path_list_index,
    1202             :                                    fib_entry->fe_sibling);
    1203             : 
    1204        2718 :         fib_entry_recursive_loop_detect_i(path_list_index);
    1205             : 
    1206             :         /*
    1207             :          * link to the path-list provided by the source, and go check
    1208             :          * if that forms any loops in the graph.
    1209             :          */
    1210        2718 :         fib_entry->fe_parent = esrc->fes_pl;
    1211        2718 :         fib_entry->fe_sibling =
    1212        2718 :             fib_path_list_child_add(fib_entry->fe_parent,
    1213             :                                     FIB_NODE_TYPE_ENTRY,
    1214             :                                     fib_entry_get_index(fib_entry));
    1215             : 
    1216        2718 :         fib_entry_recursive_loop_detect_i(fib_entry->fe_parent);
    1217        2718 :         fib_path_list_unlock(path_list_index);
    1218             : 
    1219             :         /*
    1220             :          * If this source should push its state to covered prefixs, do that now.
    1221             :          */
    1222        2718 :         fib_entry_src_covered_inherit_add(fib_entry, source);
    1223             :     }
    1224             : 
    1225       41237 :     if (!remain_installed)
    1226             :     {
    1227        4559 :         fib_entry_src_action_uninstall(fib_entry);
    1228             :     }
    1229             :     else
    1230             :     {
    1231       36678 :         fib_entry_src_action_install(fib_entry, source);
    1232             :     }
    1233       41237 :     fib_entry_src_action_fwd_update(fib_entry, source);
    1234       41237 : }
    1235             : 
    1236             : fib_entry_t *
    1237       47321 : fib_entry_src_action_installed (fib_entry_t *fib_entry,
    1238             :                                 fib_source_t source)
    1239             : {
    1240             :     fib_entry_src_t *esrc;
    1241             : 
    1242       47321 :     esrc = fib_entry_src_find(fib_entry, source);
    1243             : 
    1244       47321 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_installed,
    1245             :                              (esrc, fib_entry));
    1246             : 
    1247       47321 :     fib_entry_src_action_fwd_update(fib_entry, source);
    1248             : 
    1249       47321 :     return (fib_entry);
    1250             : }
    1251             : 
    1252             : /*
    1253             :  * fib_entry_src_action_add
    1254             :  *
    1255             :  * Adding a source can result in a new fib_entry being created, which
    1256             :  * can inturn mean the pool is realloc'd and thus the entry passed as
    1257             :  * an argument it also realloc'd
    1258             :  * @return the original entry
    1259             :  */
    1260             : fib_entry_t *
    1261       47226 : fib_entry_src_action_add (fib_entry_t *fib_entry,
    1262             :                           fib_source_t source,
    1263             :                           fib_entry_flag_t flags,
    1264             :                           const dpo_id_t *dpo)
    1265             : {
    1266             :     fib_entry_src_t *esrc;
    1267             : 
    1268       47226 :     esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
    1269             : 
    1270       47226 :     ASSERT(esrc->fes_ref_count < 255);
    1271       47226 :     esrc->fes_ref_count++;
    1272             : 
    1273       47226 :     if (flags != esrc->fes_entry_flags)
    1274             :     {
    1275           0 :         FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
    1276             :                                  (esrc, fib_entry, flags));
    1277             :     }
    1278       47226 :     esrc->fes_entry_flags = flags;
    1279             : 
    1280       47226 :     if (1 != esrc->fes_ref_count)
    1281             :     {
    1282             :         /*
    1283             :          * we only want to add the source on the 0->1 transition
    1284             :          */
    1285        1882 :         return (fib_entry);
    1286             :     }
    1287             : 
    1288       45344 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
    1289             :                              (esrc,
    1290             :                               fib_entry,
    1291             :                               flags,
    1292             :                               fib_entry_get_dpo_proto(fib_entry),
    1293             :                               dpo));
    1294             : 
    1295       45344 :     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
    1296             : 
    1297       45344 :     fib_path_list_lock(esrc->fes_pl);
    1298             : 
    1299             :     /*
    1300             :      * the source owns a lock on the entry
    1301             :      */
    1302       45344 :     fib_entry_lock(fib_entry_get_index(fib_entry));
    1303             : 
    1304       45344 :     return (fib_entry);
    1305             : }
    1306             : 
    1307             : /*
    1308             :  * fib_entry_src_action_update
    1309             :  *
    1310             :  * Adding a source can result in a new fib_entry being created, which
    1311             :  * can inturn mean the pool is realloc'd and thus the entry passed as
    1312             :  * an argument it also realloc'd
    1313             :  * @return the original entry
    1314             :  */
    1315             : fib_entry_t *
    1316           1 : fib_entry_src_action_update (fib_entry_t *fib_entry,
    1317             :                              fib_source_t source,
    1318             :                              fib_entry_flag_t flags,
    1319             :                              const dpo_id_t *dpo)
    1320             : {
    1321             :     fib_node_index_t old_path_list_index;
    1322             :     fib_entry_src_t *esrc;
    1323             : 
    1324           1 :     esrc = fib_entry_src_find_or_create(fib_entry, source, flags);
    1325             : 
    1326           1 :     if (NULL == esrc)
    1327             :     {
    1328           0 :         return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
    1329             :     }
    1330             : 
    1331           1 :     old_path_list_index = esrc->fes_pl;
    1332           1 :     esrc->fes_entry_flags = flags;
    1333             : 
    1334           1 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_add,
    1335             :                              (esrc,
    1336             :                               fib_entry,
    1337             :                               flags,
    1338             :                               fib_entry_get_dpo_proto(fib_entry),
    1339             :                               dpo));
    1340             : 
    1341           1 :     esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
    1342             : 
    1343           1 :     fib_path_list_lock(esrc->fes_pl);
    1344           1 :     fib_path_list_unlock(old_path_list_index);
    1345             : 
    1346           1 :     return (fib_entry);
    1347             : }
    1348             : 
    1349             : fib_entry_src_flag_t
    1350       37128 : fib_entry_src_action_remove_or_update_inherit (fib_entry_t *fib_entry,
    1351             :                                                fib_source_t source)
    1352             : {
    1353             :     fib_entry_src_t *esrc;
    1354             : 
    1355       37128 :     esrc = fib_entry_src_find(fib_entry, source);
    1356             : 
    1357       37128 :     if (NULL == esrc)
    1358          17 :         return (FIB_ENTRY_SRC_FLAG_ACTIVE);
    1359             : 
    1360       37111 :     if ((esrc->fes_entry_flags & FIB_ENTRY_FLAG_COVERED_INHERIT) &&
    1361           7 :         (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_INHERITED))
    1362             :     {
    1363             :         fib_entry_src_t *cover_src;
    1364             :         fib_node_index_t coveri;
    1365             :         fib_entry_t *cover;
    1366             : 
    1367             :         /*
    1368             :          * this source was pushing inherited state, but so is its
    1369             :          * cover. Now that this source is going away, we need to
    1370             :          * pull the covers forwarding and use it to update the covereds.
    1371             :          * Go grab the path-list from the cover, rather than start a walk from
    1372             :          * the cover, so we don't recursively update this entry.
    1373             :          */
    1374           1 :         coveri = fib_table_get_less_specific(fib_entry->fe_fib_index,
    1375             :                                              &fib_entry->fe_prefix);
    1376             : 
    1377             :         /*
    1378             :          * only the default route has itself as its own cover, but the
    1379             :          * default route cannot have inherited from something else.
    1380             :          */
    1381           1 :         ASSERT(coveri != fib_entry_get_index(fib_entry));
    1382             : 
    1383           1 :         cover = fib_entry_get(coveri);
    1384           1 :         cover_src = fib_entry_src_find(cover, source);
    1385             : 
    1386           1 :         ASSERT(NULL != cover_src);
    1387             : 
    1388           1 :         esrc = fib_entry_src_action_update_from_cover(fib_entry, cover_src);
    1389           1 :         esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_COVERED_INHERIT;
    1390             : 
    1391             :         /*
    1392             :          * Now push the new state from the cover down to the covereds
    1393             :          */
    1394           1 :         fib_entry_src_covered_inherit_add(fib_entry, source);
    1395             : 
    1396           1 :         return (esrc->fes_flags);
    1397             :     }
    1398             :     else
    1399             :     {
    1400       37110 :         return (fib_entry_src_action_remove(fib_entry, source));
    1401             :     }
    1402             : }
    1403             : 
    1404             : fib_entry_src_flag_t
    1405       37117 : fib_entry_src_action_remove (fib_entry_t *fib_entry,
    1406             :                              fib_source_t source)
    1407             : 
    1408             : {
    1409             :     fib_node_index_t old_path_list;
    1410             :     fib_entry_src_flag_t sflags;
    1411             :     fib_entry_src_t *esrc;
    1412             : 
    1413       37117 :     esrc = fib_entry_src_find(fib_entry, source);
    1414             : 
    1415       37117 :     if (NULL == esrc)
    1416           0 :         return (FIB_ENTRY_SRC_FLAG_ACTIVE);
    1417             : 
    1418       37117 :     esrc->fes_ref_count--;
    1419       37117 :     sflags = esrc->fes_flags;
    1420             : 
    1421       37117 :     if (0 != esrc->fes_ref_count)
    1422             :     {
    1423             :         /*
    1424             :          * only remove the source on the 1->0 transisition
    1425             :          */
    1426        1820 :         return (sflags);
    1427             :     }
    1428             : 
    1429       35297 :     if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ACTIVE)
    1430             :     {
    1431       31185 :         fib_entry_src_action_deactivate(fib_entry, source);
    1432             :     }
    1433        4112 :     else if (esrc->fes_flags & FIB_ENTRY_SRC_FLAG_CONTRIBUTING)
    1434             :     {
    1435           9 :         FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_deactivate,
    1436             :                                  (esrc, fib_entry));
    1437           9 :         esrc->fes_flags &= ~FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
    1438             :     }
    1439             : 
    1440       35297 :     old_path_list = esrc->fes_pl;
    1441             : 
    1442       35297 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_remove, (esrc));
    1443             : 
    1444       35297 :     fib_path_list_unlock(old_path_list);
    1445       35297 :     fib_entry_unlock(fib_entry_get_index(fib_entry));
    1446             : 
    1447       35297 :     sflags &= ~FIB_ENTRY_SRC_FLAG_ADDED;
    1448       35297 :     fib_entry_src_action_deinit(fib_entry, source);
    1449             : 
    1450       35297 :     return (sflags);
    1451             : }
    1452             : 
    1453             : /*
    1454             :  * fib_route_attached_cross_table
    1455             :  *
    1456             :  * Return true the the route is attached via an interface that
    1457             :  * is not in the same table as the route
    1458             :  */
    1459             : static int
    1460       48552 : fib_route_attached_cross_table (const fib_entry_t *fib_entry,
    1461             :                                 const fib_route_path_t *rpath)
    1462             : {
    1463       48552 :     const fib_prefix_t *pfx = &fib_entry->fe_prefix;
    1464             : 
    1465       48552 :     switch (pfx->fp_proto)
    1466             :     {
    1467          54 :     case FIB_PROTOCOL_MPLS:
    1468             :         /* MPLS routes are never imported/exported */
    1469          54 :         return (0);
    1470       17672 :     case FIB_PROTOCOL_IP6:
    1471             :         /* Ignore link local addresses these also can't be imported/exported */
    1472       17672 :         if (ip6_address_is_link_local_unicast (&pfx->fp_addr.ip6))
    1473             :         {
    1474        4236 :             return (0);
    1475             :         }
    1476       13436 :         break;
    1477       30826 :     case FIB_PROTOCOL_IP4:
    1478       30826 :         break;
    1479             :     }
    1480             : 
    1481             :     /*
    1482             :      * an attached path and entry's fib index not equal to interface's index
    1483             :      */
    1484       61806 :     if (fib_route_path_is_attached(rpath) &&
    1485       17544 :         fib_entry->fe_fib_index !=
    1486       17544 :         fib_table_get_index_for_sw_if_index(fib_entry_get_proto(fib_entry),
    1487             :                                             rpath->frp_sw_if_index))
    1488             :     {
    1489          10 :         return (!0);
    1490             :     }
    1491       44252 :     return (0);
    1492             : }
    1493             : 
    1494             : fib_path_list_flags_t
    1495       56503 : fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
    1496             : {
    1497       56503 :     fib_path_list_flags_t plf = FIB_PATH_LIST_FLAG_NONE;
    1498             : 
    1499       56503 :     if (eflags & FIB_ENTRY_FLAG_DROP)
    1500             :     {
    1501        6725 :         plf |= FIB_PATH_LIST_FLAG_DROP;
    1502             :     }
    1503       56503 :     if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
    1504             :     {
    1505        1485 :         plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
    1506             :     }
    1507       56503 :     if (eflags & FIB_ENTRY_FLAG_LOCAL)
    1508             :     {
    1509       14443 :         plf |= FIB_PATH_LIST_FLAG_LOCAL;
    1510             :     }
    1511             : 
    1512       56503 :     return (plf);
    1513             : }
    1514             : 
    1515             : static void
    1516       34339 : fib_entry_flags_update (const fib_entry_t *fib_entry,
    1517             :                         const fib_route_path_t *rpaths,
    1518             :                         fib_path_list_flags_t *pl_flags,
    1519             :                         fib_entry_src_t *esrc)
    1520             : {
    1521             :     const fib_route_path_t *rpath;
    1522             : 
    1523       82891 :     vec_foreach(rpath, rpaths)
    1524             :     {
    1525       48552 :         if ((esrc->fes_src == FIB_SOURCE_API) ||
    1526       29197 :             (esrc->fes_src == FIB_SOURCE_CLI))
    1527             :         {
    1528       19383 :             if (fib_route_path_is_attached(rpath))
    1529             :             {
    1530       12437 :                 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
    1531             :             }
    1532             :             else
    1533             :             {
    1534        6946 :                 esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_ATTACHED;
    1535             :             }
    1536       19383 :             if (rpath->frp_flags & FIB_ROUTE_PATH_DEAG)
    1537             :             {
    1538          64 :                 esrc->fes_entry_flags |= FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT;
    1539             :             }
    1540             :         }
    1541       48552 :         if (fib_route_attached_cross_table(fib_entry, rpath) &&
    1542          10 :             !(esrc->fes_entry_flags & FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT))
    1543             :         {
    1544          10 :             esrc->fes_entry_flags |= FIB_ENTRY_FLAG_IMPORT;
    1545             :         }
    1546             :         else
    1547             :         {
    1548       48542 :             esrc->fes_entry_flags &= ~FIB_ENTRY_FLAG_IMPORT;
    1549             :         }
    1550             :     }
    1551       34339 : }
    1552             : 
    1553             : /*
    1554             :  * fib_entry_src_action_add
    1555             :  *
    1556             :  * Adding a source can result in a new fib_entry being created, which
    1557             :  * can inturn mean the pool is realloc'd and thus the entry passed as
    1558             :  * an argument it also realloc'd
    1559             :  * @return the entry
    1560             :  */
    1561             : fib_entry_t*
    1562         357 : fib_entry_src_action_path_add (fib_entry_t *fib_entry,
    1563             :                                fib_source_t source,
    1564             :                                fib_entry_flag_t flags,
    1565             :                                const fib_route_path_t *rpaths)
    1566             : {
    1567             :     fib_node_index_t old_path_list;
    1568             :     fib_path_list_flags_t pl_flags;
    1569             :     fib_entry_src_t *esrc;
    1570             : 
    1571         357 :     esrc = fib_entry_src_find(fib_entry, source);
    1572         357 :     if (NULL == esrc)
    1573             :     {
    1574             :         const dpo_id_t *dpo;
    1575             : 
    1576          68 :         if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
    1577           0 :             dpo = &rpaths->dpo;
    1578             :         } else {
    1579          68 :             dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
    1580             :         }
    1581             : 
    1582             :         fib_entry =
    1583          68 :             fib_entry_src_action_add(fib_entry,
    1584             :                                      source,
    1585             :                                      flags,
    1586             :                                      dpo);
    1587          68 :         esrc = fib_entry_src_find(fib_entry, source);
    1588             :     }
    1589             : 
    1590             :     /*
    1591             :      * we are no doubt modifying a path-list. If the path-list
    1592             :      * is shared, and hence not modifiable, then the index returned
    1593             :      * will be for a different path-list. This FIB entry to needs
    1594             :      * to maintain its lock appropriately.
    1595             :      */
    1596         357 :     old_path_list = esrc->fes_pl;
    1597             : 
    1598         357 :     ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_add));
    1599             : 
    1600         357 :     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
    1601         357 :     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
    1602             : 
    1603         357 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_add,
    1604             :                              (esrc, fib_entry, pl_flags, rpaths));
    1605             : 
    1606         357 :     fib_path_list_lock(esrc->fes_pl);
    1607         357 :     fib_path_list_unlock(old_path_list);
    1608             : 
    1609         357 :     return (fib_entry);
    1610             : }
    1611             : 
    1612             : /*
    1613             :  * fib_entry_src_action_swap
    1614             :  *
    1615             :  * The source is providing new paths to replace the old ones.
    1616             :  * Adding a source can result in a new fib_entry being created, which
    1617             :  * can inturn mean the pool is realloc'd and thus the entry passed as
    1618             :  * an argument it also realloc'd
    1619             :  * @return the entry
    1620             :  */
    1621             : fib_entry_t*
    1622       28385 : fib_entry_src_action_path_swap (fib_entry_t *fib_entry,
    1623             :                                 fib_source_t source,
    1624             :                                 fib_entry_flag_t flags,
    1625             :                                 const fib_route_path_t *rpaths)
    1626             : {
    1627             :     fib_node_index_t old_path_list;
    1628             :     fib_path_list_flags_t pl_flags;
    1629             :     fib_entry_src_t *esrc;
    1630             : 
    1631       28385 :     esrc = fib_entry_src_find(fib_entry, source);
    1632             : 
    1633       28385 :     if (NULL == esrc)
    1634             :     {
    1635             :         const dpo_id_t *dpo;
    1636             : 
    1637         188 :         if (flags == FIB_ENTRY_FLAG_EXCLUSIVE) {
    1638           0 :             dpo = &rpaths->dpo;
    1639             :         } else {
    1640         188 :             dpo = drop_dpo_get(fib_entry_get_dpo_proto(fib_entry));
    1641             :         }
    1642             : 
    1643         188 :         fib_entry = fib_entry_src_action_add(fib_entry,
    1644             :                                              source,
    1645             :                                              flags,
    1646             :                                              dpo);
    1647         188 :         esrc = fib_entry_src_find(fib_entry, source);
    1648             :     }
    1649             :     else
    1650             :     {
    1651       28197 :         if (flags != esrc->fes_entry_flags)
    1652             :         {
    1653        2173 :             FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_flags_change,
    1654             :                                      (esrc, fib_entry, flags));
    1655             :         }
    1656       28197 :         esrc->fes_entry_flags = flags;
    1657             :     }
    1658             : 
    1659             :     /*
    1660             :      * swapping paths may create a new path-list (or may use an existing shared)
    1661             :      * but we are certainly getting a different one. This FIB entry to needs
    1662             :      * to maintain its lock appropriately.
    1663             :      */
    1664       28385 :     old_path_list = esrc->fes_pl;
    1665             : 
    1666       28385 :     ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_swap));
    1667             : 
    1668       28385 :     pl_flags = fib_entry_src_flags_2_path_list_flags(flags);
    1669             : 
    1670       28385 :     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
    1671             : 
    1672       28385 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_swap,
    1673             :                              (esrc, fib_entry,
    1674             :                               pl_flags, rpaths));
    1675             : 
    1676       28385 :     fib_path_list_lock(esrc->fes_pl);
    1677       28385 :     fib_path_list_unlock(old_path_list);
    1678             : 
    1679       28385 :     return (fib_entry);
    1680             : }
    1681             : 
    1682             : fib_entry_src_flag_t
    1683        5597 : fib_entry_src_action_path_remove (fib_entry_t *fib_entry,
    1684             :                                   fib_source_t source,
    1685             :                                   const fib_route_path_t *rpaths)
    1686             : {
    1687             :     fib_path_list_flags_t pl_flags;
    1688             :     fib_node_index_t old_path_list;
    1689             :     fib_entry_src_t *esrc;
    1690             : 
    1691        5597 :     esrc = fib_entry_src_find(fib_entry, source);
    1692             : 
    1693        5597 :     ASSERT(NULL != esrc);
    1694        5597 :     ASSERT(esrc->fes_flags & FIB_ENTRY_SRC_FLAG_ADDED);
    1695             : 
    1696             :     /*
    1697             :      * we no doubt modifying a path-list. If the path-list
    1698             :      * is shared, and hence not modifiable, then the index returned
    1699             :      * will be for a different path-list. This FIB entry to needs
    1700             :      * to maintain its lock appropriately.
    1701             :      */
    1702        5597 :     old_path_list = esrc->fes_pl;
    1703             : 
    1704        5597 :     ASSERT(FIB_ENTRY_SRC_VFT_EXISTS(esrc, fesv_path_remove));
    1705             : 
    1706        5597 :     pl_flags = fib_entry_src_flags_2_path_list_flags(fib_entry_get_flags_i(fib_entry));
    1707        5597 :     fib_entry_flags_update(fib_entry, rpaths, &pl_flags, esrc);
    1708             : 
    1709        5597 :     FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_path_remove,
    1710             :                              (esrc, pl_flags, rpaths));
    1711             : 
    1712             :     /*
    1713             :      * lock the new path-list, unlock the old if it had one
    1714             :      */
    1715        5597 :     fib_path_list_unlock(old_path_list);
    1716             : 
    1717        5597 :     if (FIB_NODE_INDEX_INVALID != esrc->fes_pl) {
    1718          16 :         fib_path_list_lock(esrc->fes_pl);
    1719          16 :         return (FIB_ENTRY_SRC_FLAG_ADDED);
    1720             :     }
    1721             :     else
    1722             :     {
    1723             :         /*
    1724             :          * no more paths left from this source
    1725             :          */
    1726        5581 :         fib_entry_src_action_remove_or_update_inherit(fib_entry, source);
    1727        5581 :         return (FIB_ENTRY_SRC_FLAG_NONE);
    1728             :     }
    1729             : }
    1730             : 
    1731             : u8*
    1732         216 : fib_entry_src_format (fib_entry_t *fib_entry,
    1733             :                       fib_source_t source,
    1734             :                       u8* s)
    1735             : {
    1736             :     fib_entry_src_t *esrc;
    1737             : 
    1738         216 :     esrc = fib_entry_src_find(fib_entry, source);
    1739             : 
    1740         216 :     FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_format, (esrc, s));
    1741             : 
    1742         145 :     return (s);
    1743             : }
    1744             : 
    1745             : adj_index_t
    1746           0 : fib_entry_get_adj_for_source (fib_node_index_t fib_entry_index,
    1747             :                               fib_source_t source)
    1748             : {
    1749             :     fib_entry_t *fib_entry;
    1750             :     fib_entry_src_t *esrc;
    1751             : 
    1752           0 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
    1753           0 :         return (ADJ_INDEX_INVALID);
    1754             : 
    1755           0 :     fib_entry = fib_entry_get(fib_entry_index);
    1756           0 :     esrc = fib_entry_src_find(fib_entry, source);
    1757             : 
    1758           0 :     if (NULL != esrc)
    1759             :     {
    1760           0 :         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
    1761             :         {
    1762           0 :             return (fib_path_list_get_adj(
    1763             :                         esrc->fes_pl,
    1764           0 :                         fib_entry_get_default_chain_type(fib_entry)));
    1765             :         }
    1766             :     }
    1767           0 :     return (ADJ_INDEX_INVALID);
    1768             : }
    1769             : 
    1770             : const int
    1771           0 : fib_entry_get_dpo_for_source (fib_node_index_t fib_entry_index,
    1772             :                               fib_source_t source,
    1773             :                               dpo_id_t *dpo)
    1774             : {
    1775             :     fib_entry_t *fib_entry;
    1776             :     fib_entry_src_t *esrc;
    1777             : 
    1778           0 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
    1779           0 :         return (0);
    1780             : 
    1781           0 :     fib_entry = fib_entry_get(fib_entry_index);
    1782           0 :     esrc = fib_entry_src_find(fib_entry, source);
    1783             : 
    1784           0 :     if (NULL != esrc)
    1785             :     {
    1786           0 :         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
    1787             :         {
    1788           0 :             fib_path_list_contribute_forwarding(
    1789             :                 esrc->fes_pl,
    1790           0 :                 fib_entry_get_default_chain_type(fib_entry),
    1791             :                 FIB_PATH_LIST_FWD_FLAG_NONE,
    1792             :                 dpo);
    1793             : 
    1794           0 :             return (dpo_id_is_valid(dpo));
    1795             :         }
    1796             :     }
    1797           0 :     return (0);
    1798             : }
    1799             : 
    1800             : fib_node_index_t
    1801           0 : fib_entry_get_path_list_for_source (fib_node_index_t fib_entry_index,
    1802             :                                     fib_source_t source)
    1803             : {
    1804             :   fib_entry_t *fib_entry;
    1805             :   fib_entry_src_t *esrc;
    1806             : 
    1807           0 :   if (FIB_NODE_INDEX_INVALID == fib_entry_index)
    1808           0 :     return FIB_NODE_INDEX_INVALID;
    1809             : 
    1810           0 :   fib_entry = fib_entry_get(fib_entry_index);
    1811           0 :   esrc = fib_entry_src_find(fib_entry, source);
    1812             : 
    1813           0 :   if (esrc)
    1814           0 :     return esrc->fes_pl;
    1815             : 
    1816           0 :   return FIB_NODE_INDEX_INVALID;
    1817             : }
    1818             : 
    1819             : u32
    1820        2121 : fib_entry_get_resolving_interface_for_source (fib_node_index_t entry_index,
    1821             :                                               fib_source_t source)
    1822             : {
    1823             :     fib_entry_t *fib_entry;
    1824             :     fib_entry_src_t *esrc;
    1825             : 
    1826        2121 :     fib_entry = fib_entry_get(entry_index);
    1827             : 
    1828        2121 :     esrc = fib_entry_src_find(fib_entry, source);
    1829             : 
    1830        2121 :     if (NULL != esrc)
    1831             :     {
    1832        2121 :         if (FIB_NODE_INDEX_INVALID != esrc->fes_pl)
    1833             :         {
    1834        2121 :             return (fib_path_list_get_resolving_interface(esrc->fes_pl));
    1835             :         }
    1836             :     }
    1837           0 :     return (~0);
    1838             : }
    1839             : 
    1840             : fib_entry_flag_t
    1841       20578 : fib_entry_get_flags_for_source (fib_node_index_t entry_index,
    1842             :                                 fib_source_t source)
    1843             : {
    1844             :     fib_entry_t *fib_entry;
    1845             :     fib_entry_src_t *esrc;
    1846             : 
    1847       20578 :     fib_entry = fib_entry_get(entry_index);
    1848             : 
    1849       20578 :     esrc = fib_entry_src_find(fib_entry, source);
    1850             : 
    1851       20578 :     if (NULL != esrc)
    1852             :     {
    1853       18117 :         return (esrc->fes_entry_flags);
    1854             :     }
    1855             : 
    1856        2461 :     return (FIB_ENTRY_FLAG_NONE);
    1857             : }
    1858             : 
    1859             : fib_source_t
    1860      413851 : fib_entry_get_source_i (const fib_entry_t *fib_entry)
    1861             : {
    1862             :     /* the vector of sources is deliberately arranged in priority order */
    1863      413851 :     if (0 == vec_len(fib_entry->fe_srcs))
    1864       71279 :         return (FIB_SOURCE_INVALID);
    1865      342572 :     return (vec_elt(fib_entry->fe_srcs, 0).fes_src);
    1866             : }
    1867             : 
    1868             : fib_entry_flag_t
    1869      673462 : fib_entry_get_flags_i (const fib_entry_t *fib_entry)
    1870             : {
    1871             :     /* the vector of sources is deliberately arranged in priority order */
    1872      673462 :     if (0 == vec_len(fib_entry->fe_srcs))
    1873      132999 :         return (FIB_ENTRY_FLAG_NONE);
    1874      540463 :     return (vec_elt(fib_entry->fe_srcs, 0).fes_entry_flags);
    1875             : }
    1876             : 
    1877             : void
    1878         281 : fib_entry_set_source_data (fib_node_index_t fib_entry_index,
    1879             :                            fib_source_t source,
    1880             :                            const void *data)
    1881             : {
    1882             :     fib_entry_t *fib_entry;
    1883             :     fib_entry_src_t *esrc;
    1884             : 
    1885         281 :     fib_entry = fib_entry_get(fib_entry_index);
    1886         281 :     esrc = fib_entry_src_find(fib_entry, source);
    1887             : 
    1888         281 :     if (NULL != esrc)
    1889             :     {
    1890         281 :         FIB_ENTRY_SRC_VFT_INVOKE(fib_entry, esrc, fesv_set_data,
    1891             :                                  (esrc, fib_entry, data));
    1892             :     }
    1893         281 : }
    1894             : 
    1895             : const void*
    1896         140 : fib_entry_get_source_data (fib_node_index_t fib_entry_index,
    1897             :                            fib_source_t source)
    1898             : {
    1899             :     fib_entry_t *fib_entry;
    1900             :     fib_entry_src_t *esrc;
    1901             : 
    1902         140 :     fib_entry = fib_entry_get(fib_entry_index);
    1903         140 :     esrc = fib_entry_src_find(fib_entry, source);
    1904             : 
    1905         140 :     if (NULL != esrc)
    1906             :     {
    1907         140 :         FIB_ENTRY_SRC_VFT_INVOKE_AND_RETURN(esrc, fesv_get_data,
    1908             :                                             (esrc, fib_entry));
    1909             :     }
    1910           0 :     return (NULL);
    1911             : }
    1912             : 
    1913             : void
    1914         575 : fib_entry_src_module_init (void)
    1915             : {
    1916         575 :     fib_entry_src_rr_register();
    1917         575 :     fib_entry_src_interface_register();
    1918         575 :     fib_entry_src_interpose_register();
    1919         575 :     fib_entry_src_drop_register();
    1920         575 :     fib_entry_src_simple_register();
    1921         575 :     fib_entry_src_api_register();
    1922         575 :     fib_entry_src_adj_register();
    1923         575 :     fib_entry_src_mpls_register();
    1924         575 :     fib_entry_src_lisp_register();
    1925         575 : }

Generated by: LCOV version 1.14