]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_rp.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pimd / pim_rp.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
8f5f5e91
DS
2/*
3 * PIM for Quagga
4 * Copyright (C) 2015 Cumulus Networks, Inc.
5 * Donald Sharp
8f5f5e91
DS
6 */
7#include <zebra.h>
8
9bf3c633 9#include "lib/json.h"
54b97c74 10#include "log.h"
8f5f5e91 11#include "network.h"
744d91b3 12#include "if.h"
36d6bd7d
DS
13#include "linklist.h"
14#include "prefix.h"
15#include "memory.h"
00d07c6f
DS
16#include "vty.h"
17#include "vrf.h"
dfe43e25 18#include "plist.h"
cba44481 19#include "nexthop.h"
89b68082 20#include "table.h"
3613d898 21#include "lib_errors.h"
8f5f5e91
DS
22
23#include "pimd.h"
993e3d8e 24#include "pim_instance.h"
75a26779 25#include "pim_vty.h"
54b97c74 26#include "pim_str.h"
7176984f 27#include "pim_iface.h"
8f5f5e91 28#include "pim_rp.h"
ed66602c 29#include "pim_rpf.h"
13afbd05 30#include "pim_sock.h"
36d6bd7d 31#include "pim_memory.h"
e34e07e6 32#include "pim_neighbor.h"
7667c556 33#include "pim_msdp.h"
1bc98276 34#include "pim_nht.h"
28309df0
SP
35#include "pim_mroute.h"
36#include "pim_oil.h"
37#include "pim_zebra.h"
d0e418b4 38#include "pim_bsm.h"
c6ced474 39#include "pim_util.h"
8c0a7680 40#include "pim_ssm.h"
f1ebd3db 41#include "termtable.h"
36d6bd7d 42
c2cf4b02
DS
43/* Cleanup pim->rpf_hash each node data */
44void pim_rp_list_hash_clean(void *data)
45{
7c591950 46 struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data;
c2cf4b02 47
6a154c88 48 list_delete(&pnc->rp_list);
6e1ef388 49
d8bc11a5 50 hash_clean_and_free(&pnc->upstream_hash, NULL);
1159c202
SP
51 if (pnc->nexthop)
52 nexthops_free(pnc->nexthop);
6e1ef388
DS
53
54 XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
c2cf4b02
DS
55}
56
d62a17ae 57static void pim_rp_info_free(struct rp_info *rp_info)
36d6bd7d 58{
0a22ddfb 59 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
ff823fc9 60
d62a17ae 61 XFREE(MTYPE_PIM_RP, rp_info);
36d6bd7d
DS
62}
63
d62a17ae 64int pim_rp_list_cmp(void *v1, void *v2)
36d6bd7d 65{
d62a17ae 66 struct rp_info *rp1 = (struct rp_info *)v1;
67 struct rp_info *rp2 = (struct rp_info *)v2;
5d1d18a1 68 int ret;
d62a17ae 69
70 /*
71 * Sort by RP IP address
72 */
b63192cf 73 ret = pim_addr_cmp(rp1->rp.rpf_addr, rp2->rp.rpf_addr);
5d1d18a1
DL
74 if (ret)
75 return ret;
d62a17ae 76
77 /*
78 * Sort by group IP address
79 */
5d1d18a1
DL
80 ret = prefix_cmp(&rp1->group, &rp2->group);
81 if (ret)
82 return ret;
d62a17ae 83
84 return 0;
36d6bd7d
DS
85}
86
d9c9a9ee 87void pim_rp_init(struct pim_instance *pim)
36d6bd7d 88{
d62a17ae 89 struct rp_info *rp_info;
89b68082 90 struct route_node *rn;
36d6bd7d 91
d9c9a9ee
DS
92 pim->rp_list = list_new();
93 pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
94 pim->rp_list->cmp = pim_rp_list_cmp;
36d6bd7d 95
89b68082 96 pim->rp_table = route_table_init();
89b68082 97
d62a17ae 98 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
36d6bd7d 99
c6ced474 100 if (!pim_get_all_mcast_group(&rp_info->group)) {
450971aa 101 flog_err(EC_LIB_DEVELOPMENT,
5d1d18a1 102 "Unable to convert all-multicast prefix");
6a154c88 103 list_delete(&pim->rp_list);
89b68082 104 route_table_finish(pim->rp_table);
2e8345c1
DS
105 XFREE(MTYPE_PIM_RP, rp_info);
106 return;
107 }
b63192cf 108 rp_info->rp.rpf_addr = PIMADDR_ANY;
36d6bd7d 109
d9c9a9ee 110 listnode_add(pim->rp_list, rp_info);
89b68082
DS
111
112 rn = route_node_get(pim->rp_table, &rp_info->group);
89b68082 113 rn->info = rp_info;
23fc858a 114 if (PIM_DEBUG_PIM_TRACE)
5d1d18a1
DL
115 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
116 rp_info, &rp_info->group,
117 route_node_get_lock_count(rn));
36d6bd7d
DS
118}
119
d9c9a9ee 120void pim_rp_free(struct pim_instance *pim)
36d6bd7d 121{
e4e52805
DS
122 if (pim->rp_table)
123 route_table_finish(pim->rp_table);
124 pim->rp_table = NULL;
906640db 125
126 if (pim->rp_list)
127 list_delete(&pim->rp_list);
36d6bd7d
DS
128}
129
dfe43e25
DW
130/*
131 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
132 */
d9c9a9ee 133static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim,
1db07606 134 pim_addr rp, const char *plist)
36d6bd7d 135{
d62a17ae 136 struct listnode *node;
137 struct rp_info *rp_info;
138
d9c9a9ee 139 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
b63192cf 140 if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
1db07606 141 rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
d62a17ae 142 return rp_info;
143 }
144 }
145
146 return NULL;
36d6bd7d
DS
147}
148
dfe43e25
DW
149/*
150 * Return true if plist is used by any rp_info
151 */
d9c9a9ee 152static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist)
dfe43e25 153{
d62a17ae 154 struct listnode *node;
155 struct rp_info *rp_info;
156
d9c9a9ee 157 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 158 if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
159 return 1;
160 }
161 }
162
163 return 0;
dfe43e25
DW
164}
165
166/*
d62a17ae 167 * Given an RP's address, return the RP's rp_info that is an exact match for
168 * 'group'
dfe43e25 169 */
fd5540ea 170static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, pim_addr rp,
123214ef 171 const struct prefix *group)
36d6bd7d 172{
d62a17ae 173 struct listnode *node;
174 struct rp_info *rp_info;
36d6bd7d 175
d9c9a9ee 176 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
b63192cf 177 if ((!pim_addr_cmp(rp, rp_info->rp.rpf_addr)) &&
fd5540ea 178 prefix_same(&rp_info->group, group))
d62a17ae 179 return rp_info;
180 }
54b97c74 181
d62a17ae 182 return NULL;
36d6bd7d
DS
183}
184
2b6b16fc
DL
185/*
186 * XXX: long-term issue: we don't actually have a good "ip address-list"
187 * implementation. ("access-list XYZ" is the closest but honestly it's
188 * kinda garbage.)
189 *
190 * So it's using a prefix-list to match an address here, which causes very
191 * unexpected results for the user since prefix-lists by default only match
192 * when the prefix length is an exact match too. i.e. you'd have to add the
193 * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32"
194 *
195 * To avoid this pitfall, this code uses "address_mode = true" for the prefix
196 * list match (this is the only user for that.)
197 *
198 * In the long run, we need to add a "ip address-list", but that's a wholly
199 * separate bag of worms, and existing configs using ip prefix-list would
200 * drop into the UX pitfall.
201 */
202
203#include "lib/plist_int.h"
204
dfe43e25
DW
205/*
206 * Given a group, return the rp_info for that group
207 */
28309df0 208struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
123214ef 209 const struct prefix *group)
36d6bd7d 210{
d62a17ae 211 struct listnode *node;
b77b1550 212 struct rp_info *best = NULL;
d62a17ae 213 struct rp_info *rp_info;
214 struct prefix_list *plist;
2b6b16fc
DL
215 const struct prefix *bp;
216 const struct prefix_list_entry *entry;
89b68082 217 struct route_node *rn;
d62a17ae 218
4646b86a 219 bp = NULL;
d9c9a9ee 220 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 221 if (rp_info->plist) {
fd5540ea 222 plist = prefix_list_lookup(PIM_AFI, rp_info->plist);
d62a17ae 223
2b6b16fc
DL
224 if (prefix_list_apply_ext(plist, &entry, group, true)
225 == PREFIX_DENY || !entry)
b77b1550
DS
226 continue;
227
228 if (!best) {
229 best = rp_info;
2b6b16fc 230 bp = &entry->prefix;
b77b1550
DS
231 continue;
232 }
233
2b6b16fc 234 if (bp && bp->prefixlen < entry->prefix.prefixlen) {
b77b1550 235 best = rp_info;
2b6b16fc 236 bp = &entry->prefix;
b77b1550 237 }
d62a17ae 238 }
239 }
240
89b68082
DS
241 rn = route_node_match(pim->rp_table, group);
242 if (!rn) {
af4c2728 243 flog_err(
450971aa 244 EC_LIB_DEVELOPMENT,
1d5453d6 245 "%s: BUG We should have found default group information",
5e81f5dd 246 __func__);
89b68082
DS
247 return best;
248 }
249
250 rp_info = rn->info;
cf568522
DS
251 if (PIM_DEBUG_PIM_TRACE) {
252 if (best)
253 zlog_debug(
254 "Lookedup(%pFX): prefix_list match %s, rn %p found: %pFX",
255 group, best->plist, rn, &rp_info->group);
256 else
257 zlog_debug("Lookedup(%pFX): rn %p found:%pFX", group,
258 rn, &rp_info->group);
259 }
89b68082 260
260c92c8 261 route_unlock_node(rn);
262
94dc0c4e
DS
263 /*
264 * rp's with prefix lists have the group as 224.0.0.0/4 which will
265 * match anything. So if we have a rp_info that should match a prefix
266 * list then if we do match then best should be the answer( even
267 * if it is NULL )
268 */
269 if (!rp_info || (rp_info && rp_info->plist))
270 return best;
271
272 /*
273 * So we have a non plist rp_info found in the lookup and no plists
274 * at all to be choosen, return it!
275 */
89b68082
DS
276 if (!best)
277 return rp_info;
278
94dc0c4e
DS
279 /*
280 * If we have a matching non prefix list and a matching prefix
281 * list we should return the actual rp_info that has the LPM
282 * If they are equal, use the prefix-list( but let's hope
283 * the end-operator doesn't do this )
284 */
285 if (rp_info->group.prefixlen > bp->prefixlen)
89b68082
DS
286 best = rp_info;
287
b77b1550 288 return best;
36d6bd7d 289}
75a26779 290
dfe43e25
DW
291/*
292 * When the user makes "ip pim rp" configuration changes or if they change the
293 * prefix-list(s) used by these statements we must tickle the upstream state
294 * for each group to make them re-lookup who their RP should be.
295 *
296 * This is a placeholder function for now.
297 */
e7016ceb 298void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
dfe43e25 299{
472ad383 300 pim_msdp_i_am_rp_changed(pim);
a749b900 301 pim_upstream_reeval_use_rpt(pim);
dfe43e25
DW
302}
303
d9c9a9ee
DS
304void pim_rp_prefix_list_update(struct pim_instance *pim,
305 struct prefix_list *plist)
dfe43e25 306{
d62a17ae 307 struct listnode *node;
308 struct rp_info *rp_info;
309 int refresh_needed = 0;
310
d9c9a9ee 311 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 312 if (rp_info->plist
313 && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
314 refresh_needed = 1;
315 break;
316 }
317 }
318
319 if (refresh_needed)
472ad383 320 pim_rp_refresh_group_to_rp_mapping(pim);
dfe43e25
DW
321}
322
d62a17ae 323static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
324 struct pim_interface *pim_ifp)
7176984f 325{
d62a17ae 326 struct listnode *node;
327 struct pim_secondary_addr *sec_addr;
c6c615c1 328 pim_addr sec_paddr;
034db86b 329
b63192cf 330 if (!pim_addr_cmp(pim_ifp->primary_address, rp_info->rp.rpf_addr))
d62a17ae 331 return 1;
7176984f 332
d62a17ae 333 if (!pim_ifp->sec_addr_list) {
334 return 0;
335 }
7176984f 336
d62a17ae 337 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
c6c615c1
MR
338 sec_paddr = pim_addr_from_prefix(&sec_addr->addr);
339 /* If an RP-address is self, It should be enough to say
340 * I am RP the prefix-length should not matter here */
341 if (!pim_addr_cmp(sec_paddr, rp_info->rp.rpf_addr))
d62a17ae 342 return 1;
d62a17ae 343 }
7176984f 344
d62a17ae 345 return 0;
7176984f 346}
347
fec883d9
DS
348static void pim_rp_check_interfaces(struct pim_instance *pim,
349 struct rp_info *rp_info)
00d07c6f 350{
d62a17ae 351 struct interface *ifp;
00d07c6f 352
d62a17ae 353 rp_info->i_am_rp = 0;
451fda4f 354 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 355 struct pim_interface *pim_ifp = ifp->info;
00d07c6f 356
d62a17ae 357 if (!pim_ifp)
358 continue;
00d07c6f 359
d62a17ae 360 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
361 rp_info->i_am_rp = 1;
362 }
363 }
00d07c6f
DS
364}
365
28309df0
SP
366void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
367{
368 struct pim_rpf old_rpf;
369 enum pim_rpf_result rpf_result;
5d99ebea
DL
370 pim_addr old_upstream_addr;
371 pim_addr new_upstream_addr;
28309df0
SP
372
373 old_upstream_addr = up->upstream_addr;
374 pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
375 up->sg.grp);
376
23fc858a 377 if (PIM_DEBUG_PIM_TRACE)
5d1d18a1 378 zlog_debug("%s: pim upstream update for old upstream %pPA",
ee2bbf7c 379 __func__, &old_upstream_addr);
28309df0 380
5d99ebea 381 if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr))
28309df0
SP
382 return;
383
384 /* Lets consider a case, where a PIM upstream has a better RP as a
385 * result of a new RP configuration with more precise group range.
386 * This upstream has to be added to the upstream hash of new RP's
387 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
388 */
5d99ebea 389 if (!pim_addr_is_any(old_upstream_addr)) {
28309df0 390 /* Deregister addr with Zebra NHT */
2dbe669b 391 if (PIM_DEBUG_PIM_TRACE)
15569c58 392 zlog_debug(
b63192cf 393 "%s: Deregister upstream %s addr %pPA with Zebra NHT",
394 __func__, up->sg_str, &old_upstream_addr);
e6e53006 395 pim_delete_tracked_nexthop(pim, old_upstream_addr, up, NULL);
28309df0
SP
396 }
397
398 /* Update the upstream address */
399 up->upstream_addr = new_upstream_addr;
400
401 old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
402
8c55c132 403 rpf_result = pim_rpf_update(pim, up, &old_rpf, __func__);
28309df0 404 if (rpf_result == PIM_RPF_FAILURE)
15569c58 405 pim_mroute_del(up->channel_oil, __func__);
28309df0
SP
406
407 /* update kernel multicast forwarding cache (MFC) */
7984af18
AK
408 if (up->rpf.source_nexthop.interface && up->channel_oil)
409 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
28309df0 410
b36576e4
AK
411 if (rpf_result == PIM_RPF_CHANGED ||
412 (rpf_result == PIM_RPF_FAILURE &&
413 old_rpf.source_nexthop.interface))
28309df0
SP
414 pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
415
28309df0
SP
416}
417
6ed1cea1 418int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
cc144e8b 419 const char *plist, enum rp_source rp_src_flag)
d0e418b4 420{
421 int result = 0;
d62a17ae 422 struct rp_info *rp_info;
423 struct rp_info *rp_all;
424 struct prefix group_all;
425 struct listnode *node, *nnode;
426 struct rp_info *tmp_rp_info;
427 char buffer[BUFSIZ];
b63192cf 428 pim_addr nht_p;
94dc0c4e 429 struct route_node *rn = NULL;
28309df0 430 struct pim_upstream *up;
62596d9a 431 bool upstream_updated = false;
d62a17ae 432
6ed1cea1 433 if (pim_addr_is_any(rp_addr))
1e0d1c25
DS
434 return PIM_RP_BAD_ADDRESS;
435
d62a17ae 436 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
d62a17ae 437
b63192cf 438 rp_info->rp.rpf_addr = rp_addr;
d0e418b4 439 prefix_copy(&rp_info->group, &group);
440 rp_info->rp_src = rp_src_flag;
d62a17ae 441
d62a17ae 442 if (plist) {
443 /*
444 * Return if the prefix-list is already configured for this RP
445 */
1db07606 446 if (pim_rp_find_prefix_list(pim, rp_addr, plist)) {
d62a17ae 447 XFREE(MTYPE_PIM_RP, rp_info);
448 return PIM_SUCCESS;
449 }
450
451 /*
452 * Barf if the prefix-list is already configured for an RP
453 */
d9c9a9ee 454 if (pim_rp_prefix_list_used(pim, plist)) {
d62a17ae 455 XFREE(MTYPE_PIM_RP, rp_info);
456 return PIM_RP_PFXLIST_IN_USE;
457 }
458
459 /*
460 * Free any existing rp_info entries for this RP
461 */
d9c9a9ee 462 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
d62a17ae 463 tmp_rp_info)) {
b63192cf 464 if (!pim_addr_cmp(rp_info->rp.rpf_addr,
465 tmp_rp_info->rp.rpf_addr)) {
d62a17ae 466 if (tmp_rp_info->plist)
99384c6e 467 pim_rp_del_config(pim, rp_addr, NULL,
d0e418b4 468 tmp_rp_info->plist);
d62a17ae 469 else
d0e418b4 470 pim_rp_del_config(
99384c6e 471 pim, rp_addr,
d62a17ae 472 prefix2str(&tmp_rp_info->group,
473 buffer, BUFSIZ),
474 NULL);
475 }
476 }
477
478 rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
479 } else {
89b68082 480
c6ced474 481 if (!pim_get_all_mcast_group(&group_all)) {
2e8345c1
DS
482 XFREE(MTYPE_PIM_RP, rp_info);
483 return PIM_GROUP_BAD_ADDRESS;
484 }
d9c9a9ee 485 rp_all = pim_rp_find_match_group(pim, &group_all);
d62a17ae 486
487 /*
488 * Barf if group is a non-multicast subnet
489 */
490 if (!prefix_match(&rp_all->group, &rp_info->group)) {
491 XFREE(MTYPE_PIM_RP, rp_info);
492 return PIM_GROUP_BAD_ADDRESS;
493 }
494
495 /*
496 * Remove any prefix-list rp_info entries for this RP
497 */
d9c9a9ee 498 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
d62a17ae 499 tmp_rp_info)) {
6ed1cea1 500 if (tmp_rp_info->plist &&
b63192cf 501 (!pim_addr_cmp(rp_info->rp.rpf_addr,
502 tmp_rp_info->rp.rpf_addr))) {
99384c6e 503 pim_rp_del_config(pim, rp_addr, NULL,
d0e418b4 504 tmp_rp_info->plist);
d62a17ae 505 }
506 }
507
508 /*
b369d0cc 509 * Take over the 224.0.0.0/4 group if the rp is INADDR_ANY
d62a17ae 510 */
cc144e8b 511 if (prefix_same(&rp_all->group, &rp_info->group) &&
512 pim_rpf_addr_is_inaddr_any(&rp_all->rp)) {
d62a17ae 513 rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
d0e418b4 514 rp_all->rp_src = rp_src_flag;
d62a17ae 515 XFREE(MTYPE_PIM_RP, rp_info);
516
517 /* Register addr with Zebra NHT */
6ed1cea1 518 nht_p = rp_all->rp.rpf_addr;
2dbe669b 519 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 520 zlog_debug(
b63192cf 521 "%s: NHT Register rp_all addr %pPA grp %pFX ",
2dbe669b 522 __func__, &nht_p, &rp_all->group);
28309df0 523
dd3364cb 524 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
28309df0
SP
525 /* Find (*, G) upstream whose RP is not
526 * configured yet
527 */
01adb431 528 if (pim_addr_is_any(up->upstream_addr) &&
2a27f13b 529 pim_addr_is_any(up->sg.src)) {
28309df0
SP
530 struct prefix grp;
531 struct rp_info *trp_info;
532
5d99ebea 533 pim_addr_to_prefix(&grp, up->sg.grp);
d0e418b4 534 trp_info = pim_rp_find_match_group(
535 pim, &grp);
62596d9a 536 if (trp_info == rp_all) {
28309df0 537 pim_upstream_update(pim, up);
62596d9a
MR
538 upstream_updated = true;
539 }
28309df0
SP
540 }
541 }
62596d9a
MR
542 if (upstream_updated)
543 pim_zebra_update_all_interfaces(pim);
28309df0 544
5bd51314
DS
545 pim_rp_check_interfaces(pim, rp_all);
546 pim_rp_refresh_group_to_rp_mapping(pim);
e6e53006 547 pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all,
4efdb9c6 548 NULL);
4533b847 549
43763b11
DS
550 if (!pim_ecmp_nexthop_lookup(pim,
551 &rp_all->rp.source_nexthop,
e6e53006 552 nht_p, &rp_all->group, 1))
43763b11 553 return PIM_RP_NO_PATH;
d62a17ae 554 return PIM_SUCCESS;
555 }
556
557 /*
558 * Return if the group is already configured for this RP
559 */
fd5540ea 560 tmp_rp_info = pim_rp_find_exact(pim, rp_addr, &rp_info->group);
d0e418b4 561 if (tmp_rp_info) {
562 if ((tmp_rp_info->rp_src != rp_src_flag)
563 && (rp_src_flag == RP_SRC_STATIC))
564 tmp_rp_info->rp_src = rp_src_flag;
d62a17ae 565 XFREE(MTYPE_PIM_RP, rp_info);
d0e418b4 566 return result;
d62a17ae 567 }
568
569 /*
570 * Barf if this group is already covered by some other RP
571 */
d9c9a9ee 572 tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group);
d62a17ae 573
574 if (tmp_rp_info) {
575 if (tmp_rp_info->plist) {
576 XFREE(MTYPE_PIM_RP, rp_info);
577 return PIM_GROUP_PFXLIST_OVERLAP;
578 } else {
579 /*
580 * If the only RP that covers this group is an
581 * RP configured for
582 * 224.0.0.0/4 that is fine, ignore that one.
583 * For all others
584 * though we must return PIM_GROUP_OVERLAP
585 */
89b68082
DS
586 if (prefix_same(&rp_info->group,
587 &tmp_rp_info->group)) {
d0e418b4 588 if ((rp_src_flag == RP_SRC_STATIC)
589 && (tmp_rp_info->rp_src
590 == RP_SRC_STATIC)) {
591 XFREE(MTYPE_PIM_RP, rp_info);
592 return PIM_GROUP_OVERLAP;
593 }
594
595 result = pim_rp_change(
49b7b2c4 596 pim, rp_addr,
d0e418b4 597 tmp_rp_info->group,
598 rp_src_flag);
d62a17ae 599 XFREE(MTYPE_PIM_RP, rp_info);
d0e418b4 600 return result;
d62a17ae 601 }
602 }
603 }
604 }
605
d9c9a9ee 606 listnode_add_sort(pim->rp_list, rp_info);
94dc0c4e
DS
607
608 if (!rp_info->plist) {
609 rn = route_node_get(pim->rp_table, &rp_info->group);
610 rn->info = rp_info;
611 }
89b68082 612
2dbe669b
DA
613 if (PIM_DEBUG_PIM_TRACE)
614 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
615 rp_info, &rp_info->group,
94dc0c4e 616 rn ? route_node_get_lock_count(rn) : 0);
d62a17ae 617
dd3364cb 618 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 619 if (pim_addr_is_any(up->sg.src)) {
28309df0
SP
620 struct prefix grp;
621 struct rp_info *trp_info;
622
5d99ebea 623 pim_addr_to_prefix(&grp, up->sg.grp);
28309df0
SP
624 trp_info = pim_rp_find_match_group(pim, &grp);
625
62596d9a 626 if (trp_info == rp_info) {
28309df0 627 pim_upstream_update(pim, up);
62596d9a
MR
628 upstream_updated = true;
629 }
28309df0
SP
630 }
631 }
632
62596d9a
MR
633 if (upstream_updated)
634 pim_zebra_update_all_interfaces(pim);
635
5bd51314
DS
636 pim_rp_check_interfaces(pim, rp_info);
637 pim_rp_refresh_group_to_rp_mapping(pim);
638
d62a17ae 639 /* Register addr with Zebra NHT */
6ed1cea1 640 nht_p = rp_info->rp.rpf_addr;
2dbe669b 641 if (PIM_DEBUG_PIM_NHT_RP)
b63192cf 642 zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
2dbe669b 643 __func__, &nht_p, &rp_info->group);
e6e53006 644 pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
645 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
43763b11
DS
646 &rp_info->group, 1))
647 return PIM_RP_NO_PATH;
d62a17ae 648
d62a17ae 649 return PIM_SUCCESS;
75a26779
DS
650}
651
99384c6e
MR
652void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr,
653 const char *group_range, const char *plist)
75a26779 654{
d62a17ae 655 struct prefix group;
d62a17ae 656 int result;
d62a17ae 657
658 if (group_range == NULL)
c6ced474 659 result = pim_get_all_mcast_group(&group);
d62a17ae 660 else
661 result = str2prefix(group_range, &group);
662
99384c6e
MR
663 if (!result) {
664 if (PIM_DEBUG_PIM_TRACE)
665 zlog_debug(
666 "%s: String to prefix failed for %pPAs group",
667 __func__, &rp_addr);
668 return;
669 }
d62a17ae 670
99384c6e 671 pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
d0e418b4 672}
673
9dca52b9
MR
674int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
675 const char *plist, enum rp_source rp_src_flag)
d0e418b4 676{
677 struct prefix g_all;
678 struct rp_info *rp_info;
679 struct rp_info *rp_all;
b63192cf 680 pim_addr nht_p;
d0e418b4 681 struct route_node *rn;
682 bool was_plist = false;
683 struct rp_info *trp_info;
684 struct pim_upstream *up;
d0e418b4 685 struct bsgrp_node *bsgrp = NULL;
686 struct bsm_rpinfo *bsrp = NULL;
62596d9a 687 bool upstream_updated = false;
d0e418b4 688
d62a17ae 689 if (plist)
d9c9a9ee 690 rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
d62a17ae 691 else
d9c9a9ee 692 rp_info = pim_rp_find_exact(pim, rp_addr, &group);
d62a17ae 693
694 if (!rp_info)
695 return PIM_RP_NOT_FOUND;
696
697 if (rp_info->plist) {
698 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
89b68082 699 was_plist = true;
d62a17ae 700 }
701
23fc858a 702 if (PIM_DEBUG_PIM_TRACE)
9dca52b9
MR
703 zlog_debug("%s: Delete RP %pPA for the group %pFX", __func__,
704 &rp_addr, &group);
d0e418b4 705
706 /* While static RP is getting deleted, we need to check if dynamic RP
707 * present for the same group in BSM RP table, then install the dynamic
708 * RP for the group node into the main rp table
709 */
710 if (rp_src_flag == RP_SRC_STATIC) {
711 bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
712
713 if (bsgrp) {
fdab2940 714 bsrp = bsm_rpinfos_first(bsgrp->bsrp_list);
d0e418b4 715 if (bsrp) {
9dca52b9 716 if (PIM_DEBUG_PIM_TRACE)
15569c58 717 zlog_debug(
9dca52b9
MR
718 "%s: BSM RP %pPA found for the group %pFX",
719 __func__, &bsrp->rp_address,
720 &group);
d0e418b4 721 return pim_rp_change(pim, bsrp->rp_address,
722 group, RP_SRC_BSR);
723 }
724 } else {
23fc858a 725 if (PIM_DEBUG_PIM_TRACE)
d0e418b4 726 zlog_debug(
2dbe669b
DA
727 "%s: BSM RP not found for the group %pFX",
728 __func__, &group);
d0e418b4 729 }
730 }
731
d62a17ae 732 /* Deregister addr with Zebra NHT */
9dca52b9 733 nht_p = rp_info->rp.rpf_addr;
2dbe669b 734 if (PIM_DEBUG_PIM_NHT_RP)
b63192cf 735 zlog_debug("%s: Deregister RP addr %pPA with Zebra ", __func__,
2dbe669b 736 &nht_p);
e6e53006 737 pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
d62a17ae 738
c6ced474 739 if (!pim_get_all_mcast_group(&g_all))
e691f179
DS
740 return PIM_RP_BAD_ADDRESS;
741
d9c9a9ee 742 rp_all = pim_rp_find_match_group(pim, &g_all);
d62a17ae 743
744 if (rp_all == rp_info) {
dd3364cb 745 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
8cfd7268
SP
746 /* Find the upstream (*, G) whose upstream address is
747 * same as the deleted RP
748 */
01adb431
DL
749 pim_addr rpf_addr;
750
b63192cf 751 rpf_addr = rp_info->rp.rpf_addr;
01adb431 752 if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
2a27f13b 753 pim_addr_is_any(up->sg.src)) {
8cfd7268 754 struct prefix grp;
5d99ebea
DL
755
756 pim_addr_to_prefix(&grp, up->sg.grp);
8cfd7268
SP
757 trp_info = pim_rp_find_match_group(pim, &grp);
758 if (trp_info == rp_all) {
759 pim_upstream_rpf_clear(pim, up);
01adb431 760 up->upstream_addr = PIMADDR_ANY;
8cfd7268
SP
761 }
762 }
763 }
b63192cf 764 rp_all->rp.rpf_addr = PIMADDR_ANY;
d62a17ae 765 rp_all->i_am_rp = 0;
766 return PIM_SUCCESS;
767 }
768
d9c9a9ee 769 listnode_delete(pim->rp_list, rp_info);
89b68082
DS
770
771 if (!was_plist) {
772 rn = route_node_get(pim->rp_table, &rp_info->group);
773 if (rn) {
774 if (rn->info != rp_info)
af4c2728 775 flog_err(
450971aa 776 EC_LIB_DEVELOPMENT,
3613d898 777 "Expected rn->info to be equal to rp_info");
89b68082 778
2dbe669b 779 if (PIM_DEBUG_PIM_TRACE)
996c9314 780 zlog_debug(
2dbe669b
DA
781 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
782 __func__, rn, rp_info, &rp_info->group,
c10e14e9 783 route_node_get_lock_count(rn));
2dbe669b 784
89b68082
DS
785 rn->info = NULL;
786 route_unlock_node(rn);
787 route_unlock_node(rn);
788 }
789 }
790
472ad383 791 pim_rp_refresh_group_to_rp_mapping(pim);
093c928f 792
dd3364cb 793 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
8cfd7268
SP
794 /* Find the upstream (*, G) whose upstream address is same as
795 * the deleted RP
796 */
01adb431
DL
797 pim_addr rpf_addr;
798
b63192cf 799 rpf_addr = rp_info->rp.rpf_addr;
01adb431 800 if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
2a27f13b 801 pim_addr_is_any(up->sg.src)) {
8cfd7268
SP
802 struct prefix grp;
803
5d99ebea 804 pim_addr_to_prefix(&grp, up->sg.grp);
8cfd7268
SP
805 trp_info = pim_rp_find_match_group(pim, &grp);
806
807 /* RP not found for the group grp */
cc144e8b 808 if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) {
8cfd7268 809 pim_upstream_rpf_clear(pim, up);
d0e418b4 810 pim_rp_set_upstream_addr(
811 pim, &up->upstream_addr, up->sg.src,
812 up->sg.grp);
8cfd7268
SP
813 }
814
815 /* RP found for the group grp */
62596d9a 816 else {
8cfd7268 817 pim_upstream_update(pim, up);
62596d9a
MR
818 upstream_updated = true;
819 }
8cfd7268
SP
820 }
821 }
822
62596d9a
MR
823 if (upstream_updated)
824 pim_zebra_update_all_interfaces(pim);
825
093c928f 826 XFREE(MTYPE_PIM_RP, rp_info);
d62a17ae 827 return PIM_SUCCESS;
75a26779 828}
13afbd05 829
49b7b2c4 830int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr,
d0e418b4 831 struct prefix group, enum rp_source rp_src_flag)
832{
b63192cf 833 pim_addr nht_p;
d0e418b4 834 struct route_node *rn;
835 int result = 0;
836 struct rp_info *rp_info = NULL;
837 struct pim_upstream *up;
62596d9a 838 bool upstream_updated = false;
49b7b2c4 839 pim_addr old_rp_addr;
d0e418b4 840
841 rn = route_node_lookup(pim->rp_table, &group);
842 if (!rn) {
843 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
844 return result;
845 }
846
847 rp_info = rn->info;
848
849 if (!rp_info) {
850 route_unlock_node(rn);
851 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
852 return result;
853 }
854
b63192cf 855 old_rp_addr = rp_info->rp.rpf_addr;
49b7b2c4 856 if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) {
d0e418b4 857 if (rp_info->rp_src != rp_src_flag) {
858 rp_info->rp_src = rp_src_flag;
859 route_unlock_node(rn);
860 return PIM_SUCCESS;
861 }
862 }
863
864 /* Deregister old RP addr with Zebra NHT */
49b7b2c4
MR
865
866 if (!pim_addr_is_any(old_rp_addr)) {
867 nht_p = rp_info->rp.rpf_addr;
2dbe669b 868 if (PIM_DEBUG_PIM_NHT_RP)
b63192cf 869 zlog_debug("%s: Deregister RP addr %pPA with Zebra ",
2dbe669b 870 __func__, &nht_p);
e6e53006 871 pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info);
d0e418b4 872 }
873
874 pim_rp_nexthop_del(rp_info);
875 listnode_delete(pim->rp_list, rp_info);
876 /* Update the new RP address*/
49b7b2c4 877
b63192cf 878 rp_info->rp.rpf_addr = new_rp_addr;
d0e418b4 879 rp_info->rp_src = rp_src_flag;
880 rp_info->i_am_rp = 0;
881
882 listnode_add_sort(pim->rp_list, rp_info);
883
dd3364cb 884 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 885 if (pim_addr_is_any(up->sg.src)) {
d0e418b4 886 struct prefix grp;
887 struct rp_info *trp_info;
888
5d99ebea 889 pim_addr_to_prefix(&grp, up->sg.grp);
d0e418b4 890 trp_info = pim_rp_find_match_group(pim, &grp);
891
62596d9a 892 if (trp_info == rp_info) {
d0e418b4 893 pim_upstream_update(pim, up);
62596d9a
MR
894 upstream_updated = true;
895 }
d0e418b4 896 }
897 }
898
62596d9a
MR
899 if (upstream_updated)
900 pim_zebra_update_all_interfaces(pim);
901
d0e418b4 902 /* Register new RP addr with Zebra NHT */
49b7b2c4 903 nht_p = rp_info->rp.rpf_addr;
2dbe669b 904 if (PIM_DEBUG_PIM_NHT_RP)
b63192cf 905 zlog_debug("%s: NHT Register RP addr %pPA grp %pFX with Zebra ",
2dbe669b 906 __func__, &nht_p, &rp_info->group);
d0e418b4 907
e6e53006 908 pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
909 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, nht_p,
d0e418b4 910 &rp_info->group, 1)) {
911 route_unlock_node(rn);
912 return PIM_RP_NO_PATH;
913 }
914
915 pim_rp_check_interfaces(pim, rp_info);
916
917 route_unlock_node(rn);
918
919 pim_rp_refresh_group_to_rp_mapping(pim);
920
921 return result;
922}
923
fec883d9 924void pim_rp_setup(struct pim_instance *pim)
13afbd05 925{
d62a17ae 926 struct listnode *node;
927 struct rp_info *rp_info;
b63192cf 928 pim_addr nht_p;
d62a17ae 929
d9c9a9ee 930 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 931 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 932 continue;
933
5d1d18a1 934 nht_p = rp_info->rp.rpf_addr;
8cfd7268 935
e6e53006 936 pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
43763b11 937 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
43a18948 938 nht_p, &rp_info->group, 1)) {
43763b11 939 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 940 zlog_debug(
43763b11 941 "Unable to lookup nexthop for rp specified");
43a18948
SP
942 pim_rp_nexthop_del(rp_info);
943 }
d62a17ae 944 }
13afbd05
DS
945}
946
54b97c74 947/*
7176984f 948 * Checks to see if we should elect ourself the actual RP when new if
949 * addresses are added against an interface.
54b97c74 950 */
d62a17ae 951void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
54b97c74 952{
d62a17ae 953 struct listnode *node;
954 struct rp_info *rp_info;
955 bool i_am_rp_changed = false;
d9c9a9ee 956 struct pim_instance *pim = pim_ifp->pim;
d62a17ae 957
d9c9a9ee 958 if (pim->rp_list == NULL)
d62a17ae 959 return;
960
d9c9a9ee 961 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 962 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 963 continue;
964
965 /* if i_am_rp is already set nothing to be done (adding new
966 * addresses
967 * is not going to make a difference). */
968 if (rp_info->i_am_rp) {
969 continue;
970 }
971
972 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
973 i_am_rp_changed = true;
974 rp_info->i_am_rp = 1;
b63192cf 975 if (PIM_DEBUG_PIM_NHT_RP)
976 zlog_debug("%s: %pPA: i am rp", __func__,
977 &rp_info->rp.rpf_addr);
d62a17ae 978 }
979 }
980
981 if (i_am_rp_changed) {
472ad383 982 pim_msdp_i_am_rp_changed(pim);
a749b900 983 pim_upstream_reeval_use_rpt(pim);
d62a17ae 984 }
7176984f 985}
36d6bd7d 986
7176984f 987/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
988 * are removed. Removing numbers is an uncommon event in an active network
989 * so I have made no attempt to optimize it. */
fec883d9 990void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
7176984f 991{
d62a17ae 992 struct listnode *node;
993 struct rp_info *rp_info;
994 bool i_am_rp_changed = false;
995 int old_i_am_rp;
996
d9c9a9ee 997 if (pim->rp_list == NULL)
d62a17ae 998 return;
999
d9c9a9ee 1000 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1001 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1002 continue;
1003
1004 old_i_am_rp = rp_info->i_am_rp;
fec883d9 1005 pim_rp_check_interfaces(pim, rp_info);
d62a17ae 1006
1007 if (old_i_am_rp != rp_info->i_am_rp) {
1008 i_am_rp_changed = true;
3d225d48 1009 if (PIM_DEBUG_PIM_NHT_RP) {
b63192cf 1010 if (rp_info->i_am_rp)
1011 zlog_debug("%s: %pPA: i am rp",
1012 __func__,
1013 &rp_info->rp.rpf_addr);
1014 else
e6e53006 1015 zlog_debug(
1016 "%s: %pPA: i am no longer rp",
1017 __func__,
1018 &rp_info->rp.rpf_addr);
d62a17ae 1019 }
1020 }
1021 }
1022
1023 if (i_am_rp_changed) {
472ad383 1024 pim_msdp_i_am_rp_changed(pim);
a749b900 1025 pim_upstream_reeval_use_rpt(pim);
d62a17ae 1026 }
54b97c74
DS
1027}
1028
1029/*
1030 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1031 * this router is the RP for the group.
1032 *
1033 * Since we only have static RP, all groups are part of this RP
1034 */
5d99ebea 1035int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group)
54b97c74 1036{
d62a17ae 1037 struct prefix g;
1038 struct rp_info *rp_info;
36d6bd7d 1039
d62a17ae 1040 memset(&g, 0, sizeof(g));
131ded08 1041 pim_addr_to_prefix(&g, group);
d9c9a9ee 1042 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 1043
d62a17ae 1044 if (rp_info)
1045 return rp_info->i_am_rp;
d62a17ae 1046 return 0;
54b97c74
DS
1047}
1048
71694057
DS
1049/*
1050 * RP(G)
1051 *
1052 * Return the RP that the Group belongs too.
1053 */
5d99ebea 1054struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group)
71694057 1055{
d62a17ae 1056 struct prefix g;
1057 struct rp_info *rp_info;
1058
1059 memset(&g, 0, sizeof(g));
8eb5ad6c 1060 pim_addr_to_prefix(&g, group);
d62a17ae 1061
d9c9a9ee 1062 rp_info = pim_rp_find_match_group(pim, &g);
d62a17ae 1063
1064 if (rp_info) {
b63192cf 1065 pim_addr nht_p;
43763b11 1066
201a31b9
SP
1067 if (pim_addr_is_any(rp_info->rp.rpf_addr)) {
1068 if (PIM_DEBUG_PIM_NHT_RP)
1069 zlog_debug(
1070 "%s: Skipping NHT Register since RP is not configured for the group %pPA",
1071 __func__, &group);
1072 return &rp_info->rp;
1073 }
1074
d62a17ae 1075 /* Register addr with Zebra NHT */
8eb5ad6c 1076 nht_p = rp_info->rp.rpf_addr;
2dbe669b 1077 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 1078 zlog_debug(
b63192cf 1079 "%s: NHT Register RP addr %pPA grp %pFX with Zebra",
2dbe669b 1080 __func__, &nht_p, &rp_info->group);
e6e53006 1081 pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
43763b11
DS
1082 pim_rpf_set_refresh_time(pim);
1083 (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
e6e53006 1084 nht_p, &rp_info->group, 1);
d62a17ae 1085 return (&rp_info->rp);
1086 }
1087
1088 // About to Go Down
1089 return NULL;
71694057
DS
1090}
1091
8f5f5e91
DS
1092/*
1093 * Set the upstream IP address we want to talk to based upon
1094 * the rp configured and the source address
1095 *
1096 * If we have don't have a RP configured and the source address is *
732c209c 1097 * then set the upstream addr as INADDR_ANY and return failure.
8f5f5e91
DS
1098 *
1099 */
5d99ebea
DL
1100int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up,
1101 pim_addr source, pim_addr group)
8f5f5e91 1102{
d62a17ae 1103 struct rp_info *rp_info;
1104 struct prefix g;
36d6bd7d 1105
d62a17ae 1106 memset(&g, 0, sizeof(g));
b1e132ac
MR
1107
1108 pim_addr_to_prefix(&g, group);
36d6bd7d 1109
d9c9a9ee 1110 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 1111
cc144e8b 1112 if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) &&
b1e132ac 1113 (pim_addr_is_any(source)))) {
3d225d48 1114 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 1115 zlog_debug("%s: Received a (*,G) with no RP configured",
15569c58 1116 __func__);
b1e132ac 1117 *up = PIMADDR_ANY;
d62a17ae 1118 return 0;
1119 }
8f5f5e91 1120
b1e132ac 1121 if (pim_addr_is_any(source))
b63192cf 1122 *up = rp_info->rp.rpf_addr;
b1e132ac
MR
1123 else
1124 *up = source;
8f5f5e91 1125
d62a17ae 1126 return 1;
8f5f5e91 1127}
75a26779 1128
0c8b717e
DS
1129int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
1130 const char *spaces)
75a26779 1131{
d62a17ae 1132 struct listnode *node;
1133 struct rp_info *rp_info;
d62a17ae 1134 int count = 0;
0c3182a0 1135 pim_addr rp_addr;
d62a17ae 1136
d9c9a9ee 1137 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1138 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1139 continue;
1140
d0e418b4 1141 if (rp_info->rp_src == RP_SRC_BSR)
1142 continue;
1143
b63192cf 1144 rp_addr = rp_info->rp.rpf_addr;
d62a17ae 1145 if (rp_info->plist)
0c3182a0
MR
1146 vty_out(vty,
1147 "%s" PIM_AF_NAME
1148 " pim rp %pPA prefix-list %s\n",
1149 spaces, &rp_addr, rp_info->plist);
d62a17ae 1150 else
0c3182a0
MR
1151 vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n",
1152 spaces, &rp_addr, &rp_info->group);
d62a17ae 1153 count++;
1154 }
1155
1156 return count;
75a26779
DS
1157}
1158
8c0a7680 1159void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
0095f482 1160 struct vty *vty, json_object *json)
00d07c6f 1161{
d62a17ae 1162 struct rp_info *rp_info;
1163 struct rp_info *prev_rp_info = NULL;
1164 struct listnode *node;
f1ebd3db
A
1165 struct ttable *tt = NULL;
1166 char *table = NULL;
025725f7 1167 char source[7];
f1ebd3db 1168 char grp[INET6_ADDRSTRLEN];
d62a17ae 1169
d62a17ae 1170 json_object *json_rp_rows = NULL;
1171 json_object *json_row = NULL;
1172
f1ebd3db
A
1173 if (!json) {
1174 /* Prepare table. */
1175 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1176 ttable_add_row(
1177 tt,
1178 "RP address|group/prefix-list|OIF|I am RP|Source|Group-Type");
1179 tt->style.cell.rpad = 2;
1180 tt->style.corner = '+';
1181 ttable_restyle(tt);
1182 }
1183
d9c9a9ee 1184 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
243e02ab
DL
1185 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
1186 continue;
d62a17ae 1187
8c0a7680
DA
1188#if PIM_IPV == 4
1189 pim_addr group = rp_info->group.u.prefix4;
1190#else
1191 pim_addr group = rp_info->group.u.prefix6;
1192#endif
1193 const char *group_type =
1194 pim_is_grp_ssm(pim, group) ? "SSM" : "ASM";
1195
c07ddc36 1196 if (range && !prefix_match(&rp_info->group, range))
8c0a7680
DA
1197 continue;
1198
243e02ab
DL
1199 if (rp_info->rp_src == RP_SRC_STATIC)
1200 strlcpy(source, "Static", sizeof(source));
1201 else if (rp_info->rp_src == RP_SRC_BSR)
1202 strlcpy(source, "BSR", sizeof(source));
1203 else
1204 strlcpy(source, "None", sizeof(source));
0095f482 1205 if (json) {
243e02ab
DL
1206 /*
1207 * If we have moved on to a new RP then add the
1208 * entry for the previous RP
1209 */
1210 if (prev_rp_info &&
b63192cf 1211 (pim_addr_cmp(prev_rp_info->rp.rpf_addr,
1212 rp_info->rp.rpf_addr))) {
5d1d18a1 1213 json_object_object_addf(
b63192cf 1214 json, json_rp_rows, "%pPA",
5d1d18a1 1215 &prev_rp_info->rp.rpf_addr);
243e02ab
DL
1216 json_rp_rows = NULL;
1217 }
d62a17ae 1218
243e02ab
DL
1219 if (!json_rp_rows)
1220 json_rp_rows = json_object_new_array();
1221
1222 json_row = json_object_new_object();
b63192cf 1223 json_object_string_addf(json_row, "rpAddress", "%pPA",
5d1d18a1 1224 &rp_info->rp.rpf_addr);
243e02ab
DL
1225 if (rp_info->rp.source_nexthop.interface)
1226 json_object_string_add(
1227 json_row, "outboundInterface",
1228 rp_info->rp.source_nexthop
1229 .interface->name);
1230 else
1231 json_object_string_add(json_row,
1232 "outboundInterface",
1233 "Unknown");
1234 if (rp_info->i_am_rp)
1235 json_object_boolean_true_add(json_row, "iAmRP");
1236 else
1237 json_object_boolean_false_add(json_row,
1238 "iAmRP");
d62a17ae 1239
243e02ab
DL
1240 if (rp_info->plist)
1241 json_object_string_add(json_row, "prefixList",
1242 rp_info->plist);
1243 else
1244 json_object_string_addf(json_row, "group",
1245 "%pFX",
1246 &rp_info->group);
1247 json_object_string_add(json_row, "source", source);
8c0a7680
DA
1248 json_object_string_add(json_row, "groupType",
1249 group_type);
d62a17ae 1250
243e02ab
DL
1251 json_object_array_add(json_rp_rows, json_row);
1252 } else {
f1ebd3db
A
1253 prefix2str(&rp_info->group, grp, sizeof(grp));
1254 ttable_add_row(tt, "%pPA|%s|%s|%s|%s|%s",
1255 &rp_info->rp.rpf_addr,
1256 rp_info->plist
1257 ? rp_info->plist
1258 : grp,
1259 rp_info->rp.source_nexthop.interface
1260 ? rp_info->rp.source_nexthop
1261 .interface->name
1262 : "Unknown",
1263 rp_info->i_am_rp
1264 ? "yes"
1265 : "no",
1266 source, group_type);
d62a17ae 1267 }
243e02ab 1268 prev_rp_info = rp_info;
d62a17ae 1269 }
1270
f1ebd3db
A
1271 /* Dump the generated table. */
1272 if (!json) {
1273 table = ttable_dump(tt, "\n");
1274 vty_out(vty, "%s\n", table);
1275 XFREE(MTYPE_TMP, table);
1276 ttable_del(tt);
1277 } else {
d62a17ae 1278 if (prev_rp_info && json_rp_rows)
b63192cf 1279 json_object_object_addf(json, json_rp_rows, "%pPA",
5d1d18a1 1280 &prev_rp_info->rp.rpf_addr);
d62a17ae 1281 }
00d07c6f 1282}
cba44481 1283
c9cd7fbc 1284void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
cba44481 1285{
d62a17ae 1286 struct listnode *node = NULL;
1287 struct rp_info *rp_info = NULL;
1288 struct nexthop *nh_node = NULL;
b63192cf 1289 pim_addr nht_p;
d62a17ae 1290 struct pim_nexthop_cache pnc;
d62a17ae 1291
d9c9a9ee 1292 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1293 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1294 continue;
1295
5d1d18a1 1296 nht_p = rp_info->rp.rpf_addr;
d62a17ae 1297 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
e6e53006 1298 if (!pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, &pnc))
cb9c7c50
DS
1299 continue;
1300
1301 for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
5d1d18a1
DL
1302#if PIM_IPV == 4
1303 if (!pim_addr_is_any(nh_node->gate.ipv4))
1304 continue;
1305#else
1306 if (!pim_addr_is_any(nh_node->gate.ipv6))
cb9c7c50 1307 continue;
5d1d18a1 1308#endif
cb9c7c50
DS
1309
1310 struct interface *ifp1 = if_lookup_by_index(
d3cc1e45 1311 nh_node->ifindex, pim->vrf->vrf_id);
c9cd7fbc
DS
1312
1313 if (nbr->interface != ifp1)
cb9c7c50
DS
1314 continue;
1315
ae449dc5 1316#if PIM_IPV == 4
cb9c7c50 1317 nh_node->gate.ipv4 = nbr->source_addr;
9bb93fa0
DL
1318#else
1319 nh_node->gate.ipv6 = nbr->source_addr;
1320#endif
5d1d18a1 1321 if (PIM_DEBUG_PIM_NHT_RP)
cb9c7c50 1322 zlog_debug(
b63192cf 1323 "%s: addr %pPA new nexthop addr %pPAs interface %s",
5d1d18a1 1324 __func__, &nht_p, &nbr->source_addr,
9bb93fa0 1325 ifp1->name);
d62a17ae 1326 }
1327 }
cba44481 1328}