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"
48 #include "pim_mroute.h"
50 #include "pim_zebra.h"
52 /* Cleanup pim->rpf_hash each node data */
53 void pim_rp_list_hash_clean(void *data
)
55 struct pim_nexthop_cache
*pnc
= (struct pim_nexthop_cache
*)data
;
57 list_delete(&pnc
->rp_list
);
59 hash_clean(pnc
->upstream_hash
, NULL
);
60 hash_free(pnc
->upstream_hash
);
61 pnc
->upstream_hash
= NULL
;
63 nexthops_free(pnc
->nexthop
);
65 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
68 static void pim_rp_info_free(struct rp_info
*rp_info
)
70 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
72 XFREE(MTYPE_PIM_RP
, rp_info
);
75 int pim_rp_list_cmp(void *v1
, void *v2
)
77 struct rp_info
*rp1
= (struct rp_info
*)v1
;
78 struct rp_info
*rp2
= (struct rp_info
*)v2
;
81 * Sort by RP IP address
83 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
84 < rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
87 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
88 > rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
92 * Sort by group IP address
94 if (rp1
->group
.u
.prefix4
.s_addr
< rp2
->group
.u
.prefix4
.s_addr
)
97 if (rp1
->group
.u
.prefix4
.s_addr
> rp2
->group
.u
.prefix4
.s_addr
)
103 void pim_rp_init(struct pim_instance
*pim
)
105 struct rp_info
*rp_info
;
106 struct route_node
*rn
;
108 pim
->rp_list
= list_new();
109 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
110 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
112 pim
->rp_table
= route_table_init();
114 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
116 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
117 flog_err(EC_LIB_DEVELOPMENT
,
118 "Unable to convert 224.0.0.0/4 to prefix");
119 list_delete(&pim
->rp_list
);
120 route_table_finish(pim
->rp_table
);
121 XFREE(MTYPE_PIM_RP
, rp_info
);
124 rp_info
->group
.family
= AF_INET
;
125 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
126 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
127 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
129 listnode_add(pim
->rp_list
, rp_info
);
131 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
135 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
136 rn
, rp_info
, rn
->lock
);
139 void pim_rp_free(struct pim_instance
*pim
)
142 list_delete(&pim
->rp_list
);
146 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
148 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
152 struct listnode
*node
;
153 struct rp_info
*rp_info
;
155 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
156 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
157 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
166 * Return true if plist is used by any rp_info
168 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
170 struct listnode
*node
;
171 struct rp_info
*rp_info
;
173 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
174 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
183 * Given an RP's address, return the RP's rp_info that is an exact match for
186 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
188 const struct prefix
*group
)
190 struct listnode
*node
;
191 struct rp_info
*rp_info
;
193 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
194 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
195 && prefix_same(&rp_info
->group
, group
))
203 * Given a group, return the rp_info for that group
205 struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
206 const struct prefix
*group
)
208 struct listnode
*node
;
209 struct rp_info
*best
= NULL
;
210 struct rp_info
*rp_info
;
211 struct prefix_list
*plist
;
212 const struct prefix
*p
, *bp
;
213 struct route_node
*rn
;
216 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
217 if (rp_info
->plist
) {
218 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
220 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
230 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
237 rn
= route_node_match(pim
->rp_table
, group
);
241 "%s: BUG We should have found default group information\n",
242 __PRETTY_FUNCTION__
);
247 if (PIM_DEBUG_TRACE
) {
248 char buf
[PREFIX_STRLEN
];
250 route_unlock_node(rn
);
251 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
253 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
260 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
267 * When the user makes "ip pim rp" configuration changes or if they change the
268 * prefix-list(s) used by these statements we must tickle the upstream state
269 * for each group to make them re-lookup who their RP should be.
271 * This is a placeholder function for now.
273 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
275 pim_msdp_i_am_rp_changed(pim
);
278 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
279 struct prefix_list
*plist
)
281 struct listnode
*node
;
282 struct rp_info
*rp_info
;
283 int refresh_needed
= 0;
285 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
287 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
294 pim_rp_refresh_group_to_rp_mapping(pim
);
297 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
298 struct pim_interface
*pim_ifp
)
300 struct listnode
*node
;
301 struct pim_secondary_addr
*sec_addr
;
303 if (pim_ifp
->primary_address
.s_addr
304 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
307 if (!pim_ifp
->sec_addr_list
) {
311 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
312 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
320 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
321 struct rp_info
*rp_info
)
323 struct interface
*ifp
;
325 rp_info
->i_am_rp
= 0;
326 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
327 struct pim_interface
*pim_ifp
= ifp
->info
;
332 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
333 rp_info
->i_am_rp
= 1;
338 void pim_upstream_update(struct pim_instance
*pim
, struct pim_upstream
*up
)
340 struct pim_rpf old_rpf
;
341 enum pim_rpf_result rpf_result
;
342 struct in_addr old_upstream_addr
;
343 struct in_addr new_upstream_addr
;
346 old_upstream_addr
= up
->upstream_addr
;
347 pim_rp_set_upstream_addr(pim
, &new_upstream_addr
, up
->sg
.src
,
351 zlog_debug("%s: pim upstream update for old upstream %s",
353 inet_ntoa(old_upstream_addr
));
355 if (old_upstream_addr
.s_addr
== new_upstream_addr
.s_addr
)
358 /* Lets consider a case, where a PIM upstream has a better RP as a
359 * result of a new RP configuration with more precise group range.
360 * This upstream has to be added to the upstream hash of new RP's
361 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
363 if (old_upstream_addr
.s_addr
!= INADDR_ANY
) {
364 /* Deregister addr with Zebra NHT */
365 nht_p
.family
= AF_INET
;
366 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
367 nht_p
.u
.prefix4
= old_upstream_addr
;
368 if (PIM_DEBUG_TRACE
) {
369 char buf
[PREFIX2STR_BUFFER
];
371 prefix2str(&nht_p
, buf
, sizeof(buf
));
372 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
373 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
375 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
378 /* Update the upstream address */
379 up
->upstream_addr
= new_upstream_addr
;
381 old_rpf
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
383 rpf_result
= pim_rpf_update(pim
, up
, &old_rpf
, 1);
384 if (rpf_result
== PIM_RPF_FAILURE
)
385 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
387 /* update kernel multicast forwarding cache (MFC) */
388 if (up
->rpf
.source_nexthop
.interface
&& up
->channel_oil
) {
389 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
390 int vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
391 /* Pass Current selected NH vif index to mroute download */
393 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
395 if (PIM_DEBUG_PIM_NHT
)
397 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
398 __PRETTY_FUNCTION__
, up
->sg_str
,
399 up
->rpf
.source_nexthop
.interface
->name
);
403 if (rpf_result
== PIM_RPF_CHANGED
)
404 pim_zebra_upstream_rpf_changed(pim
, up
, &old_rpf
);
406 pim_zebra_update_all_interfaces(pim
);
409 int pim_rp_new(struct pim_instance
*pim
, const char *rp
,
410 const char *group_range
, const char *plist
)
413 struct rp_info
*rp_info
;
414 struct rp_info
*rp_all
;
415 struct prefix group_all
;
416 struct listnode
*node
, *nnode
;
417 struct rp_info
*tmp_rp_info
;
421 struct pim_nexthop_cache pnc
;
422 struct route_node
*rn
;
423 struct pim_upstream
*up
;
424 struct listnode
*upnode
;
426 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
428 if (group_range
== NULL
)
429 result
= str2prefix("224.0.0.0/4", &rp_info
->group
);
431 result
= str2prefix(group_range
, &rp_info
->group
);
433 prefix_copy(&temp
, &rp_info
->group
);
435 if (!prefix_same(&rp_info
->group
, &temp
)) {
436 XFREE(MTYPE_PIM_RP
, rp_info
);
437 return PIM_GROUP_BAD_ADDR_MASK_COMBO
;
443 XFREE(MTYPE_PIM_RP
, rp_info
);
444 return PIM_GROUP_BAD_ADDRESS
;
447 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
448 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
449 result
= inet_pton(rp_info
->rp
.rpf_addr
.family
, rp
,
450 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
453 XFREE(MTYPE_PIM_RP
, rp_info
);
454 return PIM_RP_BAD_ADDRESS
;
459 * Return if the prefix-list is already configured for this RP
461 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
463 XFREE(MTYPE_PIM_RP
, rp_info
);
468 * Barf if the prefix-list is already configured for an RP
470 if (pim_rp_prefix_list_used(pim
, plist
)) {
471 XFREE(MTYPE_PIM_RP
, rp_info
);
472 return PIM_RP_PFXLIST_IN_USE
;
476 * Free any existing rp_info entries for this RP
478 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
480 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
481 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
482 if (tmp_rp_info
->plist
)
483 pim_rp_del(pim
, rp
, NULL
,
488 prefix2str(&tmp_rp_info
->group
,
494 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
497 if (!str2prefix("224.0.0.0/4", &group_all
)) {
498 XFREE(MTYPE_PIM_RP
, rp_info
);
499 return PIM_GROUP_BAD_ADDRESS
;
501 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
504 * Barf if group is a non-multicast subnet
506 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
507 XFREE(MTYPE_PIM_RP
, rp_info
);
508 return PIM_GROUP_BAD_ADDRESS
;
512 * Remove any prefix-list rp_info entries for this RP
514 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
516 if (tmp_rp_info
->plist
517 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
518 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
520 pim_rp_del(pim
, rp
, NULL
, tmp_rp_info
->plist
);
525 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
527 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
528 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
529 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
530 XFREE(MTYPE_PIM_RP
, rp_info
);
532 /* Register addr with Zebra NHT */
533 nht_p
.family
= AF_INET
;
534 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
536 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
537 if (PIM_DEBUG_PIM_NHT_RP
) {
538 char buf
[PREFIX2STR_BUFFER
];
539 char buf1
[PREFIX2STR_BUFFER
];
540 prefix2str(&nht_p
, buf
, sizeof(buf
));
541 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
543 "%s: NHT Register rp_all addr %s grp %s ",
544 __PRETTY_FUNCTION__
, buf
, buf1
);
547 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
,
549 /* Find (*, G) upstream whose RP is not
552 if ((up
->upstream_addr
.s_addr
== INADDR_ANY
)
553 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
555 struct rp_info
*trp_info
;
557 grp
.family
= AF_INET
;
558 grp
.prefixlen
= IPV4_MAX_BITLEN
;
559 grp
.u
.prefix4
= up
->sg
.grp
;
560 trp_info
= pim_rp_find_match_group(pim
,
562 if (trp_info
== rp_all
)
563 pim_upstream_update(pim
, up
);
567 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
568 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
570 if (!pim_ecmp_nexthop_search(
572 &rp_all
->rp
.source_nexthop
, &nht_p
,
574 return PIM_RP_NO_PATH
;
576 if (!pim_ecmp_nexthop_lookup(
577 pim
, &rp_all
->rp
.source_nexthop
,
578 &nht_p
, &rp_all
->group
, 1))
579 return PIM_RP_NO_PATH
;
581 pim_rp_check_interfaces(pim
, rp_all
);
582 pim_rp_refresh_group_to_rp_mapping(pim
);
587 * Return if the group is already configured for this RP
589 if (pim_rp_find_exact(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
591 XFREE(MTYPE_PIM_RP
, rp_info
);
596 * Barf if this group is already covered by some other RP
598 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
601 if (tmp_rp_info
->plist
) {
602 XFREE(MTYPE_PIM_RP
, rp_info
);
603 return PIM_GROUP_PFXLIST_OVERLAP
;
606 * If the only RP that covers this group is an
608 * 224.0.0.0/4 that is fine, ignore that one.
610 * though we must return PIM_GROUP_OVERLAP
612 if (prefix_same(&rp_info
->group
,
613 &tmp_rp_info
->group
)) {
614 XFREE(MTYPE_PIM_RP
, rp_info
);
615 return PIM_GROUP_OVERLAP
;
621 listnode_add_sort(pim
->rp_list
, rp_info
);
622 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
625 if (PIM_DEBUG_TRACE
) {
626 char buf
[PREFIX_STRLEN
];
628 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
630 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
634 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
635 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
637 struct rp_info
*trp_info
;
639 grp
.family
= AF_INET
;
640 grp
.prefixlen
= IPV4_MAX_BITLEN
;
641 grp
.u
.prefix4
= up
->sg
.grp
;
642 trp_info
= pim_rp_find_match_group(pim
, &grp
);
644 if (trp_info
== rp_info
)
645 pim_upstream_update(pim
, up
);
649 /* Register addr with Zebra NHT */
650 nht_p
.family
= AF_INET
;
651 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
652 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
653 if (PIM_DEBUG_PIM_NHT_RP
) {
654 char buf
[PREFIX2STR_BUFFER
];
655 char buf1
[PREFIX2STR_BUFFER
];
656 prefix2str(&nht_p
, buf
, sizeof(buf
));
657 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
658 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
659 __PRETTY_FUNCTION__
, buf
, buf1
);
662 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
663 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
)) {
664 if (!pim_ecmp_nexthop_search(pim
, &pnc
,
665 &rp_info
->rp
.source_nexthop
,
666 &nht_p
, &rp_info
->group
, 1))
667 return PIM_RP_NO_PATH
;
669 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
670 &nht_p
, &rp_info
->group
, 1))
671 return PIM_RP_NO_PATH
;
674 pim_rp_check_interfaces(pim
, rp_info
);
675 pim_rp_refresh_group_to_rp_mapping(pim
);
679 int pim_rp_del(struct pim_instance
*pim
, const char *rp
,
680 const char *group_range
, const char *plist
)
683 struct in_addr rp_addr
;
685 struct rp_info
*rp_info
;
686 struct rp_info
*rp_all
;
689 struct route_node
*rn
;
690 bool was_plist
= false;
691 struct rp_info
*trp_info
;
692 struct pim_upstream
*up
;
693 struct listnode
*upnode
;
695 if (group_range
== NULL
)
696 result
= str2prefix("224.0.0.0/4", &group
);
698 result
= str2prefix(group_range
, &group
);
701 return PIM_GROUP_BAD_ADDRESS
;
703 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
705 return PIM_RP_BAD_ADDRESS
;
708 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
710 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
713 return PIM_RP_NOT_FOUND
;
715 if (rp_info
->plist
) {
716 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
720 /* Deregister addr with Zebra NHT */
721 nht_p
.family
= AF_INET
;
722 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
723 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
724 if (PIM_DEBUG_PIM_NHT_RP
) {
725 char buf
[PREFIX2STR_BUFFER
];
726 prefix2str(&nht_p
, buf
, sizeof(buf
));
727 zlog_debug("%s: Deregister RP addr %s with Zebra ",
728 __PRETTY_FUNCTION__
, buf
);
730 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
732 if (!str2prefix("224.0.0.0/4", &g_all
))
733 return PIM_RP_BAD_ADDRESS
;
735 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
737 if (rp_all
== rp_info
) {
738 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
739 /* Find the upstream (*, G) whose upstream address is
740 * same as the deleted RP
742 if ((up
->upstream_addr
.s_addr
== rp_addr
.s_addr
) &&
743 (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
745 grp
.family
= AF_INET
;
746 grp
.prefixlen
= IPV4_MAX_BITLEN
;
747 grp
.u
.prefix4
= up
->sg
.grp
;
748 trp_info
= pim_rp_find_match_group(pim
, &grp
);
749 if (trp_info
== rp_all
) {
750 pim_upstream_rpf_clear(pim
, up
);
751 up
->upstream_addr
.s_addr
= INADDR_ANY
;
755 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
756 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
761 listnode_delete(pim
->rp_list
, rp_info
);
764 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
766 if (rn
->info
!= rp_info
)
769 "Expected rn->info to be equal to rp_info");
771 if (PIM_DEBUG_TRACE
) {
772 char buf
[PREFIX_STRLEN
];
775 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
776 __PRETTY_FUNCTION__
, rn
, rp_info
,
777 prefix2str(&rp_info
->group
, buf
,
782 route_unlock_node(rn
);
783 route_unlock_node(rn
);
787 pim_rp_refresh_group_to_rp_mapping(pim
);
789 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
790 /* Find the upstream (*, G) whose upstream address is same as
793 if ((up
->upstream_addr
.s_addr
== rp_addr
.s_addr
) &&
794 (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
797 grp
.family
= AF_INET
;
798 grp
.prefixlen
= IPV4_MAX_BITLEN
;
799 grp
.u
.prefix4
= up
->sg
.grp
;
801 trp_info
= pim_rp_find_match_group(pim
, &grp
);
803 /* RP not found for the group grp */
804 if (pim_rpf_addr_is_inaddr_none(&trp_info
->rp
)) {
805 pim_upstream_rpf_clear(pim
, up
);
806 pim_rp_set_upstream_addr(pim
,
808 up
->sg
.src
, up
->sg
.grp
);
811 /* RP found for the group grp */
813 pim_upstream_update(pim
, up
);
817 XFREE(MTYPE_PIM_RP
, rp_info
);
821 void pim_rp_setup(struct pim_instance
*pim
)
823 struct listnode
*node
;
824 struct rp_info
*rp_info
;
826 struct pim_nexthop_cache pnc
;
828 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
829 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
832 nht_p
.family
= AF_INET
;
833 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
834 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
835 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
836 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
837 pim_ecmp_nexthop_search(pim
, &pnc
,
838 &rp_info
->rp
.source_nexthop
,
839 &nht_p
, &rp_info
->group
, 1);
841 if (PIM_DEBUG_PIM_NHT_RP
) {
842 char buf
[PREFIX2STR_BUFFER
];
844 prefix2str(&nht_p
, buf
, sizeof(buf
));
846 "%s: NHT Local Nexthop not found for RP %s ",
847 __PRETTY_FUNCTION__
, buf
);
849 if (!pim_ecmp_nexthop_lookup(pim
,
850 &rp_info
->rp
.source_nexthop
,
851 &nht_p
, &rp_info
->group
, 1))
852 if (PIM_DEBUG_PIM_NHT_RP
)
854 "Unable to lookup nexthop for rp specified");
860 * Checks to see if we should elect ourself the actual RP when new if
861 * addresses are added against an interface.
863 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
865 struct listnode
*node
;
866 struct rp_info
*rp_info
;
867 bool i_am_rp_changed
= false;
868 struct pim_instance
*pim
= pim_ifp
->pim
;
870 if (pim
->rp_list
== NULL
)
873 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
874 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
877 /* if i_am_rp is already set nothing to be done (adding new
879 * is not going to make a difference). */
880 if (rp_info
->i_am_rp
) {
884 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
885 i_am_rp_changed
= true;
886 rp_info
->i_am_rp
= 1;
887 if (PIM_DEBUG_PIM_NHT_RP
) {
888 char rp
[PREFIX_STRLEN
];
889 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
891 zlog_debug("%s: %s: i am rp", __func__
, rp
);
896 if (i_am_rp_changed
) {
897 pim_msdp_i_am_rp_changed(pim
);
901 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
902 * are removed. Removing numbers is an uncommon event in an active network
903 * so I have made no attempt to optimize it. */
904 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
906 struct listnode
*node
;
907 struct rp_info
*rp_info
;
908 bool i_am_rp_changed
= false;
911 if (pim
->rp_list
== NULL
)
914 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
915 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
918 old_i_am_rp
= rp_info
->i_am_rp
;
919 pim_rp_check_interfaces(pim
, rp_info
);
921 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
922 i_am_rp_changed
= true;
923 if (PIM_DEBUG_PIM_NHT_RP
) {
924 char rp
[PREFIX_STRLEN
];
925 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
927 if (rp_info
->i_am_rp
) {
928 zlog_debug("%s: %s: i am rp", __func__
,
931 zlog_debug("%s: %s: i am no longer rp",
938 if (i_am_rp_changed
) {
939 pim_msdp_i_am_rp_changed(pim
);
944 * I_am_RP(G) is true if the group-to-RP mapping indicates that
945 * this router is the RP for the group.
947 * Since we only have static RP, all groups are part of this RP
949 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
952 struct rp_info
*rp_info
;
954 memset(&g
, 0, sizeof(g
));
959 rp_info
= pim_rp_find_match_group(pim
, &g
);
962 return rp_info
->i_am_rp
;
970 * Return the RP that the Group belongs too.
972 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
975 struct rp_info
*rp_info
;
977 memset(&g
, 0, sizeof(g
));
982 rp_info
= pim_rp_find_match_group(pim
, &g
);
986 struct pim_nexthop_cache pnc
;
987 /* Register addr with Zebra NHT */
988 nht_p
.family
= AF_INET
;
989 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
990 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
991 if (PIM_DEBUG_PIM_NHT_RP
) {
992 char buf
[PREFIX2STR_BUFFER
];
993 char buf1
[PREFIX2STR_BUFFER
];
994 prefix2str(&nht_p
, buf
, sizeof(buf
));
995 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
997 "%s: NHT Register RP addr %s grp %s with Zebra",
998 __PRETTY_FUNCTION__
, buf
, buf1
);
1000 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1001 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, &pnc
))
1002 pim_ecmp_nexthop_search(pim
, &pnc
,
1003 &rp_info
->rp
.source_nexthop
,
1004 &nht_p
, &rp_info
->group
, 1);
1006 if (PIM_DEBUG_PIM_NHT_RP
) {
1007 char buf
[PREFIX2STR_BUFFER
];
1008 char buf1
[PREFIX2STR_BUFFER
];
1009 prefix2str(&nht_p
, buf
, sizeof(buf
));
1010 prefix2str(&g
, buf1
, sizeof(buf1
));
1012 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
1013 __PRETTY_FUNCTION__
, buf
, buf1
);
1015 pim_rpf_set_refresh_time(pim
);
1016 (void)pim_ecmp_nexthop_lookup(
1017 pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
1018 &rp_info
->group
, 1);
1020 return (&rp_info
->rp
);
1028 * Set the upstream IP address we want to talk to based upon
1029 * the rp configured and the source address
1031 * If we have don't have a RP configured and the source address is *
1032 * then set the upstream addr as INADDR_ANY and return failure.
1035 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
1036 struct in_addr source
, struct in_addr group
)
1038 struct rp_info
*rp_info
;
1041 memset(&g
, 0, sizeof(g
));
1044 g
.u
.prefix4
= group
;
1046 rp_info
= pim_rp_find_match_group(pim
, &g
);
1048 if ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1049 && (source
.s_addr
== INADDR_ANY
)) {
1050 if (PIM_DEBUG_PIM_NHT_RP
)
1051 zlog_debug("%s: Received a (*,G) with no RP configured",
1052 __PRETTY_FUNCTION__
);
1053 up
->s_addr
= INADDR_ANY
;
1057 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
1063 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
1066 struct listnode
*node
;
1067 struct rp_info
*rp_info
;
1069 char group_buffer
[32];
1072 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1073 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1077 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
1079 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1083 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
1085 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1087 prefix2str(&rp_info
->group
, group_buffer
, 32));
1094 int pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
1095 struct in_addr group
,
1096 struct in_addr dest_addr
)
1098 struct rp_info
*rp_info
;
1101 memset(&g
, 0, sizeof(g
));
1104 g
.u
.prefix4
= group
;
1106 rp_info
= pim_rp_find_match_group(pim
, &g
);
1108 * See if we can short-cut some?
1109 * This might not make sense if we ever leave a static RP
1110 * type of configuration.
1111 * Note - Premature optimization might bite our patooeys' here.
1113 if (I_am_RP(pim
, group
)) {
1114 if (dest_addr
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
1118 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
1124 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1126 struct rp_info
*rp_info
;
1127 struct rp_info
*prev_rp_info
= NULL
;
1128 struct listnode
*node
;
1130 json_object
*json
= NULL
;
1131 json_object
*json_rp_rows
= NULL
;
1132 json_object
*json_row
= NULL
;
1135 json
= json_object_new_object();
1138 "RP address group/prefix-list OIF I am RP\n");
1140 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1141 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
1146 * If we have moved on to a new RP then add the
1147 * entry for the previous RP
1150 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1152 != rp_info
->rp
.rpf_addr
.u
.prefix4
1154 json_object_object_add(
1156 inet_ntoa(prev_rp_info
->rp
1160 json_rp_rows
= NULL
;
1164 json_rp_rows
= json_object_new_array();
1166 json_row
= json_object_new_object();
1167 if (rp_info
->rp
.source_nexthop
.interface
)
1168 json_object_string_add(
1169 json_row
, "outboundInterface",
1170 rp_info
->rp
.source_nexthop
1173 if (rp_info
->i_am_rp
)
1174 json_object_boolean_true_add(json_row
,
1178 json_object_string_add(json_row
,
1182 json_object_string_add(
1184 prefix2str(&rp_info
->group
, buf
,
1187 json_object_array_add(json_rp_rows
, json_row
);
1189 vty_out(vty
, "%-15s ",
1190 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1194 vty_out(vty
, "%-18s ", rp_info
->plist
);
1196 vty_out(vty
, "%-18s ",
1197 prefix2str(&rp_info
->group
, buf
,
1200 if (rp_info
->rp
.source_nexthop
.interface
)
1201 vty_out(vty
, "%-10s ",
1202 rp_info
->rp
.source_nexthop
1205 vty_out(vty
, "%-10s ", "(Unknown)");
1207 if (rp_info
->i_am_rp
)
1208 vty_out(vty
, "yes\n");
1210 vty_out(vty
, "no\n");
1213 prev_rp_info
= rp_info
;
1218 if (prev_rp_info
&& json_rp_rows
)
1219 json_object_object_add(
1221 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1224 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1225 json
, JSON_C_TO_STRING_PRETTY
));
1226 json_object_free(json
);
1230 void pim_resolve_rp_nh(struct pim_instance
*pim
)
1232 struct listnode
*node
= NULL
;
1233 struct rp_info
*rp_info
= NULL
;
1234 struct nexthop
*nh_node
= NULL
;
1235 struct prefix nht_p
;
1236 struct pim_nexthop_cache pnc
;
1237 struct pim_neighbor
*nbr
= NULL
;
1239 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1240 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1243 nht_p
.family
= AF_INET
;
1244 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1245 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1246 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1247 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1251 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1252 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1255 struct interface
*ifp1
= if_lookup_by_index(
1256 nh_node
->ifindex
, pim
->vrf_id
);
1257 nbr
= pim_neighbor_find_if(ifp1
);
1261 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1262 if (PIM_DEBUG_PIM_NHT_RP
) {
1263 char str
[PREFIX_STRLEN
];
1264 char str1
[INET_ADDRSTRLEN
];
1265 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1266 str1
, sizeof(str1
));
1267 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1270 "%s: addr %s new nexthop addr %s interface %s",
1271 __PRETTY_FUNCTION__
, str
, str1
,