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