]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_rp.c
Merge pull request #336 from dwalton76/bgpd-allowas-in-removal
[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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21#include <zebra.h>
22
9bf3c633 23#include "lib/json.h"
54b97c74 24#include "log.h"
8f5f5e91 25#include "network.h"
744d91b3 26#include "if.h"
36d6bd7d
DS
27#include "linklist.h"
28#include "prefix.h"
29#include "memory.h"
00d07c6f
DS
30#include "vty.h"
31#include "vrf.h"
dfe43e25 32#include "plist.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
DS
47
48static struct list *qpim_rp_list = NULL;
49static struct rp_info *tail = NULL;
50
51static void
52pim_rp_info_free (struct rp_info *rp_info)
53{
54 XFREE (MTYPE_PIM_RP, rp_info);
55}
56
ff3745c2 57int
36d6bd7d
DS
58pim_rp_list_cmp (void *v1, void *v2)
59{
60 struct rp_info *rp1 = (struct rp_info *)v1;
61 struct rp_info *rp2 = (struct rp_info *)v2;
62
dfe43e25
DW
63 /*
64 * Sort by RP IP address
65 */
66 if (rp1->rp.rpf_addr.u.prefix4.s_addr < rp2->rp.rpf_addr.u.prefix4.s_addr)
67 return -1;
68
69 if (rp1->rp.rpf_addr.u.prefix4.s_addr > rp2->rp.rpf_addr.u.prefix4.s_addr)
70 return 1;
71
72 /*
73 * Sort by group IP address
74 */
75 if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
76 return -1;
77
78 if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
79 return 1;
80
ff3745c2 81 return 0;
36d6bd7d
DS
82}
83
84void
85pim_rp_init (void)
86{
87 struct rp_info *rp_info;
88
89 qpim_rp_list = list_new ();
90 qpim_rp_list->del = (void (*)(void *))pim_rp_info_free;
91 qpim_rp_list->cmp = pim_rp_list_cmp;
92
93 rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
94
95 if (!rp_info)
96 return;
97
98 str2prefix ("224.0.0.0/4", &rp_info->group);
fa8da98c 99 rp_info->group.family = AF_INET;
63c59d0c
DS
100 rp_info->rp.rpf_addr.family = AF_INET;
101 rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
36d6bd7d
DS
102 tail = rp_info;
103
104 listnode_add (qpim_rp_list, rp_info);
105}
106
107void
108pim_rp_free (void)
109{
110 if (qpim_rp_list)
0b6817c5
DS
111 list_delete (qpim_rp_list);
112 qpim_rp_list = NULL;
36d6bd7d
DS
113}
114
dfe43e25
DW
115/*
116 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
117 */
36d6bd7d 118static struct rp_info *
dfe43e25 119pim_rp_find_prefix_list (struct in_addr rp, const char *plist)
36d6bd7d
DS
120{
121 struct listnode *node;
122 struct rp_info *rp_info;
123
124 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
125 {
63c59d0c 126 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr &&
dfe43e25
DW
127 rp_info->plist && strcmp(rp_info->plist, plist) == 0)
128 {
129 return rp_info;
130 }
36d6bd7d
DS
131 }
132
133 return NULL;
134}
135
dfe43e25
DW
136/*
137 * Return true if plist is used by any rp_info
138 */
139static int
140pim_rp_prefix_list_used (const char *plist)
141{
142 struct listnode *node;
143 struct rp_info *rp_info;
144
145 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
146 {
147 if (rp_info->plist && strcmp(rp_info->plist, plist) == 0)
148 {
149 return 1;
150 }
151 }
152
153 return 0;
154}
155
156/*
157 * Given an RP's address, return the RP's rp_info that is an exact match for 'group'
158 */
36d6bd7d 159static struct rp_info *
dfe43e25 160pim_rp_find_exact (struct in_addr rp, struct prefix *group)
36d6bd7d
DS
161{
162 struct listnode *node;
163 struct rp_info *rp_info;
164
165 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
166 {
63c59d0c 167 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr &&
dfe43e25 168 prefix_same (&rp_info->group, group))
36d6bd7d
DS
169 return rp_info;
170 }
54b97c74 171
36d6bd7d
DS
172 return NULL;
173}
174
dfe43e25
DW
175/*
176 * Given a group, return the rp_info for that group
177 */
36d6bd7d
DS
178static struct rp_info *
179pim_rp_find_match_group (struct prefix *group)
180{
181 struct listnode *node;
182 struct rp_info *rp_info;
dfe43e25 183 struct prefix_list *plist;
36d6bd7d
DS
184
185 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
186 {
dfe43e25
DW
187 if (rp_info->plist)
188 {
189 plist = prefix_list_lookup (AFI_IP, rp_info->plist);
190
191 if (plist && prefix_list_apply (plist, group) == PREFIX_PERMIT)
192 return rp_info;
193 }
194 else
195 {
196 if (prefix_match (&rp_info->group, group))
197 return rp_info;
198 }
36d6bd7d
DS
199 }
200
201 return NULL;
202}
75a26779 203
dfe43e25
DW
204/*
205 * When the user makes "ip pim rp" configuration changes or if they change the
206 * prefix-list(s) used by these statements we must tickle the upstream state
207 * for each group to make them re-lookup who their RP should be.
208 *
209 * This is a placeholder function for now.
210 */
211static void
212pim_rp_refresh_group_to_rp_mapping()
213{
7667c556 214 pim_msdp_i_am_rp_changed();
dfe43e25
DW
215}
216
217void
218pim_rp_prefix_list_update (struct prefix_list *plist)
219{
220 struct listnode *node;
221 struct rp_info *rp_info;
222 int refresh_needed = 0;
223
224 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
225 {
226 if (rp_info->plist && strcmp(rp_info->plist, prefix_list_name (plist)) == 0)
227 {
228 refresh_needed = 1;
229 break;
230 }
231 }
232
233 if (refresh_needed)
234 pim_rp_refresh_group_to_rp_mapping();
235}
236
7176984f 237static int
238pim_rp_check_interface_addrs(struct rp_info *rp_info,
239 struct pim_interface *pim_ifp)
240{
241 struct listnode *node;
242 struct pim_secondary_addr *sec_addr;
243
244 if (pim_ifp->primary_address.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
245 return 1;
246
247 if (!pim_ifp->sec_addr_list) {
248 return 0;
249 }
250
251 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
252 if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) {
253 return 1;
254 }
255 }
256
257 return 0;
258}
259
00d07c6f
DS
260static void
261pim_rp_check_interfaces (struct rp_info *rp_info)
262{
263 struct listnode *node;
264 struct interface *ifp;
265
7176984f 266 rp_info->i_am_rp = 0;
00d07c6f
DS
267 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
268 {
269 struct pim_interface *pim_ifp = ifp->info;
270
271 if (!pim_ifp)
272 continue;
273
7176984f 274 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
275 rp_info->i_am_rp = 1;
276 }
00d07c6f
DS
277 }
278}
279
75a26779 280int
dfe43e25 281pim_rp_new (const char *rp, const char *group_range, const char *plist)
75a26779
DS
282{
283 int result;
36d6bd7d
DS
284 struct rp_info *rp_info;
285 struct rp_info *rp_all;
286 struct prefix group_all;
dfe43e25
DW
287 struct listnode *node, *nnode;
288 struct rp_info *tmp_rp_info;
289 char buffer[BUFSIZ];
1bc98276 290 struct prefix nht_p;
36d6bd7d
DS
291
292 rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
dfe43e25
DW
293 if (!rp_info)
294 return PIM_MALLOC_FAIL;
36d6bd7d
DS
295
296 if (group_range == NULL)
297 result = str2prefix ("224.0.0.0/4", &rp_info->group);
298 else
299 result = str2prefix (group_range, &rp_info->group);
300
301 if (!result)
dfe43e25
DW
302 {
303 XFREE (MTYPE_PIM_RP, rp_info);
304 return PIM_GROUP_BAD_ADDRESS;
305 }
306
fa8da98c
DS
307 rp_info->rp.rpf_addr.family = AF_INET;
308 result = inet_pton (rp_info->rp.rpf_addr.family, rp, &rp_info->rp.rpf_addr.u.prefix4);
75a26779 309
dfe43e25 310 if (result <= 0)
36d6bd7d 311 {
36d6bd7d 312 XFREE (MTYPE_PIM_RP, rp_info);
dfe43e25 313 return PIM_RP_BAD_ADDRESS;
36d6bd7d
DS
314 }
315
dfe43e25 316 if (plist)
36d6bd7d 317 {
dfe43e25
DW
318 /*
319 * Return if the prefix-list is already configured for this RP
320 */
321 if (pim_rp_find_prefix_list (rp_info->rp.rpf_addr.u.prefix4, plist))
322 {
323 XFREE (MTYPE_PIM_RP, rp_info);
324 return PIM_SUCCESS;
325 }
326
327 /*
328 * Barf if the prefix-list is already configured for an RP
329 */
330 if (pim_rp_prefix_list_used (plist))
331 {
332 XFREE (MTYPE_PIM_RP, rp_info);
333 return PIM_RP_PFXLIST_IN_USE;
334 }
335
336 /*
337 * Free any existing rp_info entries for this RP
338 */
339 for (ALL_LIST_ELEMENTS (qpim_rp_list, node, nnode, tmp_rp_info))
340 {
341 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr)
342 {
343 if (tmp_rp_info->plist)
344 pim_rp_del (rp, NULL, tmp_rp_info->plist);
345 else
346 pim_rp_del (rp, prefix2str(&tmp_rp_info->group, buffer, BUFSIZ), NULL);
347 }
348 }
36d6bd7d 349
dfe43e25
DW
350 rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
351 }
352 else
36d6bd7d 353 {
dfe43e25
DW
354 str2prefix ("224.0.0.0/4", &group_all);
355 rp_all = pim_rp_find_match_group(&group_all);
356
357 /*
358 * Barf if group is a non-multicast subnet
359 */
360 if (! prefix_match (&rp_all->group, &rp_info->group))
36d6bd7d 361 {
dfe43e25
DW
362 XFREE (MTYPE_PIM_RP, rp_info);
363 return PIM_GROUP_BAD_ADDRESS;
36d6bd7d
DS
364 }
365
dfe43e25
DW
366 /*
367 * Remove any prefix-list rp_info entries for this RP
368 */
369 for (ALL_LIST_ELEMENTS (qpim_rp_list, node, nnode, tmp_rp_info))
370 {
371 if (tmp_rp_info->plist &&
372 rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr)
373 {
374 pim_rp_del (rp, NULL, tmp_rp_info->plist);
375 }
376 }
377
378 /*
379 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
380 */
381 if (prefix_same (&rp_all->group, &rp_info->group) &&
382 pim_rpf_addr_is_inaddr_none (&rp_all->rp))
383 {
384 rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
385 XFREE (MTYPE_PIM_RP, rp_info);
386
1bc98276
CS
387 /* Register addr with Zebra NHT */
388 nht_p.family = AF_INET;
389 nht_p.prefixlen = IPV4_MAX_BITLEN;
390 nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4;
391 if (PIM_DEBUG_PIM_TRACE)
392 {
393 char buf[PREFIX2STR_BUFFER];
394 prefix2str (&nht_p, buf, sizeof (buf));
395 zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
396 __PRETTY_FUNCTION__, buf);
397 }
398 pim_find_or_track_nexthop (&nht_p, NULL, rp_all);
399
a04da05a 400 if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
dfe43e25
DW
401 return PIM_RP_NO_PATH;
402
403 pim_rp_check_interfaces (rp_all);
44521e5d 404 pim_rp_refresh_group_to_rp_mapping();
dfe43e25
DW
405 return PIM_SUCCESS;
406 }
407
408 /*
409 * Return if the group is already configured for this RP
410 */
411 if (pim_rp_find_exact (rp_info->rp.rpf_addr.u.prefix4, &rp_info->group))
412 {
413 XFREE (MTYPE_PIM_RP, rp_info);
414 return PIM_SUCCESS;
415 }
416
417 /*
418 * Barf if this group is already covered by some other RP
419 */
420 tmp_rp_info = pim_rp_find_match_group (&rp_info->group);
421
422 if (tmp_rp_info)
423 {
424 if (tmp_rp_info->plist)
425 {
426 XFREE (MTYPE_PIM_RP, rp_info);
427 return PIM_GROUP_PFXLIST_OVERLAP;
428 }
429 else
430 {
431 /*
432 * If the only RP that covers this group is an RP configured for
433 * 224.0.0.0/4 that is fine, ignore that one. For all others
434 * though we must return PIM_GROUP_OVERLAP
435 */
436 if (! prefix_same (&group_all, &tmp_rp_info->group))
437 {
438 XFREE (MTYPE_PIM_RP, rp_info);
439 return PIM_GROUP_OVERLAP;
440 }
441 }
442 }
36d6bd7d
DS
443 }
444
445 listnode_add_sort (qpim_rp_list, rp_info);
446
1bc98276
CS
447 /* Register addr with Zebra NHT */
448 nht_p.family = AF_INET;
449 nht_p.prefixlen = IPV4_MAX_BITLEN;
450 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
451 if (PIM_DEBUG_PIM_TRACE)
452 {
453 char buf[PREFIX2STR_BUFFER];
454 prefix2str (&nht_p, buf, sizeof (buf));
455 zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf);
456 }
457 pim_find_or_track_nexthop (&nht_p, NULL, rp_info);
458
a04da05a 459 if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
dfe43e25 460 return PIM_RP_NO_PATH;
75a26779 461
00d07c6f 462 pim_rp_check_interfaces (rp_info);
1bc98276 463 pim_rp_refresh_group_to_rp_mapping ();
dfe43e25 464 return PIM_SUCCESS;
75a26779
DS
465}
466
467int
dfe43e25 468pim_rp_del (const char *rp, const char *group_range, const char *plist)
75a26779 469{
36d6bd7d
DS
470 struct prefix group;
471 struct in_addr rp_addr;
472 struct prefix g_all;
473 struct rp_info *rp_info;
474 struct rp_info *rp_all;
475 int result;
1bc98276 476 struct prefix nht_p;
36d6bd7d 477
36d6bd7d
DS
478 if (group_range == NULL)
479 result = str2prefix ("224.0.0.0/4", &group);
480 else
481 result = str2prefix (group_range, &group);
482
483 if (!result)
dfe43e25 484 return PIM_GROUP_BAD_ADDRESS;
36d6bd7d
DS
485
486 result = inet_pton (AF_INET, rp, &rp_addr);
487 if (result <= 0)
dfe43e25
DW
488 return PIM_RP_BAD_ADDRESS;
489
490 if (plist)
491 rp_info = pim_rp_find_prefix_list (rp_addr, plist);
492 else
493 rp_info = pim_rp_find_exact (rp_addr, &group);
36d6bd7d 494
36d6bd7d 495 if (!rp_info)
dfe43e25
DW
496 return PIM_RP_NOT_FOUND;
497
498 if (rp_info->plist)
499 {
500 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
501 rp_info->plist = NULL;
502 }
503
1bc98276
CS
504 /* Deregister addr with Zebra NHT */
505 nht_p.family = AF_INET;
506 nht_p.prefixlen = IPV4_MAX_BITLEN;
507 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
508 if (PIM_DEBUG_PIM_TRACE)
509 {
510 char buf[PREFIX2STR_BUFFER];
511 prefix2str (&nht_p, buf, sizeof (buf));
512 zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf);
513 }
514 pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
515
dfe43e25
DW
516 str2prefix ("224.0.0.0/4", &g_all);
517 rp_all = pim_rp_find_match_group (&g_all);
36d6bd7d
DS
518
519 if (rp_all == rp_info)
520 {
63c59d0c
DS
521 rp_all->rp.rpf_addr.family = AF_INET;
522 rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
36d6bd7d 523 rp_all->i_am_rp = 0;
dfe43e25 524 return PIM_SUCCESS;
36d6bd7d 525 }
75a26779 526
36d6bd7d 527 listnode_delete (qpim_rp_list, rp_info);
1bc98276 528 pim_rp_refresh_group_to_rp_mapping ();
dfe43e25 529 return PIM_SUCCESS;
75a26779 530}
13afbd05
DS
531
532int
533pim_rp_setup (void)
534{
36d6bd7d
DS
535 struct listnode *node;
536 struct rp_info *rp_info;
537 int ret = 0;
538
539 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
13afbd05 540 {
e30a4d4a
DS
541 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
542 continue;
543
63b8f7a3 544 if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
36d6bd7d 545 {
98906696
DS
546 if (PIM_DEBUG_PIM_TRACE)
547 zlog_debug ("Unable to lookup nexthop for rp specified");
36d6bd7d
DS
548 ret++;
549 }
13afbd05
DS
550 }
551
36d6bd7d
DS
552 if (ret)
553 return 0;
554
13afbd05
DS
555 return 1;
556}
557
54b97c74 558/*
7176984f 559 * Checks to see if we should elect ourself the actual RP when new if
560 * addresses are added against an interface.
54b97c74
DS
561 */
562void
7176984f 563pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
54b97c74 564{
36d6bd7d
DS
565 struct listnode *node;
566 struct rp_info *rp_info;
7667c556 567 bool i_am_rp_changed = false;
36d6bd7d
DS
568
569 if (qpim_rp_list == NULL)
54b97c74
DS
570 return;
571
7176984f 572 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) {
573 if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
574 continue;
575
576 /* if i_am_rp is already set nothing to be done (adding new addresses
577 * is not going to make a difference). */
578 if (rp_info->i_am_rp) {
579 continue;
580 }
581
582 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
583 i_am_rp_changed = true;
584 rp_info->i_am_rp = 1;
36d6bd7d 585 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 586 char rp[PREFIX_STRLEN];
63c59d0c 587 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
7176984f 588 zlog_debug("%s: %s: i am rp", __func__, rp);
36d6bd7d 589 }
7176984f 590 }
591 }
54b97c74 592
7176984f 593 if (i_am_rp_changed) {
594 pim_msdp_i_am_rp_changed();
595 }
596}
36d6bd7d 597
7176984f 598/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
599 * are removed. Removing numbers is an uncommon event in an active network
600 * so I have made no attempt to optimize it. */
601void
602pim_i_am_rp_re_evaluate(void)
603{
604 struct listnode *node;
605 struct rp_info *rp_info;
606 bool i_am_rp_changed = false;
607 int old_i_am_rp;
608
609 if (qpim_rp_list == NULL)
610 return;
611
612 for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
613 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
614 continue;
615
616 old_i_am_rp = rp_info->i_am_rp;
617 pim_rp_check_interfaces(rp_info);
618
619 if (old_i_am_rp != rp_info->i_am_rp) {
620 i_am_rp_changed = true;
621 if (PIM_DEBUG_ZEBRA) {
622 char rp[PREFIX_STRLEN];
623 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
624 if (rp_info->i_am_rp) {
625 zlog_debug("%s: %s: i am rp", __func__, rp);
626 } else {
627 zlog_debug("%s: %s: i am no longer rp", __func__, rp);
36d6bd7d 628 }
7176984f 629 }
54b97c74 630 }
7176984f 631 }
7667c556 632
7176984f 633 if (i_am_rp_changed) {
634 pim_msdp_i_am_rp_changed();
635 }
54b97c74
DS
636}
637
638/*
639 * I_am_RP(G) is true if the group-to-RP mapping indicates that
640 * this router is the RP for the group.
641 *
642 * Since we only have static RP, all groups are part of this RP
643 */
644int
645pim_rp_i_am_rp (struct in_addr group)
646{
36d6bd7d
DS
647 struct prefix g;
648 struct rp_info *rp_info;
649
650 memset (&g, 0, sizeof (g));
651 g.family = AF_INET;
652 g.prefixlen = 32;
653 g.u.prefix4 = group;
654
655 rp_info = pim_rp_find_match_group (&g);
656
657 if (rp_info)
658 return rp_info->i_am_rp;
659
660 return 0;
54b97c74
DS
661}
662
71694057
DS
663/*
664 * RP(G)
665 *
666 * Return the RP that the Group belongs too.
667 */
ed66602c 668struct pim_rpf *
71694057
DS
669pim_rp_g (struct in_addr group)
670{
36d6bd7d
DS
671 struct prefix g;
672 struct rp_info *rp_info;
673
674 memset (&g, 0, sizeof (g));
675 g.family = AF_INET;
676 g.prefixlen = 32;
677 g.u.prefix4 = group;
678
679 rp_info = pim_rp_find_match_group (&g);
680
681 if (rp_info)
682 {
63b8f7a3 683 pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
36d6bd7d
DS
684 return (&rp_info->rp);
685 }
686
687 // About to Go Down
688 return NULL;
71694057
DS
689}
690
8f5f5e91
DS
691/*
692 * Set the upstream IP address we want to talk to based upon
693 * the rp configured and the source address
694 *
695 * If we have don't have a RP configured and the source address is *
696 * then return failure.
697 *
698 */
699int
36d6bd7d 700pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source, struct in_addr group)
8f5f5e91 701{
36d6bd7d
DS
702 struct rp_info *rp_info;
703 struct prefix g;
704
705 memset (&g, 0, sizeof (g));
706 g.family = AF_INET;
707 g.prefixlen = 32;
708 g.u.prefix4 = group;
709
710 rp_info = pim_rp_find_match_group (&g);
711
63c59d0c 712 if ((pim_rpf_addr_is_inaddr_none (&rp_info->rp)) && (source.s_addr == INADDR_ANY))
8f5f5e91
DS
713 {
714 if (PIM_DEBUG_PIM_TRACE)
715 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
716 return 0;
717 }
718
63c59d0c 719 *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4 : source;
8f5f5e91
DS
720
721 return 1;
722}
75a26779
DS
723
724int
725pim_rp_config_write (struct vty *vty)
726{
36d6bd7d
DS
727 struct listnode *node;
728 struct rp_info *rp_info;
dfe43e25
DW
729 char rp_buffer[32];
730 char group_buffer[32];
36d6bd7d 731 int count = 0;
75a26779 732
36d6bd7d 733 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
75a26779 734 {
63c59d0c 735 if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
36d6bd7d
DS
736 continue;
737
dfe43e25
DW
738 if (rp_info->plist)
739 vty_out(vty, "ip pim rp %s prefix-list %s%s",
740 inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
741 rp_info->plist, VTY_NEWLINE);
742 else
743 vty_out(vty, "ip pim rp %s %s%s",
744 inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
745 prefix2str(&rp_info->group, group_buffer, 32), VTY_NEWLINE);
746 count++;
75a26779
DS
747 }
748
36d6bd7d 749 return count;
75a26779
DS
750}
751
752int
753pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr)
754{
36d6bd7d
DS
755 struct rp_info *rp_info;
756 struct prefix g;
757
758 memset (&g, 0, sizeof (g));
759 g.family = AF_INET;
760 g.prefixlen = 32;
761 g.u.prefix4 = group;
762
763 rp_info = pim_rp_find_match_group (&g);
75a26779
DS
764 /*
765 * See if we can short-cut some?
766 * This might not make sense if we ever leave a static RP
767 * type of configuration.
768 * Note - Premature optimization might bite our patooeys' here.
769 */
770 if (I_am_RP(group))
771 {
63c59d0c 772 if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
75a26779
DS
773 return 1;
774 }
775
c5e2cb11 776 if (if_lookup_exact_address (&dest_addr, AF_INET, VRF_DEFAULT))
75a26779 777 return 1;
1bc98276 778
75a26779
DS
779 return 0;
780}
00d07c6f
DS
781
782void
9bf3c633 783pim_rp_show_information (struct vty *vty, u_char uj)
00d07c6f
DS
784{
785 struct rp_info *rp_info;
9bf3c633 786 struct rp_info *prev_rp_info = NULL;
00d07c6f
DS
787 struct listnode *node;
788
9bf3c633
DW
789 json_object *json = NULL;
790 json_object *json_rp_rows = NULL;
791 json_object *json_row = NULL;
792
793 if (uj)
794 json = json_object_new_object();
795 else
796 vty_out (vty, "RP address group/prefix-list OIF I am RP%s", VTY_NEWLINE);
797
00d07c6f
DS
798 for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
799 {
63c59d0c 800 if (!pim_rpf_addr_is_inaddr_none (&rp_info->rp))
dce1a92f
DS
801 {
802 char buf[48];
dfe43e25 803
9bf3c633
DW
804 if (uj)
805 {
806 /*
807 * If we have moved on to a new RP then add the entry for the previous RP
808 */
809 if (prev_rp_info &&
810 prev_rp_info->rp.rpf_addr.u.prefix4.s_addr != rp_info->rp.rpf_addr.u.prefix4.s_addr)
811 {
812 json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
813 json_rp_rows = NULL;
814 }
815
816 if (!json_rp_rows)
817 json_rp_rows = json_object_new_array();
818
819 json_row = json_object_new_object();
3440bd15
DS
820 if (rp_info->rp.source_nexthop.interface)
821 json_object_string_add(json_row, "outboundInterface", rp_info->rp.source_nexthop.interface->name);
9bf3c633
DW
822
823 if (rp_info->i_am_rp)
824 json_object_boolean_true_add(json_row, "iAmRP");
dfe43e25 825
9bf3c633
DW
826 if (rp_info->plist)
827 json_object_string_add(json_row, "prefixList", rp_info->plist);
828 else
829 json_object_string_add(json_row, "group", prefix2str(&rp_info->group, buf, 48));
dfe43e25 830
9bf3c633
DW
831 json_object_array_add(json_rp_rows, json_row);
832 }
dfe43e25 833 else
9bf3c633
DW
834 {
835 vty_out (vty, "%-15s ", inet_ntoa (rp_info->rp.rpf_addr.u.prefix4));
836
837 if (rp_info->plist)
838 vty_out (vty, "%-18s ", rp_info->plist);
839 else
840 vty_out (vty, "%-18s ", prefix2str(&rp_info->group, buf, 48));
841
3440bd15
DS
842 if (rp_info->rp.source_nexthop.interface)
843 vty_out (vty, "%-10s ", rp_info->rp.source_nexthop.interface->name);
844 else
845 vty_out (vty, "%-10s ", "(Unknown)");
9bf3c633
DW
846
847 if (rp_info->i_am_rp)
848 vty_out (vty, "yes%s", VTY_NEWLINE);
849 else
850 vty_out (vty, "no%s", VTY_NEWLINE);
851 }
852
853 prev_rp_info = rp_info;
dce1a92f 854 }
00d07c6f 855 }
9bf3c633
DW
856
857 if (uj) {
858 if (prev_rp_info && json_rp_rows)
859 json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
860
5f9cf1d2 861 vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
9bf3c633
DW
862 json_object_free(json);
863 }
00d07c6f 864}