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