LCOV - code coverage report
Current view: top level - vnet/mfib - mfib_entry.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 482 540 89.3 %
Date: 2023-10-26 01:39:38 Functions: 62 70 88.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vlib/vlib.h>
      17             : 
      18             : #include <vnet/mfib/mfib_entry.h>
      19             : #include <vnet/mfib/mfib_entry_src.h>
      20             : #include <vnet/mfib/mfib_entry_cover.h>
      21             : #include <vnet/fib/fib_path_list.h>
      22             : #include <vnet/fib/fib_walk.h>
      23             : 
      24             : #include <vnet/dpo/drop_dpo.h>
      25             : #include <vnet/dpo/replicate_dpo.h>
      26             : 
      27             : /**
      28             :  * the logger
      29             :  */
      30             : vlib_log_class_t mfib_entry_logger;
      31             : 
      32             : /**
      33             :  * Pool of path extensions
      34             :  */
      35             : static mfib_path_ext_t *mfib_path_ext_pool;
      36             : 
      37             : /**
      38             :  * String names for each source
      39             :  */
      40             : static const char *mfib_source_names[] = MFIB_SOURCE_NAMES;
      41             : static const char *mfib_src_attribute_names[] = MFIB_ENTRY_SRC_ATTRIBUTES;
      42             : 
      43             : /*
      44             :  * Pool for all fib_entries
      45             :  */
      46             : mfib_entry_t *mfib_entry_pool;
      47             : 
      48             : static fib_node_t *
      49      107540 : mfib_entry_get_node (fib_node_index_t index)
      50             : {
      51      107540 :     return ((fib_node_t*)mfib_entry_get(index));
      52             : }
      53             : 
      54             : static fib_protocol_t
      55       90895 : mfib_entry_get_proto (const mfib_entry_t * mfib_entry)
      56             : {
      57       90895 :     return (mfib_entry->mfe_prefix.fp_proto);
      58             : }
      59             : 
      60             : fib_forward_chain_type_t
      61       86870 : mfib_entry_get_default_chain_type (const mfib_entry_t *mfib_entry)
      62             : {
      63       86870 :     switch (mfib_entry->mfe_prefix.fp_proto)
      64             :     {
      65       35604 :     case FIB_PROTOCOL_IP4:
      66       35604 :         return (FIB_FORW_CHAIN_TYPE_MCAST_IP4);
      67       51266 :     case FIB_PROTOCOL_IP6:
      68       51266 :         return (FIB_FORW_CHAIN_TYPE_MCAST_IP6);
      69           0 :     case FIB_PROTOCOL_MPLS:
      70           0 :         ASSERT(0);
      71           0 :         break;
      72             :     }
      73           0 :     return (FIB_FORW_CHAIN_TYPE_MCAST_IP4);
      74             : }
      75             : 
      76             : static u8 *
      77           0 : format_mfib_entry_dpo (u8 * s, va_list * args)
      78             : {
      79           0 :     index_t fei = va_arg(*args, index_t);
      80           0 :     CLIB_UNUSED(u32 indent) = va_arg(*args, u32);
      81             : 
      82           0 :     return (format(s, "%U",
      83             :                    format_mfib_entry, fei,
      84             :                    MFIB_ENTRY_FORMAT_BRIEF));
      85             : }
      86             : 
      87             : static inline mfib_path_ext_t *
      88      181440 : mfib_entry_path_ext_get (index_t mi)
      89             : {
      90      181440 :     return (pool_elt_at_index(mfib_path_ext_pool, mi));
      91             : }
      92             : 
      93             : static u8 *
      94           1 : format_mfib_entry_path_ext (u8 * s, va_list * args)
      95             : {
      96             :     mfib_path_ext_t *path_ext;
      97           1 :     index_t mpi = va_arg(*args, index_t);
      98             : 
      99           1 :     path_ext = mfib_entry_path_ext_get(mpi);
     100           2 :     return (format(s, "path:%d flags:%U",
     101             :                    path_ext->mfpe_path,
     102           1 :                    format_mfib_itf_flags, path_ext->mfpe_flags));
     103             : }
     104             : 
     105             : u8 *
     106           1 : format_mfib_entry_src_flags (u8 *s, va_list *args)
     107             : {
     108             :     mfib_entry_src_attribute_t sattr;
     109           1 :     mfib_entry_src_flags_t flag = va_arg(*args, int);
     110             : 
     111           1 :     if (!flag)
     112             :     {
     113           1 :         return format(s, "none");
     114             :     }
     115             : 
     116           0 :     FOR_EACH_MFIB_SRC_ATTRIBUTE(sattr) {
     117           0 :         if ((1 << sattr) & flag) {
     118           0 :             s = format (s, "%s,", mfib_src_attribute_names[sattr]);
     119             :         }
     120             :     }
     121             : 
     122           0 :     return (s);
     123             : }
     124             : 
     125             : u8 *
     126           5 : format_mfib_entry (u8 * s, va_list * args)
     127             : {
     128             :     fib_node_index_t fei, mfi;
     129             :     mfib_entry_t *mfib_entry;
     130             :     mfib_entry_src_t *msrc;
     131             :     u32 sw_if_index;
     132             :     int level;
     133             : 
     134           5 :     fei = va_arg (*args, fib_node_index_t);
     135           5 :     level = va_arg (*args, int);
     136           5 :     mfib_entry = mfib_entry_get(fei);
     137             : 
     138           5 :     s = format (s, "%U", format_mfib_prefix, &mfib_entry->mfe_prefix);
     139           5 :     s = format (s, ": %U", format_mfib_entry_flags, mfib_entry->mfe_flags);
     140             : 
     141           5 :     if (level >= MFIB_ENTRY_FORMAT_DETAIL)
     142             :     {
     143             :         fib_node_index_t path_index, mpi;
     144             : 
     145           1 :         s = format (s, "\n");
     146           1 :         s = format (s, " fib:%d", mfib_entry->mfe_fib_index);
     147           1 :         s = format (s, " index:%d", mfib_entry_get_index(mfib_entry));
     148           1 :         s = format (s, " locks:%d\n", mfib_entry->mfe_node.fn_locks);
     149           2 :         vec_foreach(msrc, mfib_entry->mfe_srcs)
     150             :         {
     151           1 :             s = format (s, "  src:%s flags:%U locks:%d:",
     152           1 :                         mfib_source_names[msrc->mfes_src],
     153           1 :                         format_mfib_entry_src_flags, msrc->mfes_flags,
     154             :                         msrc->mfes_ref_count);
     155           1 :             if (msrc->mfes_cover != FIB_NODE_INDEX_INVALID)
     156             :             {
     157           0 :                 s = format (s, " cover:%d", msrc->mfes_cover);
     158             :             }
     159           1 :             s = format (s, " %U\n", format_mfib_entry_flags, msrc->mfes_route_flags);
     160           1 :             if (FIB_NODE_INDEX_INVALID != msrc->mfes_pl)
     161             :             {
     162           1 :                 s = fib_path_list_format(msrc->mfes_pl, s);
     163             :             }
     164           1 :             s = format (s, "    Extensions:\n");
     165          66 :             hash_foreach(path_index, mpi, msrc->mfes_exts,
     166             :             ({
     167             :                 s = format(s, "     %U\n", format_mfib_entry_path_ext, mpi);
     168             :             }));
     169           1 :             s = format (s, "    Interface-Forwarding:\n");
     170          66 :             hash_foreach(sw_if_index, mfi, msrc->mfes_itfs,
     171             :             ({
     172             :                 s = format(s, "    %U\n", format_mfib_itf, mfi);
     173             :             }));
     174             :         }
     175             :     }
     176             : 
     177           5 :     s = format(s, "\n  Interfaces:");
     178         266 :     hash_foreach(sw_if_index, mfi, mfib_entry->mfe_itfs,
     179             :     ({
     180             :         s = format(s, "\n  %U", format_mfib_itf, mfi);
     181             :     }));
     182           5 :     if (MFIB_RPF_ID_NONE != mfib_entry->mfe_rpf_id)
     183             :     {
     184           1 :         s = format(s, "\n  RPF-ID:%d", mfib_entry->mfe_rpf_id);
     185             :     }
     186           5 :     s = format(s, "\n  %U-chain\n  %U",
     187             :                format_fib_forw_chain_type,
     188           5 :                mfib_entry_get_default_chain_type(mfib_entry),
     189             :                format_dpo_id,
     190             :                &mfib_entry->mfe_rep,
     191             :                2);
     192           5 :     s = format(s, "\n");
     193             : 
     194           5 :     if (level >= MFIB_ENTRY_FORMAT_DETAIL2)
     195             :     {
     196           0 :         s = format(s, "\nchildren:");
     197           0 :         s = fib_node_children_format(mfib_entry->mfe_node.fn_children, s);
     198             :     }
     199             : 
     200           5 :     return (s);
     201             : }
     202             : 
     203             : static mfib_entry_t*
     204       20675 : mfib_entry_from_fib_node (fib_node_t *node)
     205             : {
     206       20675 :     ASSERT(FIB_NODE_TYPE_MFIB_ENTRY == node->fn_type);
     207       20675 :     return ((mfib_entry_t*)node);
     208             : }
     209             : 
     210             : static int
     211           7 : mfib_entry_src_cmp_for_sort (void * v1,
     212             :                              void * v2)
     213             : {
     214           7 :     mfib_entry_src_t *esrc1 = v1, *esrc2 = v2;
     215             : 
     216           7 :     return (esrc1->mfes_src - esrc2->mfes_src);
     217             : }
     218             : 
     219             : static void
     220        8747 : mfib_entry_src_init (mfib_entry_t *mfib_entry,
     221             :                      mfib_source_t source)
     222             : 
     223             : {
     224        8747 :     mfib_entry_src_t esrc = {
     225             :         .mfes_pl = FIB_NODE_INDEX_INVALID,
     226             :         .mfes_route_flags = MFIB_ENTRY_FLAG_NONE,
     227             :         .mfes_src = source,
     228             :         .mfes_cover = FIB_NODE_INDEX_INVALID,
     229             :         .mfes_sibling = FIB_NODE_INDEX_INVALID,
     230             :         .mfes_ref_count = 1,
     231             :     };
     232             : 
     233        8747 :     vec_add1(mfib_entry->mfe_srcs, esrc);
     234        8747 :     vec_sort_with_function(mfib_entry->mfe_srcs,
     235             :                            mfib_entry_src_cmp_for_sort);
     236        8747 : }
     237             : 
     238             : static mfib_entry_src_t *
     239      179781 : mfib_entry_src_find (const mfib_entry_t *mfib_entry,
     240             :                      mfib_source_t source,
     241             :                      u32 *index)
     242             : 
     243             : {
     244             :     mfib_entry_src_t *esrc;
     245             :     int ii;
     246             : 
     247      179781 :     ii = 0;
     248      191919 :     vec_foreach(esrc, mfib_entry->mfe_srcs)
     249             :     {
     250      167052 :         if (esrc->mfes_src == source)
     251             :         {
     252      154914 :             if (NULL != index)
     253             :             {
     254        4039 :                 *index = ii;
     255             :             }
     256      154914 :             return (esrc);
     257             :         }
     258             :         else
     259             :         {
     260       12138 :             ii++;
     261             :         }
     262             :     }
     263             : 
     264       24867 :     return (NULL);
     265             : }
     266             : 
     267             : static mfib_entry_src_t *
     268       32286 : mfib_entry_src_find_or_create (mfib_entry_t *mfib_entry,
     269             :                                mfib_source_t source)
     270             : {
     271             :     mfib_entry_src_t *msrc;
     272             : 
     273       32286 :     msrc = mfib_entry_src_find(mfib_entry, source, NULL);
     274             : 
     275       32286 :     if (NULL == msrc)
     276             :     {
     277        8747 :         mfib_entry_src_init(mfib_entry, source);
     278        8747 :         msrc = mfib_entry_src_find(mfib_entry, source, NULL);
     279             :     }
     280             : 
     281       32286 :     return (msrc);
     282             : }
     283             : 
     284             : static mfib_entry_src_t *
     285        8772 : mfib_entry_src_update (mfib_entry_t *mfib_entry,
     286             :                        mfib_source_t source,
     287             :                        fib_rpf_id_t rpf_id,
     288             :                        mfib_entry_flags_t entry_flags)
     289             : {
     290             :     mfib_entry_src_t *msrc;
     291             : 
     292        8772 :     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
     293             : 
     294        8772 :     msrc->mfes_route_flags = entry_flags;
     295        8772 :     msrc->mfes_rpf_id = rpf_id;
     296        8772 :     msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
     297             : 
     298        8772 :     return (msrc);
     299             : }
     300             : 
     301             : static mfib_entry_src_t *
     302           6 : mfib_entry_src_update_and_lock (mfib_entry_t *mfib_entry,
     303             :                                 mfib_source_t source,
     304             :                                 fib_rpf_id_t rpf_id,
     305             :                                 mfib_entry_flags_t entry_flags)
     306             : {
     307             :     mfib_entry_src_t *msrc;
     308             : 
     309           6 :     msrc = mfib_entry_src_update(mfib_entry, source, rpf_id, entry_flags);
     310             : 
     311           6 :     msrc->mfes_ref_count++;
     312           6 :     msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
     313             : 
     314           6 :     return (msrc);
     315             : }
     316             : 
     317             : mfib_entry_src_t*
     318      175524 : mfib_entry_get_best_src (const mfib_entry_t *mfib_entry)
     319             : {
     320             :     mfib_entry_src_t *bsrc;
     321             : 
     322             :     /*
     323             :      * the enum of sources is deliberately arranged in priority order
     324             :      */
     325      175524 :     if (0 == vec_len(mfib_entry->mfe_srcs))
     326             :     {
     327        4028 :         bsrc = NULL;
     328             :     }
     329             :     else
     330             :     {
     331      171496 :         bsrc = vec_elt_at_index(mfib_entry->mfe_srcs, 0);
     332             :     }
     333             : 
     334      175524 :     return (bsrc);
     335             : }
     336             : 
     337             : static mfib_source_t
     338       82134 : mfib_entry_get_best_source (const mfib_entry_t *mfib_entry)
     339             : {
     340             :     mfib_entry_src_t *bsrc;
     341             : 
     342       82134 :     bsrc = mfib_entry_get_best_src(mfib_entry);
     343             : 
     344       82134 :     return (bsrc->mfes_src);
     345             : }
     346             : 
     347             : int
     348        3887 : mfib_entry_is_sourced (fib_node_index_t mfib_entry_index,
     349             :                        mfib_source_t source)
     350             : {
     351             :     mfib_entry_t *mfib_entry;
     352             : 
     353        3887 :     mfib_entry = mfib_entry_get(mfib_entry_index);
     354             : 
     355        3887 :     return (NULL != mfib_entry_src_find(mfib_entry, source, NULL));
     356             : }
     357             : 
     358             : int
     359         564 : mfib_entry_is_marked (fib_node_index_t mfib_entry_index,
     360             :                       mfib_source_t source)
     361             : {
     362             :     mfib_entry_t *mfib_entry;
     363             :     mfib_entry_src_t *esrc;
     364             : 
     365         564 :     mfib_entry = mfib_entry_get(mfib_entry_index);
     366             : 
     367         564 :     esrc = mfib_entry_src_find(mfib_entry, source, NULL);
     368             : 
     369         564 :     if (NULL == esrc)
     370             :     {
     371          96 :         return (0);
     372             :     }
     373             :     else
     374             :     {
     375         468 :         return (!!(esrc->mfes_flags & MFIB_ENTRY_SRC_FLAG_STALE));
     376             :     }
     377             : }
     378             : 
     379             : void
     380         468 : mfib_entry_mark (fib_node_index_t fib_entry_index,
     381             :                  mfib_source_t source)
     382             : {
     383             :     mfib_entry_t *mfib_entry;
     384             :     mfib_entry_src_t *esrc;
     385             : 
     386         468 :     mfib_entry = mfib_entry_get(fib_entry_index);
     387             : 
     388         468 :     esrc = mfib_entry_src_find(mfib_entry, source, NULL);
     389             : 
     390         468 :     if (NULL != esrc)
     391             :     {
     392         468 :         esrc->mfes_flags |= MFIB_ENTRY_SRC_FLAG_STALE;
     393             :     }
     394         468 : }
     395             : 
     396             : int
     397        7195 : mfib_entry_is_host (fib_node_index_t mfib_entry_index)
     398             : {
     399        7195 :     return (mfib_prefix_is_host(mfib_entry_get_prefix(mfib_entry_index)));
     400             : }
     401             : 
     402             : 
     403             : static void
     404        4033 : mfib_entry_src_flush (mfib_entry_src_t *msrc)
     405             : {
     406             :     u32 sw_if_index;
     407             :     index_t mfii;
     408             : 
     409      236651 :     hash_foreach(sw_if_index, mfii, msrc->mfes_itfs,
     410             :     ({
     411             :         mfib_itf_delete(mfib_itf_get(mfii));
     412             :     }));
     413        4033 :     hash_free(msrc->mfes_itfs);
     414        4033 :     msrc->mfes_itfs = NULL;
     415        4033 :     hash_free(msrc->mfes_exts);
     416        4033 :     msrc->mfes_exts = NULL;
     417        4033 :     fib_path_list_unlock(msrc->mfes_pl);
     418        4033 : }
     419             : 
     420             : static void
     421        4039 : mfib_entry_src_remove (mfib_entry_t *mfib_entry,
     422             :                        mfib_source_t source)
     423             : 
     424             : {
     425             :     mfib_entry_src_t *msrc;
     426        4039 :     u32 index = ~0;
     427             : 
     428        4039 :     msrc = mfib_entry_src_find(mfib_entry, source, &index);
     429             : 
     430        4039 :     if (NULL != msrc)
     431             :     {
     432        4039 :         ASSERT(0 != msrc->mfes_ref_count);
     433        4039 :         msrc->mfes_ref_count--;
     434             : 
     435        4039 :         if (0 == msrc->mfes_ref_count)
     436             :         {
     437        4033 :             mfib_entry_src_deactivate(mfib_entry, msrc);
     438        4033 :             mfib_entry_src_flush(msrc);
     439             : 
     440        4033 :             vec_del1(mfib_entry->mfe_srcs, index);
     441        4033 :             if (vec_len (mfib_entry->mfe_srcs) > 1)
     442           0 :                 vec_sort_with_function(mfib_entry->mfe_srcs,
     443             :                                        mfib_entry_src_cmp_for_sort);
     444             :         }
     445             :     }
     446        4039 : }
     447             : 
     448             : u32
     449           0 : mfib_entry_child_add (fib_node_index_t mfib_entry_index,
     450             :                       fib_node_type_t child_type,
     451             :                       fib_node_index_t child_index)
     452             : {
     453           0 :     return (fib_node_child_add(FIB_NODE_TYPE_MFIB_ENTRY,
     454             :                                mfib_entry_index,
     455             :                                child_type,
     456             :                                child_index));
     457             : };
     458             : 
     459             : void
     460           0 : mfib_entry_child_remove (fib_node_index_t mfib_entry_index,
     461             :                          u32 sibling_index)
     462             : {
     463           0 :     fib_node_child_remove(FIB_NODE_TYPE_MFIB_ENTRY,
     464             :                           mfib_entry_index,
     465             :                           sibling_index);
     466           0 : }
     467             : 
     468             : static mfib_entry_t *
     469        8740 : mfib_entry_alloc (u32 fib_index,
     470             :                   const mfib_prefix_t *prefix,
     471             :                   fib_node_index_t *mfib_entry_index)
     472             : {
     473             :     mfib_entry_t *mfib_entry;
     474             : 
     475        8740 :     pool_get_aligned(mfib_entry_pool, mfib_entry, CLIB_CACHE_LINE_BYTES);
     476             : 
     477        8740 :     fib_node_init(&mfib_entry->mfe_node,
     478             :                   FIB_NODE_TYPE_MFIB_ENTRY);
     479             : 
     480             :     /*
     481             :      * Some of the members require non-default initialisation
     482             :      * so we also init those that don't and thus save on the call to clib_memset.
     483             :      */
     484        8740 :     mfib_entry->mfe_flags = 0;
     485        8740 :     mfib_entry->mfe_fib_index = fib_index;
     486        8740 :     mfib_entry->mfe_prefix = *prefix;
     487        8740 :     mfib_entry->mfe_srcs = NULL;
     488        8740 :     mfib_entry->mfe_itfs = NULL;
     489        8740 :     mfib_entry->mfe_rpf_id = MFIB_RPF_ID_NONE;
     490        8740 :     mfib_entry->mfe_pl = FIB_NODE_INDEX_INVALID;
     491             : 
     492        8740 :     dpo_reset(&mfib_entry->mfe_rep);
     493             : 
     494        8740 :     *mfib_entry_index = mfib_entry_get_index(mfib_entry);
     495             : 
     496        8740 :     MFIB_ENTRY_DBG(mfib_entry, "alloc");
     497             : 
     498        8740 :     return (mfib_entry);
     499             : }
     500             : 
     501             : static inline mfib_path_ext_t *
     502      205638 : mfib_entry_path_ext_find (uword *exts,
     503             :                           fib_node_index_t path_index)
     504             : {
     505             :     uword *p;
     506             : 
     507      205638 :     p = hash_get(exts, path_index);
     508             : 
     509      205638 :     if (NULL != p)
     510             :     {
     511      181439 :         return (mfib_entry_path_ext_get(p[0]));
     512             :     }
     513             : 
     514       24199 :     return (NULL);
     515             : }
     516             : 
     517             : static mfib_path_ext_t*
     518       24139 : mfib_path_ext_add (mfib_entry_src_t *msrc,
     519             :                    fib_node_index_t path_index,
     520             :                    mfib_itf_flags_t mfi_flags)
     521             : {
     522             :     mfib_path_ext_t *path_ext;
     523             : 
     524       24139 :     pool_get(mfib_path_ext_pool, path_ext);
     525             : 
     526       24139 :     path_ext->mfpe_flags = mfi_flags;
     527       24139 :     path_ext->mfpe_path = path_index;
     528             : 
     529       24139 :     hash_set(msrc->mfes_exts, path_index,
     530             :              path_ext - mfib_path_ext_pool);
     531             : 
     532       24139 :     return (path_ext);
     533             : }
     534             : 
     535             : static void
     536       13342 : mfib_path_ext_remove (mfib_entry_src_t *msrc,
     537             :                       fib_node_index_t path_index)
     538             : {
     539             :     mfib_path_ext_t *path_ext;
     540             : 
     541       13342 :     path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
     542             : 
     543       13342 :     hash_unset(msrc->mfes_exts, path_index);
     544       13342 :     pool_put(mfib_path_ext_pool, path_ext);
     545       13342 : }
     546             : 
     547             : typedef struct mfib_entry_collect_forwarding_ctx_t_
     548             : {
     549             :     load_balance_path_t * next_hops;
     550             :     fib_forward_chain_type_t fct;
     551             :     mfib_entry_src_t *msrc;
     552             :     dpo_proto_t payload_proto;
     553             : } mfib_entry_collect_forwarding_ctx_t;
     554             : 
     555             : static fib_path_list_walk_rc_t
     556      183004 : mfib_entry_src_collect_forwarding (fib_node_index_t pl_index,
     557             :                                    fib_node_index_t path_index,
     558             :                                    void *arg)
     559             : {
     560             :     mfib_entry_collect_forwarding_ctx_t *ctx;
     561             :     load_balance_path_t *nh;
     562             : 
     563      183004 :     ctx = arg;
     564             : 
     565             :     /*
     566             :      * if the path is not resolved, don't include it.
     567             :      */
     568      183004 :     if (!fib_path_is_resolved(path_index))
     569             :     {
     570       16857 :         return (FIB_PATH_LIST_WALK_CONTINUE);
     571             :     }
     572             : 
     573             :     /*
     574             :      * If the path is not forwarding to use it
     575             :      */
     576             :     mfib_path_ext_t *path_ext;
     577             :     
     578      166147 :     path_ext = mfib_entry_path_ext_find(ctx->msrc->mfes_exts,
     579             :                                         path_index);
     580             : 
     581      166147 :     if (NULL != path_ext &&
     582      166087 :         !(path_ext->mfpe_flags & MFIB_ITF_FLAG_FORWARD))
     583             :     {
     584       86161 :         return (FIB_PATH_LIST_WALK_CONTINUE);
     585             :     }
     586             :     
     587       79986 :     switch (ctx->fct)
     588             :     {
     589       79986 :     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
     590             :     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
     591             :         /*
     592             :          * EOS traffic with no label to stack, we need the IP Adj
     593             :          */
     594       79986 :         vec_add2(ctx->next_hops, nh, 1);
     595             : 
     596       79986 :         nh->path_index = path_index;
     597       79986 :         nh->path_weight = fib_path_get_weight(path_index);
     598       79986 :         fib_path_contribute_forwarding(path_index, ctx->fct,
     599       79986 :                                        ctx->payload_proto, &nh->path_dpo);
     600       79986 :         break;
     601             : 
     602           0 :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
     603             :     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
     604             :     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
     605             :     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
     606             :     case FIB_FORW_CHAIN_TYPE_ETHERNET:
     607             :     case FIB_FORW_CHAIN_TYPE_NSH:
     608             :     case FIB_FORW_CHAIN_TYPE_BIER:
     609           0 :         ASSERT(0);
     610           0 :         break;
     611             :     }
     612             : 
     613       79986 :     return (FIB_PATH_LIST_WALK_CONTINUE);
     614             : }
     615             : 
     616             : static void
     617       90891 : mfib_entry_stack (mfib_entry_t *mfib_entry,
     618             :                   mfib_entry_src_t *msrc)
     619             : {
     620             :     dpo_proto_t dp;
     621             : 
     622       90891 :     dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
     623             : 
     624             :     /*
     625             :      * unlink the enty from the previous path list.
     626             :      */
     627       90891 :     if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_pl)
     628             :     {
     629       74594 :         fib_path_list_child_remove(mfib_entry->mfe_pl,
     630             :                                    mfib_entry->mfe_sibling);
     631             :     }
     632             : 
     633       90891 :     if (NULL != msrc)
     634             :     {
     635      260595 :         mfib_entry_collect_forwarding_ctx_t ctx = {
     636             :             .next_hops = NULL,
     637       86865 :             .fct = mfib_entry_get_default_chain_type(mfib_entry),
     638             :             .msrc = msrc,
     639       86865 :             .payload_proto = fib_proto_to_dpo(mfib_entry->mfe_prefix.fp_proto),
     640             :         };
     641             : 
     642             :         /*
     643             :          * link the entry to the path-list.
     644             :          * The entry needs to be a child so that we receive the back-walk
     645             :          * updates to recalculate forwarding.
     646             :          */
     647       86865 :         mfib_entry->mfe_pl = msrc->mfes_pl;
     648       86865 :         mfib_entry->mfe_flags = msrc->mfes_route_flags;
     649       86865 :         mfib_entry->mfe_itfs = msrc->mfes_itfs;
     650       86865 :         mfib_entry->mfe_rpf_id = msrc->mfes_rpf_id;
     651             : 
     652       86865 :         if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_pl)
     653             :         {
     654       78127 :             mfib_entry->mfe_sibling =
     655       78127 :                 fib_path_list_child_add(mfib_entry->mfe_pl,
     656             :                                         FIB_NODE_TYPE_MFIB_ENTRY,
     657             :                                         mfib_entry_get_index(mfib_entry));
     658             : 
     659       78127 :             fib_path_list_walk(mfib_entry->mfe_pl,
     660             :                                mfib_entry_src_collect_forwarding,
     661             :                                &ctx);
     662             :         }
     663       86865 :         if (!(MFIB_ENTRY_FLAG_EXCLUSIVE & mfib_entry->mfe_flags))
     664             :         {
     665       86861 :             if (NULL == ctx.next_hops)
     666             :             {
     667             :                 /*
     668             :                  * no next-hops, stack directly on the drop
     669             :                  */
     670        8852 :                 dpo_stack(DPO_MFIB_ENTRY, dp,
     671             :                           &mfib_entry->mfe_rep,
     672             :                           drop_dpo_get(dp));
     673             :             }
     674             :             else
     675             :             {
     676             :                 /*
     677             :                  * each path contirbutes a next-hop. form a replicate
     678             :                  * from those choices.
     679             :                  */
     680      156016 :                 if (!dpo_id_is_valid(&mfib_entry->mfe_rep) ||
     681       78007 :                     dpo_is_drop(&mfib_entry->mfe_rep))
     682             :                 {
     683        7202 :                     dpo_id_t tmp_dpo = DPO_INVALID;
     684             : 
     685        7202 :                     dpo_set(&tmp_dpo,
     686             :                             DPO_REPLICATE, dp,
     687             :                             replicate_create(0, dp));
     688             : 
     689        7202 :                     dpo_stack(DPO_MFIB_ENTRY, dp,
     690             :                               &mfib_entry->mfe_rep,
     691             :                               &tmp_dpo);
     692             : 
     693        7202 :                     dpo_reset(&tmp_dpo);
     694             :                 }
     695       78009 :                 replicate_multipath_update(&mfib_entry->mfe_rep,
     696             :                                            ctx.next_hops);
     697             :             }
     698             :         }
     699             :         else
     700             :         {
     701             :             /*
     702             :              * for exclusive routes the source provided a replicate DPO
     703             :              * which we stashed in the special path list with one path,
     704             :              * so we can stack directly on that.
     705             :              */
     706           4 :             ASSERT(1 == vec_len(ctx.next_hops));
     707             : 
     708           4 :             if (NULL != ctx.next_hops)
     709             :             {
     710           4 :                 dpo_stack(DPO_MFIB_ENTRY, dp,
     711             :                           &mfib_entry->mfe_rep,
     712           4 :                           &ctx.next_hops[0].path_dpo);
     713           4 :                 dpo_reset(&ctx.next_hops[0].path_dpo);
     714           4 :                 vec_free(ctx.next_hops);
     715             :             }
     716             :             else
     717             :             {
     718           0 :                 dpo_stack(DPO_MFIB_ENTRY, dp,
     719             :                           &mfib_entry->mfe_rep,
     720             :                           drop_dpo_get(dp));
     721             :             }
     722             :         }
     723             :     }
     724             :     else
     725             :     {
     726        4026 :         dpo_stack(DPO_MFIB_ENTRY, dp,
     727             :                   &mfib_entry->mfe_rep,
     728             :                   drop_dpo_get(dp));
     729             :     }
     730             : 
     731             :     /*
     732             :      * time for walkies fido.
     733             :      */
     734       90891 :     fib_node_back_walk_ctx_t bw_ctx = {
     735             :         .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
     736             :     };
     737             : 
     738       90891 :     fib_walk_sync(FIB_NODE_TYPE_MFIB_ENTRY,
     739             :                   mfib_entry_get_index(mfib_entry),
     740             :                   &bw_ctx);
     741       90891 : }
     742             : 
     743             : static fib_node_index_t*
     744       23514 : mfib_entry_src_paths_add (mfib_entry_src_t *msrc,
     745             :                           const fib_route_path_t *rpaths)
     746             : {
     747       23514 :     ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_route_flags));
     748             : 
     749       23514 :     msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
     750             : 
     751       23514 :     if (FIB_NODE_INDEX_INVALID == msrc->mfes_pl)
     752             :     {
     753             :         /* A non-shared path-list */
     754        7196 :         msrc->mfes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NO_URPF,
     755             :                                              NULL);
     756        7196 :         fib_path_list_lock(msrc->mfes_pl);
     757             :     }
     758             : 
     759       23514 :     return (fib_path_list_paths_add(msrc->mfes_pl, rpaths));
     760             : }
     761             : 
     762             : static fib_node_index_t*
     763       38894 : mfib_entry_src_paths_remove (mfib_entry_src_t *msrc,
     764             :                              const fib_route_path_t *rpaths)
     765             : {
     766       38894 :     ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_route_flags));
     767             : 
     768       38894 :     msrc->mfes_flags &= ~MFIB_ENTRY_SRC_FLAG_STALE;
     769             : 
     770       38894 :     return (fib_path_list_paths_remove(msrc->mfes_pl, rpaths));
     771             : }
     772             : 
     773             : static void
     774       90891 : mfib_entry_recalculate_forwarding (mfib_entry_t *mfib_entry,
     775             :                                    mfib_source_t old_best)
     776             : {
     777             :     mfib_entry_src_t *bsrc, *osrc;
     778             : 
     779             :     /*
     780             :      * copy the forwarding data from the bast source
     781             :      */
     782       90891 :     bsrc = mfib_entry_get_best_src(mfib_entry);
     783       90891 :     osrc = mfib_entry_src_find(mfib_entry, old_best, NULL);
     784             : 
     785       90891 :     if (NULL != bsrc)
     786             :     {
     787       86865 :         if (bsrc->mfes_src != old_best)
     788             :         {
     789             :             /*
     790             :              * we are changing from one source to another
     791             :              * deactivate the old, and activate the new
     792             :              */
     793        8742 :             mfib_entry_src_deactivate(mfib_entry, osrc);
     794        8742 :             mfib_entry_src_activate(mfib_entry, bsrc);
     795             :         }
     796             :     }
     797             :     else
     798             :     {
     799        4026 :         mfib_entry_src_deactivate(mfib_entry, osrc);
     800             :     }
     801             : 
     802       90891 :     mfib_entry_stack(mfib_entry, bsrc);
     803       90891 :     mfib_entry_cover_update_notify(mfib_entry);
     804       90891 : }
     805             : 
     806             : 
     807             : fib_node_index_t
     808        8740 : mfib_entry_create (u32 fib_index,
     809             :                    mfib_source_t source,
     810             :                    const mfib_prefix_t *prefix,
     811             :                    fib_rpf_id_t rpf_id,
     812             :                    mfib_entry_flags_t entry_flags,
     813             :                    index_t repi)
     814             : {
     815             :     fib_node_index_t mfib_entry_index;
     816             :     mfib_entry_t *mfib_entry;
     817             :     mfib_entry_src_t *msrc;
     818             : 
     819        8740 :     mfib_entry = mfib_entry_alloc(fib_index, prefix,
     820             :                                   &mfib_entry_index);
     821        8740 :     msrc = mfib_entry_src_update(mfib_entry, source,
     822             :                                  rpf_id, entry_flags);
     823             : 
     824        8740 :     if (INDEX_INVALID != repi)
     825             :     {
     826             :         /*
     827             :          * The source is providing its own replicate DPO.
     828             :          * Create a sepcial path-list to manage it, that way
     829             :          * this entry and the source are equivalent to a normal
     830             :          * entry
     831             :          */
     832             :         fib_node_index_t old_pl_index;
     833             :         dpo_proto_t dp;
     834           2 :         dpo_id_t dpo = DPO_INVALID;
     835             : 
     836           2 :         dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
     837           2 :         old_pl_index = msrc->mfes_pl;
     838             : 
     839           2 :         dpo_set(&dpo, DPO_REPLICATE, dp, repi);
     840             : 
     841           2 :         msrc->mfes_pl =
     842           2 :             fib_path_list_create_special(dp,
     843             :                                          FIB_PATH_LIST_FLAG_EXCLUSIVE,
     844             :                                          &dpo);
     845             : 
     846           2 :         dpo_reset(&dpo);
     847           2 :         fib_path_list_lock(msrc->mfes_pl);
     848           2 :         fib_path_list_unlock(old_pl_index);
     849             :     }
     850             : 
     851        8740 :     mfib_entry_recalculate_forwarding(mfib_entry, MFIB_SOURCE_NONE);
     852             : 
     853        8740 :     return (mfib_entry_index);
     854             : }
     855             : 
     856             : static int
     857       41971 : mfib_entry_ok_for_delete (mfib_entry_t *mfib_entry)
     858             : {
     859       41971 :     return (0 == vec_len(mfib_entry->mfe_srcs));
     860             : }
     861             : 
     862             : static int
     863       38926 : mfib_entry_src_ok_for_delete (const mfib_entry_src_t *msrc)
     864             : {
     865       77846 :     return ((INDEX_INVALID == msrc->mfes_cover &&
     866       77822 :              MFIB_ENTRY_FLAG_NONE == msrc->mfes_route_flags &&
     867      116748 :              0 == fib_path_list_get_n_paths(msrc->mfes_pl)) &&
     868         999 :             (0 == hash_elts(msrc->mfes_itfs)));
     869             : 
     870             :     /* return ((MFIB_ENTRY_FLAG_NONE == msrc->mfes_route_flags) && */
     871             :     /*         (0 == fib_path_list_get_n_paths(msrc->mfes_pl)) && */
     872             :     /*         (0 == hash_elts(msrc->mfes_itfs))); */
     873             : }
     874             : 
     875             : 
     876             : static void
     877          32 : mfib_entry_update_i (mfib_entry_t *mfib_entry,
     878             :                      mfib_entry_src_t *msrc,
     879             :                      mfib_source_t current_best,
     880             :                      index_t repi)
     881             : {
     882          32 :     if (INDEX_INVALID != repi)
     883             :     {
     884             :         /*
     885             :          * The source is providing its own replicate DPO.
     886             :          * Create a sepcial path-list to manage it, that way
     887             :          * this entry and the source are equivalent to a normal
     888             :          * entry
     889             :          */
     890             :         fib_node_index_t old_pl_index;
     891             :         dpo_proto_t dp;
     892           2 :         dpo_id_t dpo = DPO_INVALID;
     893             : 
     894           2 :         dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
     895           2 :         old_pl_index = msrc->mfes_pl;
     896             : 
     897           2 :         dpo_set(&dpo, DPO_REPLICATE, dp, repi);
     898             : 
     899           2 :         msrc->mfes_pl =
     900           2 :             fib_path_list_create_special(dp,
     901             :                                          FIB_PATH_LIST_FLAG_EXCLUSIVE,
     902             :                                          &dpo);
     903             : 
     904           2 :         dpo_reset(&dpo);
     905           2 :         fib_path_list_lock(msrc->mfes_pl);
     906           2 :         fib_path_list_unlock(old_pl_index);
     907             :     }
     908             : 
     909          32 :     if (mfib_entry_src_ok_for_delete(msrc))
     910             :     {
     911             :         /*
     912             :          * this source has no interfaces and no flags.
     913             :          * it has nothing left to give - remove it
     914             :          */
     915           2 :         mfib_entry_src_remove(mfib_entry, msrc->mfes_src);
     916             :     }
     917             : 
     918          32 :     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
     919          32 : }
     920             : 
     921             : int
     922           6 : mfib_entry_special_add (fib_node_index_t mfib_entry_index,
     923             :                         mfib_source_t source,
     924             :                         mfib_entry_flags_t entry_flags,
     925             :                         fib_rpf_id_t rpf_id,
     926             :                         index_t repi)
     927             : {
     928             :     mfib_source_t current_best;
     929             :     mfib_entry_t *mfib_entry;
     930             :     mfib_entry_src_t *msrc;
     931             : 
     932           6 :     mfib_entry = mfib_entry_get(mfib_entry_index);
     933           6 :     current_best = mfib_entry_get_best_source(mfib_entry);
     934             : 
     935           6 :     msrc = mfib_entry_src_update_and_lock(mfib_entry, source, rpf_id,
     936             :                                           entry_flags);
     937             : 
     938           6 :     mfib_entry_update_i(mfib_entry, msrc, current_best, repi);
     939             : 
     940           6 :     return (mfib_entry_ok_for_delete(mfib_entry));
     941             : }
     942             : 
     943             : int
     944          26 : mfib_entry_update (fib_node_index_t mfib_entry_index,
     945             :                    mfib_source_t source,
     946             :                    mfib_entry_flags_t entry_flags,
     947             :                    fib_rpf_id_t rpf_id,
     948             :                    index_t repi)
     949             : {
     950             :     mfib_source_t current_best;
     951             :     mfib_entry_t *mfib_entry;
     952             :     mfib_entry_src_t *msrc;
     953             : 
     954          26 :     mfib_entry = mfib_entry_get(mfib_entry_index);
     955          26 :     current_best = mfib_entry_get_best_source(mfib_entry);
     956          26 :     msrc = mfib_entry_src_update(mfib_entry, source, rpf_id, entry_flags);
     957             : 
     958          26 :     mfib_entry_update_i(mfib_entry, msrc, current_best, repi);
     959             : 
     960          26 :     return (mfib_entry_ok_for_delete(mfib_entry));
     961             : }
     962             : 
     963             : static void
     964       17367 : mfib_entry_itf_add (mfib_entry_src_t *msrc,
     965             :                     u32 sw_if_index,
     966             :                     index_t mi)
     967             : {
     968       17367 :     hash_set(msrc->mfes_itfs, sw_if_index, mi);
     969       17367 : }
     970             : 
     971             : static void
     972       12374 : mfib_entry_itf_remove (mfib_entry_src_t *msrc,
     973             :                        u32 sw_if_index)
     974             : {
     975             :     mfib_itf_t *mfi;
     976             : 
     977       12374 :     mfi = mfib_entry_itf_find(msrc->mfes_itfs, sw_if_index);
     978             : 
     979       12374 :     mfib_itf_delete(mfi);
     980             : 
     981       12374 :     hash_unset(msrc->mfes_itfs, sw_if_index);
     982       12374 : }
     983             : 
     984             : static int
     985       39491 : mfib_entry_path_itf_based (const fib_route_path_t *rpath)
     986             : {
     987       78973 :     return (!(rpath->frp_flags & FIB_ROUTE_PATH_BIER_IMP) &&
     988       39482 :             ~0 != rpath->frp_sw_if_index);
     989             : }
     990             : 
     991             : void
     992       23514 : mfib_entry_path_update (fib_node_index_t mfib_entry_index,
     993             :                         mfib_source_t source,
     994             :                         const fib_route_path_t *rpaths)
     995             : {
     996             :     fib_node_index_t* path_indices, path_index;
     997             :     const fib_route_path_t *rpath;
     998             :     mfib_source_t current_best;
     999             :     mfib_path_ext_t *path_ext;
    1000             :     const mfib_prefix_t *pfx;
    1001             :     mfib_entry_t *mfib_entry;
    1002             :     mfib_entry_src_t *msrc;
    1003             :     mfib_itf_flags_t old;
    1004             :     u32 ii;
    1005             : 
    1006       23514 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1007       23514 :     pfx = mfib_entry_get_prefix(mfib_entry_index);
    1008       23514 :     ASSERT(NULL != mfib_entry);
    1009       23514 :     current_best = mfib_entry_get_best_source(mfib_entry);
    1010       23514 :     msrc = mfib_entry_src_find_or_create(mfib_entry, source);
    1011             : 
    1012             :     /*
    1013             :      * add the path to the path-list. If it's a duplicate we'll get
    1014             :      * back the original path.
    1015             :      */
    1016       23514 :     path_indices = mfib_entry_src_paths_add(msrc, rpaths);
    1017             : 
    1018       49663 :     vec_foreach_index(ii, path_indices)
    1019             :     {
    1020       26149 :         path_index = path_indices[ii];
    1021       26149 :         rpath = &rpaths[ii];
    1022             : 
    1023       26149 :         if (FIB_NODE_INDEX_INVALID == path_index)
    1024           0 :             continue;
    1025             : 
    1026             :         /*
    1027             :          * find the path extension for that path
    1028             :          */
    1029       26149 :         path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
    1030             : 
    1031       26149 :         if (NULL == path_ext)
    1032             :         {
    1033       24139 :             old = MFIB_ITF_FLAG_NONE;
    1034       24139 :             path_ext = mfib_path_ext_add(msrc, path_index,
    1035       24139 :                                          rpath->frp_mitf_flags);
    1036             :         }
    1037             :         else
    1038             :         {
    1039        2010 :             old = path_ext->mfpe_flags;
    1040        2010 :             path_ext->mfpe_flags = rpath->frp_mitf_flags;
    1041             :         }
    1042             : 
    1043             :         /*
    1044             :          * Has the path changed its contribution to the input interface set.
    1045             :          * Which only paths with interfaces can do...
    1046             :          */
    1047       26149 :         if (mfib_entry_path_itf_based(rpath))
    1048             :         {
    1049             :             mfib_itf_t *mfib_itf;
    1050             : 
    1051       19379 :             if (old != rpath->frp_mitf_flags)
    1052             :             {
    1053             :                 /*
    1054             :                  * change of flag contributions
    1055             :                  */
    1056       17375 :                 mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
    1057             :                                                rpath->frp_sw_if_index);
    1058             : 
    1059       17375 :                 if (NULL == mfib_itf)
    1060             :                 {
    1061       17367 :                     index_t mfib_itf_i = mfib_itf_create(path_index,
    1062       17367 :                                                          rpath->frp_mitf_flags);
    1063       17367 :                     mfib_entry_itf_add(msrc,
    1064             :                                        rpath->frp_sw_if_index,
    1065             :                                        mfib_itf_i);
    1066             : 
    1067       17367 :                     if (MFIB_ITF_FLAG_ACCEPT & rpath->frp_mitf_flags)
    1068             :                     {
    1069             :                         /* new accepting interface - add the mac to the driver */
    1070       16150 :                         mfib_itf_mac_add(mfib_itf_get(mfib_itf_i), pfx);
    1071             :                     }
    1072             :                 }
    1073             :                 else
    1074             :                 {
    1075           8 :                     u8 was_accept = !!(old & MFIB_ITF_FLAG_ACCEPT);
    1076           8 :                     u8 is_accept = !!(rpath->frp_mitf_flags & MFIB_ITF_FLAG_ACCEPT);
    1077             : 
    1078           8 :                     if (mfib_itf_update(mfib_itf,
    1079             :                                         path_index,
    1080           8 :                                         rpath->frp_mitf_flags))
    1081             :                     {
    1082             :                         /*
    1083             :                          * no more interface flags on this path, remove
    1084             :                          * from the data-plane set
    1085             :                          */
    1086           0 :                         if (was_accept)
    1087             :                         {
    1088           0 :                             mfib_itf_mac_del(mfib_itf, pfx);
    1089             : 
    1090             :                         }
    1091           0 :                         mfib_entry_itf_remove(msrc, rpath->frp_sw_if_index);
    1092             :                     }
    1093             :                     else
    1094             :                     {
    1095             :                         /*
    1096             :                          * is there a change to the ACCEPT flag that
    1097             :                          * requires us to update hte driver with the
    1098             :                          * MAC
    1099             :                          */
    1100           8 :                         if (is_accept != was_accept)
    1101             :                         {
    1102           2 :                             if (is_accept)
    1103             :                             {
    1104           2 :                                 mfib_itf_mac_add(mfib_itf, pfx);
    1105             :                             }
    1106           0 :                             else if (was_accept)
    1107             :                             {
    1108           0 :                                 mfib_itf_mac_del(mfib_itf, pfx);
    1109             :                             }
    1110             :                         }
    1111             :                     }
    1112             :                 }
    1113             :             }
    1114             :         }
    1115             :     }
    1116       23514 :     vec_free(path_indices);
    1117             : 
    1118       23514 :     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
    1119       23514 : }
    1120             : 
    1121             : /*
    1122             :  * mfib_entry_path_remove
    1123             :  *
    1124             :  * remove a path from the entry.
    1125             :  * return the mfib_entry's index if it is still present, INVALID otherwise.
    1126             :  */
    1127             : int
    1128       38899 : mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
    1129             :                         mfib_source_t source,
    1130             :                         const fib_route_path_t *rpaths)
    1131             : {
    1132             :     fib_node_index_t path_index, *path_indices;
    1133             :     const fib_route_path_t *rpath;
    1134             :     mfib_source_t current_best;
    1135             :     const mfib_prefix_t *pfx;
    1136             :     mfib_entry_t *mfib_entry;
    1137             :     mfib_entry_src_t *msrc;
    1138             :     u32 ii;
    1139             : 
    1140       38899 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1141       38899 :     pfx = mfib_entry_get_prefix(mfib_entry_index);
    1142       38899 :     ASSERT(NULL != mfib_entry);
    1143       38899 :     current_best = mfib_entry_get_best_source(mfib_entry);
    1144       38899 :     msrc = mfib_entry_src_find(mfib_entry, source, NULL);
    1145             : 
    1146       38899 :     if (NULL == msrc)
    1147             :     {
    1148             :         /*
    1149             :          * there are no paths left for this source
    1150             :          */
    1151           5 :         return (mfib_entry_ok_for_delete(mfib_entry));
    1152             :     }
    1153             : 
    1154             :     /*
    1155             :      * remove the paths from the path-list. If it's not there we'll get
    1156             :      * back an empty vector
    1157             :      */
    1158       38894 :     path_indices = mfib_entry_src_paths_remove(msrc, rpaths);
    1159             : 
    1160       77825 :     vec_foreach_index(ii, path_indices)
    1161             :     {
    1162       38931 :         path_index = path_indices[ii];
    1163       38931 :         rpath = &rpaths[ii];
    1164             : 
    1165       38931 :         if (FIB_NODE_INDEX_INVALID == path_index)
    1166       25589 :             continue;
    1167             :       
    1168             :         /*
    1169             :          * don't need the extension, nor the interface anymore
    1170             :          */
    1171       13342 :         mfib_path_ext_remove(msrc, path_index);
    1172       13342 :         if (mfib_entry_path_itf_based(rpath))
    1173             :         {
    1174             :             u8 was_accept, is_accept;
    1175             :             mfib_itf_t *mfib_itf;
    1176             : 
    1177       12376 :             mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
    1178             :                                            rpath->frp_sw_if_index);
    1179       12376 :             was_accept = !!(MFIB_ITF_FLAG_ACCEPT & mfib_itf->mfi_flags);
    1180             : 
    1181       12376 :             if (mfib_itf_update(mfib_itf,
    1182             :                                 path_index,
    1183             :                                 MFIB_ITF_FLAG_NONE))
    1184             :             {
    1185       12374 :                 if (was_accept)
    1186             :                 {
    1187       12327 :                     mfib_itf_mac_del(mfib_itf, pfx);                    
    1188             :                 }
    1189             : 
    1190             :                 /*
    1191             :                  * no more interface flags on this path, remove
    1192             :                  * from the data-plane set
    1193             :                  */
    1194       12374 :                 mfib_entry_itf_remove(msrc, rpath->frp_sw_if_index);
    1195             :             }
    1196             :             else
    1197             :             {
    1198           2 :                 is_accept = !!(MFIB_ITF_FLAG_ACCEPT & mfib_itf->mfi_flags);
    1199             : 
    1200           2 :                 if (was_accept && !is_accept)
    1201             :                 {
    1202           0 :                     mfib_itf_mac_del(mfib_itf, pfx);                    
    1203             :                 }
    1204             :             }
    1205             :         }
    1206             :     }
    1207       38894 :     vec_free(path_indices);
    1208             : 
    1209       38894 :     if (mfib_entry_src_ok_for_delete(msrc))
    1210             :       {
    1211             :         /*
    1212             :          * this source has no interfaces and no flags.
    1213             :          * it has nothing left to give - remove it
    1214             :          */
    1215         997 :         mfib_entry_src_remove(mfib_entry, source);
    1216             :       }
    1217             : 
    1218       38894 :     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
    1219             : 
    1220       38894 :     return (mfib_entry_ok_for_delete(mfib_entry));
    1221             : }
    1222             : 
    1223             : /**
    1224             :  * mfib_entry_delete
    1225             :  *
    1226             :  * The source is withdrawing all the paths it provided
    1227             :  */
    1228             : int
    1229        3040 : mfib_entry_delete (fib_node_index_t mfib_entry_index,
    1230             :                    mfib_source_t source)
    1231             : {
    1232             :     mfib_source_t current_best;
    1233             :     mfib_entry_t *mfib_entry;
    1234             : 
    1235        3040 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1236        3040 :     current_best = mfib_entry_get_best_source(mfib_entry);
    1237        3040 :     mfib_entry_src_remove(mfib_entry, source);
    1238             : 
    1239        3040 :     mfib_entry_recalculate_forwarding(mfib_entry, current_best);
    1240             : 
    1241        3040 :     return (mfib_entry_ok_for_delete(mfib_entry));
    1242             : }
    1243             : 
    1244             : static int
    1245        2743 : fib_ip4_address_compare (ip4_address_t * a1,
    1246             :                          ip4_address_t * a2)
    1247             : {
    1248             :     /*
    1249             :      * IP addresses are unsiged ints. the return value here needs to be signed
    1250             :      * a simple subtraction won't cut it.
    1251             :      * If the addresses are the same, the sort order is undefiend, so phoey.
    1252             :      */
    1253        2743 :     return ((clib_net_to_host_u32(a1->data_u32) >
    1254        2743 :              clib_net_to_host_u32(a2->data_u32) ) ?
    1255        2743 :             1 : -1);
    1256             : }
    1257             : 
    1258             : static int
    1259        3093 : fib_ip6_address_compare (ip6_address_t * a1,
    1260             :                          ip6_address_t * a2)
    1261             : {
    1262             :   int i;
    1263       19079 :   for (i = 0; i < ARRAY_LEN (a1->as_u16); i++)
    1264             :   {
    1265       19075 :       int cmp = (clib_net_to_host_u16 (a1->as_u16[i]) -
    1266       19075 :                  clib_net_to_host_u16 (a2->as_u16[i]));
    1267       19075 :       if (cmp != 0)
    1268        3089 :           return cmp;
    1269             :   }
    1270           4 :   return 0;
    1271             : }
    1272             : 
    1273             : static int
    1274        5832 : mfib_entry_cmp (fib_node_index_t mfib_entry_index1,
    1275             :                 fib_node_index_t mfib_entry_index2)
    1276             : {
    1277             :     mfib_entry_t *mfib_entry1, *mfib_entry2;
    1278        5832 :     int cmp = 0;
    1279             : 
    1280        5832 :     mfib_entry1 = mfib_entry_get(mfib_entry_index1);
    1281        5832 :     mfib_entry2 = mfib_entry_get(mfib_entry_index2);
    1282             : 
    1283        5832 :     switch (mfib_entry1->mfe_prefix.fp_proto)
    1284             :     {
    1285        2743 :     case FIB_PROTOCOL_IP4:
    1286        2743 :         cmp = fib_ip4_address_compare(&mfib_entry1->mfe_prefix.fp_grp_addr.ip4,
    1287             :                                       &mfib_entry2->mfe_prefix.fp_grp_addr.ip4);
    1288             : 
    1289        2743 :         if (0 == cmp)
    1290             :         {
    1291           0 :             cmp = fib_ip4_address_compare(&mfib_entry1->mfe_prefix.fp_src_addr.ip4,
    1292             :                                           &mfib_entry2->mfe_prefix.fp_src_addr.ip4);
    1293             :         }
    1294        2743 :         break;
    1295        3089 :     case FIB_PROTOCOL_IP6:
    1296        3089 :         cmp = fib_ip6_address_compare(&mfib_entry1->mfe_prefix.fp_grp_addr.ip6,
    1297             :                                       &mfib_entry2->mfe_prefix.fp_grp_addr.ip6);
    1298             : 
    1299        3089 :         if (0 == cmp)
    1300             :         {
    1301           4 :             cmp = fib_ip6_address_compare(&mfib_entry1->mfe_prefix.fp_src_addr.ip6,
    1302             :                                           &mfib_entry2->mfe_prefix.fp_src_addr.ip6);
    1303             :         }
    1304        3089 :         break;
    1305           0 :     case FIB_PROTOCOL_MPLS:
    1306           0 :         ASSERT(0);
    1307           0 :         cmp = 0;
    1308           0 :         break;
    1309             :     }
    1310             : 
    1311        5832 :     if (0 == cmp) {
    1312           0 :         cmp = (mfib_entry1->mfe_prefix.fp_len - mfib_entry2->mfe_prefix.fp_len);
    1313             :     }
    1314        5832 :     return (cmp);
    1315             : }
    1316             : 
    1317             : int
    1318        5832 : mfib_entry_cmp_for_sort (void *i1, void *i2)
    1319             : {
    1320        5832 :     fib_node_index_t *mfib_entry_index1 = i1, *mfib_entry_index2 = i2;
    1321             : 
    1322        5832 :     return (mfib_entry_cmp(*mfib_entry_index1,
    1323             :                            *mfib_entry_index2));
    1324             : }
    1325             : 
    1326             : static void
    1327        4026 : mfib_entry_last_lock_gone (fib_node_t *node)
    1328             : {
    1329             :     mfib_entry_t *mfib_entry;
    1330             :     mfib_entry_src_t *msrc;
    1331             : 
    1332        4026 :     mfib_entry = mfib_entry_from_fib_node(node);
    1333             : 
    1334        4026 :     dpo_reset(&mfib_entry->mfe_rep);
    1335             : 
    1336        4026 :     MFIB_ENTRY_DBG(mfib_entry, "last-lock");
    1337             : 
    1338        4026 :     vec_foreach(msrc, mfib_entry->mfe_srcs)
    1339             :     {
    1340           0 :         mfib_entry_src_flush(msrc);
    1341             :     }
    1342             : 
    1343        4026 :     vec_free(mfib_entry->mfe_srcs);
    1344             : 
    1345        4026 :     fib_node_deinit(&mfib_entry->mfe_node);
    1346        4026 :     pool_put(mfib_entry_pool, mfib_entry);
    1347        4026 : }
    1348             : 
    1349             : u32
    1350         911 : mfib_entry_get_stats_index (fib_node_index_t fib_entry_index)
    1351             : {
    1352             :     mfib_entry_t *mfib_entry;
    1353             : 
    1354         911 :     mfib_entry = mfib_entry_get(fib_entry_index);
    1355             : 
    1356         911 :     return (mfib_entry->mfe_rep.dpoi_index);
    1357             : }
    1358             : 
    1359             : /*
    1360             :  * mfib_entry_back_walk_notify
    1361             :  *
    1362             :  * A back walk has reach this entry.
    1363             :  */
    1364             : static fib_node_back_walk_rc_t
    1365       16649 : mfib_entry_back_walk_notify (fib_node_t *node,
    1366             :                             fib_node_back_walk_ctx_t *ctx)
    1367             : {
    1368             :     mfib_entry_t *mfib_entry;
    1369             : 
    1370       16649 :     mfib_entry = mfib_entry_from_fib_node(node);
    1371       16649 :     mfib_entry_recalculate_forwarding(mfib_entry,
    1372             :                                       mfib_entry_get_best_source(mfib_entry));
    1373             : 
    1374       16649 :     return (FIB_NODE_BACK_WALK_CONTINUE);
    1375             : }
    1376             : 
    1377             : static void
    1378           1 : mfib_entry_show_memory (void)
    1379             : {
    1380           1 :     fib_show_memory_usage("multicast-Entry",
    1381           1 :                           pool_elts(mfib_entry_pool),
    1382           1 :                           pool_len(mfib_entry_pool),
    1383             :                           sizeof(mfib_entry_t));
    1384           1 : }
    1385             : 
    1386             : /*
    1387             :  * The MFIB entry's graph node virtual function table
    1388             :  */
    1389             : static const fib_node_vft_t mfib_entry_vft = {
    1390             :     .fnv_get = mfib_entry_get_node,
    1391             :     .fnv_last_lock = mfib_entry_last_lock_gone,
    1392             :     .fnv_back_walk = mfib_entry_back_walk_notify,
    1393             :     .fnv_mem_show = mfib_entry_show_memory,
    1394             : };
    1395             : 
    1396             : void
    1397       50703 : mfib_entry_lock (fib_node_index_t mfib_entry_index)
    1398             : {
    1399             :     mfib_entry_t *mfib_entry;
    1400             : 
    1401       50703 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1402             : 
    1403       50703 :     fib_node_lock(&mfib_entry->mfe_node);
    1404       50703 : }
    1405             : 
    1406             : void
    1407       45989 : mfib_entry_unlock (fib_node_index_t mfib_entry_index)
    1408             : {
    1409             :     mfib_entry_t *mfib_entry;
    1410             : 
    1411       45989 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1412             : 
    1413       45989 :     fib_node_unlock(&mfib_entry->mfe_node);
    1414       45989 : }
    1415             : 
    1416             : static void
    1417           0 : mfib_entry_dpo_lock (dpo_id_t *dpo)
    1418             : {
    1419           0 : }
    1420             : static void
    1421           0 : mfib_entry_dpo_unlock (dpo_id_t *dpo)
    1422             : {
    1423           0 : }
    1424             : 
    1425             : const static dpo_vft_t mfib_entry_dpo_vft = {
    1426             :     .dv_lock = mfib_entry_dpo_lock,
    1427             :     .dv_unlock = mfib_entry_dpo_unlock,
    1428             :     .dv_format = format_mfib_entry_dpo,
    1429             :     .dv_mem_show = mfib_entry_show_memory,
    1430             : };
    1431             : 
    1432             : const static char* const mfib_entry_ip4_nodes[] =
    1433             : {
    1434             :     "ip4-mfib-forward-rpf",
    1435             :     NULL,
    1436             : };
    1437             : const static char* const mfib_entry_ip6_nodes[] =
    1438             : {
    1439             :     "ip6-mfib-forward-rpf",
    1440             :     NULL,
    1441             : };
    1442             : 
    1443             : const static char* const * const mfib_entry_nodes[DPO_PROTO_NUM] =
    1444             : {
    1445             :     [DPO_PROTO_IP4]  = mfib_entry_ip4_nodes,
    1446             :     [DPO_PROTO_IP6]  = mfib_entry_ip6_nodes,
    1447             : };
    1448             : 
    1449             : void
    1450         575 : mfib_entry_module_init (void)
    1451             : {
    1452         575 :     fib_node_register_type (FIB_NODE_TYPE_MFIB_ENTRY, &mfib_entry_vft);
    1453         575 :     dpo_register(DPO_MFIB_ENTRY, &mfib_entry_dpo_vft, mfib_entry_nodes);
    1454         575 :     mfib_entry_logger = vlib_log_register_class("mfib", "entry");
    1455         575 : }
    1456             : 
    1457             : fib_route_path_t*
    1458        2451 : mfib_entry_encode (fib_node_index_t mfib_entry_index)
    1459             : {
    1460        2451 :     fib_path_encode_ctx_t ctx = {
    1461             :         .rpaths = NULL,
    1462             :     };
    1463             :     mfib_entry_t *mfib_entry;
    1464             :     fib_route_path_t *rpath;
    1465             :     mfib_entry_src_t *bsrc;
    1466             : 
    1467        2451 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1468        2451 :     bsrc = mfib_entry_get_best_src(mfib_entry);
    1469             : 
    1470        2451 :     if (FIB_NODE_INDEX_INVALID != bsrc->mfes_pl)
    1471             :     {
    1472        2141 :         fib_path_list_walk_w_ext(bsrc->mfes_pl,
    1473             :                                  NULL,
    1474             :                                  fib_path_encode,
    1475             :                                  &ctx);
    1476             :     }
    1477             : 
    1478        8378 :     vec_foreach(rpath, ctx.rpaths)
    1479             :     {
    1480             :         mfib_itf_t *mfib_itf;
    1481             : 
    1482        5927 :         mfib_itf = mfib_entry_itf_find(bsrc->mfes_itfs,
    1483             :                                        rpath->frp_sw_if_index);
    1484        5927 :         if (mfib_itf)
    1485             :         {
    1486        5027 :             rpath->frp_mitf_flags = mfib_itf->mfi_flags;
    1487             :         }
    1488             :     }
    1489             : 
    1490        2451 :     return (ctx.rpaths);
    1491             : }
    1492             : 
    1493             : const mfib_prefix_t *
    1494       74973 : mfib_entry_get_prefix (fib_node_index_t mfib_entry_index)
    1495             : {
    1496             :     mfib_entry_t *mfib_entry;
    1497             : 
    1498       74973 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1499             : 
    1500       74973 :     return (&mfib_entry->mfe_prefix);
    1501             : }
    1502             : 
    1503             : u32
    1504        5219 : mfib_entry_get_fib_index (fib_node_index_t mfib_entry_index)
    1505             : {
    1506             :     mfib_entry_t *mfib_entry;
    1507             : 
    1508        5219 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1509             : 
    1510        5219 :     return (mfib_entry->mfe_fib_index);
    1511             : }
    1512             : 
    1513             : const dpo_id_t*
    1514           0 : mfib_entry_contribute_ip_forwarding (fib_node_index_t mfib_entry_index)
    1515             : {
    1516             :     mfib_entry_t *mfib_entry;
    1517             : 
    1518           0 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1519             : 
    1520           0 :     return (&mfib_entry->mfe_rep);
    1521             : }
    1522             : 
    1523             : void
    1524          72 : mfib_entry_contribute_forwarding (fib_node_index_t mfib_entry_index,
    1525             :                                   fib_forward_chain_type_t type,
    1526             :                                   mfib_entry_fwd_flags_t flags,
    1527             :                                   dpo_id_t *dpo)
    1528             : {
    1529             :     /*
    1530             :      * An IP mFIB entry can only provide a forwarding chain that
    1531             :      * is the same IP proto as the prefix.
    1532             :      * No use-cases (i know of) for other combinations.
    1533             :      */
    1534             :     mfib_entry_t *mfib_entry;
    1535             :     dpo_proto_t dp;
    1536             : 
    1537          72 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1538             : 
    1539          72 :     dp = fib_proto_to_dpo(mfib_entry->mfe_prefix.fp_proto);
    1540             : 
    1541          72 :     if (type == mfib_forw_chain_type_from_dpo_proto(dp))
    1542             :     {
    1543             :         replicate_t * rep;
    1544             : 
    1545          72 :         rep = replicate_get(mfib_entry->mfe_rep.dpoi_index);
    1546             : 
    1547          72 :         if ((rep->rep_flags & REPLICATE_FLAGS_HAS_LOCAL) &&
    1548          24 :             (flags & MFIB_ENTRY_FWD_FLAG_NO_LOCAL))
    1549           2 :         {
    1550             :             /*
    1551             :              * caller does not want the local paths that the entry has
    1552             :              */
    1553           2 :             dpo_proto_t rep_proto = rep->rep_proto;
    1554           2 :             dpo_set(dpo, DPO_REPLICATE, rep_proto,
    1555             :                     replicate_dup(REPLICATE_FLAGS_NONE,
    1556             :                                   mfib_entry->mfe_rep.dpoi_index));
    1557             :         }
    1558             :         else
    1559             :         {
    1560          70 :             dpo_copy(dpo, &mfib_entry->mfe_rep);
    1561             :         }
    1562             :     }
    1563             :     else
    1564             :     {
    1565           0 :         dpo_copy(dpo, drop_dpo_get(dp));
    1566             :     }
    1567          72 : }
    1568             : 
    1569             : /*
    1570             :  * fib_entry_cover_changed
    1571             :  *
    1572             :  * this entry is tracking its cover and that cover has changed.
    1573             :  */
    1574             : void
    1575           4 : mfib_entry_cover_changed (fib_node_index_t mfib_entry_index)
    1576             : {
    1577             :     mfib_entry_t *mfib_entry;
    1578             :     mfib_entry_src_t *msrc;
    1579             :     mfib_src_res_t res;
    1580             : 
    1581           4 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1582           4 :     msrc = mfib_entry_get_best_src(mfib_entry);
    1583             : 
    1584           4 :     res = mfib_entry_src_cover_change(mfib_entry, msrc);
    1585             : 
    1586           4 :     if (MFIB_SRC_REEVALUATE == res)
    1587             :     {
    1588           4 :         mfib_entry_recalculate_forwarding(mfib_entry, msrc->mfes_src);
    1589             :     }
    1590           4 :     MFIB_ENTRY_DBG(mfib_entry, "cover-changed");
    1591           4 : }
    1592             : 
    1593             : /*
    1594             :  * mfib_entry_cover_updated
    1595             :  *
    1596             :  * this entry is tracking its cover and that cover has been updated
    1597             :  * (i.e. its forwarding information has changed).
    1598             :  */
    1599             : void
    1600          18 : mfib_entry_cover_updated (fib_node_index_t mfib_entry_index)
    1601             : {
    1602             :     mfib_entry_t *mfib_entry;
    1603             :     mfib_entry_src_t *msrc;
    1604             :     mfib_src_res_t res;
    1605             : 
    1606          18 :     mfib_entry = mfib_entry_get(mfib_entry_index);
    1607          18 :     msrc = mfib_entry_get_best_src(mfib_entry);
    1608             : 
    1609          18 :     res = mfib_entry_src_cover_update(mfib_entry, msrc);
    1610             : 
    1611          18 :     if (MFIB_SRC_REEVALUATE == res)
    1612             :     {
    1613          18 :         mfib_entry_recalculate_forwarding(mfib_entry, msrc->mfes_src);
    1614             :     }
    1615          18 :     MFIB_ENTRY_DBG(mfib_entry, "cover-updated");
    1616          18 : }
    1617             : 
    1618             : u32
    1619           0 : mfib_entry_pool_size (void)
    1620             : {
    1621           0 :     return (pool_elts(mfib_entry_pool));
    1622             : }
    1623             : 
    1624             : static clib_error_t *
    1625           0 : show_mfib_entry_command (vlib_main_t * vm,
    1626             :                         unformat_input_t * input,
    1627             :                         vlib_cli_command_t * cmd)
    1628             : {
    1629             :     fib_node_index_t fei;
    1630             : 
    1631           0 :     if (unformat (input, "%d", &fei))
    1632             :     {
    1633             :         /*
    1634             :          * show one in detail
    1635             :          */
    1636           0 :         if (!pool_is_free_index(mfib_entry_pool, fei))
    1637             :         {
    1638           0 :             vlib_cli_output (vm, "%d@%U",
    1639             :                              fei,
    1640             :                              format_mfib_entry, fei,
    1641             :                              MFIB_ENTRY_FORMAT_DETAIL2);
    1642             :         }
    1643             :         else
    1644             :         {
    1645           0 :             vlib_cli_output (vm, "entry %d invalid", fei);
    1646             :         }
    1647             :     }
    1648             :     else
    1649             :     {
    1650             :         /*
    1651             :          * show all
    1652             :          */
    1653           0 :         vlib_cli_output (vm, "FIB Entries:");
    1654           0 :         pool_foreach_index (fei, mfib_entry_pool)
    1655             :          {
    1656           0 :             vlib_cli_output (vm, "%d@%U",
    1657             :                              fei,
    1658             :                              format_mfib_entry, fei,
    1659             :                              MFIB_ENTRY_FORMAT_BRIEF);
    1660             :         }
    1661             :     }
    1662             : 
    1663           0 :     return (NULL);
    1664             : }
    1665             : 
    1666             : /*?
    1667             :  * This command displays an entry, or all entries, in the mfib tables indexed
    1668             :  * by their unique numerical identifier.
    1669             :  ?*/
    1670      285289 : VLIB_CLI_COMMAND (show_mfib_entry, static) = {
    1671             :   .path = "show mfib entry",
    1672             :   .function = show_mfib_entry_command,
    1673             :   .short_help = "show mfib entry",
    1674             : };

Generated by: LCOV version 1.14