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
));
119 zlog_err("Unable to alloc rp_info");
120 route_table_finish(pim
->rp_table
);
121 list_delete_and_null(&pim
->rp_list
);
125 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
126 zlog_err("Unable to convert 224.0.0.0/4 to prefix");
127 list_delete_and_null(&pim
->rp_list
);
128 route_table_finish(pim
->rp_table
);
129 XFREE(MTYPE_PIM_RP
, rp_info
);
132 rp_info
->group
.family
= AF_INET
;
133 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
134 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
135 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
137 listnode_add(pim
->rp_list
, rp_info
);
139 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
141 zlog_err("Failure to get route node for pim->rp_table");
142 list_delete_and_null(&pim
->rp_list
);
143 route_table_finish(pim
->rp_table
);
144 XFREE(MTYPE_PIM_RP
, rp_info
);
150 zlog_debug("Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
151 rn
, rp_info
, rn
->lock
);
154 void pim_rp_free(struct pim_instance
*pim
)
157 list_delete_and_null(&pim
->rp_list
);
161 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
163 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
167 struct listnode
*node
;
168 struct rp_info
*rp_info
;
170 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
171 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
172 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
181 * Return true if plist is used by any rp_info
183 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
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_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
198 * Given an RP's address, return the RP's rp_info that is an exact match for
201 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
203 struct prefix
*group
)
205 struct listnode
*node
;
206 struct rp_info
*rp_info
;
208 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
209 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
210 && prefix_same(&rp_info
->group
, group
))
218 * Given a group, return the rp_info for that group
220 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
221 struct prefix
*group
)
223 struct listnode
*node
;
224 struct rp_info
*best
= NULL
;
225 struct rp_info
*rp_info
;
226 struct prefix_list
*plist
;
227 struct prefix
*p
, *bp
;
228 struct route_node
*rn
;
231 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
232 if (rp_info
->plist
) {
233 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
235 if (prefix_list_apply_which_prefix(plist
, &p
, group
) == PREFIX_DENY
)
244 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
251 rn
= route_node_match(pim
->rp_table
, group
);
253 zlog_err("%s: BUG We should have found default group information\n",
254 __PRETTY_FUNCTION__
);
259 if (PIM_DEBUG_TRACE
) {
260 char buf
[PREFIX_STRLEN
];
262 route_unlock_node(rn
);
263 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d",
265 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
272 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
279 * When the user makes "ip pim rp" configuration changes or if they change the
280 * prefix-list(s) used by these statements we must tickle the upstream state
281 * for each group to make them re-lookup who their RP should be.
283 * This is a placeholder function for now.
285 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
287 pim_msdp_i_am_rp_changed(pim
);
290 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
291 struct prefix_list
*plist
)
293 struct listnode
*node
;
294 struct rp_info
*rp_info
;
295 int refresh_needed
= 0;
297 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
299 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
306 pim_rp_refresh_group_to_rp_mapping(pim
);
309 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
310 struct pim_interface
*pim_ifp
)
312 struct listnode
*node
;
313 struct pim_secondary_addr
*sec_addr
;
315 if (pim_ifp
->primary_address
.s_addr
316 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
319 if (!pim_ifp
->sec_addr_list
) {
323 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
324 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
332 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
333 struct rp_info
*rp_info
)
335 struct interface
*ifp
;
337 rp_info
->i_am_rp
= 0;
338 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
339 struct pim_interface
*pim_ifp
= ifp
->info
;
344 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
345 rp_info
->i_am_rp
= 1;
350 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
351 const char *group_range
, const char *plist
)
354 struct rp_info
*rp_info
;
355 struct rp_info
*rp_all
;
356 struct prefix group_all
;
357 struct listnode
*node
, *nnode
;
358 struct rp_info
*tmp_rp_info
;
361 struct pim_nexthop_cache pnc
;
362 struct route_node
*rn
;
364 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
366 return PIM_MALLOC_FAIL
;
368 if (group_range
== NULL
)
369 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
371 result
= str2prefix(group_range
, &rp_info
->group
);
374 XFREE(MTYPE_PIM_RP
, rp_info
);
375 return PIM_GROUP_BAD_ADDRESS
;
378 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
379 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
380 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
381 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
384 XFREE(MTYPE_PIM_RP
, rp_info
);
385 return PIM_RP_BAD_ADDRESS
;
390 * Return if the prefix-list is already configured for this RP
392 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
394 XFREE(MTYPE_PIM_RP
, rp_info
);
399 * Barf if the prefix-list is already configured for an RP
401 if (pim_rp_prefix_list_used(pim
, plist
)) {
402 XFREE(MTYPE_PIM_RP
, rp_info
);
403 return PIM_RP_PFXLIST_IN_USE
;
407 * Free any existing rp_info entries for this RP
409 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
411 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
412 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
413 if (tmp_rp_info
->plist
)
414 pim_rp_del(pim
, rp
, NULL
,
419 prefix2str(&tmp_rp_info
->group
,
425 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
428 if (!str2prefix("224.0.0.0/4", &group_all
)) {
429 XFREE(MTYPE_PIM_RP
, rp_info
);
430 return PIM_GROUP_BAD_ADDRESS
;
432 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
435 * Barf if group is a non-multicast subnet
437 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
438 XFREE(MTYPE_PIM_RP
, rp_info
);
439 return PIM_GROUP_BAD_ADDRESS
;
443 * Remove any prefix-list rp_info entries for this RP
445 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
447 if (tmp_rp_info
->plist
448 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
449 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
451 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
456 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
458 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
459 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
460 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
461 XFREE(MTYPE_PIM_RP
, rp_info
);
463 /* Register addr with Zebra NHT */
464 nht_p
.family
= AF_INET
;
465 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
467 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
468 if (PIM_DEBUG_PIM_NHT_RP
) {
469 char buf
[PREFIX2STR_BUFFER
];
470 char buf1
[PREFIX2STR_BUFFER
];
471 prefix2str(&nht_p
, buf
, sizeof(buf
));
472 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
474 "%s: NHT Register rp_all addr %s grp %s ",
475 __PRETTY_FUNCTION__
, buf
, buf1
);
477 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
478 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
480 if (!pim_ecmp_nexthop_search(
482 &rp_all
->rp
.source_nexthop
, &nht_p
,
484 return PIM_RP_NO_PATH
;
486 if (pim_nexthop_lookup(
487 pim
, &rp_all
->rp
.source_nexthop
,
488 rp_all
->rp
.rpf_addr
.u
.prefix4
, 1)
490 return PIM_RP_NO_PATH
;
492 pim_rp_check_interfaces(pim
, rp_all
);
493 pim_rp_refresh_group_to_rp_mapping(pim
);
498 * Return if the group is already configured for this RP
500 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
502 XFREE(MTYPE_PIM_RP
, rp_info
);
507 * Barf if this group is already covered by some other RP
509 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
512 if (tmp_rp_info
->plist
) {
513 XFREE(MTYPE_PIM_RP
, rp_info
);
514 return PIM_GROUP_PFXLIST_OVERLAP
;
517 * If the only RP that covers this group is an
519 * 224.0.0.0/4 that is fine, ignore that one.
521 * though we must return PIM_GROUP_OVERLAP
523 if (prefix_same(&rp_info
->group
,
524 &tmp_rp_info
->group
)) {
525 XFREE(MTYPE_PIM_RP
, rp_info
);
526 return PIM_GROUP_OVERLAP
;
532 listnode_add_sort(pim
->rp_list
, rp_info
);
533 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
535 char buf
[PREFIX_STRLEN
];
536 zlog_err("Failure to get route node for pim->rp_table: %s",
537 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)));
538 return PIM_MALLOC_FAIL
;
542 if (PIM_DEBUG_TRACE
) {
543 char buf
[PREFIX_STRLEN
];
545 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d",
547 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
551 /* Register addr with Zebra NHT */
552 nht_p
.family
= AF_INET
;
553 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
554 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
555 if (PIM_DEBUG_PIM_NHT_RP
) {
556 char buf
[PREFIX2STR_BUFFER
];
557 char buf1
[PREFIX2STR_BUFFER
];
558 prefix2str(&nht_p
, buf
, sizeof(buf
));
559 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
560 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
561 __PRETTY_FUNCTION__
, buf
, buf1
);
564 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
565 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
566 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
567 &rp_info
->rp
.source_nexthop
,
568 &nht_p
, &rp_info
->group
, 1))
569 return PIM_RP_NO_PATH
;
571 if (pim_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
572 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1)
574 return PIM_RP_NO_PATH
;
577 pim_rp_check_interfaces(pim
, rp_info
);
578 pim_rp_refresh_group_to_rp_mapping(pim
);
582 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
583 const char *group_range
, const char *plist
)
586 struct in_addr rp_addr
;
588 struct rp_info
*rp_info
;
589 struct rp_info
*rp_all
;
592 struct route_node
*rn
;
593 bool was_plist
= false;
595 if (group_range
== NULL
)
596 result
= str2prefix("224.0.0.0/4", &group
);
598 result
= str2prefix(group_range
, &group
);
601 return PIM_GROUP_BAD_ADDRESS
;
603 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
605 return PIM_RP_BAD_ADDRESS
;
608 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
610 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
613 return PIM_RP_NOT_FOUND
;
615 if (rp_info
->plist
) {
616 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
617 rp_info
->plist
= NULL
;
621 /* Deregister addr with Zebra NHT */
622 nht_p
.family
= AF_INET
;
623 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
624 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
625 if (PIM_DEBUG_PIM_NHT_RP
) {
626 char buf
[PREFIX2STR_BUFFER
];
627 prefix2str(&nht_p
, buf
, sizeof(buf
));
628 zlog_debug("%s: Deregister RP addr %s with Zebra ",
629 __PRETTY_FUNCTION__
, buf
);
631 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
633 if (!str2prefix("224.0.0.0/4", &g_all
))
634 return PIM_RP_BAD_ADDRESS
;
636 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
638 if (rp_all
== rp_info
) {
639 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
640 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
645 listnode_delete(pim
->rp_list
, rp_info
);
648 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
650 if (rn
->info
!= rp_info
)
651 zlog_err("WTF matey");
653 if (PIM_DEBUG_TRACE
) {
654 char buf
[PREFIX_STRLEN
];
656 zlog_debug("%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
659 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
663 route_unlock_node(rn
);
664 route_unlock_node(rn
);
668 pim_rp_refresh_group_to_rp_mapping(pim
);
670 XFREE(MTYPE_PIM_RP
, rp_info
);
674 void pim_rp_setup(struct pim_instance
*pim
)
676 struct listnode
*node
;
677 struct rp_info
*rp_info
;
679 struct pim_nexthop_cache pnc
;
681 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
682 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
685 nht_p
.family
= AF_INET
;
686 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
687 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
688 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
689 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
690 pim_ecmp_nexthop_search(pim
, &pnc
,
691 &rp_info
->rp
.source_nexthop
,
692 &nht_p
, &rp_info
->group
, 1);
694 if (PIM_DEBUG_PIM_NHT_RP
) {
695 char buf
[PREFIX2STR_BUFFER
];
696 prefix2str(&nht_p
, buf
, sizeof(buf
));
698 "%s: NHT Local Nexthop not found for RP %s ",
699 __PRETTY_FUNCTION__
, buf
);
701 if (!pim_nexthop_lookup(
702 pim
, &rp_info
->rp
.source_nexthop
,
703 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1))
704 if (PIM_DEBUG_PIM_NHT_RP
)
706 "Unable to lookup nexthop for rp specified");
712 * Checks to see if we should elect ourself the actual RP when new if
713 * addresses are added against an interface.
715 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
717 struct listnode
*node
;
718 struct rp_info
*rp_info
;
719 bool i_am_rp_changed
= false;
720 struct pim_instance
*pim
= pim_ifp
->pim
;
722 if (pim
->rp_list
== NULL
)
725 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
726 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
729 /* if i_am_rp is already set nothing to be done (adding new
731 * is not going to make a difference). */
732 if (rp_info
->i_am_rp
) {
736 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
737 i_am_rp_changed
= true;
738 rp_info
->i_am_rp
= 1;
739 if (PIM_DEBUG_PIM_NHT_RP
) {
740 char rp
[PREFIX_STRLEN
];
741 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
743 zlog_debug("%s: %s: i am rp", __func__
, rp
);
748 if (i_am_rp_changed
) {
749 pim_msdp_i_am_rp_changed(pim
);
753 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
754 * are removed. Removing numbers is an uncommon event in an active network
755 * so I have made no attempt to optimize it. */
756 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
758 struct listnode
*node
;
759 struct rp_info
*rp_info
;
760 bool i_am_rp_changed
= false;
763 if (pim
->rp_list
== NULL
)
766 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
767 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
770 old_i_am_rp
= rp_info
->i_am_rp
;
771 pim_rp_check_interfaces(pim
, rp_info
);
773 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
774 i_am_rp_changed
= true;
775 if (PIM_DEBUG_PIM_NHT_RP
) {
776 char rp
[PREFIX_STRLEN
];
777 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
779 if (rp_info
->i_am_rp
) {
780 zlog_debug("%s: %s: i am rp", __func__
,
783 zlog_debug("%s: %s: i am no longer rp",
790 if (i_am_rp_changed
) {
791 pim_msdp_i_am_rp_changed(pim
);
796 * I_am_RP(G) is true if the group-to-RP mapping indicates that
797 * this router is the RP for the group.
799 * Since we only have static RP, all groups are part of this RP
801 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
804 struct rp_info
*rp_info
;
806 memset(&g
, 0, sizeof(g
));
811 rp_info
= pim_rp_find_match_group(pim
, &g
);
814 return rp_info
->i_am_rp
;
822 * Return the RP that the Group belongs too.
824 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
827 struct rp_info
*rp_info
;
829 memset(&g
, 0, sizeof(g
));
834 rp_info
= pim_rp_find_match_group(pim
, &g
);
838 struct pim_nexthop_cache pnc
;
839 /* Register addr with Zebra NHT */
840 nht_p
.family
= AF_INET
;
841 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
842 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
843 if (PIM_DEBUG_PIM_NHT_RP
) {
844 char buf
[PREFIX2STR_BUFFER
];
845 char buf1
[PREFIX2STR_BUFFER
];
846 prefix2str(&nht_p
, buf
, sizeof(buf
));
847 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
849 "%s: NHT Register RP addr %s grp %s with Zebra",
850 __PRETTY_FUNCTION__
, buf
, buf1
);
852 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
853 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
854 pim_ecmp_nexthop_search(pim
, &pnc
,
855 &rp_info
->rp
.source_nexthop
,
856 &nht_p
, &rp_info
->group
, 1);
858 if (PIM_DEBUG_PIM_NHT_RP
) {
859 char buf
[PREFIX2STR_BUFFER
];
860 char buf1
[PREFIX2STR_BUFFER
];
861 prefix2str(&nht_p
, buf
, sizeof(buf
));
862 prefix2str(&g
, buf1
, sizeof(buf1
));
864 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
865 __PRETTY_FUNCTION__
, buf
, buf1
);
867 pim_rpf_set_refresh_time();
868 pim_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
869 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1);
871 return (&rp_info
->rp
);
879 * Set the upstream IP address we want to talk to based upon
880 * the rp configured and the source address
882 * If we have don't have a RP configured and the source address is *
883 * then return failure.
886 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
887 struct in_addr source
, struct in_addr group
)
889 struct rp_info
*rp_info
;
892 memset(&g
, 0, sizeof(g
));
897 rp_info
= pim_rp_find_match_group(pim
, &g
);
899 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
900 && (source
.s_addr
== INADDR_ANY
)) {
901 if (PIM_DEBUG_PIM_NHT_RP
)
902 zlog_debug("%s: Received a (*,G) with no RP configured",
903 __PRETTY_FUNCTION__
);
907 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
913 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
916 struct listnode
*node
;
917 struct rp_info
*rp_info
;
919 char group_buffer
[32];
922 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
923 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
927 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
929 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
933 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
935 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
937 prefix2str(&rp_info
->group
, group_buffer
, 32));
944 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
945 struct in_addr group
,
946 struct in_addr dest_addr
)
948 struct rp_info
*rp_info
;
951 memset(&g
, 0, sizeof(g
));
956 rp_info
= pim_rp_find_match_group(pim
, &g
);
958 * See if we can short-cut some?
959 * This might not make sense if we ever leave a static RP
960 * type of configuration.
961 * Note - Premature optimization might bite our patooeys' here.
963 if (I_am_RP(pim
, group
)) {
964 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
968 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
974 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
,
977 struct rp_info
*rp_info
;
978 struct rp_info
*prev_rp_info
= NULL
;
979 struct listnode
*node
;
981 json_object
*json
= NULL
;
982 json_object
*json_rp_rows
= NULL
;
983 json_object
*json_row
= NULL
;
986 json
= json_object_new_object();
989 "RP address group/prefix-list OIF I am RP\n");
991 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
992 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
997 * If we have moved on to a new RP then add the
998 * entry for the previous RP
1001 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1003 != rp_info
->rp
.rpf_addr
.u
.prefix4
1005 json_object_object_add(
1007 inet_ntoa(prev_rp_info
->rp
1011 json_rp_rows
= NULL
;
1015 json_rp_rows
= json_object_new_array();
1017 json_row
= json_object_new_object();
1018 if (rp_info
->rp
.source_nexthop
.interface
)
1019 json_object_string_add(
1020 json_row
, "outboundInterface",
1021 rp_info
->rp
.source_nexthop
1024 if (rp_info
->i_am_rp
)
1025 json_object_boolean_true_add(json_row
,
1029 json_object_string_add(json_row
,
1033 json_object_string_add(
1035 prefix2str(&rp_info
->group
, buf
,
1038 json_object_array_add(json_rp_rows
, json_row
);
1040 vty_out(vty
, "%-15s ",
1041 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1045 vty_out(vty
, "%-18s ", rp_info
->plist
);
1047 vty_out(vty
, "%-18s ",
1048 prefix2str(&rp_info
->group
, buf
,
1051 if (rp_info
->rp
.source_nexthop
.interface
)
1052 vty_out(vty
, "%-10s ",
1053 rp_info
->rp
.source_nexthop
1056 vty_out(vty
, "%-10s ", "(Unknown)");
1058 if (rp_info
->i_am_rp
)
1059 vty_out(vty
, "yes\n");
1061 vty_out(vty
, "no\n");
1064 prev_rp_info
= rp_info
;
1069 if (prev_rp_info
&& json_rp_rows
)
1070 json_object_object_add(
1072 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1075 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1076 json
, JSON_C_TO_STRING_PRETTY
));
1077 json_object_free(json
);
1081 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1083 struct listnode
*node
= NULL
;
1084 struct rp_info
*rp_info
= NULL
;
1085 struct nexthop
*nh_node
= NULL
;
1086 struct prefix nht_p
;
1087 struct pim_nexthop_cache pnc
;
1088 struct pim_neighbor
*nbr
= NULL
;
1090 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1091 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1094 nht_p
.family
= AF_INET
;
1095 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1096 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1097 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1098 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1102 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1103 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1106 struct interface
*ifp1
= if_lookup_by_index(
1107 nh_node
->ifindex
, pim
->vrf_id
);
1108 nbr
= pim_neighbor_find_if(ifp1
);
1112 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1113 if (PIM_DEBUG_PIM_NHT_RP
) {
1114 char str
[PREFIX_STRLEN
];
1115 char str1
[INET_ADDRSTRLEN
];
1116 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1117 str1
, sizeof(str1
));
1118 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1121 "%s: addr %s new nexthop addr %s interface %s",
1122 __PRETTY_FUNCTION__
, str
, str1
,