]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_nht.c
Merge pull request #11545 from opensourcerouting/fix/memory_leak_for_bmp_listener
[mirror_frr.git] / pimd / pim_nht.c
1 /*
2 * PIM for Quagga
3 * Copyright (C) 2017 Cumulus Networks, Inc.
4 * Chirag Shah
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 #include "network.h"
22 #include "zclient.h"
23 #include "stream.h"
24 #include "nexthop.h"
25 #include "if.h"
26 #include "hash.h"
27 #include "jhash.h"
28
29 #include "lib/printfrr.h"
30
31 #include "pimd.h"
32 #include "pimd/pim_nht.h"
33 #include "pim_instance.h"
34 #include "log.h"
35 #include "pim_time.h"
36 #include "pim_oil.h"
37 #include "pim_ifchannel.h"
38 #include "pim_mroute.h"
39 #include "pim_zebra.h"
40 #include "pim_upstream.h"
41 #include "pim_join.h"
42 #include "pim_jp_agg.h"
43 #include "pim_zebra.h"
44 #include "pim_zlookup.h"
45 #include "pim_rp.h"
46 #include "pim_addr.h"
47
48 /**
49 * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
50 * command to Zebra.
51 */
52 void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
53 struct pim_nexthop_cache *pnc, int command)
54 {
55 struct prefix p;
56 int ret;
57
58 pim_addr_to_prefix(&p, pnc->rpf.rpf_addr);
59 ret = zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, false, false,
60 pim->vrf->vrf_id);
61 if (ret == ZCLIENT_SEND_FAILURE)
62 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
63
64 if (PIM_DEBUG_PIM_NHT)
65 zlog_debug(
66 "%s: NHT %sregistered addr %pFX(%s) with Zebra ret:%d ",
67 __func__,
68 (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", &p,
69 pim->vrf->name, ret);
70
71 return;
72 }
73
74 struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
75 struct pim_rpf *rpf)
76 {
77 struct pim_nexthop_cache *pnc = NULL;
78 struct pim_nexthop_cache lookup;
79
80 lookup.rpf.rpf_addr = rpf->rpf_addr;
81 pnc = hash_lookup(pim->rpf_hash, &lookup);
82
83 return pnc;
84 }
85
86 static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
87 struct pim_rpf *rpf_addr)
88 {
89 struct pim_nexthop_cache *pnc;
90 char hash_name[64];
91
92 pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE,
93 sizeof(struct pim_nexthop_cache));
94 pnc->rpf.rpf_addr = rpf_addr->rpf_addr;
95
96 pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern);
97
98 pnc->rp_list = list_new();
99 pnc->rp_list->cmp = pim_rp_list_cmp;
100
101 snprintfrr(hash_name, sizeof(hash_name), "PNC %pPA(%s) Upstream Hash",
102 &pnc->rpf.rpf_addr, pim->vrf->name);
103 pnc->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
104 pim_upstream_equal, hash_name);
105
106 return pnc;
107 }
108
109 static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim,
110 pim_addr addr)
111 {
112 struct pim_nexthop_cache *pnc = NULL;
113 struct pim_rpf rpf;
114 struct zclient *zclient = NULL;
115
116 zclient = pim_zebra_zclient_get();
117 memset(&rpf, 0, sizeof(rpf));
118 rpf.rpf_addr = addr;
119
120 pnc = pim_nexthop_cache_find(pim, &rpf);
121 if (!pnc) {
122 pnc = pim_nexthop_cache_add(pim, &rpf);
123 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
124 ZEBRA_NEXTHOP_REGISTER);
125 if (PIM_DEBUG_PIM_NHT_DETAIL)
126 zlog_debug(
127 "%s: NHT cache and zebra notification added for %pPA(%s)",
128 __func__, &addr, pim->vrf->name);
129 }
130
131 return pnc;
132 }
133
134 /* TBD: this does several distinct things and should probably be split up.
135 * (checking state vs. returning pnc vs. adding upstream vs. adding rp)
136 */
137 int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
138 struct pim_upstream *up, struct rp_info *rp,
139 struct pim_nexthop_cache *out_pnc)
140 {
141 struct pim_nexthop_cache *pnc;
142 struct listnode *ch_node = NULL;
143
144 pnc = pim_nht_get(pim, addr);
145
146 assertf(up || rp, "addr=%pPA", &addr);
147
148 if (rp != NULL) {
149 ch_node = listnode_lookup(pnc->rp_list, rp);
150 if (ch_node == NULL)
151 listnode_add_sort(pnc->rp_list, rp);
152 }
153
154 if (up != NULL)
155 (void)hash_get(pnc->upstream_hash, up, hash_alloc_intern);
156
157 if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) {
158 if (out_pnc)
159 memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
160 return 1;
161 }
162
163 return 0;
164 }
165
166 #if PIM_IPV == 4
167 void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
168 {
169 struct pim_nexthop_cache *pnc;
170
171 pnc = pim_nht_get(pim, addr);
172
173 pnc->bsr_count++;
174 }
175 #endif /* PIM_IPV == 4 */
176
177 static void pim_nht_drop_maybe(struct pim_instance *pim,
178 struct pim_nexthop_cache *pnc)
179 {
180 if (PIM_DEBUG_PIM_NHT)
181 zlog_debug(
182 "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u",
183 __func__, &pnc->rpf.rpf_addr, pim->vrf->name,
184 pnc->rp_list->count, pnc->upstream_hash->count,
185 pnc->bsr_count);
186
187 if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0
188 && pnc->bsr_count == 0) {
189 struct zclient *zclient = pim_zebra_zclient_get();
190
191 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
192 ZEBRA_NEXTHOP_UNREGISTER);
193
194 list_delete(&pnc->rp_list);
195 hash_free(pnc->upstream_hash);
196
197 hash_release(pim->rpf_hash, pnc);
198 if (pnc->nexthop)
199 nexthops_free(pnc->nexthop);
200 XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
201 }
202 }
203
204 void pim_delete_tracked_nexthop(struct pim_instance *pim, pim_addr addr,
205 struct pim_upstream *up, struct rp_info *rp)
206 {
207 struct pim_nexthop_cache *pnc = NULL;
208 struct pim_nexthop_cache lookup;
209 struct pim_upstream *upstream = NULL;
210
211 /* Remove from RPF hash if it is the last entry */
212 lookup.rpf.rpf_addr = addr;
213 pnc = hash_lookup(pim->rpf_hash, &lookup);
214 if (!pnc) {
215 zlog_warn("attempting to delete nonexistent NHT entry %pPA",
216 &addr);
217 return;
218 }
219
220 if (rp) {
221 /* Release the (*, G)upstream from pnc->upstream_hash,
222 * whose Group belongs to the RP getting deleted
223 */
224 frr_each (rb_pim_upstream, &pim->upstream_head, upstream) {
225 struct prefix grp;
226 struct rp_info *trp_info;
227
228 if (!pim_addr_is_any(upstream->sg.src))
229 continue;
230
231 pim_addr_to_prefix(&grp, upstream->sg.grp);
232 trp_info = pim_rp_find_match_group(pim, &grp);
233 if (trp_info == rp)
234 hash_release(pnc->upstream_hash, upstream);
235 }
236 listnode_delete(pnc->rp_list, rp);
237 }
238
239 if (up)
240 hash_release(pnc->upstream_hash, up);
241
242 pim_nht_drop_maybe(pim, pnc);
243 }
244
245 #if PIM_IPV == 4
246 void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
247 {
248 struct pim_nexthop_cache *pnc = NULL;
249 struct pim_nexthop_cache lookup;
250
251 /*
252 * Nothing to do here if the address to unregister
253 * is 0.0.0.0 as that the BSR has not been registered
254 * for tracking yet.
255 */
256 if (addr.s_addr == INADDR_ANY)
257 return;
258
259 lookup.rpf.rpf_addr = addr;
260
261 pnc = hash_lookup(pim->rpf_hash, &lookup);
262
263 if (!pnc) {
264 zlog_warn("attempting to delete nonexistent NHT BSR entry %pI4",
265 &addr);
266 return;
267 }
268
269 assertf(pnc->bsr_count > 0, "addr=%pI4", &addr);
270 pnc->bsr_count--;
271
272 pim_nht_drop_maybe(pim, pnc);
273 }
274
275 bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
276 struct interface *src_ifp, pim_addr src_ip)
277 {
278 struct pim_nexthop_cache *pnc = NULL;
279 struct pim_nexthop_cache lookup;
280 struct pim_neighbor *nbr = NULL;
281 struct nexthop *nh;
282 struct interface *ifp;
283
284 lookup.rpf.rpf_addr = bsr_addr;
285
286 pnc = hash_lookup(pim->rpf_hash, &lookup);
287 if (!pnc || !CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED)) {
288 /* BSM from a new freshly registered BSR - do a synchronous
289 * zebra query since otherwise we'd drop the first packet,
290 * leading to additional delay in picking up BSM data
291 */
292
293 /* FIXME: this should really be moved into a generic NHT
294 * function that does "add and get immediate result" or maybe
295 * "check cache or get immediate result." But until that can
296 * be worked in, here's a copy of the code below :(
297 */
298 struct pim_zlookup_nexthop nexthop_tab[router->multipath];
299 ifindex_t i;
300 struct interface *ifp = NULL;
301 int num_ifindex;
302
303 memset(nexthop_tab, 0, sizeof(nexthop_tab));
304 num_ifindex = zclient_lookup_nexthop(
305 pim, nexthop_tab, router->multipath, bsr_addr,
306 PIM_NEXTHOP_LOOKUP_MAX);
307
308 if (num_ifindex <= 0)
309 return false;
310
311 for (i = 0; i < num_ifindex; i++) {
312 struct pim_zlookup_nexthop *znh = &nexthop_tab[i];
313
314 /* pim_zlookup_nexthop has no ->type */
315
316 /* 1:1 match code below with znh instead of nh */
317 ifp = if_lookup_by_index(znh->ifindex,
318 pim->vrf->vrf_id);
319
320 if (!ifp || !ifp->info)
321 continue;
322
323 if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
324 return true;
325
326 nbr = pim_neighbor_find(ifp, znh->nexthop_addr);
327 if (!nbr)
328 continue;
329
330 return znh->ifindex == src_ifp->ifindex &&
331 (!pim_addr_cmp(znh->nexthop_addr, src_ip));
332 }
333 return false;
334 }
335
336 if (!CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID))
337 return false;
338
339 /* if we accept BSMs from more than one ECMP nexthop, this will cause
340 * BSM message "multiplication" for each ECMP hop. i.e. if you have
341 * 4-way ECMP and 4 hops you end up with 256 copies of each BSM
342 * message.
343 *
344 * so... only accept the first (IPv4) valid nexthop as source.
345 */
346
347 for (nh = pnc->nexthop; nh; nh = nh->next) {
348 pim_addr nhaddr;
349
350 switch (nh->type) {
351 #if PIM_IPV == 4
352 case NEXTHOP_TYPE_IPV4:
353 if (nh->ifindex == IFINDEX_INTERNAL)
354 continue;
355
356 /* fallthru */
357 case NEXTHOP_TYPE_IPV4_IFINDEX:
358 nhaddr = nh->gate.ipv4;
359 break;
360 #else
361 case NEXTHOP_TYPE_IPV6:
362 if (nh->ifindex == IFINDEX_INTERNAL)
363 continue;
364
365 /* fallthru */
366 case NEXTHOP_TYPE_IPV6_IFINDEX:
367 nhaddr = nh->gate.ipv6;
368 break;
369 #endif
370 case NEXTHOP_TYPE_IFINDEX:
371 nhaddr = bsr_addr;
372 break;
373
374 default:
375 continue;
376 }
377
378 ifp = if_lookup_by_index(nh->ifindex, pim->vrf->vrf_id);
379 if (!ifp || !ifp->info)
380 continue;
381
382 if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
383 return true;
384
385 /* MRIB (IGP) may be pointing at a router where PIM is down */
386 nbr = pim_neighbor_find(ifp, nhaddr);
387 if (!nbr)
388 continue;
389
390 return nh->ifindex == src_ifp->ifindex &&
391 (!pim_addr_cmp(nhaddr, src_ip));
392 }
393 return false;
394 }
395 #endif /* PIM_IPV == 4 */
396
397 void pim_rp_nexthop_del(struct rp_info *rp_info)
398 {
399 rp_info->rp.source_nexthop.interface = NULL;
400 rp_info->rp.source_nexthop.mrib_nexthop_addr = PIMADDR_ANY;
401 rp_info->rp.source_nexthop.mrib_metric_preference =
402 router->infinite_assert_metric.metric_preference;
403 rp_info->rp.source_nexthop.mrib_route_metric =
404 router->infinite_assert_metric.route_metric;
405 }
406
407 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
408 static void pim_update_rp_nh(struct pim_instance *pim,
409 struct pim_nexthop_cache *pnc)
410 {
411 struct listnode *node = NULL;
412 struct rp_info *rp_info = NULL;
413
414 /*Traverse RP list and update each RP Nexthop info */
415 for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) {
416 if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
417 continue;
418
419 // Compute PIM RPF using cached nexthop
420 if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
421 rp_info->rp.rpf_addr,
422 &rp_info->group, 1))
423 pim_rp_nexthop_del(rp_info);
424 }
425 }
426
427 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
428 static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
429 {
430 struct pim_instance *pim = (struct pim_instance *)arg;
431 struct pim_upstream *up = (struct pim_upstream *)bucket->data;
432
433 enum pim_rpf_result rpf_result;
434 struct pim_rpf old;
435
436 old.source_nexthop.interface = up->rpf.source_nexthop.interface;
437 rpf_result = pim_rpf_update(pim, up, &old, __func__);
438
439 /* update kernel multicast forwarding cache (MFC); if the
440 * RPF nbr is now unreachable the MFC has already been updated
441 * by pim_rpf_clear
442 */
443 if (rpf_result != PIM_RPF_FAILURE)
444 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
445
446 if (rpf_result == PIM_RPF_CHANGED ||
447 (rpf_result == PIM_RPF_FAILURE && old.source_nexthop.interface))
448 pim_zebra_upstream_rpf_changed(pim, up, &old);
449
450
451 if (PIM_DEBUG_PIM_NHT) {
452 zlog_debug(
453 "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
454 __func__, up->sg_str, pim->vrf->name,
455 old.source_nexthop.interface ? old.source_nexthop
456 .interface->name
457 : "Unknown",
458 up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
459 .interface->name
460 : "Unknown");
461 }
462
463 return HASHWALK_CONTINUE;
464 }
465
466 static int pim_update_upstream_nh(struct pim_instance *pim,
467 struct pim_nexthop_cache *pnc)
468 {
469 hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim);
470
471 pim_zebra_update_all_interfaces(pim);
472
473 return 0;
474 }
475
476 uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
477 {
478 uint32_t hash_val;
479
480 if (!src)
481 return 0;
482
483 hash_val = prefix_hash_key(src);
484 if (grp)
485 hash_val ^= prefix_hash_key(grp);
486 return hash_val;
487 }
488
489 static int pim_ecmp_nexthop_search(struct pim_instance *pim,
490 struct pim_nexthop_cache *pnc,
491 struct pim_nexthop *nexthop, pim_addr src,
492 struct prefix *grp, int neighbor_needed)
493 {
494 struct pim_neighbor *nbrs[router->multipath], *nbr = NULL;
495 struct interface *ifps[router->multipath];
496 struct nexthop *nh_node = NULL;
497 ifindex_t first_ifindex;
498 struct interface *ifp = NULL;
499 uint32_t hash_val = 0, mod_val = 0;
500 uint8_t nh_iter = 0, found = 0;
501 uint32_t i, num_nbrs = 0;
502 pim_addr nh_addr = nexthop->mrib_nexthop_addr;
503 pim_addr grp_addr = pim_addr_from_prefix(grp);
504
505 if (!pnc || !pnc->nexthop_num || !nexthop)
506 return 0;
507
508 memset(&nbrs, 0, sizeof(nbrs));
509 memset(&ifps, 0, sizeof(ifps));
510
511
512 // Current Nexthop is VALID, check to stay on the current path.
513 if (nexthop->interface && nexthop->interface->info &&
514 (!pim_addr_is_any(nh_addr))) {
515 /* User configured knob to explicitly switch
516 to new path is disabled or current path
517 metric is less than nexthop update.
518 */
519
520 if (pim->ecmp_rebalance_enable == 0) {
521 uint8_t curr_route_valid = 0;
522 // Check if current nexthop is present in new updated
523 // Nexthop list.
524 // If the current nexthop is not valid, candidate to
525 // choose new Nexthop.
526 for (nh_node = pnc->nexthop; nh_node;
527 nh_node = nh_node->next) {
528 curr_route_valid = (nexthop->interface->ifindex
529 == nh_node->ifindex);
530 if (curr_route_valid)
531 break;
532 }
533
534 if (curr_route_valid &&
535 !pim_if_connected_to_source(nexthop->interface,
536 src)) {
537 nbr = pim_neighbor_find(
538 nexthop->interface,
539 nexthop->mrib_nexthop_addr);
540 if (!nbr
541 && !if_is_loopback(nexthop->interface)) {
542 if (PIM_DEBUG_PIM_NHT)
543 zlog_debug(
544 "%s: current nexthop does not have nbr ",
545 __func__);
546 } else {
547 /* update metric even if the upstream
548 * neighbor stays unchanged
549 */
550 nexthop->mrib_metric_preference =
551 pnc->distance;
552 nexthop->mrib_route_metric =
553 pnc->metric;
554 if (PIM_DEBUG_PIM_NHT)
555 zlog_debug(
556 "%s: (%pPA,%pPA)(%s) current nexthop %s is valid, skipping new path selection",
557 __func__, &src,
558 &grp_addr,
559 pim->vrf->name,
560 nexthop->interface->name);
561 return 1;
562 }
563 }
564 }
565 }
566
567 /*
568 * Look up all interfaces and neighbors,
569 * store for later usage
570 */
571 for (nh_node = pnc->nexthop, i = 0; nh_node;
572 nh_node = nh_node->next, i++) {
573 ifps[i] =
574 if_lookup_by_index(nh_node->ifindex, pim->vrf->vrf_id);
575 if (ifps[i]) {
576 #if PIM_IPV == 4
577 pim_addr nhaddr = nh_node->gate.ipv4;
578 #else
579 pim_addr nhaddr = nh_node->gate.ipv6;
580 #endif
581 nbrs[i] = pim_neighbor_find(ifps[i], nhaddr);
582 if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
583 num_nbrs++;
584 }
585 }
586 if (pim->ecmp_enable) {
587 struct prefix src_pfx;
588 uint32_t consider = pnc->nexthop_num;
589
590 if (neighbor_needed && num_nbrs < consider)
591 consider = num_nbrs;
592
593 if (consider == 0)
594 return 0;
595
596 // PIM ECMP flag is enable then choose ECMP path.
597 pim_addr_to_prefix(&src_pfx, src);
598 hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
599 mod_val = hash_val % consider;
600 }
601
602 for (nh_node = pnc->nexthop; nh_node && (found == 0);
603 nh_node = nh_node->next) {
604 first_ifindex = nh_node->ifindex;
605 ifp = ifps[nh_iter];
606 if (!ifp) {
607 if (PIM_DEBUG_PIM_NHT)
608 zlog_debug(
609 "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
610 __FILE__, __func__, first_ifindex, &src,
611 pim->vrf->name);
612 if (nh_iter == mod_val)
613 mod_val++; // Select nexthpath
614 nh_iter++;
615 continue;
616 }
617 if (!ifp->info) {
618 if (PIM_DEBUG_PIM_NHT)
619 zlog_debug(
620 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
621 __func__, ifp->name, pim->vrf->name,
622 first_ifindex, &src);
623 if (nh_iter == mod_val)
624 mod_val++; // Select nexthpath
625 nh_iter++;
626 continue;
627 }
628
629 if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
630 nbr = nbrs[nh_iter];
631 if (!nbr && !if_is_loopback(ifp)) {
632 if (PIM_DEBUG_PIM_NHT)
633 zlog_debug(
634 "%s: pim nbr not found on input interface %s(%s)",
635 __func__, ifp->name,
636 pim->vrf->name);
637 if (nh_iter == mod_val)
638 mod_val++; // Select nexthpath
639 nh_iter++;
640 continue;
641 }
642 }
643
644 if (nh_iter == mod_val) {
645 nexthop->interface = ifp;
646 #if PIM_IPV == 4
647 nexthop->mrib_nexthop_addr = nh_node->gate.ipv4;
648 #else
649 nexthop->mrib_nexthop_addr = nh_node->gate.ipv6;
650 #endif
651 nexthop->mrib_metric_preference = pnc->distance;
652 nexthop->mrib_route_metric = pnc->metric;
653 nexthop->last_lookup = src;
654 nexthop->last_lookup_time = pim_time_monotonic_usec();
655 nexthop->nbr = nbr;
656 found = 1;
657 if (PIM_DEBUG_PIM_NHT)
658 zlog_debug(
659 "%s: (%pPA,%pPA)(%s) selected nhop interface %s addr %pPAs mod_val %u iter %d ecmp %d",
660 __func__, &src, &grp_addr,
661 pim->vrf->name, ifp->name, &nh_addr,
662 mod_val, nh_iter, pim->ecmp_enable);
663 }
664 nh_iter++;
665 }
666
667 if (found)
668 return 1;
669 else
670 return 0;
671 }
672
673 /* This API is used to parse Registered address nexthop update coming from Zebra
674 */
675 int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
676 {
677 struct nexthop *nexthop;
678 struct nexthop *nhlist_head = NULL;
679 struct nexthop *nhlist_tail = NULL;
680 int i;
681 struct pim_rpf rpf;
682 struct pim_nexthop_cache *pnc = NULL;
683 struct interface *ifp = NULL;
684 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
685 struct pim_instance *pim;
686 struct zapi_route nhr;
687 struct prefix match;
688
689 if (!vrf)
690 return 0;
691 pim = vrf->info;
692
693 if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) {
694 zlog_err("%s: Decode of nexthop update from zebra failed",
695 __func__);
696 return 0;
697 }
698
699 if (cmd == ZEBRA_NEXTHOP_UPDATE) {
700 rpf.rpf_addr = pim_addr_from_prefix(&match);
701 pnc = pim_nexthop_cache_find(pim, &rpf);
702 if (!pnc) {
703 if (PIM_DEBUG_PIM_NHT)
704 zlog_debug(
705 "%s: Skipping NHT update, addr %pPA is not in local cached DB.",
706 __func__, &rpf.rpf_addr);
707 return 0;
708 }
709 } else {
710 /*
711 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
712 */
713 return 0;
714 }
715
716 pnc->last_update = pim_time_monotonic_usec();
717
718 if (nhr.nexthop_num) {
719 pnc->nexthop_num = 0; // Only increment for pim enabled rpf.
720
721 for (i = 0; i < nhr.nexthop_num; i++) {
722 nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
723 switch (nexthop->type) {
724 case NEXTHOP_TYPE_IFINDEX:
725 /*
726 * Connected route (i.e. no nexthop), use
727 * RPF address from nexthop cache (i.e.
728 * destination) as PIM nexthop.
729 */
730 #if PIM_IPV == 4
731 nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
732 nexthop->gate.ipv4 = pnc->rpf.rpf_addr;
733 #else
734 nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
735 nexthop->gate.ipv6 = pnc->rpf.rpf_addr;
736 #endif
737 break;
738 #if PIM_IPV == 4
739 /* RFC5549 IPv4-over-IPv6 nexthop handling:
740 * if we get an IPv6 nexthop in IPv4 PIM, hunt down a
741 * PIM neighbor and use that instead.
742 */
743 case NEXTHOP_TYPE_IPV6_IFINDEX: {
744 struct interface *ifp1 = NULL;
745 struct pim_neighbor *nbr = NULL;
746
747 ifp1 = if_lookup_by_index(nexthop->ifindex,
748 pim->vrf->vrf_id);
749
750 if (!ifp1)
751 nbr = NULL;
752 else
753 /* FIXME: should really use nbr's
754 * secondary address list here
755 */
756 nbr = pim_neighbor_find_if(ifp1);
757
758 /* Overwrite with Nbr address as NH addr */
759 if (nbr)
760 nexthop->gate.ipv4 = nbr->source_addr;
761 else
762 // Mark nexthop address to 0 until PIM
763 // Nbr is resolved.
764 nexthop->gate.ipv4 = PIMADDR_ANY;
765
766 break;
767 }
768 #else
769 case NEXTHOP_TYPE_IPV6_IFINDEX:
770 #endif
771 case NEXTHOP_TYPE_IPV6:
772 case NEXTHOP_TYPE_IPV4:
773 case NEXTHOP_TYPE_IPV4_IFINDEX:
774 case NEXTHOP_TYPE_BLACKHOLE:
775 /* nothing to do for the other nexthop types */
776 break;
777 }
778
779 ifp = if_lookup_by_index(nexthop->ifindex,
780 pim->vrf->vrf_id);
781 if (!ifp) {
782 if (PIM_DEBUG_PIM_NHT) {
783 char buf[NEXTHOP_STRLEN];
784 zlog_debug(
785 "%s: could not find interface for ifindex %d(%s) (addr %s)",
786 __func__, nexthop->ifindex,
787 pim->vrf->name,
788 nexthop2str(nexthop, buf,
789 sizeof(buf)));
790 }
791 nexthop_free(nexthop);
792 continue;
793 }
794
795 if (PIM_DEBUG_PIM_NHT) {
796 #if PIM_IPV == 4
797 pim_addr nhaddr = nexthop->gate.ipv4;
798 #else
799 pim_addr nhaddr = nexthop->gate.ipv6;
800 #endif
801 zlog_debug(
802 "%s: NHT addr %pFX(%s) %d-nhop via %pPA(%s) type %d distance:%u metric:%u ",
803 __func__, &match, pim->vrf->name, i + 1,
804 &nhaddr, ifp->name, nexthop->type,
805 nhr.distance, nhr.metric);
806 }
807
808 if (!ifp->info) {
809 /*
810 * Though Multicast is not enabled on this
811 * Interface store it in database otheriwse we
812 * may miss this update and this will not cause
813 * any issue, because while choosing the path we
814 * are ommitting the Interfaces which are not
815 * multicast enabled
816 */
817 if (PIM_DEBUG_PIM_NHT) {
818 char buf[NEXTHOP_STRLEN];
819
820 zlog_debug(
821 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
822 __func__, ifp->name,
823 pim->vrf->name,
824 nexthop->ifindex,
825 nexthop2str(nexthop, buf,
826 sizeof(buf)));
827 }
828 }
829
830 if (nhlist_tail) {
831 nhlist_tail->next = nexthop;
832 nhlist_tail = nexthop;
833 } else {
834 nhlist_tail = nexthop;
835 nhlist_head = nexthop;
836 }
837 // Only keep track of nexthops which are PIM enabled.
838 pnc->nexthop_num++;
839 }
840 /* Reset existing pnc->nexthop before assigning new list */
841 nexthops_free(pnc->nexthop);
842 pnc->nexthop = nhlist_head;
843 if (pnc->nexthop_num) {
844 pnc->flags |= PIM_NEXTHOP_VALID;
845 pnc->distance = nhr.distance;
846 pnc->metric = nhr.metric;
847 }
848 } else {
849 pnc->flags &= ~PIM_NEXTHOP_VALID;
850 pnc->nexthop_num = nhr.nexthop_num;
851 nexthops_free(pnc->nexthop);
852 pnc->nexthop = NULL;
853 }
854 SET_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED);
855
856 if (PIM_DEBUG_PIM_NHT)
857 zlog_debug(
858 "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
859 __func__, &match, pim->vrf->name, nhr.nexthop_num,
860 pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
861 listcount(pnc->rp_list));
862
863 pim_rpf_set_refresh_time(pim);
864
865 if (listcount(pnc->rp_list))
866 pim_update_rp_nh(pim, pnc);
867 if (pnc->upstream_hash->count)
868 pim_update_upstream_nh(pim, pnc);
869
870 return 0;
871 }
872
873 int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
874 struct pim_nexthop *nexthop, pim_addr src,
875 struct prefix *grp, int neighbor_needed)
876 {
877 struct pim_nexthop_cache *pnc;
878 struct pim_zlookup_nexthop nexthop_tab[router->multipath];
879 struct pim_neighbor *nbrs[router->multipath], *nbr = NULL;
880 struct pim_rpf rpf;
881 int num_ifindex;
882 struct interface *ifps[router->multipath], *ifp;
883 int first_ifindex;
884 int found = 0;
885 uint8_t i = 0;
886 uint32_t hash_val = 0, mod_val = 0;
887 uint32_t num_nbrs = 0;
888
889 if (PIM_DEBUG_PIM_NHT_DETAIL)
890 zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
891 __func__, &src, pim->vrf->name,
892 nexthop->last_lookup_time);
893
894 rpf.rpf_addr = src;
895
896 pnc = pim_nexthop_cache_find(pim, &rpf);
897 if (pnc) {
898 if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED))
899 return pim_ecmp_nexthop_search(pim, pnc, nexthop, src, grp,
900 neighbor_needed);
901 }
902
903 memset(nexthop_tab, 0,
904 sizeof(struct pim_zlookup_nexthop) * router->multipath);
905 num_ifindex =
906 zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, src,
907 PIM_NEXTHOP_LOOKUP_MAX);
908 if (num_ifindex < 1) {
909 if (PIM_DEBUG_PIM_NHT)
910 zlog_warn(
911 "%s: could not find nexthop ifindex for address %pPA(%s)",
912 __func__, &src, pim->vrf->name);
913 return 0;
914 }
915
916 memset(&nbrs, 0, sizeof(nbrs));
917 memset(&ifps, 0, sizeof(ifps));
918
919 /*
920 * Look up all interfaces and neighbors,
921 * store for later usage
922 */
923 for (i = 0; i < num_ifindex; i++) {
924 ifps[i] = if_lookup_by_index(nexthop_tab[i].ifindex,
925 pim->vrf->vrf_id);
926 if (ifps[i]) {
927 nbrs[i] = pim_neighbor_find(
928 ifps[i], nexthop_tab[i].nexthop_addr);
929 if (nbrs[i] || pim_if_connected_to_source(ifps[i], src))
930 num_nbrs++;
931 }
932 }
933
934 // If PIM ECMP enable then choose ECMP path.
935 if (pim->ecmp_enable) {
936 struct prefix src_pfx;
937 uint32_t consider = num_ifindex;
938
939 if (neighbor_needed && num_nbrs < consider)
940 consider = num_nbrs;
941
942 if (consider == 0)
943 return 0;
944
945 pim_addr_to_prefix(&src_pfx, src);
946 hash_val = pim_compute_ecmp_hash(&src_pfx, grp);
947 mod_val = hash_val % consider;
948 if (PIM_DEBUG_PIM_NHT_DETAIL)
949 zlog_debug("%s: hash_val %u mod_val %u", __func__,
950 hash_val, mod_val);
951 }
952
953 i = 0;
954 while (!found && (i < num_ifindex)) {
955 first_ifindex = nexthop_tab[i].ifindex;
956
957 ifp = ifps[i];
958 if (!ifp) {
959 if (PIM_DEBUG_PIM_NHT)
960 zlog_debug(
961 "%s %s: could not find interface for ifindex %d (address %pPA(%s))",
962 __FILE__, __func__, first_ifindex, &src,
963 pim->vrf->name);
964 if (i == mod_val)
965 mod_val++;
966 i++;
967 continue;
968 }
969
970 if (!ifp->info) {
971 if (PIM_DEBUG_PIM_NHT)
972 zlog_debug(
973 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
974 __func__, ifp->name, pim->vrf->name,
975 first_ifindex, &src);
976 if (i == mod_val)
977 mod_val++;
978 i++;
979 continue;
980 }
981 if (neighbor_needed && !pim_if_connected_to_source(ifp, src)) {
982 nbr = nbrs[i];
983 if (PIM_DEBUG_PIM_NHT_DETAIL)
984 zlog_debug("ifp name: %s(%s), pim nbr: %p",
985 ifp->name, pim->vrf->name, nbr);
986 if (!nbr && !if_is_loopback(ifp)) {
987 if (i == mod_val)
988 mod_val++;
989 if (PIM_DEBUG_PIM_NHT)
990 zlog_debug(
991 "%s: NBR (%pPA) not found on input interface %s(%s) (RPF for source %pPA)",
992 __func__,
993 &nexthop_tab[i].nexthop_addr,
994 ifp->name, pim->vrf->name,
995 &src);
996 i++;
997 continue;
998 }
999 }
1000
1001 if (i == mod_val) {
1002 if (PIM_DEBUG_PIM_NHT)
1003 zlog_debug(
1004 "%s: found nhop %pPA for addr %pPA interface %s(%s) metric %d dist %d",
1005 __func__, &nexthop_tab[i].nexthop_addr,
1006 &src, ifp->name, pim->vrf->name,
1007 nexthop_tab[i].route_metric,
1008 nexthop_tab[i].protocol_distance);
1009 /* update nexthop data */
1010 nexthop->interface = ifp;
1011 nexthop->mrib_nexthop_addr =
1012 nexthop_tab[i].nexthop_addr;
1013 nexthop->mrib_metric_preference =
1014 nexthop_tab[i].protocol_distance;
1015 nexthop->mrib_route_metric =
1016 nexthop_tab[i].route_metric;
1017 nexthop->last_lookup = src;
1018 nexthop->last_lookup_time = pim_time_monotonic_usec();
1019 nexthop->nbr = nbr;
1020 found = 1;
1021 }
1022 i++;
1023 }
1024
1025 if (found)
1026 return 1;
1027 else
1028 return 0;
1029 }
1030
1031 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, pim_addr src,
1032 struct prefix *grp)
1033 {
1034 struct pim_nexthop nhop;
1035 int vif_index;
1036 ifindex_t ifindex;
1037
1038 memset(&nhop, 0, sizeof(nhop));
1039 if (!pim_ecmp_nexthop_lookup(pim, &nhop, src, grp, 1)) {
1040 if (PIM_DEBUG_PIM_NHT)
1041 zlog_debug(
1042 "%s: could not find nexthop ifindex for address %pPA(%s)",
1043 __func__, &src, pim->vrf->name);
1044 return -1;
1045 }
1046
1047 ifindex = nhop.interface->ifindex;
1048 if (PIM_DEBUG_PIM_NHT)
1049 zlog_debug(
1050 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %pPA",
1051 __func__, ifindex,
1052 ifindex2ifname(ifindex, pim->vrf->vrf_id),
1053 pim->vrf->name, &src);
1054
1055 vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
1056
1057 if (vif_index < 0) {
1058 if (PIM_DEBUG_PIM_NHT) {
1059 zlog_debug(
1060 "%s: low vif_index=%d(%s) < 1 nexthop for address %pPA",
1061 __func__, vif_index, pim->vrf->name, &src);
1062 }
1063 return -2;
1064 }
1065
1066 return vif_index;
1067 }