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();
106 zlog_err("Unable to alloc rp_list");
109 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
110 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
112 pim
->rp_table
= route_table_init();
113 if (!pim
->rp_table
) {
114 zlog_err("Unable to alloc rp_table");
115 list_delete_and_null(&pim
->rp_list
);
119 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
121 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
122 zlog_err("Unable to convert 224.0.0.0/4 to prefix");
123 list_delete_and_null(&pim
->rp_list
);
124 route_table_finish(pim
->rp_table
);
125 XFREE(MTYPE_PIM_RP
, rp_info
);
128 rp_info
->group
.family
= AF_INET
;
129 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
130 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
131 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
133 listnode_add(pim
->rp_list
, rp_info
);
135 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
137 zlog_err("Failure to get route node for pim->rp_table");
138 list_delete_and_null(&pim
->rp_list
);
139 route_table_finish(pim
->rp_table
);
140 XFREE(MTYPE_PIM_RP
, rp_info
);
147 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
148 rn
, rp_info
, rn
->lock
);
151 void pim_rp_free(struct pim_instance
*pim
)
154 list_delete_and_null(&pim
->rp_list
);
158 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
160 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
164 struct listnode
*node
;
165 struct rp_info
*rp_info
;
167 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
168 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
169 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
178 * Return true if plist is used by any rp_info
180 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
182 struct listnode
*node
;
183 struct rp_info
*rp_info
;
185 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
186 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
195 * Given an RP's address, return the RP's rp_info that is an exact match for
198 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
200 const struct prefix
*group
)
202 struct listnode
*node
;
203 struct rp_info
*rp_info
;
205 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
206 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
207 && prefix_same(&rp_info
->group
, group
))
215 * Given a group, return the rp_info for that group
217 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
218 const struct prefix
*group
)
220 struct listnode
*node
;
221 struct rp_info
*best
= NULL
;
222 struct rp_info
*rp_info
;
223 struct prefix_list
*plist
;
224 const struct prefix
*p
, *bp
;
225 struct route_node
*rn
;
228 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
229 if (rp_info
->plist
) {
230 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
232 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
242 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
249 rn
= route_node_match(pim
->rp_table
, group
);
252 "%s: BUG We should have found default group information\n",
253 __PRETTY_FUNCTION__
);
258 if (PIM_DEBUG_TRACE
) {
259 char buf
[PREFIX_STRLEN
];
261 route_unlock_node(rn
);
262 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
264 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
271 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
278 * When the user makes "ip pim rp" configuration changes or if they change the
279 * prefix-list(s) used by these statements we must tickle the upstream state
280 * for each group to make them re-lookup who their RP should be.
282 * This is a placeholder function for now.
284 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
286 pim_msdp_i_am_rp_changed(pim
);
289 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
290 struct prefix_list
*plist
)
292 struct listnode
*node
;
293 struct rp_info
*rp_info
;
294 int refresh_needed
= 0;
296 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
298 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
305 pim_rp_refresh_group_to_rp_mapping(pim
);
308 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
309 struct pim_interface
*pim_ifp
)
311 struct listnode
*node
;
312 struct pim_secondary_addr
*sec_addr
;
314 if (pim_ifp
->primary_address
.s_addr
315 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
318 if (!pim_ifp
->sec_addr_list
) {
322 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
323 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
331 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
332 struct rp_info
*rp_info
)
334 struct interface
*ifp
;
336 rp_info
->i_am_rp
= 0;
337 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
338 struct pim_interface
*pim_ifp
= ifp
->info
;
343 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
344 rp_info
->i_am_rp
= 1;
349 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
350 const char *group_range
, const char *plist
)
353 struct rp_info
*rp_info
;
354 struct rp_info
*rp_all
;
355 struct prefix group_all
;
356 struct listnode
*node
, *nnode
;
357 struct rp_info
*tmp_rp_info
;
360 struct pim_nexthop_cache pnc
;
361 struct route_node
*rn
;
363 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
365 if (group_range
== NULL
)
366 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
368 result
= str2prefix(group_range
, &rp_info
->group
);
371 XFREE(MTYPE_PIM_RP
, rp_info
);
372 return PIM_GROUP_BAD_ADDRESS
;
375 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
376 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
377 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
378 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
381 XFREE(MTYPE_PIM_RP
, rp_info
);
382 return PIM_RP_BAD_ADDRESS
;
387 * Return if the prefix-list is already configured for this RP
389 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
391 XFREE(MTYPE_PIM_RP
, rp_info
);
396 * Barf if the prefix-list is already configured for an RP
398 if (pim_rp_prefix_list_used(pim
, plist
)) {
399 XFREE(MTYPE_PIM_RP
, rp_info
);
400 return PIM_RP_PFXLIST_IN_USE
;
404 * Free any existing rp_info entries for this RP
406 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
408 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
409 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
410 if (tmp_rp_info
->plist
)
411 pim_rp_del(pim
, rp
, NULL
,
416 prefix2str(&tmp_rp_info
->group
,
422 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
425 if (!str2prefix("224.0.0.0/4", &group_all
)) {
426 XFREE(MTYPE_PIM_RP
, rp_info
);
427 return PIM_GROUP_BAD_ADDRESS
;
429 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
432 * Barf if group is a non-multicast subnet
434 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
435 XFREE(MTYPE_PIM_RP
, rp_info
);
436 return PIM_GROUP_BAD_ADDRESS
;
440 * Remove any prefix-list rp_info entries for this RP
442 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
444 if (tmp_rp_info
->plist
445 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
446 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
448 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
453 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
455 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
456 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
457 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
458 XFREE(MTYPE_PIM_RP
, rp_info
);
460 /* Register addr with Zebra NHT */
461 nht_p
.family
= AF_INET
;
462 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
464 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
465 if (PIM_DEBUG_PIM_NHT_RP
) {
466 char buf
[PREFIX2STR_BUFFER
];
467 char buf1
[PREFIX2STR_BUFFER
];
468 prefix2str(&nht_p
, buf
, sizeof(buf
));
469 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
471 "%s: NHT Register rp_all addr %s grp %s ",
472 __PRETTY_FUNCTION__
, buf
, buf1
);
474 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
475 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
477 if (!pim_ecmp_nexthop_search(
479 &rp_all
->rp
.source_nexthop
, &nht_p
,
481 return PIM_RP_NO_PATH
;
483 if (!pim_ecmp_nexthop_lookup(
484 pim
, &rp_all
->rp
.source_nexthop
,
485 &nht_p
, &rp_all
->group
, 1))
486 return PIM_RP_NO_PATH
;
488 pim_rp_check_interfaces(pim
, rp_all
);
489 pim_rp_refresh_group_to_rp_mapping(pim
);
494 * Return if the group is already configured for this RP
496 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
498 XFREE(MTYPE_PIM_RP
, rp_info
);
503 * Barf if this group is already covered by some other RP
505 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
508 if (tmp_rp_info
->plist
) {
509 XFREE(MTYPE_PIM_RP
, rp_info
);
510 return PIM_GROUP_PFXLIST_OVERLAP
;
513 * If the only RP that covers this group is an
515 * 224.0.0.0/4 that is fine, ignore that one.
517 * though we must return PIM_GROUP_OVERLAP
519 if (prefix_same(&rp_info
->group
,
520 &tmp_rp_info
->group
)) {
521 XFREE(MTYPE_PIM_RP
, rp_info
);
522 return PIM_GROUP_OVERLAP
;
528 listnode_add_sort(pim
->rp_list
, rp_info
);
529 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
532 if (PIM_DEBUG_TRACE
) {
533 char buf
[PREFIX_STRLEN
];
535 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
537 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
541 /* Register addr with Zebra NHT */
542 nht_p
.family
= AF_INET
;
543 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
544 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
545 if (PIM_DEBUG_PIM_NHT_RP
) {
546 char buf
[PREFIX2STR_BUFFER
];
547 char buf1
[PREFIX2STR_BUFFER
];
548 prefix2str(&nht_p
, buf
, sizeof(buf
));
549 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
550 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
551 __PRETTY_FUNCTION__
, buf
, buf1
);
554 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
555 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
556 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
557 &rp_info
->rp
.source_nexthop
,
558 &nht_p
, &rp_info
->group
, 1))
559 return PIM_RP_NO_PATH
;
561 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
562 &nht_p
, &rp_info
->group
, 1))
563 return PIM_RP_NO_PATH
;
566 pim_rp_check_interfaces(pim
, rp_info
);
567 pim_rp_refresh_group_to_rp_mapping(pim
);
571 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
572 const char *group_range
, const char *plist
)
575 struct in_addr rp_addr
;
577 struct rp_info
*rp_info
;
578 struct rp_info
*rp_all
;
581 struct route_node
*rn
;
582 bool was_plist
= false;
584 if (group_range
== NULL
)
585 result
= str2prefix("224.0.0.0/4", &group
);
587 result
= str2prefix(group_range
, &group
);
590 return PIM_GROUP_BAD_ADDRESS
;
592 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
594 return PIM_RP_BAD_ADDRESS
;
597 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
599 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
602 return PIM_RP_NOT_FOUND
;
604 if (rp_info
->plist
) {
605 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
609 /* Deregister addr with Zebra NHT */
610 nht_p
.family
= AF_INET
;
611 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
612 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
613 if (PIM_DEBUG_PIM_NHT_RP
) {
614 char buf
[PREFIX2STR_BUFFER
];
615 prefix2str(&nht_p
, buf
, sizeof(buf
));
616 zlog_debug("%s: Deregister RP addr %s with Zebra ",
617 __PRETTY_FUNCTION__
, buf
);
619 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
621 if (!str2prefix("224.0.0.0/4", &g_all
))
622 return PIM_RP_BAD_ADDRESS
;
624 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
626 if (rp_all
== rp_info
) {
627 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
628 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
633 listnode_delete(pim
->rp_list
, rp_info
);
636 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
638 if (rn
->info
!= rp_info
)
639 zlog_err("WTF matey");
641 if (PIM_DEBUG_TRACE
) {
642 char buf
[PREFIX_STRLEN
];
645 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
646 __PRETTY_FUNCTION__
, rn
, rp_info
,
647 prefix2str(&rp_info
->group
, buf
,
652 route_unlock_node(rn
);
653 route_unlock_node(rn
);
657 pim_rp_refresh_group_to_rp_mapping(pim
);
659 XFREE(MTYPE_PIM_RP
, rp_info
);
663 void pim_rp_setup(struct pim_instance
*pim
)
665 struct listnode
*node
;
666 struct rp_info
*rp_info
;
668 struct pim_nexthop_cache pnc
;
670 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
671 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
674 nht_p
.family
= AF_INET
;
675 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
676 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
677 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
678 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
679 pim_ecmp_nexthop_search(pim
, &pnc
,
680 &rp_info
->rp
.source_nexthop
,
681 &nht_p
, &rp_info
->group
, 1);
683 if (PIM_DEBUG_PIM_NHT_RP
) {
684 char buf
[PREFIX2STR_BUFFER
];
685 prefix2str(&nht_p
, buf
, sizeof(buf
));
687 "%s: NHT Local Nexthop not found for RP %s ",
688 __PRETTY_FUNCTION__
, buf
);
690 if (!pim_ecmp_nexthop_lookup(pim
,
691 &rp_info
->rp
.source_nexthop
,
692 &nht_p
, &rp_info
->group
, 1))
693 if (PIM_DEBUG_PIM_NHT_RP
)
695 "Unable to lookup nexthop for rp specified");
701 * Checks to see if we should elect ourself the actual RP when new if
702 * addresses are added against an interface.
704 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
706 struct listnode
*node
;
707 struct rp_info
*rp_info
;
708 bool i_am_rp_changed
= false;
709 struct pim_instance
*pim
= pim_ifp
->pim
;
711 if (pim
->rp_list
== NULL
)
714 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
715 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
718 /* if i_am_rp is already set nothing to be done (adding new
720 * is not going to make a difference). */
721 if (rp_info
->i_am_rp
) {
725 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
726 i_am_rp_changed
= true;
727 rp_info
->i_am_rp
= 1;
728 if (PIM_DEBUG_PIM_NHT_RP
) {
729 char rp
[PREFIX_STRLEN
];
730 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
732 zlog_debug("%s: %s: i am rp", __func__
, rp
);
737 if (i_am_rp_changed
) {
738 pim_msdp_i_am_rp_changed(pim
);
742 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
743 * are removed. Removing numbers is an uncommon event in an active network
744 * so I have made no attempt to optimize it. */
745 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
747 struct listnode
*node
;
748 struct rp_info
*rp_info
;
749 bool i_am_rp_changed
= false;
752 if (pim
->rp_list
== NULL
)
755 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
756 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
759 old_i_am_rp
= rp_info
->i_am_rp
;
760 pim_rp_check_interfaces(pim
, rp_info
);
762 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
763 i_am_rp_changed
= true;
764 if (PIM_DEBUG_PIM_NHT_RP
) {
765 char rp
[PREFIX_STRLEN
];
766 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
768 if (rp_info
->i_am_rp
) {
769 zlog_debug("%s: %s: i am rp", __func__
,
772 zlog_debug("%s: %s: i am no longer rp",
779 if (i_am_rp_changed
) {
780 pim_msdp_i_am_rp_changed(pim
);
785 * I_am_RP(G) is true if the group-to-RP mapping indicates that
786 * this router is the RP for the group.
788 * Since we only have static RP, all groups are part of this RP
790 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
793 struct rp_info
*rp_info
;
795 memset(&g
, 0, sizeof(g
));
800 rp_info
= pim_rp_find_match_group(pim
, &g
);
803 return rp_info
->i_am_rp
;
811 * Return the RP that the Group belongs too.
813 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
816 struct rp_info
*rp_info
;
818 memset(&g
, 0, sizeof(g
));
823 rp_info
= pim_rp_find_match_group(pim
, &g
);
827 struct pim_nexthop_cache pnc
;
828 /* Register addr with Zebra NHT */
829 nht_p
.family
= AF_INET
;
830 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
831 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
832 if (PIM_DEBUG_PIM_NHT_RP
) {
833 char buf
[PREFIX2STR_BUFFER
];
834 char buf1
[PREFIX2STR_BUFFER
];
835 prefix2str(&nht_p
, buf
, sizeof(buf
));
836 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
838 "%s: NHT Register RP addr %s grp %s with Zebra",
839 __PRETTY_FUNCTION__
, buf
, buf1
);
841 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
842 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
843 pim_ecmp_nexthop_search(pim
, &pnc
,
844 &rp_info
->rp
.source_nexthop
,
845 &nht_p
, &rp_info
->group
, 1);
847 if (PIM_DEBUG_PIM_NHT_RP
) {
848 char buf
[PREFIX2STR_BUFFER
];
849 char buf1
[PREFIX2STR_BUFFER
];
850 prefix2str(&nht_p
, buf
, sizeof(buf
));
851 prefix2str(&g
, buf1
, sizeof(buf1
));
853 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
854 __PRETTY_FUNCTION__
, buf
, buf1
);
856 pim_rpf_set_refresh_time(pim
);
857 (void)pim_ecmp_nexthop_lookup(
858 pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
861 return (&rp_info
->rp
);
869 * Set the upstream IP address we want to talk to based upon
870 * the rp configured and the source address
872 * If we have don't have a RP configured and the source address is *
873 * then return failure.
876 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
877 struct in_addr source
, struct in_addr group
)
879 struct rp_info
*rp_info
;
882 memset(&g
, 0, sizeof(g
));
887 rp_info
= pim_rp_find_match_group(pim
, &g
);
889 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
890 && (source
.s_addr
== INADDR_ANY
)) {
891 if (PIM_DEBUG_PIM_NHT_RP
)
892 zlog_debug("%s: Received a (*,G) with no RP configured",
893 __PRETTY_FUNCTION__
);
897 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
903 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
906 struct listnode
*node
;
907 struct rp_info
*rp_info
;
909 char group_buffer
[32];
912 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
913 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
917 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
919 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
923 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
925 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
927 prefix2str(&rp_info
->group
, group_buffer
, 32));
934 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
935 struct in_addr group
,
936 struct in_addr dest_addr
)
938 struct rp_info
*rp_info
;
941 memset(&g
, 0, sizeof(g
));
946 rp_info
= pim_rp_find_match_group(pim
, &g
);
948 * See if we can short-cut some?
949 * This might not make sense if we ever leave a static RP
950 * type of configuration.
951 * Note - Premature optimization might bite our patooeys' here.
953 if (I_am_RP(pim
, group
)) {
954 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
958 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
964 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
,
967 struct rp_info
*rp_info
;
968 struct rp_info
*prev_rp_info
= NULL
;
969 struct listnode
*node
;
971 json_object
*json
= NULL
;
972 json_object
*json_rp_rows
= NULL
;
973 json_object
*json_row
= NULL
;
976 json
= json_object_new_object();
979 "RP address group/prefix-list OIF I am RP\n");
981 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
982 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
987 * If we have moved on to a new RP then add the
988 * entry for the previous RP
991 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
993 != rp_info
->rp
.rpf_addr
.u
.prefix4
995 json_object_object_add(
997 inet_ntoa(prev_rp_info
->rp
1001 json_rp_rows
= NULL
;
1005 json_rp_rows
= json_object_new_array();
1007 json_row
= json_object_new_object();
1008 if (rp_info
->rp
.source_nexthop
.interface
)
1009 json_object_string_add(
1010 json_row
, "outboundInterface",
1011 rp_info
->rp
.source_nexthop
1014 if (rp_info
->i_am_rp
)
1015 json_object_boolean_true_add(json_row
,
1019 json_object_string_add(json_row
,
1023 json_object_string_add(
1025 prefix2str(&rp_info
->group
, buf
,
1028 json_object_array_add(json_rp_rows
, json_row
);
1030 vty_out(vty
, "%-15s ",
1031 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1035 vty_out(vty
, "%-18s ", rp_info
->plist
);
1037 vty_out(vty
, "%-18s ",
1038 prefix2str(&rp_info
->group
, buf
,
1041 if (rp_info
->rp
.source_nexthop
.interface
)
1042 vty_out(vty
, "%-10s ",
1043 rp_info
->rp
.source_nexthop
1046 vty_out(vty
, "%-10s ", "(Unknown)");
1048 if (rp_info
->i_am_rp
)
1049 vty_out(vty
, "yes\n");
1051 vty_out(vty
, "no\n");
1054 prev_rp_info
= rp_info
;
1059 if (prev_rp_info
&& json_rp_rows
)
1060 json_object_object_add(
1062 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1065 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1066 json
, JSON_C_TO_STRING_PRETTY
));
1067 json_object_free(json
);
1071 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1073 struct listnode
*node
= NULL
;
1074 struct rp_info
*rp_info
= NULL
;
1075 struct nexthop
*nh_node
= NULL
;
1076 struct prefix nht_p
;
1077 struct pim_nexthop_cache pnc
;
1078 struct pim_neighbor
*nbr
= NULL
;
1080 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1081 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1084 nht_p
.family
= AF_INET
;
1085 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1086 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1087 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1088 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1092 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1093 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1096 struct interface
*ifp1
= if_lookup_by_index(
1097 nh_node
->ifindex
, pim
->vrf_id
);
1098 nbr
= pim_neighbor_find_if(ifp1
);
1102 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1103 if (PIM_DEBUG_PIM_NHT_RP
) {
1104 char str
[PREFIX_STRLEN
];
1105 char str1
[INET_ADDRSTRLEN
];
1106 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1107 str1
, sizeof(str1
));
1108 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1111 "%s: addr %s new nexthop addr %s interface %s",
1112 __PRETTY_FUNCTION__
, str
, str1
,