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