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