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 /* Cleanup pim->rpf_hash each node data */
49 void pim_rp_list_hash_clean(void *data
)
51 struct pim_nexthop_cache
*pnc
= (struct pim_nexthop_cache
*)data
;
53 list_delete(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
;
100 pim
->rp_list
= list_new();
101 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
102 pim
->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
;
118 listnode_add(pim
->rp_list
, rp_info
);
121 void pim_rp_free(struct pim_instance
*pim
)
124 list_delete(pim
->rp_list
);
129 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
131 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
135 struct listnode
*node
;
136 struct rp_info
*rp_info
;
138 for (ALL_LIST_ELEMENTS_RO(pim
->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(struct pim_instance
*pim
, const char *plist
)
153 struct listnode
*node
;
154 struct rp_info
*rp_info
;
156 for (ALL_LIST_ELEMENTS_RO(pim
->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 pim_instance
*pim
,
171 struct prefix
*group
)
173 struct listnode
*node
;
174 struct rp_info
*rp_info
;
176 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
177 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
178 && prefix_same(&rp_info
->group
, group
))
186 * Given a group, return the rp_info for that group
188 static struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
189 struct prefix
*group
)
191 struct listnode
*node
;
192 struct rp_info
*rp_info
;
193 struct prefix_list
*plist
;
195 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
196 if (rp_info
->plist
) {
197 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
200 && prefix_list_apply(plist
, group
) == PREFIX_PERMIT
)
203 if (prefix_match(&rp_info
->group
, group
))
212 * When the user makes "ip pim rp" configuration changes or if they change the
213 * prefix-list(s) used by these statements we must tickle the upstream state
214 * for each group to make them re-lookup who their RP should be.
216 * This is a placeholder function for now.
218 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
220 pim_msdp_i_am_rp_changed(pim
);
223 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
224 struct prefix_list
*plist
)
226 struct listnode
*node
;
227 struct rp_info
*rp_info
;
228 int refresh_needed
= 0;
230 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
232 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
239 pim_rp_refresh_group_to_rp_mapping(pim
);
242 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
243 struct pim_interface
*pim_ifp
)
245 struct listnode
*node
;
246 struct pim_secondary_addr
*sec_addr
;
248 if (pim_ifp
->primary_address
.s_addr
249 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
252 if (!pim_ifp
->sec_addr_list
) {
256 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
257 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
265 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
266 struct rp_info
*rp_info
)
268 struct listnode
*node
;
269 struct interface
*ifp
;
271 rp_info
->i_am_rp
= 0;
272 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim
->vrf_id
), node
, ifp
)) {
273 struct pim_interface
*pim_ifp
= ifp
->info
;
278 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
279 rp_info
->i_am_rp
= 1;
284 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
285 const char *group_range
, const char *plist
)
288 struct rp_info
*rp_info
;
289 struct rp_info
*rp_all
;
290 struct prefix group_all
;
291 struct listnode
*node
, *nnode
;
292 struct rp_info
*tmp_rp_info
;
295 struct pim_nexthop_cache pnc
;
297 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
299 return PIM_MALLOC_FAIL
;
301 if (group_range
== NULL
)
302 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
304 result
= str2prefix(group_range
, &rp_info
->group
);
307 XFREE(MTYPE_PIM_RP
, rp_info
);
308 return PIM_GROUP_BAD_ADDRESS
;
311 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
312 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
313 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
314 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
317 XFREE(MTYPE_PIM_RP
, rp_info
);
318 return PIM_RP_BAD_ADDRESS
;
323 * Return if the prefix-list is already configured for this RP
325 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
327 XFREE(MTYPE_PIM_RP
, rp_info
);
332 * Barf if the prefix-list is already configured for an RP
334 if (pim_rp_prefix_list_used(pim
, plist
)) {
335 XFREE(MTYPE_PIM_RP
, rp_info
);
336 return PIM_RP_PFXLIST_IN_USE
;
340 * Free any existing rp_info entries for this RP
342 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
344 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
345 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
346 if (tmp_rp_info
->plist
)
347 pim_rp_del(pim
, rp
, NULL
,
352 prefix2str(&tmp_rp_info
->group
,
358 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
360 if (!str2prefix("224.0.0.0/4", &group_all
)) {
361 XFREE(MTYPE_PIM_RP
, rp_info
);
362 return PIM_GROUP_BAD_ADDRESS
;
364 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
367 * Barf if group is a non-multicast subnet
369 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
370 XFREE(MTYPE_PIM_RP
, rp_info
);
371 return PIM_GROUP_BAD_ADDRESS
;
375 * Remove any prefix-list rp_info entries for this RP
377 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
379 if (tmp_rp_info
->plist
380 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
381 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
383 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
388 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
390 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
391 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
392 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
393 XFREE(MTYPE_PIM_RP
, rp_info
);
395 /* Register addr with Zebra NHT */
396 nht_p
.family
= AF_INET
;
397 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
399 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
400 if (PIM_DEBUG_PIM_NHT_RP
) {
401 char buf
[PREFIX2STR_BUFFER
];
402 char buf1
[PREFIX2STR_BUFFER
];
403 prefix2str(&nht_p
, buf
, sizeof(buf
));
404 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
406 "%s: NHT Register rp_all addr %s grp %s ",
407 __PRETTY_FUNCTION__
, buf
, buf1
);
409 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
410 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
412 if (!pim_ecmp_nexthop_search(
414 &rp_all
->rp
.source_nexthop
, &nht_p
,
416 return PIM_RP_NO_PATH
;
418 if (pim_nexthop_lookup(
419 pim
, &rp_all
->rp
.source_nexthop
,
420 rp_all
->rp
.rpf_addr
.u
.prefix4
, 1)
422 return PIM_RP_NO_PATH
;
424 pim_rp_check_interfaces(pim
, rp_all
);
425 pim_rp_refresh_group_to_rp_mapping(pim
);
430 * Return if the group is already configured for this RP
432 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
434 XFREE(MTYPE_PIM_RP
, rp_info
);
439 * Barf if this group is already covered by some other RP
441 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
444 if (tmp_rp_info
->plist
) {
445 XFREE(MTYPE_PIM_RP
, rp_info
);
446 return PIM_GROUP_PFXLIST_OVERLAP
;
449 * If the only RP that covers this group is an
451 * 224.0.0.0/4 that is fine, ignore that one.
453 * though we must return PIM_GROUP_OVERLAP
455 if (!prefix_same(&group_all
,
456 &tmp_rp_info
->group
)) {
457 XFREE(MTYPE_PIM_RP
, rp_info
);
458 return PIM_GROUP_OVERLAP
;
464 listnode_add_sort(pim
->rp_list
, rp_info
);
466 /* Register addr with Zebra NHT */
467 nht_p
.family
= AF_INET
;
468 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
469 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
470 if (PIM_DEBUG_PIM_NHT_RP
) {
471 char buf
[PREFIX2STR_BUFFER
];
472 char buf1
[PREFIX2STR_BUFFER
];
473 prefix2str(&nht_p
, buf
, sizeof(buf
));
474 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
475 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
476 __PRETTY_FUNCTION__
, buf
, buf1
);
479 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
480 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
481 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
482 &rp_info
->rp
.source_nexthop
,
483 &nht_p
, &rp_info
->group
, 1))
484 return PIM_RP_NO_PATH
;
486 if (pim_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
487 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1)
489 return PIM_RP_NO_PATH
;
492 pim_rp_check_interfaces(pim
, rp_info
);
493 pim_rp_refresh_group_to_rp_mapping(pim
);
497 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
498 const char *group_range
, const char *plist
)
501 struct in_addr rp_addr
;
503 struct rp_info
*rp_info
;
504 struct rp_info
*rp_all
;
508 if (group_range
== NULL
)
509 result
= str2prefix("224.0.0.0/4", &group
);
511 result
= str2prefix(group_range
, &group
);
514 return PIM_GROUP_BAD_ADDRESS
;
516 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
518 return PIM_RP_BAD_ADDRESS
;
521 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
523 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
526 return PIM_RP_NOT_FOUND
;
528 if (rp_info
->plist
) {
529 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
530 rp_info
->plist
= NULL
;
533 /* Deregister addr with Zebra NHT */
534 nht_p
.family
= AF_INET
;
535 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
536 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
537 if (PIM_DEBUG_PIM_NHT_RP
) {
538 char buf
[PREFIX2STR_BUFFER
];
539 prefix2str(&nht_p
, buf
, sizeof(buf
));
540 zlog_debug("%s: Deregister RP addr %s with Zebra ",
541 __PRETTY_FUNCTION__
, buf
);
543 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
545 if (!str2prefix("224.0.0.0/4", &g_all
))
546 return PIM_RP_BAD_ADDRESS
;
548 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
550 if (rp_all
== rp_info
) {
551 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
552 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
557 listnode_delete(pim
->rp_list
, rp_info
);
558 pim_rp_refresh_group_to_rp_mapping(pim
);
562 void pim_rp_setup(struct pim_instance
*pim
)
564 struct listnode
*node
;
565 struct rp_info
*rp_info
;
567 struct pim_nexthop_cache pnc
;
569 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
570 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
573 nht_p
.family
= AF_INET
;
574 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
575 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
576 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
577 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
578 pim_ecmp_nexthop_search(pim
, &pnc
,
579 &rp_info
->rp
.source_nexthop
,
580 &nht_p
, &rp_info
->group
, 1);
582 if (PIM_DEBUG_PIM_NHT_RP
) {
583 char buf
[PREFIX2STR_BUFFER
];
584 prefix2str(&nht_p
, buf
, sizeof(buf
));
586 "%s: NHT Local Nexthop not found for RP %s ",
587 __PRETTY_FUNCTION__
, buf
);
589 if (!pim_nexthop_lookup(
590 pim
, &rp_info
->rp
.source_nexthop
,
591 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1))
592 if (PIM_DEBUG_PIM_NHT_RP
)
594 "Unable to lookup nexthop for rp specified");
600 * Checks to see if we should elect ourself the actual RP when new if
601 * addresses are added against an interface.
603 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
605 struct listnode
*node
;
606 struct rp_info
*rp_info
;
607 bool i_am_rp_changed
= false;
608 struct pim_instance
*pim
= pim_ifp
->pim
;
610 if (pim
->rp_list
== NULL
)
613 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
614 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
617 /* if i_am_rp is already set nothing to be done (adding new
619 * is not going to make a difference). */
620 if (rp_info
->i_am_rp
) {
624 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
625 i_am_rp_changed
= true;
626 rp_info
->i_am_rp
= 1;
627 if (PIM_DEBUG_PIM_NHT_RP
) {
628 char rp
[PREFIX_STRLEN
];
629 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
631 zlog_debug("%s: %s: i am rp", __func__
, rp
);
636 if (i_am_rp_changed
) {
637 pim_msdp_i_am_rp_changed(pim
);
641 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
642 * are removed. Removing numbers is an uncommon event in an active network
643 * so I have made no attempt to optimize it. */
644 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
646 struct listnode
*node
;
647 struct rp_info
*rp_info
;
648 bool i_am_rp_changed
= false;
651 if (pim
->rp_list
== NULL
)
654 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
655 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
658 old_i_am_rp
= rp_info
->i_am_rp
;
659 pim_rp_check_interfaces(pim
, rp_info
);
661 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
662 i_am_rp_changed
= true;
663 if (PIM_DEBUG_PIM_NHT_RP
) {
664 char rp
[PREFIX_STRLEN
];
665 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
667 if (rp_info
->i_am_rp
) {
668 zlog_debug("%s: %s: i am rp", __func__
,
671 zlog_debug("%s: %s: i am no longer rp",
678 if (i_am_rp_changed
) {
679 pim_msdp_i_am_rp_changed(pim
);
684 * I_am_RP(G) is true if the group-to-RP mapping indicates that
685 * this router is the RP for the group.
687 * Since we only have static RP, all groups are part of this RP
689 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
692 struct rp_info
*rp_info
;
694 memset(&g
, 0, sizeof(g
));
699 rp_info
= pim_rp_find_match_group(pim
, &g
);
702 return rp_info
->i_am_rp
;
710 * Return the RP that the Group belongs too.
712 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
715 struct rp_info
*rp_info
;
717 memset(&g
, 0, sizeof(g
));
722 rp_info
= pim_rp_find_match_group(pim
, &g
);
726 struct pim_nexthop_cache pnc
;
727 /* Register addr with Zebra NHT */
728 nht_p
.family
= AF_INET
;
729 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
730 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
731 if (PIM_DEBUG_PIM_NHT_RP
) {
732 char buf
[PREFIX2STR_BUFFER
];
733 char buf1
[PREFIX2STR_BUFFER
];
734 prefix2str(&nht_p
, buf
, sizeof(buf
));
735 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
737 "%s: NHT Register RP addr %s grp %s with Zebra",
738 __PRETTY_FUNCTION__
, buf
, buf1
);
740 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
741 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
742 pim_ecmp_nexthop_search(pim
, &pnc
,
743 &rp_info
->rp
.source_nexthop
,
744 &nht_p
, &rp_info
->group
, 1);
746 if (PIM_DEBUG_PIM_NHT_RP
) {
747 char buf
[PREFIX2STR_BUFFER
];
748 char buf1
[PREFIX2STR_BUFFER
];
749 prefix2str(&nht_p
, buf
, sizeof(buf
));
750 prefix2str(&g
, buf1
, sizeof(buf1
));
752 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
753 __PRETTY_FUNCTION__
, buf
, buf1
);
755 pim_rpf_set_refresh_time();
756 pim_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
757 rp_info
->rp
.rpf_addr
.u
.prefix4
, 1);
759 return (&rp_info
->rp
);
767 * Set the upstream IP address we want to talk to based upon
768 * the rp configured and the source address
770 * If we have don't have a RP configured and the source address is *
771 * then return failure.
774 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
775 struct in_addr source
, struct in_addr group
)
777 struct rp_info
*rp_info
;
780 memset(&g
, 0, sizeof(g
));
785 rp_info
= pim_rp_find_match_group(pim
, &g
);
787 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
788 && (source
.s_addr
== INADDR_ANY
)) {
789 if (PIM_DEBUG_PIM_NHT_RP
)
790 zlog_debug("%s: Received a (*,G) with no RP configured",
791 __PRETTY_FUNCTION__
);
795 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
801 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
804 struct listnode
*node
;
805 struct rp_info
*rp_info
;
807 char group_buffer
[32];
810 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
811 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
815 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
817 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
821 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
823 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
825 prefix2str(&rp_info
->group
, group_buffer
, 32));
832 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
833 struct in_addr group
,
834 struct in_addr dest_addr
)
836 struct rp_info
*rp_info
;
839 memset(&g
, 0, sizeof(g
));
844 rp_info
= pim_rp_find_match_group(pim
, &g
);
846 * See if we can short-cut some?
847 * This might not make sense if we ever leave a static RP
848 * type of configuration.
849 * Note - Premature optimization might bite our patooeys' here.
851 if (I_am_RP(pim
, group
)) {
852 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
856 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
862 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
,
865 struct rp_info
*rp_info
;
866 struct rp_info
*prev_rp_info
= NULL
;
867 struct listnode
*node
;
869 json_object
*json
= NULL
;
870 json_object
*json_rp_rows
= NULL
;
871 json_object
*json_row
= NULL
;
874 json
= json_object_new_object();
877 "RP address group/prefix-list OIF I am RP\n");
879 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
880 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
885 * If we have moved on to a new RP then add the
886 * entry for the previous RP
889 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
891 != rp_info
->rp
.rpf_addr
.u
.prefix4
893 json_object_object_add(
895 inet_ntoa(prev_rp_info
->rp
903 json_rp_rows
= json_object_new_array();
905 json_row
= json_object_new_object();
906 if (rp_info
->rp
.source_nexthop
.interface
)
907 json_object_string_add(
908 json_row
, "outboundInterface",
909 rp_info
->rp
.source_nexthop
912 if (rp_info
->i_am_rp
)
913 json_object_boolean_true_add(json_row
,
917 json_object_string_add(json_row
,
921 json_object_string_add(
923 prefix2str(&rp_info
->group
, buf
,
926 json_object_array_add(json_rp_rows
, json_row
);
928 vty_out(vty
, "%-15s ",
929 inet_ntoa(rp_info
->rp
.rpf_addr
.u
933 vty_out(vty
, "%-18s ", rp_info
->plist
);
935 vty_out(vty
, "%-18s ",
936 prefix2str(&rp_info
->group
, buf
,
939 if (rp_info
->rp
.source_nexthop
.interface
)
940 vty_out(vty
, "%-10s ",
941 rp_info
->rp
.source_nexthop
944 vty_out(vty
, "%-10s ", "(Unknown)");
946 if (rp_info
->i_am_rp
)
947 vty_out(vty
, "yes\n");
949 vty_out(vty
, "no\n");
952 prev_rp_info
= rp_info
;
957 if (prev_rp_info
&& json_rp_rows
)
958 json_object_object_add(
960 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
963 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
964 json
, JSON_C_TO_STRING_PRETTY
));
965 json_object_free(json
);
969 void pim_resolve_rp_nh(struct pim_instance
*pim
)
971 struct listnode
*node
= NULL
;
972 struct rp_info
*rp_info
= NULL
;
973 struct nexthop
*nh_node
= NULL
;
975 struct pim_nexthop_cache pnc
;
976 struct pim_neighbor
*nbr
= NULL
;
978 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
979 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
982 nht_p
.family
= AF_INET
;
983 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
984 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
985 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
986 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
990 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
991 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
994 struct interface
*ifp1
= if_lookup_by_index(
995 nh_node
->ifindex
, pim
->vrf_id
);
996 nbr
= pim_neighbor_find_if(ifp1
);
1000 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1001 if (PIM_DEBUG_PIM_NHT_RP
) {
1002 char str
[PREFIX_STRLEN
];
1003 char str1
[INET_ADDRSTRLEN
];
1004 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1005 str1
, sizeof(str1
));
1006 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1009 "%s: addr %s new nexthop addr %s interface %s",
1010 __PRETTY_FUNCTION__
, str
, str1
,