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