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
30 #include "pimd/pim_nht.h"
34 #include "pim_ifchannel.h"
35 #include "pim_mroute.h"
36 #include "pim_zebra.h"
37 #include "pim_upstream.h"
39 #include "pim_jp_agg.h"
40 #include "pim_zebra.h"
41 #include "pim_zlookup.h"
44 * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
47 void pim_sendmsg_zebra_rnh(struct pim_instance
*pim
, struct zclient
*zclient
,
48 struct pim_nexthop_cache
*pnc
, int command
)
53 p
= &(pnc
->rpf
.rpf_addr
);
54 ret
= zclient_send_rnh(zclient
, command
, p
, false, pim
->vrf_id
);
56 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
58 if (PIM_DEBUG_PIM_NHT
) {
59 char buf
[PREFIX2STR_BUFFER
];
60 prefix2str(p
, buf
, sizeof(buf
));
62 "%s: NHT %sregistered addr %s(%s) with Zebra ret:%d ",
64 (command
== ZEBRA_NEXTHOP_REGISTER
) ? " " : "de", buf
,
71 struct pim_nexthop_cache
*pim_nexthop_cache_find(struct pim_instance
*pim
,
74 struct pim_nexthop_cache
*pnc
= NULL
;
75 struct pim_nexthop_cache lookup
;
77 lookup
.rpf
.rpf_addr
.family
= rpf
->rpf_addr
.family
;
78 lookup
.rpf
.rpf_addr
.prefixlen
= rpf
->rpf_addr
.prefixlen
;
79 lookup
.rpf
.rpf_addr
.u
.prefix4
.s_addr
= rpf
->rpf_addr
.u
.prefix4
.s_addr
;
81 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
86 static struct pim_nexthop_cache
*pim_nexthop_cache_add(struct pim_instance
*pim
,
87 struct pim_rpf
*rpf_addr
)
89 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 snprintf(hash_name
, 64, "PNC %s(%s) Upstream Hash",
106 prefix2str(&pnc
->rpf
.rpf_addr
, buf1
, 64), 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 struct pim_nexthop_cache
*out_pnc
)
125 struct pim_nexthop_cache
*pnc
= NULL
;
127 struct listnode
*ch_node
= NULL
;
128 struct zclient
*zclient
= NULL
;
130 zclient
= pim_zebra_zclient_get();
131 memset(&rpf
, 0, sizeof(struct pim_rpf
));
132 rpf
.rpf_addr
.family
= addr
->family
;
133 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
134 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
136 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
138 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
139 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
140 ZEBRA_NEXTHOP_REGISTER
);
141 if (PIM_DEBUG_PIM_NHT
) {
142 char buf
[PREFIX2STR_BUFFER
];
143 prefix2str(addr
, buf
, sizeof(buf
));
145 "%s: NHT cache and zebra notification added for %s(%s)",
146 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
);
151 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
153 listnode_add_sort(pnc
->rp_list
, rp
);
157 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
159 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
160 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
167 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
168 struct pim_upstream
*up
, struct rp_info
*rp
)
170 struct pim_nexthop_cache
*pnc
= NULL
;
171 struct pim_nexthop_cache lookup
;
172 struct zclient
*zclient
= NULL
;
174 zclient
= pim_zebra_zclient_get();
176 /* Remove from RPF hash if it is the last entry */
177 lookup
.rpf
.rpf_addr
= *addr
;
178 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
181 listnode_delete(pnc
->rp_list
, rp
);
183 hash_release(pnc
->upstream_hash
, up
);
185 if (PIM_DEBUG_PIM_NHT
) {
186 char buf
[PREFIX_STRLEN
];
187 prefix2str(addr
, buf
, sizeof buf
);
189 "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
190 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
191 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
194 if (pnc
->rp_list
->count
== 0
195 && pnc
->upstream_hash
->count
== 0) {
196 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
197 ZEBRA_NEXTHOP_UNREGISTER
);
199 list_delete(&pnc
->rp_list
);
200 hash_free(pnc
->upstream_hash
);
202 hash_release(pim
->rpf_hash
, pnc
);
204 nexthops_free(pnc
->nexthop
);
205 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
210 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
211 static void pim_update_rp_nh(struct pim_instance
*pim
,
212 struct pim_nexthop_cache
*pnc
)
214 struct listnode
*node
= NULL
;
215 struct rp_info
*rp_info
= NULL
;
217 /*Traverse RP list and update each RP Nexthop info */
218 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
219 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
222 // Compute PIM RPF using cached nexthop
223 pim_ecmp_nexthop_search(pim
, pnc
, &rp_info
->rp
.source_nexthop
,
224 &rp_info
->rp
.rpf_addr
, &rp_info
->group
,
229 /* This API is used to traverse nexthop cache of RPF addr
230 of upstream entry whose IPv4 nexthop address is in
231 unresolved state and due to event like pim neighbor
232 UP event if it can be resolved.
234 void pim_resolve_upstream_nh(struct pim_instance
*pim
, struct prefix
*nht_p
)
236 struct nexthop
*nh_node
= NULL
;
237 struct pim_nexthop_cache pnc
;
238 struct pim_neighbor
*nbr
= NULL
;
240 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
241 if (!pim_find_or_track_nexthop(pim
, nht_p
, NULL
, NULL
, &pnc
))
244 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
245 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
248 struct interface
*ifp1
=
249 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
250 nbr
= pim_neighbor_find_if(ifp1
);
254 nh_node
->gate
.ipv4
= nbr
->source_addr
;
255 if (PIM_DEBUG_PIM_NHT
) {
256 char str
[PREFIX_STRLEN
];
257 char str1
[INET_ADDRSTRLEN
];
258 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
, str1
,
260 pim_addr_dump("<nht_addr?>", nht_p
, str
, sizeof(str
));
262 "%s: addr %s new nexthop addr %s interface %s",
263 __PRETTY_FUNCTION__
, str
, str1
, ifp1
->name
);
268 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
269 static int pim_update_upstream_nh_helper(struct hash_backet
*backet
, void *arg
)
271 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
272 struct pim_upstream
*up
= (struct pim_upstream
*)backet
->data
;
275 enum pim_rpf_result rpf_result
;
278 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
279 rpf_result
= pim_rpf_update(pim
, up
, &old
, 0);
280 if (rpf_result
== PIM_RPF_FAILURE
) {
281 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
282 return HASHWALK_CONTINUE
;
285 /* update kernel multicast forwarding cache (MFC) */
286 if (up
->channel_oil
) {
287 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
289 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
290 /* Pass Current selected NH vif index to mroute download
293 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
295 if (PIM_DEBUG_PIM_NHT
)
297 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
298 __PRETTY_FUNCTION__
, up
->sg_str
,
299 up
->rpf
.source_nexthop
.interface
->name
);
303 if (rpf_result
== PIM_RPF_CHANGED
)
304 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
307 if (PIM_DEBUG_PIM_NHT
) {
308 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
309 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
310 old
.source_nexthop
.interface
->name
,
311 up
->rpf
.source_nexthop
.interface
->name
);
314 return HASHWALK_CONTINUE
;
317 static int pim_update_upstream_nh(struct pim_instance
*pim
,
318 struct pim_nexthop_cache
*pnc
)
320 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
322 pim_zebra_update_all_interfaces(pim
);
327 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
330 uint32_t s
= 0, g
= 0;
335 switch (src
->family
) {
337 s
= src
->u
.prefix4
.s_addr
;
340 g
= grp
->u
.prefix4
.s_addr
;
346 hash_val
= jhash_2words(g
, s
, 101);
350 int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
351 struct pim_nexthop_cache
*pnc
,
352 struct pim_nexthop
*nexthop
, struct prefix
*src
,
353 struct prefix
*grp
, int neighbor_needed
)
355 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
356 struct interface
*ifps
[MULTIPATH_NUM
];
357 struct nexthop
*nh_node
= NULL
;
358 ifindex_t first_ifindex
;
359 struct interface
*ifp
= NULL
;
360 uint32_t hash_val
= 0, mod_val
= 0;
361 uint8_t nh_iter
= 0, found
= 0;
362 uint32_t i
, num_nbrs
= 0;
364 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
367 memset(&nbrs
, 0, sizeof(nbrs
));
368 memset(&ifps
, 0, sizeof(ifps
));
370 // Current Nexthop is VALID, check to stay on the current path.
371 if (nexthop
->interface
&& nexthop
->interface
->info
372 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
373 != PIM_NET_INADDR_ANY
) {
374 /* User configured knob to explicitly switch
375 to new path is disabled or current path
376 metric is less than nexthop update.
379 if (pim
->ecmp_rebalance_enable
== 0) {
380 uint8_t curr_route_valid
= 0;
381 // Check if current nexthop is present in new updated
383 // If the current nexthop is not valid, candidate to
384 // choose new Nexthop.
385 for (nh_node
= pnc
->nexthop
; nh_node
;
386 nh_node
= nh_node
->next
) {
387 curr_route_valid
= (nexthop
->interface
->ifindex
388 == nh_node
->ifindex
);
389 if (curr_route_valid
)
394 && !pim_if_connected_to_source(nexthop
->interface
,
396 nbr
= pim_neighbor_find(
398 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
400 && !if_is_loopback(nexthop
->interface
)) {
401 if (PIM_DEBUG_PIM_NHT
)
403 "%s: current nexthop does not have nbr ",
404 __PRETTY_FUNCTION__
);
406 if (PIM_DEBUG_PIM_NHT
) {
407 char src_str
[INET_ADDRSTRLEN
];
408 pim_inet4_dump("<addr?>",
412 char grp_str
[INET_ADDRSTRLEN
];
413 pim_inet4_dump("<addr?>",
418 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
422 nexthop
->interface
->name
);
431 * Look up all interfaces and neighbors,
432 * store for later usage
434 for (nh_node
= pnc
->nexthop
, i
= 0; nh_node
;
435 nh_node
= nh_node
->next
, i
++) {
436 ifps
[i
] = if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
438 nbrs
[i
] = pim_neighbor_find(ifps
[i
],
440 if (nbrs
[i
] || pim_if_connected_to_source(ifps
[i
],
446 if (pim
->ecmp_enable
) {
447 uint32_t consider
= pnc
->nexthop_num
;
449 if (neighbor_needed
&& num_nbrs
< consider
)
455 // PIM ECMP flag is enable then choose ECMP path.
456 hash_val
= pim_compute_ecmp_hash(src
, grp
);
457 mod_val
= hash_val
% consider
;
460 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
461 nh_node
= nh_node
->next
) {
462 first_ifindex
= nh_node
->ifindex
;
465 if (PIM_DEBUG_PIM_NHT
) {
466 char addr_str
[INET_ADDRSTRLEN
];
467 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
468 addr_str
, sizeof(addr_str
));
470 "%s %s: could not find interface for ifindex %d (address %s(%s))",
471 __FILE__
, __PRETTY_FUNCTION__
,
472 first_ifindex
, addr_str
,
475 if (nh_iter
== mod_val
)
476 mod_val
++; // Select nexthpath
481 if (PIM_DEBUG_PIM_NHT
) {
482 char addr_str
[INET_ADDRSTRLEN
];
483 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
484 addr_str
, sizeof(addr_str
));
486 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
487 __PRETTY_FUNCTION__
, ifp
->name
,
488 pim
->vrf
->name
, first_ifindex
,
491 if (nh_iter
== mod_val
)
492 mod_val
++; // Select nexthpath
498 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
500 if (!nbr
&& !if_is_loopback(ifp
)) {
501 if (PIM_DEBUG_PIM_NHT
)
503 "%s: pim nbr not found on input interface %s(%s)",
504 __PRETTY_FUNCTION__
, ifp
->name
,
506 if (nh_iter
== mod_val
)
507 mod_val
++; // Select nexthpath
513 if (nh_iter
== mod_val
) {
514 nexthop
->interface
= ifp
;
515 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
516 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
517 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
519 nexthop
->mrib_metric_preference
= pnc
->distance
;
520 nexthop
->mrib_route_metric
= pnc
->metric
;
521 nexthop
->last_lookup
= src
->u
.prefix4
;
522 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
525 if (PIM_DEBUG_PIM_NHT
) {
526 char buf
[INET_ADDRSTRLEN
];
527 char buf2
[INET_ADDRSTRLEN
];
528 char buf3
[INET_ADDRSTRLEN
];
529 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
531 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
535 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
538 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
539 __PRETTY_FUNCTION__
, buf2
, buf3
,
540 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
541 nh_iter
, pim
->ecmp_enable
);
553 /* This API is used to parse Registered address nexthop update coming from Zebra
555 int pim_parse_nexthop_update(int command
, struct zclient
*zclient
,
556 zebra_size_t length
, vrf_id_t vrf_id
)
558 struct nexthop
*nexthop
;
559 struct nexthop
*nhlist_head
= NULL
;
560 struct nexthop
*nhlist_tail
= NULL
;
563 struct pim_nexthop_cache
*pnc
= NULL
;
564 struct pim_neighbor
*nbr
= NULL
;
565 struct interface
*ifp
= NULL
;
566 struct interface
*ifp1
= NULL
;
567 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
568 struct pim_instance
*pim
;
569 struct zapi_route nhr
;
575 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
576 if (PIM_DEBUG_PIM_NHT
)
578 "%s: Decode of nexthop update from zebra failed",
579 __PRETTY_FUNCTION__
);
583 if (command
== ZEBRA_NEXTHOP_UPDATE
) {
584 prefix_copy(&rpf
.rpf_addr
, &nhr
.prefix
);
585 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
587 if (PIM_DEBUG_PIM_NHT
) {
588 char buf
[PREFIX2STR_BUFFER
];
589 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
591 "%s: Skipping NHT update, addr %s is not in local cached DB.",
592 __PRETTY_FUNCTION__
, buf
);
598 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
603 pnc
->last_update
= pim_time_monotonic_usec();
605 if (nhr
.nexthop_num
) {
606 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
608 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
609 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
610 switch (nexthop
->type
) {
611 case NEXTHOP_TYPE_IPV4
:
612 case NEXTHOP_TYPE_IPV4_IFINDEX
:
613 case NEXTHOP_TYPE_IPV6
:
614 case NEXTHOP_TYPE_BLACKHOLE
:
616 case NEXTHOP_TYPE_IFINDEX
:
618 * Connected route (i.e. no nexthop), use
619 * RPF address from nexthop cache (i.e.
620 * destination) as PIM nexthop.
622 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
624 pnc
->rpf
.rpf_addr
.u
.prefix4
;
626 case NEXTHOP_TYPE_IPV6_IFINDEX
:
627 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
629 nbr
= pim_neighbor_find_if(ifp1
);
630 /* Overwrite with Nbr address as NH addr */
632 nexthop
->gate
.ipv4
= nbr
->source_addr
;
634 // Mark nexthop address to 0 until PIM
636 nexthop
->gate
.ipv4
.s_addr
=
643 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
645 if (PIM_DEBUG_PIM_NHT
) {
646 char buf
[NEXTHOP_STRLEN
];
648 "%s: could not find interface for ifindex %d(%s) (addr %s)",
652 nexthop2str(nexthop
, buf
,
655 nexthop_free(nexthop
);
659 if (PIM_DEBUG_PIM_NHT
) {
660 char p_str
[PREFIX2STR_BUFFER
];
662 prefix2str(&nhr
.prefix
, p_str
, sizeof(p_str
));
664 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
665 __PRETTY_FUNCTION__
, p_str
,
666 pim
->vrf
->name
, i
+ 1,
667 inet_ntoa(nexthop
->gate
.ipv4
),
668 ifp
->name
, nexthop
->type
, nhr
.distance
,
673 if (PIM_DEBUG_PIM_NHT
) {
674 char buf
[NEXTHOP_STRLEN
];
677 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
678 __PRETTY_FUNCTION__
, ifp
->name
,
681 nexthop2str(nexthop
, buf
,
684 nexthop_free(nexthop
);
689 nhlist_tail
->next
= nexthop
;
690 nhlist_tail
= nexthop
;
692 nhlist_tail
= nexthop
;
693 nhlist_head
= nexthop
;
695 // Only keep track of nexthops which are PIM enabled.
698 /* Reset existing pnc->nexthop before assigning new list */
699 nexthops_free(pnc
->nexthop
);
700 pnc
->nexthop
= nhlist_head
;
701 if (pnc
->nexthop_num
) {
702 pnc
->flags
|= PIM_NEXTHOP_VALID
;
703 pnc
->distance
= nhr
.distance
;
704 pnc
->metric
= nhr
.metric
;
707 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
708 pnc
->nexthop_num
= nhr
.nexthop_num
;
709 nexthops_free(pnc
->nexthop
);
713 if (PIM_DEBUG_PIM_NHT
) {
714 char buf
[PREFIX2STR_BUFFER
];
715 prefix2str(&nhr
.prefix
, buf
, sizeof(buf
));
717 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
718 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
719 nhr
.nexthop_num
, pnc
->nexthop_num
, vrf_id
,
720 pnc
->upstream_hash
->count
, listcount(pnc
->rp_list
));
723 pim_rpf_set_refresh_time(pim
);
725 if (listcount(pnc
->rp_list
))
726 pim_update_rp_nh(pim
, pnc
);
727 if (pnc
->upstream_hash
->count
)
728 pim_update_upstream_nh(pim
, pnc
);
733 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
734 struct pim_nexthop
*nexthop
, struct prefix
*src
,
735 struct prefix
*grp
, int neighbor_needed
)
737 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
738 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
740 struct interface
*ifps
[MULTIPATH_NUM
], *ifp
;
744 uint32_t hash_val
= 0, mod_val
= 0;
745 uint32_t num_nbrs
= 0;
746 char addr_str
[PREFIX_STRLEN
];
748 if (PIM_DEBUG_PIM_NHT
) {
749 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
751 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
752 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
753 nexthop
->last_lookup_time
);
756 memset(nexthop_tab
, 0,
757 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
759 zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
760 src
->u
.prefix4
, PIM_NEXTHOP_LOOKUP_MAX
);
761 if (num_ifindex
< 1) {
762 if (PIM_DEBUG_PIM_NHT
)
764 "%s: could not find nexthop ifindex for address %s(%s)",
765 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
769 memset(&nbrs
, 0, sizeof(nbrs
));
770 memset(&ifps
, 0, sizeof(ifps
));
773 * Look up all interfaces and neighbors,
774 * store for later usage
776 for (i
= 0; i
< num_ifindex
; i
++) {
777 ifps
[i
] = if_lookup_by_index(nexthop_tab
[i
].ifindex
,
780 nbrs
[i
] = pim_neighbor_find(
781 ifps
[i
], nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
783 || pim_if_connected_to_source(ifps
[i
],
789 // If PIM ECMP enable then choose ECMP path.
790 if (pim
->ecmp_enable
) {
791 uint32_t consider
= num_ifindex
;
793 if (neighbor_needed
&& num_nbrs
< consider
)
799 hash_val
= pim_compute_ecmp_hash(src
, grp
);
800 mod_val
= hash_val
% consider
;
801 if (PIM_DEBUG_PIM_NHT_DETAIL
)
802 zlog_debug("%s: hash_val %u mod_val %u",
803 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
807 while (!found
&& (i
< num_ifindex
)) {
808 first_ifindex
= nexthop_tab
[i
].ifindex
;
812 if (PIM_DEBUG_PIM_NHT
)
814 "%s %s: could not find interface for ifindex %d (address %s(%s))",
815 __FILE__
, __PRETTY_FUNCTION__
,
816 first_ifindex
, addr_str
,
825 if (PIM_DEBUG_PIM_NHT
)
827 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
828 __PRETTY_FUNCTION__
, ifp
->name
,
829 pim
->vrf
->name
, first_ifindex
,
837 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
839 if (PIM_DEBUG_PIM_NHT_DETAIL
)
840 zlog_debug("ifp name: %s(%s), pim nbr: %p",
841 ifp
->name
, pim
->vrf
->name
, nbr
);
842 if (!nbr
&& !if_is_loopback(ifp
)) {
846 if (PIM_DEBUG_PIM_NHT
)
848 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
849 __PRETTY_FUNCTION__
, ifp
->name
,
850 pim
->vrf
->name
, addr_str
);
856 if (PIM_DEBUG_PIM_NHT
) {
857 char nexthop_str
[PREFIX_STRLEN
];
859 pim_addr_dump("<nexthop?>",
860 &nexthop_tab
[i
].nexthop_addr
,
861 nexthop_str
, sizeof(nexthop_str
));
863 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
864 __PRETTY_FUNCTION__
, nexthop_str
,
865 addr_str
, ifp
->name
, pim
->vrf
->name
,
866 nexthop_tab
[i
].route_metric
,
867 nexthop_tab
[i
].protocol_distance
);
869 /* update nexthop data */
870 nexthop
->interface
= ifp
;
871 nexthop
->mrib_nexthop_addr
=
872 nexthop_tab
[i
].nexthop_addr
;
873 nexthop
->mrib_metric_preference
=
874 nexthop_tab
[i
].protocol_distance
;
875 nexthop
->mrib_route_metric
=
876 nexthop_tab
[i
].route_metric
;
877 nexthop
->last_lookup
= src
->u
.prefix4
;
878 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
891 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
892 struct prefix
*src
, struct prefix
*grp
)
894 struct pim_nexthop nhop
;
897 char addr_str
[PREFIX_STRLEN
];
899 if (PIM_DEBUG_PIM_NHT
)
900 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
902 if (!pim_ecmp_nexthop_lookup(pim
, &nhop
, src
, grp
, 0)) {
903 if (PIM_DEBUG_PIM_NHT
)
905 "%s: could not find nexthop ifindex for address %s(%s)",
906 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
910 ifindex
= nhop
.interface
->ifindex
;
911 if (PIM_DEBUG_PIM_NHT
)
913 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
914 __PRETTY_FUNCTION__
, ifindex
,
915 ifindex2ifname(ifindex
, pim
->vrf_id
),
916 pim
->vrf
->name
, addr_str
);
918 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
921 if (PIM_DEBUG_PIM_NHT
) {
923 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
924 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,