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"
45 * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
48 void pim_sendmsg_zebra_rnh(struct pim_instance
*pim
, struct zclient
*zclient
,
49 struct pim_nexthop_cache
*pnc
, int command
)
54 p
= &(pnc
->rpf
.rpf_addr
);
55 ret
= zclient_send_rnh(zclient
, command
, p
, false, pim
->vrf_id
);
57 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
59 if (PIM_DEBUG_PIM_NHT
) {
60 char buf
[PREFIX2STR_BUFFER
];
61 prefix2str(p
, buf
, sizeof(buf
));
63 "%s: NHT %sregistered addr %s(%s) with Zebra ret:%d ",
65 (command
== ZEBRA_NEXTHOP_REGISTER
) ? " " : "de", buf
,
72 struct pim_nexthop_cache
*pim_nexthop_cache_find(struct pim_instance
*pim
,
75 struct pim_nexthop_cache
*pnc
= NULL
;
76 struct pim_nexthop_cache lookup
;
78 lookup
.rpf
.rpf_addr
.family
= rpf
->rpf_addr
.family
;
79 lookup
.rpf
.rpf_addr
.prefixlen
= rpf
->rpf_addr
.prefixlen
;
80 lookup
.rpf
.rpf_addr
.u
.prefix4
.s_addr
= rpf
->rpf_addr
.u
.prefix4
.s_addr
;
82 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
87 static struct pim_nexthop_cache
*pim_nexthop_cache_add(struct pim_instance
*pim
,
88 struct pim_rpf
*rpf_addr
)
90 struct pim_nexthop_cache
*pnc
;
94 pnc
= XCALLOC(MTYPE_PIM_NEXTHOP_CACHE
,
95 sizeof(struct pim_nexthop_cache
));
96 pnc
->rpf
.rpf_addr
.family
= rpf_addr
->rpf_addr
.family
;
97 pnc
->rpf
.rpf_addr
.prefixlen
= rpf_addr
->rpf_addr
.prefixlen
;
98 pnc
->rpf
.rpf_addr
.u
.prefix4
.s_addr
=
99 rpf_addr
->rpf_addr
.u
.prefix4
.s_addr
;
101 pnc
= hash_get(pim
->rpf_hash
, pnc
, hash_alloc_intern
);
103 pnc
->rp_list
= list_new();
104 pnc
->rp_list
->cmp
= pim_rp_list_cmp
;
106 snprintf(hash_name
, 64, "PNC %s(%s) Upstream Hash",
107 prefix2str(&pnc
->rpf
.rpf_addr
, buf1
, 64), pim
->vrf
->name
);
108 pnc
->upstream_hash
= hash_create_size(8192, pim_upstream_hash_key
,
109 pim_upstream_equal
, hash_name
);
115 * pim_find_or_track_nexthop
117 * This API is used to Register an address with Zebra
122 int pim_find_or_track_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
123 struct pim_upstream
*up
, struct rp_info
*rp
,
124 struct pim_nexthop_cache
*out_pnc
)
126 struct pim_nexthop_cache
*pnc
= NULL
;
128 struct listnode
*ch_node
= NULL
;
129 struct zclient
*zclient
= NULL
;
131 zclient
= pim_zebra_zclient_get();
132 memset(&rpf
, 0, sizeof(struct pim_rpf
));
133 rpf
.rpf_addr
.family
= addr
->family
;
134 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
135 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
137 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
139 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
140 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
141 ZEBRA_NEXTHOP_REGISTER
);
142 if (PIM_DEBUG_PIM_NHT
) {
143 char buf
[PREFIX2STR_BUFFER
];
144 prefix2str(addr
, buf
, sizeof(buf
));
146 "%s: NHT cache and zebra notification added for %s(%s)",
147 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
);
152 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
154 listnode_add_sort(pnc
->rp_list
, rp
);
158 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
160 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
161 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
168 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
169 struct pim_upstream
*up
, struct rp_info
*rp
)
171 struct pim_nexthop_cache
*pnc
= NULL
;
172 struct pim_nexthop_cache lookup
;
173 struct zclient
*zclient
= NULL
;
174 struct listnode
*upnode
= NULL
;
175 struct pim_upstream
*upstream
= NULL
;
177 zclient
= pim_zebra_zclient_get();
179 /* Remove from RPF hash if it is the last entry */
180 lookup
.rpf
.rpf_addr
= *addr
;
181 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
184 /* Release the (*, G)upstream from pnc->upstream_hash,
185 * whose Group belongs to the RP getting deleted
187 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
,
190 struct rp_info
*trp_info
;
192 if (upstream
->sg
.src
.s_addr
!= INADDR_ANY
)
195 grp
.family
= AF_INET
;
196 grp
.prefixlen
= IPV4_MAX_BITLEN
;
197 grp
.u
.prefix4
= upstream
->sg
.grp
;
199 trp_info
= pim_rp_find_match_group(pim
, &grp
);
201 hash_release(pnc
->upstream_hash
,
204 listnode_delete(pnc
->rp_list
, rp
);
208 hash_release(pnc
->upstream_hash
, up
);
210 if (PIM_DEBUG_PIM_NHT
) {
211 char buf
[PREFIX_STRLEN
];
212 prefix2str(addr
, buf
, sizeof buf
);
214 "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
215 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
216 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
219 if (pnc
->rp_list
->count
== 0
220 && pnc
->upstream_hash
->count
== 0) {
221 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
222 ZEBRA_NEXTHOP_UNREGISTER
);
224 list_delete(&pnc
->rp_list
);
225 hash_free(pnc
->upstream_hash
);
227 hash_release(pim
->rpf_hash
, pnc
);
229 nexthops_free(pnc
->nexthop
);
230 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
235 void pim_rp_nexthop_del(struct rp_info
*rp_info
)
237 rp_info
->rp
.source_nexthop
.interface
= NULL
;
238 rp_info
->rp
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
240 rp_info
->rp
.source_nexthop
.mrib_metric_preference
=
241 router
->infinite_assert_metric
.metric_preference
;
242 rp_info
->rp
.source_nexthop
.mrib_route_metric
=
243 router
->infinite_assert_metric
.route_metric
;
246 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
247 static void pim_update_rp_nh(struct pim_instance
*pim
,
248 struct pim_nexthop_cache
*pnc
)
250 struct listnode
*node
= NULL
;
251 struct rp_info
*rp_info
= NULL
;
253 /*Traverse RP list and update each RP Nexthop info */
254 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
255 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
258 // Compute PIM RPF using cached nexthop
259 if (!pim_ecmp_nexthop_search(pim
, pnc
,
260 &rp_info
->rp
.source_nexthop
,
261 &rp_info
->rp
.rpf_addr
, &rp_info
->group
,
263 pim_rp_nexthop_del(rp_info
);
267 /* This API is used to traverse nexthop cache of RPF addr
268 of upstream entry whose IPv4 nexthop address is in
269 unresolved state and due to event like pim neighbor
270 UP event if it can be resolved.
272 void pim_resolve_upstream_nh(struct pim_instance
*pim
, struct prefix
*nht_p
)
274 struct nexthop
*nh_node
= NULL
;
275 struct pim_nexthop_cache pnc
;
276 struct pim_neighbor
*nbr
= NULL
;
278 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
279 if (!pim_find_or_track_nexthop(pim
, nht_p
, NULL
, NULL
, &pnc
))
282 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
283 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
286 struct interface
*ifp1
=
287 if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
288 nbr
= pim_neighbor_find_if(ifp1
);
292 nh_node
->gate
.ipv4
= nbr
->source_addr
;
293 if (PIM_DEBUG_PIM_NHT
) {
294 char str
[PREFIX_STRLEN
];
295 char str1
[INET_ADDRSTRLEN
];
296 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
, str1
,
298 pim_addr_dump("<nht_addr?>", nht_p
, str
, sizeof(str
));
300 "%s: addr %s new nexthop addr %s interface %s",
301 __PRETTY_FUNCTION__
, str
, str1
, ifp1
->name
);
306 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
307 static int pim_update_upstream_nh_helper(struct hash_bucket
*bucket
, void *arg
)
309 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
310 struct pim_upstream
*up
= (struct pim_upstream
*)bucket
->data
;
313 enum pim_rpf_result rpf_result
;
316 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
317 rpf_result
= pim_rpf_update(pim
, up
, &old
, 0);
318 if (rpf_result
== PIM_RPF_FAILURE
) {
319 pim_upstream_rpf_clear(pim
, up
);
320 return HASHWALK_CONTINUE
;
323 /* update kernel multicast forwarding cache (MFC) */
324 if (up
->rpf
.source_nexthop
.interface
) {
325 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
327 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
328 /* Pass Current selected NH vif index to mroute download
331 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
333 if (PIM_DEBUG_PIM_NHT
)
335 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
336 __PRETTY_FUNCTION__
, up
->sg_str
,
337 up
->rpf
.source_nexthop
.interface
->name
);
341 if (rpf_result
== PIM_RPF_CHANGED
)
342 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
345 if (PIM_DEBUG_PIM_NHT
) {
346 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
347 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
348 old
.source_nexthop
.interface
349 ? old
.source_nexthop
.interface
->name
: "Unknwon",
350 up
->rpf
.source_nexthop
.interface
->name
);
353 return HASHWALK_CONTINUE
;
356 static int pim_update_upstream_nh(struct pim_instance
*pim
,
357 struct pim_nexthop_cache
*pnc
)
359 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
361 pim_zebra_update_all_interfaces(pim
);
366 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
369 uint32_t s
= 0, g
= 0;
374 switch (src
->family
) {
376 s
= src
->u
.prefix4
.s_addr
;
379 g
= grp
->u
.prefix4
.s_addr
;
385 hash_val
= jhash_2words(g
, s
, 101);
389 int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
390 struct pim_nexthop_cache
*pnc
,
391 struct pim_nexthop
*nexthop
, struct prefix
*src
,
392 struct prefix
*grp
, int neighbor_needed
)
394 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
395 struct interface
*ifps
[MULTIPATH_NUM
];
396 struct nexthop
*nh_node
= NULL
;
397 ifindex_t first_ifindex
;
398 struct interface
*ifp
= NULL
;
399 uint32_t hash_val
= 0, mod_val
= 0;
400 uint8_t nh_iter
= 0, found
= 0;
401 uint32_t i
, num_nbrs
= 0;
403 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
406 memset(&nbrs
, 0, sizeof(nbrs
));
407 memset(&ifps
, 0, sizeof(ifps
));
409 // Current Nexthop is VALID, check to stay on the current path.
410 if (nexthop
->interface
&& nexthop
->interface
->info
411 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
412 != PIM_NET_INADDR_ANY
) {
413 /* User configured knob to explicitly switch
414 to new path is disabled or current path
415 metric is less than nexthop update.
418 if (pim
->ecmp_rebalance_enable
== 0) {
419 uint8_t curr_route_valid
= 0;
420 // Check if current nexthop is present in new updated
422 // If the current nexthop is not valid, candidate to
423 // choose new Nexthop.
424 for (nh_node
= pnc
->nexthop
; nh_node
;
425 nh_node
= nh_node
->next
) {
426 curr_route_valid
= (nexthop
->interface
->ifindex
427 == nh_node
->ifindex
);
428 if (curr_route_valid
)
433 && !pim_if_connected_to_source(nexthop
->interface
,
435 nbr
= pim_neighbor_find(
437 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
439 && !if_is_loopback(nexthop
->interface
)) {
440 if (PIM_DEBUG_PIM_NHT
)
442 "%s: current nexthop does not have nbr ",
443 __PRETTY_FUNCTION__
);
445 if (PIM_DEBUG_PIM_NHT
) {
446 char src_str
[INET_ADDRSTRLEN
];
447 pim_inet4_dump("<addr?>",
451 char grp_str
[INET_ADDRSTRLEN
];
452 pim_inet4_dump("<addr?>",
457 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
461 nexthop
->interface
->name
);
470 * Look up all interfaces and neighbors,
471 * store for later usage
473 for (nh_node
= pnc
->nexthop
, i
= 0; nh_node
;
474 nh_node
= nh_node
->next
, i
++) {
475 ifps
[i
] = if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
477 nbrs
[i
] = pim_neighbor_find(ifps
[i
],
479 if (nbrs
[i
] || pim_if_connected_to_source(ifps
[i
],
485 if (pim
->ecmp_enable
) {
486 uint32_t consider
= pnc
->nexthop_num
;
488 if (neighbor_needed
&& num_nbrs
< consider
)
494 // PIM ECMP flag is enable then choose ECMP path.
495 hash_val
= pim_compute_ecmp_hash(src
, grp
);
496 mod_val
= hash_val
% consider
;
499 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
500 nh_node
= nh_node
->next
) {
501 first_ifindex
= nh_node
->ifindex
;
504 if (PIM_DEBUG_PIM_NHT
) {
505 char addr_str
[INET_ADDRSTRLEN
];
506 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
507 addr_str
, sizeof(addr_str
));
509 "%s %s: could not find interface for ifindex %d (address %s(%s))",
510 __FILE__
, __PRETTY_FUNCTION__
,
511 first_ifindex
, addr_str
,
514 if (nh_iter
== mod_val
)
515 mod_val
++; // Select nexthpath
520 if (PIM_DEBUG_PIM_NHT
) {
521 char addr_str
[INET_ADDRSTRLEN
];
522 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
523 addr_str
, sizeof(addr_str
));
525 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
526 __PRETTY_FUNCTION__
, ifp
->name
,
527 pim
->vrf
->name
, first_ifindex
,
530 if (nh_iter
== mod_val
)
531 mod_val
++; // Select nexthpath
537 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
539 if (!nbr
&& !if_is_loopback(ifp
)) {
540 if (PIM_DEBUG_PIM_NHT
)
542 "%s: pim nbr not found on input interface %s(%s)",
543 __PRETTY_FUNCTION__
, ifp
->name
,
545 if (nh_iter
== mod_val
)
546 mod_val
++; // Select nexthpath
552 if (nh_iter
== mod_val
) {
553 nexthop
->interface
= ifp
;
554 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
555 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
556 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
558 nexthop
->mrib_metric_preference
= pnc
->distance
;
559 nexthop
->mrib_route_metric
= pnc
->metric
;
560 nexthop
->last_lookup
= src
->u
.prefix4
;
561 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
564 if (PIM_DEBUG_PIM_NHT
) {
565 char buf
[INET_ADDRSTRLEN
];
566 char buf2
[INET_ADDRSTRLEN
];
567 char buf3
[INET_ADDRSTRLEN
];
568 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
570 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
574 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
577 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
578 __PRETTY_FUNCTION__
, buf2
, buf3
,
579 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
580 nh_iter
, pim
->ecmp_enable
);
592 /* This API is used to parse Registered address nexthop update coming from Zebra
594 int pim_parse_nexthop_update(int command
, struct zclient
*zclient
,
595 zebra_size_t length
, vrf_id_t vrf_id
)
597 struct nexthop
*nexthop
;
598 struct nexthop
*nhlist_head
= NULL
;
599 struct nexthop
*nhlist_tail
= NULL
;
602 struct pim_nexthop_cache
*pnc
= NULL
;
603 struct pim_neighbor
*nbr
= NULL
;
604 struct interface
*ifp
= NULL
;
605 struct interface
*ifp1
= NULL
;
606 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
607 struct pim_instance
*pim
;
608 struct zapi_route nhr
;
614 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
615 if (PIM_DEBUG_PIM_NHT
)
617 "%s: Decode of nexthop update from zebra failed",
618 __PRETTY_FUNCTION__
);
622 if (command
== ZEBRA_NEXTHOP_UPDATE
) {
623 prefix_copy(&rpf
.rpf_addr
, &nhr
.prefix
);
624 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
626 if (PIM_DEBUG_PIM_NHT
) {
627 char buf
[PREFIX2STR_BUFFER
];
628 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
630 "%s: Skipping NHT update, addr %s is not in local cached DB.",
631 __PRETTY_FUNCTION__
, buf
);
637 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
642 pnc
->last_update
= pim_time_monotonic_usec();
644 if (nhr
.nexthop_num
) {
645 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
647 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
648 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
649 switch (nexthop
->type
) {
650 case NEXTHOP_TYPE_IPV4
:
651 case NEXTHOP_TYPE_IPV4_IFINDEX
:
652 case NEXTHOP_TYPE_IPV6
:
653 case NEXTHOP_TYPE_BLACKHOLE
:
655 case NEXTHOP_TYPE_IFINDEX
:
657 * Connected route (i.e. no nexthop), use
658 * RPF address from nexthop cache (i.e.
659 * destination) as PIM nexthop.
661 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
663 pnc
->rpf
.rpf_addr
.u
.prefix4
;
665 case NEXTHOP_TYPE_IPV6_IFINDEX
:
666 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
668 nbr
= pim_neighbor_find_if(ifp1
);
669 /* Overwrite with Nbr address as NH addr */
671 nexthop
->gate
.ipv4
= nbr
->source_addr
;
673 // Mark nexthop address to 0 until PIM
675 nexthop
->gate
.ipv4
.s_addr
=
682 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
684 if (PIM_DEBUG_PIM_NHT
) {
685 char buf
[NEXTHOP_STRLEN
];
687 "%s: could not find interface for ifindex %d(%s) (addr %s)",
691 nexthop2str(nexthop
, buf
,
694 nexthop_free(nexthop
);
698 if (PIM_DEBUG_PIM_NHT
) {
699 char p_str
[PREFIX2STR_BUFFER
];
701 prefix2str(&nhr
.prefix
, p_str
, sizeof(p_str
));
703 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
704 __PRETTY_FUNCTION__
, p_str
,
705 pim
->vrf
->name
, i
+ 1,
706 inet_ntoa(nexthop
->gate
.ipv4
),
707 ifp
->name
, nexthop
->type
, nhr
.distance
,
712 if (PIM_DEBUG_PIM_NHT
) {
713 char buf
[NEXTHOP_STRLEN
];
716 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
717 __PRETTY_FUNCTION__
, ifp
->name
,
720 nexthop2str(nexthop
, buf
,
723 nexthop_free(nexthop
);
728 nhlist_tail
->next
= nexthop
;
729 nhlist_tail
= nexthop
;
731 nhlist_tail
= nexthop
;
732 nhlist_head
= nexthop
;
734 // Only keep track of nexthops which are PIM enabled.
737 /* Reset existing pnc->nexthop before assigning new list */
738 nexthops_free(pnc
->nexthop
);
739 pnc
->nexthop
= nhlist_head
;
740 if (pnc
->nexthop_num
) {
741 pnc
->flags
|= PIM_NEXTHOP_VALID
;
742 pnc
->distance
= nhr
.distance
;
743 pnc
->metric
= nhr
.metric
;
746 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
747 pnc
->nexthop_num
= nhr
.nexthop_num
;
748 nexthops_free(pnc
->nexthop
);
752 if (PIM_DEBUG_PIM_NHT
) {
753 char buf
[PREFIX2STR_BUFFER
];
754 prefix2str(&nhr
.prefix
, buf
, sizeof(buf
));
756 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
757 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
758 nhr
.nexthop_num
, pnc
->nexthop_num
, vrf_id
,
759 pnc
->upstream_hash
->count
, listcount(pnc
->rp_list
));
762 pim_rpf_set_refresh_time(pim
);
764 if (listcount(pnc
->rp_list
))
765 pim_update_rp_nh(pim
, pnc
);
766 if (pnc
->upstream_hash
->count
)
767 pim_update_upstream_nh(pim
, pnc
);
772 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
773 struct pim_nexthop
*nexthop
, struct prefix
*src
,
774 struct prefix
*grp
, int neighbor_needed
)
776 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
777 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
779 struct interface
*ifps
[MULTIPATH_NUM
], *ifp
;
783 uint32_t hash_val
= 0, mod_val
= 0;
784 uint32_t num_nbrs
= 0;
785 char addr_str
[PREFIX_STRLEN
];
787 if (PIM_DEBUG_PIM_NHT
) {
788 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
790 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
791 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
792 nexthop
->last_lookup_time
);
795 memset(nexthop_tab
, 0,
796 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
798 zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
799 src
->u
.prefix4
, PIM_NEXTHOP_LOOKUP_MAX
);
800 if (num_ifindex
< 1) {
801 if (PIM_DEBUG_PIM_NHT
)
803 "%s: could not find nexthop ifindex for address %s(%s)",
804 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
808 memset(&nbrs
, 0, sizeof(nbrs
));
809 memset(&ifps
, 0, sizeof(ifps
));
812 * Look up all interfaces and neighbors,
813 * store for later usage
815 for (i
= 0; i
< num_ifindex
; i
++) {
816 ifps
[i
] = if_lookup_by_index(nexthop_tab
[i
].ifindex
,
819 nbrs
[i
] = pim_neighbor_find(
820 ifps
[i
], nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
822 || pim_if_connected_to_source(ifps
[i
],
828 // If PIM ECMP enable then choose ECMP path.
829 if (pim
->ecmp_enable
) {
830 uint32_t consider
= num_ifindex
;
832 if (neighbor_needed
&& num_nbrs
< consider
)
838 hash_val
= pim_compute_ecmp_hash(src
, grp
);
839 mod_val
= hash_val
% consider
;
840 if (PIM_DEBUG_PIM_NHT_DETAIL
)
841 zlog_debug("%s: hash_val %u mod_val %u",
842 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
846 while (!found
&& (i
< num_ifindex
)) {
847 first_ifindex
= nexthop_tab
[i
].ifindex
;
851 if (PIM_DEBUG_PIM_NHT
)
853 "%s %s: could not find interface for ifindex %d (address %s(%s))",
854 __FILE__
, __PRETTY_FUNCTION__
,
855 first_ifindex
, addr_str
,
864 if (PIM_DEBUG_PIM_NHT
)
866 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
867 __PRETTY_FUNCTION__
, ifp
->name
,
868 pim
->vrf
->name
, first_ifindex
,
876 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
878 if (PIM_DEBUG_PIM_NHT_DETAIL
)
879 zlog_debug("ifp name: %s(%s), pim nbr: %p",
880 ifp
->name
, pim
->vrf
->name
, nbr
);
881 if (!nbr
&& !if_is_loopback(ifp
)) {
885 if (PIM_DEBUG_PIM_NHT
)
887 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
888 __PRETTY_FUNCTION__
, ifp
->name
,
889 pim
->vrf
->name
, addr_str
);
895 if (PIM_DEBUG_PIM_NHT
) {
896 char nexthop_str
[PREFIX_STRLEN
];
898 pim_addr_dump("<nexthop?>",
899 &nexthop_tab
[i
].nexthop_addr
,
900 nexthop_str
, sizeof(nexthop_str
));
902 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
903 __PRETTY_FUNCTION__
, nexthop_str
,
904 addr_str
, ifp
->name
, pim
->vrf
->name
,
905 nexthop_tab
[i
].route_metric
,
906 nexthop_tab
[i
].protocol_distance
);
908 /* update nexthop data */
909 nexthop
->interface
= ifp
;
910 nexthop
->mrib_nexthop_addr
=
911 nexthop_tab
[i
].nexthop_addr
;
912 nexthop
->mrib_metric_preference
=
913 nexthop_tab
[i
].protocol_distance
;
914 nexthop
->mrib_route_metric
=
915 nexthop_tab
[i
].route_metric
;
916 nexthop
->last_lookup
= src
->u
.prefix4
;
917 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
930 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
931 struct prefix
*src
, struct prefix
*grp
)
933 struct pim_nexthop nhop
;
936 char addr_str
[PREFIX_STRLEN
];
938 if (PIM_DEBUG_PIM_NHT
)
939 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
941 if (!pim_ecmp_nexthop_lookup(pim
, &nhop
, src
, grp
, 0)) {
942 if (PIM_DEBUG_PIM_NHT
)
944 "%s: could not find nexthop ifindex for address %s(%s)",
945 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
949 ifindex
= nhop
.interface
->ifindex
;
950 if (PIM_DEBUG_PIM_NHT
)
952 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
953 __PRETTY_FUNCTION__
, ifindex
,
954 ifindex2ifname(ifindex
, pim
->vrf_id
),
955 pim
->vrf
->name
, addr_str
);
957 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
960 if (PIM_DEBUG_PIM_NHT
) {
962 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
963 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,