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
37 #include "pim_iface.h"
42 #include "pim_memory.h"
43 #include "pim_iface.h"
48 static struct list
*qpim_rp_list
= NULL
;
49 static struct rp_info
*tail
= NULL
;
51 /* Cleanup pim->rpf_hash each node data */
52 void pim_rp_list_hash_clean(void *data
)
54 struct pim_nexthop_cache
*pnc
;
56 pnc
= (struct pim_nexthop_cache
*)data
;
57 if (pnc
->rp_list
->count
)
58 list_delete_all_node(pnc
->rp_list
);
59 if (pnc
->upstream_list
->count
)
60 list_delete_all_node(pnc
->upstream_list
);
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(void)
98 struct rp_info
*rp_info
;
100 qpim_rp_list
= list_new();
101 qpim_rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
102 qpim_rp_list
->cmp
= pim_rp_list_cmp
;
104 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
109 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
110 XFREE(MTYPE_PIM_RP
, rp_info
);
113 rp_info
->group
.family
= AF_INET
;
114 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
115 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
116 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
119 listnode_add(qpim_rp_list
, rp_info
);
122 void pim_rp_free(void)
125 list_delete(qpim_rp_list
);
130 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
132 static struct rp_info
*pim_rp_find_prefix_list(struct in_addr rp
,
135 struct listnode
*node
;
136 struct rp_info
*rp_info
;
138 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
139 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
140 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
149 * Return true if plist is used by any rp_info
151 static int pim_rp_prefix_list_used(const char *plist
)
153 struct listnode
*node
;
154 struct rp_info
*rp_info
;
156 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
157 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
166 * Given an RP's address, return the RP's rp_info that is an exact match for
169 static struct rp_info
*pim_rp_find_exact(struct in_addr rp
,
170 struct prefix
*group
)
172 struct listnode
*node
;
173 struct rp_info
*rp_info
;
175 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
176 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
177 && prefix_same(&rp_info
->group
, group
))
185 * Given a group, return the rp_info for that group
187 static struct rp_info
*pim_rp_find_match_group(struct prefix
*group
)
189 struct listnode
*node
;
190 struct rp_info
*rp_info
;
191 struct prefix_list
*plist
;
193 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
194 if (rp_info
->plist
) {
195 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
198 && prefix_list_apply(plist
, group
) == PREFIX_PERMIT
)
201 if (prefix_match(&rp_info
->group
, group
))
210 * When the user makes "ip pim rp" configuration changes or if they change the
211 * prefix-list(s) used by these statements we must tickle the upstream state
212 * for each group to make them re-lookup who their RP should be.
214 * This is a placeholder function for now.
216 static void pim_rp_refresh_group_to_rp_mapping()
218 pim_msdp_i_am_rp_changed();
221 void pim_rp_prefix_list_update(struct prefix_list
*plist
)
223 struct listnode
*node
;
224 struct rp_info
*rp_info
;
225 int refresh_needed
= 0;
227 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
229 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
236 pim_rp_refresh_group_to_rp_mapping();
239 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
240 struct pim_interface
*pim_ifp
)
242 struct listnode
*node
;
243 struct pim_secondary_addr
*sec_addr
;
245 if (pim_ifp
->primary_address
.s_addr
246 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
249 if (!pim_ifp
->sec_addr_list
) {
253 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
254 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
262 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
263 struct rp_info
*rp_info
)
265 struct listnode
*node
;
266 struct interface
*ifp
;
268 rp_info
->i_am_rp
= 0;
269 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, ifp
)) {
270 struct pim_interface
*pim_ifp
= ifp
->info
;
275 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
276 rp_info
->i_am_rp
= 1;
281 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
282 const char *group_range
, const char *plist
)
285 struct rp_info
*rp_info
;
286 struct rp_info
*rp_all
;
287 struct prefix group_all
;
288 struct listnode
*node
, *nnode
;
289 struct rp_info
*tmp_rp_info
;
292 struct pim_nexthop_cache pnc
;
294 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
296 return PIM_MALLOC_FAIL
;
298 if (group_range
== NULL
)
299 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
301 result
= str2prefix(group_range
, &rp_info
->group
);
304 XFREE(MTYPE_PIM_RP
, rp_info
);
305 return PIM_GROUP_BAD_ADDRESS
;
308 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
309 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
310 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
311 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
314 XFREE(MTYPE_PIM_RP
, rp_info
);
315 return PIM_RP_BAD_ADDRESS
;
320 * Return if the prefix-list is already configured for this RP
322 if (pim_rp_find_prefix_list(rp_info
->rp
.rpf_addr
.u
.prefix4
,
324 XFREE(MTYPE_PIM_RP
, rp_info
);
329 * Barf if the prefix-list is already configured for an RP
331 if (pim_rp_prefix_list_used(plist
)) {
332 XFREE(MTYPE_PIM_RP
, rp_info
);
333 return PIM_RP_PFXLIST_IN_USE
;
337 * Free any existing rp_info entries for this RP
339 for (ALL_LIST_ELEMENTS(qpim_rp_list
, node
, nnode
,
341 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
342 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
343 if (tmp_rp_info
->plist
)
344 pim_rp_del(pim
, rp
, NULL
,
349 prefix2str(&tmp_rp_info
->group
,
355 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
357 if (!str2prefix("224.0.0.0/4", &group_all
)) {
358 XFREE(MTYPE_PIM_RP
, rp_info
);
359 return PIM_GROUP_BAD_ADDRESS
;
361 rp_all
= pim_rp_find_match_group(&group_all
);
364 * Barf if group is a non-multicast subnet
366 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
367 XFREE(MTYPE_PIM_RP
, rp_info
);
368 return PIM_GROUP_BAD_ADDRESS
;
372 * Remove any prefix-list rp_info entries for this RP
374 for (ALL_LIST_ELEMENTS(qpim_rp_list
, node
, nnode
,
376 if (tmp_rp_info
->plist
377 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
378 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
380 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
385 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
387 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
388 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
389 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
390 XFREE(MTYPE_PIM_RP
, rp_info
);
392 /* Register addr with Zebra NHT */
393 nht_p
.family
= AF_INET
;
394 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
396 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
397 if (PIM_DEBUG_PIM_TRACE
) {
398 char buf
[PREFIX2STR_BUFFER
];
399 char buf1
[PREFIX2STR_BUFFER
];
400 prefix2str(&nht_p
, buf
, sizeof(buf
));
401 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
403 "%s: NHT Register rp_all addr %s grp %s ",
404 __PRETTY_FUNCTION__
, buf
, buf1
);
406 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
407 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
409 if (!pim_ecmp_nexthop_search(
411 &rp_all
->rp
.source_nexthop
, &nht_p
,
413 return PIM_RP_NO_PATH
;
415 if (pim_nexthop_lookup(
416 &rp_all
->rp
.source_nexthop
,
417 rp_all
->rp
.rpf_addr
.u
.prefix4
, 1)
419 return PIM_RP_NO_PATH
;
421 pim_rp_check_interfaces(pim
, rp_all
);
422 pim_rp_refresh_group_to_rp_mapping();
427 * Return if the group is already configured for this RP
429 if (pim_rp_find_exact(rp_info
->rp
.rpf_addr
.u
.prefix4
,
431 XFREE(MTYPE_PIM_RP
, rp_info
);
436 * Barf if this group is already covered by some other RP
438 tmp_rp_info
= pim_rp_find_match_group(&rp_info
->group
);
441 if (tmp_rp_info
->plist
) {
442 XFREE(MTYPE_PIM_RP
, rp_info
);
443 return PIM_GROUP_PFXLIST_OVERLAP
;
446 * If the only RP that covers this group is an
448 * 224.0.0.0/4 that is fine, ignore that one.
450 * though we must return PIM_GROUP_OVERLAP
452 if (!prefix_same(&group_all
,
453 &tmp_rp_info
->group
)) {
454 XFREE(MTYPE_PIM_RP
, rp_info
);
455 return PIM_GROUP_OVERLAP
;
461 listnode_add_sort(qpim_rp_list
, rp_info
);
463 /* Register addr with Zebra NHT */
464 nht_p
.family
= AF_INET
;
465 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
466 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
467 if (PIM_DEBUG_PIM_TRACE
) {
468 char buf
[PREFIX2STR_BUFFER
];
469 char buf1
[PREFIX2STR_BUFFER
];
470 prefix2str(&nht_p
, buf
, sizeof(buf
));
471 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
472 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
473 __PRETTY_FUNCTION__
, buf
, buf1
);
476 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
477 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
478 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
479 &rp_info
->rp
.source_nexthop
,
480 &nht_p
, &rp_info
->group
, 1))
481 return PIM_RP_NO_PATH
;
483 if (pim_nexthop_lookup(&rp_info
->rp
.source_nexthop
,
484 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1)
486 return PIM_RP_NO_PATH
;
489 pim_rp_check_interfaces(pim
, rp_info
);
490 pim_rp_refresh_group_to_rp_mapping();
494 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
495 const char *group_range
, const char *plist
)
498 struct in_addr rp_addr
;
500 struct rp_info
*rp_info
;
501 struct rp_info
*rp_all
;
505 if (group_range
== NULL
)
506 result
= str2prefix("224.0.0.0/4", &group
);
508 result
= str2prefix(group_range
, &group
);
511 return PIM_GROUP_BAD_ADDRESS
;
513 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
515 return PIM_RP_BAD_ADDRESS
;
518 rp_info
= pim_rp_find_prefix_list(rp_addr
, plist
);
520 rp_info
= pim_rp_find_exact(rp_addr
, &group
);
523 return PIM_RP_NOT_FOUND
;
525 if (rp_info
->plist
) {
526 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
527 rp_info
->plist
= NULL
;
530 /* Deregister addr with Zebra NHT */
531 nht_p
.family
= AF_INET
;
532 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
533 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
534 if (PIM_DEBUG_PIM_TRACE
) {
535 char buf
[PREFIX2STR_BUFFER
];
536 prefix2str(&nht_p
, buf
, sizeof(buf
));
537 zlog_debug("%s: Deregister RP addr %s with Zebra ",
538 __PRETTY_FUNCTION__
, buf
);
540 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
542 str2prefix("224.0.0.0/4", &g_all
);
543 rp_all
= pim_rp_find_match_group(&g_all
);
545 if (rp_all
== rp_info
) {
546 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
547 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
552 listnode_delete(qpim_rp_list
, rp_info
);
553 pim_rp_refresh_group_to_rp_mapping();
557 void pim_rp_setup(struct pim_instance
*pim
)
559 struct listnode
*node
;
560 struct rp_info
*rp_info
;
562 struct pim_nexthop_cache pnc
;
564 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
565 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
568 nht_p
.family
= AF_INET
;
569 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
570 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
571 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
572 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
573 pim_ecmp_nexthop_search(pim
, &pnc
,
574 &rp_info
->rp
.source_nexthop
,
575 &nht_p
, &rp_info
->group
, 1);
577 if (PIM_DEBUG_ZEBRA
) {
578 char buf
[PREFIX2STR_BUFFER
];
579 prefix2str(&nht_p
, buf
, sizeof(buf
));
581 "%s: NHT Local Nexthop not found for RP %s ",
582 __PRETTY_FUNCTION__
, buf
);
584 if (pim_nexthop_lookup(&rp_info
->rp
.source_nexthop
,
585 rp_info
->rp
.rpf_addr
.u
.prefix4
,
588 if (PIM_DEBUG_PIM_TRACE
)
590 "Unable to lookup nexthop for rp specified");
596 * Checks to see if we should elect ourself the actual RP when new if
597 * addresses are added against an interface.
599 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
601 struct listnode
*node
;
602 struct rp_info
*rp_info
;
603 bool i_am_rp_changed
= false;
605 if (qpim_rp_list
== NULL
)
608 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
609 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
612 /* if i_am_rp is already set nothing to be done (adding new
614 * is not going to make a difference). */
615 if (rp_info
->i_am_rp
) {
619 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
620 i_am_rp_changed
= true;
621 rp_info
->i_am_rp
= 1;
622 if (PIM_DEBUG_ZEBRA
) {
623 char rp
[PREFIX_STRLEN
];
624 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
626 zlog_debug("%s: %s: i am rp", __func__
, rp
);
631 if (i_am_rp_changed
) {
632 pim_msdp_i_am_rp_changed();
636 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
637 * are removed. Removing numbers is an uncommon event in an active network
638 * so I have made no attempt to optimize it. */
639 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
641 struct listnode
*node
;
642 struct rp_info
*rp_info
;
643 bool i_am_rp_changed
= false;
646 if (qpim_rp_list
== NULL
)
649 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
650 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
653 old_i_am_rp
= rp_info
->i_am_rp
;
654 pim_rp_check_interfaces(pim
, rp_info
);
656 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
657 i_am_rp_changed
= true;
658 if (PIM_DEBUG_ZEBRA
) {
659 char rp
[PREFIX_STRLEN
];
660 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
662 if (rp_info
->i_am_rp
) {
663 zlog_debug("%s: %s: i am rp", __func__
,
666 zlog_debug("%s: %s: i am no longer rp",
673 if (i_am_rp_changed
) {
674 pim_msdp_i_am_rp_changed();
679 * I_am_RP(G) is true if the group-to-RP mapping indicates that
680 * this router is the RP for the group.
682 * Since we only have static RP, all groups are part of this RP
684 int pim_rp_i_am_rp(struct in_addr group
)
687 struct rp_info
*rp_info
;
689 memset(&g
, 0, sizeof(g
));
694 rp_info
= pim_rp_find_match_group(&g
);
697 return rp_info
->i_am_rp
;
705 * Return the RP that the Group belongs too.
707 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
710 struct rp_info
*rp_info
;
712 memset(&g
, 0, sizeof(g
));
717 rp_info
= pim_rp_find_match_group(&g
);
721 struct pim_nexthop_cache pnc
;
722 /* Register addr with Zebra NHT */
723 nht_p
.family
= AF_INET
;
724 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
725 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
726 if (PIM_DEBUG_PIM_TRACE
) {
727 char buf
[PREFIX2STR_BUFFER
];
728 char buf1
[PREFIX2STR_BUFFER
];
729 prefix2str(&nht_p
, buf
, sizeof(buf
));
730 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
732 "%s: NHT Register RP addr %s grp %s with Zebra",
733 __PRETTY_FUNCTION__
, buf
, buf1
);
735 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
736 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
737 pim_ecmp_nexthop_search(pim
, &pnc
,
738 &rp_info
->rp
.source_nexthop
,
739 &nht_p
, &rp_info
->group
, 1);
741 if (PIM_DEBUG_ZEBRA
) {
742 char buf
[PREFIX2STR_BUFFER
];
743 char buf1
[PREFIX2STR_BUFFER
];
744 prefix2str(&nht_p
, buf
, sizeof(buf
));
745 prefix2str(&g
, buf1
, sizeof(buf1
));
747 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
748 __PRETTY_FUNCTION__
, buf
, buf1
);
750 pim_rpf_set_refresh_time();
751 pim_nexthop_lookup(&rp_info
->rp
.source_nexthop
,
752 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1);
754 return (&rp_info
->rp
);
762 * Set the upstream IP address we want to talk to based upon
763 * the rp configured and the source address
765 * If we have don't have a RP configured and the source address is *
766 * then return failure.
769 int pim_rp_set_upstream_addr(struct in_addr
*up
, struct in_addr source
,
770 struct in_addr group
)
772 struct rp_info
*rp_info
;
775 memset(&g
, 0, sizeof(g
));
780 rp_info
= pim_rp_find_match_group(&g
);
782 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
783 && (source
.s_addr
== INADDR_ANY
)) {
784 if (PIM_DEBUG_PIM_TRACE
)
785 zlog_debug("%s: Received a (*,G) with no RP configured",
786 __PRETTY_FUNCTION__
);
790 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
796 int pim_rp_config_write(struct vty
*vty
)
798 struct listnode
*node
;
799 struct rp_info
*rp_info
;
801 char group_buffer
[32];
804 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
805 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
809 vty_out(vty
, "ip pim rp %s prefix-list %s\n",
811 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
815 vty_out(vty
, "ip pim rp %s %s\n",
817 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
819 prefix2str(&rp_info
->group
, group_buffer
, 32));
826 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
827 struct in_addr group
,
828 struct in_addr dest_addr
)
830 struct rp_info
*rp_info
;
833 memset(&g
, 0, sizeof(g
));
838 rp_info
= pim_rp_find_match_group(&g
);
840 * See if we can short-cut some?
841 * This might not make sense if we ever leave a static RP
842 * type of configuration.
843 * Note - Premature optimization might bite our patooeys' here.
845 if (I_am_RP(group
)) {
846 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
850 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
856 void pim_rp_show_information(struct vty
*vty
, u_char uj
)
858 struct rp_info
*rp_info
;
859 struct rp_info
*prev_rp_info
= NULL
;
860 struct listnode
*node
;
862 json_object
*json
= NULL
;
863 json_object
*json_rp_rows
= NULL
;
864 json_object
*json_row
= NULL
;
867 json
= json_object_new_object();
870 "RP address group/prefix-list OIF I am RP\n");
872 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
873 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
878 * If we have moved on to a new RP then add the
879 * entry for the previous RP
882 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
884 != rp_info
->rp
.rpf_addr
.u
.prefix4
886 json_object_object_add(
888 inet_ntoa(prev_rp_info
->rp
896 json_rp_rows
= json_object_new_array();
898 json_row
= json_object_new_object();
899 if (rp_info
->rp
.source_nexthop
.interface
)
900 json_object_string_add(
901 json_row
, "outboundInterface",
902 rp_info
->rp
.source_nexthop
905 if (rp_info
->i_am_rp
)
906 json_object_boolean_true_add(json_row
,
910 json_object_string_add(json_row
,
914 json_object_string_add(
916 prefix2str(&rp_info
->group
, buf
,
919 json_object_array_add(json_rp_rows
, json_row
);
921 vty_out(vty
, "%-15s ",
922 inet_ntoa(rp_info
->rp
.rpf_addr
.u
926 vty_out(vty
, "%-18s ", rp_info
->plist
);
928 vty_out(vty
, "%-18s ",
929 prefix2str(&rp_info
->group
, buf
,
932 if (rp_info
->rp
.source_nexthop
.interface
)
933 vty_out(vty
, "%-10s ",
934 rp_info
->rp
.source_nexthop
937 vty_out(vty
, "%-10s ", "(Unknown)");
939 if (rp_info
->i_am_rp
)
940 vty_out(vty
, "yes\n");
942 vty_out(vty
, "no\n");
945 prev_rp_info
= rp_info
;
950 if (prev_rp_info
&& json_rp_rows
)
951 json_object_object_add(
953 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
956 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
957 json
, JSON_C_TO_STRING_PRETTY
));
958 json_object_free(json
);
962 void pim_resolve_rp_nh(struct pim_instance
*pim
)
964 struct listnode
*node
= NULL
;
965 struct rp_info
*rp_info
= NULL
;
966 struct nexthop
*nh_node
= NULL
;
968 struct pim_nexthop_cache pnc
;
969 struct pim_neighbor
*nbr
= NULL
;
971 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list
, node
, rp_info
)) {
972 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
975 nht_p
.family
= AF_INET
;
976 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
977 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
978 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
979 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
983 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
984 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
987 struct interface
*ifp1
= if_lookup_by_index(
988 nh_node
->ifindex
, pim
->vrf_id
);
989 nbr
= pim_neighbor_find_if(ifp1
);
993 nh_node
->gate
.ipv4
= nbr
->source_addr
;
994 if (PIM_DEBUG_TRACE
) {
995 char str
[PREFIX_STRLEN
];
996 char str1
[INET_ADDRSTRLEN
];
997 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
999 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1002 "%s: addr %s new nexthop addr %s interface %s",
1003 __PRETTY_FUNCTION__
, str
, str1
,