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"
53 /* Cleanup pim->rpf_hash each node data */
54 void pim_rp_list_hash_clean(void *data
)
56 struct pim_nexthop_cache
*pnc
= (struct pim_nexthop_cache
*)data
;
58 list_delete(&pnc
->rp_list
);
60 hash_clean(pnc
->upstream_hash
, NULL
);
61 hash_free(pnc
->upstream_hash
);
62 pnc
->upstream_hash
= NULL
;
64 nexthops_free(pnc
->nexthop
);
66 XFREE(MTYPE_PIM_NEXTHOP_CACHE
, pnc
);
69 static void pim_rp_info_free(struct rp_info
*rp_info
)
71 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
73 XFREE(MTYPE_PIM_RP
, rp_info
);
76 int pim_rp_list_cmp(void *v1
, void *v2
)
78 struct rp_info
*rp1
= (struct rp_info
*)v1
;
79 struct rp_info
*rp2
= (struct rp_info
*)v2
;
82 * Sort by RP IP address
84 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
85 < rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
88 if (rp1
->rp
.rpf_addr
.u
.prefix4
.s_addr
89 > rp2
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
93 * Sort by group IP address
95 if (rp1
->group
.u
.prefix4
.s_addr
< rp2
->group
.u
.prefix4
.s_addr
)
98 if (rp1
->group
.u
.prefix4
.s_addr
> rp2
->group
.u
.prefix4
.s_addr
)
104 void pim_rp_init(struct pim_instance
*pim
)
106 struct rp_info
*rp_info
;
107 struct route_node
*rn
;
109 pim
->rp_list
= list_new();
110 pim
->rp_list
->del
= (void (*)(void *))pim_rp_info_free
;
111 pim
->rp_list
->cmp
= pim_rp_list_cmp
;
113 pim
->rp_table
= route_table_init();
115 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
117 if (!str2prefix("224.0.0.0/4", &rp_info
->group
)) {
118 flog_err(EC_LIB_DEVELOPMENT
,
119 "Unable to convert 224.0.0.0/4 to prefix");
120 list_delete(&pim
->rp_list
);
121 route_table_finish(pim
->rp_table
);
122 XFREE(MTYPE_PIM_RP
, rp_info
);
125 rp_info
->group
.family
= AF_INET
;
126 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
127 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
128 rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
130 listnode_add(pim
->rp_list
, rp_info
);
132 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
134 if (PIM_DEBUG_PIM_TRACE
)
136 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
137 rn
, rp_info
, rn
->lock
);
140 void pim_rp_free(struct pim_instance
*pim
)
143 list_delete(&pim
->rp_list
);
147 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
149 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
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
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
158 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
167 * Return true if plist is used by any rp_info
169 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
171 struct listnode
*node
;
172 struct rp_info
*rp_info
;
174 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
175 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
184 * Given an RP's address, return the RP's rp_info that is an exact match for
187 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
189 const struct prefix
*group
)
191 struct listnode
*node
;
192 struct rp_info
*rp_info
;
194 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
195 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
196 && prefix_same(&rp_info
->group
, group
))
204 * Given a group, return the rp_info for that group
206 struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
207 const struct prefix
*group
)
209 struct listnode
*node
;
210 struct rp_info
*best
= NULL
;
211 struct rp_info
*rp_info
;
212 struct prefix_list
*plist
;
213 const struct prefix
*p
, *bp
;
214 struct route_node
*rn
;
217 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
218 if (rp_info
->plist
) {
219 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
221 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
231 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
238 rn
= route_node_match(pim
->rp_table
, group
);
242 "%s: BUG We should have found default group information\n",
243 __PRETTY_FUNCTION__
);
248 if (PIM_DEBUG_PIM_TRACE
) {
249 char buf
[PREFIX_STRLEN
];
251 route_unlock_node(rn
);
252 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn
,
254 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
261 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
268 * When the user makes "ip pim rp" configuration changes or if they change the
269 * prefix-list(s) used by these statements we must tickle the upstream state
270 * for each group to make them re-lookup who their RP should be.
272 * This is a placeholder function for now.
274 static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
276 pim_msdp_i_am_rp_changed(pim
);
279 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
280 struct prefix_list
*plist
)
282 struct listnode
*node
;
283 struct rp_info
*rp_info
;
284 int refresh_needed
= 0;
286 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
288 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
295 pim_rp_refresh_group_to_rp_mapping(pim
);
298 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
299 struct pim_interface
*pim_ifp
)
301 struct listnode
*node
;
302 struct pim_secondary_addr
*sec_addr
;
304 if (pim_ifp
->primary_address
.s_addr
305 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
308 if (!pim_ifp
->sec_addr_list
) {
312 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
313 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
321 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
322 struct rp_info
*rp_info
)
324 struct interface
*ifp
;
326 rp_info
->i_am_rp
= 0;
327 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
328 struct pim_interface
*pim_ifp
= ifp
->info
;
333 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
334 rp_info
->i_am_rp
= 1;
339 void pim_upstream_update(struct pim_instance
*pim
, struct pim_upstream
*up
)
341 struct pim_rpf old_rpf
;
342 enum pim_rpf_result rpf_result
;
343 struct in_addr old_upstream_addr
;
344 struct in_addr new_upstream_addr
;
347 old_upstream_addr
= up
->upstream_addr
;
348 pim_rp_set_upstream_addr(pim
, &new_upstream_addr
, up
->sg
.src
,
351 if (PIM_DEBUG_PIM_TRACE
)
352 zlog_debug("%s: pim upstream update for old upstream %s",
354 inet_ntoa(old_upstream_addr
));
356 if (old_upstream_addr
.s_addr
== new_upstream_addr
.s_addr
)
359 /* Lets consider a case, where a PIM upstream has a better RP as a
360 * result of a new RP configuration with more precise group range.
361 * This upstream has to be added to the upstream hash of new RP's
362 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
364 if (old_upstream_addr
.s_addr
!= INADDR_ANY
) {
365 /* Deregister addr with Zebra NHT */
366 nht_p
.family
= AF_INET
;
367 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
368 nht_p
.u
.prefix4
= old_upstream_addr
;
369 if (PIM_DEBUG_PIM_TRACE
) {
370 char buf
[PREFIX2STR_BUFFER
];
372 prefix2str(&nht_p
, buf
, sizeof(buf
));
373 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
374 __PRETTY_FUNCTION__
, up
->sg_str
, buf
);
376 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
379 /* Update the upstream address */
380 up
->upstream_addr
= new_upstream_addr
;
382 old_rpf
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
384 rpf_result
= pim_rpf_update(pim
, up
, &old_rpf
);
385 if (rpf_result
== PIM_RPF_FAILURE
)
386 pim_mroute_del(up
->channel_oil
, __PRETTY_FUNCTION__
);
388 /* update kernel multicast forwarding cache (MFC) */
389 if (up
->rpf
.source_nexthop
.interface
&& up
->channel_oil
) {
390 ifindex_t ifindex
= up
->rpf
.source_nexthop
.interface
->ifindex
;
391 int vif_index
= pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
392 /* Pass Current selected NH vif index to mroute download */
394 pim_scan_individual_oil(up
->channel_oil
, vif_index
);
396 if (PIM_DEBUG_PIM_NHT
)
398 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
399 __PRETTY_FUNCTION__
, up
->sg_str
,
400 up
->rpf
.source_nexthop
.interface
->name
);
404 if (rpf_result
== PIM_RPF_CHANGED
)
405 pim_zebra_upstream_rpf_changed(pim
, up
, &old_rpf
);
407 pim_zebra_update_all_interfaces(pim
);
410 int pim_rp_new_config(struct pim_instance
*pim
, const char *rp
,
411 const char *group_range
, const char *plist
)
415 struct in_addr rp_addr
;
417 if (group_range
== NULL
)
418 result
= str2prefix("224.0.0.0/4", &group
);
420 result
= str2prefix(group_range
, &group
);
424 prefix_copy(&temp
, &group
);
426 if (!prefix_same(&group
, &temp
))
427 return PIM_GROUP_BAD_ADDR_MASK_COMBO
;
432 return PIM_GROUP_BAD_ADDRESS
;
434 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
437 return PIM_RP_BAD_ADDRESS
;
439 result
= pim_rp_new(pim
, rp_addr
, group
, plist
, RP_SRC_STATIC
);
443 int pim_rp_new(struct pim_instance
*pim
, struct in_addr rp_addr
,
444 struct prefix group
, const char *plist
,
445 enum rp_source rp_src_flag
)
448 char rp
[INET_ADDRSTRLEN
];
449 struct rp_info
*rp_info
;
450 struct rp_info
*rp_all
;
451 struct prefix group_all
;
452 struct listnode
*node
, *nnode
;
453 struct rp_info
*tmp_rp_info
;
456 struct route_node
*rn
;
457 struct pim_upstream
*up
;
458 struct listnode
*upnode
;
460 if (rp_addr
.s_addr
== INADDR_ANY
||
461 rp_addr
.s_addr
== INADDR_NONE
)
462 return PIM_RP_BAD_ADDRESS
;
464 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
466 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
467 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
468 rp_info
->rp
.rpf_addr
.u
.prefix4
= rp_addr
;
469 prefix_copy(&rp_info
->group
, &group
);
470 rp_info
->rp_src
= rp_src_flag
;
472 inet_ntop(AF_INET
, &rp_info
->rp
.rpf_addr
.u
.prefix4
, rp
, sizeof(rp
));
476 * Return if the prefix-list is already configured for this RP
478 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
480 XFREE(MTYPE_PIM_RP
, rp_info
);
485 * Barf if the prefix-list is already configured for an RP
487 if (pim_rp_prefix_list_used(pim
, plist
)) {
488 XFREE(MTYPE_PIM_RP
, rp_info
);
489 return PIM_RP_PFXLIST_IN_USE
;
493 * Free any existing rp_info entries for this RP
495 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
497 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
498 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
499 if (tmp_rp_info
->plist
)
500 pim_rp_del_config(pim
, rp
, NULL
,
505 prefix2str(&tmp_rp_info
->group
,
511 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
514 if (!str2prefix("224.0.0.0/4", &group_all
)) {
515 XFREE(MTYPE_PIM_RP
, rp_info
);
516 return PIM_GROUP_BAD_ADDRESS
;
518 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
521 * Barf if group is a non-multicast subnet
523 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
524 XFREE(MTYPE_PIM_RP
, rp_info
);
525 return PIM_GROUP_BAD_ADDRESS
;
529 * Remove any prefix-list rp_info entries for this RP
531 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
533 if (tmp_rp_info
->plist
534 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
535 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
537 pim_rp_del_config(pim
, rp
, NULL
,
543 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
545 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
546 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
547 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
548 rp_all
->rp_src
= rp_src_flag
;
549 XFREE(MTYPE_PIM_RP
, rp_info
);
551 /* Register addr with Zebra NHT */
552 nht_p
.family
= AF_INET
;
553 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
555 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
556 if (PIM_DEBUG_PIM_NHT_RP
) {
557 char buf
[PREFIX2STR_BUFFER
];
558 char buf1
[PREFIX2STR_BUFFER
];
559 prefix2str(&nht_p
, buf
, sizeof(buf
));
560 prefix2str(&rp_all
->group
, buf1
, sizeof(buf1
));
562 "%s: NHT Register rp_all addr %s grp %s ",
563 __PRETTY_FUNCTION__
, buf
, buf1
);
566 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
,
568 /* Find (*, G) upstream whose RP is not
571 if ((up
->upstream_addr
.s_addr
== INADDR_ANY
)
572 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
574 struct rp_info
*trp_info
;
576 grp
.family
= AF_INET
;
577 grp
.prefixlen
= IPV4_MAX_BITLEN
;
578 grp
.u
.prefix4
= up
->sg
.grp
;
579 trp_info
= pim_rp_find_match_group(
581 if (trp_info
== rp_all
)
582 pim_upstream_update(pim
, up
);
586 pim_rp_check_interfaces(pim
, rp_all
);
587 pim_rp_refresh_group_to_rp_mapping(pim
);
588 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
591 if (!pim_ecmp_nexthop_lookup(pim
,
592 &rp_all
->rp
.source_nexthop
,
593 &nht_p
, &rp_all
->group
, 1))
594 return PIM_RP_NO_PATH
;
599 * Return if the group is already configured for this RP
601 tmp_rp_info
= pim_rp_find_exact(
602 pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
, &rp_info
->group
);
604 if ((tmp_rp_info
->rp_src
!= rp_src_flag
)
605 && (rp_src_flag
== RP_SRC_STATIC
))
606 tmp_rp_info
->rp_src
= rp_src_flag
;
607 XFREE(MTYPE_PIM_RP
, rp_info
);
612 * Barf if this group is already covered by some other RP
614 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
617 if (tmp_rp_info
->plist
) {
618 XFREE(MTYPE_PIM_RP
, rp_info
);
619 return PIM_GROUP_PFXLIST_OVERLAP
;
622 * If the only RP that covers this group is an
624 * 224.0.0.0/4 that is fine, ignore that one.
626 * though we must return PIM_GROUP_OVERLAP
628 if (prefix_same(&rp_info
->group
,
629 &tmp_rp_info
->group
)) {
630 if ((rp_src_flag
== RP_SRC_STATIC
)
631 && (tmp_rp_info
->rp_src
633 XFREE(MTYPE_PIM_RP
, rp_info
);
634 return PIM_GROUP_OVERLAP
;
637 result
= pim_rp_change(
639 rp_info
->rp
.rpf_addr
.u
.prefix4
,
642 XFREE(MTYPE_PIM_RP
, rp_info
);
649 listnode_add_sort(pim
->rp_list
, rp_info
);
650 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
653 if (PIM_DEBUG_PIM_TRACE
) {
654 char buf
[PREFIX_STRLEN
];
656 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn
,
658 prefix2str(&rp_info
->group
, buf
, sizeof(buf
)),
662 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
663 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
665 struct rp_info
*trp_info
;
667 grp
.family
= AF_INET
;
668 grp
.prefixlen
= IPV4_MAX_BITLEN
;
669 grp
.u
.prefix4
= up
->sg
.grp
;
670 trp_info
= pim_rp_find_match_group(pim
, &grp
);
672 if (trp_info
== rp_info
)
673 pim_upstream_update(pim
, up
);
677 pim_rp_check_interfaces(pim
, rp_info
);
678 pim_rp_refresh_group_to_rp_mapping(pim
);
680 /* Register addr with Zebra NHT */
681 nht_p
.family
= AF_INET
;
682 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
683 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
684 if (PIM_DEBUG_PIM_NHT_RP
) {
685 char buf
[PREFIX2STR_BUFFER
];
686 char buf1
[PREFIX2STR_BUFFER
];
687 prefix2str(&nht_p
, buf
, sizeof(buf
));
688 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
689 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
690 __PRETTY_FUNCTION__
, buf
, buf1
);
692 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
693 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
695 return PIM_RP_NO_PATH
;
700 int pim_rp_del_config(struct pim_instance
*pim
, const char *rp
,
701 const char *group_range
, const char *plist
)
704 struct in_addr rp_addr
;
707 if (group_range
== NULL
)
708 result
= str2prefix("224.0.0.0/4", &group
);
710 result
= str2prefix(group_range
, &group
);
713 return PIM_GROUP_BAD_ADDRESS
;
715 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
717 return PIM_RP_BAD_ADDRESS
;
719 result
= pim_rp_del(pim
, rp_addr
, group
, plist
, RP_SRC_STATIC
);
723 int pim_rp_del(struct pim_instance
*pim
, struct in_addr rp_addr
,
724 struct prefix group
, const char *plist
,
725 enum rp_source rp_src_flag
)
728 struct rp_info
*rp_info
;
729 struct rp_info
*rp_all
;
731 struct route_node
*rn
;
732 bool was_plist
= false;
733 struct rp_info
*trp_info
;
734 struct pim_upstream
*up
;
735 struct listnode
*upnode
;
736 struct bsgrp_node
*bsgrp
= NULL
;
737 struct bsm_rpinfo
*bsrp
= NULL
;
738 char grp_str
[PREFIX2STR_BUFFER
];
739 char rp_str
[INET_ADDRSTRLEN
];
741 if (!inet_ntop(AF_INET
, &rp_addr
, rp_str
, sizeof(rp_str
)))
742 sprintf(rp_str
, "<rp?>");
743 prefix2str(&group
, grp_str
, sizeof(grp_str
));
746 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
748 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
751 return PIM_RP_NOT_FOUND
;
753 if (rp_info
->plist
) {
754 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
758 if (PIM_DEBUG_PIM_TRACE
)
759 zlog_debug("%s: Delete RP %s for the group %s",
760 __PRETTY_FUNCTION__
, rp_str
, grp_str
);
762 /* While static RP is getting deleted, we need to check if dynamic RP
763 * present for the same group in BSM RP table, then install the dynamic
764 * RP for the group node into the main rp table
766 if (rp_src_flag
== RP_SRC_STATIC
) {
767 bsgrp
= pim_bsm_get_bsgrp_node(&pim
->global_scope
, &group
);
770 bsrp
= listnode_head(bsgrp
->bsrp_list
);
772 if (PIM_DEBUG_PIM_TRACE
) {
773 char bsrp_str
[INET_ADDRSTRLEN
];
775 if (!inet_ntop(AF_INET
, bsrp
, bsrp_str
,
777 sprintf(bsrp_str
, "<bsrp?>");
779 zlog_debug("%s: BSM RP %s found for the group %s",
783 return pim_rp_change(pim
, bsrp
->rp_address
,
787 if (PIM_DEBUG_PIM_TRACE
)
789 "%s: BSM RP not found for the group %s",
790 __PRETTY_FUNCTION__
, grp_str
);
794 /* Deregister addr with Zebra NHT */
795 nht_p
.family
= AF_INET
;
796 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
797 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
798 if (PIM_DEBUG_PIM_NHT_RP
) {
799 char buf
[PREFIX2STR_BUFFER
];
800 prefix2str(&nht_p
, buf
, sizeof(buf
));
801 zlog_debug("%s: Deregister RP addr %s with Zebra ",
802 __PRETTY_FUNCTION__
, buf
);
804 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
806 if (!str2prefix("224.0.0.0/4", &g_all
))
807 return PIM_RP_BAD_ADDRESS
;
809 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
811 if (rp_all
== rp_info
) {
812 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
813 /* Find the upstream (*, G) whose upstream address is
814 * same as the deleted RP
816 if ((up
->upstream_addr
.s_addr
817 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
818 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
820 grp
.family
= AF_INET
;
821 grp
.prefixlen
= IPV4_MAX_BITLEN
;
822 grp
.u
.prefix4
= up
->sg
.grp
;
823 trp_info
= pim_rp_find_match_group(pim
, &grp
);
824 if (trp_info
== rp_all
) {
825 pim_upstream_rpf_clear(pim
, up
);
826 up
->upstream_addr
.s_addr
= INADDR_ANY
;
830 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
831 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
836 listnode_delete(pim
->rp_list
, rp_info
);
839 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
841 if (rn
->info
!= rp_info
)
844 "Expected rn->info to be equal to rp_info");
846 if (PIM_DEBUG_PIM_TRACE
) {
847 char buf
[PREFIX_STRLEN
];
850 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
851 __PRETTY_FUNCTION__
, rn
, rp_info
,
852 prefix2str(&rp_info
->group
, buf
,
857 route_unlock_node(rn
);
858 route_unlock_node(rn
);
862 pim_rp_refresh_group_to_rp_mapping(pim
);
864 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
865 /* Find the upstream (*, G) whose upstream address is same as
868 if ((up
->upstream_addr
.s_addr
869 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
870 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
873 grp
.family
= AF_INET
;
874 grp
.prefixlen
= IPV4_MAX_BITLEN
;
875 grp
.u
.prefix4
= up
->sg
.grp
;
877 trp_info
= pim_rp_find_match_group(pim
, &grp
);
879 /* RP not found for the group grp */
880 if (pim_rpf_addr_is_inaddr_none(&trp_info
->rp
)) {
881 pim_upstream_rpf_clear(pim
, up
);
882 pim_rp_set_upstream_addr(
883 pim
, &up
->upstream_addr
, up
->sg
.src
,
887 /* RP found for the group grp */
889 pim_upstream_update(pim
, up
);
893 XFREE(MTYPE_PIM_RP
, rp_info
);
897 int pim_rp_change(struct pim_instance
*pim
, struct in_addr new_rp_addr
,
898 struct prefix group
, enum rp_source rp_src_flag
)
901 struct route_node
*rn
;
903 struct rp_info
*rp_info
= NULL
;
904 struct pim_upstream
*up
;
905 struct listnode
*upnode
;
907 rn
= route_node_lookup(pim
->rp_table
, &group
);
909 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
916 route_unlock_node(rn
);
917 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
921 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== new_rp_addr
.s_addr
) {
922 if (rp_info
->rp_src
!= rp_src_flag
) {
923 rp_info
->rp_src
= rp_src_flag
;
924 route_unlock_node(rn
);
929 nht_p
.family
= AF_INET
;
930 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
932 /* Deregister old RP addr with Zebra NHT */
933 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
!= INADDR_ANY
) {
934 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
935 if (PIM_DEBUG_PIM_NHT_RP
) {
936 char buf
[PREFIX2STR_BUFFER
];
938 prefix2str(&nht_p
, buf
, sizeof(buf
));
939 zlog_debug("%s: Deregister RP addr %s with Zebra ",
940 __PRETTY_FUNCTION__
, buf
);
942 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
945 pim_rp_nexthop_del(rp_info
);
946 listnode_delete(pim
->rp_list
, rp_info
);
947 /* Update the new RP address*/
948 rp_info
->rp
.rpf_addr
.u
.prefix4
= new_rp_addr
;
949 rp_info
->rp_src
= rp_src_flag
;
950 rp_info
->i_am_rp
= 0;
952 listnode_add_sort(pim
->rp_list
, rp_info
);
954 for (ALL_LIST_ELEMENTS_RO(pim
->upstream_list
, upnode
, up
)) {
955 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
957 struct rp_info
*trp_info
;
959 grp
.family
= AF_INET
;
960 grp
.prefixlen
= IPV4_MAX_BITLEN
;
961 grp
.u
.prefix4
= up
->sg
.grp
;
962 trp_info
= pim_rp_find_match_group(pim
, &grp
);
964 if (trp_info
== rp_info
)
965 pim_upstream_update(pim
, up
);
969 /* Register new RP addr with Zebra NHT */
970 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
971 if (PIM_DEBUG_PIM_NHT_RP
) {
972 char buf
[PREFIX2STR_BUFFER
];
973 char buf1
[PREFIX2STR_BUFFER
];
975 prefix2str(&nht_p
, buf
, sizeof(buf
));
976 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
977 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
978 __PRETTY_FUNCTION__
, buf
, buf1
);
981 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
982 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
983 &rp_info
->group
, 1)) {
984 route_unlock_node(rn
);
985 return PIM_RP_NO_PATH
;
988 pim_rp_check_interfaces(pim
, rp_info
);
990 route_unlock_node(rn
);
992 pim_rp_refresh_group_to_rp_mapping(pim
);
997 void pim_rp_setup(struct pim_instance
*pim
)
999 struct listnode
*node
;
1000 struct rp_info
*rp_info
;
1001 struct prefix nht_p
;
1003 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1004 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1007 nht_p
.family
= AF_INET
;
1008 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1009 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1011 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
1013 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
1014 &nht_p
, &rp_info
->group
, 1))
1015 if (PIM_DEBUG_PIM_NHT_RP
)
1017 "Unable to lookup nexthop for rp specified");
1022 * Checks to see if we should elect ourself the actual RP when new if
1023 * addresses are added against an interface.
1025 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
1027 struct listnode
*node
;
1028 struct rp_info
*rp_info
;
1029 bool i_am_rp_changed
= false;
1030 struct pim_instance
*pim
= pim_ifp
->pim
;
1032 if (pim
->rp_list
== NULL
)
1035 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1036 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1039 /* if i_am_rp is already set nothing to be done (adding new
1041 * is not going to make a difference). */
1042 if (rp_info
->i_am_rp
) {
1046 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
1047 i_am_rp_changed
= true;
1048 rp_info
->i_am_rp
= 1;
1049 if (PIM_DEBUG_PIM_NHT_RP
) {
1050 char rp
[PREFIX_STRLEN
];
1051 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1053 zlog_debug("%s: %s: i am rp", __func__
, rp
);
1058 if (i_am_rp_changed
) {
1059 pim_msdp_i_am_rp_changed(pim
);
1063 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
1064 * are removed. Removing numbers is an uncommon event in an active network
1065 * so I have made no attempt to optimize it. */
1066 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
1068 struct listnode
*node
;
1069 struct rp_info
*rp_info
;
1070 bool i_am_rp_changed
= false;
1073 if (pim
->rp_list
== NULL
)
1076 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1077 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1080 old_i_am_rp
= rp_info
->i_am_rp
;
1081 pim_rp_check_interfaces(pim
, rp_info
);
1083 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
1084 i_am_rp_changed
= true;
1085 if (PIM_DEBUG_PIM_NHT_RP
) {
1086 char rp
[PREFIX_STRLEN
];
1087 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1089 if (rp_info
->i_am_rp
) {
1090 zlog_debug("%s: %s: i am rp", __func__
,
1093 zlog_debug("%s: %s: i am no longer rp",
1100 if (i_am_rp_changed
) {
1101 pim_msdp_i_am_rp_changed(pim
);
1106 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1107 * this router is the RP for the group.
1109 * Since we only have static RP, all groups are part of this RP
1111 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
1114 struct rp_info
*rp_info
;
1116 memset(&g
, 0, sizeof(g
));
1119 g
.u
.prefix4
= group
;
1121 rp_info
= pim_rp_find_match_group(pim
, &g
);
1124 return rp_info
->i_am_rp
;
1132 * Return the RP that the Group belongs too.
1134 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
1137 struct rp_info
*rp_info
;
1139 memset(&g
, 0, sizeof(g
));
1142 g
.u
.prefix4
= group
;
1144 rp_info
= pim_rp_find_match_group(pim
, &g
);
1147 struct prefix nht_p
;
1149 /* Register addr with Zebra NHT */
1150 nht_p
.family
= AF_INET
;
1151 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1152 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1153 if (PIM_DEBUG_PIM_NHT_RP
) {
1154 char buf
[PREFIX2STR_BUFFER
];
1155 char buf1
[PREFIX2STR_BUFFER
];
1156 prefix2str(&nht_p
, buf
, sizeof(buf
));
1157 prefix2str(&rp_info
->group
, buf1
, sizeof(buf1
));
1159 "%s: NHT Register RP addr %s grp %s with Zebra",
1160 __PRETTY_FUNCTION__
, buf
, buf1
);
1162 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
1164 pim_rpf_set_refresh_time(pim
);
1165 (void)pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
1166 &nht_p
, &rp_info
->group
, 1);
1167 return (&rp_info
->rp
);
1175 * Set the upstream IP address we want to talk to based upon
1176 * the rp configured and the source address
1178 * If we have don't have a RP configured and the source address is *
1179 * then set the upstream addr as INADDR_ANY and return failure.
1182 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
1183 struct in_addr source
, struct in_addr group
)
1185 struct rp_info
*rp_info
;
1188 memset(&g
, 0, sizeof(g
));
1191 g
.u
.prefix4
= group
;
1193 rp_info
= pim_rp_find_match_group(pim
, &g
);
1195 if (!rp_info
|| ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1196 && (source
.s_addr
== INADDR_ANY
))) {
1197 if (PIM_DEBUG_PIM_NHT_RP
)
1198 zlog_debug("%s: Received a (*,G) with no RP configured",
1199 __PRETTY_FUNCTION__
);
1200 up
->s_addr
= INADDR_ANY
;
1204 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
1210 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
1213 struct listnode
*node
;
1214 struct rp_info
*rp_info
;
1216 char group_buffer
[32];
1219 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1220 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1223 if (rp_info
->rp_src
== RP_SRC_BSR
)
1227 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
1229 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1233 vty_out(vty
, "%sip pim rp %s %s\n", spaces
,
1235 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1237 prefix2str(&rp_info
->group
, group_buffer
, 32));
1244 bool pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
1245 struct in_addr dest_addr
)
1247 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
1253 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1255 struct rp_info
*rp_info
;
1256 struct rp_info
*prev_rp_info
= NULL
;
1257 struct listnode
*node
;
1260 json_object
*json
= NULL
;
1261 json_object
*json_rp_rows
= NULL
;
1262 json_object
*json_row
= NULL
;
1265 json
= json_object_new_object();
1268 "RP address group/prefix-list OIF I am RP Source\n");
1269 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1270 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
1273 if (rp_info
->rp_src
== RP_SRC_STATIC
)
1274 strcpy(source
, "Static");
1275 else if (rp_info
->rp_src
== RP_SRC_BSR
)
1276 strcpy(source
, "BSR");
1278 strcpy(source
, "None");
1281 * If we have moved on to a new RP then add the
1282 * entry for the previous RP
1285 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1287 != rp_info
->rp
.rpf_addr
.u
.prefix4
1289 json_object_object_add(
1291 inet_ntoa(prev_rp_info
->rp
1295 json_rp_rows
= NULL
;
1299 json_rp_rows
= json_object_new_array();
1301 json_row
= json_object_new_object();
1302 if (rp_info
->rp
.source_nexthop
.interface
)
1303 json_object_string_add(
1304 json_row
, "outboundInterface",
1305 rp_info
->rp
.source_nexthop
1308 if (rp_info
->i_am_rp
)
1309 json_object_boolean_true_add(json_row
,
1313 json_object_string_add(json_row
,
1317 json_object_string_add(
1319 prefix2str(&rp_info
->group
, buf
,
1321 json_object_string_add(json_row
, "source",
1324 json_object_array_add(json_rp_rows
, json_row
);
1326 vty_out(vty
, "%-15s ",
1327 inet_ntoa(rp_info
->rp
.rpf_addr
.u
1331 vty_out(vty
, "%-18s ", rp_info
->plist
);
1333 vty_out(vty
, "%-18s ",
1334 prefix2str(&rp_info
->group
, buf
,
1337 if (rp_info
->rp
.source_nexthop
.interface
)
1338 vty_out(vty
, "%-16s ",
1339 rp_info
->rp
.source_nexthop
1342 vty_out(vty
, "%-16s ", "(Unknown)");
1344 if (rp_info
->i_am_rp
)
1345 vty_out(vty
, "yes");
1349 vty_out(vty
, "%14s\n", source
);
1351 prev_rp_info
= rp_info
;
1356 if (prev_rp_info
&& json_rp_rows
)
1357 json_object_object_add(
1359 inet_ntoa(prev_rp_info
->rp
.rpf_addr
.u
.prefix4
),
1362 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1363 json
, JSON_C_TO_STRING_PRETTY
));
1364 json_object_free(json
);
1368 void pim_resolve_rp_nh(struct pim_instance
*pim
, struct pim_neighbor
*nbr
)
1370 struct listnode
*node
= NULL
;
1371 struct rp_info
*rp_info
= NULL
;
1372 struct nexthop
*nh_node
= NULL
;
1373 struct prefix nht_p
;
1374 struct pim_nexthop_cache pnc
;
1376 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1377 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1380 nht_p
.family
= AF_INET
;
1381 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1382 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1383 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1384 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1388 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1389 if (nh_node
->gate
.ipv4
.s_addr
!= 0)
1392 struct interface
*ifp1
= if_lookup_by_index(
1393 nh_node
->ifindex
, pim
->vrf_id
);
1395 if (nbr
->interface
!= ifp1
)
1398 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1399 if (PIM_DEBUG_PIM_NHT_RP
) {
1400 char str
[PREFIX_STRLEN
];
1401 char str1
[INET_ADDRSTRLEN
];
1402 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1403 str1
, sizeof(str1
));
1404 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1407 "%s: addr %s new nexthop addr %s interface %s",
1408 __PRETTY_FUNCTION__
, str
, str1
,