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
)
65 XFREE(MTYPE_PIM_RP
, rp_info
);
68 int pim_rp_list_cmp(void *v1
, void *v2
)
70 struct rp_info
*rp1
= (struct rp_info
*)v1
;
71 struct rp_info
*rp2
= (struct rp_info
*)v2
;
74 * Sort by RP IP address
76 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
77 < rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
80 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
81 > rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
85 * Sort by group IP address
87 if (rp1
->group
.u
.prefix4
.s_addr
< rp2
->group
.u
.prefix4
.s_addr
)
90 if (rp1
->group
.u
.prefix4
.s_addr
> rp2
->group
.u
.prefix4
.s_addr
)
96 void pim_rp_init(struct pim_instance
*pim
)
98 struct rp_info
*rp_info
;
99 struct route_node
*rn
;
101 pim
->rp_list
= list_new();
103 zlog_err("Unable to alloc rp_list");
106 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
107 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
109 pim
->rp_table
= route_table_init();
110 if (!pim
->rp_table
) {
111 zlog_err("Unable to alloc rp_table");
112 list_delete_and_null(&pim
->rp_list
);
116 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
118 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
119 zlog_err("Unable to convert 224.0.0.0/4 to prefix");
120 list_delete_and_null(&pim
->rp_list
);
121 route_table_finish(pim
->rp_table
);
122 XFREE(MTYPE_PIM_RP
, rp_info
);
125 rp_info
->group
.family
= AF_INET
;
126 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
127 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
128 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
130 listnode_add(pim
->rp_list
, rp_info
);
132 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
134 zlog_err("Failure to get route node for pim->rp_table");
135 list_delete_and_null(&pim
->rp_list
);
136 route_table_finish(pim
->rp_table
);
137 XFREE(MTYPE_PIM_RP
, rp_info
);
144 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
145 rn
, rp_info
, rn
->lock
);
148 void pim_rp_free(struct pim_instance
*pim
)
151 list_delete_and_null(&pim
->rp_list
);
155 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
157 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
161 struct listnode
*node
;
162 struct rp_info
*rp_info
;
164 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
165 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
166 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
175 * Return true if plist is used by any rp_info
177 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
179 struct listnode
*node
;
180 struct rp_info
*rp_info
;
182 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
183 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
192 * Given an RP's address, return the RP's rp_info that is an exact match for
195 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
197 struct prefix
*group
)
199 struct listnode
*node
;
200 struct rp_info
*rp_info
;
202 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
203 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
204 && prefix_same(&rp_info
->group
, group
))
212 * Given a group, return the rp_info for that group
214 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
215 struct prefix
*group
)
217 struct listnode
*node
;
218 struct rp_info
*best
= NULL
;
219 struct rp_info
*rp_info
;
220 struct prefix_list
*plist
;
221 struct prefix
*p
, *bp
;
222 struct route_node
*rn
;
225 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
226 if (rp_info
->plist
) {
227 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
229 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
239 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
246 rn
= route_node_match(pim
->rp_table
, group
);
249 "%s: BUG We should have found default group information\n",
250 __PRETTY_FUNCTION__
);
255 if (PIM_DEBUG_TRACE
) {
256 char buf
[PREFIX_STRLEN
];
258 route_unlock_node(rn
);
259 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
261 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
268 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
275 * When the user makes "ip pim rp" configuration changes or if they change the
276 * prefix-list(s) used by these statements we must tickle the upstream state
277 * for each group to make them re-lookup who their RP should be.
279 * This is a placeholder function for now.
281 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
283 pim_msdp_i_am_rp_changed(pim
);
286 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
287 struct prefix_list
*plist
)
289 struct listnode
*node
;
290 struct rp_info
*rp_info
;
291 int refresh_needed
= 0;
293 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
295 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
302 pim_rp_refresh_group_to_rp_mapping(pim
);
305 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
306 struct pim_interface
*pim_ifp
)
308 struct listnode
*node
;
309 struct pim_secondary_addr
*sec_addr
;
311 if (pim_ifp
->primary_address
.s_addr
312 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
315 if (!pim_ifp
->sec_addr_list
) {
319 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
320 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
328 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
329 struct rp_info
*rp_info
)
331 struct interface
*ifp
;
333 rp_info
->i_am_rp
= 0;
334 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
335 struct pim_interface
*pim_ifp
= ifp
->info
;
340 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
341 rp_info
->i_am_rp
= 1;
346 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
347 const char *group_range
, const char *plist
)
350 struct rp_info
*rp_info
;
351 struct rp_info
*rp_all
;
352 struct prefix group_all
;
353 struct listnode
*node
, *nnode
;
354 struct rp_info
*tmp_rp_info
;
357 struct pim_nexthop_cache pnc
;
358 struct route_node
*rn
;
360 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
362 if (group_range
== NULL
)
363 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
365 result
= str2prefix(group_range
, &rp_info
->group
);
368 XFREE(MTYPE_PIM_RP
, rp_info
);
369 return PIM_GROUP_BAD_ADDRESS
;
372 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
373 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
374 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
375 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
378 XFREE(MTYPE_PIM_RP
, rp_info
);
379 return PIM_RP_BAD_ADDRESS
;
384 * Return if the prefix-list is already configured for this RP
386 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
388 XFREE(MTYPE_PIM_RP
, rp_info
);
393 * Barf if the prefix-list is already configured for an RP
395 if (pim_rp_prefix_list_used(pim
, plist
)) {
396 XFREE(MTYPE_PIM_RP
, rp_info
);
397 return PIM_RP_PFXLIST_IN_USE
;
401 * Free any existing rp_info entries for this RP
403 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
405 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
406 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
407 if (tmp_rp_info
->plist
)
408 pim_rp_del(pim
, rp
, NULL
,
413 prefix2str(&tmp_rp_info
->group
,
419 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
422 if (!str2prefix("224.0.0.0/4", &group_all
)) {
423 XFREE(MTYPE_PIM_RP
, rp_info
);
424 return PIM_GROUP_BAD_ADDRESS
;
426 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
429 * Barf if group is a non-multicast subnet
431 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
432 XFREE(MTYPE_PIM_RP
, rp_info
);
433 return PIM_GROUP_BAD_ADDRESS
;
437 * Remove any prefix-list rp_info entries for this RP
439 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
441 if (tmp_rp_info
->plist
442 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
443 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
445 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
450 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
452 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
453 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
454 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
455 XFREE(MTYPE_PIM_RP
, rp_info
);
457 /* Register addr with Zebra NHT */
458 nht_p
.family
= AF_INET
;
459 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
461 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
462 if (PIM_DEBUG_PIM_NHT_RP
) {
463 char buf
[PREFIX2STR_BUFFER
];
464 char buf1
[PREFIX2STR_BUFFER
];
465 prefix2str(&nht_p
, buf
, sizeof(buf
));
466 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
468 "%s: NHT Register rp_all addr %s grp %s ",
469 __PRETTY_FUNCTION__
, buf
, buf1
);
471 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
472 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
474 if (!pim_ecmp_nexthop_search(
476 &rp_all
->rp
.source_nexthop
, &nht_p
,
478 return PIM_RP_NO_PATH
;
480 if (!pim_ecmp_nexthop_lookup(
481 pim
, &rp_all
->rp
.source_nexthop
,
482 &nht_p
, &rp_all
->group
, 1))
483 return PIM_RP_NO_PATH
;
485 pim_rp_check_interfaces(pim
, rp_all
);
486 pim_rp_refresh_group_to_rp_mapping(pim
);
491 * Return if the group is already configured for this RP
493 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
495 XFREE(MTYPE_PIM_RP
, rp_info
);
500 * Barf if this group is already covered by some other RP
502 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
505 if (tmp_rp_info
->plist
) {
506 XFREE(MTYPE_PIM_RP
, rp_info
);
507 return PIM_GROUP_PFXLIST_OVERLAP
;
510 * If the only RP that covers this group is an
512 * 224.0.0.0/4 that is fine, ignore that one.
514 * though we must return PIM_GROUP_OVERLAP
516 if (prefix_same(&rp_info
->group
,
517 &tmp_rp_info
->group
)) {
518 XFREE(MTYPE_PIM_RP
, rp_info
);
519 return PIM_GROUP_OVERLAP
;
525 listnode_add_sort(pim
->rp_list
, rp_info
);
526 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
529 if (PIM_DEBUG_TRACE
) {
530 char buf
[PREFIX_STRLEN
];
532 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
534 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
538 /* Register addr with Zebra NHT */
539 nht_p
.family
= AF_INET
;
540 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
541 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
542 if (PIM_DEBUG_PIM_NHT_RP
) {
543 char buf
[PREFIX2STR_BUFFER
];
544 char buf1
[PREFIX2STR_BUFFER
];
545 prefix2str(&nht_p
, buf
, sizeof(buf
));
546 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
547 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
548 __PRETTY_FUNCTION__
, buf
, buf1
);
551 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
552 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
553 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
554 &rp_info
->rp
.source_nexthop
,
555 &nht_p
, &rp_info
->group
, 1))
556 return PIM_RP_NO_PATH
;
558 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
559 &nht_p
, &rp_info
->group
, 1))
560 return PIM_RP_NO_PATH
;
563 pim_rp_check_interfaces(pim
, rp_info
);
564 pim_rp_refresh_group_to_rp_mapping(pim
);
568 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
569 const char *group_range
, const char *plist
)
572 struct in_addr rp_addr
;
574 struct rp_info
*rp_info
;
575 struct rp_info
*rp_all
;
578 struct route_node
*rn
;
579 bool was_plist
= false;
581 if (group_range
== NULL
)
582 result
= str2prefix("224.0.0.0/4", &group
);
584 result
= str2prefix(group_range
, &group
);
587 return PIM_GROUP_BAD_ADDRESS
;
589 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
591 return PIM_RP_BAD_ADDRESS
;
594 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
596 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
599 return PIM_RP_NOT_FOUND
;
601 if (rp_info
->plist
) {
602 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
603 rp_info
->plist
= NULL
;
607 /* Deregister addr with Zebra NHT */
608 nht_p
.family
= AF_INET
;
609 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
610 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
611 if (PIM_DEBUG_PIM_NHT_RP
) {
612 char buf
[PREFIX2STR_BUFFER
];
613 prefix2str(&nht_p
, buf
, sizeof(buf
));
614 zlog_debug("%s: Deregister RP addr %s with Zebra ",
615 __PRETTY_FUNCTION__
, buf
);
617 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
619 if (!str2prefix("224.0.0.0/4", &g_all
))
620 return PIM_RP_BAD_ADDRESS
;
622 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
624 if (rp_all
== rp_info
) {
625 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
626 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
631 listnode_delete(pim
->rp_list
, rp_info
);
634 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
636 if (rn
->info
!= rp_info
)
637 zlog_err("WTF matey");
639 if (PIM_DEBUG_TRACE
) {
640 char buf
[PREFIX_STRLEN
];
643 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
644 __PRETTY_FUNCTION__
, rn
, rp_info
,
645 prefix2str(&rp_info
->group
, buf
,
650 route_unlock_node(rn
);
651 route_unlock_node(rn
);
655 pim_rp_refresh_group_to_rp_mapping(pim
);
657 XFREE(MTYPE_PIM_RP
, rp_info
);
661 void pim_rp_setup(struct pim_instance
*pim
)
663 struct listnode
*node
;
664 struct rp_info
*rp_info
;
666 struct pim_nexthop_cache pnc
;
668 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
669 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
672 nht_p
.family
= AF_INET
;
673 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
674 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
675 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
676 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
677 pim_ecmp_nexthop_search(pim
, &pnc
,
678 &rp_info
->rp
.source_nexthop
,
679 &nht_p
, &rp_info
->group
, 1);
681 if (PIM_DEBUG_PIM_NHT_RP
) {
682 char buf
[PREFIX2STR_BUFFER
];
683 prefix2str(&nht_p
, buf
, sizeof(buf
));
685 "%s: NHT Local Nexthop not found for RP %s ",
686 __PRETTY_FUNCTION__
, buf
);
688 if (!pim_ecmp_nexthop_lookup(pim
,
689 &rp_info
->rp
.source_nexthop
,
690 &nht_p
, &rp_info
->group
, 1))
691 if (PIM_DEBUG_PIM_NHT_RP
)
693 "Unable to lookup nexthop for rp specified");
699 * Checks to see if we should elect ourself the actual RP when new if
700 * addresses are added against an interface.
702 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
704 struct listnode
*node
;
705 struct rp_info
*rp_info
;
706 bool i_am_rp_changed
= false;
707 struct pim_instance
*pim
= pim_ifp
->pim
;
709 if (pim
->rp_list
== NULL
)
712 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
713 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
716 /* if i_am_rp is already set nothing to be done (adding new
718 * is not going to make a difference). */
719 if (rp_info
->i_am_rp
) {
723 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
724 i_am_rp_changed
= true;
725 rp_info
->i_am_rp
= 1;
726 if (PIM_DEBUG_PIM_NHT_RP
) {
727 char rp
[PREFIX_STRLEN
];
728 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
730 zlog_debug("%s: %s: i am rp", __func__
, rp
);
735 if (i_am_rp_changed
) {
736 pim_msdp_i_am_rp_changed(pim
);
740 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
741 * are removed. Removing numbers is an uncommon event in an active network
742 * so I have made no attempt to optimize it. */
743 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
745 struct listnode
*node
;
746 struct rp_info
*rp_info
;
747 bool i_am_rp_changed
= false;
750 if (pim
->rp_list
== NULL
)
753 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
754 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
757 old_i_am_rp
= rp_info
->i_am_rp
;
758 pim_rp_check_interfaces(pim
, rp_info
);
760 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
761 i_am_rp_changed
= true;
762 if (PIM_DEBUG_PIM_NHT_RP
) {
763 char rp
[PREFIX_STRLEN
];
764 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
766 if (rp_info
->i_am_rp
) {
767 zlog_debug("%s: %s: i am rp", __func__
,
770 zlog_debug("%s: %s: i am no longer rp",
777 if (i_am_rp_changed
) {
778 pim_msdp_i_am_rp_changed(pim
);
783 * I_am_RP(G) is true if the group-to-RP mapping indicates that
784 * this router is the RP for the group.
786 * Since we only have static RP, all groups are part of this RP
788 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
791 struct rp_info
*rp_info
;
793 memset(&g
, 0, sizeof(g
));
798 rp_info
= pim_rp_find_match_group(pim
, &g
);
801 return rp_info
->i_am_rp
;
809 * Return the RP that the Group belongs too.
811 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
814 struct rp_info
*rp_info
;
816 memset(&g
, 0, sizeof(g
));
821 rp_info
= pim_rp_find_match_group(pim
, &g
);
825 struct pim_nexthop_cache pnc
;
826 /* Register addr with Zebra NHT */
827 nht_p
.family
= AF_INET
;
828 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
829 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
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(&rp_info
->group
, buf1
, sizeof(buf1
));
836 "%s: NHT Register RP addr %s grp %s with Zebra",
837 __PRETTY_FUNCTION__
, buf
, buf1
);
839 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
840 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
841 pim_ecmp_nexthop_search(pim
, &pnc
,
842 &rp_info
->rp
.source_nexthop
,
843 &nht_p
, &rp_info
->group
, 1);
845 if (PIM_DEBUG_PIM_NHT_RP
) {
846 char buf
[PREFIX2STR_BUFFER
];
847 char buf1
[PREFIX2STR_BUFFER
];
848 prefix2str(&nht_p
, buf
, sizeof(buf
));
849 prefix2str(&g
, buf1
, sizeof(buf1
));
851 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
852 __PRETTY_FUNCTION__
, buf
, buf1
);
854 pim_rpf_set_refresh_time(pim
);
855 pim_ecmp_nexthop_lookup(pim
,
856 &rp_info
->rp
.source_nexthop
,
857 &nht_p
, &rp_info
->group
, 1);
859 return (&rp_info
->rp
);
867 * Set the upstream IP address we want to talk to based upon
868 * the rp configured and the source address
870 * If we have don't have a RP configured and the source address is *
871 * then return failure.
874 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
875 struct in_addr source
, struct in_addr group
)
877 struct rp_info
*rp_info
;
880 memset(&g
, 0, sizeof(g
));
885 rp_info
= pim_rp_find_match_group(pim
, &g
);
887 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
888 && (source
.s_addr
== INADDR_ANY
)) {
889 if (PIM_DEBUG_PIM_NHT_RP
)
890 zlog_debug("%s: Received a (*,G) with no RP configured",
891 __PRETTY_FUNCTION__
);
895 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
901 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
904 struct listnode
*node
;
905 struct rp_info
*rp_info
;
907 char group_buffer
[32];
910 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
911 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
915 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
917 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
921 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
923 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
925 prefix2str(&rp_info
->group
, group_buffer
, 32));
932 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
933 struct in_addr group
,
934 struct in_addr dest_addr
)
936 struct rp_info
*rp_info
;
939 memset(&g
, 0, sizeof(g
));
944 rp_info
= pim_rp_find_match_group(pim
, &g
);
946 * See if we can short-cut some?
947 * This might not make sense if we ever leave a static RP
948 * type of configuration.
949 * Note - Premature optimization might bite our patooeys' here.
951 if (I_am_RP(pim
, group
)) {
952 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
956 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
962 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
,
965 struct rp_info
*rp_info
;
966 struct rp_info
*prev_rp_info
= NULL
;
967 struct listnode
*node
;
969 json_object
*json
= NULL
;
970 json_object
*json_rp_rows
= NULL
;
971 json_object
*json_row
= NULL
;
974 json
= json_object_new_object();
977 "RP address group/prefix-list OIF I am RP\n");
979 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
980 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
985 * If we have moved on to a new RP then add the
986 * entry for the previous RP
989 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
991 != rp_info
->rp
.rpf_addr
.u
.prefix4
993 json_object_object_add(
995 inet_ntoa(prev_rp_info
->rp
1003 json_rp_rows
= json_object_new_array();
1005 json_row
= json_object_new_object();
1006 if (rp_info
->rp
.source_nexthop
.interface
)
1007 json_object_string_add(
1008 json_row
, "outboundInterface",
1009 rp_info
->rp
.source_nexthop
1012 if (rp_info
->i_am_rp
)
1013 json_object_boolean_true_add(json_row
,
1017 json_object_string_add(json_row
,
1021 json_object_string_add(
1023 prefix2str(&rp_info
->group
, buf
,
1026 json_object_array_add(json_rp_rows
, json_row
);
1028 vty_out(vty
, "%-15s ",
1029 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1033 vty_out(vty
, "%-18s ", rp_info
->plist
);
1035 vty_out(vty
, "%-18s ",
1036 prefix2str(&rp_info
->group
, buf
,
1039 if (rp_info
->rp
.source_nexthop
.interface
)
1040 vty_out(vty
, "%-10s ",
1041 rp_info
->rp
.source_nexthop
1044 vty_out(vty
, "%-10s ", "(Unknown)");
1046 if (rp_info
->i_am_rp
)
1047 vty_out(vty
, "yes\n");
1049 vty_out(vty
, "no\n");
1052 prev_rp_info
= rp_info
;
1057 if (prev_rp_info
&& json_rp_rows
)
1058 json_object_object_add(
1060 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1063 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1064 json
, JSON_C_TO_STRING_PRETTY
));
1065 json_object_free(json
);
1069 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1071 struct listnode
*node
= NULL
;
1072 struct rp_info
*rp_info
= NULL
;
1073 struct nexthop
*nh_node
= NULL
;
1074 struct prefix nht_p
;
1075 struct pim_nexthop_cache pnc
;
1076 struct pim_neighbor
*nbr
= NULL
;
1078 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1079 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1082 nht_p
.family
= AF_INET
;
1083 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1084 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1085 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1086 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1090 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1091 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1094 struct interface
*ifp1
= if_lookup_by_index(
1095 nh_node
->ifindex
, pim
->vrf_id
);
1096 nbr
= pim_neighbor_find_if(ifp1
);
1100 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1101 if (PIM_DEBUG_PIM_NHT_RP
) {
1102 char str
[PREFIX_STRLEN
];
1103 char str1
[INET_ADDRSTRLEN
];
1104 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1105 str1
, sizeof(str1
));
1106 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1109 "%s: addr %s new nexthop addr %s interface %s",
1110 __PRETTY_FUNCTION__
, str
, str1
,