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