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