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 bool bsr_track_needed
,
125 struct pim_nexthop_cache
*out_pnc
)
127 struct pim_nexthop_cache
*pnc
= NULL
;
129 struct listnode
*ch_node
= NULL
;
130 struct zclient
*zclient
= NULL
;
132 zclient
= pim_zebra_zclient_get();
133 memset(&rpf
, 0, sizeof(struct pim_rpf
));
134 rpf
.rpf_addr
.family
= addr
->family
;
135 rpf
.rpf_addr
.prefixlen
= addr
->prefixlen
;
136 rpf
.rpf_addr
.u
.prefix4
= addr
->u
.prefix4
;
138 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
140 pnc
= pim_nexthop_cache_add(pim
, &rpf
);
141 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
142 ZEBRA_NEXTHOP_REGISTER
);
143 if (PIM_DEBUG_PIM_NHT
) {
144 char buf
[PREFIX2STR_BUFFER
];
145 prefix2str(addr
, buf
, sizeof(buf
));
147 "%s: NHT cache and zebra notification added for %s(%s)",
148 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
);
153 ch_node
= listnode_lookup(pnc
->rp_list
, rp
);
155 listnode_add_sort(pnc
->rp_list
, rp
);
159 hash_get(pnc
->upstream_hash
, up
, hash_alloc_intern
);
161 if (bsr_track_needed
)
162 pnc
->bsr_tracking
= true;
164 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_VALID
)) {
166 memcpy(out_pnc
, pnc
, sizeof(struct pim_nexthop_cache
));
173 void pim_delete_tracked_nexthop(struct pim_instance
*pim
, struct prefix
*addr
,
174 struct pim_upstream
*up
, struct rp_info
*rp
,
175 bool del_bsr_tracking
)
177 struct pim_nexthop_cache
*pnc
= NULL
;
178 struct pim_nexthop_cache lookup
;
179 struct zclient
*zclient
= NULL
;
180 struct listnode
*upnode
= NULL
;
181 struct pim_upstream
*upstream
= NULL
;
183 zclient
= pim_zebra_zclient_get();
185 /* Remove from RPF hash if it is the last entry */
186 lookup
.rpf
.rpf_addr
= *addr
;
187 pnc
= hash_lookup(pim
->rpf_hash
, &lookup
);
190 /* Release the (*, G)upstream from pnc->upstream_hash,
191 * whose Group belongs to the RP getting deleted
193 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
,
196 struct rp_info
*trp_info
;
198 if (upstream
->sg
.src
.s_addr
!= INADDR_ANY
)
201 grp
.family
= AF_INET
;
202 grp
.prefixlen
= IPV4_MAX_BITLEN
;
203 grp
.u
.prefix4
= upstream
->sg
.grp
;
205 trp_info
= pim_rp_find_match_group(pim
, &grp
);
207 hash_release(pnc
->upstream_hash
,
210 listnode_delete(pnc
->rp_list
, rp
);
214 hash_release(pnc
->upstream_hash
, up
);
216 if (del_bsr_tracking
)
217 pnc
->bsr_tracking
= false;
219 if (PIM_DEBUG_PIM_NHT
) {
220 char buf
[PREFIX_STRLEN
];
221 prefix2str(addr
, buf
, sizeof buf
);
223 "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
224 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
225 pnc
->rp_list
->count
, pnc
->upstream_hash
->count
);
228 if (pnc
->rp_list
->count
== 0
229 && pnc
->upstream_hash
->count
== 0
230 && pnc
->bsr_tracking
== false) {
231 pim_sendmsg_zebra_rnh(pim
, zclient
, pnc
,
232 ZEBRA_NEXTHOP_UNREGISTER
);
234 list_delete(&pnc
->rp_list
);
235 hash_free(pnc
->upstream_hash
);
237 hash_release(pim
->rpf_hash
, pnc
);
239 nexthops_free(pnc
->nexthop
);
240 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
245 /* Given a source address and a neighbor address, check if the neighbor is one
246 * of the next hop to reach the source. search from zebra route database
248 bool pim_nexthop_match(struct pim_instance
*pim
, struct in_addr addr
,
249 struct in_addr ip_src
)
251 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
253 ifindex_t first_ifindex
= 0;
254 struct interface
*ifp
= NULL
;
255 struct pim_neighbor
*nbr
= NULL
;
258 if (addr
.s_addr
== INADDR_NONE
)
261 memset(nexthop_tab
, 0,
262 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
263 num_ifindex
= zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
264 addr
, PIM_NEXTHOP_LOOKUP_MAX
);
265 if (num_ifindex
< 1) {
266 char addr_str
[INET_ADDRSTRLEN
];
268 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
270 "%s %s: could not find nexthop ifindex for address %s",
271 __FILE__
, __PRETTY_FUNCTION__
, addr_str
);
275 while (i
< num_ifindex
) {
276 first_ifindex
= nexthop_tab
[i
].ifindex
;
278 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
280 if (PIM_DEBUG_ZEBRA
) {
281 char addr_str
[INET_ADDRSTRLEN
];
283 pim_inet4_dump("<addr?>", addr
, addr_str
,
286 "%s %s: could not find interface for ifindex %d (address %s)",
287 __FILE__
, __PRETTY_FUNCTION__
,
288 first_ifindex
, addr_str
);
295 if (PIM_DEBUG_ZEBRA
) {
296 char addr_str
[INET_ADDRSTRLEN
];
298 pim_inet4_dump("<addr?>", addr
, addr_str
,
301 "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
302 __PRETTY_FUNCTION__
, ifp
->name
,
303 first_ifindex
, addr_str
);
309 if (!pim_if_connected_to_source(ifp
, addr
)) {
310 nbr
= pim_neighbor_find(
311 ifp
, nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
312 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
313 zlog_debug("ifp name: %s, pim nbr: %p",
315 if (!nbr
&& !if_is_loopback(ifp
)) {
321 if (nexthop_tab
[i
].nexthop_addr
.u
.prefix4
.s_addr
331 /* Given a source address and a neighbor address, check if the neighbor is one
332 * of the next hop to reach the source. search from pim next hop cache
334 bool pim_nexthop_match_nht_cache(struct pim_instance
*pim
, struct in_addr addr
,
335 struct in_addr ip_src
)
338 ifindex_t first_ifindex
;
339 struct interface
*ifp
= NULL
;
341 struct pim_neighbor
*nbr
= NULL
;
342 struct nexthop
*nh_node
= NULL
;
343 struct pim_nexthop_cache
*pnc
= NULL
;
345 memset(&rpf
, 0, sizeof(struct pim_rpf
));
346 rpf
.rpf_addr
.family
= AF_INET
;
347 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
348 rpf
.rpf_addr
.u
.prefix4
= addr
;
350 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
351 if (!pnc
|| !pnc
->nexthop_num
)
354 for (nh_node
= pnc
->nexthop
; nh_node
; nh_node
= nh_node
->next
) {
355 first_ifindex
= nh_node
->ifindex
;
356 ifp
= if_lookup_by_index(first_ifindex
, pim
->vrf_id
);
358 if (PIM_DEBUG_PIM_NHT
) {
359 char addr_str
[INET_ADDRSTRLEN
];
361 pim_inet4_dump("<addr?>", addr
, addr_str
,
364 "%s %s: could not find interface for ifindex %d (address %s(%s))",
365 __FILE__
, __PRETTY_FUNCTION__
,
366 first_ifindex
, addr_str
,
373 if (PIM_DEBUG_PIM_NHT
) {
374 char addr_str
[INET_ADDRSTRLEN
];
376 pim_inet4_dump("<addr?>", addr
, addr_str
,
379 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
380 __PRETTY_FUNCTION__
, ifp
->name
,
381 pim
->vrf
->name
, first_ifindex
,
388 if (!pim_if_connected_to_source(ifp
, addr
)) {
389 nbr
= pim_neighbor_find(ifp
, nh_node
->gate
.ipv4
);
390 if (!nbr
&& !if_is_loopback(ifp
)) {
391 if (PIM_DEBUG_PIM_NHT
)
393 "%s: pim nbr not found on input interface %s(%s)",
394 __PRETTY_FUNCTION__
, ifp
->name
,
401 if (nh_node
->gate
.ipv4
.s_addr
== ip_src
.s_addr
)
408 void pim_rp_nexthop_del(struct rp_info
*rp_info
)
410 rp_info
->rp
.source_nexthop
.interface
= NULL
;
411 rp_info
->rp
.source_nexthop
.mrib_nexthop_addr
.u
.prefix4
.s_addr
=
413 rp_info
->rp
.source_nexthop
.mrib_metric_preference
=
414 router
->infinite_assert_metric
.metric_preference
;
415 rp_info
->rp
.source_nexthop
.mrib_route_metric
=
416 router
->infinite_assert_metric
.route_metric
;
419 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
420 static void pim_update_rp_nh(struct pim_instance
*pim
,
421 struct pim_nexthop_cache
*pnc
)
423 struct listnode
*node
= NULL
;
424 struct rp_info
*rp_info
= NULL
;
426 /*Traverse RP list and update each RP Nexthop info */
427 for (ALL_LIST_ELEMENTS_RO(pnc
->rp_list
, node
, rp_info
)) {
428 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
431 // Compute PIM RPF using cached nexthop
432 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
433 &rp_info
->rp
.rpf_addr
,
435 pim_rp_nexthop_del(rp_info
);
439 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
440 static int pim_update_upstream_nh_helper(struct hash_bucket
*bucket
, void *arg
)
442 struct pim_instance
*pim
= (struct pim_instance
*)arg
;
443 struct pim_upstream
*up
= (struct pim_upstream
*)bucket
->data
;
446 enum pim_rpf_result rpf_result
;
449 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
450 rpf_result
= pim_rpf_update(pim
, up
, &old
);
451 if (rpf_result
== PIM_RPF_FAILURE
) {
452 pim_upstream_rpf_clear(pim
, up
);
453 return HASHWALK_CONTINUE
;
456 /* update kernel multicast forwarding cache (MFC) */
457 if (up
->rpf
.source_nexthop
.interface
) {
458 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
460 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
461 /* Pass Current selected NH vif index to mroute download
464 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
466 if (PIM_DEBUG_PIM_NHT
)
468 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
469 __PRETTY_FUNCTION__
, up
->sg_str
,
470 up
->rpf
.source_nexthop
.interface
->name
);
474 if (rpf_result
== PIM_RPF_CHANGED
)
475 pim_zebra_upstream_rpf_changed(pim
, up
, &old
);
478 if (PIM_DEBUG_PIM_NHT
) {
479 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
480 __PRETTY_FUNCTION__
, up
->sg_str
, pim
->vrf
->name
,
481 old
.source_nexthop
.interface
482 ? old
.source_nexthop
.interface
->name
: "Unknwon",
483 up
->rpf
.source_nexthop
.interface
->name
);
486 return HASHWALK_CONTINUE
;
489 static int pim_update_upstream_nh(struct pim_instance
*pim
,
490 struct pim_nexthop_cache
*pnc
)
492 hash_walk(pnc
->upstream_hash
, pim_update_upstream_nh_helper
, pim
);
494 pim_zebra_update_all_interfaces(pim
);
499 uint32_t pim_compute_ecmp_hash(struct prefix
*src
, struct prefix
*grp
)
502 uint32_t s
= 0, g
= 0;
507 switch (src
->family
) {
509 s
= src
->u
.prefix4
.s_addr
;
512 g
= grp
->u
.prefix4
.s_addr
;
518 hash_val
= jhash_2words(g
, s
, 101);
522 static int pim_ecmp_nexthop_search(struct pim_instance
*pim
,
523 struct pim_nexthop_cache
*pnc
,
524 struct pim_nexthop
*nexthop
,
525 struct prefix
*src
, struct prefix
*grp
,
528 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
529 struct interface
*ifps
[MULTIPATH_NUM
];
530 struct nexthop
*nh_node
= NULL
;
531 ifindex_t first_ifindex
;
532 struct interface
*ifp
= NULL
;
533 uint32_t hash_val
= 0, mod_val
= 0;
534 uint8_t nh_iter
= 0, found
= 0;
535 uint32_t i
, num_nbrs
= 0;
537 if (!pnc
|| !pnc
->nexthop_num
|| !nexthop
)
540 memset(&nbrs
, 0, sizeof(nbrs
));
541 memset(&ifps
, 0, sizeof(ifps
));
543 // Current Nexthop is VALID, check to stay on the current path.
544 if (nexthop
->interface
&& nexthop
->interface
->info
545 && nexthop
->mrib_nexthop_addr
.u
.prefix4
.s_addr
546 != PIM_NET_INADDR_ANY
) {
547 /* User configured knob to explicitly switch
548 to new path is disabled or current path
549 metric is less than nexthop update.
552 if (pim
->ecmp_rebalance_enable
== 0) {
553 uint8_t curr_route_valid
= 0;
554 // Check if current nexthop is present in new updated
556 // If the current nexthop is not valid, candidate to
557 // choose new Nexthop.
558 for (nh_node
= pnc
->nexthop
; nh_node
;
559 nh_node
= nh_node
->next
) {
560 curr_route_valid
= (nexthop
->interface
->ifindex
561 == nh_node
->ifindex
);
562 if (curr_route_valid
)
567 && !pim_if_connected_to_source(nexthop
->interface
,
569 nbr
= pim_neighbor_find(
571 nexthop
->mrib_nexthop_addr
.u
.prefix4
);
573 && !if_is_loopback(nexthop
->interface
)) {
574 if (PIM_DEBUG_PIM_NHT
)
576 "%s: current nexthop does not have nbr ",
577 __PRETTY_FUNCTION__
);
579 if (PIM_DEBUG_PIM_NHT
) {
580 char src_str
[INET_ADDRSTRLEN
];
581 pim_inet4_dump("<addr?>",
585 char grp_str
[INET_ADDRSTRLEN
];
586 pim_inet4_dump("<addr?>",
591 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
595 nexthop
->interface
->name
);
604 * Look up all interfaces and neighbors,
605 * store for later usage
607 for (nh_node
= pnc
->nexthop
, i
= 0; nh_node
;
608 nh_node
= nh_node
->next
, i
++) {
609 ifps
[i
] = if_lookup_by_index(nh_node
->ifindex
, pim
->vrf_id
);
611 nbrs
[i
] = pim_neighbor_find(ifps
[i
],
613 if (nbrs
[i
] || pim_if_connected_to_source(ifps
[i
],
619 if (pim
->ecmp_enable
) {
620 uint32_t consider
= pnc
->nexthop_num
;
622 if (neighbor_needed
&& num_nbrs
< consider
)
628 // PIM ECMP flag is enable then choose ECMP path.
629 hash_val
= pim_compute_ecmp_hash(src
, grp
);
630 mod_val
= hash_val
% consider
;
633 for (nh_node
= pnc
->nexthop
; nh_node
&& (found
== 0);
634 nh_node
= nh_node
->next
) {
635 first_ifindex
= nh_node
->ifindex
;
638 if (PIM_DEBUG_PIM_NHT
) {
639 char addr_str
[INET_ADDRSTRLEN
];
640 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
641 addr_str
, sizeof(addr_str
));
643 "%s %s: could not find interface for ifindex %d (address %s(%s))",
644 __FILE__
, __PRETTY_FUNCTION__
,
645 first_ifindex
, addr_str
,
648 if (nh_iter
== mod_val
)
649 mod_val
++; // Select nexthpath
654 if (PIM_DEBUG_PIM_NHT
) {
655 char addr_str
[INET_ADDRSTRLEN
];
656 pim_inet4_dump("<addr?>", src
->u
.prefix4
,
657 addr_str
, sizeof(addr_str
));
659 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
660 __PRETTY_FUNCTION__
, ifp
->name
,
661 pim
->vrf
->name
, first_ifindex
,
664 if (nh_iter
== mod_val
)
665 mod_val
++; // Select nexthpath
671 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
673 if (!nbr
&& !if_is_loopback(ifp
)) {
674 if (PIM_DEBUG_PIM_NHT
)
676 "%s: pim nbr not found on input interface %s(%s)",
677 __PRETTY_FUNCTION__
, ifp
->name
,
679 if (nh_iter
== mod_val
)
680 mod_val
++; // Select nexthpath
686 if (nh_iter
== mod_val
) {
687 nexthop
->interface
= ifp
;
688 nexthop
->mrib_nexthop_addr
.family
= AF_INET
;
689 nexthop
->mrib_nexthop_addr
.prefixlen
= IPV4_MAX_BITLEN
;
690 nexthop
->mrib_nexthop_addr
.u
.prefix4
=
692 nexthop
->mrib_metric_preference
= pnc
->distance
;
693 nexthop
->mrib_route_metric
= pnc
->metric
;
694 nexthop
->last_lookup
= src
->u
.prefix4
;
695 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
698 if (PIM_DEBUG_PIM_NHT
) {
699 char buf
[INET_ADDRSTRLEN
];
700 char buf2
[INET_ADDRSTRLEN
];
701 char buf3
[INET_ADDRSTRLEN
];
702 pim_inet4_dump("<src?>", src
->u
.prefix4
, buf2
,
704 pim_inet4_dump("<grp?>", grp
->u
.prefix4
, buf3
,
708 nexthop
->mrib_nexthop_addr
.u
.prefix4
,
711 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
712 __PRETTY_FUNCTION__
, buf2
, buf3
,
713 pim
->vrf
->name
, ifp
->name
, buf
, mod_val
,
714 nh_iter
, pim
->ecmp_enable
);
726 /* This API is used to parse Registered address nexthop update coming from Zebra
728 int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS
)
730 struct nexthop
*nexthop
;
731 struct nexthop
*nhlist_head
= NULL
;
732 struct nexthop
*nhlist_tail
= NULL
;
735 struct pim_nexthop_cache
*pnc
= NULL
;
736 struct pim_neighbor
*nbr
= NULL
;
737 struct interface
*ifp
= NULL
;
738 struct interface
*ifp1
= NULL
;
739 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
740 struct pim_instance
*pim
;
741 struct zapi_route nhr
;
747 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
748 if (PIM_DEBUG_PIM_NHT
)
750 "%s: Decode of nexthop update from zebra failed",
751 __PRETTY_FUNCTION__
);
755 if (cmd
== ZEBRA_NEXTHOP_UPDATE
) {
756 prefix_copy(&rpf
.rpf_addr
, &nhr
.prefix
);
757 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
759 if (PIM_DEBUG_PIM_NHT
) {
760 char buf
[PREFIX2STR_BUFFER
];
761 prefix2str(&rpf
.rpf_addr
, buf
, sizeof(buf
));
763 "%s: Skipping NHT update, addr %s is not in local cached DB.",
764 __PRETTY_FUNCTION__
, buf
);
770 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
775 pnc
->last_update
= pim_time_monotonic_usec();
777 if (nhr
.nexthop_num
) {
778 pnc
->nexthop_num
= 0; // Only increment for pim enabled rpf.
780 for (i
= 0; i
< nhr
.nexthop_num
; i
++) {
781 nexthop
= nexthop_from_zapi_nexthop(&nhr
.nexthops
[i
]);
782 switch (nexthop
->type
) {
783 case NEXTHOP_TYPE_IPV4
:
784 case NEXTHOP_TYPE_IPV4_IFINDEX
:
785 case NEXTHOP_TYPE_IPV6
:
786 case NEXTHOP_TYPE_BLACKHOLE
:
788 case NEXTHOP_TYPE_IFINDEX
:
790 * Connected route (i.e. no nexthop), use
791 * RPF address from nexthop cache (i.e.
792 * destination) as PIM nexthop.
794 nexthop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
796 pnc
->rpf
.rpf_addr
.u
.prefix4
;
798 case NEXTHOP_TYPE_IPV6_IFINDEX
:
799 ifp1
= if_lookup_by_index(nexthop
->ifindex
,
801 nbr
= pim_neighbor_find_if(ifp1
);
802 /* Overwrite with Nbr address as NH addr */
804 nexthop
->gate
.ipv4
= nbr
->source_addr
;
806 // Mark nexthop address to 0 until PIM
808 nexthop
->gate
.ipv4
.s_addr
=
815 ifp
= if_lookup_by_index(nexthop
->ifindex
, pim
->vrf_id
);
817 if (PIM_DEBUG_PIM_NHT
) {
818 char buf
[NEXTHOP_STRLEN
];
820 "%s: could not find interface for ifindex %d(%s) (addr %s)",
824 nexthop2str(nexthop
, buf
,
827 nexthop_free(nexthop
);
831 if (PIM_DEBUG_PIM_NHT
) {
832 char p_str
[PREFIX2STR_BUFFER
];
834 prefix2str(&nhr
.prefix
, p_str
, sizeof(p_str
));
836 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
837 __PRETTY_FUNCTION__
, p_str
,
838 pim
->vrf
->name
, i
+ 1,
839 inet_ntoa(nexthop
->gate
.ipv4
),
840 ifp
->name
, nexthop
->type
, nhr
.distance
,
845 if (PIM_DEBUG_PIM_NHT
) {
846 char buf
[NEXTHOP_STRLEN
];
849 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
850 __PRETTY_FUNCTION__
, ifp
->name
,
853 nexthop2str(nexthop
, buf
,
856 nexthop_free(nexthop
);
861 nhlist_tail
->next
= nexthop
;
862 nhlist_tail
= nexthop
;
864 nhlist_tail
= nexthop
;
865 nhlist_head
= nexthop
;
867 // Only keep track of nexthops which are PIM enabled.
870 /* Reset existing pnc->nexthop before assigning new list */
871 nexthops_free(pnc
->nexthop
);
872 pnc
->nexthop
= nhlist_head
;
873 if (pnc
->nexthop_num
) {
874 pnc
->flags
|= PIM_NEXTHOP_VALID
;
875 pnc
->distance
= nhr
.distance
;
876 pnc
->metric
= nhr
.metric
;
879 pnc
->flags
&= ~PIM_NEXTHOP_VALID
;
880 pnc
->nexthop_num
= nhr
.nexthop_num
;
881 nexthops_free(pnc
->nexthop
);
884 SET_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
);
886 if (PIM_DEBUG_PIM_NHT
) {
887 char buf
[PREFIX2STR_BUFFER
];
888 prefix2str(&nhr
.prefix
, buf
, sizeof(buf
));
890 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
891 __PRETTY_FUNCTION__
, buf
, pim
->vrf
->name
,
892 nhr
.nexthop_num
, pnc
->nexthop_num
, vrf_id
,
893 pnc
->upstream_hash
->count
, listcount(pnc
->rp_list
));
896 pim_rpf_set_refresh_time(pim
);
898 if (listcount(pnc
->rp_list
))
899 pim_update_rp_nh(pim
, pnc
);
900 if (pnc
->upstream_hash
->count
)
901 pim_update_upstream_nh(pim
, pnc
);
906 int pim_ecmp_nexthop_lookup(struct pim_instance
*pim
,
907 struct pim_nexthop
*nexthop
, struct prefix
*src
,
908 struct prefix
*grp
, int neighbor_needed
)
910 struct pim_nexthop_cache
*pnc
;
911 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
912 struct pim_neighbor
*nbrs
[MULTIPATH_NUM
], *nbr
= NULL
;
915 struct interface
*ifps
[MULTIPATH_NUM
], *ifp
;
919 uint32_t hash_val
= 0, mod_val
= 0;
920 uint32_t num_nbrs
= 0;
921 char addr_str
[PREFIX_STRLEN
];
923 if (PIM_DEBUG_PIM_NHT
) {
924 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
926 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
927 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
,
928 nexthop
->last_lookup_time
);
931 memset(&rpf
, 0, sizeof(struct pim_rpf
));
932 rpf
.rpf_addr
.family
= AF_INET
;
933 rpf
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
934 rpf
.rpf_addr
.u
.prefix4
= src
->u
.prefix4
;
936 pnc
= pim_nexthop_cache_find(pim
, &rpf
);
938 if (CHECK_FLAG(pnc
->flags
, PIM_NEXTHOP_ANSWER_RECEIVED
))
939 return pim_ecmp_nexthop_search(pim
, pnc
, nexthop
, src
, grp
,
943 memset(nexthop_tab
, 0,
944 sizeof(struct pim_zlookup_nexthop
) * MULTIPATH_NUM
);
946 zclient_lookup_nexthop(pim
, nexthop_tab
, MULTIPATH_NUM
,
947 src
->u
.prefix4
, PIM_NEXTHOP_LOOKUP_MAX
);
948 if (num_ifindex
< 1) {
949 if (PIM_DEBUG_PIM_NHT
)
951 "%s: could not find nexthop ifindex for address %s(%s)",
952 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
956 memset(&nbrs
, 0, sizeof(nbrs
));
957 memset(&ifps
, 0, sizeof(ifps
));
960 * Look up all interfaces and neighbors,
961 * store for later usage
963 for (i
= 0; i
< num_ifindex
; i
++) {
964 ifps
[i
] = if_lookup_by_index(nexthop_tab
[i
].ifindex
,
967 nbrs
[i
] = pim_neighbor_find(
968 ifps
[i
], nexthop_tab
[i
].nexthop_addr
.u
.prefix4
);
970 || pim_if_connected_to_source(ifps
[i
],
976 // If PIM ECMP enable then choose ECMP path.
977 if (pim
->ecmp_enable
) {
978 uint32_t consider
= num_ifindex
;
980 if (neighbor_needed
&& num_nbrs
< consider
)
986 hash_val
= pim_compute_ecmp_hash(src
, grp
);
987 mod_val
= hash_val
% consider
;
988 if (PIM_DEBUG_PIM_NHT_DETAIL
)
989 zlog_debug("%s: hash_val %u mod_val %u",
990 __PRETTY_FUNCTION__
, hash_val
, mod_val
);
994 while (!found
&& (i
< num_ifindex
)) {
995 first_ifindex
= nexthop_tab
[i
].ifindex
;
999 if (PIM_DEBUG_PIM_NHT
)
1001 "%s %s: could not find interface for ifindex %d (address %s(%s))",
1002 __FILE__
, __PRETTY_FUNCTION__
,
1003 first_ifindex
, addr_str
,
1012 if (PIM_DEBUG_PIM_NHT
)
1014 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
1015 __PRETTY_FUNCTION__
, ifp
->name
,
1016 pim
->vrf
->name
, first_ifindex
,
1024 && !pim_if_connected_to_source(ifp
, src
->u
.prefix4
)) {
1026 if (PIM_DEBUG_PIM_NHT_DETAIL
)
1027 zlog_debug("ifp name: %s(%s), pim nbr: %p",
1028 ifp
->name
, pim
->vrf
->name
, nbr
);
1029 if (!nbr
&& !if_is_loopback(ifp
)) {
1033 if (PIM_DEBUG_PIM_NHT
)
1035 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
1036 __PRETTY_FUNCTION__
, ifp
->name
,
1037 pim
->vrf
->name
, addr_str
);
1043 if (PIM_DEBUG_PIM_NHT
) {
1044 char nexthop_str
[PREFIX_STRLEN
];
1046 pim_addr_dump("<nexthop?>",
1047 &nexthop_tab
[i
].nexthop_addr
,
1048 nexthop_str
, sizeof(nexthop_str
));
1050 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
1051 __PRETTY_FUNCTION__
, nexthop_str
,
1052 addr_str
, ifp
->name
, pim
->vrf
->name
,
1053 nexthop_tab
[i
].route_metric
,
1054 nexthop_tab
[i
].protocol_distance
);
1056 /* update nexthop data */
1057 nexthop
->interface
= ifp
;
1058 nexthop
->mrib_nexthop_addr
=
1059 nexthop_tab
[i
].nexthop_addr
;
1060 nexthop
->mrib_metric_preference
=
1061 nexthop_tab
[i
].protocol_distance
;
1062 nexthop
->mrib_route_metric
=
1063 nexthop_tab
[i
].route_metric
;
1064 nexthop
->last_lookup
= src
->u
.prefix4
;
1065 nexthop
->last_lookup_time
= pim_time_monotonic_usec();
1078 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance
*pim
,
1079 struct prefix
*src
, struct prefix
*grp
)
1081 struct pim_nexthop nhop
;
1084 char addr_str
[PREFIX_STRLEN
];
1086 if (PIM_DEBUG_PIM_NHT
)
1087 pim_inet4_dump("<addr?>", src
->u
.prefix4
, addr_str
,
1090 memset(&nhop
, 0, sizeof(nhop
));
1091 if (!pim_ecmp_nexthop_lookup(pim
, &nhop
, src
, grp
, 0)) {
1092 if (PIM_DEBUG_PIM_NHT
)
1094 "%s: could not find nexthop ifindex for address %s(%s)",
1095 __PRETTY_FUNCTION__
, addr_str
, pim
->vrf
->name
);
1099 ifindex
= nhop
.interface
->ifindex
;
1100 if (PIM_DEBUG_PIM_NHT
)
1102 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
1103 __PRETTY_FUNCTION__
, ifindex
,
1104 ifindex2ifname(ifindex
, pim
->vrf_id
),
1105 pim
->vrf
->name
, addr_str
);
1107 vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
1109 if (vif_index
< 0) {
1110 if (PIM_DEBUG_PIM_NHT
) {
1112 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
1113 __PRETTY_FUNCTION__
, vif_index
, pim
->vrf
->name
,