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