3 * Copyright (C) 2017 Cumulus Networks, Inc.
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.
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.
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
29 #include "lib/printfrr.h"
32 #include "pimd/pim_nht.h"
36 #include "pim_ifchannel.h"
37 #include "pim_mroute.h"
38 #include "pim_zebra.h"
39 #include "pim_upstream.h"
41 #include "pim_jp_agg.h"
42 #include "pim_zebra.h"
43 #include "pim_zlookup.h"
48 * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
51 void pim_sendmsg_zebra_rnh(struct pim_instance
*pim
, struct zclient
*zclient
,
52 struct pim_nexthop_cache
*pnc
, int command
)
57 p
= &(pnc
->rpf
.rpf_addr
);
58 ret
= zclient_send_rnh(zclient
, command
, p
, SAFI_UNICAST
, false, false,
60 if (ret
== ZCLIENT_SEND_FAILURE
)
61 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
63 if (PIM_DEBUG_PIM_NHT
)
65 "%s: NHT %sregistered addr %pFX(%s) with Zebra ret:%d ",
67 (command
== ZEBRA_NEXTHOP_REGISTER
) ? " " : "de", p
,
73 struct pim_nexthop_cache
*pim_nexthop_cache_find(struct pim_instance
*pim
,
76 struct pim_nexthop_cache
*pnc
= NULL
;
77 struct pim_nexthop_cache lookup
;
79 lookup
.rpf
.rpf_addr
= rpf
->rpf_addr
;
80 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
85 static struct pim_nexthop_cache
*pim_nexthop_cache_add(struct pim_instance
*pim
,
86 struct pim_rpf
*rpf_addr
)
88 struct pim_nexthop_cache
*pnc
;
91 pnc
= XCALLOC(MTYPE_PIM_NEXTHOP_CACHE
,
92 sizeof(struct pim_nexthop_cache
));
93 pnc
->rpf
.rpf_addr
= rpf_addr
->rpf_addr
;
95 pnc
= hash_get(pim
->rpf_hash
, pnc
, hash_alloc_intern
);
97 pnc
->rp_list
= list_new();
98 pnc
->rp_list
->cmp
= pim_rp_list_cmp
;
100 snprintfrr(hash_name
, sizeof(hash_name
), "PNC %pFX(%s) Upstream Hash",
101 &pnc
->rpf
.rpf_addr
, pim
->vrf
->name
);
102 pnc
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
103 pim_upstream_equal
, hash_name
);
108 static struct pim_nexthop_cache
*pim_nht_get(struct pim_instance
*pim
,
111 struct pim_nexthop_cache
*pnc
= NULL
;
113 struct zclient
*zclient
= NULL
;
115 zclient
= pim_zebra_zclient_get();
116 memset(&rpf
, 0, sizeof(struct pim_rpf
));
117 rpf
.rpf_addr
= *addr
;
119 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
121 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
122 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
123 ZEBRA_NEXTHOP_REGISTER
);
124 if (PIM_DEBUG_PIM_NHT_DETAIL
)
126 "%s: NHT cache and zebra notification added for %pFX(%s)",
127 __func__
, addr
, pim
->vrf
->name
);
133 /* TBD: this does several distinct things and should probably be split up.
134 * (checking state vs. returning pnc vs. adding upstream vs. adding rp)
136 int pim_find_or_track_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
137 struct pim_upstream
*up
, struct rp_info
*rp
,
138 struct pim_nexthop_cache
*out_pnc
)
140 struct pim_nexthop_cache
*pnc
;
141 struct listnode
*ch_node
= NULL
;
143 pnc
= pim_nht_get(pim
, addr
);
145 assertf(up
|| rp
, "addr=%pFX", addr
);
148 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
150 listnode_add_sort(pnc
->rp_list
, rp
);
154 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
156 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
158 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
166 void pim_nht_bsr_add(struct pim_instance
*pim
, struct in_addr addr
)
168 struct pim_nexthop_cache
*pnc
;
171 pfx
.family
= AF_INET
;
172 pfx
.prefixlen
= IPV4_MAX_BITLEN
;
173 pfx
.u
.prefix4
= addr
;
175 pnc
= pim_nht_get(pim
, &pfx
);
179 #endif /* PIM_IPV == 4 */
181 static void pim_nht_drop_maybe(struct pim_instance
*pim
,
182 struct pim_nexthop_cache
*pnc
)
184 if (PIM_DEBUG_PIM_NHT
)
186 "%s: NHT %pFX(%s) rp_list count:%d upstream count:%ld BSR count:%u",
187 __func__
, &pnc
->rpf
.rpf_addr
, pim
->vrf
->name
,
188 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
,
191 if (pnc
->rp_list
->count
== 0 && pnc
->upstream_hash
->count
== 0
192 && pnc
->bsr_count
== 0) {
193 struct zclient
*zclient
= pim_zebra_zclient_get();
195 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
196 ZEBRA_NEXTHOP_UNREGISTER
);
198 list_delete(&pnc
->rp_list
);
199 hash_free(pnc
->upstream_hash
);
201 hash_release(pim
->rpf_hash
, pnc
);
203 nexthops_free(pnc
->nexthop
);
204 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
208 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
209 struct pim_upstream
*up
, struct rp_info
*rp
)
211 struct pim_nexthop_cache
*pnc
= NULL
;
212 struct pim_nexthop_cache lookup
;
213 struct pim_upstream
*upstream
= NULL
;
215 /* Remove from RPF hash if it is the last entry */
216 lookup
.rpf
.rpf_addr
= *addr
;
217 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
219 zlog_warn("attempting to delete nonexistent NHT entry %pFX",
225 /* Release the (*, G)upstream from pnc->upstream_hash,
226 * whose Group belongs to the RP getting deleted
228 frr_each (rb_pim_upstream
, &pim
->upstream_head
, upstream
) {
230 struct rp_info
*trp_info
;
232 if (!pim_addr_is_any(upstream
->sg
.src
))
235 pim_addr_to_prefix(&grp
, upstream
->sg
.grp
);
236 trp_info
= pim_rp_find_match_group(pim
, &grp
);
238 hash_release(pnc
->upstream_hash
, upstream
);
240 listnode_delete(pnc
->rp_list
, rp
);
244 hash_release(pnc
->upstream_hash
, up
);
246 pim_nht_drop_maybe(pim
, pnc
);
250 void pim_nht_bsr_del(struct pim_instance
*pim
, struct in_addr addr
)
252 struct pim_nexthop_cache
*pnc
= NULL
;
253 struct pim_nexthop_cache lookup
;
256 * Nothing to do here if the address to unregister
257 * is 0.0.0.0 as that the BSR has not been registered
260 if (addr
.s_addr
== INADDR_ANY
)
263 lookup
.rpf
.rpf_addr
.family
= AF_INET
;
264 lookup
.rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
265 lookup
.rpf
.rpf_addr
.u
.prefix4
= addr
;
267 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
270 zlog_warn("attempting to delete nonexistent NHT BSR entry %pI4",
275 assertf(pnc
->bsr_count
> 0, "addr=%pI4", &addr
);
278 pim_nht_drop_maybe(pim
, pnc
);
281 bool pim_nht_bsr_rpf_check(struct pim_instance
*pim
, struct in_addr bsr_addr
,
282 struct interface
*src_ifp
, pim_addr src_ip
)
284 struct pim_nexthop_cache
*pnc
= NULL
;
285 struct pim_nexthop_cache lookup
;
286 struct pim_neighbor
*nbr
= NULL
;
288 struct interface
*ifp
;
290 lookup
.rpf
.rpf_addr
.family
= AF_INET
;
291 lookup
.rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
292 lookup
.rpf
.rpf_addr
.u
.prefix4
= bsr_addr
;
294 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
295 if (!pnc
|| !CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
)) {
296 /* BSM from a new freshly registered BSR - do a synchronous
297 * zebra query since otherwise we'd drop the first packet,
298 * leading to additional delay in picking up BSM data
301 /* FIXME: this should really be moved into a generic NHT
302 * function that does "add and get immediate result" or maybe
303 * "check cache or get immediate result." But until that can
304 * be worked in, here's a copy of the code below :(
306 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
308 struct interface
*ifp
= NULL
;
311 memset(nexthop_tab
, 0, sizeof(nexthop_tab
));
312 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
,
313 MULTIPATH_NUM
, bsr_addr
,
314 PIM_NEXTHOP_LOOKUP_MAX
);
316 if (num_ifindex
<= 0)
319 for (i
= 0; i
< num_ifindex
; i
++) {
320 struct pim_zlookup_nexthop
*znh
= &nexthop_tab
[i
];
322 /* pim_zlookup_nexthop has no ->type */
324 /* 1:1 match code below with znh instead of nh */
325 ifp
= if_lookup_by_index(znh
->ifindex
,
328 if (!ifp
|| !ifp
->info
)
331 if (if_is_loopback(ifp
) && if_is_loopback(src_ifp
))
334 nbr
= pim_neighbor_find_prefix(ifp
, &znh
->nexthop_addr
);
338 return znh
->ifindex
== src_ifp
->ifindex
339 && znh
->nexthop_addr
.u
.prefix4
.s_addr
345 if (!CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
))
348 /* if we accept BSMs from more than one ECMP nexthop, this will cause
349 * BSM message "multiplication" for each ECMP hop. i.e. if you have
350 * 4-way ECMP and 4 hops you end up with 256 copies of each BSM
353 * so... only accept the first (IPv4) valid nexthop as source.
356 for (nh
= pnc
->nexthop
; nh
; nh
= nh
->next
) {
361 case NEXTHOP_TYPE_IPV4
:
362 if (nh
->ifindex
== IFINDEX_INTERNAL
)
366 case NEXTHOP_TYPE_IPV4_IFINDEX
:
367 nhaddr
= nh
->gate
.ipv4
;
370 case NEXTHOP_TYPE_IPV6
:
371 if (nh
->ifindex
== IFINDEX_INTERNAL
)
375 case NEXTHOP_TYPE_IPV6_IFINDEX
:
376 nhaddr
= nh
->gate
.ipv6
;
379 case NEXTHOP_TYPE_IFINDEX
:
387 ifp
= if_lookup_by_index(nh
->ifindex
, pim
->vrf
->vrf_id
);
388 if (!ifp
|| !ifp
->info
)
391 if (if_is_loopback(ifp
) && if_is_loopback(src_ifp
))
394 /* MRIB (IGP) may be pointing at a router where PIM is down */
395 nbr
= pim_neighbor_find(ifp
, nhaddr
);
399 return nh
->ifindex
== src_ifp
->ifindex
400 && nhaddr
.s_addr
== src_ip
.s_addr
;
404 #endif /* PIM_IPV == 4 */
406 void pim_rp_nexthop_del(struct rp_info
*rp_info
)
408 rp_info
->rp
.source_nexthop
.interface
= NULL
;
409 pim_addr_to_prefix(&rp_info
->rp
.source_nexthop
.mrib_nexthop_addr
,
411 rp_info
->rp
.source_nexthop
.mrib_metric_preference
=
412 router
->infinite_assert_metric
.metric_preference
;
413 rp_info
->rp
.source_nexthop
.mrib_route_metric
=
414 router
->infinite_assert_metric
.route_metric
;
417 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
418 static void pim_update_rp_nh(struct pim_instance
*pim
,
419 struct pim_nexthop_cache
*pnc
)
421 struct listnode
*node
= NULL
;
422 struct rp_info
*rp_info
= NULL
;
424 /*Traverse RP list and update each RP Nexthop info */
425 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
426 if (pim_rpf_addr_is_inaddr_any(&rp_info
->rp
))
429 // Compute PIM RPF using cached nexthop
430 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
431 &rp_info
->rp
.rpf_addr
,
433 pim_rp_nexthop_del(rp_info
);
437 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
438 static int pim_update_upstream_nh_helper(struct hash_bucket
*bucket
, void *arg
)
440 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
441 struct pim_upstream
*up
= (struct pim_upstream
*)bucket
->data
;
443 enum pim_rpf_result rpf_result
;
446 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
447 rpf_result
= pim_rpf_update(pim
, up
, &old
, __func__
);
449 /* update kernel multicast forwarding cache (MFC); if the
450 * RPF nbr is now unreachable the MFC has already been updated
453 if (rpf_result
!= PIM_RPF_FAILURE
)
454 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
456 if (rpf_result
== PIM_RPF_CHANGED
||
457 (rpf_result
== PIM_RPF_FAILURE
&& old
.source_nexthop
.interface
))
458 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
461 if (PIM_DEBUG_PIM_NHT
) {
463 "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
464 __func__
, up
->sg_str
, pim
->vrf
->name
,
465 old
.source_nexthop
.interface
? old
.source_nexthop
468 up
->rpf
.source_nexthop
.interface
? up
->rpf
.source_nexthop
473 return HASHWALK_CONTINUE
;
476 static int pim_update_upstream_nh(struct pim_instance
*pim
,
477 struct pim_nexthop_cache
*pnc
)
479 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
481 pim_zebra_update_all_interfaces(pim
);
486 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
493 hash_val
= prefix_hash_key(src
);
495 hash_val
^= prefix_hash_key(grp
);
499 static int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
500 struct pim_nexthop_cache
*pnc
,
501 struct pim_nexthop
*nexthop
,
502 struct prefix
*src
, struct prefix
*grp
,
505 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
506 struct interface
*ifps
[MULTIPATH_NUM
];
507 struct nexthop
*nh_node
= NULL
;
508 ifindex_t first_ifindex
;
509 struct interface
*ifp
= NULL
;
510 uint32_t hash_val
= 0, mod_val
= 0;
511 uint8_t nh_iter
= 0, found
= 0;
512 uint32_t i
, num_nbrs
= 0;
513 pim_addr nh_addr
= pim_addr_from_prefix(&(nexthop
->mrib_nexthop_addr
));
514 pim_addr src_addr
= pim_addr_from_prefix(src
);
515 pim_addr grp_addr
= pim_addr_from_prefix(grp
);
517 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
520 memset(&nbrs
, 0, sizeof(nbrs
));
521 memset(&ifps
, 0, sizeof(ifps
));
524 // Current Nexthop is VALID, check to stay on the current path.
525 if (nexthop
->interface
&& nexthop
->interface
->info
&&
526 (!pim_addr_is_any(nh_addr
))) {
527 /* User configured knob to explicitly switch
528 to new path is disabled or current path
529 metric is less than nexthop update.
532 if (pim
->ecmp_rebalance_enable
== 0) {
533 uint8_t curr_route_valid
= 0;
534 // Check if current nexthop is present in new updated
536 // If the current nexthop is not valid, candidate to
537 // choose new Nexthop.
538 for (nh_node
= pnc
->nexthop
; nh_node
;
539 nh_node
= nh_node
->next
) {
540 curr_route_valid
= (nexthop
->interface
->ifindex
541 == nh_node
->ifindex
);
542 if (curr_route_valid
)
546 if (curr_route_valid
&&
547 !pim_if_connected_to_source(nexthop
->interface
,
549 nbr
= pim_neighbor_find_prefix(
551 &nexthop
->mrib_nexthop_addr
);
553 && !if_is_loopback(nexthop
->interface
)) {
554 if (PIM_DEBUG_PIM_NHT
)
556 "%s: current nexthop does not have nbr ",
559 /* update metric even if the upstream
560 * neighbor stays unchanged
562 nexthop
->mrib_metric_preference
=
564 nexthop
->mrib_route_metric
=
566 if (PIM_DEBUG_PIM_NHT
)
568 "%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection",
572 nexthop
->interface
->name
);
580 * Look up all interfaces and neighbors,
581 * store for later usage
583 for (nh_node
= pnc
->nexthop
, i
= 0; nh_node
;
584 nh_node
= nh_node
->next
, i
++) {
586 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf
->vrf_id
);
589 pim_addr nhaddr
= nh_node
->gate
.ipv4
;
591 pim_addr nhaddr
= nh_node
->gate
.ipv6
;
593 nbrs
[i
] = pim_neighbor_find(ifps
[i
], nhaddr
);
595 pim_if_connected_to_source(ifps
[i
], src_addr
))
599 if (pim
->ecmp_enable
) {
600 uint32_t consider
= pnc
->nexthop_num
;
602 if (neighbor_needed
&& num_nbrs
< consider
)
608 // PIM ECMP flag is enable then choose ECMP path.
609 hash_val
= pim_compute_ecmp_hash(src
, grp
);
610 mod_val
= hash_val
% consider
;
613 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
614 nh_node
= nh_node
->next
) {
615 first_ifindex
= nh_node
->ifindex
;
618 if (PIM_DEBUG_PIM_NHT
)
620 "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
621 __FILE__
, __func__
, first_ifindex
,
622 &src_addr
, pim
->vrf
->name
);
623 if (nh_iter
== mod_val
)
624 mod_val
++; // Select nexthpath
629 if (PIM_DEBUG_PIM_NHT
)
631 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
632 __func__
, ifp
->name
, pim
->vrf
->name
,
633 first_ifindex
, &src_addr
);
634 if (nh_iter
== mod_val
)
635 mod_val
++; // Select nexthpath
640 if (neighbor_needed
&&
641 !pim_if_connected_to_source(ifp
, src_addr
)) {
643 if (!nbr
&& !if_is_loopback(ifp
)) {
644 if (PIM_DEBUG_PIM_NHT
)
646 "%s: pim nbr not found on input interface %s(%s)",
649 if (nh_iter
== mod_val
)
650 mod_val
++; // Select nexthpath
656 if (nh_iter
== mod_val
) {
657 nexthop
->interface
= ifp
;
658 nexthop
->mrib_nexthop_addr
.family
= PIM_AF
;
659 nexthop
->mrib_nexthop_addr
.prefixlen
= PIM_MAX_BITLEN
;
661 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
664 nexthop
->mrib_nexthop_addr
.u
.prefix6
=
667 nexthop
->mrib_metric_preference
= pnc
->distance
;
668 nexthop
->mrib_route_metric
= pnc
->metric
;
669 nexthop
->last_lookup
= src_addr
;
670 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
673 if (PIM_DEBUG_PIM_NHT
)
675 "%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d",
676 __func__
, &src_addr
, &grp_addr
,
677 pim
->vrf
->name
, ifp
->name
, &nh_addr
,
678 mod_val
, nh_iter
, pim
->ecmp_enable
);
689 /* This API is used to parse Registered address nexthop update coming from Zebra
691 int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS
)
693 struct nexthop
*nexthop
;
694 struct nexthop
*nhlist_head
= NULL
;
695 struct nexthop
*nhlist_tail
= NULL
;
698 struct pim_nexthop_cache
*pnc
= NULL
;
699 struct interface
*ifp
= NULL
;
700 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
701 struct pim_instance
*pim
;
702 struct zapi_route nhr
;
709 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &match
, &nhr
)) {
710 zlog_err("%s: Decode of nexthop update from zebra failed",
715 if (cmd
== ZEBRA_NEXTHOP_UPDATE
) {
716 prefix_copy(&rpf
.rpf_addr
, &match
);
717 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
719 if (PIM_DEBUG_PIM_NHT
)
721 "%s: Skipping NHT update, addr %pFX is not in local cached DB.",
722 __func__
, &rpf
.rpf_addr
);
727 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
732 pnc
->last_update
= pim_time_monotonic_usec();
734 if (nhr
.nexthop_num
) {
735 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
737 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
738 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
739 switch (nexthop
->type
) {
740 case NEXTHOP_TYPE_IFINDEX
:
742 * Connected route (i.e. no nexthop), use
743 * RPF address from nexthop cache (i.e.
744 * destination) as PIM nexthop.
747 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
749 pnc
->rpf
.rpf_addr
.u
.prefix4
;
751 nexthop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
753 pnc
->rpf
.rpf_addr
.u
.prefix6
;
757 /* RFC5549 IPv4-over-IPv6 nexthop handling:
758 * if we get an IPv6 nexthop in IPv4 PIM, hunt down a
759 * PIM neighbor and use that instead.
761 case NEXTHOP_TYPE_IPV6_IFINDEX
: {
762 struct interface
*ifp1
= NULL
;
763 struct pim_neighbor
*nbr
= NULL
;
765 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
771 /* FIXME: should really use nbr's
772 * secondary address list here
774 nbr
= pim_neighbor_find_if(ifp1
);
776 /* Overwrite with Nbr address as NH addr */
778 nexthop
->gate
.ipv4
= nbr
->source_addr
;
780 // Mark nexthop address to 0 until PIM
782 nexthop
->gate
.ipv4
= PIMADDR_ANY
;
787 case NEXTHOP_TYPE_IPV6_IFINDEX
:
789 case NEXTHOP_TYPE_IPV6
:
790 case NEXTHOP_TYPE_IPV4
:
791 case NEXTHOP_TYPE_IPV4_IFINDEX
:
792 case NEXTHOP_TYPE_BLACKHOLE
:
793 /* nothing to do for the other nexthop types */
797 ifp
= if_lookup_by_index(nexthop
->ifindex
,
800 if (PIM_DEBUG_PIM_NHT
) {
801 char buf
[NEXTHOP_STRLEN
];
803 "%s: could not find interface for ifindex %d(%s) (addr %s)",
804 __func__
, nexthop
->ifindex
,
806 nexthop2str(nexthop
, buf
,
809 nexthop_free(nexthop
);
813 if (PIM_DEBUG_PIM_NHT
) {
815 pim_addr nhaddr
= nexthop
->gate
.ipv4
;
817 pim_addr nhaddr
= nexthop
->gate
.ipv6
;
820 "%s: NHT addr %pFX(%s) %d-nhop via %pPA(%s) type %d distance:%u metric:%u ",
821 __func__
, &match
, pim
->vrf
->name
, i
+ 1,
822 &nhaddr
, ifp
->name
, nexthop
->type
,
823 nhr
.distance
, nhr
.metric
);
828 * Though Multicast is not enabled on this
829 * Interface store it in database otheriwse we
830 * may miss this update and this will not cause
831 * any issue, because while choosing the path we
832 * are ommitting the Interfaces which are not
835 if (PIM_DEBUG_PIM_NHT
) {
836 char buf
[NEXTHOP_STRLEN
];
839 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
843 nexthop2str(nexthop
, buf
,
849 nhlist_tail
->next
= nexthop
;
850 nhlist_tail
= nexthop
;
852 nhlist_tail
= nexthop
;
853 nhlist_head
= nexthop
;
855 // Only keep track of nexthops which are PIM enabled.
858 /* Reset existing pnc->nexthop before assigning new list */
859 nexthops_free(pnc
->nexthop
);
860 pnc
->nexthop
= nhlist_head
;
861 if (pnc
->nexthop_num
) {
862 pnc
->flags
|= PIM_NEXTHOP_VALID
;
863 pnc
->distance
= nhr
.distance
;
864 pnc
->metric
= nhr
.metric
;
867 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
868 pnc
->nexthop_num
= nhr
.nexthop_num
;
869 nexthops_free(pnc
->nexthop
);
872 SET_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
);
874 if (PIM_DEBUG_PIM_NHT
)
876 "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
877 __func__
, &match
, pim
->vrf
->name
, nhr
.nexthop_num
,
878 pnc
->nexthop_num
, vrf_id
, pnc
->upstream_hash
->count
,
879 listcount(pnc
->rp_list
));
881 pim_rpf_set_refresh_time(pim
);
883 if (listcount(pnc
->rp_list
))
884 pim_update_rp_nh(pim
, pnc
);
885 if (pnc
->upstream_hash
->count
)
886 pim_update_upstream_nh(pim
, pnc
);
891 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
892 struct pim_nexthop
*nexthop
, struct prefix
*src
,
893 struct prefix
*grp
, int neighbor_needed
)
895 struct pim_nexthop_cache
*pnc
;
896 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
897 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
900 struct interface
*ifps
[MULTIPATH_NUM
], *ifp
;
904 uint32_t hash_val
= 0, mod_val
= 0;
905 uint32_t num_nbrs
= 0;
906 pim_addr src_addr
= pim_addr_from_prefix(src
);
908 if (PIM_DEBUG_PIM_NHT_DETAIL
)
909 zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
910 __func__
, &src_addr
, pim
->vrf
->name
,
911 nexthop
->last_lookup_time
);
915 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
917 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
))
918 return pim_ecmp_nexthop_search(pim
, pnc
, nexthop
, src
, grp
,
922 memset(nexthop_tab
, 0,
923 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
924 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
925 src_addr
, PIM_NEXTHOP_LOOKUP_MAX
);
926 if (num_ifindex
< 1) {
927 if (PIM_DEBUG_PIM_NHT
)
929 "%s: could not find nexthop ifindex for address %pPA(%s)",
930 __func__
, &src_addr
, pim
->vrf
->name
);
934 memset(&nbrs
, 0, sizeof(nbrs
));
935 memset(&ifps
, 0, sizeof(ifps
));
938 * Look up all interfaces and neighbors,
939 * store for later usage
941 for (i
= 0; i
< num_ifindex
; i
++) {
942 ifps
[i
] = if_lookup_by_index(nexthop_tab
[i
].ifindex
,
945 nbrs
[i
] = pim_neighbor_find_prefix(
946 ifps
[i
], &nexthop_tab
[i
].nexthop_addr
);
948 pim_if_connected_to_source(ifps
[i
], src_addr
))
953 // If PIM ECMP enable then choose ECMP path.
954 if (pim
->ecmp_enable
) {
955 uint32_t consider
= num_ifindex
;
957 if (neighbor_needed
&& num_nbrs
< consider
)
963 hash_val
= pim_compute_ecmp_hash(src
, grp
);
964 mod_val
= hash_val
% consider
;
965 if (PIM_DEBUG_PIM_NHT_DETAIL
)
966 zlog_debug("%s: hash_val %u mod_val %u", __func__
,
971 while (!found
&& (i
< num_ifindex
)) {
972 first_ifindex
= nexthop_tab
[i
].ifindex
;
976 if (PIM_DEBUG_PIM_NHT
)
978 "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
979 __FILE__
, __func__
, first_ifindex
,
980 &src_addr
, pim
->vrf
->name
);
988 if (PIM_DEBUG_PIM_NHT
)
990 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
991 __func__
, ifp
->name
, pim
->vrf
->name
,
992 first_ifindex
, &src_addr
);
998 if (neighbor_needed
&&
999 !pim_if_connected_to_source(ifp
, src_addr
)) {
1001 if (PIM_DEBUG_PIM_NHT_DETAIL
)
1002 zlog_debug("ifp name: %s(%s), pim nbr: %p",
1003 ifp
->name
, pim
->vrf
->name
, nbr
);
1004 if (!nbr
&& !if_is_loopback(ifp
)) {
1007 if (PIM_DEBUG_PIM_NHT
)
1009 "%s: NBR (%pFXh) not found on input interface %s(%s) (RPF for source %pPA)",
1011 &nexthop_tab
[i
].nexthop_addr
,
1012 ifp
->name
, pim
->vrf
->name
,
1020 if (PIM_DEBUG_PIM_NHT
) {
1021 char nexthop_str
[PREFIX_STRLEN
];
1023 pim_addr_dump("<nexthop?>",
1024 &nexthop_tab
[i
].nexthop_addr
,
1025 nexthop_str
, sizeof(nexthop_str
));
1027 "%s: found nhop %s for addr %pPA interface %s(%s) metric %d dist %d",
1028 __func__
, nexthop_str
, &src_addr
,
1029 ifp
->name
, pim
->vrf
->name
,
1030 nexthop_tab
[i
].route_metric
,
1031 nexthop_tab
[i
].protocol_distance
);
1033 /* update nexthop data */
1034 nexthop
->interface
= ifp
;
1035 nexthop
->mrib_nexthop_addr
=
1036 nexthop_tab
[i
].nexthop_addr
;
1037 nexthop
->mrib_metric_preference
=
1038 nexthop_tab
[i
].protocol_distance
;
1039 nexthop
->mrib_route_metric
=
1040 nexthop_tab
[i
].route_metric
;
1041 nexthop
->last_lookup
= src_addr
;
1042 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
1055 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
1056 struct prefix
*src
, struct prefix
*grp
)
1058 struct pim_nexthop nhop
;
1063 if (PIM_DEBUG_PIM_NHT_DETAIL
) {
1064 src_addr
= pim_addr_from_prefix(src
);
1067 memset(&nhop
, 0, sizeof(nhop
));
1068 if (!pim_ecmp_nexthop_lookup(pim
, &nhop
, src
, grp
, 1)) {
1069 if (PIM_DEBUG_PIM_NHT
)
1071 "%s: could not find nexthop ifindex for address %pPA(%s)",
1072 __func__
, &src_addr
, pim
->vrf
->name
);
1076 ifindex
= nhop
.interface
->ifindex
;
1077 if (PIM_DEBUG_PIM_NHT
)
1079 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA",
1081 ifindex2ifname(ifindex
, pim
->vrf
->vrf_id
),
1082 pim
->vrf
->name
, &src_addr
);
1084 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
1086 if (vif_index
< 0) {
1087 if (PIM_DEBUG_PIM_NHT
) {
1089 "%s: low vif_index=%d(%s) < 1 nexthop for address %pPA",
1090 __func__
, vif_index
, pim
->vrf
->name
, &src_addr
);