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