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_neighbor.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_BITLEN
;
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 route_table_finish(pim
->rp_table
);
144 pim
->rp_table
= NULL
;
147 list_delete(&pim
->rp_list
);
151 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
153 static struct rp_info
*pim_rp_find_prefix_list(struct pim_instance
*pim
,
157 struct listnode
*node
;
158 struct rp_info
*rp_info
;
160 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
161 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
162 && rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
171 * Return true if plist is used by any rp_info
173 static int pim_rp_prefix_list_used(struct pim_instance
*pim
, const char *plist
)
175 struct listnode
*node
;
176 struct rp_info
*rp_info
;
178 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
179 if (rp_info
->plist
&& strcmp(rp_info
->plist
, plist
) == 0) {
188 * Given an RP's address, return the RP's rp_info that is an exact match for
191 static struct rp_info
*pim_rp_find_exact(struct pim_instance
*pim
,
193 const struct prefix
*group
)
195 struct listnode
*node
;
196 struct rp_info
*rp_info
;
198 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
199 if (rp
.s_addr
== rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
200 && prefix_same(&rp_info
->group
, group
))
208 * XXX: long-term issue: we don't actually have a good "ip address-list"
209 * implementation. ("access-list XYZ" is the closest but honestly it's
212 * So it's using a prefix-list to match an address here, which causes very
213 * unexpected results for the user since prefix-lists by default only match
214 * when the prefix length is an exact match too. i.e. you'd have to add the
215 * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32"
217 * To avoid this pitfall, this code uses "address_mode = true" for the prefix
218 * list match (this is the only user for that.)
220 * In the long run, we need to add a "ip address-list", but that's a wholly
221 * separate bag of worms, and existing configs using ip prefix-list would
222 * drop into the UX pitfall.
225 #include "lib/plist_int.h"
228 * Given a group, return the rp_info for that group
230 struct rp_info
*pim_rp_find_match_group(struct pim_instance
*pim
,
231 const struct prefix
*group
)
233 struct listnode
*node
;
234 struct rp_info
*best
= NULL
;
235 struct rp_info
*rp_info
;
236 struct prefix_list
*plist
;
237 const struct prefix
*bp
;
238 const struct prefix_list_entry
*entry
;
239 struct route_node
*rn
;
242 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
243 if (rp_info
->plist
) {
244 plist
= prefix_list_lookup(AFI_IP
, rp_info
->plist
);
246 if (prefix_list_apply_ext(plist
, &entry
, group
, true)
247 == PREFIX_DENY
|| !entry
)
256 if (bp
&& bp
->prefixlen
< entry
->prefix
.prefixlen
) {
263 rn
= route_node_match(pim
->rp_table
, group
);
267 "%s: BUG We should have found default group information",
273 if (PIM_DEBUG_PIM_TRACE
)
274 zlog_debug("Lookedup: %p for rp_info: %p(%pFX) Lock: %d", rn
,
275 rp_info
, &rp_info
->group
,
276 route_node_get_lock_count(rn
));
278 route_unlock_node(rn
);
283 if (rp_info
->group
.prefixlen
< best
->group
.prefixlen
)
290 * When the user makes "ip pim rp" configuration changes or if they change the
291 * prefix-list(s) used by these statements we must tickle the upstream state
292 * for each group to make them re-lookup who their RP should be.
294 * This is a placeholder function for now.
296 void pim_rp_refresh_group_to_rp_mapping(struct pim_instance
*pim
)
298 pim_msdp_i_am_rp_changed(pim
);
299 pim_upstream_reeval_use_rpt(pim
);
302 void pim_rp_prefix_list_update(struct pim_instance
*pim
,
303 struct prefix_list
*plist
)
305 struct listnode
*node
;
306 struct rp_info
*rp_info
;
307 int refresh_needed
= 0;
309 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
311 && strcmp(rp_info
->plist
, prefix_list_name(plist
)) == 0) {
318 pim_rp_refresh_group_to_rp_mapping(pim
);
321 static int pim_rp_check_interface_addrs(struct rp_info
*rp_info
,
322 struct pim_interface
*pim_ifp
)
324 struct listnode
*node
;
325 struct pim_secondary_addr
*sec_addr
;
327 if (pim_ifp
->primary_address
.s_addr
328 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
331 if (!pim_ifp
->sec_addr_list
) {
335 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->sec_addr_list
, node
, sec_addr
)) {
336 if (prefix_same(&sec_addr
->addr
, &rp_info
->rp
.rpf_addr
)) {
344 static void pim_rp_check_interfaces(struct pim_instance
*pim
,
345 struct rp_info
*rp_info
)
347 struct interface
*ifp
;
349 rp_info
->i_am_rp
= 0;
350 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
351 struct pim_interface
*pim_ifp
= ifp
->info
;
356 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
357 rp_info
->i_am_rp
= 1;
362 void pim_upstream_update(struct pim_instance
*pim
, struct pim_upstream
*up
)
364 struct pim_rpf old_rpf
;
365 enum pim_rpf_result rpf_result
;
366 struct in_addr old_upstream_addr
;
367 struct in_addr new_upstream_addr
;
370 old_upstream_addr
= up
->upstream_addr
;
371 pim_rp_set_upstream_addr(pim
, &new_upstream_addr
, up
->sg
.src
,
374 if (PIM_DEBUG_PIM_TRACE
)
375 zlog_debug("%s: pim upstream update for old upstream %pI4",
376 __func__
, &old_upstream_addr
);
378 if (old_upstream_addr
.s_addr
== new_upstream_addr
.s_addr
)
381 /* Lets consider a case, where a PIM upstream has a better RP as a
382 * result of a new RP configuration with more precise group range.
383 * This upstream has to be added to the upstream hash of new RP's
384 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
386 if (old_upstream_addr
.s_addr
!= INADDR_ANY
) {
387 /* Deregister addr with Zebra NHT */
388 nht_p
.family
= AF_INET
;
389 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
390 nht_p
.u
.prefix4
= old_upstream_addr
;
391 if (PIM_DEBUG_PIM_TRACE
)
393 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
394 __func__
, up
->sg_str
, &nht_p
);
395 pim_delete_tracked_nexthop(pim
, &nht_p
, up
, NULL
, false);
398 /* Update the upstream address */
399 up
->upstream_addr
= new_upstream_addr
;
401 old_rpf
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
403 rpf_result
= pim_rpf_update(pim
, up
, &old_rpf
, __func__
);
404 if (rpf_result
== PIM_RPF_FAILURE
)
405 pim_mroute_del(up
->channel_oil
, __func__
);
407 /* update kernel multicast forwarding cache (MFC) */
408 if (up
->rpf
.source_nexthop
.interface
&& up
->channel_oil
)
409 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
411 if (rpf_result
== PIM_RPF_CHANGED
||
412 (rpf_result
== PIM_RPF_FAILURE
&&
413 old_rpf
.source_nexthop
.interface
))
414 pim_zebra_upstream_rpf_changed(pim
, up
, &old_rpf
);
416 pim_zebra_update_all_interfaces(pim
);
419 int pim_rp_new(struct pim_instance
*pim
, struct in_addr rp_addr
,
420 struct prefix group
, const char *plist
,
421 enum rp_source rp_src_flag
)
424 char rp
[INET_ADDRSTRLEN
];
425 struct rp_info
*rp_info
;
426 struct rp_info
*rp_all
;
427 struct prefix group_all
;
428 struct listnode
*node
, *nnode
;
429 struct rp_info
*tmp_rp_info
;
432 struct route_node
*rn
;
433 struct pim_upstream
*up
;
435 if (rp_addr
.s_addr
== INADDR_ANY
||
436 rp_addr
.s_addr
== INADDR_NONE
)
437 return PIM_RP_BAD_ADDRESS
;
439 rp_info
= XCALLOC(MTYPE_PIM_RP
, sizeof(*rp_info
));
441 rp_info
->rp
.rpf_addr
.family
= AF_INET
;
442 rp_info
->rp
.rpf_addr
.prefixlen
= IPV4_MAX_BITLEN
;
443 rp_info
->rp
.rpf_addr
.u
.prefix4
= rp_addr
;
444 prefix_copy(&rp_info
->group
, &group
);
445 rp_info
->rp_src
= rp_src_flag
;
447 inet_ntop(AF_INET
, &rp_info
->rp
.rpf_addr
.u
.prefix4
, rp
, sizeof(rp
));
451 * Return if the prefix-list is already configured for this RP
453 if (pim_rp_find_prefix_list(pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
,
455 XFREE(MTYPE_PIM_RP
, rp_info
);
460 * Barf if the prefix-list is already configured for an RP
462 if (pim_rp_prefix_list_used(pim
, plist
)) {
463 XFREE(MTYPE_PIM_RP
, rp_info
);
464 return PIM_RP_PFXLIST_IN_USE
;
468 * Free any existing rp_info entries for this RP
470 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
472 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
473 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
) {
474 if (tmp_rp_info
->plist
)
475 pim_rp_del_config(pim
, rp
, NULL
,
480 prefix2str(&tmp_rp_info
->group
,
486 rp_info
->plist
= XSTRDUP(MTYPE_PIM_FILTER_NAME
, plist
);
489 if (!str2prefix("224.0.0.0/4", &group_all
)) {
490 XFREE(MTYPE_PIM_RP
, rp_info
);
491 return PIM_GROUP_BAD_ADDRESS
;
493 rp_all
= pim_rp_find_match_group(pim
, &group_all
);
496 * Barf if group is a non-multicast subnet
498 if (!prefix_match(&rp_all
->group
, &rp_info
->group
)) {
499 XFREE(MTYPE_PIM_RP
, rp_info
);
500 return PIM_GROUP_BAD_ADDRESS
;
504 * Remove any prefix-list rp_info entries for this RP
506 for (ALL_LIST_ELEMENTS(pim
->rp_list
, node
, nnode
,
508 if (tmp_rp_info
->plist
509 && rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
510 == tmp_rp_info
->rp
.rpf_addr
.u
.prefix4
512 pim_rp_del_config(pim
, rp
, NULL
,
518 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
520 if (prefix_same(&rp_all
->group
, &rp_info
->group
)
521 && pim_rpf_addr_is_inaddr_none(&rp_all
->rp
)) {
522 rp_all
->rp
.rpf_addr
= rp_info
->rp
.rpf_addr
;
523 rp_all
->rp_src
= rp_src_flag
;
524 XFREE(MTYPE_PIM_RP
, rp_info
);
526 /* Register addr with Zebra NHT */
527 nht_p
.family
= AF_INET
;
528 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
530 rp_all
->rp
.rpf_addr
.u
.prefix4
; // RP address
531 if (PIM_DEBUG_PIM_NHT_RP
)
533 "%s: NHT Register rp_all addr %pFX grp %pFX ",
534 __func__
, &nht_p
, &rp_all
->group
);
536 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
537 /* Find (*, G) upstream whose RP is not
540 if ((up
->upstream_addr
.s_addr
== INADDR_ANY
)
541 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
543 struct rp_info
*trp_info
;
545 grp
.family
= AF_INET
;
546 grp
.prefixlen
= IPV4_MAX_BITLEN
;
547 grp
.u
.prefix4
= up
->sg
.grp
;
548 trp_info
= pim_rp_find_match_group(
550 if (trp_info
== rp_all
)
551 pim_upstream_update(pim
, up
);
555 pim_rp_check_interfaces(pim
, rp_all
);
556 pim_rp_refresh_group_to_rp_mapping(pim
);
557 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_all
,
560 if (!pim_ecmp_nexthop_lookup(pim
,
561 &rp_all
->rp
.source_nexthop
,
562 &nht_p
, &rp_all
->group
, 1))
563 return PIM_RP_NO_PATH
;
568 * Return if the group is already configured for this RP
570 tmp_rp_info
= pim_rp_find_exact(
571 pim
, rp_info
->rp
.rpf_addr
.u
.prefix4
, &rp_info
->group
);
573 if ((tmp_rp_info
->rp_src
!= rp_src_flag
)
574 && (rp_src_flag
== RP_SRC_STATIC
))
575 tmp_rp_info
->rp_src
= rp_src_flag
;
576 XFREE(MTYPE_PIM_RP
, rp_info
);
581 * Barf if this group is already covered by some other RP
583 tmp_rp_info
= pim_rp_find_match_group(pim
, &rp_info
->group
);
586 if (tmp_rp_info
->plist
) {
587 XFREE(MTYPE_PIM_RP
, rp_info
);
588 return PIM_GROUP_PFXLIST_OVERLAP
;
591 * If the only RP that covers this group is an
593 * 224.0.0.0/4 that is fine, ignore that one.
595 * though we must return PIM_GROUP_OVERLAP
597 if (prefix_same(&rp_info
->group
,
598 &tmp_rp_info
->group
)) {
599 if ((rp_src_flag
== RP_SRC_STATIC
)
600 && (tmp_rp_info
->rp_src
602 XFREE(MTYPE_PIM_RP
, rp_info
);
603 return PIM_GROUP_OVERLAP
;
606 result
= pim_rp_change(
608 rp_info
->rp
.rpf_addr
.u
.prefix4
,
611 XFREE(MTYPE_PIM_RP
, rp_info
);
618 listnode_add_sort(pim
->rp_list
, rp_info
);
619 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
622 if (PIM_DEBUG_PIM_TRACE
)
623 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn
,
624 rp_info
, &rp_info
->group
,
625 route_node_get_lock_count(rn
));
627 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
628 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
630 struct rp_info
*trp_info
;
632 grp
.family
= AF_INET
;
633 grp
.prefixlen
= IPV4_MAX_BITLEN
;
634 grp
.u
.prefix4
= up
->sg
.grp
;
635 trp_info
= pim_rp_find_match_group(pim
, &grp
);
637 if (trp_info
== rp_info
)
638 pim_upstream_update(pim
, up
);
642 pim_rp_check_interfaces(pim
, rp_info
);
643 pim_rp_refresh_group_to_rp_mapping(pim
);
645 /* Register addr with Zebra NHT */
646 nht_p
.family
= AF_INET
;
647 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
648 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
649 if (PIM_DEBUG_PIM_NHT_RP
)
650 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
651 __func__
, &nht_p
, &rp_info
->group
);
652 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
653 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
655 return PIM_RP_NO_PATH
;
660 int pim_rp_del_config(struct pim_instance
*pim
, const char *rp
,
661 const char *group_range
, const char *plist
)
664 struct in_addr rp_addr
;
667 if (group_range
== NULL
)
668 result
= str2prefix("224.0.0.0/4", &group
);
670 result
= str2prefix(group_range
, &group
);
673 return PIM_GROUP_BAD_ADDRESS
;
675 result
= inet_pton(AF_INET
, rp
, &rp_addr
);
677 return PIM_RP_BAD_ADDRESS
;
679 result
= pim_rp_del(pim
, rp_addr
, group
, plist
, RP_SRC_STATIC
);
683 int pim_rp_del(struct pim_instance
*pim
, struct in_addr rp_addr
,
684 struct prefix group
, const char *plist
,
685 enum rp_source rp_src_flag
)
688 struct rp_info
*rp_info
;
689 struct rp_info
*rp_all
;
691 struct route_node
*rn
;
692 bool was_plist
= false;
693 struct rp_info
*trp_info
;
694 struct pim_upstream
*up
;
695 struct bsgrp_node
*bsgrp
= NULL
;
696 struct bsm_rpinfo
*bsrp
= NULL
;
697 char rp_str
[INET_ADDRSTRLEN
];
699 if (!inet_ntop(AF_INET
, &rp_addr
, rp_str
, sizeof(rp_str
)))
700 snprintf(rp_str
, sizeof(rp_str
), "<rp?>");
703 rp_info
= pim_rp_find_prefix_list(pim
, rp_addr
, plist
);
705 rp_info
= pim_rp_find_exact(pim
, rp_addr
, &group
);
708 return PIM_RP_NOT_FOUND
;
710 if (rp_info
->plist
) {
711 XFREE(MTYPE_PIM_FILTER_NAME
, rp_info
->plist
);
715 if (PIM_DEBUG_PIM_TRACE
)
716 zlog_debug("%s: Delete RP %s for the group %pFX", __func__
,
719 /* While static RP is getting deleted, we need to check if dynamic RP
720 * present for the same group in BSM RP table, then install the dynamic
721 * RP for the group node into the main rp table
723 if (rp_src_flag
== RP_SRC_STATIC
) {
724 bsgrp
= pim_bsm_get_bsgrp_node(&pim
->global_scope
, &group
);
727 bsrp
= bsm_rpinfos_first(bsgrp
->bsrp_list
);
729 if (PIM_DEBUG_PIM_TRACE
) {
730 char bsrp_str
[INET_ADDRSTRLEN
];
732 if (!inet_ntop(AF_INET
, bsrp
, bsrp_str
,
739 "%s: BSM RP %s found for the group %pFX",
740 __func__
, bsrp_str
, &group
);
742 return pim_rp_change(pim
, bsrp
->rp_address
,
746 if (PIM_DEBUG_PIM_TRACE
)
748 "%s: BSM RP not found for the group %pFX",
753 /* Deregister addr with Zebra NHT */
754 nht_p
.family
= AF_INET
;
755 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
756 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
757 if (PIM_DEBUG_PIM_NHT_RP
)
758 zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__
,
760 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
762 if (!str2prefix("224.0.0.0/4", &g_all
))
763 return PIM_RP_BAD_ADDRESS
;
765 rp_all
= pim_rp_find_match_group(pim
, &g_all
);
767 if (rp_all
== rp_info
) {
768 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
769 /* Find the upstream (*, G) whose upstream address is
770 * same as the deleted RP
772 if ((up
->upstream_addr
.s_addr
773 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
774 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
776 grp
.family
= AF_INET
;
777 grp
.prefixlen
= IPV4_MAX_BITLEN
;
778 grp
.u
.prefix4
= up
->sg
.grp
;
779 trp_info
= pim_rp_find_match_group(pim
, &grp
);
780 if (trp_info
== rp_all
) {
781 pim_upstream_rpf_clear(pim
, up
);
782 up
->upstream_addr
.s_addr
= INADDR_ANY
;
786 rp_all
->rp
.rpf_addr
.family
= AF_INET
;
787 rp_all
->rp
.rpf_addr
.u
.prefix4
.s_addr
= INADDR_NONE
;
792 listnode_delete(pim
->rp_list
, rp_info
);
795 rn
= route_node_get(pim
->rp_table
, &rp_info
->group
);
797 if (rn
->info
!= rp_info
)
800 "Expected rn->info to be equal to rp_info");
802 if (PIM_DEBUG_PIM_TRACE
)
804 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
805 __func__
, rn
, rp_info
, &rp_info
->group
,
806 route_node_get_lock_count(rn
));
809 route_unlock_node(rn
);
810 route_unlock_node(rn
);
814 pim_rp_refresh_group_to_rp_mapping(pim
);
816 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
817 /* Find the upstream (*, G) whose upstream address is same as
820 if ((up
->upstream_addr
.s_addr
821 == rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
)
822 && (up
->sg
.src
.s_addr
== INADDR_ANY
)) {
825 grp
.family
= AF_INET
;
826 grp
.prefixlen
= IPV4_MAX_BITLEN
;
827 grp
.u
.prefix4
= up
->sg
.grp
;
829 trp_info
= pim_rp_find_match_group(pim
, &grp
);
831 /* RP not found for the group grp */
832 if (pim_rpf_addr_is_inaddr_none(&trp_info
->rp
)) {
833 pim_upstream_rpf_clear(pim
, up
);
834 pim_rp_set_upstream_addr(
835 pim
, &up
->upstream_addr
, up
->sg
.src
,
839 /* RP found for the group grp */
841 pim_upstream_update(pim
, up
);
845 XFREE(MTYPE_PIM_RP
, rp_info
);
849 int pim_rp_change(struct pim_instance
*pim
, struct in_addr new_rp_addr
,
850 struct prefix group
, enum rp_source rp_src_flag
)
853 struct route_node
*rn
;
855 struct rp_info
*rp_info
= NULL
;
856 struct pim_upstream
*up
;
858 rn
= route_node_lookup(pim
->rp_table
, &group
);
860 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
867 route_unlock_node(rn
);
868 result
= pim_rp_new(pim
, new_rp_addr
, group
, NULL
, rp_src_flag
);
872 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== new_rp_addr
.s_addr
) {
873 if (rp_info
->rp_src
!= rp_src_flag
) {
874 rp_info
->rp_src
= rp_src_flag
;
875 route_unlock_node(rn
);
880 nht_p
.family
= AF_INET
;
881 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
883 /* Deregister old RP addr with Zebra NHT */
884 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
!= INADDR_ANY
) {
885 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
886 if (PIM_DEBUG_PIM_NHT_RP
)
887 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
889 pim_delete_tracked_nexthop(pim
, &nht_p
, NULL
, rp_info
, false);
892 pim_rp_nexthop_del(rp_info
);
893 listnode_delete(pim
->rp_list
, rp_info
);
894 /* Update the new RP address*/
895 rp_info
->rp
.rpf_addr
.u
.prefix4
= new_rp_addr
;
896 rp_info
->rp_src
= rp_src_flag
;
897 rp_info
->i_am_rp
= 0;
899 listnode_add_sort(pim
->rp_list
, rp_info
);
901 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
902 if (up
->sg
.src
.s_addr
== INADDR_ANY
) {
904 struct rp_info
*trp_info
;
906 grp
.family
= AF_INET
;
907 grp
.prefixlen
= IPV4_MAX_BITLEN
;
908 grp
.u
.prefix4
= up
->sg
.grp
;
909 trp_info
= pim_rp_find_match_group(pim
, &grp
);
911 if (trp_info
== rp_info
)
912 pim_upstream_update(pim
, up
);
916 /* Register new RP addr with Zebra NHT */
917 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
918 if (PIM_DEBUG_PIM_NHT_RP
)
919 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
920 __func__
, &nht_p
, &rp_info
->group
);
922 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false, NULL
);
923 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
, &nht_p
,
924 &rp_info
->group
, 1)) {
925 route_unlock_node(rn
);
926 return PIM_RP_NO_PATH
;
929 pim_rp_check_interfaces(pim
, rp_info
);
931 route_unlock_node(rn
);
933 pim_rp_refresh_group_to_rp_mapping(pim
);
938 void pim_rp_setup(struct pim_instance
*pim
)
940 struct listnode
*node
;
941 struct rp_info
*rp_info
;
944 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
945 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
948 nht_p
.family
= AF_INET
;
949 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
950 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
952 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
954 if (!pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
955 &nht_p
, &rp_info
->group
, 1))
956 if (PIM_DEBUG_PIM_NHT_RP
)
958 "Unable to lookup nexthop for rp specified");
963 * Checks to see if we should elect ourself the actual RP when new if
964 * addresses are added against an interface.
966 void pim_rp_check_on_if_add(struct pim_interface
*pim_ifp
)
968 struct listnode
*node
;
969 struct rp_info
*rp_info
;
970 bool i_am_rp_changed
= false;
971 struct pim_instance
*pim
= pim_ifp
->pim
;
973 if (pim
->rp_list
== NULL
)
976 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
977 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
980 /* if i_am_rp is already set nothing to be done (adding new
982 * is not going to make a difference). */
983 if (rp_info
->i_am_rp
) {
987 if (pim_rp_check_interface_addrs(rp_info
, pim_ifp
)) {
988 i_am_rp_changed
= true;
989 rp_info
->i_am_rp
= 1;
990 if (PIM_DEBUG_PIM_NHT_RP
) {
991 char rp
[PREFIX_STRLEN
];
992 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
994 zlog_debug("%s: %s: i am rp", __func__
, rp
);
999 if (i_am_rp_changed
) {
1000 pim_msdp_i_am_rp_changed(pim
);
1001 pim_upstream_reeval_use_rpt(pim
);
1005 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
1006 * are removed. Removing numbers is an uncommon event in an active network
1007 * so I have made no attempt to optimize it. */
1008 void pim_i_am_rp_re_evaluate(struct pim_instance
*pim
)
1010 struct listnode
*node
;
1011 struct rp_info
*rp_info
;
1012 bool i_am_rp_changed
= false;
1015 if (pim
->rp_list
== NULL
)
1018 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1019 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1022 old_i_am_rp
= rp_info
->i_am_rp
;
1023 pim_rp_check_interfaces(pim
, rp_info
);
1025 if (old_i_am_rp
!= rp_info
->i_am_rp
) {
1026 i_am_rp_changed
= true;
1027 if (PIM_DEBUG_PIM_NHT_RP
) {
1028 char rp
[PREFIX_STRLEN
];
1029 pim_addr_dump("<rp?>", &rp_info
->rp
.rpf_addr
,
1031 if (rp_info
->i_am_rp
) {
1032 zlog_debug("%s: %s: i am rp", __func__
,
1035 zlog_debug("%s: %s: i am no longer rp",
1042 if (i_am_rp_changed
) {
1043 pim_msdp_i_am_rp_changed(pim
);
1044 pim_upstream_reeval_use_rpt(pim
);
1049 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1050 * this router is the RP for the group.
1052 * Since we only have static RP, all groups are part of this RP
1054 int pim_rp_i_am_rp(struct pim_instance
*pim
, struct in_addr group
)
1057 struct rp_info
*rp_info
;
1059 memset(&g
, 0, sizeof(g
));
1061 g
.prefixlen
= IPV4_MAX_BITLEN
;
1062 g
.u
.prefix4
= group
;
1064 rp_info
= pim_rp_find_match_group(pim
, &g
);
1067 return rp_info
->i_am_rp
;
1075 * Return the RP that the Group belongs too.
1077 struct pim_rpf
*pim_rp_g(struct pim_instance
*pim
, struct in_addr group
)
1080 struct rp_info
*rp_info
;
1082 memset(&g
, 0, sizeof(g
));
1084 g
.prefixlen
= IPV4_MAX_BITLEN
;
1085 g
.u
.prefix4
= group
;
1087 rp_info
= pim_rp_find_match_group(pim
, &g
);
1090 struct prefix nht_p
;
1092 /* Register addr with Zebra NHT */
1093 nht_p
.family
= AF_INET
;
1094 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1095 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1096 if (PIM_DEBUG_PIM_NHT_RP
)
1098 "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
1099 __func__
, &nht_p
, &rp_info
->group
);
1100 pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
, false,
1102 pim_rpf_set_refresh_time(pim
);
1103 (void)pim_ecmp_nexthop_lookup(pim
, &rp_info
->rp
.source_nexthop
,
1104 &nht_p
, &rp_info
->group
, 1);
1105 return (&rp_info
->rp
);
1113 * Set the upstream IP address we want to talk to based upon
1114 * the rp configured and the source address
1116 * If we have don't have a RP configured and the source address is *
1117 * then set the upstream addr as INADDR_ANY and return failure.
1120 int pim_rp_set_upstream_addr(struct pim_instance
*pim
, struct in_addr
*up
,
1121 struct in_addr source
, struct in_addr group
)
1123 struct rp_info
*rp_info
;
1126 memset(&g
, 0, sizeof(g
));
1128 g
.prefixlen
= IPV4_MAX_BITLEN
;
1129 g
.u
.prefix4
= group
;
1131 rp_info
= pim_rp_find_match_group(pim
, &g
);
1133 if (!rp_info
|| ((pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1134 && (source
.s_addr
== INADDR_ANY
))) {
1135 if (PIM_DEBUG_PIM_NHT_RP
)
1136 zlog_debug("%s: Received a (*,G) with no RP configured",
1138 up
->s_addr
= INADDR_ANY
;
1142 *up
= (source
.s_addr
== INADDR_ANY
) ? rp_info
->rp
.rpf_addr
.u
.prefix4
1148 int pim_rp_config_write(struct pim_instance
*pim
, struct vty
*vty
,
1151 struct listnode
*node
;
1152 struct rp_info
*rp_info
;
1156 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1157 if (pim_rpf_addr_is_inaddr_none(&rp_info
->rp
))
1160 if (rp_info
->rp_src
== RP_SRC_BSR
)
1164 vty_out(vty
, "%sip pim rp %s prefix-list %s\n", spaces
,
1166 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1170 vty_out(vty
, "%sip pim rp %s %pFX\n", spaces
,
1172 &rp_info
->rp
.rpf_addr
.u
.prefix4
,
1181 bool pim_rp_check_is_my_ip_address(struct pim_instance
*pim
,
1182 struct in_addr dest_addr
)
1184 if (if_lookup_exact_address(&dest_addr
, AF_INET
, pim
->vrf
->vrf_id
))
1190 void pim_rp_show_information(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1192 struct rp_info
*rp_info
;
1193 struct rp_info
*prev_rp_info
= NULL
;
1194 struct listnode
*node
;
1196 char buf
[PREFIX_STRLEN
];
1198 json_object
*json
= NULL
;
1199 json_object
*json_rp_rows
= NULL
;
1200 json_object
*json_row
= NULL
;
1203 json
= json_object_new_object();
1206 "RP address group/prefix-list OIF I am RP Source\n");
1207 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1208 if (!pim_rpf_addr_is_inaddr_none(&rp_info
->rp
)) {
1211 if (rp_info
->rp_src
== RP_SRC_STATIC
)
1212 strlcpy(source
, "Static", sizeof(source
));
1213 else if (rp_info
->rp_src
== RP_SRC_BSR
)
1214 strlcpy(source
, "BSR", sizeof(source
));
1216 strlcpy(source
, "None", sizeof(source
));
1219 * If we have moved on to a new RP then add the
1220 * entry for the previous RP
1223 && prev_rp_info
->rp
.rpf_addr
.u
.prefix4
1225 != rp_info
->rp
.rpf_addr
.u
.prefix4
1227 json_object_object_add(
1235 json_rp_rows
= NULL
;
1239 json_rp_rows
= json_object_new_array();
1241 json_row
= json_object_new_object();
1242 json_object_string_add(
1243 json_row
, "rpAddress",
1245 &rp_info
->rp
.rpf_addr
.u
1248 if (rp_info
->rp
.source_nexthop
.interface
)
1249 json_object_string_add(
1250 json_row
, "outboundInterface",
1251 rp_info
->rp
.source_nexthop
1254 json_object_string_add(
1255 json_row
, "outboundInterface",
1257 if (rp_info
->i_am_rp
)
1258 json_object_boolean_true_add(json_row
,
1261 json_object_boolean_false_add(json_row
,
1265 json_object_string_add(json_row
,
1269 json_object_string_add(
1271 prefix2str(&rp_info
->group
, buf
,
1273 json_object_string_add(json_row
, "source",
1276 json_object_array_add(json_rp_rows
, json_row
);
1278 vty_out(vty
, "%-15s ",
1280 &rp_info
->rp
.rpf_addr
.u
1285 vty_out(vty
, "%-18s ", rp_info
->plist
);
1287 vty_out(vty
, "%-18pFX ",
1290 if (rp_info
->rp
.source_nexthop
.interface
)
1291 vty_out(vty
, "%-16s ",
1292 rp_info
->rp
.source_nexthop
1295 vty_out(vty
, "%-16s ", "(Unknown)");
1297 if (rp_info
->i_am_rp
)
1298 vty_out(vty
, "yes");
1302 vty_out(vty
, "%14s\n", source
);
1304 prev_rp_info
= rp_info
;
1309 if (prev_rp_info
&& json_rp_rows
)
1310 json_object_object_add(
1313 &prev_rp_info
->rp
.rpf_addr
.u
.prefix4
,
1317 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1318 json
, JSON_C_TO_STRING_PRETTY
));
1319 json_object_free(json
);
1323 void pim_resolve_rp_nh(struct pim_instance
*pim
, struct pim_neighbor
*nbr
)
1325 struct listnode
*node
= NULL
;
1326 struct rp_info
*rp_info
= NULL
;
1327 struct nexthop
*nh_node
= NULL
;
1328 struct prefix nht_p
;
1329 struct pim_nexthop_cache pnc
;
1331 for (ALL_LIST_ELEMENTS_RO(pim
->rp_list
, node
, rp_info
)) {
1332 if (rp_info
->rp
.rpf_addr
.u
.prefix4
.s_addr
== INADDR_NONE
)
1335 nht_p
.family
= AF_INET
;
1336 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1337 nht_p
.u
.prefix4
= rp_info
->rp
.rpf_addr
.u
.prefix4
;
1338 memset(&pnc
, 0, sizeof(struct pim_nexthop_cache
));
1339 if (!pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, rp_info
,
1343 for (nh_node
= pnc
.nexthop
; nh_node
; nh_node
= nh_node
->next
) {
1344 if (nh_node
->gate
.ipv4
.s_addr
!= INADDR_ANY
)
1347 struct interface
*ifp1
= if_lookup_by_index(
1348 nh_node
->ifindex
, pim
->vrf
->vrf_id
);
1350 if (nbr
->interface
!= ifp1
)
1353 nh_node
->gate
.ipv4
= nbr
->source_addr
;
1354 if (PIM_DEBUG_PIM_NHT_RP
) {
1355 char str
[PREFIX_STRLEN
];
1356 char str1
[INET_ADDRSTRLEN
];
1357 pim_inet4_dump("<nht_nbr?>", nbr
->source_addr
,
1358 str1
, sizeof(str1
));
1359 pim_addr_dump("<nht_addr?>", &nht_p
, str
,
1362 "%s: addr %s new nexthop addr %s interface %s",
1363 __func__
, str
, str1
, ifp1
->name
);