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
34 #include "lib_errors.h"
39 #include "pim_iface.h"
44 #include "pim_memory.h"
45 #include "pim_iface.h"
50 /* Cleanup pim->rpf_hash each node data */
51 void pim_rp_list_hash_clean(void *data
)
53 struct pim_nexthop_cache
*pnc
= (struct pim_nexthop_cache
*)data
;
55 list_delete(&pnc
->rp_list
);
57 hash_clean(pnc
->upstream_hash
, NULL
);
58 hash_free(pnc
->upstream_hash
);
59 pnc
->upstream_hash
= NULL
;
61 nexthops_free(pnc
->nexthop
);
63 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
66 static void pim_rp_info_free(struct rp_info
*rp_info
)
69 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
71 XFREE(MTYPE_PIM_RP
, rp_info
);
74 int pim_rp_list_cmp(void *v1
, void *v2
)
76 struct rp_info
*rp1
= (struct rp_info
*)v1
;
77 struct rp_info
*rp2
= (struct rp_info
*)v2
;
80 * Sort by RP IP address
82 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
83 < rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
86 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
87 > rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
91 * Sort by group IP address
93 if (rp1
->group
.u
.prefix4
.s_addr
< rp2
->group
.u
.prefix4
.s_addr
)
96 if (rp1
->group
.u
.prefix4
.s_addr
> rp2
->group
.u
.prefix4
.s_addr
)
102 void pim_rp_init(struct pim_instance
*pim
)
104 struct rp_info
*rp_info
;
105 struct route_node
*rn
;
107 pim
->rp_list
= list_new();
108 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
109 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
111 pim
->rp_table
= route_table_init();
113 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
115 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
116 flog_err(EC_LIB_DEVELOPMENT
,
117 "Unable to convert 224.0.0.0/4 to prefix");
118 list_delete(&pim
->rp_list
);
119 route_table_finish(pim
->rp_table
);
120 XFREE(MTYPE_PIM_RP
, rp_info
);
123 rp_info
->group
.family
= AF_INET
;
124 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
125 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
126 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
128 listnode_add(pim
->rp_list
, rp_info
);
130 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
134 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
135 rn
, rp_info
, rn
->lock
);
138 void pim_rp_free(struct pim_instance
*pim
)
141 list_delete(&pim
->rp_list
);
145 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
147 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
151 struct listnode
*node
;
152 struct rp_info
*rp_info
;
154 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
155 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
156 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
165 * Return true if plist is used by any rp_info
167 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
169 struct listnode
*node
;
170 struct rp_info
*rp_info
;
172 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
173 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
182 * Given an RP's address, return the RP's rp_info that is an exact match for
185 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
187 const struct prefix
*group
)
189 struct listnode
*node
;
190 struct rp_info
*rp_info
;
192 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
193 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
194 && prefix_same(&rp_info
->group
, group
))
202 * Given a group, return the rp_info for that group
204 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
205 const struct prefix
*group
)
207 struct listnode
*node
;
208 struct rp_info
*best
= NULL
;
209 struct rp_info
*rp_info
;
210 struct prefix_list
*plist
;
211 const struct prefix
*p
, *bp
;
212 struct route_node
*rn
;
215 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
216 if (rp_info
->plist
) {
217 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
219 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
229 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
236 rn
= route_node_match(pim
->rp_table
, group
);
240 "%s: BUG We should have found default group information\n",
241 __PRETTY_FUNCTION__
);
246 if (PIM_DEBUG_TRACE
) {
247 char buf
[PREFIX_STRLEN
];
249 route_unlock_node(rn
);
250 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
252 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
259 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
266 * When the user makes "ip pim rp" configuration changes or if they change the
267 * prefix-list(s) used by these statements we must tickle the upstream state
268 * for each group to make them re-lookup who their RP should be.
270 * This is a placeholder function for now.
272 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
274 pim_msdp_i_am_rp_changed(pim
);
277 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
278 struct prefix_list
*plist
)
280 struct listnode
*node
;
281 struct rp_info
*rp_info
;
282 int refresh_needed
= 0;
284 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
286 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
293 pim_rp_refresh_group_to_rp_mapping(pim
);
296 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
297 struct pim_interface
*pim_ifp
)
299 struct listnode
*node
;
300 struct pim_secondary_addr
*sec_addr
;
302 if (pim_ifp
->primary_address
.s_addr
303 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
306 if (!pim_ifp
->sec_addr_list
) {
310 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
311 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
319 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
320 struct rp_info
*rp_info
)
322 struct interface
*ifp
;
324 rp_info
->i_am_rp
= 0;
325 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
326 struct pim_interface
*pim_ifp
= ifp
->info
;
331 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
332 rp_info
->i_am_rp
= 1;
337 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
338 const char *group_range
, const char *plist
)
341 struct rp_info
*rp_info
;
342 struct rp_info
*rp_all
;
343 struct prefix group_all
;
344 struct listnode
*node
, *nnode
;
345 struct rp_info
*tmp_rp_info
;
348 struct pim_nexthop_cache pnc
;
349 struct route_node
*rn
;
351 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
353 if (group_range
== NULL
)
354 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
356 result
= str2prefix(group_range
, &rp_info
->group
);
359 XFREE(MTYPE_PIM_RP
, rp_info
);
360 return PIM_GROUP_BAD_ADDRESS
;
363 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
364 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
365 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
366 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
369 XFREE(MTYPE_PIM_RP
, rp_info
);
370 return PIM_RP_BAD_ADDRESS
;
375 * Return if the prefix-list is already configured for this RP
377 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
379 XFREE(MTYPE_PIM_RP
, rp_info
);
384 * Barf if the prefix-list is already configured for an RP
386 if (pim_rp_prefix_list_used(pim
, plist
)) {
387 XFREE(MTYPE_PIM_RP
, rp_info
);
388 return PIM_RP_PFXLIST_IN_USE
;
392 * Free any existing rp_info entries for this RP
394 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
396 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
397 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
398 if (tmp_rp_info
->plist
)
399 pim_rp_del(pim
, rp
, NULL
,
404 prefix2str(&tmp_rp_info
->group
,
410 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
413 if (!str2prefix("224.0.0.0/4", &group_all
)) {
414 XFREE(MTYPE_PIM_RP
, rp_info
);
415 return PIM_GROUP_BAD_ADDRESS
;
417 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
420 * Barf if group is a non-multicast subnet
422 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
423 XFREE(MTYPE_PIM_RP
, rp_info
);
424 return PIM_GROUP_BAD_ADDRESS
;
428 * Remove any prefix-list rp_info entries for this RP
430 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
432 if (tmp_rp_info
->plist
433 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
434 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
436 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
441 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
443 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
444 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
445 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
446 XFREE(MTYPE_PIM_RP
, rp_info
);
448 /* Register addr with Zebra NHT */
449 nht_p
.family
= AF_INET
;
450 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
452 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
453 if (PIM_DEBUG_PIM_NHT_RP
) {
454 char buf
[PREFIX2STR_BUFFER
];
455 char buf1
[PREFIX2STR_BUFFER
];
456 prefix2str(&nht_p
, buf
, sizeof(buf
));
457 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
459 "%s: NHT Register rp_all addr %s grp %s ",
460 __PRETTY_FUNCTION__
, buf
, buf1
);
462 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
463 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
465 if (!pim_ecmp_nexthop_search(
467 &rp_all
->rp
.source_nexthop
, &nht_p
,
469 return PIM_RP_NO_PATH
;
471 if (!pim_ecmp_nexthop_lookup(
472 pim
, &rp_all
->rp
.source_nexthop
,
473 &nht_p
, &rp_all
->group
, 1))
474 return PIM_RP_NO_PATH
;
476 pim_rp_check_interfaces(pim
, rp_all
);
477 pim_rp_refresh_group_to_rp_mapping(pim
);
482 * Return if the group is already configured for this RP
484 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
486 XFREE(MTYPE_PIM_RP
, rp_info
);
491 * Barf if this group is already covered by some other RP
493 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
496 if (tmp_rp_info
->plist
) {
497 XFREE(MTYPE_PIM_RP
, rp_info
);
498 return PIM_GROUP_PFXLIST_OVERLAP
;
501 * If the only RP that covers this group is an
503 * 224.0.0.0/4 that is fine, ignore that one.
505 * though we must return PIM_GROUP_OVERLAP
507 if (prefix_same(&rp_info
->group
,
508 &tmp_rp_info
->group
)) {
509 XFREE(MTYPE_PIM_RP
, rp_info
);
510 return PIM_GROUP_OVERLAP
;
516 listnode_add_sort(pim
->rp_list
, rp_info
);
517 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
520 if (PIM_DEBUG_TRACE
) {
521 char buf
[PREFIX_STRLEN
];
523 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
525 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
529 /* Register addr with Zebra NHT */
530 nht_p
.family
= AF_INET
;
531 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
532 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
533 if (PIM_DEBUG_PIM_NHT_RP
) {
534 char buf
[PREFIX2STR_BUFFER
];
535 char buf1
[PREFIX2STR_BUFFER
];
536 prefix2str(&nht_p
, buf
, sizeof(buf
));
537 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
538 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
539 __PRETTY_FUNCTION__
, buf
, buf1
);
542 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
543 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
544 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
545 &rp_info
->rp
.source_nexthop
,
546 &nht_p
, &rp_info
->group
, 1))
547 return PIM_RP_NO_PATH
;
549 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
550 &nht_p
, &rp_info
->group
, 1))
551 return PIM_RP_NO_PATH
;
554 pim_rp_check_interfaces(pim
, rp_info
);
555 pim_rp_refresh_group_to_rp_mapping(pim
);
559 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
560 const char *group_range
, const char *plist
)
563 struct in_addr rp_addr
;
565 struct rp_info
*rp_info
;
566 struct rp_info
*rp_all
;
569 struct route_node
*rn
;
570 bool was_plist
= false;
572 if (group_range
== NULL
)
573 result
= str2prefix("224.0.0.0/4", &group
);
575 result
= str2prefix(group_range
, &group
);
578 return PIM_GROUP_BAD_ADDRESS
;
580 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
582 return PIM_RP_BAD_ADDRESS
;
585 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
587 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
590 return PIM_RP_NOT_FOUND
;
592 if (rp_info
->plist
) {
593 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
597 /* Deregister addr with Zebra NHT */
598 nht_p
.family
= AF_INET
;
599 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
600 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
601 if (PIM_DEBUG_PIM_NHT_RP
) {
602 char buf
[PREFIX2STR_BUFFER
];
603 prefix2str(&nht_p
, buf
, sizeof(buf
));
604 zlog_debug("%s: Deregister RP addr %s with Zebra ",
605 __PRETTY_FUNCTION__
, buf
);
607 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
609 if (!str2prefix("224.0.0.0/4", &g_all
))
610 return PIM_RP_BAD_ADDRESS
;
612 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
614 if (rp_all
== rp_info
) {
615 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
616 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
621 listnode_delete(pim
->rp_list
, rp_info
);
624 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
626 if (rn
->info
!= rp_info
)
629 "Expected rn->info to be equal to rp_info");
631 if (PIM_DEBUG_TRACE
) {
632 char buf
[PREFIX_STRLEN
];
635 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
636 __PRETTY_FUNCTION__
, rn
, rp_info
,
637 prefix2str(&rp_info
->group
, buf
,
642 route_unlock_node(rn
);
643 route_unlock_node(rn
);
647 pim_rp_refresh_group_to_rp_mapping(pim
);
649 XFREE(MTYPE_PIM_RP
, rp_info
);
653 void pim_rp_setup(struct pim_instance
*pim
)
655 struct listnode
*node
;
656 struct rp_info
*rp_info
;
658 struct pim_nexthop_cache pnc
;
660 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
661 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
664 nht_p
.family
= AF_INET
;
665 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
666 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
667 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
668 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
669 pim_ecmp_nexthop_search(pim
, &pnc
,
670 &rp_info
->rp
.source_nexthop
,
671 &nht_p
, &rp_info
->group
, 1);
673 if (PIM_DEBUG_PIM_NHT_RP
) {
674 char buf
[PREFIX2STR_BUFFER
];
675 prefix2str(&nht_p
, buf
, sizeof(buf
));
677 "%s: NHT Local Nexthop not found for RP %s ",
678 __PRETTY_FUNCTION__
, buf
);
680 if (!pim_ecmp_nexthop_lookup(pim
,
681 &rp_info
->rp
.source_nexthop
,
682 &nht_p
, &rp_info
->group
, 1))
683 if (PIM_DEBUG_PIM_NHT_RP
)
685 "Unable to lookup nexthop for rp specified");
691 * Checks to see if we should elect ourself the actual RP when new if
692 * addresses are added against an interface.
694 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
696 struct listnode
*node
;
697 struct rp_info
*rp_info
;
698 bool i_am_rp_changed
= false;
699 struct pim_instance
*pim
= pim_ifp
->pim
;
701 if (pim
->rp_list
== NULL
)
704 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
705 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
708 /* if i_am_rp is already set nothing to be done (adding new
710 * is not going to make a difference). */
711 if (rp_info
->i_am_rp
) {
715 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
716 i_am_rp_changed
= true;
717 rp_info
->i_am_rp
= 1;
718 if (PIM_DEBUG_PIM_NHT_RP
) {
719 char rp
[PREFIX_STRLEN
];
720 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
722 zlog_debug("%s: %s: i am rp", __func__
, rp
);
727 if (i_am_rp_changed
) {
728 pim_msdp_i_am_rp_changed(pim
);
732 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
733 * are removed. Removing numbers is an uncommon event in an active network
734 * so I have made no attempt to optimize it. */
735 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
737 struct listnode
*node
;
738 struct rp_info
*rp_info
;
739 bool i_am_rp_changed
= false;
742 if (pim
->rp_list
== NULL
)
745 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
746 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
749 old_i_am_rp
= rp_info
->i_am_rp
;
750 pim_rp_check_interfaces(pim
, rp_info
);
752 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
753 i_am_rp_changed
= true;
754 if (PIM_DEBUG_PIM_NHT_RP
) {
755 char rp
[PREFIX_STRLEN
];
756 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
758 if (rp_info
->i_am_rp
) {
759 zlog_debug("%s: %s: i am rp", __func__
,
762 zlog_debug("%s: %s: i am no longer rp",
769 if (i_am_rp_changed
) {
770 pim_msdp_i_am_rp_changed(pim
);
775 * I_am_RP(G) is true if the group-to-RP mapping indicates that
776 * this router is the RP for the group.
778 * Since we only have static RP, all groups are part of this RP
780 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
783 struct rp_info
*rp_info
;
785 memset(&g
, 0, sizeof(g
));
790 rp_info
= pim_rp_find_match_group(pim
, &g
);
793 return rp_info
->i_am_rp
;
801 * Return the RP that the Group belongs too.
803 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
806 struct rp_info
*rp_info
;
808 memset(&g
, 0, sizeof(g
));
813 rp_info
= pim_rp_find_match_group(pim
, &g
);
817 struct pim_nexthop_cache pnc
;
818 /* Register addr with Zebra NHT */
819 nht_p
.family
= AF_INET
;
820 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
821 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
822 if (PIM_DEBUG_PIM_NHT_RP
) {
823 char buf
[PREFIX2STR_BUFFER
];
824 char buf1
[PREFIX2STR_BUFFER
];
825 prefix2str(&nht_p
, buf
, sizeof(buf
));
826 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
828 "%s: NHT Register RP addr %s grp %s with Zebra",
829 __PRETTY_FUNCTION__
, buf
, buf1
);
831 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
832 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
833 pim_ecmp_nexthop_search(pim
, &pnc
,
834 &rp_info
->rp
.source_nexthop
,
835 &nht_p
, &rp_info
->group
, 1);
837 if (PIM_DEBUG_PIM_NHT_RP
) {
838 char buf
[PREFIX2STR_BUFFER
];
839 char buf1
[PREFIX2STR_BUFFER
];
840 prefix2str(&nht_p
, buf
, sizeof(buf
));
841 prefix2str(&g
, buf1
, sizeof(buf1
));
843 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
844 __PRETTY_FUNCTION__
, buf
, buf1
);
846 pim_rpf_set_refresh_time(pim
);
847 (void)pim_ecmp_nexthop_lookup(
848 pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
851 return (&rp_info
->rp
);
859 * Set the upstream IP address we want to talk to based upon
860 * the rp configured and the source address
862 * If we have don't have a RP configured and the source address is *
863 * then return failure.
866 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
867 struct in_addr source
, struct in_addr group
)
869 struct rp_info
*rp_info
;
872 memset(&g
, 0, sizeof(g
));
877 rp_info
= pim_rp_find_match_group(pim
, &g
);
879 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
880 && (source
.s_addr
== INADDR_ANY
)) {
881 if (PIM_DEBUG_PIM_NHT_RP
)
882 zlog_debug("%s: Received a (*,G) with no RP configured",
883 __PRETTY_FUNCTION__
);
887 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
893 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
896 struct listnode
*node
;
897 struct rp_info
*rp_info
;
899 char group_buffer
[32];
902 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
903 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
907 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
909 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
913 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
915 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
917 prefix2str(&rp_info
->group
, group_buffer
, 32));
924 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
925 struct in_addr group
,
926 struct in_addr dest_addr
)
928 struct rp_info
*rp_info
;
931 memset(&g
, 0, sizeof(g
));
936 rp_info
= pim_rp_find_match_group(pim
, &g
);
938 * See if we can short-cut some?
939 * This might not make sense if we ever leave a static RP
940 * type of configuration.
941 * Note - Premature optimization might bite our patooeys' here.
943 if (I_am_RP(pim
, group
)) {
944 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
948 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
954 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
956 struct rp_info
*rp_info
;
957 struct rp_info
*prev_rp_info
= NULL
;
958 struct listnode
*node
;
960 json_object
*json
= NULL
;
961 json_object
*json_rp_rows
= NULL
;
962 json_object
*json_row
= NULL
;
965 json
= json_object_new_object();
968 "RP address group/prefix-list OIF I am RP\n");
970 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
971 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
976 * If we have moved on to a new RP then add the
977 * entry for the previous RP
980 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
982 != rp_info
->rp
.rpf_addr
.u
.prefix4
984 json_object_object_add(
986 inet_ntoa(prev_rp_info
->rp
994 json_rp_rows
= json_object_new_array();
996 json_row
= json_object_new_object();
997 if (rp_info
->rp
.source_nexthop
.interface
)
998 json_object_string_add(
999 json_row
, "outboundInterface",
1000 rp_info
->rp
.source_nexthop
1003 if (rp_info
->i_am_rp
)
1004 json_object_boolean_true_add(json_row
,
1008 json_object_string_add(json_row
,
1012 json_object_string_add(
1014 prefix2str(&rp_info
->group
, buf
,
1017 json_object_array_add(json_rp_rows
, json_row
);
1019 vty_out(vty
, "%-15s ",
1020 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1024 vty_out(vty
, "%-18s ", rp_info
->plist
);
1026 vty_out(vty
, "%-18s ",
1027 prefix2str(&rp_info
->group
, buf
,
1030 if (rp_info
->rp
.source_nexthop
.interface
)
1031 vty_out(vty
, "%-10s ",
1032 rp_info
->rp
.source_nexthop
1035 vty_out(vty
, "%-10s ", "(Unknown)");
1037 if (rp_info
->i_am_rp
)
1038 vty_out(vty
, "yes\n");
1040 vty_out(vty
, "no\n");
1043 prev_rp_info
= rp_info
;
1048 if (prev_rp_info
&& json_rp_rows
)
1049 json_object_object_add(
1051 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1054 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1055 json
, JSON_C_TO_STRING_PRETTY
));
1056 json_object_free(json
);
1060 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1062 struct listnode
*node
= NULL
;
1063 struct rp_info
*rp_info
= NULL
;
1064 struct nexthop
*nh_node
= NULL
;
1065 struct prefix nht_p
;
1066 struct pim_nexthop_cache pnc
;
1067 struct pim_neighbor
*nbr
= NULL
;
1069 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1070 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1073 nht_p
.family
= AF_INET
;
1074 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1075 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1076 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1077 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1081 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1082 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1085 struct interface
*ifp1
= if_lookup_by_index(
1086 nh_node
->ifindex
, pim
->vrf_id
);
1087 nbr
= pim_neighbor_find_if(ifp1
);
1091 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1092 if (PIM_DEBUG_PIM_NHT_RP
) {
1093 char str
[PREFIX_STRLEN
];
1094 char str1
[INET_ADDRSTRLEN
];
1095 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1096 str1
, sizeof(str1
));
1097 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1100 "%s: addr %s new nexthop addr %s interface %s",
1101 __PRETTY_FUNCTION__
, str
, str1
,