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