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