]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_rp.c
pim6d: Modify pim_rp_find_prefix_list for PIMv6
[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 */
d9c9a9ee
DS
191static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
192 struct in_addr rp,
123214ef 193 const struct prefix *group)
36d6bd7d 194{
d62a17ae 195 struct listnode *node;
196 struct rp_info *rp_info;
36d6bd7d 197
d9c9a9ee 198 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 199 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
200 && prefix_same(&rp_info->group, group))
201 return rp_info;
202 }
54b97c74 203
d62a17ae 204 return NULL;
36d6bd7d
DS
205}
206
2b6b16fc
DL
207/*
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
210 * kinda garbage.)
211 *
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"
216 *
217 * To avoid this pitfall, this code uses "address_mode = true" for the prefix
218 * list match (this is the only user for that.)
219 *
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.
223 */
224
225#include "lib/plist_int.h"
226
dfe43e25
DW
227/*
228 * Given a group, return the rp_info for that group
229 */
28309df0 230struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
123214ef 231 const struct prefix *group)
36d6bd7d 232{
d62a17ae 233 struct listnode *node;
b77b1550 234 struct rp_info *best = NULL;
d62a17ae 235 struct rp_info *rp_info;
236 struct prefix_list *plist;
2b6b16fc
DL
237 const struct prefix *bp;
238 const struct prefix_list_entry *entry;
89b68082 239 struct route_node *rn;
d62a17ae 240
4646b86a 241 bp = NULL;
d9c9a9ee 242 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 243 if (rp_info->plist) {
244 plist = prefix_list_lookup(AFI_IP, rp_info->plist);
245
2b6b16fc
DL
246 if (prefix_list_apply_ext(plist, &entry, group, true)
247 == PREFIX_DENY || !entry)
b77b1550
DS
248 continue;
249
250 if (!best) {
251 best = rp_info;
2b6b16fc 252 bp = &entry->prefix;
b77b1550
DS
253 continue;
254 }
255
2b6b16fc 256 if (bp && bp->prefixlen < entry->prefix.prefixlen) {
b77b1550 257 best = rp_info;
2b6b16fc 258 bp = &entry->prefix;
b77b1550 259 }
d62a17ae 260 }
261 }
262
89b68082
DS
263 rn = route_node_match(pim->rp_table, group);
264 if (!rn) {
af4c2728 265 flog_err(
450971aa 266 EC_LIB_DEVELOPMENT,
1d5453d6 267 "%s: BUG We should have found default group information",
5e81f5dd 268 __func__);
89b68082
DS
269 return best;
270 }
271
272 rp_info = rn->info;
2dbe669b
DA
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,
c10e14e9 276 route_node_get_lock_count(rn));
89b68082 277
260c92c8 278 route_unlock_node(rn);
279
89b68082
DS
280 if (!best)
281 return rp_info;
282
283 if (rp_info->group.prefixlen < best->group.prefixlen)
284 best = rp_info;
285
b77b1550 286 return best;
36d6bd7d 287}
75a26779 288
dfe43e25
DW
289/*
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.
293 *
294 * This is a placeholder function for now.
295 */
e7016ceb 296void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
dfe43e25 297{
472ad383 298 pim_msdp_i_am_rp_changed(pim);
a749b900 299 pim_upstream_reeval_use_rpt(pim);
dfe43e25
DW
300}
301
d9c9a9ee
DS
302void pim_rp_prefix_list_update(struct pim_instance *pim,
303 struct prefix_list *plist)
dfe43e25 304{
d62a17ae 305 struct listnode *node;
306 struct rp_info *rp_info;
307 int refresh_needed = 0;
308
d9c9a9ee 309 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 310 if (rp_info->plist
311 && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
312 refresh_needed = 1;
313 break;
314 }
315 }
316
317 if (refresh_needed)
472ad383 318 pim_rp_refresh_group_to_rp_mapping(pim);
dfe43e25
DW
319}
320
d62a17ae 321static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
322 struct pim_interface *pim_ifp)
7176984f 323{
d62a17ae 324 struct listnode *node;
325 struct pim_secondary_addr *sec_addr;
034db86b 326 pim_addr rpf_addr;
7176984f 327
034db86b
DL
328 rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
329
330 if (!pim_addr_cmp(pim_ifp->primary_address, 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)) {
338 if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
339 return 1;
340 }
341 }
7176984f 342
d62a17ae 343 return 0;
7176984f 344}
345
fec883d9
DS
346static void pim_rp_check_interfaces(struct pim_instance *pim,
347 struct rp_info *rp_info)
00d07c6f 348{
d62a17ae 349 struct interface *ifp;
00d07c6f 350
d62a17ae 351 rp_info->i_am_rp = 0;
451fda4f 352 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 353 struct pim_interface *pim_ifp = ifp->info;
00d07c6f 354
d62a17ae 355 if (!pim_ifp)
356 continue;
00d07c6f 357
d62a17ae 358 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
359 rp_info->i_am_rp = 1;
360 }
361 }
00d07c6f
DS
362}
363
28309df0
SP
364void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
365{
366 struct pim_rpf old_rpf;
367 enum pim_rpf_result rpf_result;
5d99ebea
DL
368 pim_addr old_upstream_addr;
369 pim_addr new_upstream_addr;
28309df0
SP
370 struct prefix nht_p;
371
372 old_upstream_addr = up->upstream_addr;
373 pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
374 up->sg.grp);
375
23fc858a 376 if (PIM_DEBUG_PIM_TRACE)
ee2bbf7c
MS
377 zlog_debug("%s: pim upstream update for old upstream %pI4",
378 __func__, &old_upstream_addr);
28309df0 379
5d99ebea 380 if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr))
28309df0
SP
381 return;
382
383 /* Lets consider a case, where a PIM upstream has a better RP as a
384 * result of a new RP configuration with more precise group range.
385 * This upstream has to be added to the upstream hash of new RP's
386 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
387 */
5d99ebea 388 if (!pim_addr_is_any(old_upstream_addr)) {
28309df0 389 /* Deregister addr with Zebra NHT */
5d99ebea 390 pim_addr_to_prefix(&nht_p, old_upstream_addr);
2dbe669b 391 if (PIM_DEBUG_PIM_TRACE)
15569c58 392 zlog_debug(
2dbe669b
DA
393 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
394 __func__, up->sg_str, &nht_p);
4efdb9c6 395 pim_delete_tracked_nexthop(pim, &nht_p, 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];
428 struct prefix nht_p;
89b68082 429 struct route_node *rn;
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
6ed1cea1 438 pim_addr_to_prefix(&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)) {
6ed1cea1
MR
464 if (prefix_same(&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
MR
500 if (tmp_rp_info->plist &&
501 prefix_same(&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(
2dbe669b
DA
521 "%s: NHT Register rp_all addr %pFX grp %pFX ",
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);
43763b11 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,
552 &nht_p, &rp_all->group, 1))
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 */
d0e418b4 560 tmp_rp_info = pim_rp_find_exact(
561 pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group);
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
672int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
673 struct prefix group, const char *plist,
674 enum rp_source rp_src_flag)
675{
676 struct prefix g_all;
677 struct rp_info *rp_info;
678 struct rp_info *rp_all;
679 struct prefix nht_p;
680 struct route_node *rn;
681 bool was_plist = false;
682 struct rp_info *trp_info;
683 struct pim_upstream *up;
d0e418b4 684 struct bsgrp_node *bsgrp = NULL;
685 struct bsm_rpinfo *bsrp = NULL;
d0e418b4 686 char rp_str[INET_ADDRSTRLEN];
62596d9a 687 bool upstream_updated = false;
d0e418b4 688
689 if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)))
772270f3 690 snprintf(rp_str, sizeof(rp_str), "<rp?>");
d0e418b4 691
d62a17ae 692 if (plist)
d9c9a9ee 693 rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
d62a17ae 694 else
d9c9a9ee 695 rp_info = pim_rp_find_exact(pim, rp_addr, &group);
d62a17ae 696
697 if (!rp_info)
698 return PIM_RP_NOT_FOUND;
699
700 if (rp_info->plist) {
701 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
89b68082 702 was_plist = true;
d62a17ae 703 }
704
23fc858a 705 if (PIM_DEBUG_PIM_TRACE)
2dbe669b
DA
706 zlog_debug("%s: Delete RP %s for the group %pFX", __func__,
707 rp_str, &group);
d0e418b4 708
709 /* While static RP is getting deleted, we need to check if dynamic RP
710 * present for the same group in BSM RP table, then install the dynamic
711 * RP for the group node into the main rp table
712 */
713 if (rp_src_flag == RP_SRC_STATIC) {
714 bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
715
716 if (bsgrp) {
fdab2940 717 bsrp = bsm_rpinfos_first(bsgrp->bsrp_list);
d0e418b4 718 if (bsrp) {
23fc858a 719 if (PIM_DEBUG_PIM_TRACE) {
d0e418b4 720 char bsrp_str[INET_ADDRSTRLEN];
721
722 if (!inet_ntop(AF_INET, bsrp, bsrp_str,
723 sizeof(bsrp_str)))
772270f3
QY
724 snprintf(bsrp_str,
725 sizeof(bsrp_str),
726 "<bsrp?>");
d0e418b4 727
15569c58 728 zlog_debug(
2dbe669b
DA
729 "%s: BSM RP %s found for the group %pFX",
730 __func__, bsrp_str, &group);
d0e418b4 731 }
732 return pim_rp_change(pim, bsrp->rp_address,
733 group, RP_SRC_BSR);
734 }
735 } else {
23fc858a 736 if (PIM_DEBUG_PIM_TRACE)
d0e418b4 737 zlog_debug(
2dbe669b
DA
738 "%s: BSM RP not found for the group %pFX",
739 __func__, &group);
d0e418b4 740 }
741 }
742
d62a17ae 743 /* Deregister addr with Zebra NHT */
744 nht_p.family = AF_INET;
745 nht_p.prefixlen = IPV4_MAX_BITLEN;
746 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
2dbe669b
DA
747 if (PIM_DEBUG_PIM_NHT_RP)
748 zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__,
749 &nht_p);
4efdb9c6 750 pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
d62a17ae 751
c6ced474 752 if (!pim_get_all_mcast_group(&g_all))
e691f179
DS
753 return PIM_RP_BAD_ADDRESS;
754
d9c9a9ee 755 rp_all = pim_rp_find_match_group(pim, &g_all);
d62a17ae 756
757 if (rp_all == rp_info) {
dd3364cb 758 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
8cfd7268
SP
759 /* Find the upstream (*, G) whose upstream address is
760 * same as the deleted RP
761 */
01adb431
DL
762 pim_addr rpf_addr;
763
764 rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
765 if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
2a27f13b 766 pim_addr_is_any(up->sg.src)) {
8cfd7268 767 struct prefix grp;
5d99ebea
DL
768
769 pim_addr_to_prefix(&grp, up->sg.grp);
8cfd7268
SP
770 trp_info = pim_rp_find_match_group(pim, &grp);
771 if (trp_info == rp_all) {
772 pim_upstream_rpf_clear(pim, up);
01adb431 773 up->upstream_addr = PIMADDR_ANY;
8cfd7268
SP
774 }
775 }
776 }
cc144e8b 777 pim_addr_to_prefix(&rp_all->rp.rpf_addr, PIMADDR_ANY);
d62a17ae 778 rp_all->i_am_rp = 0;
779 return PIM_SUCCESS;
780 }
781
d9c9a9ee 782 listnode_delete(pim->rp_list, rp_info);
89b68082
DS
783
784 if (!was_plist) {
785 rn = route_node_get(pim->rp_table, &rp_info->group);
786 if (rn) {
787 if (rn->info != rp_info)
af4c2728 788 flog_err(
450971aa 789 EC_LIB_DEVELOPMENT,
3613d898 790 "Expected rn->info to be equal to rp_info");
89b68082 791
2dbe669b 792 if (PIM_DEBUG_PIM_TRACE)
996c9314 793 zlog_debug(
2dbe669b
DA
794 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
795 __func__, rn, rp_info, &rp_info->group,
c10e14e9 796 route_node_get_lock_count(rn));
2dbe669b 797
89b68082
DS
798 rn->info = NULL;
799 route_unlock_node(rn);
800 route_unlock_node(rn);
801 }
802 }
803
472ad383 804 pim_rp_refresh_group_to_rp_mapping(pim);
093c928f 805
dd3364cb 806 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
8cfd7268
SP
807 /* Find the upstream (*, G) whose upstream address is same as
808 * the deleted RP
809 */
01adb431
DL
810 pim_addr rpf_addr;
811
812 rpf_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
813 if (!pim_addr_cmp(up->upstream_addr, rpf_addr) &&
2a27f13b 814 pim_addr_is_any(up->sg.src)) {
8cfd7268
SP
815 struct prefix grp;
816
5d99ebea 817 pim_addr_to_prefix(&grp, up->sg.grp);
8cfd7268
SP
818 trp_info = pim_rp_find_match_group(pim, &grp);
819
820 /* RP not found for the group grp */
cc144e8b 821 if (pim_rpf_addr_is_inaddr_any(&trp_info->rp)) {
8cfd7268 822 pim_upstream_rpf_clear(pim, up);
d0e418b4 823 pim_rp_set_upstream_addr(
824 pim, &up->upstream_addr, up->sg.src,
825 up->sg.grp);
8cfd7268
SP
826 }
827
828 /* RP found for the group grp */
62596d9a 829 else {
8cfd7268 830 pim_upstream_update(pim, up);
62596d9a
MR
831 upstream_updated = true;
832 }
8cfd7268
SP
833 }
834 }
835
62596d9a
MR
836 if (upstream_updated)
837 pim_zebra_update_all_interfaces(pim);
838
093c928f 839 XFREE(MTYPE_PIM_RP, rp_info);
d62a17ae 840 return PIM_SUCCESS;
75a26779 841}
13afbd05 842
49b7b2c4 843int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr,
d0e418b4 844 struct prefix group, enum rp_source rp_src_flag)
845{
846 struct prefix nht_p;
847 struct route_node *rn;
848 int result = 0;
849 struct rp_info *rp_info = NULL;
850 struct pim_upstream *up;
62596d9a 851 bool upstream_updated = false;
49b7b2c4 852 pim_addr old_rp_addr;
d0e418b4 853
854 rn = route_node_lookup(pim->rp_table, &group);
855 if (!rn) {
856 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
857 return result;
858 }
859
860 rp_info = rn->info;
861
862 if (!rp_info) {
863 route_unlock_node(rn);
864 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
865 return result;
866 }
867
49b7b2c4
MR
868 old_rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
869 if (!pim_addr_cmp(new_rp_addr, old_rp_addr)) {
d0e418b4 870 if (rp_info->rp_src != rp_src_flag) {
871 rp_info->rp_src = rp_src_flag;
872 route_unlock_node(rn);
873 return PIM_SUCCESS;
874 }
875 }
876
49b7b2c4
MR
877 nht_p.family = PIM_AF;
878 nht_p.prefixlen = PIM_MAX_BITLEN;
35a30302 879
d0e418b4 880 /* Deregister old RP addr with Zebra NHT */
49b7b2c4
MR
881
882 if (!pim_addr_is_any(old_rp_addr)) {
883 nht_p = rp_info->rp.rpf_addr;
2dbe669b
DA
884 if (PIM_DEBUG_PIM_NHT_RP)
885 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
886 __func__, &nht_p);
4efdb9c6 887 pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
d0e418b4 888 }
889
890 pim_rp_nexthop_del(rp_info);
891 listnode_delete(pim->rp_list, rp_info);
892 /* Update the new RP address*/
49b7b2c4
MR
893
894 pim_addr_to_prefix(&rp_info->rp.rpf_addr, new_rp_addr);
d0e418b4 895 rp_info->rp_src = rp_src_flag;
896 rp_info->i_am_rp = 0;
897
898 listnode_add_sort(pim->rp_list, rp_info);
899
dd3364cb 900 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2a27f13b 901 if (pim_addr_is_any(up->sg.src)) {
d0e418b4 902 struct prefix grp;
903 struct rp_info *trp_info;
904
5d99ebea 905 pim_addr_to_prefix(&grp, up->sg.grp);
d0e418b4 906 trp_info = pim_rp_find_match_group(pim, &grp);
907
62596d9a 908 if (trp_info == rp_info) {
d0e418b4 909 pim_upstream_update(pim, up);
62596d9a
MR
910 upstream_updated = true;
911 }
d0e418b4 912 }
913 }
914
62596d9a
MR
915 if (upstream_updated)
916 pim_zebra_update_all_interfaces(pim);
917
d0e418b4 918 /* Register new RP addr with Zebra NHT */
49b7b2c4 919 nht_p = rp_info->rp.rpf_addr;
2dbe669b
DA
920 if (PIM_DEBUG_PIM_NHT_RP)
921 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
922 __func__, &nht_p, &rp_info->group);
d0e418b4 923
4efdb9c6 924 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
d0e418b4 925 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
926 &rp_info->group, 1)) {
927 route_unlock_node(rn);
928 return PIM_RP_NO_PATH;
929 }
930
931 pim_rp_check_interfaces(pim, rp_info);
932
933 route_unlock_node(rn);
934
935 pim_rp_refresh_group_to_rp_mapping(pim);
936
937 return result;
938}
939
fec883d9 940void pim_rp_setup(struct pim_instance *pim)
13afbd05 941{
d62a17ae 942 struct listnode *node;
943 struct rp_info *rp_info;
d62a17ae 944 struct prefix nht_p;
d62a17ae 945
d9c9a9ee 946 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 947 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 948 continue;
949
950 nht_p.family = AF_INET;
951 nht_p.prefixlen = IPV4_MAX_BITLEN;
952 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
8cfd7268 953
4efdb9c6 954 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
43763b11
DS
955 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
956 &nht_p, &rp_info->group, 1))
957 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 958 zlog_debug(
43763b11 959 "Unable to lookup nexthop for rp specified");
d62a17ae 960 }
13afbd05
DS
961}
962
54b97c74 963/*
7176984f 964 * Checks to see if we should elect ourself the actual RP when new if
965 * addresses are added against an interface.
54b97c74 966 */
d62a17ae 967void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
54b97c74 968{
d62a17ae 969 struct listnode *node;
970 struct rp_info *rp_info;
971 bool i_am_rp_changed = false;
d9c9a9ee 972 struct pim_instance *pim = pim_ifp->pim;
d62a17ae 973
d9c9a9ee 974 if (pim->rp_list == NULL)
d62a17ae 975 return;
976
d9c9a9ee 977 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 978 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 979 continue;
980
981 /* if i_am_rp is already set nothing to be done (adding new
982 * addresses
983 * is not going to make a difference). */
984 if (rp_info->i_am_rp) {
985 continue;
986 }
987
988 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
989 i_am_rp_changed = true;
990 rp_info->i_am_rp = 1;
3d225d48 991 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 992 char rp[PREFIX_STRLEN];
993 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
994 rp, sizeof(rp));
995 zlog_debug("%s: %s: i am rp", __func__, rp);
996 }
997 }
998 }
999
1000 if (i_am_rp_changed) {
472ad383 1001 pim_msdp_i_am_rp_changed(pim);
a749b900 1002 pim_upstream_reeval_use_rpt(pim);
d62a17ae 1003 }
7176984f 1004}
36d6bd7d 1005
7176984f 1006/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
1007 * are removed. Removing numbers is an uncommon event in an active network
1008 * so I have made no attempt to optimize it. */
fec883d9 1009void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
7176984f 1010{
d62a17ae 1011 struct listnode *node;
1012 struct rp_info *rp_info;
1013 bool i_am_rp_changed = false;
1014 int old_i_am_rp;
1015
d9c9a9ee 1016 if (pim->rp_list == NULL)
d62a17ae 1017 return;
1018
d9c9a9ee 1019 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1020 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1021 continue;
1022
1023 old_i_am_rp = rp_info->i_am_rp;
fec883d9 1024 pim_rp_check_interfaces(pim, rp_info);
d62a17ae 1025
1026 if (old_i_am_rp != rp_info->i_am_rp) {
1027 i_am_rp_changed = true;
3d225d48 1028 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 1029 char rp[PREFIX_STRLEN];
1030 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
1031 rp, sizeof(rp));
1032 if (rp_info->i_am_rp) {
1033 zlog_debug("%s: %s: i am rp", __func__,
1034 rp);
1035 } else {
1036 zlog_debug("%s: %s: i am no longer rp",
1037 __func__, rp);
1038 }
1039 }
1040 }
1041 }
1042
1043 if (i_am_rp_changed) {
472ad383 1044 pim_msdp_i_am_rp_changed(pim);
a749b900 1045 pim_upstream_reeval_use_rpt(pim);
d62a17ae 1046 }
54b97c74
DS
1047}
1048
1049/*
1050 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1051 * this router is the RP for the group.
1052 *
1053 * Since we only have static RP, all groups are part of this RP
1054 */
5d99ebea 1055int pim_rp_i_am_rp(struct pim_instance *pim, pim_addr group)
54b97c74 1056{
d62a17ae 1057 struct prefix g;
1058 struct rp_info *rp_info;
36d6bd7d 1059
d62a17ae 1060 memset(&g, 0, sizeof(g));
131ded08 1061 pim_addr_to_prefix(&g, group);
d9c9a9ee 1062 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 1063
d62a17ae 1064 if (rp_info)
1065 return rp_info->i_am_rp;
d62a17ae 1066 return 0;
54b97c74
DS
1067}
1068
71694057
DS
1069/*
1070 * RP(G)
1071 *
1072 * Return the RP that the Group belongs too.
1073 */
5d99ebea 1074struct pim_rpf *pim_rp_g(struct pim_instance *pim, pim_addr group)
71694057 1075{
d62a17ae 1076 struct prefix g;
1077 struct rp_info *rp_info;
1078
1079 memset(&g, 0, sizeof(g));
8eb5ad6c 1080 pim_addr_to_prefix(&g, group);
d62a17ae 1081
d9c9a9ee 1082 rp_info = pim_rp_find_match_group(pim, &g);
d62a17ae 1083
1084 if (rp_info) {
1085 struct prefix nht_p;
43763b11 1086
d62a17ae 1087 /* Register addr with Zebra NHT */
8eb5ad6c 1088 nht_p = rp_info->rp.rpf_addr;
2dbe669b 1089 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 1090 zlog_debug(
2dbe669b
DA
1091 "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
1092 __func__, &nht_p, &rp_info->group);
4efdb9c6 1093 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
43763b11
DS
1094 pim_rpf_set_refresh_time(pim);
1095 (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
1096 &nht_p, &rp_info->group, 1);
d62a17ae 1097 return (&rp_info->rp);
1098 }
1099
1100 // About to Go Down
1101 return NULL;
71694057
DS
1102}
1103
8f5f5e91
DS
1104/*
1105 * Set the upstream IP address we want to talk to based upon
1106 * the rp configured and the source address
1107 *
1108 * If we have don't have a RP configured and the source address is *
732c209c 1109 * then set the upstream addr as INADDR_ANY and return failure.
8f5f5e91
DS
1110 *
1111 */
5d99ebea
DL
1112int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up,
1113 pim_addr source, pim_addr group)
8f5f5e91 1114{
d62a17ae 1115 struct rp_info *rp_info;
1116 struct prefix g;
36d6bd7d 1117
d62a17ae 1118 memset(&g, 0, sizeof(g));
b1e132ac
MR
1119
1120 pim_addr_to_prefix(&g, group);
36d6bd7d 1121
d9c9a9ee 1122 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 1123
cc144e8b 1124 if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) &&
b1e132ac 1125 (pim_addr_is_any(source)))) {
3d225d48 1126 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 1127 zlog_debug("%s: Received a (*,G) with no RP configured",
15569c58 1128 __func__);
b1e132ac 1129 *up = PIMADDR_ANY;
d62a17ae 1130 return 0;
1131 }
8f5f5e91 1132
b1e132ac
MR
1133 if (pim_addr_is_any(source))
1134 *up = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
1135 else
1136 *up = source;
8f5f5e91 1137
d62a17ae 1138 return 1;
8f5f5e91 1139}
75a26779 1140
0c8b717e
DS
1141int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
1142 const char *spaces)
75a26779 1143{
d62a17ae 1144 struct listnode *node;
1145 struct rp_info *rp_info;
d62a17ae 1146 int count = 0;
0c3182a0 1147 pim_addr rp_addr;
d62a17ae 1148
d9c9a9ee 1149 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1150 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1151 continue;
1152
d0e418b4 1153 if (rp_info->rp_src == RP_SRC_BSR)
1154 continue;
1155
0c3182a0 1156 rp_addr = pim_addr_from_prefix(&rp_info->rp.rpf_addr);
d62a17ae 1157 if (rp_info->plist)
0c3182a0
MR
1158 vty_out(vty,
1159 "%s" PIM_AF_NAME
1160 " pim rp %pPA prefix-list %s\n",
1161 spaces, &rp_addr, rp_info->plist);
d62a17ae 1162 else
0c3182a0
MR
1163 vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n",
1164 spaces, &rp_addr, &rp_info->group);
d62a17ae 1165 count++;
1166 }
1167
1168 return count;
75a26779
DS
1169}
1170
088f1098 1171void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
00d07c6f 1172{
d62a17ae 1173 struct rp_info *rp_info;
1174 struct rp_info *prev_rp_info = NULL;
1175 struct listnode *node;
025725f7 1176 char source[7];
ee2bbf7c 1177 char buf[PREFIX_STRLEN];
d62a17ae 1178
1179 json_object *json = NULL;
1180 json_object *json_rp_rows = NULL;
1181 json_object *json_row = NULL;
1182
1183 if (uj)
1184 json = json_object_new_object();
1185 else
1186 vty_out(vty,
d6593fc5 1187 "RP address group/prefix-list OIF I am RP Source\n");
d9c9a9ee 1188 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1189 if (!pim_rpf_addr_is_inaddr_any(&rp_info->rp)) {
d62a17ae 1190 char buf[48];
1191
025725f7 1192 if (rp_info->rp_src == RP_SRC_STATIC)
96e43299 1193 strlcpy(source, "Static", sizeof(source));
025725f7 1194 else if (rp_info->rp_src == RP_SRC_BSR)
96e43299 1195 strlcpy(source, "BSR", sizeof(source));
025725f7 1196 else
96e43299 1197 strlcpy(source, "None", sizeof(source));
d62a17ae 1198 if (uj) {
1199 /*
1200 * If we have moved on to a new RP then add the
1201 * entry for the previous RP
1202 */
1203 if (prev_rp_info
1204 && prev_rp_info->rp.rpf_addr.u.prefix4
1205 .s_addr
1206 != rp_info->rp.rpf_addr.u.prefix4
1207 .s_addr) {
1208 json_object_object_add(
1209 json,
ee2bbf7c
MS
1210 inet_ntop(AF_INET,
1211 &prev_rp_info->rp
d62a17ae 1212 .rpf_addr.u
ee2bbf7c
MS
1213 .prefix4,
1214 buf, sizeof(buf)),
d62a17ae 1215 json_rp_rows);
1216 json_rp_rows = NULL;
1217 }
1218
1219 if (!json_rp_rows)
1220 json_rp_rows = json_object_new_array();
1221
1222 json_row = json_object_new_object();
b0d5264e
DA
1223 json_object_string_addf(
1224 json_row, "rpAddress", "%pI4",
1225 &rp_info->rp.rpf_addr.u.prefix4);
d62a17ae 1226 if (rp_info->rp.source_nexthop.interface)
1227 json_object_string_add(
1228 json_row, "outboundInterface",
1229 rp_info->rp.source_nexthop
1230 .interface->name);
a7a5472e
SP
1231 else
1232 json_object_string_add(
1233 json_row, "outboundInterface",
1234 "Unknown");
d62a17ae 1235 if (rp_info->i_am_rp)
1236 json_object_boolean_true_add(json_row,
1237 "iAmRP");
a7a5472e
SP
1238 else
1239 json_object_boolean_false_add(json_row,
1240 "iAmRP");
d62a17ae 1241
1242 if (rp_info->plist)
1243 json_object_string_add(json_row,
1244 "prefixList",
1245 rp_info->plist);
1246 else
9afa5231
DA
1247 json_object_string_addf(
1248 json_row, "group", "%pFX",
1249 &rp_info->group);
d0e418b4 1250 json_object_string_add(json_row, "source",
025725f7 1251 source);
d62a17ae 1252
1253 json_object_array_add(json_rp_rows, json_row);
1254 } else {
1255 vty_out(vty, "%-15s ",
ee2bbf7c
MS
1256 inet_ntop(AF_INET,
1257 &rp_info->rp.rpf_addr.u
1258 .prefix4,
1259 buf, sizeof(buf)));
d62a17ae 1260
1261 if (rp_info->plist)
1262 vty_out(vty, "%-18s ", rp_info->plist);
1263 else
2dbe669b
DA
1264 vty_out(vty, "%-18pFX ",
1265 &rp_info->group);
d62a17ae 1266
1267 if (rp_info->rp.source_nexthop.interface)
ff415346 1268 vty_out(vty, "%-16s ",
d62a17ae 1269 rp_info->rp.source_nexthop
1270 .interface->name);
1271 else
ff415346 1272 vty_out(vty, "%-16s ", "(Unknown)");
d62a17ae 1273
1274 if (rp_info->i_am_rp)
d6593fc5 1275 vty_out(vty, "yes");
d62a17ae 1276 else
025725f7 1277 vty_out(vty, "no");
d62a17ae 1278
025725f7 1279 vty_out(vty, "%14s\n", source);
1280 }
d62a17ae 1281 prev_rp_info = rp_info;
1282 }
1283 }
1284
1285 if (uj) {
1286 if (prev_rp_info && json_rp_rows)
1287 json_object_object_add(
1288 json,
ee2bbf7c
MS
1289 inet_ntop(AF_INET,
1290 &prev_rp_info->rp.rpf_addr.u.prefix4,
1291 buf, sizeof(buf)),
d62a17ae 1292 json_rp_rows);
1293
129f5638 1294 vty_json(vty, json);
d62a17ae 1295 }
00d07c6f 1296}
cba44481 1297
c9cd7fbc 1298void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
cba44481 1299{
d62a17ae 1300 struct listnode *node = NULL;
1301 struct rp_info *rp_info = NULL;
1302 struct nexthop *nh_node = NULL;
1303 struct prefix nht_p;
1304 struct pim_nexthop_cache pnc;
d62a17ae 1305
d9c9a9ee 1306 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
cc144e8b 1307 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
d62a17ae 1308 continue;
1309
1310 nht_p.family = AF_INET;
1311 nht_p.prefixlen = IPV4_MAX_BITLEN;
1312 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
1313 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9 1314 if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
4efdb9c6 1315 &pnc))
cb9c7c50
DS
1316 continue;
1317
1318 for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
3a6290bd 1319 if (nh_node->gate.ipv4.s_addr != INADDR_ANY)
cb9c7c50
DS
1320 continue;
1321
1322 struct interface *ifp1 = if_lookup_by_index(
d3cc1e45 1323 nh_node->ifindex, pim->vrf->vrf_id);
c9cd7fbc
DS
1324
1325 if (nbr->interface != ifp1)
cb9c7c50
DS
1326 continue;
1327
ae449dc5 1328#if PIM_IPV == 4
cb9c7c50 1329 nh_node->gate.ipv4 = nbr->source_addr;
9bb93fa0
DL
1330#else
1331 nh_node->gate.ipv6 = nbr->source_addr;
1332#endif
3d225d48 1333 if (PIM_DEBUG_PIM_NHT_RP) {
cb9c7c50 1334 char str[PREFIX_STRLEN];
cb9c7c50
DS
1335 pim_addr_dump("<nht_addr?>", &nht_p, str,
1336 sizeof(str));
1337 zlog_debug(
9bb93fa0
DL
1338 "%s: addr %s new nexthop addr %pPAs interface %s",
1339 __func__, str, &nbr->source_addr,
1340 ifp1->name);
d62a17ae 1341 }
1342 }
1343 }
cba44481 1344}