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