]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_rp.c
*: rename zlog_fer -> flog_err
[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
DS
41#include "pim_str.h"
42#include "pim_rpf.h"
13afbd05 43#include "pim_sock.h"
36d6bd7d 44#include "pim_memory.h"
00d07c6f 45#include "pim_iface.h"
7667c556 46#include "pim_msdp.h"
1bc98276 47#include "pim_nht.h"
8f5f5e91 48
36d6bd7d 49
c2cf4b02
DS
50/* Cleanup pim->rpf_hash each node data */
51void pim_rp_list_hash_clean(void *data)
52{
7c591950 53 struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data;
c2cf4b02 54
affe9e99 55 list_delete_and_null(&pnc->rp_list);
6e1ef388 56
7c591950
DS
57 hash_clean(pnc->upstream_hash, NULL);
58 hash_free(pnc->upstream_hash);
59 pnc->upstream_hash = NULL;
6e1ef388
DS
60
61 XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
c2cf4b02
DS
62}
63
d62a17ae 64static void pim_rp_info_free(struct rp_info *rp_info)
36d6bd7d 65{
ff823fc9
DS
66 if (rp_info->plist)
67 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
68
d62a17ae 69 XFREE(MTYPE_PIM_RP, rp_info);
36d6bd7d
DS
70}
71
d62a17ae 72int pim_rp_list_cmp(void *v1, void *v2)
36d6bd7d 73{
d62a17ae 74 struct rp_info *rp1 = (struct rp_info *)v1;
75 struct rp_info *rp2 = (struct rp_info *)v2;
76
77 /*
78 * Sort by RP IP address
79 */
80 if (rp1->rp.rpf_addr.u.prefix4.s_addr
81 < rp2->rp.rpf_addr.u.prefix4.s_addr)
82 return -1;
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 /*
89 * Sort by group IP address
90 */
91 if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
92 return -1;
93
94 if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
95 return 1;
96
97 return 0;
36d6bd7d
DS
98}
99
d9c9a9ee 100void pim_rp_init(struct pim_instance *pim)
36d6bd7d 101{
d62a17ae 102 struct rp_info *rp_info;
89b68082 103 struct route_node *rn;
36d6bd7d 104
d9c9a9ee
DS
105 pim->rp_list = list_new();
106 pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
107 pim->rp_list->cmp = pim_rp_list_cmp;
36d6bd7d 108
89b68082 109 pim->rp_table = route_table_init();
89b68082 110
d62a17ae 111 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
36d6bd7d 112
2e8345c1 113 if (!str2prefix("224.0.0.0/4", &rp_info->group)) {
af4c2728 114 flog_err(LIB_ERR_DEVELOPMENT,
d9ff4302 115 "Unable to convert 224.0.0.0/4 to prefix");
affe9e99 116 list_delete_and_null(&pim->rp_list);
89b68082 117 route_table_finish(pim->rp_table);
2e8345c1
DS
118 XFREE(MTYPE_PIM_RP, rp_info);
119 return;
120 }
d62a17ae 121 rp_info->group.family = AF_INET;
122 rp_info->rp.rpf_addr.family = AF_INET;
123 rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN;
124 rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
36d6bd7d 125
d9c9a9ee 126 listnode_add(pim->rp_list, rp_info);
89b68082
DS
127
128 rn = route_node_get(pim->rp_table, &rp_info->group);
89b68082
DS
129 rn->info = rp_info;
130 if (PIM_DEBUG_TRACE)
996c9314
LB
131 zlog_debug(
132 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
133 rn, rp_info, rn->lock);
36d6bd7d
DS
134}
135
d9c9a9ee 136void pim_rp_free(struct pim_instance *pim)
36d6bd7d 137{
d9c9a9ee 138 if (pim->rp_list)
affe9e99 139 list_delete_and_null(&pim->rp_list);
36d6bd7d
DS
140}
141
dfe43e25
DW
142/*
143 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
144 */
d9c9a9ee
DS
145static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim,
146 struct in_addr rp,
d62a17ae 147 const char *plist)
36d6bd7d 148{
d62a17ae 149 struct listnode *node;
150 struct rp_info *rp_info;
151
d9c9a9ee 152 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 153 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
154 && rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
155 return rp_info;
156 }
157 }
158
159 return NULL;
36d6bd7d
DS
160}
161
dfe43e25
DW
162/*
163 * Return true if plist is used by any rp_info
164 */
d9c9a9ee 165static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist)
dfe43e25 166{
d62a17ae 167 struct listnode *node;
168 struct rp_info *rp_info;
169
d9c9a9ee 170 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 171 if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
172 return 1;
173 }
174 }
175
176 return 0;
dfe43e25
DW
177}
178
179/*
d62a17ae 180 * Given an RP's address, return the RP's rp_info that is an exact match for
181 * 'group'
dfe43e25 182 */
d9c9a9ee
DS
183static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
184 struct in_addr rp,
123214ef 185 const struct prefix *group)
36d6bd7d 186{
d62a17ae 187 struct listnode *node;
188 struct rp_info *rp_info;
36d6bd7d 189
d9c9a9ee 190 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 191 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
192 && prefix_same(&rp_info->group, group))
193 return rp_info;
194 }
54b97c74 195
d62a17ae 196 return NULL;
36d6bd7d
DS
197}
198
dfe43e25
DW
199/*
200 * Given a group, return the rp_info for that group
201 */
d9c9a9ee 202static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
123214ef 203 const struct prefix *group)
36d6bd7d 204{
d62a17ae 205 struct listnode *node;
b77b1550 206 struct rp_info *best = NULL;
d62a17ae 207 struct rp_info *rp_info;
208 struct prefix_list *plist;
123214ef 209 const struct prefix *p, *bp;
89b68082 210 struct route_node *rn;
d62a17ae 211
4646b86a 212 bp = NULL;
d9c9a9ee 213 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 214 if (rp_info->plist) {
215 plist = prefix_list_lookup(AFI_IP, rp_info->plist);
216
996c9314
LB
217 if (prefix_list_apply_which_prefix(plist, &p, group)
218 == PREFIX_DENY)
b77b1550
DS
219 continue;
220
221 if (!best) {
222 best = rp_info;
223 bp = p;
224 continue;
225 }
226
4646b86a 227 if (bp && bp->prefixlen < p->prefixlen) {
b77b1550
DS
228 best = rp_info;
229 bp = p;
230 }
d62a17ae 231 }
232 }
233
89b68082
DS
234 rn = route_node_match(pim->rp_table, group);
235 if (!rn) {
af4c2728 236 flog_err(
3613d898 237 LIB_ERR_DEVELOPMENT,
996c9314
LB
238 "%s: BUG We should have found default group information\n",
239 __PRETTY_FUNCTION__);
89b68082
DS
240 return best;
241 }
242
243 rp_info = rn->info;
244 if (PIM_DEBUG_TRACE) {
245 char buf[PREFIX_STRLEN];
246
247 route_unlock_node(rn);
996c9314
LB
248 zlog_debug("Lookedup: %p for rp_info: %p(%s) Lock: %d", rn,
249 rp_info,
89b68082
DS
250 prefix2str(&rp_info->group, buf, sizeof(buf)),
251 rn->lock);
252 }
253
254 if (!best)
255 return rp_info;
256
257 if (rp_info->group.prefixlen < best->group.prefixlen)
258 best = rp_info;
259
b77b1550 260 return best;
36d6bd7d 261}
75a26779 262
dfe43e25
DW
263/*
264 * When the user makes "ip pim rp" configuration changes or if they change the
265 * prefix-list(s) used by these statements we must tickle the upstream state
266 * for each group to make them re-lookup who their RP should be.
267 *
268 * This is a placeholder function for now.
269 */
472ad383 270static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
dfe43e25 271{
472ad383 272 pim_msdp_i_am_rp_changed(pim);
dfe43e25
DW
273}
274
d9c9a9ee
DS
275void pim_rp_prefix_list_update(struct pim_instance *pim,
276 struct prefix_list *plist)
dfe43e25 277{
d62a17ae 278 struct listnode *node;
279 struct rp_info *rp_info;
280 int refresh_needed = 0;
281
d9c9a9ee 282 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 283 if (rp_info->plist
284 && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
285 refresh_needed = 1;
286 break;
287 }
288 }
289
290 if (refresh_needed)
472ad383 291 pim_rp_refresh_group_to_rp_mapping(pim);
dfe43e25
DW
292}
293
d62a17ae 294static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
295 struct pim_interface *pim_ifp)
7176984f 296{
d62a17ae 297 struct listnode *node;
298 struct pim_secondary_addr *sec_addr;
7176984f 299
d62a17ae 300 if (pim_ifp->primary_address.s_addr
301 == rp_info->rp.rpf_addr.u.prefix4.s_addr)
302 return 1;
7176984f 303
d62a17ae 304 if (!pim_ifp->sec_addr_list) {
305 return 0;
306 }
7176984f 307
d62a17ae 308 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
309 if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
310 return 1;
311 }
312 }
7176984f 313
d62a17ae 314 return 0;
7176984f 315}
316
fec883d9
DS
317static void pim_rp_check_interfaces(struct pim_instance *pim,
318 struct rp_info *rp_info)
00d07c6f 319{
d62a17ae 320 struct interface *ifp;
00d07c6f 321
d62a17ae 322 rp_info->i_am_rp = 0;
451fda4f 323 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 324 struct pim_interface *pim_ifp = ifp->info;
00d07c6f 325
d62a17ae 326 if (!pim_ifp)
327 continue;
00d07c6f 328
d62a17ae 329 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
330 rp_info->i_am_rp = 1;
331 }
332 }
00d07c6f
DS
333}
334
fec883d9
DS
335int pim_rp_new(struct pim_instance *pim, const char *rp,
336 const char *group_range, const char *plist)
75a26779 337{
d62a17ae 338 int result = 0;
339 struct rp_info *rp_info;
340 struct rp_info *rp_all;
341 struct prefix group_all;
342 struct listnode *node, *nnode;
343 struct rp_info *tmp_rp_info;
344 char buffer[BUFSIZ];
345 struct prefix nht_p;
346 struct pim_nexthop_cache pnc;
89b68082 347 struct route_node *rn;
d62a17ae 348
349 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
d62a17ae 350
351 if (group_range == NULL)
352 result = str2prefix("224.0.0.0/4", &rp_info->group);
353 else
354 result = str2prefix(group_range, &rp_info->group);
355
356 if (!result) {
357 XFREE(MTYPE_PIM_RP, rp_info);
358 return PIM_GROUP_BAD_ADDRESS;
359 }
360
361 rp_info->rp.rpf_addr.family = AF_INET;
362 rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN;
363 result = inet_pton(rp_info->rp.rpf_addr.family, rp,
364 &rp_info->rp.rpf_addr.u.prefix4);
365
366 if (result <= 0) {
367 XFREE(MTYPE_PIM_RP, rp_info);
368 return PIM_RP_BAD_ADDRESS;
369 }
370
371 if (plist) {
372 /*
373 * Return if the prefix-list is already configured for this RP
374 */
d9c9a9ee 375 if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4,
d62a17ae 376 plist)) {
377 XFREE(MTYPE_PIM_RP, rp_info);
378 return PIM_SUCCESS;
379 }
380
381 /*
382 * Barf if the prefix-list is already configured for an RP
383 */
d9c9a9ee 384 if (pim_rp_prefix_list_used(pim, plist)) {
d62a17ae 385 XFREE(MTYPE_PIM_RP, rp_info);
386 return PIM_RP_PFXLIST_IN_USE;
387 }
388
389 /*
390 * Free any existing rp_info entries for this RP
391 */
d9c9a9ee 392 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
d62a17ae 393 tmp_rp_info)) {
394 if (rp_info->rp.rpf_addr.u.prefix4.s_addr
395 == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) {
396 if (tmp_rp_info->plist)
fec883d9 397 pim_rp_del(pim, rp, NULL,
d62a17ae 398 tmp_rp_info->plist);
399 else
400 pim_rp_del(
fec883d9 401 pim, rp,
d62a17ae 402 prefix2str(&tmp_rp_info->group,
403 buffer, BUFSIZ),
404 NULL);
405 }
406 }
407
408 rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
409 } else {
89b68082 410
2e8345c1
DS
411 if (!str2prefix("224.0.0.0/4", &group_all)) {
412 XFREE(MTYPE_PIM_RP, rp_info);
413 return PIM_GROUP_BAD_ADDRESS;
414 }
d9c9a9ee 415 rp_all = pim_rp_find_match_group(pim, &group_all);
d62a17ae 416
417 /*
418 * Barf if group is a non-multicast subnet
419 */
420 if (!prefix_match(&rp_all->group, &rp_info->group)) {
421 XFREE(MTYPE_PIM_RP, rp_info);
422 return PIM_GROUP_BAD_ADDRESS;
423 }
424
425 /*
426 * Remove any prefix-list rp_info entries for this RP
427 */
d9c9a9ee 428 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
d62a17ae 429 tmp_rp_info)) {
430 if (tmp_rp_info->plist
431 && rp_info->rp.rpf_addr.u.prefix4.s_addr
432 == tmp_rp_info->rp.rpf_addr.u.prefix4
433 .s_addr) {
fec883d9 434 pim_rp_del(pim, rp, NULL, tmp_rp_info->plist);
d62a17ae 435 }
436 }
437
438 /*
439 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
440 */
441 if (prefix_same(&rp_all->group, &rp_info->group)
442 && pim_rpf_addr_is_inaddr_none(&rp_all->rp)) {
443 rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
444 XFREE(MTYPE_PIM_RP, rp_info);
445
446 /* Register addr with Zebra NHT */
447 nht_p.family = AF_INET;
448 nht_p.prefixlen = IPV4_MAX_BITLEN;
449 nht_p.u.prefix4 =
450 rp_all->rp.rpf_addr.u.prefix4; // RP address
3d225d48 451 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 452 char buf[PREFIX2STR_BUFFER];
453 char buf1[PREFIX2STR_BUFFER];
454 prefix2str(&nht_p, buf, sizeof(buf));
455 prefix2str(&rp_all->group, buf1, sizeof(buf1));
456 zlog_debug(
457 "%s: NHT Register rp_all addr %s grp %s ",
458 __PRETTY_FUNCTION__, buf, buf1);
459 }
460 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9
DS
461 if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
462 &pnc)) {
cb9c7c50 463 if (!pim_ecmp_nexthop_search(
fec883d9 464 pim, &pnc,
25b787a2
DS
465 &rp_all->rp.source_nexthop, &nht_p,
466 &rp_all->group, 1))
d62a17ae 467 return PIM_RP_NO_PATH;
468 } else {
53bc94b0 469 if (!pim_ecmp_nexthop_lookup(
d9c9a9ee 470 pim, &rp_all->rp.source_nexthop,
53bc94b0 471 &nht_p, &rp_all->group, 1))
d62a17ae 472 return PIM_RP_NO_PATH;
473 }
fec883d9 474 pim_rp_check_interfaces(pim, rp_all);
472ad383 475 pim_rp_refresh_group_to_rp_mapping(pim);
d62a17ae 476 return PIM_SUCCESS;
477 }
478
479 /*
480 * Return if the group is already configured for this RP
481 */
d9c9a9ee 482 if (pim_rp_find_exact(pim, rp_info->rp.rpf_addr.u.prefix4,
d62a17ae 483 &rp_info->group)) {
484 XFREE(MTYPE_PIM_RP, rp_info);
485 return PIM_SUCCESS;
486 }
487
488 /*
489 * Barf if this group is already covered by some other RP
490 */
d9c9a9ee 491 tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group);
d62a17ae 492
493 if (tmp_rp_info) {
494 if (tmp_rp_info->plist) {
495 XFREE(MTYPE_PIM_RP, rp_info);
496 return PIM_GROUP_PFXLIST_OVERLAP;
497 } else {
498 /*
499 * If the only RP that covers this group is an
500 * RP configured for
501 * 224.0.0.0/4 that is fine, ignore that one.
502 * For all others
503 * though we must return PIM_GROUP_OVERLAP
504 */
89b68082
DS
505 if (prefix_same(&rp_info->group,
506 &tmp_rp_info->group)) {
d62a17ae 507 XFREE(MTYPE_PIM_RP, rp_info);
508 return PIM_GROUP_OVERLAP;
509 }
510 }
511 }
512 }
513
d9c9a9ee 514 listnode_add_sort(pim->rp_list, rp_info);
89b68082 515 rn = route_node_get(pim->rp_table, &rp_info->group);
89b68082
DS
516 rn->info = rp_info;
517
518 if (PIM_DEBUG_TRACE) {
519 char buf[PREFIX_STRLEN];
520
996c9314
LB
521 zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn,
522 rp_info,
89b68082
DS
523 prefix2str(&rp_info->group, buf, sizeof(buf)),
524 rn->lock);
525 }
d62a17ae 526
527 /* Register addr with Zebra NHT */
528 nht_p.family = AF_INET;
529 nht_p.prefixlen = IPV4_MAX_BITLEN;
530 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
3d225d48 531 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 532 char buf[PREFIX2STR_BUFFER];
533 char buf1[PREFIX2STR_BUFFER];
534 prefix2str(&nht_p, buf, sizeof(buf));
535 prefix2str(&rp_info->group, buf1, sizeof(buf1));
536 zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
537 __PRETTY_FUNCTION__, buf, buf1);
538 }
539
540 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9
DS
541 if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) {
542 if (!pim_ecmp_nexthop_search(pim, &pnc,
25b787a2 543 &rp_info->rp.source_nexthop,
cb9c7c50 544 &nht_p, &rp_info->group, 1))
d62a17ae 545 return PIM_RP_NO_PATH;
546 } else {
53bc94b0
DS
547 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
548 &nht_p, &rp_info->group, 1))
d62a17ae 549 return PIM_RP_NO_PATH;
550 }
551
fec883d9 552 pim_rp_check_interfaces(pim, rp_info);
472ad383 553 pim_rp_refresh_group_to_rp_mapping(pim);
d62a17ae 554 return PIM_SUCCESS;
75a26779
DS
555}
556
fec883d9
DS
557int pim_rp_del(struct pim_instance *pim, const char *rp,
558 const char *group_range, const char *plist)
75a26779 559{
d62a17ae 560 struct prefix group;
561 struct in_addr rp_addr;
562 struct prefix g_all;
563 struct rp_info *rp_info;
564 struct rp_info *rp_all;
565 int result;
566 struct prefix nht_p;
89b68082
DS
567 struct route_node *rn;
568 bool was_plist = false;
d62a17ae 569
570 if (group_range == NULL)
571 result = str2prefix("224.0.0.0/4", &group);
572 else
573 result = str2prefix(group_range, &group);
574
575 if (!result)
576 return PIM_GROUP_BAD_ADDRESS;
577
578 result = inet_pton(AF_INET, rp, &rp_addr);
579 if (result <= 0)
580 return PIM_RP_BAD_ADDRESS;
581
582 if (plist)
d9c9a9ee 583 rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
d62a17ae 584 else
d9c9a9ee 585 rp_info = pim_rp_find_exact(pim, rp_addr, &group);
d62a17ae 586
587 if (!rp_info)
588 return PIM_RP_NOT_FOUND;
589
590 if (rp_info->plist) {
591 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
89b68082 592 was_plist = true;
d62a17ae 593 }
594
595 /* Deregister addr with Zebra NHT */
596 nht_p.family = AF_INET;
597 nht_p.prefixlen = IPV4_MAX_BITLEN;
598 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
3d225d48 599 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 600 char buf[PREFIX2STR_BUFFER];
601 prefix2str(&nht_p, buf, sizeof(buf));
602 zlog_debug("%s: Deregister RP addr %s with Zebra ",
603 __PRETTY_FUNCTION__, buf);
604 }
fec883d9 605 pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
d62a17ae 606
e691f179
DS
607 if (!str2prefix("224.0.0.0/4", &g_all))
608 return PIM_RP_BAD_ADDRESS;
609
d9c9a9ee 610 rp_all = pim_rp_find_match_group(pim, &g_all);
d62a17ae 611
612 if (rp_all == rp_info) {
613 rp_all->rp.rpf_addr.family = AF_INET;
614 rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
615 rp_all->i_am_rp = 0;
616 return PIM_SUCCESS;
617 }
618
d9c9a9ee 619 listnode_delete(pim->rp_list, rp_info);
89b68082
DS
620
621 if (!was_plist) {
622 rn = route_node_get(pim->rp_table, &rp_info->group);
623 if (rn) {
624 if (rn->info != rp_info)
af4c2728 625 flog_err(
3613d898
DS
626 LIB_ERR_DEVELOPMENT,
627 "Expected rn->info to be equal to rp_info");
89b68082
DS
628
629 if (PIM_DEBUG_TRACE) {
630 char buf[PREFIX_STRLEN];
631
996c9314
LB
632 zlog_debug(
633 "%s:Found for Freeing: %p for rp_info: %p(%s) Lock: %d",
634 __PRETTY_FUNCTION__, rn, rp_info,
635 prefix2str(&rp_info->group, buf,
636 sizeof(buf)),
637 rn->lock);
89b68082
DS
638 }
639 rn->info = NULL;
640 route_unlock_node(rn);
641 route_unlock_node(rn);
642 }
643 }
644
472ad383 645 pim_rp_refresh_group_to_rp_mapping(pim);
093c928f
DS
646
647 XFREE(MTYPE_PIM_RP, rp_info);
d62a17ae 648 return PIM_SUCCESS;
75a26779 649}
13afbd05 650
fec883d9 651void pim_rp_setup(struct pim_instance *pim)
13afbd05 652{
d62a17ae 653 struct listnode *node;
654 struct rp_info *rp_info;
d62a17ae 655 struct prefix nht_p;
656 struct pim_nexthop_cache pnc;
657
d9c9a9ee 658 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 659 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
660 continue;
661
662 nht_p.family = AF_INET;
663 nht_p.prefixlen = IPV4_MAX_BITLEN;
664 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
665 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9
DS
666 if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
667 pim_ecmp_nexthop_search(pim, &pnc,
cb9c7c50
DS
668 &rp_info->rp.source_nexthop,
669 &nht_p, &rp_info->group, 1);
670 else {
3d225d48 671 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 672 char buf[PREFIX2STR_BUFFER];
673 prefix2str(&nht_p, buf, sizeof(buf));
674 zlog_debug(
675 "%s: NHT Local Nexthop not found for RP %s ",
676 __PRETTY_FUNCTION__, buf);
677 }
ff5d90c2
DS
678 if (!pim_ecmp_nexthop_lookup(pim,
679 &rp_info->rp.source_nexthop,
680 &nht_p, &rp_info->group, 1))
3d225d48 681 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 682 zlog_debug(
683 "Unable to lookup nexthop for rp specified");
d62a17ae 684 }
685 }
13afbd05
DS
686}
687
54b97c74 688/*
7176984f 689 * Checks to see if we should elect ourself the actual RP when new if
690 * addresses are added against an interface.
54b97c74 691 */
d62a17ae 692void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
54b97c74 693{
d62a17ae 694 struct listnode *node;
695 struct rp_info *rp_info;
696 bool i_am_rp_changed = false;
d9c9a9ee 697 struct pim_instance *pim = pim_ifp->pim;
d62a17ae 698
d9c9a9ee 699 if (pim->rp_list == NULL)
d62a17ae 700 return;
701
d9c9a9ee 702 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 703 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
704 continue;
705
706 /* if i_am_rp is already set nothing to be done (adding new
707 * addresses
708 * is not going to make a difference). */
709 if (rp_info->i_am_rp) {
710 continue;
711 }
712
713 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
714 i_am_rp_changed = true;
715 rp_info->i_am_rp = 1;
3d225d48 716 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 717 char rp[PREFIX_STRLEN];
718 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
719 rp, sizeof(rp));
720 zlog_debug("%s: %s: i am rp", __func__, rp);
721 }
722 }
723 }
724
725 if (i_am_rp_changed) {
472ad383 726 pim_msdp_i_am_rp_changed(pim);
d62a17ae 727 }
7176984f 728}
36d6bd7d 729
7176984f 730/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
731 * are removed. Removing numbers is an uncommon event in an active network
732 * so I have made no attempt to optimize it. */
fec883d9 733void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
7176984f 734{
d62a17ae 735 struct listnode *node;
736 struct rp_info *rp_info;
737 bool i_am_rp_changed = false;
738 int old_i_am_rp;
739
d9c9a9ee 740 if (pim->rp_list == NULL)
d62a17ae 741 return;
742
d9c9a9ee 743 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 744 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
745 continue;
746
747 old_i_am_rp = rp_info->i_am_rp;
fec883d9 748 pim_rp_check_interfaces(pim, rp_info);
d62a17ae 749
750 if (old_i_am_rp != rp_info->i_am_rp) {
751 i_am_rp_changed = true;
3d225d48 752 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 753 char rp[PREFIX_STRLEN];
754 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
755 rp, sizeof(rp));
756 if (rp_info->i_am_rp) {
757 zlog_debug("%s: %s: i am rp", __func__,
758 rp);
759 } else {
760 zlog_debug("%s: %s: i am no longer rp",
761 __func__, rp);
762 }
763 }
764 }
765 }
766
767 if (i_am_rp_changed) {
472ad383 768 pim_msdp_i_am_rp_changed(pim);
d62a17ae 769 }
54b97c74
DS
770}
771
772/*
773 * I_am_RP(G) is true if the group-to-RP mapping indicates that
774 * this router is the RP for the group.
775 *
776 * Since we only have static RP, all groups are part of this RP
777 */
d9c9a9ee 778int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group)
54b97c74 779{
d62a17ae 780 struct prefix g;
781 struct rp_info *rp_info;
36d6bd7d 782
d62a17ae 783 memset(&g, 0, sizeof(g));
784 g.family = AF_INET;
785 g.prefixlen = 32;
786 g.u.prefix4 = group;
36d6bd7d 787
d9c9a9ee 788 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 789
d62a17ae 790 if (rp_info)
791 return rp_info->i_am_rp;
36d6bd7d 792
d62a17ae 793 return 0;
54b97c74
DS
794}
795
71694057
DS
796/*
797 * RP(G)
798 *
799 * Return the RP that the Group belongs too.
800 */
fec883d9 801struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
71694057 802{
d62a17ae 803 struct prefix g;
804 struct rp_info *rp_info;
805
806 memset(&g, 0, sizeof(g));
807 g.family = AF_INET;
808 g.prefixlen = 32;
809 g.u.prefix4 = group;
810
d9c9a9ee 811 rp_info = pim_rp_find_match_group(pim, &g);
d62a17ae 812
813 if (rp_info) {
814 struct prefix nht_p;
815 struct pim_nexthop_cache pnc;
816 /* Register addr with Zebra NHT */
817 nht_p.family = AF_INET;
818 nht_p.prefixlen = IPV4_MAX_BITLEN;
819 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
3d225d48 820 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 821 char buf[PREFIX2STR_BUFFER];
822 char buf1[PREFIX2STR_BUFFER];
823 prefix2str(&nht_p, buf, sizeof(buf));
824 prefix2str(&rp_info->group, buf1, sizeof(buf1));
825 zlog_debug(
826 "%s: NHT Register RP addr %s grp %s with Zebra",
827 __PRETTY_FUNCTION__, buf, buf1);
828 }
829 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9
DS
830 if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
831 pim_ecmp_nexthop_search(pim, &pnc,
d62a17ae 832 &rp_info->rp.source_nexthop,
833 &nht_p, &rp_info->group, 1);
cb9c7c50 834 else {
3d225d48 835 if (PIM_DEBUG_PIM_NHT_RP) {
d62a17ae 836 char buf[PREFIX2STR_BUFFER];
837 char buf1[PREFIX2STR_BUFFER];
838 prefix2str(&nht_p, buf, sizeof(buf));
839 prefix2str(&g, buf1, sizeof(buf1));
840 zlog_debug(
841 "%s: Nexthop cache not found for RP %s grp %s register with Zebra",
842 __PRETTY_FUNCTION__, buf, buf1);
843 }
bfc92019 844 pim_rpf_set_refresh_time(pim);
56cb79b6
A
845 (void)pim_ecmp_nexthop_lookup(
846 pim, &rp_info->rp.source_nexthop, &nht_p,
847 &rp_info->group, 1);
d62a17ae 848 }
849 return (&rp_info->rp);
850 }
851
852 // About to Go Down
853 return NULL;
71694057
DS
854}
855
8f5f5e91
DS
856/*
857 * Set the upstream IP address we want to talk to based upon
858 * the rp configured and the source address
859 *
860 * If we have don't have a RP configured and the source address is *
861 * then return failure.
862 *
863 */
d9c9a9ee
DS
864int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
865 struct in_addr source, struct in_addr group)
8f5f5e91 866{
d62a17ae 867 struct rp_info *rp_info;
868 struct prefix g;
36d6bd7d 869
d62a17ae 870 memset(&g, 0, sizeof(g));
871 g.family = AF_INET;
872 g.prefixlen = 32;
873 g.u.prefix4 = group;
36d6bd7d 874
d9c9a9ee 875 rp_info = pim_rp_find_match_group(pim, &g);
36d6bd7d 876
d62a17ae 877 if ((pim_rpf_addr_is_inaddr_none(&rp_info->rp))
878 && (source.s_addr == INADDR_ANY)) {
3d225d48 879 if (PIM_DEBUG_PIM_NHT_RP)
d62a17ae 880 zlog_debug("%s: Received a (*,G) with no RP configured",
881 __PRETTY_FUNCTION__);
882 return 0;
883 }
8f5f5e91 884
d62a17ae 885 *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4
886 : source;
8f5f5e91 887
d62a17ae 888 return 1;
8f5f5e91 889}
75a26779 890
0c8b717e
DS
891int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
892 const char *spaces)
75a26779 893{
d62a17ae 894 struct listnode *node;
895 struct rp_info *rp_info;
896 char rp_buffer[32];
897 char group_buffer[32];
898 int count = 0;
899
d9c9a9ee 900 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 901 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
902 continue;
903
904 if (rp_info->plist)
0c8b717e 905 vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces,
d62a17ae 906 inet_ntop(AF_INET,
907 &rp_info->rp.rpf_addr.u.prefix4,
908 rp_buffer, 32),
909 rp_info->plist);
910 else
0c8b717e 911 vty_out(vty, "%sip pim rp %s %s\n", spaces,
d62a17ae 912 inet_ntop(AF_INET,
913 &rp_info->rp.rpf_addr.u.prefix4,
914 rp_buffer, 32),
915 prefix2str(&rp_info->group, group_buffer, 32));
916 count++;
917 }
918
919 return count;
75a26779
DS
920}
921
fec883d9
DS
922int pim_rp_check_is_my_ip_address(struct pim_instance *pim,
923 struct in_addr group,
d62a17ae 924 struct in_addr dest_addr)
75a26779 925{
d62a17ae 926 struct rp_info *rp_info;
927 struct prefix g;
928
929 memset(&g, 0, sizeof(g));
930 g.family = AF_INET;
931 g.prefixlen = 32;
932 g.u.prefix4 = group;
933
d9c9a9ee 934 rp_info = pim_rp_find_match_group(pim, &g);
d62a17ae 935 /*
936 * See if we can short-cut some?
937 * This might not make sense if we ever leave a static RP
938 * type of configuration.
939 * Note - Premature optimization might bite our patooeys' here.
940 */
d9c9a9ee 941 if (I_am_RP(pim, group)) {
d62a17ae 942 if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
943 return 1;
944 }
945
fec883d9 946 if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id))
d62a17ae 947 return 1;
948
949 return 0;
75a26779 950}
00d07c6f 951
64c86530 952void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
d7c0a89a 953 uint8_t uj)
00d07c6f 954{
d62a17ae 955 struct rp_info *rp_info;
956 struct rp_info *prev_rp_info = NULL;
957 struct listnode *node;
958
959 json_object *json = NULL;
960 json_object *json_rp_rows = NULL;
961 json_object *json_row = NULL;
962
963 if (uj)
964 json = json_object_new_object();
965 else
966 vty_out(vty,
967 "RP address group/prefix-list OIF I am RP\n");
968
d9c9a9ee 969 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 970 if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) {
971 char buf[48];
972
973 if (uj) {
974 /*
975 * If we have moved on to a new RP then add the
976 * entry for the previous RP
977 */
978 if (prev_rp_info
979 && prev_rp_info->rp.rpf_addr.u.prefix4
980 .s_addr
981 != rp_info->rp.rpf_addr.u.prefix4
982 .s_addr) {
983 json_object_object_add(
984 json,
985 inet_ntoa(prev_rp_info->rp
986 .rpf_addr.u
987 .prefix4),
988 json_rp_rows);
989 json_rp_rows = NULL;
990 }
991
992 if (!json_rp_rows)
993 json_rp_rows = json_object_new_array();
994
995 json_row = json_object_new_object();
996 if (rp_info->rp.source_nexthop.interface)
997 json_object_string_add(
998 json_row, "outboundInterface",
999 rp_info->rp.source_nexthop
1000 .interface->name);
1001
1002 if (rp_info->i_am_rp)
1003 json_object_boolean_true_add(json_row,
1004 "iAmRP");
1005
1006 if (rp_info->plist)
1007 json_object_string_add(json_row,
1008 "prefixList",
1009 rp_info->plist);
1010 else
1011 json_object_string_add(
1012 json_row, "group",
1013 prefix2str(&rp_info->group, buf,
1014 48));
1015
1016 json_object_array_add(json_rp_rows, json_row);
1017 } else {
1018 vty_out(vty, "%-15s ",
1019 inet_ntoa(rp_info->rp.rpf_addr.u
1020 .prefix4));
1021
1022 if (rp_info->plist)
1023 vty_out(vty, "%-18s ", rp_info->plist);
1024 else
1025 vty_out(vty, "%-18s ",
1026 prefix2str(&rp_info->group, buf,
1027 48));
1028
1029 if (rp_info->rp.source_nexthop.interface)
1030 vty_out(vty, "%-10s ",
1031 rp_info->rp.source_nexthop
1032 .interface->name);
1033 else
1034 vty_out(vty, "%-10s ", "(Unknown)");
1035
1036 if (rp_info->i_am_rp)
1037 vty_out(vty, "yes\n");
1038 else
1039 vty_out(vty, "no\n");
1040 }
1041
1042 prev_rp_info = rp_info;
1043 }
1044 }
1045
1046 if (uj) {
1047 if (prev_rp_info && json_rp_rows)
1048 json_object_object_add(
1049 json,
1050 inet_ntoa(prev_rp_info->rp.rpf_addr.u.prefix4),
1051 json_rp_rows);
1052
9d303b37
DL
1053 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1054 json, JSON_C_TO_STRING_PRETTY));
d62a17ae 1055 json_object_free(json);
1056 }
00d07c6f 1057}
cba44481 1058
fec883d9 1059void pim_resolve_rp_nh(struct pim_instance *pim)
cba44481 1060{
d62a17ae 1061 struct listnode *node = NULL;
1062 struct rp_info *rp_info = NULL;
1063 struct nexthop *nh_node = NULL;
1064 struct prefix nht_p;
1065 struct pim_nexthop_cache pnc;
1066 struct pim_neighbor *nbr = NULL;
1067
d9c9a9ee 1068 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
d62a17ae 1069 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
1070 continue;
1071
1072 nht_p.family = AF_INET;
1073 nht_p.prefixlen = IPV4_MAX_BITLEN;
1074 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
1075 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
fec883d9 1076 if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
25bdac42 1077 &pnc))
cb9c7c50
DS
1078 continue;
1079
1080 for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
1081 if (nh_node->gate.ipv4.s_addr != 0)
1082 continue;
1083
1084 struct interface *ifp1 = if_lookup_by_index(
fec883d9 1085 nh_node->ifindex, pim->vrf_id);
cb9c7c50
DS
1086 nbr = pim_neighbor_find_if(ifp1);
1087 if (!nbr)
1088 continue;
1089
1090 nh_node->gate.ipv4 = nbr->source_addr;
3d225d48 1091 if (PIM_DEBUG_PIM_NHT_RP) {
cb9c7c50
DS
1092 char str[PREFIX_STRLEN];
1093 char str1[INET_ADDRSTRLEN];
1094 pim_inet4_dump("<nht_nbr?>", nbr->source_addr,
1095 str1, sizeof(str1));
1096 pim_addr_dump("<nht_addr?>", &nht_p, str,
1097 sizeof(str));
1098 zlog_debug(
1099 "%s: addr %s new nexthop addr %s interface %s",
1100 __PRETTY_FUNCTION__, str, str1,
1101 ifp1->name);
d62a17ae 1102 }
1103 }
1104 }
cba44481 1105}