back to topotato report
topotato coverage report
Current view: top level - pimd - pim_nht.c (source / functions) Hit Total Coverage
Test: test_pim_bfd.py::PIMBFDTest Lines: 12 522 2.3 %
Date: 2023-02-24 18:39:40 Functions: 2 21 9.5 %

          Line data    Source code
       1             : /*
       2             :  * PIM for Quagga
       3             :  * Copyright (C) 2017 Cumulus Networks, Inc.
       4             :  * Chirag Shah
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 2 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : #include <zebra.h>
      21             : #include "network.h"
      22             : #include "zclient.h"
      23             : #include "stream.h"
      24             : #include "nexthop.h"
      25             : #include "if.h"
      26             : #include "hash.h"
      27             : #include "jhash.h"
      28             : 
      29             : #include "lib/printfrr.h"
      30             : 
      31             : #include "pimd.h"
      32             : #include "pimd/pim_nht.h"
      33             : #include "pim_instance.h"
      34             : #include "log.h"
      35             : #include "pim_time.h"
      36             : #include "pim_oil.h"
      37             : #include "pim_ifchannel.h"
      38             : #include "pim_mroute.h"
      39             : #include "pim_zebra.h"
      40             : #include "pim_upstream.h"
      41             : #include "pim_join.h"
      42             : #include "pim_jp_agg.h"
      43             : #include "pim_zebra.h"
      44             : #include "pim_zlookup.h"
      45             : #include "pim_rp.h"
      46             : #include "pim_addr.h"
      47             : 
      48             : /**
      49             :  * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
      50             :  *   command to Zebra.
      51             :  */
      52           0 : void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
      53             :                            struct pim_nexthop_cache *pnc, int command)
      54             : {
      55           0 :         struct prefix p;
      56           0 :         int ret;
      57             : 
      58           0 :         pim_addr_to_prefix(&p, pnc->rpf.rpf_addr);
      59           0 :         ret = zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, false, false,
      60           0 :                                pim->vrf->vrf_id);
      61           0 :         if (ret == ZCLIENT_SEND_FAILURE)
      62           0 :                 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
      63             : 
      64           0 :         if (PIM_DEBUG_PIM_NHT)
      65           0 :                 zlog_debug(
      66             :                         "%s: NHT %sregistered addr %pFX(%s) with Zebra ret:%d ",
      67             :                         __func__,
      68             :                         (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", &p,
      69             :                         pim->vrf->name, ret);
      70             : 
      71           0 :         return;
      72             : }
      73             : 
      74          44 : struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
      75             :                                                  struct pim_rpf *rpf)
      76             : {
      77          44 :         struct pim_nexthop_cache *pnc = NULL;
      78          44 :         struct pim_nexthop_cache lookup;
      79             : 
      80          44 :         lookup.rpf.rpf_addr = rpf->rpf_addr;
      81          44 :         pnc = hash_lookup(pim->rpf_hash, &lookup);
      82             : 
      83          44 :         return pnc;
      84             : }
      85             : 
      86           0 : static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
      87             :                                                        struct pim_rpf *rpf_addr)
      88             : {
      89           0 :         struct pim_nexthop_cache *pnc;
      90           0 :         char hash_name[64];
      91             : 
      92           0 :         pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE,
      93             :                       sizeof(struct pim_nexthop_cache));
      94           0 :         pnc->rpf.rpf_addr = rpf_addr->rpf_addr;
      95             : 
      96           0 :         pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern);
      97             : 
      98           0 :         pnc->rp_list = list_new();
      99           0 :         pnc->rp_list->cmp = pim_rp_list_cmp;
     100             : 
     101           0 :         snprintfrr(hash_name, sizeof(hash_name), "PNC %pPA(%s) Upstream Hash",
     102           0 :                    &pnc->rpf.rpf_addr, pim->vrf->name);
     103           0 :         pnc->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
     104             :                                               pim_upstream_equal, hash_name);
     105             : 
     106           0 :         return pnc;
     107             : }
     108             : 
     109           0 : static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim,
     110             :                                              pim_addr addr)
     111             : {
     112           0 :         struct pim_nexthop_cache *pnc = NULL;
     113           0 :         struct pim_rpf rpf;
     114           0 :         struct zclient *zclient = NULL;
     115             : 
     116           0 :         zclient = pim_zebra_zclient_get();
     117           0 :         memset(&rpf, 0, sizeof(rpf));
     118           0 :         rpf.rpf_addr = addr;
     119             : 
     120           0 :         pnc = pim_nexthop_cache_find(pim, &rpf);
     121           0 :         if (!pnc) {
     122           0 :                 pnc = pim_nexthop_cache_add(pim, &rpf);
     123           0 :                 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
     124             :                                       ZEBRA_NEXTHOP_REGISTER);
     125           0 :                 if (PIM_DEBUG_PIM_NHT_DETAIL)
     126           0 :                         zlog_debug(
     127             :                                 "%s: NHT cache and zebra notification added for %pPA(%s)",
     128             :                                 __func__, &addr, pim->vrf->name);
     129             :         }
     130             : 
     131           0 :         return pnc;
     132             : }
     133             : 
     134             : /* TBD: this does several distinct things and should probably be split up.
     135             :  * (checking state vs. returning pnc vs. adding upstream vs. adding rp)
     136             :  */
     137           0 : int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
     138             :                               struct pim_upstream *up, struct rp_info *rp,
     139             :                               struct pim_nexthop_cache *out_pnc)
     140             : {
     141           0 :         struct pim_nexthop_cache *pnc;
     142           0 :         struct listnode *ch_node = NULL;
     143             : 
     144           0 :         pnc = pim_nht_get(pim, addr);
     145             : 
     146           0 :         assertf(up || rp, "addr=%pPA", &addr);
     147             : 
     148           0 :         if (rp != NULL) {
     149           0 :                 ch_node = listnode_lookup(pnc->rp_list, rp);
     150           0 :                 if (ch_node == NULL)
     151           0 :                         listnode_add_sort(pnc->rp_list, rp);
     152             :         }
     153             : 
     154           0 :         if (up != NULL)
     155           0 :                 (void)hash_get(pnc->upstream_hash, up, hash_alloc_intern);
     156             : 
     157           0 :         if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) {
     158           0 :                 if (out_pnc)
     159           0 :                         memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
     160           0 :                 return 1;
     161             :         }
     162             : 
     163             :         return 0;
     164             : }
     165             : 
     166           0 : void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr)
     167             : {
     168           0 :         struct pim_nexthop_cache *pnc;
     169             : 
     170           0 :         pnc = pim_nht_get(pim, addr);
     171             : 
     172           0 :         pnc->bsr_count++;
     173           0 : }
     174             : 
     175           0 : static void pim_nht_drop_maybe(struct pim_instance *pim,
     176             :                                struct pim_nexthop_cache *pnc)
     177             : {
     178           0 :         if (PIM_DEBUG_PIM_NHT)
     179           0 :                 zlog_debug(
     180             :                         "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u",
     181             :                         __func__, &pnc->rpf.rpf_addr, pim->vrf->name,
     182             :                         pnc->rp_list->count, pnc->upstream_hash->count,
     183             :                         pnc->bsr_count);
     184             : 
     185           0 :         if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0
     186           0 :             && pnc->bsr_count == 0) {
     187           0 :                 struct zclient *zclient = pim_zebra_zclient_get();
     188             : 
     189           0 :                 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
     190             :                                       ZEBRA_NEXTHOP_UNREGISTER);
     191             : 
     192           0 :                 list_delete(&pnc->rp_list);
     193           0 :                 hash_free(pnc->upstream_hash);
     194             : 
     195           0 :                 hash_release(pim->rpf_hash, pnc);
     196           0 :                 if (pnc->nexthop)
     197           0 :                         nexthops_free(pnc->nexthop);
     198           0 :                 XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
     199             :         }
     200           0 : }
     201             : 
     202           0 : void pim_delete_tracked_nexthop(struct pim_instance *pim, pim_addr addr,
     203             :                                 struct pim_upstream *up, struct rp_info *rp)
     204             : {
     205           0 :         struct pim_nexthop_cache *pnc = NULL;
     206           0 :         struct pim_nexthop_cache lookup;
     207           0 :         struct pim_upstream *upstream = NULL;
     208             : 
     209             :         /* Remove from RPF hash if it is the last entry */
     210           0 :         lookup.rpf.rpf_addr = addr;
     211           0 :         pnc = hash_lookup(pim->rpf_hash, &lookup);
     212           0 :         if (!pnc) {
     213           0 :                 zlog_warn("attempting to delete nonexistent NHT entry %pPA",
     214             :                           &addr);
     215           0 :                 return;
     216             :         }
     217             : 
     218           0 :         if (rp) {
     219             :                 /* Release the (*, G)upstream from pnc->upstream_hash,
     220             :                  * whose Group belongs to the RP getting deleted
     221             :                  */
     222           0 :                 frr_each (rb_pim_upstream, &pim->upstream_head, upstream) {
     223           0 :                         struct prefix grp;
     224           0 :                         struct rp_info *trp_info;
     225             : 
     226           0 :                         if (!pim_addr_is_any(upstream->sg.src))
     227           0 :                                 continue;
     228             : 
     229           0 :                         pim_addr_to_prefix(&grp, upstream->sg.grp);
     230           0 :                         trp_info = pim_rp_find_match_group(pim, &grp);
     231           0 :                         if (trp_info == rp)
     232           0 :                                 hash_release(pnc->upstream_hash, upstream);
     233             :                 }
     234           0 :                 listnode_delete(pnc->rp_list, rp);
     235             :         }
     236             : 
     237           0 :         if (up)
     238           0 :                 hash_release(pnc->upstream_hash, up);
     239             : 
     240           0 :         pim_nht_drop_maybe(pim, pnc);
     241             : }
     242             : 
     243           0 : void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr)
     244             : {
     245           0 :         struct pim_nexthop_cache *pnc = NULL;
     246           0 :         struct pim_nexthop_cache lookup;
     247             : 
     248             :         /*
     249             :          * Nothing to do here if the address to unregister
     250             :          * is 0.0.0.0 as that the BSR has not been registered
     251             :          * for tracking yet.
     252             :          */
     253           0 :         if (pim_addr_is_any(addr))
     254           0 :                 return;
     255             : 
     256           0 :         lookup.rpf.rpf_addr = addr;
     257             : 
     258           0 :         pnc = hash_lookup(pim->rpf_hash, &lookup);
     259             : 
     260           0 :         if (!pnc) {
     261           0 :                 zlog_warn("attempting to delete nonexistent NHT BSR entry %pPA",
     262             :                           &addr);
     263           0 :                 return;
     264             :         }
     265             : 
     266           0 :         assertf(pnc->bsr_count > 0, "addr=%pPA", &addr);
     267           0 :         pnc->bsr_count--;
     268             : 
     269           0 :         pim_nht_drop_maybe(pim, pnc);
     270             : }
     271             : 
     272           0 : bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
     273             :                            struct interface *src_ifp, pim_addr src_ip)
     274             : {
     275           0 :         struct pim_nexthop_cache *pnc = NULL;
     276           0 :         struct pim_nexthop_cache lookup;
     277           0 :         struct pim_neighbor *nbr = NULL;
     278           0 :         struct nexthop *nh;
     279           0 :         struct interface *ifp;
     280             : 
     281           0 :         lookup.rpf.rpf_addr = bsr_addr;
     282             : 
     283           0 :         pnc = hash_lookup(pim->rpf_hash, &lookup);
     284           0 :         if (!pnc || !CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED)) {
     285             :                 /* BSM from a new freshly registered BSR - do a synchronous
     286             :                  * zebra query since otherwise we'd drop the first packet,
     287             :                  * leading to additional delay in picking up BSM data
     288             :                  */
     289             : 
     290             :                 /* FIXME: this should really be moved into a generic NHT
     291             :                  * function that does "add and get immediate result" or maybe
     292             :                  * "check cache or get immediate result." But until that can
     293             :                  * be worked in, here's a copy of the code below :(
     294             :                  */
     295           0 :                 struct pim_zlookup_nexthop nexthop_tab[router->multipath];
     296           0 :                 ifindex_t i;
     297           0 :                 struct interface *ifp = NULL;
     298           0 :                 int num_ifindex;
     299             : 
     300           0 :                 memset(nexthop_tab, 0, sizeof(nexthop_tab));
     301           0 :                 num_ifindex = zclient_lookup_nexthop(
     302           0 :                         pim, nexthop_tab, router->multipath, bsr_addr,
     303             :                         PIM_NEXTHOP_LOOKUP_MAX);
     304             : 
     305           0 :                 if (num_ifindex <= 0)
     306             :                         return false;
     307             : 
     308           0 :                 for (i = 0; i < num_ifindex; i++) {
     309           0 :                         struct pim_zlookup_nexthop *znh = &nexthop_tab[i];
     310             : 
     311             :                         /* pim_zlookup_nexthop has no ->type */
     312             : 
     313             :                         /* 1:1 match code below with znh instead of nh */
     314           0 :                         ifp = if_lookup_by_index(znh->ifindex,
     315           0 :                                                  pim->vrf->vrf_id);
     316             : 
     317           0 :                         if (!ifp || !ifp->info)
     318           0 :                                 continue;
     319             : 
     320           0 :                         if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
     321             :                                 return true;
     322             : 
     323           0 :                         nbr = pim_neighbor_find(ifp, znh->nexthop_addr);
     324           0 :                         if (!nbr)
     325           0 :                                 continue;
     326             : 
     327           0 :                         return znh->ifindex == src_ifp->ifindex &&
     328           0 :                                (!pim_addr_cmp(znh->nexthop_addr, src_ip));
     329             :                 }
     330             :                 return false;
     331             :         }
     332             : 
     333           0 :         if (!CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID))
     334             :                 return false;
     335             : 
     336             :         /* if we accept BSMs from more than one ECMP nexthop, this will cause
     337             :          * BSM message "multiplication" for each ECMP hop.  i.e. if you have
     338             :          * 4-way ECMP and 4 hops you end up with 256 copies of each BSM
     339             :          * message.
     340             :          *
     341             :          * so...  only accept the first (IPv4) valid nexthop as source.
     342             :          */
     343             : 
     344           0 :         for (nh = pnc->nexthop; nh; nh = nh->next) {
     345           0 :                 pim_addr nhaddr;
     346             : 
     347           0 :                 switch (nh->type) {
     348             : #if PIM_IPV == 4
     349           0 :                 case NEXTHOP_TYPE_IPV4:
     350           0 :                         if (nh->ifindex == IFINDEX_INTERNAL)
     351           0 :                                 continue;
     352             : 
     353             :                         /* fallthru */
     354             :                 case NEXTHOP_TYPE_IPV4_IFINDEX:
     355           0 :                         nhaddr = nh->gate.ipv4;
     356           0 :                         break;
     357           0 :                 case NEXTHOP_TYPE_IPV6:
     358             :                 case NEXTHOP_TYPE_IPV6_IFINDEX:
     359           0 :                         continue;
     360             : #else
     361             :                 case NEXTHOP_TYPE_IPV6:
     362             :                         if (nh->ifindex == IFINDEX_INTERNAL)
     363             :                                 continue;
     364             : 
     365             :                         /* fallthru */
     366             :                 case NEXTHOP_TYPE_IPV6_IFINDEX:
     367             :                         nhaddr = nh->gate.ipv6;
     368             :                         break;
     369             :                 case NEXTHOP_TYPE_IPV4:
     370             :                 case NEXTHOP_TYPE_IPV4_IFINDEX:
     371             :                         continue;
     372             : #endif
     373           0 :                 case NEXTHOP_TYPE_IFINDEX:
     374           0 :                         nhaddr = bsr_addr;
     375           0 :                         break;
     376             : 
     377           0 :                 case NEXTHOP_TYPE_BLACKHOLE:
     378           0 :                         continue;
     379             :                 }
     380             : 
     381           0 :                 ifp = if_lookup_by_index(nh->ifindex, pim->vrf->vrf_id);
     382           0 :                 if (!ifp || !ifp->info)
     383           0 :                         continue;
     384             : 
     385           0 :                 if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
     386           0 :                         return true;
     387             : 
     388             :                 /* MRIB (IGP) may be pointing at a router where PIM is down */
     389           0 :                 nbr = pim_neighbor_find(ifp, nhaddr);
     390           0 :                 if (!nbr)
     391           0 :                         continue;
     392             : 
     393           0 :                 return nh->ifindex == src_ifp->ifindex &&
     394           0 :                        (!pim_addr_cmp(nhaddr, src_ip));
     395             :         }
     396             :         return false;
     397             : }
     398             : 
     399           0 : void pim_rp_nexthop_del(struct rp_info *rp_info)
     400             : {
     401           0 :         rp_info->rp.source_nexthop.interface = NULL;
     402           0 :         rp_info->rp.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
     403           0 :         rp_info->rp.source_nexthop.mrib_metric_preference =
     404           0 :                 router->infinite_assert_metric.metric_preference;
     405           0 :         rp_info->rp.source_nexthop.mrib_route_metric =
     406           0 :                 router->infinite_assert_metric.route_metric;
     407           0 : }
     408             : 
     409             : /* Update RP nexthop info based on Nexthop update received from Zebra.*/
     410           0 : static void pim_update_rp_nh(struct pim_instance *pim,
     411             :                              struct pim_nexthop_cache *pnc)
     412             : {
     413           0 :         struct listnode *node = NULL;
     414           0 :         struct rp_info *rp_info = NULL;
     415             : 
     416             :         /*Traverse RP list and update each RP Nexthop info */
     417           0 :         for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) {
     418           0 :                 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
     419           0 :                         continue;
     420             : 
     421             :                 // Compute PIM RPF using cached nexthop
     422           0 :                 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
     423             :                                              rp_info->rp.rpf_addr,
     424             :                                              &rp_info->group, 1))
     425           0 :                         pim_rp_nexthop_del(rp_info);
     426             :         }
     427           0 : }
     428             : 
     429             : /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
     430           0 : static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
     431             : {
     432           0 :         struct pim_instance *pim = (struct pim_instance *)arg;
     433           0 :         struct pim_upstream *up = (struct pim_upstream *)bucket->data;
     434             : 
     435           0 :         enum pim_rpf_result rpf_result;
     436           0 :         struct pim_rpf old;
     437             : 
     438           0 :         old.source_nexthop.interface = up->rpf.source_nexthop.interface;
     439           0 :         rpf_result = pim_rpf_update(pim, up, &old, __func__);
     440             : 
     441             :         /* update kernel multicast forwarding cache (MFC); if the
     442             :          * RPF nbr is now unreachable the MFC has already been updated
     443             :          * by pim_rpf_clear
     444             :          */
     445           0 :         if (rpf_result == PIM_RPF_CHANGED)
     446           0 :                 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
     447             : 
     448           0 :         if (rpf_result == PIM_RPF_CHANGED ||
     449           0 :                 (rpf_result == PIM_RPF_FAILURE && old.source_nexthop.interface))
     450           0 :                 pim_zebra_upstream_rpf_changed(pim, up, &old);
     451             : 
     452             : 
     453           0 :         if (PIM_DEBUG_PIM_NHT) {
     454           0 :                 zlog_debug(
     455             :                         "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
     456             :                         __func__, up->sg_str, pim->vrf->name,
     457             :                         old.source_nexthop.interface ? old.source_nexthop
     458             :                                                                .interface->name
     459             :                                                      : "Unknown",
     460             :                         up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
     461             :                                                                    .interface->name
     462             :                                                          : "Unknown");
     463             :         }
     464             : 
     465           0 :         return HASHWALK_CONTINUE;
     466             : }
     467             : 
     468           0 : static int pim_update_upstream_nh(struct pim_instance *pim,
     469             :                                   struct pim_nexthop_cache *pnc)
     470             : {
     471           0 :         hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim);
     472             : 
     473           0 :         pim_zebra_update_all_interfaces(pim);
     474             : 
     475           0 :         return 0;
     476             : }
     477             : 
     478           0 : static int pim_upstream_nh_if_update_helper(struct hash_bucket *bucket,
     479             :                                             void *arg)
     480             : {
     481           0 :         struct pim_nexthop_cache *pnc = bucket->data;
     482           0 :         struct pnc_hash_walk_data *pwd = arg;
     483           0 :         struct pim_instance *pim = pwd->pim;
     484           0 :         struct interface *ifp = pwd->ifp;
     485           0 :         struct nexthop *nh_node = NULL;
     486           0 :         ifindex_t first_ifindex;
     487             : 
     488           0 :         for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
     489           0 :                 first_ifindex = nh_node->ifindex;
     490           0 :                 if (ifp != if_lookup_by_index(first_ifindex, pim->vrf->vrf_id))
     491           0 :                         continue;
     492             : 
     493           0 :                 if (pnc->upstream_hash->count) {
     494           0 :                         pim_update_upstream_nh(pim, pnc);
     495           0 :                         break;
     496             :                 }
     497             :         }
     498             : 
     499           0 :         return HASHWALK_CONTINUE;
     500             : }
     501             : 
     502           6 : void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp)
     503             : {
     504           6 :         struct pnc_hash_walk_data pwd;
     505             : 
     506           6 :         pwd.pim = pim;
     507           6 :         pwd.ifp = ifp;
     508             : 
     509           6 :         hash_walk(pim->rpf_hash, pim_upstream_nh_if_update_helper, &pwd);
     510           6 : }
     511             : 
     512           0 : uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
     513             : {
     514           0 :         uint32_t hash_val;
     515             : 
     516           0 :         if (!src)
     517             :                 return 0;
     518             : 
     519           0 :         hash_val = prefix_hash_key(src);
     520           0 :         if (grp)
     521           0 :                 hash_val ^= prefix_hash_key(grp);
     522             :         return hash_val;
     523             : }
     524             : 
     525           0 : static int pim_ecmp_nexthop_search(struct pim_instance *pim,
     526             :                                    struct pim_nexthop_cache *pnc,
     527             :                                    struct pim_nexthop *nexthop, pim_addr src,
     528             :                                    struct prefix *grp, int neighbor_needed)
     529           0 : {
     530           0 :         struct pim_neighbor *nbrs[router->multipath], *nbr = NULL;
     531           0 :         struct interface *ifps[router->multipath];
     532           0 :         struct nexthop *nh_node = NULL;
     533           0 :         ifindex_t first_ifindex;
     534           0 :         struct interface *ifp = NULL;
     535           0 :         uint32_t hash_val = 0, mod_val = 0;
     536           0 :         uint8_t nh_iter = 0, found = 0;
     537           0 :         uint32_t i, num_nbrs = 0;
     538           0 :         struct pim_interface *pim_ifp;
     539             : 
     540           0 :         if (!pnc || !pnc->nexthop_num || !nexthop)
     541             :                 return 0;
     542             : 
     543           0 :         pim_addr nh_addr = nexthop->mrib_nexthop_addr;
     544           0 :         pim_addr grp_addr = pim_addr_from_prefix(grp);
     545             : 
     546           0 :         memset(&nbrs, 0, sizeof(nbrs));
     547           0 :         memset(&ifps, 0, sizeof(ifps));
     548             : 
     549             : 
     550             :         // Current Nexthop is VALID, check to stay on the current path.
     551           0 :         if (nexthop->interface && nexthop->interface->info &&
     552           0 :             (!pim_addr_is_any(nh_addr))) {
     553             :                 /* User configured knob to explicitly switch
     554             :                    to new path is disabled or current path
     555             :                    metric is less than nexthop update.
     556             :                  */
     557             : 
     558           0 :                 if (pim->ecmp_rebalance_enable == 0) {
     559           0 :                         uint8_t curr_route_valid = 0;
     560             :                         // Check if current nexthop is present in new updated
     561             :                         // Nexthop list.
     562             :                         // If the current nexthop is not valid, candidate to
     563             :                         // choose new Nexthop.
     564           0 :                         for (nh_node = pnc->nexthop; nh_node;
     565           0 :                              nh_node = nh_node->next) {
     566           0 :                                 curr_route_valid = (nexthop->interface->ifindex
     567           0 :                                                     == nh_node->ifindex);
     568           0 :                                 if (curr_route_valid)
     569             :                                         break;
     570             :                         }
     571             : 
     572           0 :                         if (curr_route_valid &&
     573           0 :                             !pim_if_connected_to_source(nexthop->interface,
     574             :                                                         src)) {
     575           0 :                                 nbr = pim_neighbor_find(
     576             :                                         nexthop->interface,
     577             :                                         nexthop->mrib_nexthop_addr);
     578           0 :                                 if (!nbr
     579           0 :                                     && !if_is_loopback(nexthop->interface)) {
     580           0 :                                         if (PIM_DEBUG_PIM_NHT)
     581           0 :                                                 zlog_debug(
     582             :                                                         "%s: current nexthop does not have nbr ",
     583             :                                                         __func__);
     584             :                                 } else {
     585             :                                         /* update metric even if the upstream
     586             :                                          * neighbor stays unchanged
     587             :                                          */
     588           0 :                                         nexthop->mrib_metric_preference =
     589           0 :                                                 pnc->distance;
     590           0 :                                         nexthop->mrib_route_metric =
     591           0 :                                                 pnc->metric;
     592           0 :                                         if (PIM_DEBUG_PIM_NHT)
     593           0 :                                                 zlog_debug(
     594             :                                                         "%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection",
     595             :                                                         __func__, &src,
     596             :                                                         &grp_addr,
     597             :                                                         pim->vrf->name,
     598             :                                                         nexthop->interface->name);
     599           0 :                                         return 1;
     600             :                                 }
     601             :                         }
     602             :                 }
     603             :         }
     604             : 
     605             :         /*
     606             :          * Look up all interfaces and neighbors,
     607             :          * store for later usage
     608             :          */
     609           0 :         for (nh_node = pnc->nexthop, i = 0; nh_node;
     610           0 :              nh_node = nh_node->next, i++) {
     611           0 :                 ifps[i] =
     612           0 :                         if_lookup_by_index(nh_node->ifindex, pim->vrf->vrf_id);
     613           0 :                 if (ifps[i]) {
     614             : #if PIM_IPV == 4
     615           0 :                         pim_addr nhaddr = nh_node->gate.ipv4;
     616             : #else
     617             :                         pim_addr nhaddr = nh_node->gate.ipv6;
     618             : #endif
     619           0 :                         nbrs[i] = pim_neighbor_find(ifps[i], nhaddr);
     620           0 :                         if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
     621           0 :                                 num_nbrs++;
     622             :                 }
     623             :         }
     624           0 :         if (pim->ecmp_enable) {
     625           0 :                 struct prefix src_pfx;
     626           0 :                 uint32_t consider = pnc->nexthop_num;
     627             : 
     628           0 :                 if (neighbor_needed && num_nbrs < consider)
     629           0 :                         consider = num_nbrs;
     630             : 
     631           0 :                 if (consider == 0)
     632           0 :                         return 0;
     633             : 
     634             :                 // PIM ECMP flag is enable then choose ECMP path.
     635           0 :                 pim_addr_to_prefix(&src_pfx, src);
     636           0 :                 hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
     637           0 :                 mod_val = hash_val % consider;
     638             :         }
     639             : 
     640           0 :         for (nh_node = pnc->nexthop; nh_node && (found == 0);
     641           0 :              nh_node = nh_node->next) {
     642           0 :                 first_ifindex = nh_node->ifindex;
     643           0 :                 ifp = ifps[nh_iter];
     644           0 :                 if (!ifp) {
     645           0 :                         if (PIM_DEBUG_PIM_NHT)
     646           0 :                                 zlog_debug(
     647             :                                         "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
     648             :                                         __FILE__, __func__, first_ifindex, &src,
     649             :                                         pim->vrf->name);
     650           0 :                         if (nh_iter == mod_val)
     651           0 :                                 mod_val++; // Select nexthpath
     652           0 :                         nh_iter++;
     653           0 :                         continue;
     654             :                 }
     655             : 
     656           0 :                 pim_ifp = ifp->info;
     657             : 
     658           0 :                 if (!pim_ifp || !pim_ifp->pim_enable) {
     659           0 :                         if (PIM_DEBUG_PIM_NHT)
     660           0 :                                 zlog_debug(
     661             :                                         "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
     662             :                                         __func__, ifp->name, pim->vrf->name,
     663             :                                         first_ifindex, &src);
     664           0 :                         if (nh_iter == mod_val)
     665           0 :                                 mod_val++; // Select nexthpath
     666           0 :                         nh_iter++;
     667           0 :                         continue;
     668             :                 }
     669             : 
     670           0 :                 if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
     671           0 :                         nbr = nbrs[nh_iter];
     672           0 :                         if (!nbr && !if_is_loopback(ifp)) {
     673           0 :                                 if (PIM_DEBUG_PIM_NHT)
     674           0 :                                         zlog_debug(
     675             :                                                 "%s: pim nbr not found on input interface %s(%s)",
     676             :                                                 __func__, ifp->name,
     677             :                                                 pim->vrf->name);
     678           0 :                                 if (nh_iter == mod_val)
     679           0 :                                         mod_val++; // Select nexthpath
     680           0 :                                 nh_iter++;
     681           0 :                                 continue;
     682             :                         }
     683             :                 }
     684             : 
     685           0 :                 if (nh_iter == mod_val) {
     686           0 :                         nexthop->interface = ifp;
     687             : #if PIM_IPV == 4
     688           0 :                         nexthop->mrib_nexthop_addr = nh_node->gate.ipv4;
     689             : #else
     690             :                         nexthop->mrib_nexthop_addr = nh_node->gate.ipv6;
     691             : #endif
     692           0 :                         nexthop->mrib_metric_preference = pnc->distance;
     693           0 :                         nexthop->mrib_route_metric = pnc->metric;
     694           0 :                         nexthop->last_lookup = src;
     695           0 :                         nexthop->last_lookup_time = pim_time_monotonic_usec();
     696           0 :                         nexthop->nbr = nbr;
     697           0 :                         found = 1;
     698           0 :                         if (PIM_DEBUG_PIM_NHT)
     699           0 :                                 zlog_debug(
     700             :                                         "%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d",
     701             :                                         __func__, &src, &grp_addr,
     702             :                                         pim->vrf->name, ifp->name, &nh_addr,
     703             :                                         mod_val, nh_iter, pim->ecmp_enable);
     704             :                 }
     705           0 :                 nh_iter++;
     706             :         }
     707             : 
     708           0 :         if (found)
     709             :                 return 1;
     710             :         else
     711             :                 return 0;
     712             : }
     713             : 
     714             : /* This API is used to parse Registered address nexthop update coming from Zebra
     715             :  */
     716           0 : int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
     717             : {
     718           0 :         struct nexthop *nexthop;
     719           0 :         struct nexthop *nhlist_head = NULL;
     720           0 :         struct nexthop *nhlist_tail = NULL;
     721           0 :         int i;
     722           0 :         struct pim_rpf rpf;
     723           0 :         struct pim_nexthop_cache *pnc = NULL;
     724           0 :         struct interface *ifp = NULL;
     725           0 :         struct vrf *vrf = vrf_lookup_by_id(vrf_id);
     726           0 :         struct pim_instance *pim;
     727           0 :         struct zapi_route nhr;
     728           0 :         struct prefix match;
     729             : 
     730           0 :         if (!vrf)
     731             :                 return 0;
     732           0 :         pim = vrf->info;
     733             : 
     734           0 :         if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) {
     735           0 :                 zlog_err("%s: Decode of nexthop update from zebra failed",
     736             :                          __func__);
     737           0 :                 return 0;
     738             :         }
     739             : 
     740           0 :         if (cmd == ZEBRA_NEXTHOP_UPDATE) {
     741           0 :                 rpf.rpf_addr = pim_addr_from_prefix(&match);
     742           0 :                 pnc = pim_nexthop_cache_find(pim, &rpf);
     743           0 :                 if (!pnc) {
     744           0 :                         if (PIM_DEBUG_PIM_NHT)
     745           0 :                                 zlog_debug(
     746             :                                         "%s: Skipping NHT update, addr %pPA is not in local cached DB.",
     747             :                                         __func__, &rpf.rpf_addr);
     748           0 :                         return 0;
     749             :                 }
     750             :         } else {
     751             :                 /*
     752             :                  * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
     753             :                  */
     754             :                 return 0;
     755             :         }
     756             : 
     757           0 :         pnc->last_update = pim_time_monotonic_usec();
     758             : 
     759           0 :         if (nhr.nexthop_num) {
     760           0 :                 pnc->nexthop_num = 0; // Only increment for pim enabled rpf.
     761             : 
     762           0 :                 for (i = 0; i < nhr.nexthop_num; i++) {
     763           0 :                         nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
     764           0 :                         switch (nexthop->type) {
     765           0 :                         case NEXTHOP_TYPE_IFINDEX:
     766             :                                 /*
     767             :                                  * Connected route (i.e. no nexthop), use
     768             :                                  * RPF address from nexthop cache (i.e.
     769             :                                  * destination) as PIM nexthop.
     770             :                                  */
     771             : #if PIM_IPV == 4
     772           0 :                                 nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
     773           0 :                                 nexthop->gate.ipv4 = pnc->rpf.rpf_addr;
     774             : #else
     775             :                                 nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
     776             :                                 nexthop->gate.ipv6 = pnc->rpf.rpf_addr;
     777             : #endif
     778           0 :                                 break;
     779             : #if PIM_IPV == 4
     780             :                         /* RFC5549 IPv4-over-IPv6 nexthop handling:
     781             :                          * if we get an IPv6 nexthop in IPv4 PIM, hunt down a
     782             :                          * PIM neighbor and use that instead.
     783             :                          */
     784           0 :                         case NEXTHOP_TYPE_IPV6_IFINDEX: {
     785           0 :                                 struct interface *ifp1 = NULL;
     786           0 :                                 struct pim_neighbor *nbr = NULL;
     787             : 
     788           0 :                                 ifp1 = if_lookup_by_index(nexthop->ifindex,
     789           0 :                                                           pim->vrf->vrf_id);
     790             : 
     791           0 :                                 if (!ifp1)
     792             :                                         nbr = NULL;
     793             :                                 else
     794             :                                         /* FIXME: should really use nbr's
     795             :                                          * secondary address list here
     796             :                                          */
     797           0 :                                         nbr = pim_neighbor_find_if(ifp1);
     798             : 
     799             :                                 /* Overwrite with Nbr address as NH addr */
     800           0 :                                 if (nbr)
     801           0 :                                         nexthop->gate.ipv4 = nbr->source_addr;
     802             :                                 else
     803             :                                         // Mark nexthop address to 0 until PIM
     804             :                                         // Nbr is resolved.
     805           0 :                                         nexthop->gate.ipv4 = PIMADDR_ANY;
     806             : 
     807             :                                 break;
     808             :                         }
     809             : #else
     810             :                         case NEXTHOP_TYPE_IPV6_IFINDEX:
     811             : #endif
     812             :                         case NEXTHOP_TYPE_IPV6:
     813             :                         case NEXTHOP_TYPE_IPV4:
     814             :                         case NEXTHOP_TYPE_IPV4_IFINDEX:
     815             :                         case NEXTHOP_TYPE_BLACKHOLE:
     816             :                                 /* nothing to do for the other nexthop types */
     817             :                                 break;
     818             :                         }
     819             : 
     820           0 :                         ifp = if_lookup_by_index(nexthop->ifindex,
     821           0 :                                                  pim->vrf->vrf_id);
     822           0 :                         if (!ifp) {
     823           0 :                                 if (PIM_DEBUG_PIM_NHT) {
     824           0 :                                         char buf[NEXTHOP_STRLEN];
     825           0 :                                         zlog_debug(
     826             :                                                 "%s: could not find interface for ifindex %d(%s) (addr %s)",
     827             :                                                 __func__, nexthop->ifindex,
     828             :                                                 pim->vrf->name,
     829             :                                                 nexthop2str(nexthop, buf,
     830             :                                                             sizeof(buf)));
     831             :                                 }
     832           0 :                                 nexthop_free(nexthop);
     833           0 :                                 continue;
     834             :                         }
     835             : 
     836           0 :                         if (PIM_DEBUG_PIM_NHT) {
     837             : #if PIM_IPV == 4
     838           0 :                                 pim_addr nhaddr = nexthop->gate.ipv4;
     839             : #else
     840             :                                 pim_addr nhaddr = nexthop->gate.ipv6;
     841             : #endif
     842           0 :                                 zlog_debug(
     843             :                                         "%s: NHT addr %pFX(%s) %d-nhop via %pPA(%s) type %d distance:%u metric:%u ",
     844             :                                         __func__, &match, pim->vrf->name, i + 1,
     845             :                                         &nhaddr, ifp->name, nexthop->type,
     846             :                                         nhr.distance, nhr.metric);
     847             :                         }
     848             : 
     849           0 :                         if (!ifp->info) {
     850             :                                 /*
     851             :                                  * Though Multicast is not enabled on this
     852             :                                  * Interface store it in database otheriwse we
     853             :                                  * may miss this update and this will not cause
     854             :                                  * any issue, because while choosing the path we
     855             :                                  * are ommitting the Interfaces which are not
     856             :                                  * multicast enabled
     857             :                                  */
     858           0 :                                 if (PIM_DEBUG_PIM_NHT) {
     859           0 :                                         char buf[NEXTHOP_STRLEN];
     860             : 
     861           0 :                                         zlog_debug(
     862             :                                                 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
     863             :                                                 __func__, ifp->name,
     864             :                                                 pim->vrf->name,
     865             :                                                 nexthop->ifindex,
     866             :                                                 nexthop2str(nexthop, buf,
     867             :                                                             sizeof(buf)));
     868             :                                 }
     869             :                         }
     870             : 
     871           0 :                         if (nhlist_tail) {
     872           0 :                                 nhlist_tail->next = nexthop;
     873           0 :                                 nhlist_tail = nexthop;
     874             :                         } else {
     875             :                                 nhlist_tail = nexthop;
     876             :                                 nhlist_head = nexthop;
     877             :                         }
     878             :                         // Only keep track of nexthops which are PIM enabled.
     879           0 :                         pnc->nexthop_num++;
     880             :                 }
     881             :                 /* Reset existing pnc->nexthop before assigning new list */
     882           0 :                 nexthops_free(pnc->nexthop);
     883           0 :                 pnc->nexthop = nhlist_head;
     884           0 :                 if (pnc->nexthop_num) {
     885           0 :                         pnc->flags |= PIM_NEXTHOP_VALID;
     886           0 :                         pnc->distance = nhr.distance;
     887           0 :                         pnc->metric = nhr.metric;
     888             :                 }
     889             :         } else {
     890           0 :                 pnc->flags &= ~PIM_NEXTHOP_VALID;
     891           0 :                 pnc->nexthop_num = nhr.nexthop_num;
     892           0 :                 nexthops_free(pnc->nexthop);
     893           0 :                 pnc->nexthop = NULL;
     894             :         }
     895           0 :         SET_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED);
     896             : 
     897           0 :         if (PIM_DEBUG_PIM_NHT)
     898           0 :                 zlog_debug(
     899             :                         "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
     900             :                         __func__, &match, pim->vrf->name, nhr.nexthop_num,
     901             :                         pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
     902             :                         listcount(pnc->rp_list));
     903             : 
     904           0 :         pim_rpf_set_refresh_time(pim);
     905             : 
     906           0 :         if (listcount(pnc->rp_list))
     907           0 :                 pim_update_rp_nh(pim, pnc);
     908           0 :         if (pnc->upstream_hash->count)
     909           0 :                 pim_update_upstream_nh(pim, pnc);
     910             : 
     911             :         return 0;
     912             : }
     913             : 
     914           0 : int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
     915             :                             struct pim_nexthop *nexthop, pim_addr src,
     916             :                             struct prefix *grp, int neighbor_needed)
     917           0 : {
     918           0 :         struct pim_nexthop_cache *pnc;
     919           0 :         struct pim_zlookup_nexthop nexthop_tab[router->multipath];
     920           0 :         struct pim_neighbor *nbrs[router->multipath], *nbr = NULL;
     921           0 :         struct pim_rpf rpf;
     922           0 :         int num_ifindex;
     923           0 :         struct interface *ifps[router->multipath], *ifp;
     924           0 :         int first_ifindex;
     925           0 :         int found = 0;
     926           0 :         uint8_t i = 0;
     927           0 :         uint32_t hash_val = 0, mod_val = 0;
     928           0 :         uint32_t num_nbrs = 0;
     929           0 :         struct pim_interface *pim_ifp;
     930             : 
     931           0 :         if (PIM_DEBUG_PIM_NHT_DETAIL)
     932           0 :                 zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
     933             :                            __func__, &src, pim->vrf->name,
     934             :                            nexthop->last_lookup_time);
     935             : 
     936           0 :         rpf.rpf_addr = src;
     937             : 
     938           0 :         pnc = pim_nexthop_cache_find(pim, &rpf);
     939           0 :         if (pnc) {
     940           0 :                 if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED))
     941           0 :                     return pim_ecmp_nexthop_search(pim, pnc, nexthop, src, grp,
     942             :                                                    neighbor_needed);
     943             :         }
     944             : 
     945           0 :         memset(nexthop_tab, 0,
     946           0 :                sizeof(struct pim_zlookup_nexthop) * router->multipath);
     947           0 :         num_ifindex =
     948           0 :                 zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, src,
     949             :                                        PIM_NEXTHOP_LOOKUP_MAX);
     950           0 :         if (num_ifindex < 1) {
     951           0 :                 if (PIM_DEBUG_PIM_NHT)
     952           0 :                         zlog_warn(
     953             :                                 "%s: could not find nexthop ifindex for address %pPA(%s)",
     954             :                                 __func__, &src, pim->vrf->name);
     955           0 :                 return 0;
     956             :         }
     957             : 
     958           0 :         memset(&nbrs, 0, sizeof(nbrs));
     959           0 :         memset(&ifps, 0, sizeof(ifps));
     960             : 
     961             :         /*
     962             :          * Look up all interfaces and neighbors,
     963             :          * store for later usage
     964             :          */
     965           0 :         for (i = 0; i < num_ifindex; i++) {
     966           0 :                 ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex,
     967           0 :                                              pim->vrf->vrf_id);
     968           0 :                 if (ifps[i]) {
     969           0 :                         nbrs[i] = pim_neighbor_find(
     970             :                                 ifps[i], nexthop_tab[i].nexthop_addr);
     971           0 :                         if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
     972           0 :                                 num_nbrs++;
     973             :                 }
     974             :         }
     975             : 
     976             :         // If PIM ECMP enable then choose ECMP path.
     977           0 :         if (pim->ecmp_enable) {
     978           0 :                 struct prefix src_pfx;
     979           0 :                 uint32_t consider = num_ifindex;
     980             : 
     981           0 :                 if (neighbor_needed && num_nbrs < consider)
     982           0 :                         consider = num_nbrs;
     983             : 
     984           0 :                 if (consider == 0)
     985           0 :                         return 0;
     986             : 
     987           0 :                 pim_addr_to_prefix(&src_pfx, src);
     988           0 :                 hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
     989           0 :                 mod_val = hash_val % consider;
     990           0 :                 if (PIM_DEBUG_PIM_NHT_DETAIL)
     991           0 :                         zlog_debug("%s: hash_val %u mod_val %u", __func__,
     992             :                                    hash_val, mod_val);
     993             :         }
     994             : 
     995             :         i = 0;
     996           0 :         while (!found && (i < num_ifindex)) {
     997           0 :                 first_ifindex = nexthop_tab[i].ifindex;
     998             : 
     999           0 :                 ifp = ifps[i];
    1000           0 :                 if (!ifp) {
    1001           0 :                         if (PIM_DEBUG_PIM_NHT)
    1002           0 :                                 zlog_debug(
    1003             :                                         "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
    1004             :                                         __FILE__, __func__, first_ifindex, &src,
    1005             :                                         pim->vrf->name);
    1006           0 :                         if (i == mod_val)
    1007           0 :                                 mod_val++;
    1008           0 :                         i++;
    1009           0 :                         continue;
    1010             :                 }
    1011             : 
    1012           0 :                 pim_ifp = ifp->info;
    1013             : 
    1014           0 :                 if (!pim_ifp || !pim_ifp->pim_enable) {
    1015           0 :                         if (PIM_DEBUG_PIM_NHT)
    1016           0 :                                 zlog_debug(
    1017             :                                         "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
    1018             :                                         __func__, ifp->name, pim->vrf->name,
    1019             :                                         first_ifindex, &src);
    1020           0 :                         if (i == mod_val)
    1021           0 :                                 mod_val++;
    1022           0 :                         i++;
    1023           0 :                         continue;
    1024             :                 }
    1025           0 :                 if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
    1026           0 :                         nbr = nbrs[i];
    1027           0 :                         if (PIM_DEBUG_PIM_NHT_DETAIL)
    1028           0 :                                 zlog_debug("ifp name: %s(%s), pim nbr: %p",
    1029             :                                            ifp->name, pim->vrf->name, nbr);
    1030           0 :                         if (!nbr && !if_is_loopback(ifp)) {
    1031           0 :                                 if (i == mod_val)
    1032           0 :                                         mod_val++;
    1033           0 :                                 if (PIM_DEBUG_PIM_NHT)
    1034           0 :                                         zlog_debug(
    1035             :                                                 "%s: NBR (%pPA) not found on input interface %s(%s) (RPF for source %pPA)",
    1036             :                                                 __func__,
    1037             :                                                 &nexthop_tab[i].nexthop_addr,
    1038             :                                                 ifp->name, pim->vrf->name,
    1039             :                                                 &src);
    1040           0 :                                 i++;
    1041           0 :                                 continue;
    1042             :                         }
    1043             :                 }
    1044             : 
    1045           0 :                 if (i == mod_val) {
    1046           0 :                         if (PIM_DEBUG_PIM_NHT)
    1047           0 :                                 zlog_debug(
    1048             :                                         "%s: found nhop %pPA for addr %pPA interface %s(%s) metric %d dist %d",
    1049             :                                         __func__, &nexthop_tab[i].nexthop_addr,
    1050             :                                         &src, ifp->name, pim->vrf->name,
    1051             :                                         nexthop_tab[i].route_metric,
    1052             :                                         nexthop_tab[i].protocol_distance);
    1053             :                         /* update nexthop data */
    1054           0 :                         nexthop->interface = ifp;
    1055           0 :                         nexthop->mrib_nexthop_addr =
    1056             :                                 nexthop_tab[i].nexthop_addr;
    1057           0 :                         nexthop->mrib_metric_preference =
    1058           0 :                                 nexthop_tab[i].protocol_distance;
    1059           0 :                         nexthop->mrib_route_metric =
    1060           0 :                                 nexthop_tab[i].route_metric;
    1061           0 :                         nexthop->last_lookup = src;
    1062           0 :                         nexthop->last_lookup_time = pim_time_monotonic_usec();
    1063           0 :                         nexthop->nbr = nbr;
    1064           0 :                         found = 1;
    1065             :                 }
    1066           0 :                 i++;
    1067             :         }
    1068             : 
    1069           0 :         if (found)
    1070             :                 return 1;
    1071             :         else
    1072             :                 return 0;
    1073             : }
    1074             : 
    1075           0 : int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, pim_addr src,
    1076             :                                      struct prefix *grp)
    1077             : {
    1078           0 :         struct pim_nexthop nhop;
    1079           0 :         int vif_index;
    1080           0 :         ifindex_t ifindex;
    1081             : 
    1082           0 :         memset(&nhop, 0, sizeof(nhop));
    1083           0 :         if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 1)) {
    1084           0 :                 if (PIM_DEBUG_PIM_NHT)
    1085           0 :                         zlog_debug(
    1086             :                                 "%s: could not find nexthop ifindex for address %pPA(%s)",
    1087             :                                 __func__, &src, pim->vrf->name);
    1088           0 :                 return -1;
    1089             :         }
    1090             : 
    1091           0 :         ifindex = nhop.interface->ifindex;
    1092           0 :         if (PIM_DEBUG_PIM_NHT)
    1093           0 :                 zlog_debug(
    1094             :                         "%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA",
    1095             :                         __func__, ifindex,
    1096             :                         ifindex2ifname(ifindex, pim->vrf->vrf_id),
    1097             :                         pim->vrf->name, &src);
    1098             : 
    1099           0 :         vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
    1100             : 
    1101           0 :         if (vif_index < 0) {
    1102           0 :                 if (PIM_DEBUG_PIM_NHT) {
    1103           0 :                         zlog_debug(
    1104             :                                 "%s: low vif_index=%d(%s) < 1 nexthop for address %pPA",
    1105             :                                 __func__, vif_index, pim->vrf->name, &src);
    1106             :                 }
    1107           0 :                 return -2;
    1108             :         }
    1109             : 
    1110             :         return vif_index;
    1111             : }

Generated by: LCOV version v1.16-topotato