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