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