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_and_null(&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 struct pim_neighbor
*nbr
;
306 nbr
= pim_neighbor_find(old
.source_nexthop
.interface
,
307 old
.rpf_addr
.u
.prefix4
);
309 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
312 * We have detected a case where we might need to rescan
313 * the inherited o_list so do it.
315 if (up
->channel_oil
&& up
->channel_oil
->oil_inherited_rescan
) {
316 pim_upstream_inherited_olist_decide(pim
, up
);
317 up
->channel_oil
->oil_inherited_rescan
= 0;
320 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
322 * If we come up real fast we can be here
323 * where the mroute has not been installed
326 if (up
->channel_oil
&& !up
->channel_oil
->installed
)
327 pim_mroute_add(up
->channel_oil
,
328 __PRETTY_FUNCTION__
);
331 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
333 * Transitions from Joined State
335 * RPF'(S,G) changes not due to an Assert
337 * The upstream (S,G) state machine remains in Joined
338 * state. Send Join(S,G) to the new upstream
339 * neighbor, which is the new value of RPF'(S,G).
340 * Send Prune(S,G) to the old upstream neighbor, which
341 * is the old value of RPF'(S,G). Set the Join
342 * Timer (JT) to expire after t_periodic seconds.
344 pim_jp_agg_switch_interface(&old
, &up
->rpf
, up
);
346 pim_upstream_join_timer_restart(up
, &old
);
347 } /* up->join_state == PIM_UPSTREAM_JOINED */
350 * FIXME can join_desired actually be changed by
351 * pim_rpf_update() returning PIM_RPF_CHANGED ?
353 pim_upstream_update_join_desired(pim
, up
);
355 } /* PIM_RPF_CHANGED */
357 if (PIM_DEBUG_PIM_NHT
) {
358 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
359 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
360 old
.source_nexthop
.interface
->name
,
361 up
->rpf
.source_nexthop
.interface
->name
);
364 return HASHWALK_CONTINUE
;
367 static int pim_update_upstream_nh(struct pim_instance
*pim
,
368 struct pim_nexthop_cache
*pnc
)
370 struct listnode
*node
;
371 struct interface
*ifp
;
373 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
375 FOR_ALL_INTERFACES (pim
->vrf
, ifp
)
377 struct pim_interface
*pim_ifp
= ifp
->info
;
378 struct pim_iface_upstream_switch
*us
;
380 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
,
383 rpf
.source_nexthop
.interface
= ifp
;
384 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
385 pim_joinprune_send(&rpf
, us
->us
);
386 pim_jp_agg_clear_group(us
->us
);
393 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
396 uint32_t s
= 0, g
= 0;
401 switch (src
->family
) {
403 s
= src
->u
.prefix4
.s_addr
;
406 g
= grp
->u
.prefix4
.s_addr
;
412 hash_val
= jhash_2words(g
, s
, 101);
416 int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
417 struct pim_nexthop_cache
*pnc
,
418 struct pim_nexthop
*nexthop
, struct prefix
*src
,
419 struct prefix
*grp
, int neighbor_needed
)
421 struct pim_neighbor
*nbr
= NULL
;
422 struct nexthop
*nh_node
= NULL
;
423 ifindex_t first_ifindex
;
424 struct interface
*ifp
= NULL
;
425 uint32_t hash_val
= 0, mod_val
= 0;
426 uint8_t nh_iter
= 0, found
= 0;
428 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
431 // Current Nexthop is VALID, check to stay on the current path.
432 if (nexthop
->interface
&& nexthop
->interface
->info
433 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
434 != PIM_NET_INADDR_ANY
) {
435 /* User configured knob to explicitly switch
436 to new path is disabled or current path
437 metric is less than nexthop update.
440 if (pim
->ecmp_rebalance_enable
== 0) {
441 uint8_t curr_route_valid
= 0;
442 // Check if current nexthop is present in new updated
444 // If the current nexthop is not valid, candidate to
445 // choose new Nexthop.
446 for (nh_node
= pnc
->nexthop
; nh_node
;
447 nh_node
= nh_node
->next
) {
448 curr_route_valid
= (nexthop
->interface
->ifindex
449 == nh_node
->ifindex
);
450 if (curr_route_valid
)
455 && !pim_if_connected_to_source(nexthop
->interface
,
457 nbr
= pim_neighbor_find(
459 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
461 && !if_is_loopback(nexthop
->interface
)) {
462 if (PIM_DEBUG_PIM_NHT
)
464 "%s: current nexthop does not have nbr ",
465 __PRETTY_FUNCTION__
);
467 if (PIM_DEBUG_PIM_NHT
) {
468 char src_str
[INET_ADDRSTRLEN
];
469 pim_inet4_dump("<addr?>",
473 char grp_str
[INET_ADDRSTRLEN
];
474 pim_inet4_dump("<addr?>",
479 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
483 nexthop
->interface
->name
);
490 if (pim
->ecmp_enable
) {
491 // PIM ECMP flag is enable then choose ECMP path.
492 hash_val
= pim_compute_ecmp_hash(src
, grp
);
493 mod_val
= hash_val
% pnc
->nexthop_num
;
496 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
497 nh_node
= nh_node
->next
) {
498 first_ifindex
= nh_node
->ifindex
;
499 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
501 if (PIM_DEBUG_PIM_NHT
) {
502 char addr_str
[INET_ADDRSTRLEN
];
503 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
504 addr_str
, sizeof(addr_str
));
506 "%s %s: could not find interface for ifindex %d (address %s(%s))",
507 __FILE__
, __PRETTY_FUNCTION__
,
508 first_ifindex
, addr_str
,
511 if (nh_iter
== mod_val
)
512 mod_val
++; // Select nexthpath
517 if (PIM_DEBUG_PIM_NHT
) {
518 char addr_str
[INET_ADDRSTRLEN
];
519 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
520 addr_str
, sizeof(addr_str
));
522 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
523 __PRETTY_FUNCTION__
, ifp
->name
,
524 pim
->vrf
->name
, first_ifindex
,
527 if (nh_iter
== mod_val
)
528 mod_val
++; // Select nexthpath
534 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
535 nbr
= pim_neighbor_find(ifp
, nh_node
->gate
.ipv4
);
536 if (!nbr
&& !if_is_loopback(ifp
)) {
537 if (PIM_DEBUG_PIM_NHT
)
539 "%s: pim nbr not found on input interface %s(%s)",
540 __PRETTY_FUNCTION__
, ifp
->name
,
542 if (nh_iter
== mod_val
)
543 mod_val
++; // Select nexthpath
549 if (nh_iter
== mod_val
) {
550 nexthop
->interface
= ifp
;
551 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
552 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
553 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
555 nexthop
->mrib_metric_preference
= pnc
->distance
;
556 nexthop
->mrib_route_metric
= pnc
->metric
;
557 nexthop
->last_lookup
= src
->u
.prefix4
;
558 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
561 if (PIM_DEBUG_PIM_NHT
) {
562 char buf
[INET_ADDRSTRLEN
];
563 char buf2
[INET_ADDRSTRLEN
];
564 char buf3
[INET_ADDRSTRLEN
];
565 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
567 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
571 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
574 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
575 __PRETTY_FUNCTION__
, buf2
, buf3
,
576 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
577 nh_iter
, pim
->ecmp_enable
);
589 /* This API is used to parse Registered address nexthop update coming from Zebra
591 int pim_parse_nexthop_update(int command
, struct zclient
*zclient
,
592 zebra_size_t length
, vrf_id_t vrf_id
)
594 struct nexthop
*nexthop
;
595 struct nexthop
*nhlist_head
= NULL
;
596 struct nexthop
*nhlist_tail
= NULL
;
599 struct pim_nexthop_cache
*pnc
= NULL
;
600 struct pim_neighbor
*nbr
= NULL
;
601 struct interface
*ifp
= NULL
;
602 struct interface
*ifp1
= NULL
;
603 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
604 struct pim_instance
*pim
;
605 struct zapi_route nhr
;
611 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
612 if (PIM_DEBUG_PIM_NHT
)
614 "%s: Decode of nexthop update from zebra failed",
615 __PRETTY_FUNCTION__
);
619 if (command
== ZEBRA_NEXTHOP_UPDATE
) {
620 prefix_copy(&rpf
.rpf_addr
, &nhr
.prefix
);
621 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
623 if (PIM_DEBUG_PIM_NHT
) {
624 char buf
[PREFIX2STR_BUFFER
];
625 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
627 "%s: Skipping NHT update, addr %s is not in local cached DB.",
628 __PRETTY_FUNCTION__
, buf
);
634 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
639 pnc
->last_update
= pim_time_monotonic_usec();
641 if (nhr
.nexthop_num
) {
642 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
644 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
645 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
646 switch (nexthop
->type
) {
647 case NEXTHOP_TYPE_IPV4
:
648 case NEXTHOP_TYPE_IPV4_IFINDEX
:
649 case NEXTHOP_TYPE_IPV6
:
650 case NEXTHOP_TYPE_BLACKHOLE
:
652 case NEXTHOP_TYPE_IFINDEX
:
654 * Connected route (i.e. no nexthop), use
655 * RPF address from nexthop cache (i.e.
656 * destination) as PIM nexthop.
658 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
660 pnc
->rpf
.rpf_addr
.u
.prefix4
;
662 case NEXTHOP_TYPE_IPV6_IFINDEX
:
663 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
665 nbr
= pim_neighbor_find_if(ifp1
);
666 /* Overwrite with Nbr address as NH addr */
668 nexthop
->gate
.ipv4
= nbr
->source_addr
;
670 // Mark nexthop address to 0 until PIM
672 nexthop
->gate
.ipv4
.s_addr
=
679 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
681 if (PIM_DEBUG_PIM_NHT
) {
682 char buf
[NEXTHOP_STRLEN
];
684 "%s: could not find interface for ifindex %d(%s) (addr %s)",
688 nexthop2str(nexthop
, buf
,
691 nexthop_free(nexthop
);
695 if (PIM_DEBUG_PIM_NHT
) {
696 char p_str
[PREFIX2STR_BUFFER
];
698 prefix2str(&nhr
.prefix
, p_str
, sizeof(p_str
));
700 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
701 __PRETTY_FUNCTION__
, p_str
,
702 pim
->vrf
->name
, i
+ 1,
703 inet_ntoa(nexthop
->gate
.ipv4
),
704 ifp
->name
, nexthop
->type
, nhr
.distance
,
709 if (PIM_DEBUG_PIM_NHT
) {
710 char buf
[NEXTHOP_STRLEN
];
713 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
714 __PRETTY_FUNCTION__
, ifp
->name
,
717 nexthop2str(nexthop
, buf
,
720 nexthop_free(nexthop
);
725 nhlist_tail
->next
= nexthop
;
726 nhlist_tail
= nexthop
;
728 nhlist_tail
= nexthop
;
729 nhlist_head
= nexthop
;
731 // Only keep track of nexthops which are PIM enabled.
734 /* Reset existing pnc->nexthop before assigning new list */
735 nexthops_free(pnc
->nexthop
);
736 pnc
->nexthop
= nhlist_head
;
737 if (pnc
->nexthop_num
) {
738 pnc
->flags
|= PIM_NEXTHOP_VALID
;
739 pnc
->distance
= nhr
.distance
;
740 pnc
->metric
= nhr
.metric
;
743 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
744 pnc
->nexthop_num
= nhr
.nexthop_num
;
745 nexthops_free(pnc
->nexthop
);
749 if (PIM_DEBUG_PIM_NHT
) {
750 char buf
[PREFIX2STR_BUFFER
];
751 prefix2str(&nhr
.prefix
, buf
, sizeof(buf
));
753 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
754 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
755 nhr
.nexthop_num
, pnc
->nexthop_num
, vrf_id
,
756 pnc
->upstream_hash
->count
, listcount(pnc
->rp_list
));
759 pim_rpf_set_refresh_time(pim
);
761 if (listcount(pnc
->rp_list
))
762 pim_update_rp_nh(pim
, pnc
);
763 if (pnc
->upstream_hash
->count
)
764 pim_update_upstream_nh(pim
, pnc
);
769 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
770 struct pim_nexthop
*nexthop
, struct in_addr addr
,
771 struct prefix
*src
, struct prefix
*grp
,
774 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
775 struct pim_neighbor
*nbr
= NULL
;
777 struct interface
*ifp
;
781 uint32_t hash_val
= 0, mod_val
= 0;
783 if (PIM_DEBUG_PIM_NHT
) {
784 char addr_str
[INET_ADDRSTRLEN
];
785 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
786 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
787 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
788 nexthop
->last_lookup_time
);
791 memset(nexthop_tab
, 0,
792 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
793 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
794 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
795 if (num_ifindex
< 1) {
796 if (PIM_DEBUG_PIM_NHT
) {
797 char addr_str
[INET_ADDRSTRLEN
];
798 pim_inet4_dump("<addr?>", addr
, addr_str
,
801 "%s: could not find nexthop ifindex for address %s(%s)",
802 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
807 // If PIM ECMP enable then choose ECMP path.
808 if (pim
->ecmp_enable
) {
809 hash_val
= pim_compute_ecmp_hash(src
, grp
);
810 mod_val
= hash_val
% num_ifindex
;
811 if (PIM_DEBUG_PIM_NHT_DETAIL
)
812 zlog_debug("%s: hash_val %u mod_val %u",
813 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
816 while (!found
&& (i
< num_ifindex
)) {
817 first_ifindex
= nexthop_tab
[i
].ifindex
;
819 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
821 if (PIM_DEBUG_PIM_NHT
) {
822 char addr_str
[INET_ADDRSTRLEN
];
823 pim_inet4_dump("<addr?>", addr
, addr_str
,
826 "%s %s: could not find interface for ifindex %d (address %s(%s))",
827 __FILE__
, __PRETTY_FUNCTION__
,
828 first_ifindex
, addr_str
,
838 if (PIM_DEBUG_PIM_NHT
) {
839 char addr_str
[INET_ADDRSTRLEN
];
840 pim_inet4_dump("<addr?>", addr
, addr_str
,
843 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
844 __PRETTY_FUNCTION__
, ifp
->name
,
845 pim
->vrf
->name
, first_ifindex
,
853 if (neighbor_needed
&& !pim_if_connected_to_source(ifp
, addr
)) {
854 nbr
= pim_neighbor_find(
855 ifp
, nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
856 if (PIM_DEBUG_PIM_NHT_DETAIL
)
857 zlog_debug("ifp name: %s(%s), pim nbr: %p",
858 ifp
->name
, pim
->vrf
->name
, nbr
);
859 if (!nbr
&& !if_is_loopback(ifp
)) {
863 if (PIM_DEBUG_PIM_NHT
) {
864 char addr_str
[INET_ADDRSTRLEN
];
865 pim_inet4_dump("<addr?>", addr
,
869 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
870 __PRETTY_FUNCTION__
, ifp
->name
,
871 pim
->vrf
->name
, addr_str
);
878 if (PIM_DEBUG_PIM_NHT
) {
879 char nexthop_str
[PREFIX_STRLEN
];
880 char addr_str
[INET_ADDRSTRLEN
];
881 pim_addr_dump("<nexthop?>",
882 &nexthop_tab
[i
].nexthop_addr
,
883 nexthop_str
, sizeof(nexthop_str
));
884 pim_inet4_dump("<addr?>", addr
, addr_str
,
887 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
888 __PRETTY_FUNCTION__
, nexthop_str
,
889 addr_str
, ifp
->name
, pim
->vrf
->name
,
890 nexthop_tab
[i
].route_metric
,
891 nexthop_tab
[i
].protocol_distance
);
893 /* update nexthop data */
894 nexthop
->interface
= ifp
;
895 nexthop
->mrib_nexthop_addr
=
896 nexthop_tab
[i
].nexthop_addr
;
897 nexthop
->mrib_metric_preference
=
898 nexthop_tab
[i
].protocol_distance
;
899 nexthop
->mrib_route_metric
=
900 nexthop_tab
[i
].route_metric
;
901 nexthop
->last_lookup
= addr
;
902 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
915 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
916 struct in_addr addr
, struct prefix
*src
,
919 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
922 ifindex_t first_ifindex
;
923 uint32_t hash_val
= 0, mod_val
= 0;
925 memset(nexthop_tab
, 0,
926 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
927 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
928 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
929 if (num_ifindex
< 1) {
930 if (PIM_DEBUG_PIM_NHT
) {
931 char addr_str
[INET_ADDRSTRLEN
];
932 pim_inet4_dump("<addr?>", addr
, addr_str
,
935 "%s: could not find nexthop ifindex for address %s(%s)",
936 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
941 // If PIM ECMP enable then choose ECMP path.
942 if (pim
->ecmp_enable
) {
943 hash_val
= pim_compute_ecmp_hash(src
, grp
);
944 mod_val
= hash_val
% num_ifindex
;
945 if (PIM_DEBUG_PIM_NHT_DETAIL
)
946 zlog_debug("%s: hash_val %u mod_val %u",
947 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
950 first_ifindex
= nexthop_tab
[mod_val
].ifindex
;
952 if (PIM_DEBUG_PIM_NHT
) {
953 char addr_str
[INET_ADDRSTRLEN
];
954 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
956 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
957 __PRETTY_FUNCTION__
, first_ifindex
,
958 ifindex2ifname(first_ifindex
, pim
->vrf_id
),
959 pim
->vrf
->name
, addr_str
);
962 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, first_ifindex
);
965 if (PIM_DEBUG_PIM_NHT
) {
966 char addr_str
[INET_ADDRSTRLEN
];
967 pim_inet4_dump("<addr?>", addr
, addr_str
,
970 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
971 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,