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