3 * Copyright (C) 2015 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
38 #include "pim_iface.h"
43 #include "pim_memory.h"
44 #include "pim_iface.h"
49 /* Cleanup pim->rpf_hash each node data */
50 void pim_rp_list_hash_clean(void *data
)
52 struct pim_nexthop_cache
*pnc
= (struct pim_nexthop_cache
*)data
;
54 list_delete_and_null(&pnc
->rp_list
);
56 hash_clean(pnc
->upstream_hash
, NULL
);
57 hash_free(pnc
->upstream_hash
);
58 pnc
->upstream_hash
= NULL
;
60 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
63 static void pim_rp_info_free(struct rp_info
*rp_info
)
66 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
68 XFREE(MTYPE_PIM_RP
, rp_info
);
71 int pim_rp_list_cmp(void *v1
, void *v2
)
73 struct rp_info
*rp1
= (struct rp_info
*)v1
;
74 struct rp_info
*rp2
= (struct rp_info
*)v2
;
77 * Sort by RP IP address
79 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
80 < rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
83 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
84 > rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
88 * Sort by group IP address
90 if (rp1
->group
.u
.prefix4
.s_addr
< rp2
->group
.u
.prefix4
.s_addr
)
93 if (rp1
->group
.u
.prefix4
.s_addr
> rp2
->group
.u
.prefix4
.s_addr
)
99 void pim_rp_init(struct pim_instance
*pim
)
101 struct rp_info
*rp_info
;
102 struct route_node
*rn
;
104 pim
->rp_list
= list_new();
105 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
106 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
108 pim
->rp_table
= route_table_init();
110 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
112 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
113 zlog_err("Unable to convert 224.0.0.0/4 to prefix");
114 list_delete_and_null(&pim
->rp_list
);
115 route_table_finish(pim
->rp_table
);
116 XFREE(MTYPE_PIM_RP
, rp_info
);
119 rp_info
->group
.family
= AF_INET
;
120 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
121 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
122 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
124 listnode_add(pim
->rp_list
, rp_info
);
126 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
130 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
131 rn
, rp_info
, rn
->lock
);
134 void pim_rp_free(struct pim_instance
*pim
)
137 list_delete_and_null(&pim
->rp_list
);
141 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
143 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
147 struct listnode
*node
;
148 struct rp_info
*rp_info
;
150 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
151 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
152 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
161 * Return true if plist is used by any rp_info
163 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
165 struct listnode
*node
;
166 struct rp_info
*rp_info
;
168 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
169 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
178 * Given an RP's address, return the RP's rp_info that is an exact match for
181 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
183 const struct prefix
*group
)
185 struct listnode
*node
;
186 struct rp_info
*rp_info
;
188 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
189 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
190 && prefix_same(&rp_info
->group
, group
))
198 * Given a group, return the rp_info for that group
200 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
201 const struct prefix
*group
)
203 struct listnode
*node
;
204 struct rp_info
*best
= NULL
;
205 struct rp_info
*rp_info
;
206 struct prefix_list
*plist
;
207 const struct prefix
*p
, *bp
;
208 struct route_node
*rn
;
211 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
212 if (rp_info
->plist
) {
213 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
215 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
225 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
232 rn
= route_node_match(pim
->rp_table
, group
);
235 "%s: BUG We should have found default group information\n",
236 __PRETTY_FUNCTION__
);
241 if (PIM_DEBUG_TRACE
) {
242 char buf
[PREFIX_STRLEN
];
244 route_unlock_node(rn
);
245 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
247 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
254 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
261 * When the user makes "ip pim rp" configuration changes or if they change the
262 * prefix-list(s) used by these statements we must tickle the upstream state
263 * for each group to make them re-lookup who their RP should be.
265 * This is a placeholder function for now.
267 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
269 pim_msdp_i_am_rp_changed(pim
);
272 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
273 struct prefix_list
*plist
)
275 struct listnode
*node
;
276 struct rp_info
*rp_info
;
277 int refresh_needed
= 0;
279 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
281 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
288 pim_rp_refresh_group_to_rp_mapping(pim
);
291 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
292 struct pim_interface
*pim_ifp
)
294 struct listnode
*node
;
295 struct pim_secondary_addr
*sec_addr
;
297 if (pim_ifp
->primary_address
.s_addr
298 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
301 if (!pim_ifp
->sec_addr_list
) {
305 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
306 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
314 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
315 struct rp_info
*rp_info
)
317 struct interface
*ifp
;
319 rp_info
->i_am_rp
= 0;
320 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
321 struct pim_interface
*pim_ifp
= ifp
->info
;
326 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
327 rp_info
->i_am_rp
= 1;
332 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
333 const char *group_range
, const char *plist
)
336 struct rp_info
*rp_info
;
337 struct rp_info
*rp_all
;
338 struct prefix group_all
;
339 struct listnode
*node
, *nnode
;
340 struct rp_info
*tmp_rp_info
;
343 struct pim_nexthop_cache pnc
;
344 struct route_node
*rn
;
346 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
348 if (group_range
== NULL
)
349 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
351 result
= str2prefix(group_range
, &rp_info
->group
);
354 XFREE(MTYPE_PIM_RP
, rp_info
);
355 return PIM_GROUP_BAD_ADDRESS
;
358 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
359 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
360 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
361 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
364 XFREE(MTYPE_PIM_RP
, rp_info
);
365 return PIM_RP_BAD_ADDRESS
;
370 * Return if the prefix-list is already configured for this RP
372 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
374 XFREE(MTYPE_PIM_RP
, rp_info
);
379 * Barf if the prefix-list is already configured for an RP
381 if (pim_rp_prefix_list_used(pim
, plist
)) {
382 XFREE(MTYPE_PIM_RP
, rp_info
);
383 return PIM_RP_PFXLIST_IN_USE
;
387 * Free any existing rp_info entries for this RP
389 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
391 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
392 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
393 if (tmp_rp_info
->plist
)
394 pim_rp_del(pim
, rp
, NULL
,
399 prefix2str(&tmp_rp_info
->group
,
405 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
408 if (!str2prefix("224.0.0.0/4", &group_all
)) {
409 XFREE(MTYPE_PIM_RP
, rp_info
);
410 return PIM_GROUP_BAD_ADDRESS
;
412 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
415 * Barf if group is a non-multicast subnet
417 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
418 XFREE(MTYPE_PIM_RP
, rp_info
);
419 return PIM_GROUP_BAD_ADDRESS
;
423 * Remove any prefix-list rp_info entries for this RP
425 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
427 if (tmp_rp_info
->plist
428 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
429 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
431 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
436 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
438 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
439 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
440 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
441 XFREE(MTYPE_PIM_RP
, rp_info
);
443 /* Register addr with Zebra NHT */
444 nht_p
.family
= AF_INET
;
445 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
447 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
448 if (PIM_DEBUG_PIM_NHT_RP
) {
449 char buf
[PREFIX2STR_BUFFER
];
450 char buf1
[PREFIX2STR_BUFFER
];
451 prefix2str(&nht_p
, buf
, sizeof(buf
));
452 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
454 "%s: NHT Register rp_all addr %s grp %s ",
455 __PRETTY_FUNCTION__
, buf
, buf1
);
457 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
458 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
460 if (!pim_ecmp_nexthop_search(
462 &rp_all
->rp
.source_nexthop
, &nht_p
,
464 return PIM_RP_NO_PATH
;
466 if (!pim_ecmp_nexthop_lookup(
467 pim
, &rp_all
->rp
.source_nexthop
,
468 &nht_p
, &rp_all
->group
, 1))
469 return PIM_RP_NO_PATH
;
471 pim_rp_check_interfaces(pim
, rp_all
);
472 pim_rp_refresh_group_to_rp_mapping(pim
);
477 * Return if the group is already configured for this RP
479 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
481 XFREE(MTYPE_PIM_RP
, rp_info
);
486 * Barf if this group is already covered by some other RP
488 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
491 if (tmp_rp_info
->plist
) {
492 XFREE(MTYPE_PIM_RP
, rp_info
);
493 return PIM_GROUP_PFXLIST_OVERLAP
;
496 * If the only RP that covers this group is an
498 * 224.0.0.0/4 that is fine, ignore that one.
500 * though we must return PIM_GROUP_OVERLAP
502 if (prefix_same(&rp_info
->group
,
503 &tmp_rp_info
->group
)) {
504 XFREE(MTYPE_PIM_RP
, rp_info
);
505 return PIM_GROUP_OVERLAP
;
511 listnode_add_sort(pim
->rp_list
, rp_info
);
512 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
515 if (PIM_DEBUG_TRACE
) {
516 char buf
[PREFIX_STRLEN
];
518 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
520 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
524 /* Register addr with Zebra NHT */
525 nht_p
.family
= AF_INET
;
526 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
527 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
528 if (PIM_DEBUG_PIM_NHT_RP
) {
529 char buf
[PREFIX2STR_BUFFER
];
530 char buf1
[PREFIX2STR_BUFFER
];
531 prefix2str(&nht_p
, buf
, sizeof(buf
));
532 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
533 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
534 __PRETTY_FUNCTION__
, buf
, buf1
);
537 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
538 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
539 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
540 &rp_info
->rp
.source_nexthop
,
541 &nht_p
, &rp_info
->group
, 1))
542 return PIM_RP_NO_PATH
;
544 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
545 &nht_p
, &rp_info
->group
, 1))
546 return PIM_RP_NO_PATH
;
549 pim_rp_check_interfaces(pim
, rp_info
);
550 pim_rp_refresh_group_to_rp_mapping(pim
);
554 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
555 const char *group_range
, const char *plist
)
558 struct in_addr rp_addr
;
560 struct rp_info
*rp_info
;
561 struct rp_info
*rp_all
;
564 struct route_node
*rn
;
565 bool was_plist
= false;
567 if (group_range
== NULL
)
568 result
= str2prefix("224.0.0.0/4", &group
);
570 result
= str2prefix(group_range
, &group
);
573 return PIM_GROUP_BAD_ADDRESS
;
575 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
577 return PIM_RP_BAD_ADDRESS
;
580 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
582 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
585 return PIM_RP_NOT_FOUND
;
587 if (rp_info
->plist
) {
588 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
592 /* Deregister addr with Zebra NHT */
593 nht_p
.family
= AF_INET
;
594 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
595 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
596 if (PIM_DEBUG_PIM_NHT_RP
) {
597 char buf
[PREFIX2STR_BUFFER
];
598 prefix2str(&nht_p
, buf
, sizeof(buf
));
599 zlog_debug("%s: Deregister RP addr %s with Zebra ",
600 __PRETTY_FUNCTION__
, buf
);
602 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
604 if (!str2prefix("224.0.0.0/4", &g_all
))
605 return PIM_RP_BAD_ADDRESS
;
607 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
609 if (rp_all
== rp_info
) {
610 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
611 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
616 listnode_delete(pim
->rp_list
, rp_info
);
619 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
621 if (rn
->info
!= rp_info
)
622 zlog_err("WTF matey");
624 if (PIM_DEBUG_TRACE
) {
625 char buf
[PREFIX_STRLEN
];
628 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
629 __PRETTY_FUNCTION__
, rn
, rp_info
,
630 prefix2str(&rp_info
->group
, buf
,
635 route_unlock_node(rn
);
636 route_unlock_node(rn
);
640 pim_rp_refresh_group_to_rp_mapping(pim
);
642 XFREE(MTYPE_PIM_RP
, rp_info
);
646 void pim_rp_setup(struct pim_instance
*pim
)
648 struct listnode
*node
;
649 struct rp_info
*rp_info
;
651 struct pim_nexthop_cache pnc
;
653 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
654 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
657 nht_p
.family
= AF_INET
;
658 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
659 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
660 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
661 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
662 pim_ecmp_nexthop_search(pim
, &pnc
,
663 &rp_info
->rp
.source_nexthop
,
664 &nht_p
, &rp_info
->group
, 1);
666 if (PIM_DEBUG_PIM_NHT_RP
) {
667 char buf
[PREFIX2STR_BUFFER
];
668 prefix2str(&nht_p
, buf
, sizeof(buf
));
670 "%s: NHT Local Nexthop not found for RP %s ",
671 __PRETTY_FUNCTION__
, buf
);
673 if (!pim_ecmp_nexthop_lookup(pim
,
674 &rp_info
->rp
.source_nexthop
,
675 &nht_p
, &rp_info
->group
, 1))
676 if (PIM_DEBUG_PIM_NHT_RP
)
678 "Unable to lookup nexthop for rp specified");
684 * Checks to see if we should elect ourself the actual RP when new if
685 * addresses are added against an interface.
687 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
689 struct listnode
*node
;
690 struct rp_info
*rp_info
;
691 bool i_am_rp_changed
= false;
692 struct pim_instance
*pim
= pim_ifp
->pim
;
694 if (pim
->rp_list
== NULL
)
697 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
698 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
701 /* if i_am_rp is already set nothing to be done (adding new
703 * is not going to make a difference). */
704 if (rp_info
->i_am_rp
) {
708 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
709 i_am_rp_changed
= true;
710 rp_info
->i_am_rp
= 1;
711 if (PIM_DEBUG_PIM_NHT_RP
) {
712 char rp
[PREFIX_STRLEN
];
713 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
715 zlog_debug("%s: %s: i am rp", __func__
, rp
);
720 if (i_am_rp_changed
) {
721 pim_msdp_i_am_rp_changed(pim
);
725 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
726 * are removed. Removing numbers is an uncommon event in an active network
727 * so I have made no attempt to optimize it. */
728 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
730 struct listnode
*node
;
731 struct rp_info
*rp_info
;
732 bool i_am_rp_changed
= false;
735 if (pim
->rp_list
== NULL
)
738 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
739 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
742 old_i_am_rp
= rp_info
->i_am_rp
;
743 pim_rp_check_interfaces(pim
, rp_info
);
745 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
746 i_am_rp_changed
= true;
747 if (PIM_DEBUG_PIM_NHT_RP
) {
748 char rp
[PREFIX_STRLEN
];
749 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
751 if (rp_info
->i_am_rp
) {
752 zlog_debug("%s: %s: i am rp", __func__
,
755 zlog_debug("%s: %s: i am no longer rp",
762 if (i_am_rp_changed
) {
763 pim_msdp_i_am_rp_changed(pim
);
768 * I_am_RP(G) is true if the group-to-RP mapping indicates that
769 * this router is the RP for the group.
771 * Since we only have static RP, all groups are part of this RP
773 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
776 struct rp_info
*rp_info
;
778 memset(&g
, 0, sizeof(g
));
783 rp_info
= pim_rp_find_match_group(pim
, &g
);
786 return rp_info
->i_am_rp
;
794 * Return the RP that the Group belongs too.
796 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
799 struct rp_info
*rp_info
;
801 memset(&g
, 0, sizeof(g
));
806 rp_info
= pim_rp_find_match_group(pim
, &g
);
810 struct pim_nexthop_cache pnc
;
811 /* Register addr with Zebra NHT */
812 nht_p
.family
= AF_INET
;
813 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
814 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
815 if (PIM_DEBUG_PIM_NHT_RP
) {
816 char buf
[PREFIX2STR_BUFFER
];
817 char buf1
[PREFIX2STR_BUFFER
];
818 prefix2str(&nht_p
, buf
, sizeof(buf
));
819 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
821 "%s: NHT Register RP addr %s grp %s with Zebra",
822 __PRETTY_FUNCTION__
, buf
, buf1
);
824 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
825 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
826 pim_ecmp_nexthop_search(pim
, &pnc
,
827 &rp_info
->rp
.source_nexthop
,
828 &nht_p
, &rp_info
->group
, 1);
830 if (PIM_DEBUG_PIM_NHT_RP
) {
831 char buf
[PREFIX2STR_BUFFER
];
832 char buf1
[PREFIX2STR_BUFFER
];
833 prefix2str(&nht_p
, buf
, sizeof(buf
));
834 prefix2str(&g
, buf1
, sizeof(buf1
));
836 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
837 __PRETTY_FUNCTION__
, buf
, buf1
);
839 pim_rpf_set_refresh_time(pim
);
840 (void)pim_ecmp_nexthop_lookup(
841 pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
844 return (&rp_info
->rp
);
852 * Set the upstream IP address we want to talk to based upon
853 * the rp configured and the source address
855 * If we have don't have a RP configured and the source address is *
856 * then return failure.
859 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
860 struct in_addr source
, struct in_addr group
)
862 struct rp_info
*rp_info
;
865 memset(&g
, 0, sizeof(g
));
870 rp_info
= pim_rp_find_match_group(pim
, &g
);
872 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
873 && (source
.s_addr
== INADDR_ANY
)) {
874 if (PIM_DEBUG_PIM_NHT_RP
)
875 zlog_debug("%s: Received a (*,G) with no RP configured",
876 __PRETTY_FUNCTION__
);
880 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
886 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
889 struct listnode
*node
;
890 struct rp_info
*rp_info
;
892 char group_buffer
[32];
895 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
896 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
900 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
902 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
906 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
908 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
910 prefix2str(&rp_info
->group
, group_buffer
, 32));
917 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
918 struct in_addr group
,
919 struct in_addr dest_addr
)
921 struct rp_info
*rp_info
;
924 memset(&g
, 0, sizeof(g
));
929 rp_info
= pim_rp_find_match_group(pim
, &g
);
931 * See if we can short-cut some?
932 * This might not make sense if we ever leave a static RP
933 * type of configuration.
934 * Note - Premature optimization might bite our patooeys' here.
936 if (I_am_RP(pim
, group
)) {
937 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
941 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
947 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
,
950 struct rp_info
*rp_info
;
951 struct rp_info
*prev_rp_info
= NULL
;
952 struct listnode
*node
;
954 json_object
*json
= NULL
;
955 json_object
*json_rp_rows
= NULL
;
956 json_object
*json_row
= NULL
;
959 json
= json_object_new_object();
962 "RP address group/prefix-list OIF I am RP\n");
964 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
965 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
970 * If we have moved on to a new RP then add the
971 * entry for the previous RP
974 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
976 != rp_info
->rp
.rpf_addr
.u
.prefix4
978 json_object_object_add(
980 inet_ntoa(prev_rp_info
->rp
988 json_rp_rows
= json_object_new_array();
990 json_row
= json_object_new_object();
991 if (rp_info
->rp
.source_nexthop
.interface
)
992 json_object_string_add(
993 json_row
, "outboundInterface",
994 rp_info
->rp
.source_nexthop
997 if (rp_info
->i_am_rp
)
998 json_object_boolean_true_add(json_row
,
1002 json_object_string_add(json_row
,
1006 json_object_string_add(
1008 prefix2str(&rp_info
->group
, buf
,
1011 json_object_array_add(json_rp_rows
, json_row
);
1013 vty_out(vty
, "%-15s ",
1014 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1018 vty_out(vty
, "%-18s ", rp_info
->plist
);
1020 vty_out(vty
, "%-18s ",
1021 prefix2str(&rp_info
->group
, buf
,
1024 if (rp_info
->rp
.source_nexthop
.interface
)
1025 vty_out(vty
, "%-10s ",
1026 rp_info
->rp
.source_nexthop
1029 vty_out(vty
, "%-10s ", "(Unknown)");
1031 if (rp_info
->i_am_rp
)
1032 vty_out(vty
, "yes\n");
1034 vty_out(vty
, "no\n");
1037 prev_rp_info
= rp_info
;
1042 if (prev_rp_info
&& json_rp_rows
)
1043 json_object_object_add(
1045 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1048 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1049 json
, JSON_C_TO_STRING_PRETTY
));
1050 json_object_free(json
);
1054 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1056 struct listnode
*node
= NULL
;
1057 struct rp_info
*rp_info
= NULL
;
1058 struct nexthop
*nh_node
= NULL
;
1059 struct prefix nht_p
;
1060 struct pim_nexthop_cache pnc
;
1061 struct pim_neighbor
*nbr
= NULL
;
1063 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1064 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1067 nht_p
.family
= AF_INET
;
1068 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1069 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1070 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1071 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1075 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1076 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1079 struct interface
*ifp1
= if_lookup_by_index(
1080 nh_node
->ifindex
, pim
->vrf_id
);
1081 nbr
= pim_neighbor_find_if(ifp1
);
1085 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1086 if (PIM_DEBUG_PIM_NHT_RP
) {
1087 char str
[PREFIX_STRLEN
];
1088 char str1
[INET_ADDRSTRLEN
];
1089 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1090 str1
, sizeof(str1
));
1091 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1094 "%s: addr %s new nexthop addr %s interface %s",
1095 __PRETTY_FUNCTION__
, str
, str1
,