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
)
55 if (!zclient
|| zclient
->sock
< 0)
58 p
= &(pnc
->rpf
.rpf_addr
);
61 zclient_create_header(s
, command
, pim
->vrf_id
);
62 /* get update for all routes for a prefix */
65 stream_putw(s
, PREFIX_FAMILY(p
));
66 stream_putc(s
, p
->prefixlen
);
67 switch (PREFIX_FAMILY(p
)) {
69 stream_put_in_addr(s
, &p
->u
.prefix4
);
72 stream_put(s
, &(p
->u
.prefix6
), 16);
77 stream_putw_at(s
, 0, stream_get_endp(s
));
79 ret
= zclient_send_message(zclient
);
81 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
84 if (PIM_DEBUG_PIM_NHT
) {
85 char buf
[PREFIX2STR_BUFFER
];
86 prefix2str(p
, buf
, sizeof(buf
));
88 "%s: NHT %sregistered addr %s(%s) with Zebra ret:%d ",
90 (command
== ZEBRA_NEXTHOP_REGISTER
) ? " " : "de", buf
,
97 struct pim_nexthop_cache
*pim_nexthop_cache_find(struct pim_instance
*pim
,
100 struct pim_nexthop_cache
*pnc
= NULL
;
101 struct pim_nexthop_cache lookup
;
103 lookup
.rpf
.rpf_addr
.family
= rpf
->rpf_addr
.family
;
104 lookup
.rpf
.rpf_addr
.prefixlen
= rpf
->rpf_addr
.prefixlen
;
105 lookup
.rpf
.rpf_addr
.u
.prefix4
.s_addr
= rpf
->rpf_addr
.u
.prefix4
.s_addr
;
107 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
112 static struct pim_nexthop_cache
*pim_nexthop_cache_add(struct pim_instance
*pim
,
113 struct pim_rpf
*rpf_addr
)
115 struct pim_nexthop_cache
*pnc
;
119 pnc
= XCALLOC(MTYPE_PIM_NEXTHOP_CACHE
,
120 sizeof(struct pim_nexthop_cache
));
122 zlog_err("%s: NHT PIM XCALLOC failure ", __PRETTY_FUNCTION__
);
125 pnc
->rpf
.rpf_addr
.family
= rpf_addr
->rpf_addr
.family
;
126 pnc
->rpf
.rpf_addr
.prefixlen
= rpf_addr
->rpf_addr
.prefixlen
;
127 pnc
->rpf
.rpf_addr
.u
.prefix4
.s_addr
=
128 rpf_addr
->rpf_addr
.u
.prefix4
.s_addr
;
130 pnc
= hash_get(pim
->rpf_hash
, pnc
, hash_alloc_intern
);
132 pnc
->rp_list
= list_new();
133 pnc
->rp_list
->cmp
= pim_rp_list_cmp
;
135 snprintf(hash_name
, 64, "PNC %s(%s) Upstream Hash",
136 prefix2str(&pnc
->rpf
.rpf_addr
, buf1
, 64),
138 pnc
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
146 * pim_find_or_track_nexthop
148 * This API is used to Register an address with Zebra
153 int pim_find_or_track_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
154 struct pim_upstream
*up
, struct rp_info
*rp
,
155 struct pim_nexthop_cache
*out_pnc
)
157 struct pim_nexthop_cache
*pnc
= NULL
;
159 struct listnode
*ch_node
= NULL
;
160 struct zclient
*zclient
= NULL
;
162 zclient
= pim_zebra_zclient_get();
163 memset(&rpf
, 0, sizeof(struct pim_rpf
));
164 rpf
.rpf_addr
.family
= addr
->family
;
165 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
166 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
168 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
170 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
172 char rpf_str
[PREFIX_STRLEN
];
173 pim_addr_dump("<nht-pnc?>", addr
, rpf_str
,
175 zlog_warn("%s: pnc node allocation failed. addr %s ",
176 __PRETTY_FUNCTION__
, rpf_str
);
179 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
180 ZEBRA_NEXTHOP_REGISTER
);
181 if (PIM_DEBUG_PIM_NHT
) {
182 char buf
[PREFIX2STR_BUFFER
];
183 prefix2str(addr
, buf
, sizeof(buf
));
185 "%s: NHT cache and zebra notification added for %s(%s)",
186 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
);
191 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
193 listnode_add_sort(pnc
->rp_list
, rp
);
197 up
= hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
199 if (pnc
&& CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
200 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
207 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
208 struct pim_upstream
*up
, struct rp_info
*rp
)
210 struct pim_nexthop_cache
*pnc
= NULL
;
211 struct pim_nexthop_cache lookup
;
212 struct zclient
*zclient
= NULL
;
214 zclient
= pim_zebra_zclient_get();
216 /* Remove from RPF hash if it is the last entry */
217 lookup
.rpf
.rpf_addr
= *addr
;
218 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
221 listnode_delete(pnc
->rp_list
, rp
);
223 hash_release(pnc
->upstream_hash
, up
);
225 if (PIM_DEBUG_PIM_NHT
) {
226 char buf
[PREFIX_STRLEN
];
227 prefix2str(addr
, buf
, sizeof buf
);
229 "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
230 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
231 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
234 if (pnc
->rp_list
->count
== 0
235 && pnc
->upstream_hash
->count
== 0) {
236 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
237 ZEBRA_NEXTHOP_UNREGISTER
);
239 list_delete(pnc
->rp_list
);
240 hash_free(pnc
->upstream_hash
);
242 hash_release(pim
->rpf_hash
, pnc
);
244 nexthops_free(pnc
->nexthop
);
245 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
250 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
251 static int pim_update_rp_nh(struct pim_instance
*pim
,
252 struct pim_nexthop_cache
*pnc
)
254 struct listnode
*node
= NULL
;
255 struct rp_info
*rp_info
= NULL
;
258 /*Traverse RP list and update each RP Nexthop info */
259 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
260 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
263 // Compute PIM RPF using cached nexthop
264 ret
= pim_ecmp_nexthop_search(
265 pim
, pnc
, &rp_info
->rp
.source_nexthop
,
266 &rp_info
->rp
.rpf_addr
, &rp_info
->group
, 1);
272 /* This API is used to traverse nexthop cache of RPF addr
273 of upstream entry whose IPv4 nexthop address is in
274 unresolved state and due to event like pim neighbor
275 UP event if it can be resolved.
277 void pim_resolve_upstream_nh(struct pim_instance
*pim
, struct prefix
*nht_p
)
279 struct nexthop
*nh_node
= NULL
;
280 struct pim_nexthop_cache pnc
;
281 struct pim_neighbor
*nbr
= NULL
;
283 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
284 if (!pim_find_or_track_nexthop(pim
, nht_p
, NULL
, NULL
, &pnc
))
287 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
288 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
291 struct interface
*ifp1
=
292 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
293 nbr
= pim_neighbor_find_if(ifp1
);
297 nh_node
->gate
.ipv4
= nbr
->source_addr
;
298 if (PIM_DEBUG_PIM_NHT
) {
299 char str
[PREFIX_STRLEN
];
300 char str1
[INET_ADDRSTRLEN
];
301 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
, str1
,
303 pim_addr_dump("<nht_addr?>", nht_p
, str
, sizeof(str
));
305 "%s: addr %s new nexthop addr %s interface %s",
306 __PRETTY_FUNCTION__
, str
, str1
, ifp1
->name
);
311 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
312 static int pim_update_upstream_nh_helper(struct hash_backet
*backet
, void *arg
)
314 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
315 struct pim_upstream
*up
= (struct pim_upstream
*)backet
->data
;
318 enum pim_rpf_result rpf_result
;
321 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
322 rpf_result
= pim_rpf_update(pim
, up
, &old
, 0);
323 if (rpf_result
== PIM_RPF_FAILURE
)
324 return HASHWALK_CONTINUE
;
326 /* update kernel multicast forwarding cache (MFC) */
327 if (up
->channel_oil
) {
328 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
330 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
331 /* Pass Current selected NH vif index to mroute download
334 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
336 if (PIM_DEBUG_PIM_NHT
)
338 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
339 __PRETTY_FUNCTION__
, up
->sg_str
,
340 up
->rpf
.source_nexthop
.interface
->name
);
344 if (rpf_result
== PIM_RPF_CHANGED
) {
345 struct pim_neighbor
*nbr
;
347 nbr
= pim_neighbor_find(old
.source_nexthop
.interface
,
348 old
.rpf_addr
.u
.prefix4
);
350 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
);
353 * We have detected a case where we might need to rescan
354 * the inherited o_list so do it.
357 && up
->channel_oil
->oil_inherited_rescan
) {
358 pim_upstream_inherited_olist_decide(pim
, up
);
359 up
->channel_oil
->oil_inherited_rescan
= 0;
362 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
364 * If we come up real fast we can be here
365 * where the mroute has not been installed
369 && !up
->channel_oil
->installed
)
370 pim_mroute_add(up
->channel_oil
,
371 __PRETTY_FUNCTION__
);
374 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
376 * Transitions from Joined State
378 * RPF'(S,G) changes not due to an Assert
380 * The upstream (S,G) state machine remains in Joined
381 * state. Send Join(S,G) to the new upstream
382 * neighbor, which is the new value of RPF'(S,G).
383 * Send Prune(S,G) to the old upstream neighbor, which
384 * is the old value of RPF'(S,G). Set the Join
385 * Timer (JT) to expire after t_periodic seconds.
387 pim_jp_agg_switch_interface(&old
, &up
->rpf
, up
);
389 pim_upstream_join_timer_restart(up
, &old
);
390 } /* up->join_state == PIM_UPSTREAM_JOINED */
393 * FIXME can join_desired actually be changed by
394 * pim_rpf_update() returning PIM_RPF_CHANGED ?
396 pim_upstream_update_join_desired(pim
, up
);
398 } /* PIM_RPF_CHANGED */
400 if (PIM_DEBUG_PIM_NHT
) {
401 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
402 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
403 old
.source_nexthop
.interface
->name
,
404 up
->rpf
.source_nexthop
.interface
->name
);
407 return HASHWALK_CONTINUE
;
410 static int pim_update_upstream_nh(struct pim_instance
*pim
,
411 struct pim_nexthop_cache
*pnc
)
413 struct listnode
*node
, *ifnode
;
414 struct interface
*ifp
;
416 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
418 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), ifnode
, ifp
))
420 struct pim_interface
*pim_ifp
= ifp
->info
;
421 struct pim_iface_upstream_switch
*us
;
423 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
,
426 rpf
.source_nexthop
.interface
= ifp
;
427 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
428 pim_joinprune_send(&rpf
, us
->us
);
429 pim_jp_agg_clear_group(us
->us
);
436 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
439 uint32_t s
= 0, g
= 0;
444 switch (src
->family
) {
446 s
= src
->u
.prefix4
.s_addr
;
449 g
= grp
->u
.prefix4
.s_addr
;
455 hash_val
= jhash_2words(g
, s
, 101);
459 int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
460 struct pim_nexthop_cache
*pnc
,
461 struct pim_nexthop
*nexthop
, struct prefix
*src
,
462 struct prefix
*grp
, int neighbor_needed
)
464 struct pim_neighbor
*nbr
= NULL
;
465 struct nexthop
*nh_node
= NULL
;
466 ifindex_t first_ifindex
;
467 struct interface
*ifp
= NULL
;
468 uint32_t hash_val
= 0, mod_val
= 0;
469 uint8_t nh_iter
= 0, found
= 0;
471 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
474 // Current Nexthop is VALID, check to stay on the current path.
475 if (nexthop
->interface
&& nexthop
->interface
->info
476 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
477 != PIM_NET_INADDR_ANY
) {
478 /* User configured knob to explicitly switch
479 to new path is disabled or current path
480 metric is less than nexthop update.
483 if (qpim_ecmp_rebalance_enable
== 0) {
484 uint8_t curr_route_valid
= 0;
485 // Check if current nexthop is present in new updated
487 // If the current nexthop is not valid, candidate to
488 // choose new Nexthop.
489 for (nh_node
= pnc
->nexthop
; nh_node
;
490 nh_node
= nh_node
->next
) {
491 curr_route_valid
= (nexthop
->interface
->ifindex
492 == nh_node
->ifindex
);
493 if (curr_route_valid
)
498 && !pim_if_connected_to_source(nexthop
->interface
,
500 nbr
= pim_neighbor_find(
502 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
504 && !if_is_loopback(nexthop
->interface
)) {
505 if (PIM_DEBUG_PIM_NHT
)
507 "%s: current nexthop does not have nbr ",
508 __PRETTY_FUNCTION__
);
510 if (PIM_DEBUG_PIM_NHT
) {
511 char src_str
[INET_ADDRSTRLEN
];
512 pim_inet4_dump("<addr?>",
516 char grp_str
[INET_ADDRSTRLEN
];
517 pim_inet4_dump("<addr?>",
522 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
526 nexthop
->interface
->name
);
533 if (qpim_ecmp_enable
) {
534 // PIM ECMP flag is enable then choose ECMP path.
535 hash_val
= pim_compute_ecmp_hash(src
, grp
);
536 mod_val
= hash_val
% pnc
->nexthop_num
;
539 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
540 nh_node
= nh_node
->next
) {
541 first_ifindex
= nh_node
->ifindex
;
542 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
544 if (PIM_DEBUG_PIM_NHT
) {
545 char addr_str
[INET_ADDRSTRLEN
];
546 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
547 addr_str
, sizeof(addr_str
));
549 "%s %s: could not find interface for ifindex %d (address %s(%s))",
550 __FILE__
, __PRETTY_FUNCTION__
,
551 first_ifindex
, addr_str
,
554 if (nh_iter
== mod_val
)
555 mod_val
++; // Select nexthpath
560 if (PIM_DEBUG_PIM_NHT
) {
561 char addr_str
[INET_ADDRSTRLEN
];
562 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
563 addr_str
, sizeof(addr_str
));
565 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
566 __PRETTY_FUNCTION__
, ifp
->name
,
567 pim
->vrf
->name
, first_ifindex
,
570 if (nh_iter
== mod_val
)
571 mod_val
++; // Select nexthpath
577 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
578 nbr
= pim_neighbor_find(ifp
, nh_node
->gate
.ipv4
);
579 if (!nbr
&& !if_is_loopback(ifp
)) {
580 if (PIM_DEBUG_PIM_NHT
)
582 "%s: pim nbr not found on input interface %s(%s)",
583 __PRETTY_FUNCTION__
, ifp
->name
,
585 if (nh_iter
== mod_val
)
586 mod_val
++; // Select nexthpath
592 if (nh_iter
== mod_val
) {
593 nexthop
->interface
= ifp
;
594 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
595 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
596 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
598 nexthop
->mrib_metric_preference
= pnc
->distance
;
599 nexthop
->mrib_route_metric
= pnc
->metric
;
600 nexthop
->last_lookup
= src
->u
.prefix4
;
601 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
604 if (PIM_DEBUG_PIM_NHT
) {
605 char buf
[INET_ADDRSTRLEN
];
606 char buf2
[INET_ADDRSTRLEN
];
607 char buf3
[INET_ADDRSTRLEN
];
608 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
610 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
614 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
617 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
618 __PRETTY_FUNCTION__
, buf2
, buf3
,
619 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
620 nh_iter
, qpim_ecmp_enable
);
632 /* This API is used to parse Registered address nexthop update coming from Zebra
634 int pim_parse_nexthop_update(int command
, struct zclient
*zclient
,
635 zebra_size_t length
, vrf_id_t vrf_id
)
639 struct nexthop
*nexthop
;
640 struct nexthop
*nhlist_head
= NULL
;
641 struct nexthop
*nhlist_tail
= NULL
;
642 uint32_t metric
, distance
;
643 u_char nexthop_num
= 0;
646 struct pim_nexthop_cache
*pnc
= NULL
;
647 struct pim_neighbor
*nbr
= NULL
;
648 struct interface
*ifp
= NULL
;
649 struct interface
*ifp1
= NULL
;
650 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
651 struct pim_instance
*pim
= vrf
->info
;
654 memset(&p
, 0, sizeof(struct prefix
));
655 p
.family
= stream_getw(s
);
656 p
.prefixlen
= stream_getc(s
);
659 p
.u
.prefix4
.s_addr
= stream_get_ipv4(s
);
662 stream_get(&p
.u
.prefix6
, s
, 16);
668 if (command
== ZEBRA_NEXTHOP_UPDATE
) {
669 rpf
.rpf_addr
.family
= p
.family
;
670 rpf
.rpf_addr
.prefixlen
= p
.prefixlen
;
671 rpf
.rpf_addr
.u
.prefix4
.s_addr
= p
.u
.prefix4
.s_addr
;
672 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
674 if (PIM_DEBUG_PIM_NHT
) {
675 char buf
[PREFIX2STR_BUFFER
];
676 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
678 "%s: Skipping NHT update, addr %s is not in local cached DB.",
679 __PRETTY_FUNCTION__
, buf
);
685 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
690 pnc
->last_update
= pim_time_monotonic_usec();
691 distance
= stream_getc(s
);
692 metric
= stream_getl(s
);
693 nexthop_num
= stream_getc(s
);
696 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
698 for (i
= 0; i
< nexthop_num
; i
++) {
699 nexthop
= nexthop_new();
700 nexthop
->type
= stream_getc(s
);
701 switch (nexthop
->type
) {
702 case NEXTHOP_TYPE_IPV4
:
703 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
704 nexthop
->ifindex
= stream_getl(s
);
706 case NEXTHOP_TYPE_IFINDEX
:
707 nexthop
->ifindex
= stream_getl(s
);
709 case NEXTHOP_TYPE_IPV4_IFINDEX
:
710 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
711 nexthop
->ifindex
= stream_getl(s
);
713 case NEXTHOP_TYPE_IPV6
:
714 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
716 case NEXTHOP_TYPE_IPV6_IFINDEX
:
717 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
718 nexthop
->ifindex
= stream_getl(s
);
719 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
721 nbr
= pim_neighbor_find_if(ifp1
);
722 /* Overwrite with Nbr address as NH addr */
724 nexthop
->gate
.ipv4
= nbr
->source_addr
;
726 // Mark nexthop address to 0 until PIM
728 nexthop
->gate
.ipv4
.s_addr
=
738 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
740 if (PIM_DEBUG_PIM_NHT
) {
741 char buf
[NEXTHOP_STRLEN
];
743 "%s: could not find interface for ifindex %d(%s) (addr %s)",
747 nexthop2str(nexthop
, buf
,
750 nexthop_free(nexthop
);
754 if (PIM_DEBUG_PIM_NHT
) {
755 char p_str
[PREFIX2STR_BUFFER
];
756 prefix2str(&p
, p_str
, sizeof(p_str
));
758 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
759 __PRETTY_FUNCTION__
, p_str
,
760 pim
->vrf
->name
, i
+ 1,
761 inet_ntoa(nexthop
->gate
.ipv4
),
762 ifp
->name
, nexthop
->type
, distance
,
767 if (PIM_DEBUG_PIM_NHT
) {
768 char buf
[NEXTHOP_STRLEN
];
770 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
771 __PRETTY_FUNCTION__
, ifp
->name
,
774 nexthop2str(nexthop
, buf
,
777 nexthop_free(nexthop
);
782 nhlist_tail
->next
= nexthop
;
783 nhlist_tail
= nexthop
;
785 nhlist_tail
= nexthop
;
786 nhlist_head
= nexthop
;
788 // Only keep track of nexthops which are PIM enabled.
791 /* Reset existing pnc->nexthop before assigning new list */
792 nexthops_free(pnc
->nexthop
);
793 pnc
->nexthop
= nhlist_head
;
794 if (pnc
->nexthop_num
) {
795 pnc
->flags
|= PIM_NEXTHOP_VALID
;
796 pnc
->distance
= distance
;
797 pnc
->metric
= metric
;
800 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
801 pnc
->nexthop_num
= nexthop_num
;
802 nexthops_free(pnc
->nexthop
);
806 if (PIM_DEBUG_PIM_NHT
) {
807 char buf
[PREFIX2STR_BUFFER
];
808 prefix2str(&p
, buf
, sizeof(buf
));
810 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d",
811 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
, nexthop_num
,
812 pnc
->nexthop_num
, vrf_id
, pnc
->upstream_hash
->count
,
813 listcount(pnc
->rp_list
));
816 pim_rpf_set_refresh_time();
818 if (listcount(pnc
->rp_list
))
819 pim_update_rp_nh(pim
, pnc
);
820 if (pnc
->upstream_hash
->count
)
821 pim_update_upstream_nh(pim
, pnc
);
826 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
827 struct pim_nexthop
*nexthop
, struct in_addr addr
,
828 struct prefix
*src
, struct prefix
*grp
,
831 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
832 struct pim_neighbor
*nbr
= NULL
;
834 struct interface
*ifp
;
838 uint32_t hash_val
= 0, mod_val
= 0;
840 if (PIM_DEBUG_PIM_NHT
) {
841 char addr_str
[INET_ADDRSTRLEN
];
842 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
843 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
844 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
845 nexthop
->last_lookup_time
);
848 memset(nexthop_tab
, 0,
849 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
850 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
851 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
852 if (num_ifindex
< 1) {
853 if (PIM_DEBUG_PIM_NHT
) {
854 char addr_str
[INET_ADDRSTRLEN
];
855 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
857 "%s: could not find nexthop ifindex for address %s(%s)",
858 __PRETTY_FUNCTION__
, addr_str
,
864 // If PIM ECMP enable then choose ECMP path.
865 if (qpim_ecmp_enable
) {
866 hash_val
= pim_compute_ecmp_hash(src
, grp
);
867 mod_val
= hash_val
% num_ifindex
;
868 if (PIM_DEBUG_PIM_NHT_DETAIL
)
869 zlog_debug("%s: hash_val %u mod_val %u",
870 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
873 while (!found
&& (i
< num_ifindex
)) {
874 first_ifindex
= nexthop_tab
[i
].ifindex
;
876 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
878 if (PIM_DEBUG_PIM_NHT
) {
879 char addr_str
[INET_ADDRSTRLEN
];
880 pim_inet4_dump("<addr?>", addr
, addr_str
,
883 "%s %s: could not find interface for ifindex %d (address %s(%s))",
884 __FILE__
, __PRETTY_FUNCTION__
,
885 first_ifindex
, addr_str
,
895 if (PIM_DEBUG_PIM_NHT
) {
896 char addr_str
[INET_ADDRSTRLEN
];
897 pim_inet4_dump("<addr?>", addr
, addr_str
,
900 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
901 __PRETTY_FUNCTION__
, ifp
->name
,
902 pim
->vrf
->name
, first_ifindex
,
910 if (neighbor_needed
&& !pim_if_connected_to_source(ifp
, addr
)) {
911 nbr
= pim_neighbor_find(
912 ifp
, nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
913 if (PIM_DEBUG_PIM_NHT_DETAIL
)
914 zlog_debug("ifp name: %s(%s), pim nbr: %p",
915 ifp
->name
, pim
->vrf
->name
, nbr
);
916 if (!nbr
&& !if_is_loopback(ifp
)) {
920 if (PIM_DEBUG_PIM_NHT
) {
921 char addr_str
[INET_ADDRSTRLEN
];
922 pim_inet4_dump("<addr?>", addr
,
926 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
927 __PRETTY_FUNCTION__
, ifp
->name
,
928 pim
->vrf
->name
, addr_str
);
935 if (PIM_DEBUG_PIM_NHT
) {
936 char nexthop_str
[PREFIX_STRLEN
];
937 char addr_str
[INET_ADDRSTRLEN
];
938 pim_addr_dump("<nexthop?>",
939 &nexthop_tab
[i
].nexthop_addr
,
940 nexthop_str
, sizeof(nexthop_str
));
941 pim_inet4_dump("<addr?>", addr
, addr_str
,
944 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
945 __PRETTY_FUNCTION__
, nexthop_str
,
946 addr_str
, ifp
->name
, pim
->vrf
->name
,
947 nexthop_tab
[i
].route_metric
,
948 nexthop_tab
[i
].protocol_distance
);
950 /* update nextop data */
951 nexthop
->interface
= ifp
;
952 nexthop
->mrib_nexthop_addr
=
953 nexthop_tab
[i
].nexthop_addr
;
954 nexthop
->mrib_metric_preference
=
955 nexthop_tab
[i
].protocol_distance
;
956 nexthop
->mrib_route_metric
=
957 nexthop_tab
[i
].route_metric
;
958 nexthop
->last_lookup
= addr
;
959 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
972 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
973 struct in_addr addr
, struct prefix
*src
,
976 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
979 ifindex_t first_ifindex
;
980 uint32_t hash_val
= 0, mod_val
= 0;
982 memset(nexthop_tab
, 0,
983 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
984 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
985 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
986 if (num_ifindex
< 1) {
987 if (PIM_DEBUG_PIM_NHT
) {
988 char addr_str
[INET_ADDRSTRLEN
];
989 pim_inet4_dump("<addr?>", addr
, addr_str
,
992 "%s: could not find nexthop ifindex for address %s(%s)",
993 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
998 // If PIM ECMP enable then choose ECMP path.
999 if (qpim_ecmp_enable
) {
1000 hash_val
= pim_compute_ecmp_hash(src
, grp
);
1001 mod_val
= hash_val
% num_ifindex
;
1002 if (PIM_DEBUG_PIM_NHT_DETAIL
)
1003 zlog_debug("%s: hash_val %u mod_val %u",
1004 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
1007 first_ifindex
= nexthop_tab
[mod_val
].ifindex
;
1009 if (PIM_DEBUG_PIM_NHT
) {
1010 char addr_str
[INET_ADDRSTRLEN
];
1011 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
1013 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
1014 __PRETTY_FUNCTION__
, first_ifindex
,
1015 ifindex2ifname(first_ifindex
, pim
->vrf_id
),
1016 pim
->vrf
->name
, addr_str
);
1019 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, first_ifindex
);
1021 if (vif_index
< 0) {
1022 if (PIM_DEBUG_PIM_NHT
) {
1023 char addr_str
[INET_ADDRSTRLEN
];
1024 pim_inet4_dump("<addr?>", addr
, addr_str
,
1027 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
1028 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,