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"
43 #include "pim_memory.h"
44 #include "pim_neighbor.h"
47 #include "pim_mroute.h"
49 #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_BITLEN
;
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
);
133 if (PIM_DEBUG_PIM_TRACE
)
135 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
136 rn
, rp_info
, route_node_get_lock_count(rn
));
139 void pim_rp_free(struct pim_instance
*pim
)
142 route_table_finish(pim
->rp_table
);
143 pim
->rp_table
= NULL
;
146 list_delete(&pim
->rp_list
);
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 * XXX: long-term issue: we don't actually have a good "ip address-list"
208 * implementation. ("access-list XYZ" is the closest but honestly it's
211 * So it's using a prefix-list to match an address here, which causes very
212 * unexpected results for the user since prefix-lists by default only match
213 * when the prefix length is an exact match too. i.e. you'd have to add the
214 * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32"
216 * To avoid this pitfall, this code uses "address_mode = true" for the prefix
217 * list match (this is the only user for that.)
219 * In the long run, we need to add a "ip address-list", but that's a wholly
220 * separate bag of worms, and existing configs using ip prefix-list would
221 * drop into the UX pitfall.
224 #include "lib/plist_int.h"
227 * Given a group, return the rp_info for that group
229 struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
230 const struct prefix
*group
)
232 struct listnode
*node
;
233 struct rp_info
*best
= NULL
;
234 struct rp_info
*rp_info
;
235 struct prefix_list
*plist
;
236 const struct prefix
*bp
;
237 const struct prefix_list_entry
*entry
;
238 struct route_node
*rn
;
241 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
242 if (rp_info
->plist
) {
243 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
245 if (prefix_list_apply_ext(plist
, &entry
, group
, true)
246 == PREFIX_DENY
|| !entry
)
255 if (bp
&& bp
->prefixlen
< entry
->prefix
.prefixlen
) {
262 rn
= route_node_match(pim
->rp_table
, group
);
266 "%s: BUG We should have found default group information",
272 if (PIM_DEBUG_PIM_TRACE
)
273 zlog_debug("Lookedup: %p for rp_info: %p(%pFX) Lock: %d", rn
,
274 rp_info
, &rp_info
->group
,
275 route_node_get_lock_count(rn
));
277 route_unlock_node(rn
);
282 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
289 * When the user makes "ip pim rp" configuration changes or if they change the
290 * prefix-list(s) used by these statements we must tickle the upstream state
291 * for each group to make them re-lookup who their RP should be.
293 * This is a placeholder function for now.
295 void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
297 pim_msdp_i_am_rp_changed(pim
);
298 pim_upstream_reeval_use_rpt(pim
);
301 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
302 struct prefix_list
*plist
)
304 struct listnode
*node
;
305 struct rp_info
*rp_info
;
306 int refresh_needed
= 0;
308 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
310 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
317 pim_rp_refresh_group_to_rp_mapping(pim
);
320 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
321 struct pim_interface
*pim_ifp
)
323 struct listnode
*node
;
324 struct pim_secondary_addr
*sec_addr
;
326 if (pim_ifp
->primary_address
.s_addr
327 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
330 if (!pim_ifp
->sec_addr_list
) {
334 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
335 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
343 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
344 struct rp_info
*rp_info
)
346 struct interface
*ifp
;
348 rp_info
->i_am_rp
= 0;
349 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
350 struct pim_interface
*pim_ifp
= ifp
->info
;
355 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
356 rp_info
->i_am_rp
= 1;
361 void pim_upstream_update(struct pim_instance
*pim
, struct pim_upstream
*up
)
363 struct pim_rpf old_rpf
;
364 enum pim_rpf_result rpf_result
;
365 struct in_addr old_upstream_addr
;
366 struct in_addr new_upstream_addr
;
369 old_upstream_addr
= up
->upstream_addr
;
370 pim_rp_set_upstream_addr(pim
, &new_upstream_addr
, up
->sg
.src
,
373 if (PIM_DEBUG_PIM_TRACE
)
374 zlog_debug("%s: pim upstream update for old upstream %pI4",
375 __func__
, &old_upstream_addr
);
377 if (old_upstream_addr
.s_addr
== new_upstream_addr
.s_addr
)
380 /* Lets consider a case, where a PIM upstream has a better RP as a
381 * result of a new RP configuration with more precise group range.
382 * This upstream has to be added to the upstream hash of new RP's
383 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
385 if (old_upstream_addr
.s_addr
!= INADDR_ANY
) {
386 /* Deregister addr with Zebra NHT */
387 nht_p
.family
= AF_INET
;
388 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
389 nht_p
.u
.prefix4
= old_upstream_addr
;
390 if (PIM_DEBUG_PIM_TRACE
)
392 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
393 __func__
, up
->sg_str
, &nht_p
);
394 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
);
397 /* Update the upstream address */
398 up
->upstream_addr
= new_upstream_addr
;
400 old_rpf
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
402 rpf_result
= pim_rpf_update(pim
, up
, &old_rpf
, __func__
);
403 if (rpf_result
== PIM_RPF_FAILURE
)
404 pim_mroute_del(up
->channel_oil
, __func__
);
406 /* update kernel multicast forwarding cache (MFC) */
407 if (up
->rpf
.source_nexthop
.interface
&& up
->channel_oil
)
408 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
410 if (rpf_result
== PIM_RPF_CHANGED
||
411 (rpf_result
== PIM_RPF_FAILURE
&&
412 old_rpf
.source_nexthop
.interface
))
413 pim_zebra_upstream_rpf_changed(pim
, up
, &old_rpf
);
417 int pim_rp_new(struct pim_instance
*pim
, struct in_addr rp_addr
,
418 struct prefix group
, const char *plist
,
419 enum rp_source rp_src_flag
)
422 char rp
[INET_ADDRSTRLEN
];
423 struct rp_info
*rp_info
;
424 struct rp_info
*rp_all
;
425 struct prefix group_all
;
426 struct listnode
*node
, *nnode
;
427 struct rp_info
*tmp_rp_info
;
430 struct route_node
*rn
;
431 struct pim_upstream
*up
;
432 bool upstream_updated
= false;
434 if (rp_addr
.s_addr
== INADDR_ANY
||
435 rp_addr
.s_addr
== INADDR_NONE
)
436 return PIM_RP_BAD_ADDRESS
;
438 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
440 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
441 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
442 rp_info
->rp
.rpf_addr
.u
.prefix4
= rp_addr
;
443 prefix_copy(&rp_info
->group
, &group
);
444 rp_info
->rp_src
= rp_src_flag
;
446 inet_ntop(AF_INET
, &rp_info
->rp
.rpf_addr
.u
.prefix4
, rp
, sizeof(rp
));
450 * Return if the prefix-list is already configured for this RP
452 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
454 XFREE(MTYPE_PIM_RP
, rp_info
);
459 * Barf if the prefix-list is already configured for an RP
461 if (pim_rp_prefix_list_used(pim
, plist
)) {
462 XFREE(MTYPE_PIM_RP
, rp_info
);
463 return PIM_RP_PFXLIST_IN_USE
;
467 * Free any existing rp_info entries for this RP
469 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
471 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
472 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
473 if (tmp_rp_info
->plist
)
474 pim_rp_del_config(pim
, rp
, NULL
,
479 prefix2str(&tmp_rp_info
->group
,
485 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
488 if (!str2prefix("224.0.0.0/4", &group_all
)) {
489 XFREE(MTYPE_PIM_RP
, rp_info
);
490 return PIM_GROUP_BAD_ADDRESS
;
492 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
495 * Barf if group is a non-multicast subnet
497 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
498 XFREE(MTYPE_PIM_RP
, rp_info
);
499 return PIM_GROUP_BAD_ADDRESS
;
503 * Remove any prefix-list rp_info entries for this RP
505 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
507 if (tmp_rp_info
->plist
508 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
509 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
511 pim_rp_del_config(pim
, rp
, NULL
,
517 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
519 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
520 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
521 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
522 rp_all
->rp_src
= rp_src_flag
;
523 XFREE(MTYPE_PIM_RP
, rp_info
);
525 /* Register addr with Zebra NHT */
526 nht_p
.family
= AF_INET
;
527 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
529 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
530 if (PIM_DEBUG_PIM_NHT_RP
)
532 "%s: NHT Register rp_all addr %pFX grp %pFX ",
533 __func__
, &nht_p
, &rp_all
->group
);
535 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
536 /* Find (*, G) upstream whose RP is not
539 if ((up
->upstream_addr
.s_addr
== INADDR_ANY
)
540 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
542 struct rp_info
*trp_info
;
544 grp
.family
= AF_INET
;
545 grp
.prefixlen
= IPV4_MAX_BITLEN
;
546 grp
.u
.prefix4
= up
->sg
.grp
;
547 trp_info
= pim_rp_find_match_group(
549 if (trp_info
== rp_all
) {
550 pim_upstream_update(pim
, up
);
551 upstream_updated
= true;
555 if (upstream_updated
)
556 pim_zebra_update_all_interfaces(pim
);
558 pim_rp_check_interfaces(pim
, rp_all
);
559 pim_rp_refresh_group_to_rp_mapping(pim
);
560 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
563 if (!pim_ecmp_nexthop_lookup(pim
,
564 &rp_all
->rp
.source_nexthop
,
565 &nht_p
, &rp_all
->group
, 1))
566 return PIM_RP_NO_PATH
;
571 * Return if the group is already configured for this RP
573 tmp_rp_info
= pim_rp_find_exact(
574 pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
, &rp_info
->group
);
576 if ((tmp_rp_info
->rp_src
!= rp_src_flag
)
577 && (rp_src_flag
== RP_SRC_STATIC
))
578 tmp_rp_info
->rp_src
= rp_src_flag
;
579 XFREE(MTYPE_PIM_RP
, rp_info
);
584 * Barf if this group is already covered by some other RP
586 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
589 if (tmp_rp_info
->plist
) {
590 XFREE(MTYPE_PIM_RP
, rp_info
);
591 return PIM_GROUP_PFXLIST_OVERLAP
;
594 * If the only RP that covers this group is an
596 * 224.0.0.0/4 that is fine, ignore that one.
598 * though we must return PIM_GROUP_OVERLAP
600 if (prefix_same(&rp_info
->group
,
601 &tmp_rp_info
->group
)) {
602 if ((rp_src_flag
== RP_SRC_STATIC
)
603 && (tmp_rp_info
->rp_src
605 XFREE(MTYPE_PIM_RP
, rp_info
);
606 return PIM_GROUP_OVERLAP
;
609 result
= pim_rp_change(
611 rp_info
->rp
.rpf_addr
.u
.prefix4
,
614 XFREE(MTYPE_PIM_RP
, rp_info
);
621 listnode_add_sort(pim
->rp_list
, rp_info
);
622 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
625 if (PIM_DEBUG_PIM_TRACE
)
626 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn
,
627 rp_info
, &rp_info
->group
,
628 route_node_get_lock_count(rn
));
630 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
631 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
633 struct rp_info
*trp_info
;
635 grp
.family
= AF_INET
;
636 grp
.prefixlen
= IPV4_MAX_BITLEN
;
637 grp
.u
.prefix4
= up
->sg
.grp
;
638 trp_info
= pim_rp_find_match_group(pim
, &grp
);
640 if (trp_info
== rp_info
) {
641 pim_upstream_update(pim
, up
);
642 upstream_updated
= true;
647 if (upstream_updated
)
648 pim_zebra_update_all_interfaces(pim
);
650 pim_rp_check_interfaces(pim
, rp_info
);
651 pim_rp_refresh_group_to_rp_mapping(pim
);
653 /* Register addr with Zebra NHT */
654 nht_p
.family
= AF_INET
;
655 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
656 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
657 if (PIM_DEBUG_PIM_NHT_RP
)
658 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
659 __func__
, &nht_p
, &rp_info
->group
);
660 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, NULL
);
661 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
663 return PIM_RP_NO_PATH
;
668 int pim_rp_del_config(struct pim_instance
*pim
, const char *rp
,
669 const char *group_range
, const char *plist
)
672 struct in_addr rp_addr
;
675 if (group_range
== NULL
)
676 result
= str2prefix("224.0.0.0/4", &group
);
678 result
= str2prefix(group_range
, &group
);
681 return PIM_GROUP_BAD_ADDRESS
;
683 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
685 return PIM_RP_BAD_ADDRESS
;
687 result
= pim_rp_del(pim
, rp_addr
, group
, plist
, RP_SRC_STATIC
);
691 int pim_rp_del(struct pim_instance
*pim
, struct in_addr rp_addr
,
692 struct prefix group
, const char *plist
,
693 enum rp_source rp_src_flag
)
696 struct rp_info
*rp_info
;
697 struct rp_info
*rp_all
;
699 struct route_node
*rn
;
700 bool was_plist
= false;
701 struct rp_info
*trp_info
;
702 struct pim_upstream
*up
;
703 struct bsgrp_node
*bsgrp
= NULL
;
704 struct bsm_rpinfo
*bsrp
= NULL
;
705 char rp_str
[INET_ADDRSTRLEN
];
706 bool upstream_updated
= false;
708 if (!inet_ntop(AF_INET
, &rp_addr
, rp_str
, sizeof(rp_str
)))
709 snprintf(rp_str
, sizeof(rp_str
), "<rp?>");
712 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
714 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
717 return PIM_RP_NOT_FOUND
;
719 if (rp_info
->plist
) {
720 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
724 if (PIM_DEBUG_PIM_TRACE
)
725 zlog_debug("%s: Delete RP %s for the group %pFX", __func__
,
728 /* While static RP is getting deleted, we need to check if dynamic RP
729 * present for the same group in BSM RP table, then install the dynamic
730 * RP for the group node into the main rp table
732 if (rp_src_flag
== RP_SRC_STATIC
) {
733 bsgrp
= pim_bsm_get_bsgrp_node(&pim
->global_scope
, &group
);
736 bsrp
= bsm_rpinfos_first(bsgrp
->bsrp_list
);
738 if (PIM_DEBUG_PIM_TRACE
) {
739 char bsrp_str
[INET_ADDRSTRLEN
];
741 if (!inet_ntop(AF_INET
, bsrp
, bsrp_str
,
748 "%s: BSM RP %s found for the group %pFX",
749 __func__
, bsrp_str
, &group
);
751 return pim_rp_change(pim
, bsrp
->rp_address
,
755 if (PIM_DEBUG_PIM_TRACE
)
757 "%s: BSM RP not found for the group %pFX",
762 /* Deregister addr with Zebra NHT */
763 nht_p
.family
= AF_INET
;
764 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
765 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
766 if (PIM_DEBUG_PIM_NHT_RP
)
767 zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__
,
769 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
771 if (!str2prefix("224.0.0.0/4", &g_all
))
772 return PIM_RP_BAD_ADDRESS
;
774 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
776 if (rp_all
== rp_info
) {
777 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
778 /* Find the upstream (*, G) whose upstream address is
779 * same as the deleted RP
781 if ((up
->upstream_addr
.s_addr
782 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
783 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
785 grp
.family
= AF_INET
;
786 grp
.prefixlen
= IPV4_MAX_BITLEN
;
787 grp
.u
.prefix4
= up
->sg
.grp
;
788 trp_info
= pim_rp_find_match_group(pim
, &grp
);
789 if (trp_info
== rp_all
) {
790 pim_upstream_rpf_clear(pim
, up
);
791 up
->upstream_addr
.s_addr
= INADDR_ANY
;
795 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
796 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
801 listnode_delete(pim
->rp_list
, rp_info
);
804 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
806 if (rn
->info
!= rp_info
)
809 "Expected rn->info to be equal to rp_info");
811 if (PIM_DEBUG_PIM_TRACE
)
813 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
814 __func__
, rn
, rp_info
, &rp_info
->group
,
815 route_node_get_lock_count(rn
));
818 route_unlock_node(rn
);
819 route_unlock_node(rn
);
823 pim_rp_refresh_group_to_rp_mapping(pim
);
825 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
826 /* Find the upstream (*, G) whose upstream address is same as
829 if ((up
->upstream_addr
.s_addr
830 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
831 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
834 grp
.family
= AF_INET
;
835 grp
.prefixlen
= IPV4_MAX_BITLEN
;
836 grp
.u
.prefix4
= up
->sg
.grp
;
838 trp_info
= pim_rp_find_match_group(pim
, &grp
);
840 /* RP not found for the group grp */
841 if (pim_rpf_addr_is_inaddr_none(&trp_info
->rp
)) {
842 pim_upstream_rpf_clear(pim
, up
);
843 pim_rp_set_upstream_addr(
844 pim
, &up
->upstream_addr
, up
->sg
.src
,
848 /* RP found for the group grp */
850 pim_upstream_update(pim
, up
);
851 upstream_updated
= true;
856 if (upstream_updated
)
857 pim_zebra_update_all_interfaces(pim
);
859 XFREE(MTYPE_PIM_RP
, rp_info
);
863 int pim_rp_change(struct pim_instance
*pim
, struct in_addr new_rp_addr
,
864 struct prefix group
, enum rp_source rp_src_flag
)
867 struct route_node
*rn
;
869 struct rp_info
*rp_info
= NULL
;
870 struct pim_upstream
*up
;
871 bool upstream_updated
= false;
873 rn
= route_node_lookup(pim
->rp_table
, &group
);
875 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
882 route_unlock_node(rn
);
883 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
887 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== new_rp_addr
.s_addr
) {
888 if (rp_info
->rp_src
!= rp_src_flag
) {
889 rp_info
->rp_src
= rp_src_flag
;
890 route_unlock_node(rn
);
895 nht_p
.family
= AF_INET
;
896 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
898 /* Deregister old RP addr with Zebra NHT */
899 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
!= INADDR_ANY
) {
900 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
901 if (PIM_DEBUG_PIM_NHT_RP
)
902 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
904 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
);
907 pim_rp_nexthop_del(rp_info
);
908 listnode_delete(pim
->rp_list
, rp_info
);
909 /* Update the new RP address*/
910 rp_info
->rp
.rpf_addr
.u
.prefix4
= new_rp_addr
;
911 rp_info
->rp_src
= rp_src_flag
;
912 rp_info
->i_am_rp
= 0;
914 listnode_add_sort(pim
->rp_list
, rp_info
);
916 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
917 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
919 struct rp_info
*trp_info
;
921 grp
.family
= AF_INET
;
922 grp
.prefixlen
= IPV4_MAX_BITLEN
;
923 grp
.u
.prefix4
= up
->sg
.grp
;
924 trp_info
= pim_rp_find_match_group(pim
, &grp
);
926 if (trp_info
== rp_info
) {
927 pim_upstream_update(pim
, up
);
928 upstream_updated
= true;
933 if (upstream_updated
)
934 pim_zebra_update_all_interfaces(pim
);
936 /* Register new RP addr with Zebra NHT */
937 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
938 if (PIM_DEBUG_PIM_NHT_RP
)
939 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
940 __func__
, &nht_p
, &rp_info
->group
);
942 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, NULL
);
943 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
944 &rp_info
->group
, 1)) {
945 route_unlock_node(rn
);
946 return PIM_RP_NO_PATH
;
949 pim_rp_check_interfaces(pim
, rp_info
);
951 route_unlock_node(rn
);
953 pim_rp_refresh_group_to_rp_mapping(pim
);
958 void pim_rp_setup(struct pim_instance
*pim
)
960 struct listnode
*node
;
961 struct rp_info
*rp_info
;
964 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
965 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
968 nht_p
.family
= AF_INET
;
969 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
970 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
972 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, NULL
);
973 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
974 &nht_p
, &rp_info
->group
, 1))
975 if (PIM_DEBUG_PIM_NHT_RP
)
977 "Unable to lookup nexthop for rp specified");
982 * Checks to see if we should elect ourself the actual RP when new if
983 * addresses are added against an interface.
985 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
987 struct listnode
*node
;
988 struct rp_info
*rp_info
;
989 bool i_am_rp_changed
= false;
990 struct pim_instance
*pim
= pim_ifp
->pim
;
992 if (pim
->rp_list
== NULL
)
995 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
996 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
999 /* if i_am_rp is already set nothing to be done (adding new
1001 * is not going to make a difference). */
1002 if (rp_info
->i_am_rp
) {
1006 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
1007 i_am_rp_changed
= true;
1008 rp_info
->i_am_rp
= 1;
1009 if (PIM_DEBUG_PIM_NHT_RP
) {
1010 char rp
[PREFIX_STRLEN
];
1011 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1013 zlog_debug("%s: %s: i am rp", __func__
, rp
);
1018 if (i_am_rp_changed
) {
1019 pim_msdp_i_am_rp_changed(pim
);
1020 pim_upstream_reeval_use_rpt(pim
);
1024 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
1025 * are removed. Removing numbers is an uncommon event in an active network
1026 * so I have made no attempt to optimize it. */
1027 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
1029 struct listnode
*node
;
1030 struct rp_info
*rp_info
;
1031 bool i_am_rp_changed
= false;
1034 if (pim
->rp_list
== NULL
)
1037 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1038 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1041 old_i_am_rp
= rp_info
->i_am_rp
;
1042 pim_rp_check_interfaces(pim
, rp_info
);
1044 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
1045 i_am_rp_changed
= true;
1046 if (PIM_DEBUG_PIM_NHT_RP
) {
1047 char rp
[PREFIX_STRLEN
];
1048 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1050 if (rp_info
->i_am_rp
) {
1051 zlog_debug("%s: %s: i am rp", __func__
,
1054 zlog_debug("%s: %s: i am no longer rp",
1061 if (i_am_rp_changed
) {
1062 pim_msdp_i_am_rp_changed(pim
);
1063 pim_upstream_reeval_use_rpt(pim
);
1068 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1069 * this router is the RP for the group.
1071 * Since we only have static RP, all groups are part of this RP
1073 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
1076 struct rp_info
*rp_info
;
1078 memset(&g
, 0, sizeof(g
));
1080 g
.prefixlen
= IPV4_MAX_BITLEN
;
1081 g
.u
.prefix4
= group
;
1083 rp_info
= pim_rp_find_match_group(pim
, &g
);
1086 return rp_info
->i_am_rp
;
1094 * Return the RP that the Group belongs too.
1096 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
1099 struct rp_info
*rp_info
;
1101 memset(&g
, 0, sizeof(g
));
1103 g
.prefixlen
= IPV4_MAX_BITLEN
;
1104 g
.u
.prefix4
= group
;
1106 rp_info
= pim_rp_find_match_group(pim
, &g
);
1109 struct prefix nht_p
;
1111 /* Register addr with Zebra NHT */
1112 nht_p
.family
= AF_INET
;
1113 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1114 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1115 if (PIM_DEBUG_PIM_NHT_RP
)
1117 "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
1118 __func__
, &nht_p
, &rp_info
->group
);
1119 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, NULL
);
1120 pim_rpf_set_refresh_time(pim
);
1121 (void)pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
1122 &nht_p
, &rp_info
->group
, 1);
1123 return (&rp_info
->rp
);
1131 * Set the upstream IP address we want to talk to based upon
1132 * the rp configured and the source address
1134 * If we have don't have a RP configured and the source address is *
1135 * then set the upstream addr as INADDR_ANY and return failure.
1138 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
1139 struct in_addr source
, struct in_addr group
)
1141 struct rp_info
*rp_info
;
1144 memset(&g
, 0, sizeof(g
));
1146 g
.prefixlen
= IPV4_MAX_BITLEN
;
1147 g
.u
.prefix4
= group
;
1149 rp_info
= pim_rp_find_match_group(pim
, &g
);
1151 if (!rp_info
|| ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1152 && (source
.s_addr
== INADDR_ANY
))) {
1153 if (PIM_DEBUG_PIM_NHT_RP
)
1154 zlog_debug("%s: Received a (*,G) with no RP configured",
1156 up
->s_addr
= INADDR_ANY
;
1160 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
1166 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
1169 struct listnode
*node
;
1170 struct rp_info
*rp_info
;
1174 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1175 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1178 if (rp_info
->rp_src
== RP_SRC_BSR
)
1182 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
1184 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1188 vty_out(vty
, "%sip pim rp %s %pFX\n", spaces
,
1190 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1199 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1201 struct rp_info
*rp_info
;
1202 struct rp_info
*prev_rp_info
= NULL
;
1203 struct listnode
*node
;
1205 char buf
[PREFIX_STRLEN
];
1207 json_object
*json
= NULL
;
1208 json_object
*json_rp_rows
= NULL
;
1209 json_object
*json_row
= NULL
;
1212 json
= json_object_new_object();
1215 "RP address group/prefix-list OIF I am RP Source\n");
1216 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1217 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
1220 if (rp_info
->rp_src
== RP_SRC_STATIC
)
1221 strlcpy(source
, "Static", sizeof(source
));
1222 else if (rp_info
->rp_src
== RP_SRC_BSR
)
1223 strlcpy(source
, "BSR", sizeof(source
));
1225 strlcpy(source
, "None", sizeof(source
));
1228 * If we have moved on to a new RP then add the
1229 * entry for the previous RP
1232 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1234 != rp_info
->rp
.rpf_addr
.u
.prefix4
1236 json_object_object_add(
1244 json_rp_rows
= NULL
;
1248 json_rp_rows
= json_object_new_array();
1250 json_row
= json_object_new_object();
1251 json_object_string_addf(
1252 json_row
, "rpAddress", "%pI4",
1253 &rp_info
->rp
.rpf_addr
.u
.prefix4
);
1254 if (rp_info
->rp
.source_nexthop
.interface
)
1255 json_object_string_add(
1256 json_row
, "outboundInterface",
1257 rp_info
->rp
.source_nexthop
1260 json_object_string_add(
1261 json_row
, "outboundInterface",
1263 if (rp_info
->i_am_rp
)
1264 json_object_boolean_true_add(json_row
,
1267 json_object_boolean_false_add(json_row
,
1271 json_object_string_add(json_row
,
1275 json_object_string_addf(
1276 json_row
, "group", "%pFX",
1278 json_object_string_add(json_row
, "source",
1281 json_object_array_add(json_rp_rows
, json_row
);
1283 vty_out(vty
, "%-15s ",
1285 &rp_info
->rp
.rpf_addr
.u
1290 vty_out(vty
, "%-18s ", rp_info
->plist
);
1292 vty_out(vty
, "%-18pFX ",
1295 if (rp_info
->rp
.source_nexthop
.interface
)
1296 vty_out(vty
, "%-16s ",
1297 rp_info
->rp
.source_nexthop
1300 vty_out(vty
, "%-16s ", "(Unknown)");
1302 if (rp_info
->i_am_rp
)
1303 vty_out(vty
, "yes");
1307 vty_out(vty
, "%14s\n", source
);
1309 prev_rp_info
= rp_info
;
1314 if (prev_rp_info
&& json_rp_rows
)
1315 json_object_object_add(
1318 &prev_rp_info
->rp
.rpf_addr
.u
.prefix4
,
1322 vty_json(vty
, json
);
1326 void pim_resolve_rp_nh(struct pim_instance
*pim
, struct pim_neighbor
*nbr
)
1328 struct listnode
*node
= NULL
;
1329 struct rp_info
*rp_info
= NULL
;
1330 struct nexthop
*nh_node
= NULL
;
1331 struct prefix nht_p
;
1332 struct pim_nexthop_cache pnc
;
1334 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1335 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1338 nht_p
.family
= AF_INET
;
1339 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1340 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1341 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1342 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1346 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1347 if (nh_node
->gate
.ipv4
.s_addr
!= INADDR_ANY
)
1350 struct interface
*ifp1
= if_lookup_by_index(
1351 nh_node
->ifindex
, pim
->vrf
->vrf_id
);
1353 if (nbr
->interface
!= ifp1
)
1356 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1357 if (PIM_DEBUG_PIM_NHT_RP
) {
1358 char str
[PREFIX_STRLEN
];
1359 char str1
[INET_ADDRSTRLEN
];
1360 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1361 str1
, sizeof(str1
));
1362 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1365 "%s: addr %s new nexthop addr %s interface %s",
1366 __func__
, str
, str1
, ifp1
->name
);