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