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