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"
47 * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
50 void pim_sendmsg_zebra_rnh(struct pim_instance
*pim
, struct zclient
*zclient
,
51 struct pim_nexthop_cache
*pnc
, int command
)
56 p
= &(pnc
->rpf
.rpf_addr
);
57 ret
= zclient_send_rnh(zclient
, command
, p
, false, false,
59 if (ret
== ZCLIENT_SEND_FAILURE
)
60 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
62 if (PIM_DEBUG_PIM_NHT
)
64 "%s: NHT %sregistered addr %pFX(%s) with Zebra ret:%d ",
66 (command
== ZEBRA_NEXTHOP_REGISTER
) ? " " : "de", p
,
72 struct pim_nexthop_cache
*pim_nexthop_cache_find(struct pim_instance
*pim
,
75 struct pim_nexthop_cache
*pnc
= NULL
;
76 struct pim_nexthop_cache lookup
;
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
;
82 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
87 static struct pim_nexthop_cache
*pim_nexthop_cache_add(struct pim_instance
*pim
,
88 struct pim_rpf
*rpf_addr
)
90 struct pim_nexthop_cache
*pnc
;
93 pnc
= XCALLOC(MTYPE_PIM_NEXTHOP_CACHE
,
94 sizeof(struct pim_nexthop_cache
));
95 pnc
->rpf
.rpf_addr
.family
= rpf_addr
->rpf_addr
.family
;
96 pnc
->rpf
.rpf_addr
.prefixlen
= rpf_addr
->rpf_addr
.prefixlen
;
97 pnc
->rpf
.rpf_addr
.u
.prefix4
.s_addr
=
98 rpf_addr
->rpf_addr
.u
.prefix4
.s_addr
;
100 pnc
= hash_get(pim
->rpf_hash
, pnc
, hash_alloc_intern
);
102 pnc
->rp_list
= list_new();
103 pnc
->rp_list
->cmp
= pim_rp_list_cmp
;
105 snprintfrr(hash_name
, sizeof(hash_name
), "PNC %pFX(%s) Upstream Hash",
106 &pnc
->rpf
.rpf_addr
, pim
->vrf
->name
);
107 pnc
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
108 pim_upstream_equal
, hash_name
);
114 * pim_find_or_track_nexthop
116 * This API is used to Register an address with Zebra
121 int pim_find_or_track_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
122 struct pim_upstream
*up
, struct rp_info
*rp
,
123 bool bsr_track_needed
,
124 struct pim_nexthop_cache
*out_pnc
)
126 struct pim_nexthop_cache
*pnc
= NULL
;
128 struct listnode
*ch_node
= NULL
;
129 struct zclient
*zclient
= NULL
;
131 zclient
= pim_zebra_zclient_get();
132 memset(&rpf
, 0, sizeof(struct pim_rpf
));
133 rpf
.rpf_addr
.family
= addr
->family
;
134 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
135 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
137 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
139 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
140 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
141 ZEBRA_NEXTHOP_REGISTER
);
142 if (PIM_DEBUG_PIM_NHT
)
144 "%s: NHT cache and zebra notification added for %pFX(%s)",
145 __func__
, addr
, pim
->vrf
->name
);
149 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
151 listnode_add_sort(pnc
->rp_list
, rp
);
155 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
157 if (bsr_track_needed
)
158 pnc
->bsr_tracking
= true;
160 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
162 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
169 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
170 struct pim_upstream
*up
, struct rp_info
*rp
,
171 bool del_bsr_tracking
)
173 struct pim_nexthop_cache
*pnc
= NULL
;
174 struct pim_nexthop_cache lookup
;
175 struct zclient
*zclient
= NULL
;
176 struct pim_upstream
*upstream
= NULL
;
178 zclient
= pim_zebra_zclient_get();
180 /* Remove from RPF hash if it is the last entry */
181 lookup
.rpf
.rpf_addr
= *addr
;
182 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
185 /* Release the (*, G)upstream from pnc->upstream_hash,
186 * whose Group belongs to the RP getting deleted
188 frr_each (rb_pim_upstream
, &pim
->upstream_head
,
191 struct rp_info
*trp_info
;
193 if (upstream
->sg
.src
.s_addr
!= INADDR_ANY
)
196 grp
.family
= AF_INET
;
197 grp
.prefixlen
= IPV4_MAX_BITLEN
;
198 grp
.u
.prefix4
= upstream
->sg
.grp
;
200 trp_info
= pim_rp_find_match_group(pim
, &grp
);
202 hash_release(pnc
->upstream_hash
,
205 listnode_delete(pnc
->rp_list
, rp
);
209 hash_release(pnc
->upstream_hash
, up
);
211 if (del_bsr_tracking
)
212 pnc
->bsr_tracking
= false;
214 if (PIM_DEBUG_PIM_NHT
)
216 "%s: NHT %pFX(%s) rp_list count:%d upstream count:%ld",
217 __func__
, addr
, pim
->vrf
->name
,
218 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
220 if (pnc
->rp_list
->count
== 0
221 && pnc
->upstream_hash
->count
== 0
222 && pnc
->bsr_tracking
== false) {
223 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
224 ZEBRA_NEXTHOP_UNREGISTER
);
226 list_delete(&pnc
->rp_list
);
227 hash_free(pnc
->upstream_hash
);
229 hash_release(pim
->rpf_hash
, pnc
);
231 nexthops_free(pnc
->nexthop
);
232 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
237 /* Given a source address and a neighbor address, check if the neighbor is one
238 * of the next hop to reach the source. search from zebra route database
240 bool pim_nexthop_match(struct pim_instance
*pim
, struct in_addr addr
,
241 struct in_addr ip_src
)
243 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
245 ifindex_t first_ifindex
= 0;
246 struct interface
*ifp
= NULL
;
247 struct pim_neighbor
*nbr
= NULL
;
250 if (addr
.s_addr
== INADDR_NONE
)
253 memset(nexthop_tab
, 0,
254 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
255 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
256 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
257 if (num_ifindex
< 1) {
258 char addr_str
[INET_ADDRSTRLEN
];
260 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
262 "%s %s: could not find nexthop ifindex for address %s",
263 __FILE__
, __func__
, addr_str
);
267 while (i
< num_ifindex
) {
268 first_ifindex
= nexthop_tab
[i
].ifindex
;
270 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf
->vrf_id
);
272 if (PIM_DEBUG_ZEBRA
) {
273 char addr_str
[INET_ADDRSTRLEN
];
275 pim_inet4_dump("<addr?>", addr
, addr_str
,
278 "%s %s: could not find interface for ifindex %d (address %s)",
279 __FILE__
, __func__
, first_ifindex
,
287 if (PIM_DEBUG_ZEBRA
) {
288 char addr_str
[INET_ADDRSTRLEN
];
290 pim_inet4_dump("<addr?>", addr
, addr_str
,
293 "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
294 __func__
, ifp
->name
, first_ifindex
,
301 if (!pim_if_connected_to_source(ifp
, addr
)) {
302 nbr
= pim_neighbor_find(
303 ifp
, nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
304 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
305 zlog_debug("ifp name: %s, pim nbr: %p",
307 if (!nbr
&& !if_is_loopback(ifp
)) {
313 if (nexthop_tab
[i
].nexthop_addr
.u
.prefix4
.s_addr
323 /* Given a source address and a neighbor address, check if the neighbor is one
324 * of the next hop to reach the source. search from pim next hop cache
326 bool pim_nexthop_match_nht_cache(struct pim_instance
*pim
, struct in_addr addr
,
327 struct in_addr ip_src
)
330 ifindex_t first_ifindex
;
331 struct interface
*ifp
= NULL
;
333 struct pim_neighbor
*nbr
= NULL
;
334 struct nexthop
*nh_node
= NULL
;
335 struct pim_nexthop_cache
*pnc
= NULL
;
337 memset(&rpf
, 0, sizeof(struct pim_rpf
));
338 rpf
.rpf_addr
.family
= AF_INET
;
339 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
340 rpf
.rpf_addr
.u
.prefix4
= addr
;
342 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
343 if (!pnc
|| !pnc
->nexthop_num
)
346 for (nh_node
= pnc
->nexthop
; nh_node
; nh_node
= nh_node
->next
) {
347 first_ifindex
= nh_node
->ifindex
;
348 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf
->vrf_id
);
350 if (PIM_DEBUG_PIM_NHT
) {
351 char addr_str
[INET_ADDRSTRLEN
];
353 pim_inet4_dump("<addr?>", addr
, addr_str
,
356 "%s %s: could not find interface for ifindex %d (address %s(%s))",
357 __FILE__
, __func__
, first_ifindex
,
358 addr_str
, pim
->vrf
->name
);
364 if (PIM_DEBUG_PIM_NHT
) {
365 char addr_str
[INET_ADDRSTRLEN
];
367 pim_inet4_dump("<addr?>", addr
, addr_str
,
370 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
371 __func__
, ifp
->name
, pim
->vrf
->name
,
372 first_ifindex
, addr_str
);
378 if (!pim_if_connected_to_source(ifp
, addr
)) {
379 nbr
= pim_neighbor_find(ifp
, nh_node
->gate
.ipv4
);
380 if (!nbr
&& !if_is_loopback(ifp
)) {
381 if (PIM_DEBUG_PIM_NHT
)
383 "%s: pim nbr not found on input interface %s(%s)",
391 if (nh_node
->gate
.ipv4
.s_addr
== ip_src
.s_addr
)
398 void pim_rp_nexthop_del(struct rp_info
*rp_info
)
400 rp_info
->rp
.source_nexthop
.interface
= NULL
;
401 rp_info
->rp
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
403 rp_info
->rp
.source_nexthop
.mrib_metric_preference
=
404 router
->infinite_assert_metric
.metric_preference
;
405 rp_info
->rp
.source_nexthop
.mrib_route_metric
=
406 router
->infinite_assert_metric
.route_metric
;
409 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
410 static void pim_update_rp_nh(struct pim_instance
*pim
,
411 struct pim_nexthop_cache
*pnc
)
413 struct listnode
*node
= NULL
;
414 struct rp_info
*rp_info
= NULL
;
416 /*Traverse RP list and update each RP Nexthop info */
417 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
418 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
421 // Compute PIM RPF using cached nexthop
422 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
423 &rp_info
->rp
.rpf_addr
,
425 pim_rp_nexthop_del(rp_info
);
429 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
430 static int pim_update_upstream_nh_helper(struct hash_bucket
*bucket
, void *arg
)
432 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
433 struct pim_upstream
*up
= (struct pim_upstream
*)bucket
->data
;
435 enum pim_rpf_result rpf_result
;
438 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
439 rpf_result
= pim_rpf_update(pim
, up
, &old
, __func__
);
441 /* update kernel multicast forwarding cache (MFC); if the
442 * RPF nbr is now unreachable the MFC has already been updated
445 if (rpf_result
!= PIM_RPF_FAILURE
)
446 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
448 if (rpf_result
== PIM_RPF_CHANGED
||
449 (rpf_result
== PIM_RPF_FAILURE
&& old
.source_nexthop
.interface
))
450 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
453 if (PIM_DEBUG_PIM_NHT
) {
455 "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
456 __func__
, up
->sg_str
, pim
->vrf
->name
,
457 old
.source_nexthop
.interface
? old
.source_nexthop
460 up
->rpf
.source_nexthop
.interface
? up
->rpf
.source_nexthop
465 return HASHWALK_CONTINUE
;
468 static int pim_update_upstream_nh(struct pim_instance
*pim
,
469 struct pim_nexthop_cache
*pnc
)
471 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
473 pim_zebra_update_all_interfaces(pim
);
478 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
481 uint32_t s
= 0, g
= 0;
486 switch (src
->family
) {
488 s
= src
->u
.prefix4
.s_addr
;
491 g
= grp
->u
.prefix4
.s_addr
;
497 hash_val
= jhash_2words(g
, s
, 101);
501 static int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
502 struct pim_nexthop_cache
*pnc
,
503 struct pim_nexthop
*nexthop
,
504 struct prefix
*src
, struct prefix
*grp
,
507 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
508 struct interface
*ifps
[MULTIPATH_NUM
];
509 struct nexthop
*nh_node
= NULL
;
510 ifindex_t first_ifindex
;
511 struct interface
*ifp
= NULL
;
512 uint32_t hash_val
= 0, mod_val
= 0;
513 uint8_t nh_iter
= 0, found
= 0;
514 uint32_t i
, num_nbrs
= 0;
516 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
519 memset(&nbrs
, 0, sizeof(nbrs
));
520 memset(&ifps
, 0, sizeof(ifps
));
522 // Current Nexthop is VALID, check to stay on the current path.
523 if (nexthop
->interface
&& nexthop
->interface
->info
524 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
525 != PIM_NET_INADDR_ANY
) {
526 /* User configured knob to explicitly switch
527 to new path is disabled or current path
528 metric is less than nexthop update.
531 if (pim
->ecmp_rebalance_enable
== 0) {
532 uint8_t curr_route_valid
= 0;
533 // Check if current nexthop is present in new updated
535 // If the current nexthop is not valid, candidate to
536 // choose new Nexthop.
537 for (nh_node
= pnc
->nexthop
; nh_node
;
538 nh_node
= nh_node
->next
) {
539 curr_route_valid
= (nexthop
->interface
->ifindex
540 == nh_node
->ifindex
);
541 if (curr_route_valid
)
546 && !pim_if_connected_to_source(nexthop
->interface
,
548 nbr
= pim_neighbor_find(
550 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
552 && !if_is_loopback(nexthop
->interface
)) {
553 if (PIM_DEBUG_PIM_NHT
)
555 "%s: current nexthop does not have nbr ",
558 /* update metric even if the upstream
559 * neighbor stays unchanged
561 nexthop
->mrib_metric_preference
=
563 nexthop
->mrib_route_metric
=
565 if (PIM_DEBUG_PIM_NHT
) {
566 char src_str
[INET_ADDRSTRLEN
];
567 pim_inet4_dump("<addr?>",
571 char grp_str
[INET_ADDRSTRLEN
];
572 pim_inet4_dump("<addr?>",
577 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
579 grp_str
, pim
->vrf
->name
,
580 nexthop
->interface
->name
);
589 * Look up all interfaces and neighbors,
590 * store for later usage
592 for (nh_node
= pnc
->nexthop
, i
= 0; nh_node
;
593 nh_node
= nh_node
->next
, i
++) {
595 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf
->vrf_id
);
597 nbrs
[i
] = pim_neighbor_find(ifps
[i
],
599 if (nbrs
[i
] || pim_if_connected_to_source(ifps
[i
],
605 if (pim
->ecmp_enable
) {
606 uint32_t consider
= pnc
->nexthop_num
;
608 if (neighbor_needed
&& num_nbrs
< consider
)
614 // PIM ECMP flag is enable then choose ECMP path.
615 hash_val
= pim_compute_ecmp_hash(src
, grp
);
616 mod_val
= hash_val
% consider
;
619 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
620 nh_node
= nh_node
->next
) {
621 first_ifindex
= nh_node
->ifindex
;
624 if (PIM_DEBUG_PIM_NHT
) {
625 char addr_str
[INET_ADDRSTRLEN
];
626 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
627 addr_str
, sizeof(addr_str
));
629 "%s %s: could not find interface for ifindex %d (address %s(%s))",
630 __FILE__
, __func__
, first_ifindex
,
631 addr_str
, pim
->vrf
->name
);
633 if (nh_iter
== mod_val
)
634 mod_val
++; // Select nexthpath
639 if (PIM_DEBUG_PIM_NHT
) {
640 char addr_str
[INET_ADDRSTRLEN
];
641 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
642 addr_str
, sizeof(addr_str
));
644 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
645 __func__
, ifp
->name
, pim
->vrf
->name
,
646 first_ifindex
, addr_str
);
648 if (nh_iter
== mod_val
)
649 mod_val
++; // Select nexthpath
655 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
657 if (!nbr
&& !if_is_loopback(ifp
)) {
658 if (PIM_DEBUG_PIM_NHT
)
660 "%s: pim nbr not found on input interface %s(%s)",
663 if (nh_iter
== mod_val
)
664 mod_val
++; // Select nexthpath
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
=
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();
682 if (PIM_DEBUG_PIM_NHT
) {
683 char buf
[INET_ADDRSTRLEN
];
684 char buf2
[INET_ADDRSTRLEN
];
685 char buf3
[INET_ADDRSTRLEN
];
686 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
688 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
692 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
695 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
696 __func__
, buf2
, buf3
, pim
->vrf
->name
,
697 ifp
->name
, buf
, mod_val
, nh_iter
,
710 /* This API is used to parse Registered address nexthop update coming from Zebra
712 int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS
)
714 struct nexthop
*nexthop
;
715 struct nexthop
*nhlist_head
= NULL
;
716 struct nexthop
*nhlist_tail
= NULL
;
719 struct pim_nexthop_cache
*pnc
= NULL
;
720 struct pim_neighbor
*nbr
= NULL
;
721 struct interface
*ifp
= NULL
;
722 struct interface
*ifp1
= NULL
;
723 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
724 struct pim_instance
*pim
;
725 struct zapi_route nhr
;
731 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
732 zlog_err("%s: Decode of nexthop update from zebra failed",
737 if (cmd
== ZEBRA_NEXTHOP_UPDATE
) {
738 prefix_copy(&rpf
.rpf_addr
, &nhr
.prefix
);
739 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
741 if (PIM_DEBUG_PIM_NHT
)
743 "%s: Skipping NHT update, addr %pFX is not in local cached DB.",
744 __func__
, &rpf
.rpf_addr
);
749 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
754 pnc
->last_update
= pim_time_monotonic_usec();
756 if (nhr
.nexthop_num
) {
757 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
759 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
760 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
761 switch (nexthop
->type
) {
762 case NEXTHOP_TYPE_IPV4
:
763 case NEXTHOP_TYPE_IPV4_IFINDEX
:
764 case NEXTHOP_TYPE_IPV6
:
765 case NEXTHOP_TYPE_BLACKHOLE
:
767 case NEXTHOP_TYPE_IFINDEX
:
769 * Connected route (i.e. no nexthop), use
770 * RPF address from nexthop cache (i.e.
771 * destination) as PIM nexthop.
773 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
775 pnc
->rpf
.rpf_addr
.u
.prefix4
;
777 case NEXTHOP_TYPE_IPV6_IFINDEX
:
778 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
784 nbr
= pim_neighbor_find_if(ifp1
);
785 /* Overwrite with Nbr address as NH addr */
787 nexthop
->gate
.ipv4
= nbr
->source_addr
;
789 // Mark nexthop address to 0 until PIM
791 nexthop
->gate
.ipv4
.s_addr
=
798 ifp
= if_lookup_by_index(nexthop
->ifindex
,
801 if (PIM_DEBUG_PIM_NHT
) {
802 char buf
[NEXTHOP_STRLEN
];
804 "%s: could not find interface for ifindex %d(%s) (addr %s)",
805 __func__
, nexthop
->ifindex
,
807 nexthop2str(nexthop
, buf
,
810 nexthop_free(nexthop
);
814 if (PIM_DEBUG_PIM_NHT
)
816 "%s: NHT addr %pFX(%s) %d-nhop via %pI4(%s) type %d distance:%u metric:%u ",
817 __func__
, &nhr
.prefix
, pim
->vrf
->name
,
818 i
+ 1, &nexthop
->gate
.ipv4
,
819 ifp
->name
, nexthop
->type
, nhr
.distance
,
824 * Though Multicast is not enabled on this
825 * Interface store it in database otheriwse we
826 * may miss this update and this will not cause
827 * any issue, because while choosing the path we
828 * are ommitting the Interfaces which are not
831 if (PIM_DEBUG_PIM_NHT
) {
832 char buf
[NEXTHOP_STRLEN
];
835 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
839 nexthop2str(nexthop
, buf
,
845 nhlist_tail
->next
= nexthop
;
846 nhlist_tail
= nexthop
;
848 nhlist_tail
= nexthop
;
849 nhlist_head
= nexthop
;
851 // Only keep track of nexthops which are PIM enabled.
854 /* Reset existing pnc->nexthop before assigning new list */
855 nexthops_free(pnc
->nexthop
);
856 pnc
->nexthop
= nhlist_head
;
857 if (pnc
->nexthop_num
) {
858 pnc
->flags
|= PIM_NEXTHOP_VALID
;
859 pnc
->distance
= nhr
.distance
;
860 pnc
->metric
= nhr
.metric
;
863 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
864 pnc
->nexthop_num
= nhr
.nexthop_num
;
865 nexthops_free(pnc
->nexthop
);
868 SET_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
);
870 if (PIM_DEBUG_PIM_NHT
)
872 "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
873 __func__
, &nhr
.prefix
, pim
->vrf
->name
, nhr
.nexthop_num
,
874 pnc
->nexthop_num
, vrf_id
, pnc
->upstream_hash
->count
,
875 listcount(pnc
->rp_list
));
877 pim_rpf_set_refresh_time(pim
);
879 if (listcount(pnc
->rp_list
))
880 pim_update_rp_nh(pim
, pnc
);
881 if (pnc
->upstream_hash
->count
)
882 pim_update_upstream_nh(pim
, pnc
);
887 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
888 struct pim_nexthop
*nexthop
, struct prefix
*src
,
889 struct prefix
*grp
, int neighbor_needed
)
891 struct pim_nexthop_cache
*pnc
;
892 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
893 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
896 struct interface
*ifps
[MULTIPATH_NUM
], *ifp
;
900 uint32_t hash_val
= 0, mod_val
= 0;
901 uint32_t num_nbrs
= 0;
902 char addr_str
[PREFIX_STRLEN
];
904 if (PIM_DEBUG_PIM_NHT
) {
905 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
907 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
908 __func__
, addr_str
, pim
->vrf
->name
,
909 nexthop
->last_lookup_time
);
912 memset(&rpf
, 0, sizeof(struct pim_rpf
));
913 rpf
.rpf_addr
.family
= AF_INET
;
914 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
915 rpf
.rpf_addr
.u
.prefix4
= src
->u
.prefix4
;
917 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
919 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
))
920 return pim_ecmp_nexthop_search(pim
, pnc
, nexthop
, src
, grp
,
924 memset(nexthop_tab
, 0,
925 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
927 zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
928 src
->u
.prefix4
, PIM_NEXTHOP_LOOKUP_MAX
);
929 if (num_ifindex
< 1) {
930 if (PIM_DEBUG_PIM_NHT
)
932 "%s: could not find nexthop ifindex for address %s(%s)",
933 __func__
, addr_str
, pim
->vrf
->name
);
937 memset(&nbrs
, 0, sizeof(nbrs
));
938 memset(&ifps
, 0, sizeof(ifps
));
941 * Look up all interfaces and neighbors,
942 * store for later usage
944 for (i
= 0; i
< num_ifindex
; i
++) {
945 ifps
[i
] = if_lookup_by_index(nexthop_tab
[i
].ifindex
,
948 nbrs
[i
] = pim_neighbor_find(
949 ifps
[i
], nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
951 || pim_if_connected_to_source(ifps
[i
],
957 // If PIM ECMP enable then choose ECMP path.
958 if (pim
->ecmp_enable
) {
959 uint32_t consider
= num_ifindex
;
961 if (neighbor_needed
&& num_nbrs
< consider
)
967 hash_val
= pim_compute_ecmp_hash(src
, grp
);
968 mod_val
= hash_val
% consider
;
969 if (PIM_DEBUG_PIM_NHT_DETAIL
)
970 zlog_debug("%s: hash_val %u mod_val %u", __func__
,
975 while (!found
&& (i
< num_ifindex
)) {
976 first_ifindex
= nexthop_tab
[i
].ifindex
;
980 if (PIM_DEBUG_PIM_NHT
)
982 "%s %s: could not find interface for ifindex %d (address %s(%s))",
983 __FILE__
, __func__
, first_ifindex
,
984 addr_str
, pim
->vrf
->name
);
992 if (PIM_DEBUG_PIM_NHT
)
994 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
995 __func__
, ifp
->name
, pim
->vrf
->name
,
996 first_ifindex
, addr_str
);
1003 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
1005 if (PIM_DEBUG_PIM_NHT_DETAIL
)
1006 zlog_debug("ifp name: %s(%s), pim nbr: %p",
1007 ifp
->name
, pim
->vrf
->name
, nbr
);
1008 if (!nbr
&& !if_is_loopback(ifp
)) {
1012 if (PIM_DEBUG_PIM_NHT
)
1014 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
1015 __func__
, ifp
->name
,
1016 pim
->vrf
->name
, addr_str
);
1022 if (PIM_DEBUG_PIM_NHT
) {
1023 char nexthop_str
[PREFIX_STRLEN
];
1025 pim_addr_dump("<nexthop?>",
1026 &nexthop_tab
[i
].nexthop_addr
,
1027 nexthop_str
, sizeof(nexthop_str
));
1029 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
1030 __func__
, nexthop_str
, addr_str
,
1031 ifp
->name
, pim
->vrf
->name
,
1032 nexthop_tab
[i
].route_metric
,
1033 nexthop_tab
[i
].protocol_distance
);
1035 /* update nexthop data */
1036 nexthop
->interface
= ifp
;
1037 nexthop
->mrib_nexthop_addr
=
1038 nexthop_tab
[i
].nexthop_addr
;
1039 nexthop
->mrib_metric_preference
=
1040 nexthop_tab
[i
].protocol_distance
;
1041 nexthop
->mrib_route_metric
=
1042 nexthop_tab
[i
].route_metric
;
1043 nexthop
->last_lookup
= src
->u
.prefix4
;
1044 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
1057 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
1058 struct prefix
*src
, struct prefix
*grp
)
1060 struct pim_nexthop nhop
;
1063 char addr_str
[PREFIX_STRLEN
];
1065 if (PIM_DEBUG_PIM_NHT
)
1066 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
1069 memset(&nhop
, 0, sizeof(nhop
));
1070 if (!pim_ecmp_nexthop_lookup(pim
, &nhop
, src
, grp
, 1)) {
1071 if (PIM_DEBUG_PIM_NHT
)
1073 "%s: could not find nexthop ifindex for address %s(%s)",
1074 __func__
, addr_str
, pim
->vrf
->name
);
1078 ifindex
= nhop
.interface
->ifindex
;
1079 if (PIM_DEBUG_PIM_NHT
)
1081 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
1083 ifindex2ifname(ifindex
, pim
->vrf
->vrf_id
),
1084 pim
->vrf
->name
, addr_str
);
1086 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
1088 if (vif_index
< 0) {
1089 if (PIM_DEBUG_PIM_NHT
) {
1091 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
1092 __func__
, vif_index
, pim
->vrf
->name
, addr_str
);