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
));
96 zlog_err("%s: NHT PIM XCALLOC failure ", __PRETTY_FUNCTION__
);
99 pnc
->rpf
.rpf_addr
.family
= rpf_addr
->rpf_addr
.family
;
100 pnc
->rpf
.rpf_addr
.prefixlen
= rpf_addr
->rpf_addr
.prefixlen
;
101 pnc
->rpf
.rpf_addr
.u
.prefix4
.s_addr
=
102 rpf_addr
->rpf_addr
.u
.prefix4
.s_addr
;
104 pnc
= hash_get(pim
->rpf_hash
, pnc
, hash_alloc_intern
);
106 pnc
->rp_list
= list_new();
107 pnc
->rp_list
->cmp
= pim_rp_list_cmp
;
109 snprintf(hash_name
, 64, "PNC %s(%s) Upstream Hash",
110 prefix2str(&pnc
->rpf
.rpf_addr
, buf1
, 64),
112 pnc
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
120 * pim_find_or_track_nexthop
122 * This API is used to Register an address with Zebra
127 int pim_find_or_track_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
128 struct pim_upstream
*up
, struct rp_info
*rp
,
129 struct pim_nexthop_cache
*out_pnc
)
131 struct pim_nexthop_cache
*pnc
= NULL
;
133 struct listnode
*ch_node
= NULL
;
134 struct zclient
*zclient
= NULL
;
136 zclient
= pim_zebra_zclient_get();
137 memset(&rpf
, 0, sizeof(struct pim_rpf
));
138 rpf
.rpf_addr
.family
= addr
->family
;
139 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
140 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
142 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
144 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
146 char rpf_str
[PREFIX_STRLEN
];
147 pim_addr_dump("<nht-pnc?>", addr
, rpf_str
,
149 zlog_warn("%s: pnc node allocation failed. addr %s ",
150 __PRETTY_FUNCTION__
, rpf_str
);
153 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
154 ZEBRA_NEXTHOP_REGISTER
);
155 if (PIM_DEBUG_PIM_NHT
) {
156 char buf
[PREFIX2STR_BUFFER
];
157 prefix2str(addr
, buf
, sizeof(buf
));
159 "%s: NHT cache and zebra notification added for %s(%s)",
160 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
);
165 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
167 listnode_add_sort(pnc
->rp_list
, rp
);
171 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
173 if (pnc
&& CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
174 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
181 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
182 struct pim_upstream
*up
, struct rp_info
*rp
)
184 struct pim_nexthop_cache
*pnc
= NULL
;
185 struct pim_nexthop_cache lookup
;
186 struct zclient
*zclient
= NULL
;
188 zclient
= pim_zebra_zclient_get();
190 /* Remove from RPF hash if it is the last entry */
191 lookup
.rpf
.rpf_addr
= *addr
;
192 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
195 listnode_delete(pnc
->rp_list
, rp
);
197 hash_release(pnc
->upstream_hash
, up
);
199 if (PIM_DEBUG_PIM_NHT
) {
200 char buf
[PREFIX_STRLEN
];
201 prefix2str(addr
, buf
, sizeof buf
);
203 "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
204 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
205 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
208 if (pnc
->rp_list
->count
== 0
209 && pnc
->upstream_hash
->count
== 0) {
210 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
211 ZEBRA_NEXTHOP_UNREGISTER
);
213 list_delete_and_null(&pnc
->rp_list
);
214 hash_free(pnc
->upstream_hash
);
216 hash_release(pim
->rpf_hash
, pnc
);
218 nexthops_free(pnc
->nexthop
);
219 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
224 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
225 static void pim_update_rp_nh(struct pim_instance
*pim
,
226 struct pim_nexthop_cache
*pnc
)
228 struct listnode
*node
= NULL
;
229 struct rp_info
*rp_info
= NULL
;
231 /*Traverse RP list and update each RP Nexthop info */
232 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
233 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
236 // Compute PIM RPF using cached nexthop
237 pim_ecmp_nexthop_search(pim
, pnc
,
238 &rp_info
->rp
.source_nexthop
,
239 &rp_info
->rp
.rpf_addr
,
244 /* This API is used to traverse nexthop cache of RPF addr
245 of upstream entry whose IPv4 nexthop address is in
246 unresolved state and due to event like pim neighbor
247 UP event if it can be resolved.
249 void pim_resolve_upstream_nh(struct pim_instance
*pim
, struct prefix
*nht_p
)
251 struct nexthop
*nh_node
= NULL
;
252 struct pim_nexthop_cache pnc
;
253 struct pim_neighbor
*nbr
= NULL
;
255 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
256 if (!pim_find_or_track_nexthop(pim
, nht_p
, NULL
, NULL
, &pnc
))
259 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
260 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
263 struct interface
*ifp1
=
264 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
265 nbr
= pim_neighbor_find_if(ifp1
);
269 nh_node
->gate
.ipv4
= nbr
->source_addr
;
270 if (PIM_DEBUG_PIM_NHT
) {
271 char str
[PREFIX_STRLEN
];
272 char str1
[INET_ADDRSTRLEN
];
273 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
, str1
,
275 pim_addr_dump("<nht_addr?>", nht_p
, str
, sizeof(str
));
277 "%s: addr %s new nexthop addr %s interface %s",
278 __PRETTY_FUNCTION__
, str
, str1
, ifp1
->name
);
283 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
284 static int pim_update_upstream_nh_helper(struct hash_backet
*backet
, void *arg
)
286 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
287 struct pim_upstream
*up
= (struct pim_upstream
*)backet
->data
;
290 enum pim_rpf_result rpf_result
;
293 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
294 rpf_result
= pim_rpf_update(pim
, up
, &old
, 0);
295 if (rpf_result
== PIM_RPF_FAILURE
) {
296 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
297 return HASHWALK_CONTINUE
;
300 /* update kernel multicast forwarding cache (MFC) */
301 if (up
->channel_oil
) {
302 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
304 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
305 /* Pass Current selected NH vif index to mroute download
308 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
310 if (PIM_DEBUG_PIM_NHT
)
312 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
313 __PRETTY_FUNCTION__
, up
->sg_str
,
314 up
->rpf
.source_nexthop
.interface
->name
);
318 if (rpf_result
== PIM_RPF_CHANGED
) {
319 struct pim_neighbor
*nbr
;
321 nbr
= pim_neighbor_find(old
.source_nexthop
.interface
,
322 old
.rpf_addr
.u
.prefix4
);
324 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
327 * We have detected a case where we might need to rescan
328 * the inherited o_list so do it.
331 && up
->channel_oil
->oil_inherited_rescan
) {
332 pim_upstream_inherited_olist_decide(pim
, up
);
333 up
->channel_oil
->oil_inherited_rescan
= 0;
336 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
338 * If we come up real fast we can be here
339 * where the mroute has not been installed
343 && !up
->channel_oil
->installed
)
344 pim_mroute_add(up
->channel_oil
,
345 __PRETTY_FUNCTION__
);
348 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
350 * Transitions from Joined State
352 * RPF'(S,G) changes not due to an Assert
354 * The upstream (S,G) state machine remains in Joined
355 * state. Send Join(S,G) to the new upstream
356 * neighbor, which is the new value of RPF'(S,G).
357 * Send Prune(S,G) to the old upstream neighbor, which
358 * is the old value of RPF'(S,G). Set the Join
359 * Timer (JT) to expire after t_periodic seconds.
361 pim_jp_agg_switch_interface(&old
, &up
->rpf
, up
);
363 pim_upstream_join_timer_restart(up
, &old
);
364 } /* up->join_state == PIM_UPSTREAM_JOINED */
367 * FIXME can join_desired actually be changed by
368 * pim_rpf_update() returning PIM_RPF_CHANGED ?
370 pim_upstream_update_join_desired(pim
, up
);
372 } /* PIM_RPF_CHANGED */
374 if (PIM_DEBUG_PIM_NHT
) {
375 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
376 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
377 old
.source_nexthop
.interface
->name
,
378 up
->rpf
.source_nexthop
.interface
->name
);
381 return HASHWALK_CONTINUE
;
384 static int pim_update_upstream_nh(struct pim_instance
*pim
,
385 struct pim_nexthop_cache
*pnc
)
387 struct listnode
*node
;
388 struct interface
*ifp
;
390 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
392 FOR_ALL_INTERFACES (pim
->vrf
, ifp
)
394 struct pim_interface
*pim_ifp
= ifp
->info
;
395 struct pim_iface_upstream_switch
*us
;
397 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
,
400 rpf
.source_nexthop
.interface
= ifp
;
401 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
402 pim_joinprune_send(&rpf
, us
->us
);
403 pim_jp_agg_clear_group(us
->us
);
410 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
413 uint32_t s
= 0, g
= 0;
418 switch (src
->family
) {
420 s
= src
->u
.prefix4
.s_addr
;
423 g
= grp
->u
.prefix4
.s_addr
;
429 hash_val
= jhash_2words(g
, s
, 101);
433 int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
434 struct pim_nexthop_cache
*pnc
,
435 struct pim_nexthop
*nexthop
, struct prefix
*src
,
436 struct prefix
*grp
, int neighbor_needed
)
438 struct pim_neighbor
*nbr
= NULL
;
439 struct nexthop
*nh_node
= NULL
;
440 ifindex_t first_ifindex
;
441 struct interface
*ifp
= NULL
;
442 uint32_t hash_val
= 0, mod_val
= 0;
443 uint8_t nh_iter
= 0, found
= 0;
445 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
448 // Current Nexthop is VALID, check to stay on the current path.
449 if (nexthop
->interface
&& nexthop
->interface
->info
450 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
451 != PIM_NET_INADDR_ANY
) {
452 /* User configured knob to explicitly switch
453 to new path is disabled or current path
454 metric is less than nexthop update.
457 if (qpim_ecmp_rebalance_enable
== 0) {
458 uint8_t curr_route_valid
= 0;
459 // Check if current nexthop is present in new updated
461 // If the current nexthop is not valid, candidate to
462 // choose new Nexthop.
463 for (nh_node
= pnc
->nexthop
; nh_node
;
464 nh_node
= nh_node
->next
) {
465 curr_route_valid
= (nexthop
->interface
->ifindex
466 == nh_node
->ifindex
);
467 if (curr_route_valid
)
472 && !pim_if_connected_to_source(nexthop
->interface
,
474 nbr
= pim_neighbor_find(
476 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
478 && !if_is_loopback(nexthop
->interface
)) {
479 if (PIM_DEBUG_PIM_NHT
)
481 "%s: current nexthop does not have nbr ",
482 __PRETTY_FUNCTION__
);
484 if (PIM_DEBUG_PIM_NHT
) {
485 char src_str
[INET_ADDRSTRLEN
];
486 pim_inet4_dump("<addr?>",
490 char grp_str
[INET_ADDRSTRLEN
];
491 pim_inet4_dump("<addr?>",
496 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
500 nexthop
->interface
->name
);
507 if (qpim_ecmp_enable
) {
508 // PIM ECMP flag is enable then choose ECMP path.
509 hash_val
= pim_compute_ecmp_hash(src
, grp
);
510 mod_val
= hash_val
% pnc
->nexthop_num
;
513 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
514 nh_node
= nh_node
->next
) {
515 first_ifindex
= nh_node
->ifindex
;
516 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
518 if (PIM_DEBUG_PIM_NHT
) {
519 char addr_str
[INET_ADDRSTRLEN
];
520 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
521 addr_str
, sizeof(addr_str
));
523 "%s %s: could not find interface for ifindex %d (address %s(%s))",
524 __FILE__
, __PRETTY_FUNCTION__
,
525 first_ifindex
, addr_str
,
528 if (nh_iter
== mod_val
)
529 mod_val
++; // Select nexthpath
534 if (PIM_DEBUG_PIM_NHT
) {
535 char addr_str
[INET_ADDRSTRLEN
];
536 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
537 addr_str
, sizeof(addr_str
));
539 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
540 __PRETTY_FUNCTION__
, ifp
->name
,
541 pim
->vrf
->name
, first_ifindex
,
544 if (nh_iter
== mod_val
)
545 mod_val
++; // Select nexthpath
551 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
552 nbr
= pim_neighbor_find(ifp
, nh_node
->gate
.ipv4
);
553 if (!nbr
&& !if_is_loopback(ifp
)) {
554 if (PIM_DEBUG_PIM_NHT
)
556 "%s: pim nbr not found on input interface %s(%s)",
557 __PRETTY_FUNCTION__
, ifp
->name
,
559 if (nh_iter
== mod_val
)
560 mod_val
++; // Select nexthpath
566 if (nh_iter
== mod_val
) {
567 nexthop
->interface
= ifp
;
568 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
569 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
570 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
572 nexthop
->mrib_metric_preference
= pnc
->distance
;
573 nexthop
->mrib_route_metric
= pnc
->metric
;
574 nexthop
->last_lookup
= src
->u
.prefix4
;
575 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
578 if (PIM_DEBUG_PIM_NHT
) {
579 char buf
[INET_ADDRSTRLEN
];
580 char buf2
[INET_ADDRSTRLEN
];
581 char buf3
[INET_ADDRSTRLEN
];
582 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
584 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
588 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
591 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
592 __PRETTY_FUNCTION__
, buf2
, buf3
,
593 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
594 nh_iter
, qpim_ecmp_enable
);
606 /* This API is used to parse Registered address nexthop update coming from Zebra
608 int pim_parse_nexthop_update(int command
, struct zclient
*zclient
,
609 zebra_size_t length
, vrf_id_t vrf_id
)
613 struct nexthop
*nexthop
;
614 struct nexthop
*nhlist_head
= NULL
;
615 struct nexthop
*nhlist_tail
= NULL
;
616 uint32_t metric
, distance
;
617 u_char nexthop_num
= 0;
620 struct pim_nexthop_cache
*pnc
= NULL
;
621 struct pim_neighbor
*nbr
= NULL
;
622 struct interface
*ifp
= NULL
;
623 struct interface
*ifp1
= NULL
;
624 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
625 struct pim_instance
*pim
;
632 memset(&p
, 0, sizeof(struct prefix
));
633 p
.family
= stream_getw(s
);
634 p
.prefixlen
= stream_getc(s
);
637 p
.u
.prefix4
.s_addr
= stream_get_ipv4(s
);
640 stream_get(&p
.u
.prefix6
, s
, 16);
646 if (command
== ZEBRA_NEXTHOP_UPDATE
) {
647 rpf
.rpf_addr
.family
= p
.family
;
648 rpf
.rpf_addr
.prefixlen
= p
.prefixlen
;
649 rpf
.rpf_addr
.u
.prefix4
.s_addr
= p
.u
.prefix4
.s_addr
;
650 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
652 if (PIM_DEBUG_PIM_NHT
) {
653 char buf
[PREFIX2STR_BUFFER
];
654 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
656 "%s: Skipping NHT update, addr %s is not in local cached DB.",
657 __PRETTY_FUNCTION__
, buf
);
663 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
668 pnc
->last_update
= pim_time_monotonic_usec();
669 distance
= stream_getc(s
);
670 metric
= stream_getl(s
);
671 nexthop_num
= stream_getc(s
);
674 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
676 for (i
= 0; i
< nexthop_num
; i
++) {
677 nexthop
= nexthop_new();
678 nexthop
->type
= stream_getc(s
);
679 switch (nexthop
->type
) {
680 case NEXTHOP_TYPE_IPV4
:
681 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
682 nexthop
->ifindex
= stream_getl(s
);
684 case NEXTHOP_TYPE_IFINDEX
:
685 nexthop
->ifindex
= stream_getl(s
);
687 case NEXTHOP_TYPE_IPV4_IFINDEX
:
688 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
689 nexthop
->ifindex
= stream_getl(s
);
691 case NEXTHOP_TYPE_IPV6
:
692 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
694 case NEXTHOP_TYPE_IPV6_IFINDEX
:
695 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
696 nexthop
->ifindex
= stream_getl(s
);
697 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
699 nbr
= pim_neighbor_find_if(ifp1
);
700 /* Overwrite with Nbr address as NH addr */
702 nexthop
->gate
.ipv4
= nbr
->source_addr
;
704 // Mark nexthop address to 0 until PIM
706 nexthop
->gate
.ipv4
.s_addr
=
716 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
718 if (PIM_DEBUG_PIM_NHT
) {
719 char buf
[NEXTHOP_STRLEN
];
721 "%s: could not find interface for ifindex %d(%s) (addr %s)",
725 nexthop2str(nexthop
, buf
,
728 nexthop_free(nexthop
);
732 if (PIM_DEBUG_PIM_NHT
) {
733 char p_str
[PREFIX2STR_BUFFER
];
734 prefix2str(&p
, p_str
, sizeof(p_str
));
736 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
737 __PRETTY_FUNCTION__
, p_str
,
738 pim
->vrf
->name
, i
+ 1,
739 inet_ntoa(nexthop
->gate
.ipv4
),
740 ifp
->name
, nexthop
->type
, distance
,
745 if (PIM_DEBUG_PIM_NHT
) {
746 char buf
[NEXTHOP_STRLEN
];
748 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
749 __PRETTY_FUNCTION__
, ifp
->name
,
752 nexthop2str(nexthop
, buf
,
755 nexthop_free(nexthop
);
760 nhlist_tail
->next
= nexthop
;
761 nhlist_tail
= nexthop
;
763 nhlist_tail
= nexthop
;
764 nhlist_head
= nexthop
;
766 // Only keep track of nexthops which are PIM enabled.
769 /* Reset existing pnc->nexthop before assigning new list */
770 nexthops_free(pnc
->nexthop
);
771 pnc
->nexthop
= nhlist_head
;
772 if (pnc
->nexthop_num
) {
773 pnc
->flags
|= PIM_NEXTHOP_VALID
;
774 pnc
->distance
= distance
;
775 pnc
->metric
= metric
;
778 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
779 pnc
->nexthop_num
= nexthop_num
;
780 nexthops_free(pnc
->nexthop
);
784 if (PIM_DEBUG_PIM_NHT
) {
785 char buf
[PREFIX2STR_BUFFER
];
786 prefix2str(&p
, buf
, sizeof(buf
));
788 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
789 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
, nexthop_num
,
790 pnc
->nexthop_num
, vrf_id
, pnc
->upstream_hash
->count
,
791 listcount(pnc
->rp_list
));
794 pim_rpf_set_refresh_time();
796 if (listcount(pnc
->rp_list
))
797 pim_update_rp_nh(pim
, pnc
);
798 if (pnc
->upstream_hash
->count
)
799 pim_update_upstream_nh(pim
, pnc
);
804 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
805 struct pim_nexthop
*nexthop
, struct in_addr addr
,
806 struct prefix
*src
, struct prefix
*grp
,
809 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
810 struct pim_neighbor
*nbr
= NULL
;
812 struct interface
*ifp
;
816 uint32_t hash_val
= 0, mod_val
= 0;
818 if (PIM_DEBUG_PIM_NHT
) {
819 char addr_str
[INET_ADDRSTRLEN
];
820 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
821 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
822 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
823 nexthop
->last_lookup_time
);
826 memset(nexthop_tab
, 0,
827 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
828 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
829 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
830 if (num_ifindex
< 1) {
831 if (PIM_DEBUG_PIM_NHT
) {
832 char addr_str
[INET_ADDRSTRLEN
];
833 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
835 "%s: could not find nexthop ifindex for address %s(%s)",
836 __PRETTY_FUNCTION__
, addr_str
,
842 // If PIM ECMP enable then choose ECMP path.
843 if (qpim_ecmp_enable
) {
844 hash_val
= pim_compute_ecmp_hash(src
, grp
);
845 mod_val
= hash_val
% num_ifindex
;
846 if (PIM_DEBUG_PIM_NHT_DETAIL
)
847 zlog_debug("%s: hash_val %u mod_val %u",
848 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
851 while (!found
&& (i
< num_ifindex
)) {
852 first_ifindex
= nexthop_tab
[i
].ifindex
;
854 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
856 if (PIM_DEBUG_PIM_NHT
) {
857 char addr_str
[INET_ADDRSTRLEN
];
858 pim_inet4_dump("<addr?>", addr
, addr_str
,
861 "%s %s: could not find interface for ifindex %d (address %s(%s))",
862 __FILE__
, __PRETTY_FUNCTION__
,
863 first_ifindex
, addr_str
,
873 if (PIM_DEBUG_PIM_NHT
) {
874 char addr_str
[INET_ADDRSTRLEN
];
875 pim_inet4_dump("<addr?>", addr
, addr_str
,
878 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
879 __PRETTY_FUNCTION__
, ifp
->name
,
880 pim
->vrf
->name
, first_ifindex
,
888 if (neighbor_needed
&& !pim_if_connected_to_source(ifp
, addr
)) {
889 nbr
= pim_neighbor_find(
890 ifp
, nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
891 if (PIM_DEBUG_PIM_NHT_DETAIL
)
892 zlog_debug("ifp name: %s(%s), pim nbr: %p",
893 ifp
->name
, pim
->vrf
->name
, nbr
);
894 if (!nbr
&& !if_is_loopback(ifp
)) {
898 if (PIM_DEBUG_PIM_NHT
) {
899 char addr_str
[INET_ADDRSTRLEN
];
900 pim_inet4_dump("<addr?>", addr
,
904 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
905 __PRETTY_FUNCTION__
, ifp
->name
,
906 pim
->vrf
->name
, addr_str
);
913 if (PIM_DEBUG_PIM_NHT
) {
914 char nexthop_str
[PREFIX_STRLEN
];
915 char addr_str
[INET_ADDRSTRLEN
];
916 pim_addr_dump("<nexthop?>",
917 &nexthop_tab
[i
].nexthop_addr
,
918 nexthop_str
, sizeof(nexthop_str
));
919 pim_inet4_dump("<addr?>", addr
, addr_str
,
922 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
923 __PRETTY_FUNCTION__
, nexthop_str
,
924 addr_str
, ifp
->name
, pim
->vrf
->name
,
925 nexthop_tab
[i
].route_metric
,
926 nexthop_tab
[i
].protocol_distance
);
928 /* update nextop data */
929 nexthop
->interface
= ifp
;
930 nexthop
->mrib_nexthop_addr
=
931 nexthop_tab
[i
].nexthop_addr
;
932 nexthop
->mrib_metric_preference
=
933 nexthop_tab
[i
].protocol_distance
;
934 nexthop
->mrib_route_metric
=
935 nexthop_tab
[i
].route_metric
;
936 nexthop
->last_lookup
= addr
;
937 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
950 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
951 struct in_addr addr
, struct prefix
*src
,
954 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
957 ifindex_t first_ifindex
;
958 uint32_t hash_val
= 0, mod_val
= 0;
960 memset(nexthop_tab
, 0,
961 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
962 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
963 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
964 if (num_ifindex
< 1) {
965 if (PIM_DEBUG_PIM_NHT
) {
966 char addr_str
[INET_ADDRSTRLEN
];
967 pim_inet4_dump("<addr?>", addr
, addr_str
,
970 "%s: could not find nexthop ifindex for address %s(%s)",
971 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
976 // If PIM ECMP enable then choose ECMP path.
977 if (qpim_ecmp_enable
) {
978 hash_val
= pim_compute_ecmp_hash(src
, grp
);
979 mod_val
= hash_val
% num_ifindex
;
980 if (PIM_DEBUG_PIM_NHT_DETAIL
)
981 zlog_debug("%s: hash_val %u mod_val %u",
982 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
985 first_ifindex
= nexthop_tab
[mod_val
].ifindex
;
987 if (PIM_DEBUG_PIM_NHT
) {
988 char addr_str
[INET_ADDRSTRLEN
];
989 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
991 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
992 __PRETTY_FUNCTION__
, first_ifindex
,
993 ifindex2ifname(first_ifindex
, pim
->vrf_id
),
994 pim
->vrf
->name
, addr_str
);
997 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, first_ifindex
);
1000 if (PIM_DEBUG_PIM_NHT
) {
1001 char addr_str
[INET_ADDRSTRLEN
];
1002 pim_inet4_dump("<addr?>", addr
, addr_str
,
1005 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
1006 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,