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
, route_node_get_lock_count(rn
));
140 void pim_rp_free(struct pim_instance
*pim
)
143 list_delete(&pim
->rp_list
);
145 route_table_finish(pim
->rp_table
);
146 pim
->rp_table
= NULL
;
150 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
152 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
156 struct listnode
*node
;
157 struct rp_info
*rp_info
;
159 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
160 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
161 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
170 * Return true if plist is used by any rp_info
172 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
174 struct listnode
*node
;
175 struct rp_info
*rp_info
;
177 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
178 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
187 * Given an RP's address, return the RP's rp_info that is an exact match for
190 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
192 const struct prefix
*group
)
194 struct listnode
*node
;
195 struct rp_info
*rp_info
;
197 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
198 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
199 && prefix_same(&rp_info
->group
, group
))
207 * Given a group, return the rp_info for that group
209 struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
210 const struct prefix
*group
)
212 struct listnode
*node
;
213 struct rp_info
*best
= NULL
;
214 struct rp_info
*rp_info
;
215 struct prefix_list
*plist
;
216 const struct prefix
*p
, *bp
;
217 struct route_node
*rn
;
220 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
221 if (rp_info
->plist
) {
222 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
224 if (prefix_list_apply_which_prefix(plist
, &p
, group
)
234 if (bp
&& bp
->prefixlen
< p
->prefixlen
) {
241 rn
= route_node_match(pim
->rp_table
, group
);
245 "%s: BUG We should have found default group information\n",
251 if (PIM_DEBUG_PIM_TRACE
)
252 zlog_debug("Lookedup: %p for rp_info: %p(%pFX) Lock: %d", rn
,
253 rp_info
, &rp_info
->group
,
254 route_node_get_lock_count(rn
));
256 route_unlock_node(rn
);
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 void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
276 pim_msdp_i_am_rp_changed(pim
);
277 pim_upstream_reeval_use_rpt(pim
);
280 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
281 struct prefix_list
*plist
)
283 struct listnode
*node
;
284 struct rp_info
*rp_info
;
285 int refresh_needed
= 0;
287 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
289 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
296 pim_rp_refresh_group_to_rp_mapping(pim
);
299 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
300 struct pim_interface
*pim_ifp
)
302 struct listnode
*node
;
303 struct pim_secondary_addr
*sec_addr
;
305 if (pim_ifp
->primary_address
.s_addr
306 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
309 if (!pim_ifp
->sec_addr_list
) {
313 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
314 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
322 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
323 struct rp_info
*rp_info
)
325 struct interface
*ifp
;
327 rp_info
->i_am_rp
= 0;
328 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
329 struct pim_interface
*pim_ifp
= ifp
->info
;
334 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
335 rp_info
->i_am_rp
= 1;
340 void pim_upstream_update(struct pim_instance
*pim
, struct pim_upstream
*up
)
342 struct pim_rpf old_rpf
;
343 enum pim_rpf_result rpf_result
;
344 struct in_addr old_upstream_addr
;
345 struct in_addr new_upstream_addr
;
348 old_upstream_addr
= up
->upstream_addr
;
349 pim_rp_set_upstream_addr(pim
, &new_upstream_addr
, up
->sg
.src
,
352 if (PIM_DEBUG_PIM_TRACE
)
353 zlog_debug("%s: pim upstream update for old upstream %pI4",
354 __func__
, &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
)
371 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
372 __func__
, up
->sg_str
, &nht_p
);
373 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
376 /* Update the upstream address */
377 up
->upstream_addr
= new_upstream_addr
;
379 old_rpf
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
381 rpf_result
= pim_rpf_update(pim
, up
, &old_rpf
, __func__
);
382 if (rpf_result
== PIM_RPF_FAILURE
)
383 pim_mroute_del(up
->channel_oil
, __func__
);
385 /* update kernel multicast forwarding cache (MFC) */
386 if (up
->rpf
.source_nexthop
.interface
&& up
->channel_oil
)
387 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
389 if (rpf_result
== PIM_RPF_CHANGED
||
390 (rpf_result
== PIM_RPF_FAILURE
&&
391 old_rpf
.source_nexthop
.interface
))
392 pim_zebra_upstream_rpf_changed(pim
, up
, &old_rpf
);
394 pim_zebra_update_all_interfaces(pim
);
397 int pim_rp_new(struct pim_instance
*pim
, struct in_addr rp_addr
,
398 struct prefix group
, const char *plist
,
399 enum rp_source rp_src_flag
)
402 char rp
[INET_ADDRSTRLEN
];
403 struct rp_info
*rp_info
;
404 struct rp_info
*rp_all
;
405 struct prefix group_all
;
406 struct listnode
*node
, *nnode
;
407 struct rp_info
*tmp_rp_info
;
410 struct route_node
*rn
;
411 struct pim_upstream
*up
;
413 if (rp_addr
.s_addr
== INADDR_ANY
||
414 rp_addr
.s_addr
== INADDR_NONE
)
415 return PIM_RP_BAD_ADDRESS
;
417 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
419 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
420 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_PREFIXLEN
;
421 rp_info
->rp
.rpf_addr
.u
.prefix4
= rp_addr
;
422 prefix_copy(&rp_info
->group
, &group
);
423 rp_info
->rp_src
= rp_src_flag
;
425 inet_ntop(AF_INET
, &rp_info
->rp
.rpf_addr
.u
.prefix4
, rp
, sizeof(rp
));
429 * Return if the prefix-list is already configured for this RP
431 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
433 XFREE(MTYPE_PIM_RP
, rp_info
);
438 * Barf if the prefix-list is already configured for an RP
440 if (pim_rp_prefix_list_used(pim
, plist
)) {
441 XFREE(MTYPE_PIM_RP
, rp_info
);
442 return PIM_RP_PFXLIST_IN_USE
;
446 * Free any existing rp_info entries for this RP
448 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
450 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
451 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
452 if (tmp_rp_info
->plist
)
453 pim_rp_del_config(pim
, rp
, NULL
,
458 prefix2str(&tmp_rp_info
->group
,
464 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
467 if (!str2prefix("224.0.0.0/4", &group_all
)) {
468 XFREE(MTYPE_PIM_RP
, rp_info
);
469 return PIM_GROUP_BAD_ADDRESS
;
471 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
474 * Barf if group is a non-multicast subnet
476 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
477 XFREE(MTYPE_PIM_RP
, rp_info
);
478 return PIM_GROUP_BAD_ADDRESS
;
482 * Remove any prefix-list rp_info entries for this RP
484 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
486 if (tmp_rp_info
->plist
487 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
488 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
490 pim_rp_del_config(pim
, rp
, NULL
,
496 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
498 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
499 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
500 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
501 rp_all
->rp_src
= rp_src_flag
;
502 XFREE(MTYPE_PIM_RP
, rp_info
);
504 /* Register addr with Zebra NHT */
505 nht_p
.family
= AF_INET
;
506 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
508 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
509 if (PIM_DEBUG_PIM_NHT_RP
)
511 "%s: NHT Register rp_all addr %pFX grp %pFX ",
512 __func__
, &nht_p
, &rp_all
->group
);
514 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
515 /* Find (*, G) upstream whose RP is not
518 if ((up
->upstream_addr
.s_addr
== INADDR_ANY
)
519 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
521 struct rp_info
*trp_info
;
523 grp
.family
= AF_INET
;
524 grp
.prefixlen
= IPV4_MAX_BITLEN
;
525 grp
.u
.prefix4
= up
->sg
.grp
;
526 trp_info
= pim_rp_find_match_group(
528 if (trp_info
== rp_all
)
529 pim_upstream_update(pim
, up
);
533 pim_rp_check_interfaces(pim
, rp_all
);
534 pim_rp_refresh_group_to_rp_mapping(pim
);
535 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
538 if (!pim_ecmp_nexthop_lookup(pim
,
539 &rp_all
->rp
.source_nexthop
,
540 &nht_p
, &rp_all
->group
, 1))
541 return PIM_RP_NO_PATH
;
546 * Return if the group is already configured for this RP
548 tmp_rp_info
= pim_rp_find_exact(
549 pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
, &rp_info
->group
);
551 if ((tmp_rp_info
->rp_src
!= rp_src_flag
)
552 && (rp_src_flag
== RP_SRC_STATIC
))
553 tmp_rp_info
->rp_src
= rp_src_flag
;
554 XFREE(MTYPE_PIM_RP
, rp_info
);
559 * Barf if this group is already covered by some other RP
561 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
564 if (tmp_rp_info
->plist
) {
565 XFREE(MTYPE_PIM_RP
, rp_info
);
566 return PIM_GROUP_PFXLIST_OVERLAP
;
569 * If the only RP that covers this group is an
571 * 224.0.0.0/4 that is fine, ignore that one.
573 * though we must return PIM_GROUP_OVERLAP
575 if (prefix_same(&rp_info
->group
,
576 &tmp_rp_info
->group
)) {
577 if ((rp_src_flag
== RP_SRC_STATIC
)
578 && (tmp_rp_info
->rp_src
580 XFREE(MTYPE_PIM_RP
, rp_info
);
581 return PIM_GROUP_OVERLAP
;
584 result
= pim_rp_change(
586 rp_info
->rp
.rpf_addr
.u
.prefix4
,
589 XFREE(MTYPE_PIM_RP
, rp_info
);
596 listnode_add_sort(pim
->rp_list
, rp_info
);
597 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
600 if (PIM_DEBUG_PIM_TRACE
)
601 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn
,
602 rp_info
, &rp_info
->group
,
603 route_node_get_lock_count(rn
));
605 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
606 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
608 struct rp_info
*trp_info
;
610 grp
.family
= AF_INET
;
611 grp
.prefixlen
= IPV4_MAX_BITLEN
;
612 grp
.u
.prefix4
= up
->sg
.grp
;
613 trp_info
= pim_rp_find_match_group(pim
, &grp
);
615 if (trp_info
== rp_info
)
616 pim_upstream_update(pim
, up
);
620 pim_rp_check_interfaces(pim
, rp_info
);
621 pim_rp_refresh_group_to_rp_mapping(pim
);
623 /* Register addr with Zebra NHT */
624 nht_p
.family
= AF_INET
;
625 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
626 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
627 if (PIM_DEBUG_PIM_NHT_RP
)
628 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
629 __func__
, &nht_p
, &rp_info
->group
);
630 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
631 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
633 return PIM_RP_NO_PATH
;
638 int pim_rp_del_config(struct pim_instance
*pim
, const char *rp
,
639 const char *group_range
, const char *plist
)
642 struct in_addr rp_addr
;
645 if (group_range
== NULL
)
646 result
= str2prefix("224.0.0.0/4", &group
);
648 result
= str2prefix(group_range
, &group
);
651 return PIM_GROUP_BAD_ADDRESS
;
653 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
655 return PIM_RP_BAD_ADDRESS
;
657 result
= pim_rp_del(pim
, rp_addr
, group
, plist
, RP_SRC_STATIC
);
661 int pim_rp_del(struct pim_instance
*pim
, struct in_addr rp_addr
,
662 struct prefix group
, const char *plist
,
663 enum rp_source rp_src_flag
)
666 struct rp_info
*rp_info
;
667 struct rp_info
*rp_all
;
669 struct route_node
*rn
;
670 bool was_plist
= false;
671 struct rp_info
*trp_info
;
672 struct pim_upstream
*up
;
673 struct bsgrp_node
*bsgrp
= NULL
;
674 struct bsm_rpinfo
*bsrp
= NULL
;
675 char rp_str
[INET_ADDRSTRLEN
];
677 if (!inet_ntop(AF_INET
, &rp_addr
, rp_str
, sizeof(rp_str
)))
678 snprintf(rp_str
, sizeof(rp_str
), "<rp?>");
681 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
683 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
686 return PIM_RP_NOT_FOUND
;
688 if (rp_info
->plist
) {
689 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
693 if (PIM_DEBUG_PIM_TRACE
)
694 zlog_debug("%s: Delete RP %s for the group %pFX", __func__
,
697 /* While static RP is getting deleted, we need to check if dynamic RP
698 * present for the same group in BSM RP table, then install the dynamic
699 * RP for the group node into the main rp table
701 if (rp_src_flag
== RP_SRC_STATIC
) {
702 bsgrp
= pim_bsm_get_bsgrp_node(&pim
->global_scope
, &group
);
705 bsrp
= listnode_head(bsgrp
->bsrp_list
);
707 if (PIM_DEBUG_PIM_TRACE
) {
708 char bsrp_str
[INET_ADDRSTRLEN
];
710 if (!inet_ntop(AF_INET
, bsrp
, bsrp_str
,
717 "%s: BSM RP %s found for the group %pFX",
718 __func__
, bsrp_str
, &group
);
720 return pim_rp_change(pim
, bsrp
->rp_address
,
724 if (PIM_DEBUG_PIM_TRACE
)
726 "%s: BSM RP not found for the group %pFX",
731 /* Deregister addr with Zebra NHT */
732 nht_p
.family
= AF_INET
;
733 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
734 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
735 if (PIM_DEBUG_PIM_NHT_RP
)
736 zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__
,
738 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
740 if (!str2prefix("224.0.0.0/4", &g_all
))
741 return PIM_RP_BAD_ADDRESS
;
743 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
745 if (rp_all
== rp_info
) {
746 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
747 /* Find the upstream (*, G) whose upstream address is
748 * same as the deleted RP
750 if ((up
->upstream_addr
.s_addr
751 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
752 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
754 grp
.family
= AF_INET
;
755 grp
.prefixlen
= IPV4_MAX_BITLEN
;
756 grp
.u
.prefix4
= up
->sg
.grp
;
757 trp_info
= pim_rp_find_match_group(pim
, &grp
);
758 if (trp_info
== rp_all
) {
759 pim_upstream_rpf_clear(pim
, up
);
760 up
->upstream_addr
.s_addr
= INADDR_ANY
;
764 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
765 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
770 listnode_delete(pim
->rp_list
, rp_info
);
773 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
775 if (rn
->info
!= rp_info
)
778 "Expected rn->info to be equal to rp_info");
780 if (PIM_DEBUG_PIM_TRACE
)
782 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
783 __func__
, rn
, rp_info
, &rp_info
->group
,
784 route_node_get_lock_count(rn
));
787 route_unlock_node(rn
);
788 route_unlock_node(rn
);
792 pim_rp_refresh_group_to_rp_mapping(pim
);
794 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
795 /* Find the upstream (*, G) whose upstream address is same as
798 if ((up
->upstream_addr
.s_addr
799 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
800 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
803 grp
.family
= AF_INET
;
804 grp
.prefixlen
= IPV4_MAX_BITLEN
;
805 grp
.u
.prefix4
= up
->sg
.grp
;
807 trp_info
= pim_rp_find_match_group(pim
, &grp
);
809 /* RP not found for the group grp */
810 if (pim_rpf_addr_is_inaddr_none(&trp_info
->rp
)) {
811 pim_upstream_rpf_clear(pim
, up
);
812 pim_rp_set_upstream_addr(
813 pim
, &up
->upstream_addr
, up
->sg
.src
,
817 /* RP found for the group grp */
819 pim_upstream_update(pim
, up
);
823 XFREE(MTYPE_PIM_RP
, rp_info
);
827 int pim_rp_change(struct pim_instance
*pim
, struct in_addr new_rp_addr
,
828 struct prefix group
, enum rp_source rp_src_flag
)
831 struct route_node
*rn
;
833 struct rp_info
*rp_info
= NULL
;
834 struct pim_upstream
*up
;
836 rn
= route_node_lookup(pim
->rp_table
, &group
);
838 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
845 route_unlock_node(rn
);
846 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
850 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== new_rp_addr
.s_addr
) {
851 if (rp_info
->rp_src
!= rp_src_flag
) {
852 rp_info
->rp_src
= rp_src_flag
;
853 route_unlock_node(rn
);
858 nht_p
.family
= AF_INET
;
859 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
861 /* Deregister old RP addr with Zebra NHT */
862 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
!= INADDR_ANY
) {
863 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
864 if (PIM_DEBUG_PIM_NHT_RP
)
865 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
867 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
870 pim_rp_nexthop_del(rp_info
);
871 listnode_delete(pim
->rp_list
, rp_info
);
872 /* Update the new RP address*/
873 rp_info
->rp
.rpf_addr
.u
.prefix4
= new_rp_addr
;
874 rp_info
->rp_src
= rp_src_flag
;
875 rp_info
->i_am_rp
= 0;
877 listnode_add_sort(pim
->rp_list
, rp_info
);
879 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
880 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
882 struct rp_info
*trp_info
;
884 grp
.family
= AF_INET
;
885 grp
.prefixlen
= IPV4_MAX_BITLEN
;
886 grp
.u
.prefix4
= up
->sg
.grp
;
887 trp_info
= pim_rp_find_match_group(pim
, &grp
);
889 if (trp_info
== rp_info
)
890 pim_upstream_update(pim
, up
);
894 /* Register new RP addr with Zebra NHT */
895 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
896 if (PIM_DEBUG_PIM_NHT_RP
)
897 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
898 __func__
, &nht_p
, &rp_info
->group
);
900 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
901 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
902 &rp_info
->group
, 1)) {
903 route_unlock_node(rn
);
904 return PIM_RP_NO_PATH
;
907 pim_rp_check_interfaces(pim
, rp_info
);
909 route_unlock_node(rn
);
911 pim_rp_refresh_group_to_rp_mapping(pim
);
916 void pim_rp_setup(struct pim_instance
*pim
)
918 struct listnode
*node
;
919 struct rp_info
*rp_info
;
922 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
923 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
926 nht_p
.family
= AF_INET
;
927 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
928 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
930 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
932 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
933 &nht_p
, &rp_info
->group
, 1))
934 if (PIM_DEBUG_PIM_NHT_RP
)
936 "Unable to lookup nexthop for rp specified");
941 * Checks to see if we should elect ourself the actual RP when new if
942 * addresses are added against an interface.
944 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
946 struct listnode
*node
;
947 struct rp_info
*rp_info
;
948 bool i_am_rp_changed
= false;
949 struct pim_instance
*pim
= pim_ifp
->pim
;
951 if (pim
->rp_list
== NULL
)
954 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
955 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
958 /* if i_am_rp is already set nothing to be done (adding new
960 * is not going to make a difference). */
961 if (rp_info
->i_am_rp
) {
965 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
966 i_am_rp_changed
= true;
967 rp_info
->i_am_rp
= 1;
968 if (PIM_DEBUG_PIM_NHT_RP
) {
969 char rp
[PREFIX_STRLEN
];
970 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
972 zlog_debug("%s: %s: i am rp", __func__
, rp
);
977 if (i_am_rp_changed
) {
978 pim_msdp_i_am_rp_changed(pim
);
979 pim_upstream_reeval_use_rpt(pim
);
983 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
984 * are removed. Removing numbers is an uncommon event in an active network
985 * so I have made no attempt to optimize it. */
986 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
988 struct listnode
*node
;
989 struct rp_info
*rp_info
;
990 bool i_am_rp_changed
= false;
993 if (pim
->rp_list
== NULL
)
996 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
997 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1000 old_i_am_rp
= rp_info
->i_am_rp
;
1001 pim_rp_check_interfaces(pim
, rp_info
);
1003 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
1004 i_am_rp_changed
= true;
1005 if (PIM_DEBUG_PIM_NHT_RP
) {
1006 char rp
[PREFIX_STRLEN
];
1007 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1009 if (rp_info
->i_am_rp
) {
1010 zlog_debug("%s: %s: i am rp", __func__
,
1013 zlog_debug("%s: %s: i am no longer rp",
1020 if (i_am_rp_changed
) {
1021 pim_msdp_i_am_rp_changed(pim
);
1022 pim_upstream_reeval_use_rpt(pim
);
1027 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1028 * this router is the RP for the group.
1030 * Since we only have static RP, all groups are part of this RP
1032 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
1035 struct rp_info
*rp_info
;
1037 memset(&g
, 0, sizeof(g
));
1040 g
.u
.prefix4
= group
;
1042 rp_info
= pim_rp_find_match_group(pim
, &g
);
1045 return rp_info
->i_am_rp
;
1053 * Return the RP that the Group belongs too.
1055 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
1058 struct rp_info
*rp_info
;
1060 memset(&g
, 0, sizeof(g
));
1063 g
.u
.prefix4
= group
;
1065 rp_info
= pim_rp_find_match_group(pim
, &g
);
1068 struct prefix nht_p
;
1070 /* Register addr with Zebra NHT */
1071 nht_p
.family
= AF_INET
;
1072 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1073 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1074 if (PIM_DEBUG_PIM_NHT_RP
)
1076 "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
1077 __func__
, &nht_p
, &rp_info
->group
);
1078 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
1080 pim_rpf_set_refresh_time(pim
);
1081 (void)pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
1082 &nht_p
, &rp_info
->group
, 1);
1083 return (&rp_info
->rp
);
1091 * Set the upstream IP address we want to talk to based upon
1092 * the rp configured and the source address
1094 * If we have don't have a RP configured and the source address is *
1095 * then set the upstream addr as INADDR_ANY and return failure.
1098 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
1099 struct in_addr source
, struct in_addr group
)
1101 struct rp_info
*rp_info
;
1104 memset(&g
, 0, sizeof(g
));
1107 g
.u
.prefix4
= group
;
1109 rp_info
= pim_rp_find_match_group(pim
, &g
);
1111 if (!rp_info
|| ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1112 && (source
.s_addr
== INADDR_ANY
))) {
1113 if (PIM_DEBUG_PIM_NHT_RP
)
1114 zlog_debug("%s: Received a (*,G) with no RP configured",
1116 up
->s_addr
= INADDR_ANY
;
1120 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
1126 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
1129 struct listnode
*node
;
1130 struct rp_info
*rp_info
;
1134 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1135 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1138 if (rp_info
->rp_src
== RP_SRC_BSR
)
1142 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
1144 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1148 vty_out(vty
, "%sip pim rp %s %pFX\n", spaces
,
1150 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1159 bool pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
1160 struct in_addr dest_addr
)
1162 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf_id
))
1168 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1170 struct rp_info
*rp_info
;
1171 struct rp_info
*prev_rp_info
= NULL
;
1172 struct listnode
*node
;
1174 char buf
[PREFIX_STRLEN
];
1176 json_object
*json
= NULL
;
1177 json_object
*json_rp_rows
= NULL
;
1178 json_object
*json_row
= NULL
;
1181 json
= json_object_new_object();
1184 "RP address group/prefix-list OIF I am RP Source\n");
1185 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1186 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
1189 if (rp_info
->rp_src
== RP_SRC_STATIC
)
1190 strlcpy(source
, "Static", sizeof(source
));
1191 else if (rp_info
->rp_src
== RP_SRC_BSR
)
1192 strlcpy(source
, "BSR", sizeof(source
));
1194 strlcpy(source
, "None", sizeof(source
));
1197 * If we have moved on to a new RP then add the
1198 * entry for the previous RP
1201 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1203 != rp_info
->rp
.rpf_addr
.u
.prefix4
1205 json_object_object_add(
1213 json_rp_rows
= NULL
;
1217 json_rp_rows
= json_object_new_array();
1219 json_row
= json_object_new_object();
1220 json_object_string_add(
1221 json_row
, "rpAddress",
1223 &rp_info
->rp
.rpf_addr
.u
1226 if (rp_info
->rp
.source_nexthop
.interface
)
1227 json_object_string_add(
1228 json_row
, "outboundInterface",
1229 rp_info
->rp
.source_nexthop
1232 json_object_string_add(
1233 json_row
, "outboundInterface",
1235 if (rp_info
->i_am_rp
)
1236 json_object_boolean_true_add(json_row
,
1239 json_object_boolean_false_add(json_row
,
1243 json_object_string_add(json_row
,
1247 json_object_string_add(
1249 prefix2str(&rp_info
->group
, buf
,
1251 json_object_string_add(json_row
, "source",
1254 json_object_array_add(json_rp_rows
, json_row
);
1256 vty_out(vty
, "%-15s ",
1258 &rp_info
->rp
.rpf_addr
.u
1263 vty_out(vty
, "%-18s ", rp_info
->plist
);
1265 vty_out(vty
, "%-18pFX ",
1268 if (rp_info
->rp
.source_nexthop
.interface
)
1269 vty_out(vty
, "%-16s ",
1270 rp_info
->rp
.source_nexthop
1273 vty_out(vty
, "%-16s ", "(Unknown)");
1275 if (rp_info
->i_am_rp
)
1276 vty_out(vty
, "yes");
1280 vty_out(vty
, "%14s\n", source
);
1282 prev_rp_info
= rp_info
;
1287 if (prev_rp_info
&& json_rp_rows
)
1288 json_object_object_add(
1291 &prev_rp_info
->rp
.rpf_addr
.u
.prefix4
,
1295 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1296 json
, JSON_C_TO_STRING_PRETTY
));
1297 json_object_free(json
);
1301 void pim_resolve_rp_nh(struct pim_instance
*pim
, struct pim_neighbor
*nbr
)
1303 struct listnode
*node
= NULL
;
1304 struct rp_info
*rp_info
= NULL
;
1305 struct nexthop
*nh_node
= NULL
;
1306 struct prefix nht_p
;
1307 struct pim_nexthop_cache pnc
;
1309 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1310 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1313 nht_p
.family
= AF_INET
;
1314 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1315 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1316 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1317 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1321 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1322 if (nh_node
->gate
.ipv4
.s_addr
!= INADDR_ANY
)
1325 struct interface
*ifp1
= if_lookup_by_index(
1326 nh_node
->ifindex
, pim
->vrf_id
);
1328 if (nbr
->interface
!= ifp1
)
1331 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1332 if (PIM_DEBUG_PIM_NHT_RP
) {
1333 char str
[PREFIX_STRLEN
];
1334 char str1
[INET_ADDRSTRLEN
];
1335 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1336 str1
, sizeof(str1
));
1337 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1340 "%s: addr %s new nexthop addr %s interface %s",
1341 __func__
, str
, str1
, ifp1
->name
);