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