]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_rp.c
Merge pull request #7550 from volta-networks/fix_bfd_isis
[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 #include "pim_mroute.h"
49 #include "pim_oil.h"
50 #include "pim_zebra.h"
51 #include "pim_bsm.h"
52
53 /* Cleanup pim->rpf_hash each node data */
54 void pim_rp_list_hash_clean(void *data)
55 {
56 struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data;
57
58 list_delete(&pnc->rp_list);
59
60 hash_clean(pnc->upstream_hash, NULL);
61 hash_free(pnc->upstream_hash);
62 pnc->upstream_hash = NULL;
63 if (pnc->nexthop)
64 nexthops_free(pnc->nexthop);
65
66 XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
67 }
68
69 static void pim_rp_info_free(struct rp_info *rp_info)
70 {
71 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
72
73 XFREE(MTYPE_PIM_RP, rp_info);
74 }
75
76 int pim_rp_list_cmp(void *v1, void *v2)
77 {
78 struct rp_info *rp1 = (struct rp_info *)v1;
79 struct rp_info *rp2 = (struct rp_info *)v2;
80
81 /*
82 * Sort by RP IP address
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 if (rp1->rp.rpf_addr.u.prefix4.s_addr
89 > rp2->rp.rpf_addr.u.prefix4.s_addr)
90 return 1;
91
92 /*
93 * Sort by group IP address
94 */
95 if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
96 return -1;
97
98 if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
99 return 1;
100
101 return 0;
102 }
103
104 void pim_rp_init(struct pim_instance *pim)
105 {
106 struct rp_info *rp_info;
107 struct route_node *rn;
108
109 pim->rp_list = list_new();
110 pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
111 pim->rp_list->cmp = pim_rp_list_cmp;
112
113 pim->rp_table = route_table_init();
114
115 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
116
117 if (!str2prefix("224.0.0.0/4", &rp_info->group)) {
118 flog_err(EC_LIB_DEVELOPMENT,
119 "Unable to convert 224.0.0.0/4 to prefix");
120 list_delete(&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 rn->info = rp_info;
134 if (PIM_DEBUG_PIM_TRACE)
135 zlog_debug(
136 "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
137 rn, rp_info, route_node_get_lock_count(rn));
138 }
139
140 void pim_rp_free(struct pim_instance *pim)
141 {
142 if (pim->rp_list)
143 list_delete(&pim->rp_list);
144 if (pim->rp_table)
145 route_table_finish(pim->rp_table);
146 pim->rp_table = NULL;
147 }
148
149 /*
150 * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
151 */
152 static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim,
153 struct in_addr rp,
154 const char *plist)
155 {
156 struct listnode *node;
157 struct rp_info *rp_info;
158
159 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
160 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
161 && rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
162 return rp_info;
163 }
164 }
165
166 return NULL;
167 }
168
169 /*
170 * Return true if plist is used by any rp_info
171 */
172 static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist)
173 {
174 struct listnode *node;
175 struct rp_info *rp_info;
176
177 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
178 if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
179 return 1;
180 }
181 }
182
183 return 0;
184 }
185
186 /*
187 * Given an RP's address, return the RP's rp_info that is an exact match for
188 * 'group'
189 */
190 static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
191 struct in_addr rp,
192 const struct prefix *group)
193 {
194 struct listnode *node;
195 struct rp_info *rp_info;
196
197 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
198 if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
199 && prefix_same(&rp_info->group, group))
200 return rp_info;
201 }
202
203 return NULL;
204 }
205
206 /*
207 * Given a group, return the rp_info for that group
208 */
209 struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
210 const struct prefix *group)
211 {
212 struct listnode *node;
213 struct rp_info *best = NULL;
214 struct rp_info *rp_info;
215 struct prefix_list *plist;
216 const struct prefix *p, *bp;
217 struct route_node *rn;
218
219 bp = NULL;
220 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
221 if (rp_info->plist) {
222 plist = prefix_list_lookup(AFI_IP, rp_info->plist);
223
224 if (prefix_list_apply_which_prefix(plist, &p, group)
225 == PREFIX_DENY)
226 continue;
227
228 if (!best) {
229 best = rp_info;
230 bp = p;
231 continue;
232 }
233
234 if (bp && bp->prefixlen < p->prefixlen) {
235 best = rp_info;
236 bp = p;
237 }
238 }
239 }
240
241 rn = route_node_match(pim->rp_table, group);
242 if (!rn) {
243 flog_err(
244 EC_LIB_DEVELOPMENT,
245 "%s: BUG We should have found default group information\n",
246 __func__);
247 return best;
248 }
249
250 rp_info = rn->info;
251 if (PIM_DEBUG_PIM_TRACE)
252 zlog_debug("Lookedup: %p for rp_info: %p(%pFX) Lock: %d", rn,
253 rp_info, &rp_info->group,
254 route_node_get_lock_count(rn));
255
256 route_unlock_node(rn);
257
258 if (!best)
259 return rp_info;
260
261 if (rp_info->group.prefixlen < best->group.prefixlen)
262 best = rp_info;
263
264 return best;
265 }
266
267 /*
268 * When the user makes "ip pim rp" configuration changes or if they change the
269 * prefix-list(s) used by these statements we must tickle the upstream state
270 * for each group to make them re-lookup who their RP should be.
271 *
272 * This is a placeholder function for now.
273 */
274 void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
275 {
276 pim_msdp_i_am_rp_changed(pim);
277 pim_upstream_reeval_use_rpt(pim);
278 }
279
280 void pim_rp_prefix_list_update(struct pim_instance *pim,
281 struct prefix_list *plist)
282 {
283 struct listnode *node;
284 struct rp_info *rp_info;
285 int refresh_needed = 0;
286
287 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
288 if (rp_info->plist
289 && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
290 refresh_needed = 1;
291 break;
292 }
293 }
294
295 if (refresh_needed)
296 pim_rp_refresh_group_to_rp_mapping(pim);
297 }
298
299 static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
300 struct pim_interface *pim_ifp)
301 {
302 struct listnode *node;
303 struct pim_secondary_addr *sec_addr;
304
305 if (pim_ifp->primary_address.s_addr
306 == rp_info->rp.rpf_addr.u.prefix4.s_addr)
307 return 1;
308
309 if (!pim_ifp->sec_addr_list) {
310 return 0;
311 }
312
313 for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
314 if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) {
315 return 1;
316 }
317 }
318
319 return 0;
320 }
321
322 static void pim_rp_check_interfaces(struct pim_instance *pim,
323 struct rp_info *rp_info)
324 {
325 struct interface *ifp;
326
327 rp_info->i_am_rp = 0;
328 FOR_ALL_INTERFACES (pim->vrf, ifp) {
329 struct pim_interface *pim_ifp = ifp->info;
330
331 if (!pim_ifp)
332 continue;
333
334 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
335 rp_info->i_am_rp = 1;
336 }
337 }
338 }
339
340 void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
341 {
342 struct pim_rpf old_rpf;
343 enum pim_rpf_result rpf_result;
344 struct in_addr old_upstream_addr;
345 struct in_addr new_upstream_addr;
346 struct prefix nht_p;
347
348 old_upstream_addr = up->upstream_addr;
349 pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
350 up->sg.grp);
351
352 if (PIM_DEBUG_PIM_TRACE)
353 zlog_debug("%s: pim upstream update for old upstream %pI4",
354 __func__, &old_upstream_addr);
355
356 if (old_upstream_addr.s_addr == new_upstream_addr.s_addr)
357 return;
358
359 /* Lets consider a case, where a PIM upstream has a better RP as a
360 * result of a new RP configuration with more precise group range.
361 * This upstream has to be added to the upstream hash of new RP's
362 * NHT(pnc) and has to be removed from old RP's NHT upstream hash
363 */
364 if (old_upstream_addr.s_addr != INADDR_ANY) {
365 /* Deregister addr with Zebra NHT */
366 nht_p.family = AF_INET;
367 nht_p.prefixlen = IPV4_MAX_BITLEN;
368 nht_p.u.prefix4 = old_upstream_addr;
369 if (PIM_DEBUG_PIM_TRACE)
370 zlog_debug(
371 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
372 __func__, up->sg_str, &nht_p);
373 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL, false);
374 }
375
376 /* Update the upstream address */
377 up->upstream_addr = new_upstream_addr;
378
379 old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
380
381 rpf_result = pim_rpf_update(pim, up, &old_rpf, __func__);
382 if (rpf_result == PIM_RPF_FAILURE)
383 pim_mroute_del(up->channel_oil, __func__);
384
385 /* update kernel multicast forwarding cache (MFC) */
386 if (up->rpf.source_nexthop.interface && up->channel_oil)
387 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
388
389 if (rpf_result == PIM_RPF_CHANGED ||
390 (rpf_result == PIM_RPF_FAILURE &&
391 old_rpf.source_nexthop.interface))
392 pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
393
394 pim_zebra_update_all_interfaces(pim);
395 }
396
397 int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
398 struct prefix group, const char *plist,
399 enum rp_source rp_src_flag)
400 {
401 int result = 0;
402 char rp[INET_ADDRSTRLEN];
403 struct rp_info *rp_info;
404 struct rp_info *rp_all;
405 struct prefix group_all;
406 struct listnode *node, *nnode;
407 struct rp_info *tmp_rp_info;
408 char buffer[BUFSIZ];
409 struct prefix nht_p;
410 struct route_node *rn;
411 struct pim_upstream *up;
412
413 if (rp_addr.s_addr == INADDR_ANY ||
414 rp_addr.s_addr == INADDR_NONE)
415 return PIM_RP_BAD_ADDRESS;
416
417 rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
418
419 rp_info->rp.rpf_addr.family = AF_INET;
420 rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN;
421 rp_info->rp.rpf_addr.u.prefix4 = rp_addr;
422 prefix_copy(&rp_info->group, &group);
423 rp_info->rp_src = rp_src_flag;
424
425 inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp, sizeof(rp));
426
427 if (plist) {
428 /*
429 * Return if the prefix-list is already configured for this RP
430 */
431 if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4,
432 plist)) {
433 XFREE(MTYPE_PIM_RP, rp_info);
434 return PIM_SUCCESS;
435 }
436
437 /*
438 * Barf if the prefix-list is already configured for an RP
439 */
440 if (pim_rp_prefix_list_used(pim, plist)) {
441 XFREE(MTYPE_PIM_RP, rp_info);
442 return PIM_RP_PFXLIST_IN_USE;
443 }
444
445 /*
446 * Free any existing rp_info entries for this RP
447 */
448 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
449 tmp_rp_info)) {
450 if (rp_info->rp.rpf_addr.u.prefix4.s_addr
451 == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) {
452 if (tmp_rp_info->plist)
453 pim_rp_del_config(pim, rp, NULL,
454 tmp_rp_info->plist);
455 else
456 pim_rp_del_config(
457 pim, rp,
458 prefix2str(&tmp_rp_info->group,
459 buffer, BUFSIZ),
460 NULL);
461 }
462 }
463
464 rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
465 } else {
466
467 if (!str2prefix("224.0.0.0/4", &group_all)) {
468 XFREE(MTYPE_PIM_RP, rp_info);
469 return PIM_GROUP_BAD_ADDRESS;
470 }
471 rp_all = pim_rp_find_match_group(pim, &group_all);
472
473 /*
474 * Barf if group is a non-multicast subnet
475 */
476 if (!prefix_match(&rp_all->group, &rp_info->group)) {
477 XFREE(MTYPE_PIM_RP, rp_info);
478 return PIM_GROUP_BAD_ADDRESS;
479 }
480
481 /*
482 * Remove any prefix-list rp_info entries for this RP
483 */
484 for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
485 tmp_rp_info)) {
486 if (tmp_rp_info->plist
487 && rp_info->rp.rpf_addr.u.prefix4.s_addr
488 == tmp_rp_info->rp.rpf_addr.u.prefix4
489 .s_addr) {
490 pim_rp_del_config(pim, rp, NULL,
491 tmp_rp_info->plist);
492 }
493 }
494
495 /*
496 * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
497 */
498 if (prefix_same(&rp_all->group, &rp_info->group)
499 && pim_rpf_addr_is_inaddr_none(&rp_all->rp)) {
500 rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
501 rp_all->rp_src = rp_src_flag;
502 XFREE(MTYPE_PIM_RP, rp_info);
503
504 /* Register addr with Zebra NHT */
505 nht_p.family = AF_INET;
506 nht_p.prefixlen = IPV4_MAX_BITLEN;
507 nht_p.u.prefix4 =
508 rp_all->rp.rpf_addr.u.prefix4; // RP address
509 if (PIM_DEBUG_PIM_NHT_RP)
510 zlog_debug(
511 "%s: NHT Register rp_all addr %pFX grp %pFX ",
512 __func__, &nht_p, &rp_all->group);
513
514 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
515 /* Find (*, G) upstream whose RP is not
516 * configured yet
517 */
518 if ((up->upstream_addr.s_addr == INADDR_ANY)
519 && (up->sg.src.s_addr == INADDR_ANY)) {
520 struct prefix grp;
521 struct rp_info *trp_info;
522
523 grp.family = AF_INET;
524 grp.prefixlen = IPV4_MAX_BITLEN;
525 grp.u.prefix4 = up->sg.grp;
526 trp_info = pim_rp_find_match_group(
527 pim, &grp);
528 if (trp_info == rp_all)
529 pim_upstream_update(pim, up);
530 }
531 }
532
533 pim_rp_check_interfaces(pim, rp_all);
534 pim_rp_refresh_group_to_rp_mapping(pim);
535 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
536 false, NULL);
537
538 if (!pim_ecmp_nexthop_lookup(pim,
539 &rp_all->rp.source_nexthop,
540 &nht_p, &rp_all->group, 1))
541 return PIM_RP_NO_PATH;
542 return PIM_SUCCESS;
543 }
544
545 /*
546 * Return if the group is already configured for this RP
547 */
548 tmp_rp_info = pim_rp_find_exact(
549 pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group);
550 if (tmp_rp_info) {
551 if ((tmp_rp_info->rp_src != rp_src_flag)
552 && (rp_src_flag == RP_SRC_STATIC))
553 tmp_rp_info->rp_src = rp_src_flag;
554 XFREE(MTYPE_PIM_RP, rp_info);
555 return result;
556 }
557
558 /*
559 * Barf if this group is already covered by some other RP
560 */
561 tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group);
562
563 if (tmp_rp_info) {
564 if (tmp_rp_info->plist) {
565 XFREE(MTYPE_PIM_RP, rp_info);
566 return PIM_GROUP_PFXLIST_OVERLAP;
567 } else {
568 /*
569 * If the only RP that covers this group is an
570 * RP configured for
571 * 224.0.0.0/4 that is fine, ignore that one.
572 * For all others
573 * though we must return PIM_GROUP_OVERLAP
574 */
575 if (prefix_same(&rp_info->group,
576 &tmp_rp_info->group)) {
577 if ((rp_src_flag == RP_SRC_STATIC)
578 && (tmp_rp_info->rp_src
579 == RP_SRC_STATIC)) {
580 XFREE(MTYPE_PIM_RP, rp_info);
581 return PIM_GROUP_OVERLAP;
582 }
583
584 result = pim_rp_change(
585 pim,
586 rp_info->rp.rpf_addr.u.prefix4,
587 tmp_rp_info->group,
588 rp_src_flag);
589 XFREE(MTYPE_PIM_RP, rp_info);
590 return result;
591 }
592 }
593 }
594 }
595
596 listnode_add_sort(pim->rp_list, rp_info);
597 rn = route_node_get(pim->rp_table, &rp_info->group);
598 rn->info = rp_info;
599
600 if (PIM_DEBUG_PIM_TRACE)
601 zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
602 rp_info, &rp_info->group,
603 route_node_get_lock_count(rn));
604
605 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
606 if (up->sg.src.s_addr == INADDR_ANY) {
607 struct prefix grp;
608 struct rp_info *trp_info;
609
610 grp.family = AF_INET;
611 grp.prefixlen = IPV4_MAX_BITLEN;
612 grp.u.prefix4 = up->sg.grp;
613 trp_info = pim_rp_find_match_group(pim, &grp);
614
615 if (trp_info == rp_info)
616 pim_upstream_update(pim, up);
617 }
618 }
619
620 pim_rp_check_interfaces(pim, rp_info);
621 pim_rp_refresh_group_to_rp_mapping(pim);
622
623 /* Register addr with Zebra NHT */
624 nht_p.family = AF_INET;
625 nht_p.prefixlen = IPV4_MAX_BITLEN;
626 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
627 if (PIM_DEBUG_PIM_NHT_RP)
628 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
629 __func__, &nht_p, &rp_info->group);
630 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL);
631 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
632 &rp_info->group, 1))
633 return PIM_RP_NO_PATH;
634
635 return PIM_SUCCESS;
636 }
637
638 int pim_rp_del_config(struct pim_instance *pim, const char *rp,
639 const char *group_range, const char *plist)
640 {
641 struct prefix group;
642 struct in_addr rp_addr;
643 int result;
644
645 if (group_range == NULL)
646 result = str2prefix("224.0.0.0/4", &group);
647 else
648 result = str2prefix(group_range, &group);
649
650 if (!result)
651 return PIM_GROUP_BAD_ADDRESS;
652
653 result = inet_pton(AF_INET, rp, &rp_addr);
654 if (result <= 0)
655 return PIM_RP_BAD_ADDRESS;
656
657 result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
658 return result;
659 }
660
661 int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
662 struct prefix group, const char *plist,
663 enum rp_source rp_src_flag)
664 {
665 struct prefix g_all;
666 struct rp_info *rp_info;
667 struct rp_info *rp_all;
668 struct prefix nht_p;
669 struct route_node *rn;
670 bool was_plist = false;
671 struct rp_info *trp_info;
672 struct pim_upstream *up;
673 struct bsgrp_node *bsgrp = NULL;
674 struct bsm_rpinfo *bsrp = NULL;
675 char rp_str[INET_ADDRSTRLEN];
676
677 if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)))
678 snprintf(rp_str, sizeof(rp_str), "<rp?>");
679
680 if (plist)
681 rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
682 else
683 rp_info = pim_rp_find_exact(pim, rp_addr, &group);
684
685 if (!rp_info)
686 return PIM_RP_NOT_FOUND;
687
688 if (rp_info->plist) {
689 XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
690 was_plist = true;
691 }
692
693 if (PIM_DEBUG_PIM_TRACE)
694 zlog_debug("%s: Delete RP %s for the group %pFX", __func__,
695 rp_str, &group);
696
697 /* While static RP is getting deleted, we need to check if dynamic RP
698 * present for the same group in BSM RP table, then install the dynamic
699 * RP for the group node into the main rp table
700 */
701 if (rp_src_flag == RP_SRC_STATIC) {
702 bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
703
704 if (bsgrp) {
705 bsrp = listnode_head(bsgrp->bsrp_list);
706 if (bsrp) {
707 if (PIM_DEBUG_PIM_TRACE) {
708 char bsrp_str[INET_ADDRSTRLEN];
709
710 if (!inet_ntop(AF_INET, bsrp, bsrp_str,
711 sizeof(bsrp_str)))
712 snprintf(bsrp_str,
713 sizeof(bsrp_str),
714 "<bsrp?>");
715
716 zlog_debug(
717 "%s: BSM RP %s found for the group %pFX",
718 __func__, bsrp_str, &group);
719 }
720 return pim_rp_change(pim, bsrp->rp_address,
721 group, RP_SRC_BSR);
722 }
723 } else {
724 if (PIM_DEBUG_PIM_TRACE)
725 zlog_debug(
726 "%s: BSM RP not found for the group %pFX",
727 __func__, &group);
728 }
729 }
730
731 /* Deregister addr with Zebra NHT */
732 nht_p.family = AF_INET;
733 nht_p.prefixlen = IPV4_MAX_BITLEN;
734 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
735 if (PIM_DEBUG_PIM_NHT_RP)
736 zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__,
737 &nht_p);
738 pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false);
739
740 if (!str2prefix("224.0.0.0/4", &g_all))
741 return PIM_RP_BAD_ADDRESS;
742
743 rp_all = pim_rp_find_match_group(pim, &g_all);
744
745 if (rp_all == rp_info) {
746 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
747 /* Find the upstream (*, G) whose upstream address is
748 * same as the deleted RP
749 */
750 if ((up->upstream_addr.s_addr
751 == rp_info->rp.rpf_addr.u.prefix4.s_addr)
752 && (up->sg.src.s_addr == INADDR_ANY)) {
753 struct prefix grp;
754 grp.family = AF_INET;
755 grp.prefixlen = IPV4_MAX_BITLEN;
756 grp.u.prefix4 = up->sg.grp;
757 trp_info = pim_rp_find_match_group(pim, &grp);
758 if (trp_info == rp_all) {
759 pim_upstream_rpf_clear(pim, up);
760 up->upstream_addr.s_addr = INADDR_ANY;
761 }
762 }
763 }
764 rp_all->rp.rpf_addr.family = AF_INET;
765 rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
766 rp_all->i_am_rp = 0;
767 return PIM_SUCCESS;
768 }
769
770 listnode_delete(pim->rp_list, rp_info);
771
772 if (!was_plist) {
773 rn = route_node_get(pim->rp_table, &rp_info->group);
774 if (rn) {
775 if (rn->info != rp_info)
776 flog_err(
777 EC_LIB_DEVELOPMENT,
778 "Expected rn->info to be equal to rp_info");
779
780 if (PIM_DEBUG_PIM_TRACE)
781 zlog_debug(
782 "%s:Found for Freeing: %p for rp_info: %p(%pFX) Lock: %d",
783 __func__, rn, rp_info, &rp_info->group,
784 route_node_get_lock_count(rn));
785
786 rn->info = NULL;
787 route_unlock_node(rn);
788 route_unlock_node(rn);
789 }
790 }
791
792 pim_rp_refresh_group_to_rp_mapping(pim);
793
794 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
795 /* Find the upstream (*, G) whose upstream address is same as
796 * the deleted RP
797 */
798 if ((up->upstream_addr.s_addr
799 == rp_info->rp.rpf_addr.u.prefix4.s_addr)
800 && (up->sg.src.s_addr == INADDR_ANY)) {
801 struct prefix grp;
802
803 grp.family = AF_INET;
804 grp.prefixlen = IPV4_MAX_BITLEN;
805 grp.u.prefix4 = up->sg.grp;
806
807 trp_info = pim_rp_find_match_group(pim, &grp);
808
809 /* RP not found for the group grp */
810 if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
811 pim_upstream_rpf_clear(pim, up);
812 pim_rp_set_upstream_addr(
813 pim, &up->upstream_addr, up->sg.src,
814 up->sg.grp);
815 }
816
817 /* RP found for the group grp */
818 else
819 pim_upstream_update(pim, up);
820 }
821 }
822
823 XFREE(MTYPE_PIM_RP, rp_info);
824 return PIM_SUCCESS;
825 }
826
827 int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
828 struct prefix group, enum rp_source rp_src_flag)
829 {
830 struct prefix nht_p;
831 struct route_node *rn;
832 int result = 0;
833 struct rp_info *rp_info = NULL;
834 struct pim_upstream *up;
835
836 rn = route_node_lookup(pim->rp_table, &group);
837 if (!rn) {
838 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
839 return result;
840 }
841
842 rp_info = rn->info;
843
844 if (!rp_info) {
845 route_unlock_node(rn);
846 result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
847 return result;
848 }
849
850 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == new_rp_addr.s_addr) {
851 if (rp_info->rp_src != rp_src_flag) {
852 rp_info->rp_src = rp_src_flag;
853 route_unlock_node(rn);
854 return PIM_SUCCESS;
855 }
856 }
857
858 nht_p.family = AF_INET;
859 nht_p.prefixlen = IPV4_MAX_BITLEN;
860
861 /* Deregister old RP addr with Zebra NHT */
862 if (rp_info->rp.rpf_addr.u.prefix4.s_addr != INADDR_ANY) {
863 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
864 if (PIM_DEBUG_PIM_NHT_RP)
865 zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
866 __func__, &nht_p);
867 pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false);
868 }
869
870 pim_rp_nexthop_del(rp_info);
871 listnode_delete(pim->rp_list, rp_info);
872 /* Update the new RP address*/
873 rp_info->rp.rpf_addr.u.prefix4 = new_rp_addr;
874 rp_info->rp_src = rp_src_flag;
875 rp_info->i_am_rp = 0;
876
877 listnode_add_sort(pim->rp_list, rp_info);
878
879 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
880 if (up->sg.src.s_addr == INADDR_ANY) {
881 struct prefix grp;
882 struct rp_info *trp_info;
883
884 grp.family = AF_INET;
885 grp.prefixlen = IPV4_MAX_BITLEN;
886 grp.u.prefix4 = up->sg.grp;
887 trp_info = pim_rp_find_match_group(pim, &grp);
888
889 if (trp_info == rp_info)
890 pim_upstream_update(pim, up);
891 }
892 }
893
894 /* Register new RP addr with Zebra NHT */
895 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
896 if (PIM_DEBUG_PIM_NHT_RP)
897 zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ",
898 __func__, &nht_p, &rp_info->group);
899
900 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL);
901 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
902 &rp_info->group, 1)) {
903 route_unlock_node(rn);
904 return PIM_RP_NO_PATH;
905 }
906
907 pim_rp_check_interfaces(pim, rp_info);
908
909 route_unlock_node(rn);
910
911 pim_rp_refresh_group_to_rp_mapping(pim);
912
913 return result;
914 }
915
916 void pim_rp_setup(struct pim_instance *pim)
917 {
918 struct listnode *node;
919 struct rp_info *rp_info;
920 struct prefix nht_p;
921
922 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
923 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
924 continue;
925
926 nht_p.family = AF_INET;
927 nht_p.prefixlen = IPV4_MAX_BITLEN;
928 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
929
930 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false,
931 NULL);
932 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
933 &nht_p, &rp_info->group, 1))
934 if (PIM_DEBUG_PIM_NHT_RP)
935 zlog_debug(
936 "Unable to lookup nexthop for rp specified");
937 }
938 }
939
940 /*
941 * Checks to see if we should elect ourself the actual RP when new if
942 * addresses are added against an interface.
943 */
944 void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
945 {
946 struct listnode *node;
947 struct rp_info *rp_info;
948 bool i_am_rp_changed = false;
949 struct pim_instance *pim = pim_ifp->pim;
950
951 if (pim->rp_list == NULL)
952 return;
953
954 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
955 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
956 continue;
957
958 /* if i_am_rp is already set nothing to be done (adding new
959 * addresses
960 * is not going to make a difference). */
961 if (rp_info->i_am_rp) {
962 continue;
963 }
964
965 if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
966 i_am_rp_changed = true;
967 rp_info->i_am_rp = 1;
968 if (PIM_DEBUG_PIM_NHT_RP) {
969 char rp[PREFIX_STRLEN];
970 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
971 rp, sizeof(rp));
972 zlog_debug("%s: %s: i am rp", __func__, rp);
973 }
974 }
975 }
976
977 if (i_am_rp_changed) {
978 pim_msdp_i_am_rp_changed(pim);
979 pim_upstream_reeval_use_rpt(pim);
980 }
981 }
982
983 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
984 * are removed. Removing numbers is an uncommon event in an active network
985 * so I have made no attempt to optimize it. */
986 void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
987 {
988 struct listnode *node;
989 struct rp_info *rp_info;
990 bool i_am_rp_changed = false;
991 int old_i_am_rp;
992
993 if (pim->rp_list == NULL)
994 return;
995
996 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
997 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
998 continue;
999
1000 old_i_am_rp = rp_info->i_am_rp;
1001 pim_rp_check_interfaces(pim, rp_info);
1002
1003 if (old_i_am_rp != rp_info->i_am_rp) {
1004 i_am_rp_changed = true;
1005 if (PIM_DEBUG_PIM_NHT_RP) {
1006 char rp[PREFIX_STRLEN];
1007 pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr,
1008 rp, sizeof(rp));
1009 if (rp_info->i_am_rp) {
1010 zlog_debug("%s: %s: i am rp", __func__,
1011 rp);
1012 } else {
1013 zlog_debug("%s: %s: i am no longer rp",
1014 __func__, rp);
1015 }
1016 }
1017 }
1018 }
1019
1020 if (i_am_rp_changed) {
1021 pim_msdp_i_am_rp_changed(pim);
1022 pim_upstream_reeval_use_rpt(pim);
1023 }
1024 }
1025
1026 /*
1027 * I_am_RP(G) is true if the group-to-RP mapping indicates that
1028 * this router is the RP for the group.
1029 *
1030 * Since we only have static RP, all groups are part of this RP
1031 */
1032 int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group)
1033 {
1034 struct prefix g;
1035 struct rp_info *rp_info;
1036
1037 memset(&g, 0, sizeof(g));
1038 g.family = AF_INET;
1039 g.prefixlen = 32;
1040 g.u.prefix4 = group;
1041
1042 rp_info = pim_rp_find_match_group(pim, &g);
1043
1044 if (rp_info)
1045 return rp_info->i_am_rp;
1046
1047 return 0;
1048 }
1049
1050 /*
1051 * RP(G)
1052 *
1053 * Return the RP that the Group belongs too.
1054 */
1055 struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
1056 {
1057 struct prefix g;
1058 struct rp_info *rp_info;
1059
1060 memset(&g, 0, sizeof(g));
1061 g.family = AF_INET;
1062 g.prefixlen = 32;
1063 g.u.prefix4 = group;
1064
1065 rp_info = pim_rp_find_match_group(pim, &g);
1066
1067 if (rp_info) {
1068 struct prefix nht_p;
1069
1070 /* Register addr with Zebra NHT */
1071 nht_p.family = AF_INET;
1072 nht_p.prefixlen = IPV4_MAX_BITLEN;
1073 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
1074 if (PIM_DEBUG_PIM_NHT_RP)
1075 zlog_debug(
1076 "%s: NHT Register RP addr %pFX grp %pFX with Zebra",
1077 __func__, &nht_p, &rp_info->group);
1078 pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false,
1079 NULL);
1080 pim_rpf_set_refresh_time(pim);
1081 (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
1082 &nht_p, &rp_info->group, 1);
1083 return (&rp_info->rp);
1084 }
1085
1086 // About to Go Down
1087 return NULL;
1088 }
1089
1090 /*
1091 * Set the upstream IP address we want to talk to based upon
1092 * the rp configured and the source address
1093 *
1094 * If we have don't have a RP configured and the source address is *
1095 * then set the upstream addr as INADDR_ANY and return failure.
1096 *
1097 */
1098 int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
1099 struct in_addr source, struct in_addr group)
1100 {
1101 struct rp_info *rp_info;
1102 struct prefix g;
1103
1104 memset(&g, 0, sizeof(g));
1105 g.family = AF_INET;
1106 g.prefixlen = 32;
1107 g.u.prefix4 = group;
1108
1109 rp_info = pim_rp_find_match_group(pim, &g);
1110
1111 if (!rp_info || ((pim_rpf_addr_is_inaddr_none(&rp_info->rp))
1112 && (source.s_addr == INADDR_ANY))) {
1113 if (PIM_DEBUG_PIM_NHT_RP)
1114 zlog_debug("%s: Received a (*,G) with no RP configured",
1115 __func__);
1116 up->s_addr = INADDR_ANY;
1117 return 0;
1118 }
1119
1120 *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4
1121 : source;
1122
1123 return 1;
1124 }
1125
1126 int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
1127 const char *spaces)
1128 {
1129 struct listnode *node;
1130 struct rp_info *rp_info;
1131 char rp_buffer[32];
1132 int count = 0;
1133
1134 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1135 if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
1136 continue;
1137
1138 if (rp_info->rp_src == RP_SRC_BSR)
1139 continue;
1140
1141 if (rp_info->plist)
1142 vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces,
1143 inet_ntop(AF_INET,
1144 &rp_info->rp.rpf_addr.u.prefix4,
1145 rp_buffer, 32),
1146 rp_info->plist);
1147 else
1148 vty_out(vty, "%sip pim rp %s %pFX\n", spaces,
1149 inet_ntop(AF_INET,
1150 &rp_info->rp.rpf_addr.u.prefix4,
1151 rp_buffer, 32),
1152 &rp_info->group);
1153 count++;
1154 }
1155
1156 return count;
1157 }
1158
1159 bool pim_rp_check_is_my_ip_address(struct pim_instance *pim,
1160 struct in_addr dest_addr)
1161 {
1162 if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id))
1163 return true;
1164
1165 return false;
1166 }
1167
1168 void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
1169 {
1170 struct rp_info *rp_info;
1171 struct rp_info *prev_rp_info = NULL;
1172 struct listnode *node;
1173 char source[7];
1174 char buf[PREFIX_STRLEN];
1175
1176 json_object *json = NULL;
1177 json_object *json_rp_rows = NULL;
1178 json_object *json_row = NULL;
1179
1180 if (uj)
1181 json = json_object_new_object();
1182 else
1183 vty_out(vty,
1184 "RP address group/prefix-list OIF I am RP Source\n");
1185 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1186 if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) {
1187 char buf[48];
1188
1189 if (rp_info->rp_src == RP_SRC_STATIC)
1190 strlcpy(source, "Static", sizeof(source));
1191 else if (rp_info->rp_src == RP_SRC_BSR)
1192 strlcpy(source, "BSR", sizeof(source));
1193 else
1194 strlcpy(source, "None", sizeof(source));
1195 if (uj) {
1196 /*
1197 * If we have moved on to a new RP then add the
1198 * entry for the previous RP
1199 */
1200 if (prev_rp_info
1201 && prev_rp_info->rp.rpf_addr.u.prefix4
1202 .s_addr
1203 != rp_info->rp.rpf_addr.u.prefix4
1204 .s_addr) {
1205 json_object_object_add(
1206 json,
1207 inet_ntop(AF_INET,
1208 &prev_rp_info->rp
1209 .rpf_addr.u
1210 .prefix4,
1211 buf, sizeof(buf)),
1212 json_rp_rows);
1213 json_rp_rows = NULL;
1214 }
1215
1216 if (!json_rp_rows)
1217 json_rp_rows = json_object_new_array();
1218
1219 json_row = json_object_new_object();
1220 json_object_string_add(
1221 json_row, "rpAddress",
1222 inet_ntop(AF_INET,
1223 &rp_info->rp.rpf_addr.u
1224 .prefix4,
1225 buf, sizeof(buf)));
1226 if (rp_info->rp.source_nexthop.interface)
1227 json_object_string_add(
1228 json_row, "outboundInterface",
1229 rp_info->rp.source_nexthop
1230 .interface->name);
1231 else
1232 json_object_string_add(
1233 json_row, "outboundInterface",
1234 "Unknown");
1235 if (rp_info->i_am_rp)
1236 json_object_boolean_true_add(json_row,
1237 "iAmRP");
1238 else
1239 json_object_boolean_false_add(json_row,
1240 "iAmRP");
1241
1242 if (rp_info->plist)
1243 json_object_string_add(json_row,
1244 "prefixList",
1245 rp_info->plist);
1246 else
1247 json_object_string_add(
1248 json_row, "group",
1249 prefix2str(&rp_info->group, buf,
1250 48));
1251 json_object_string_add(json_row, "source",
1252 source);
1253
1254 json_object_array_add(json_rp_rows, json_row);
1255 } else {
1256 vty_out(vty, "%-15s ",
1257 inet_ntop(AF_INET,
1258 &rp_info->rp.rpf_addr.u
1259 .prefix4,
1260 buf, sizeof(buf)));
1261
1262 if (rp_info->plist)
1263 vty_out(vty, "%-18s ", rp_info->plist);
1264 else
1265 vty_out(vty, "%-18pFX ",
1266 &rp_info->group);
1267
1268 if (rp_info->rp.source_nexthop.interface)
1269 vty_out(vty, "%-16s ",
1270 rp_info->rp.source_nexthop
1271 .interface->name);
1272 else
1273 vty_out(vty, "%-16s ", "(Unknown)");
1274
1275 if (rp_info->i_am_rp)
1276 vty_out(vty, "yes");
1277 else
1278 vty_out(vty, "no");
1279
1280 vty_out(vty, "%14s\n", source);
1281 }
1282 prev_rp_info = rp_info;
1283 }
1284 }
1285
1286 if (uj) {
1287 if (prev_rp_info && json_rp_rows)
1288 json_object_object_add(
1289 json,
1290 inet_ntop(AF_INET,
1291 &prev_rp_info->rp.rpf_addr.u.prefix4,
1292 buf, sizeof(buf)),
1293 json_rp_rows);
1294
1295 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1296 json, JSON_C_TO_STRING_PRETTY));
1297 json_object_free(json);
1298 }
1299 }
1300
1301 void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
1302 {
1303 struct listnode *node = NULL;
1304 struct rp_info *rp_info = NULL;
1305 struct nexthop *nh_node = NULL;
1306 struct prefix nht_p;
1307 struct pim_nexthop_cache pnc;
1308
1309 for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
1310 if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
1311 continue;
1312
1313 nht_p.family = AF_INET;
1314 nht_p.prefixlen = IPV4_MAX_BITLEN;
1315 nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
1316 memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
1317 if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
1318 false, &pnc))
1319 continue;
1320
1321 for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
1322 if (nh_node->gate.ipv4.s_addr != INADDR_ANY)
1323 continue;
1324
1325 struct interface *ifp1 = if_lookup_by_index(
1326 nh_node->ifindex, pim->vrf_id);
1327
1328 if (nbr->interface != ifp1)
1329 continue;
1330
1331 nh_node->gate.ipv4 = nbr->source_addr;
1332 if (PIM_DEBUG_PIM_NHT_RP) {
1333 char str[PREFIX_STRLEN];
1334 char str1[INET_ADDRSTRLEN];
1335 pim_inet4_dump("<nht_nbr?>", nbr->source_addr,
1336 str1, sizeof(str1));
1337 pim_addr_dump("<nht_addr?>", &nht_p, str,
1338 sizeof(str));
1339 zlog_debug(
1340 "%s: addr %s new nexthop addr %s interface %s",
1341 __func__, str, str1, ifp1->name);
1342 }
1343 }
1344 }
1345 }