]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_nht.c
Merge pull request #2636 from ppmathis/cleanup/bgpd
[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_and_null(&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 struct pim_neighbor *nbr;
305
306 nbr = pim_neighbor_find(old.source_nexthop.interface,
307 old.rpf_addr.u.prefix4);
308 if (nbr)
309 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
310
311 /*
312 * We have detected a case where we might need to rescan
313 * the inherited o_list so do it.
314 */
315 if (up->channel_oil && up->channel_oil->oil_inherited_rescan) {
316 pim_upstream_inherited_olist_decide(pim, up);
317 up->channel_oil->oil_inherited_rescan = 0;
318 }
319
320 if (up->join_state == PIM_UPSTREAM_JOINED) {
321 /*
322 * If we come up real fast we can be here
323 * where the mroute has not been installed
324 * so install it.
325 */
326 if (up->channel_oil && !up->channel_oil->installed)
327 pim_mroute_add(up->channel_oil,
328 __PRETTY_FUNCTION__);
329
330 /*
331 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
332 *
333 * Transitions from Joined State
334 *
335 * RPF'(S,G) changes not due to an Assert
336 *
337 * The upstream (S,G) state machine remains in Joined
338 * state. Send Join(S,G) to the new upstream
339 * neighbor, which is the new value of RPF'(S,G).
340 * Send Prune(S,G) to the old upstream neighbor, which
341 * is the old value of RPF'(S,G). Set the Join
342 * Timer (JT) to expire after t_periodic seconds.
343 */
344 pim_jp_agg_switch_interface(&old, &up->rpf, up);
345
346 pim_upstream_join_timer_restart(up, &old);
347 } /* up->join_state == PIM_UPSTREAM_JOINED */
348
349 /*
350 * FIXME can join_desired actually be changed by
351 * pim_rpf_update() returning PIM_RPF_CHANGED ?
352 */
353 pim_upstream_update_join_desired(pim, up);
354
355 } /* PIM_RPF_CHANGED */
356
357 if (PIM_DEBUG_PIM_NHT) {
358 zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
359 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
360 old.source_nexthop.interface->name,
361 up->rpf.source_nexthop.interface->name);
362 }
363
364 return HASHWALK_CONTINUE;
365 }
366
367 static int pim_update_upstream_nh(struct pim_instance *pim,
368 struct pim_nexthop_cache *pnc)
369 {
370 struct listnode *node;
371 struct interface *ifp;
372
373 hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim);
374
375 FOR_ALL_INTERFACES (pim->vrf, ifp)
376 if (ifp->info) {
377 struct pim_interface *pim_ifp = ifp->info;
378 struct pim_iface_upstream_switch *us;
379
380 for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list,
381 node, us)) {
382 struct pim_rpf rpf;
383 rpf.source_nexthop.interface = ifp;
384 rpf.rpf_addr.u.prefix4 = us->address;
385 pim_joinprune_send(&rpf, us->us);
386 pim_jp_agg_clear_group(us->us);
387 }
388 }
389
390 return 0;
391 }
392
393 uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
394 {
395 uint32_t hash_val;
396 uint32_t s = 0, g = 0;
397
398 if ((!src))
399 return 0;
400
401 switch (src->family) {
402 case AF_INET: {
403 s = src->u.prefix4.s_addr;
404 s = s == 0 ? 1 : s;
405 if (grp)
406 g = grp->u.prefix4.s_addr;
407 } break;
408 default:
409 break;
410 }
411
412 hash_val = jhash_2words(g, s, 101);
413 return hash_val;
414 }
415
416 int pim_ecmp_nexthop_search(struct pim_instance *pim,
417 struct pim_nexthop_cache *pnc,
418 struct pim_nexthop *nexthop, struct prefix *src,
419 struct prefix *grp, int neighbor_needed)
420 {
421 struct pim_neighbor *nbr = NULL;
422 struct nexthop *nh_node = NULL;
423 ifindex_t first_ifindex;
424 struct interface *ifp = NULL;
425 uint32_t hash_val = 0, mod_val = 0;
426 uint8_t nh_iter = 0, found = 0;
427
428 if (!pnc || !pnc->nexthop_num || !nexthop)
429 return 0;
430
431 // Current Nexthop is VALID, check to stay on the current path.
432 if (nexthop->interface && nexthop->interface->info
433 && nexthop->mrib_nexthop_addr.u.prefix4.s_addr
434 != PIM_NET_INADDR_ANY) {
435 /* User configured knob to explicitly switch
436 to new path is disabled or current path
437 metric is less than nexthop update.
438 */
439
440 if (pim->ecmp_rebalance_enable == 0) {
441 uint8_t curr_route_valid = 0;
442 // Check if current nexthop is present in new updated
443 // Nexthop list.
444 // If the current nexthop is not valid, candidate to
445 // choose new Nexthop.
446 for (nh_node = pnc->nexthop; nh_node;
447 nh_node = nh_node->next) {
448 curr_route_valid = (nexthop->interface->ifindex
449 == nh_node->ifindex);
450 if (curr_route_valid)
451 break;
452 }
453
454 if (curr_route_valid
455 && !pim_if_connected_to_source(nexthop->interface,
456 src->u.prefix4)) {
457 nbr = pim_neighbor_find(
458 nexthop->interface,
459 nexthop->mrib_nexthop_addr.u.prefix4);
460 if (!nbr
461 && !if_is_loopback(nexthop->interface)) {
462 if (PIM_DEBUG_PIM_NHT)
463 zlog_debug(
464 "%s: current nexthop does not have nbr ",
465 __PRETTY_FUNCTION__);
466 } else {
467 if (PIM_DEBUG_PIM_NHT) {
468 char src_str[INET_ADDRSTRLEN];
469 pim_inet4_dump("<addr?>",
470 src->u.prefix4,
471 src_str,
472 sizeof(src_str));
473 char grp_str[INET_ADDRSTRLEN];
474 pim_inet4_dump("<addr?>",
475 grp->u.prefix4,
476 grp_str,
477 sizeof(grp_str));
478 zlog_debug(
479 "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
480 __PRETTY_FUNCTION__,
481 src_str, grp_str,
482 pim->vrf->name,
483 nexthop->interface->name);
484 }
485 return 1;
486 }
487 }
488 }
489 }
490 if (pim->ecmp_enable) {
491 // PIM ECMP flag is enable then choose ECMP path.
492 hash_val = pim_compute_ecmp_hash(src, grp);
493 mod_val = hash_val % pnc->nexthop_num;
494 }
495
496 for (nh_node = pnc->nexthop; nh_node && (found == 0);
497 nh_node = nh_node->next) {
498 first_ifindex = nh_node->ifindex;
499 ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
500 if (!ifp) {
501 if (PIM_DEBUG_PIM_NHT) {
502 char addr_str[INET_ADDRSTRLEN];
503 pim_inet4_dump("<addr?>", src->u.prefix4,
504 addr_str, sizeof(addr_str));
505 zlog_debug(
506 "%s %s: could not find interface for ifindex %d (address %s(%s))",
507 __FILE__, __PRETTY_FUNCTION__,
508 first_ifindex, addr_str,
509 pim->vrf->name);
510 }
511 if (nh_iter == mod_val)
512 mod_val++; // Select nexthpath
513 nh_iter++;
514 continue;
515 }
516 if (!ifp->info) {
517 if (PIM_DEBUG_PIM_NHT) {
518 char addr_str[INET_ADDRSTRLEN];
519 pim_inet4_dump("<addr?>", src->u.prefix4,
520 addr_str, sizeof(addr_str));
521 zlog_debug(
522 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
523 __PRETTY_FUNCTION__, ifp->name,
524 pim->vrf->name, first_ifindex,
525 addr_str);
526 }
527 if (nh_iter == mod_val)
528 mod_val++; // Select nexthpath
529 nh_iter++;
530 continue;
531 }
532
533 if (neighbor_needed
534 && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
535 nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
536 if (!nbr && !if_is_loopback(ifp)) {
537 if (PIM_DEBUG_PIM_NHT)
538 zlog_debug(
539 "%s: pim nbr not found on input interface %s(%s)",
540 __PRETTY_FUNCTION__, ifp->name,
541 pim->vrf->name);
542 if (nh_iter == mod_val)
543 mod_val++; // Select nexthpath
544 nh_iter++;
545 continue;
546 }
547 }
548
549 if (nh_iter == mod_val) {
550 nexthop->interface = ifp;
551 nexthop->mrib_nexthop_addr.family = AF_INET;
552 nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN;
553 nexthop->mrib_nexthop_addr.u.prefix4 =
554 nh_node->gate.ipv4;
555 nexthop->mrib_metric_preference = pnc->distance;
556 nexthop->mrib_route_metric = pnc->metric;
557 nexthop->last_lookup = src->u.prefix4;
558 nexthop->last_lookup_time = pim_time_monotonic_usec();
559 nexthop->nbr = nbr;
560 found = 1;
561 if (PIM_DEBUG_PIM_NHT) {
562 char buf[INET_ADDRSTRLEN];
563 char buf2[INET_ADDRSTRLEN];
564 char buf3[INET_ADDRSTRLEN];
565 pim_inet4_dump("<src?>", src->u.prefix4, buf2,
566 sizeof(buf2));
567 pim_inet4_dump("<grp?>", grp->u.prefix4, buf3,
568 sizeof(buf3));
569 pim_inet4_dump(
570 "<rpf?>",
571 nexthop->mrib_nexthop_addr.u.prefix4,
572 buf, sizeof(buf));
573 zlog_debug(
574 "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
575 __PRETTY_FUNCTION__, buf2, buf3,
576 pim->vrf->name, ifp->name, buf, mod_val,
577 nh_iter, pim->ecmp_enable);
578 }
579 }
580 nh_iter++;
581 }
582
583 if (found)
584 return 1;
585 else
586 return 0;
587 }
588
589 /* This API is used to parse Registered address nexthop update coming from Zebra
590 */
591 int pim_parse_nexthop_update(int command, struct zclient *zclient,
592 zebra_size_t length, vrf_id_t vrf_id)
593 {
594 struct nexthop *nexthop;
595 struct nexthop *nhlist_head = NULL;
596 struct nexthop *nhlist_tail = NULL;
597 int i;
598 struct pim_rpf rpf;
599 struct pim_nexthop_cache *pnc = NULL;
600 struct pim_neighbor *nbr = NULL;
601 struct interface *ifp = NULL;
602 struct interface *ifp1 = NULL;
603 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
604 struct pim_instance *pim;
605 struct zapi_route nhr;
606
607 if (!vrf)
608 return 0;
609 pim = vrf->info;
610
611 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
612 if (PIM_DEBUG_PIM_NHT)
613 zlog_debug(
614 "%s: Decode of nexthop update from zebra failed",
615 __PRETTY_FUNCTION__);
616 return 0;
617 }
618
619 if (command == ZEBRA_NEXTHOP_UPDATE) {
620 prefix_copy(&rpf.rpf_addr, &nhr.prefix);
621 pnc = pim_nexthop_cache_find(pim, &rpf);
622 if (!pnc) {
623 if (PIM_DEBUG_PIM_NHT) {
624 char buf[PREFIX2STR_BUFFER];
625 prefix2str(&rpf.rpf_addr, buf, sizeof(buf));
626 zlog_debug(
627 "%s: Skipping NHT update, addr %s is not in local cached DB.",
628 __PRETTY_FUNCTION__, buf);
629 }
630 return 0;
631 }
632 } else {
633 /*
634 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
635 */
636 return 0;
637 }
638
639 pnc->last_update = pim_time_monotonic_usec();
640
641 if (nhr.nexthop_num) {
642 pnc->nexthop_num = 0; // Only increment for pim enabled rpf.
643
644 for (i = 0; i < nhr.nexthop_num; i++) {
645 nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
646 switch (nexthop->type) {
647 case NEXTHOP_TYPE_IPV4:
648 case NEXTHOP_TYPE_IPV4_IFINDEX:
649 case NEXTHOP_TYPE_IPV6:
650 case NEXTHOP_TYPE_BLACKHOLE:
651 break;
652 case NEXTHOP_TYPE_IFINDEX:
653 /*
654 * Connected route (i.e. no nexthop), use
655 * RPF address from nexthop cache (i.e.
656 * destination) as PIM nexthop.
657 */
658 nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
659 nexthop->gate.ipv4 =
660 pnc->rpf.rpf_addr.u.prefix4;
661 break;
662 case NEXTHOP_TYPE_IPV6_IFINDEX:
663 ifp1 = if_lookup_by_index(nexthop->ifindex,
664 pim->vrf_id);
665 nbr = pim_neighbor_find_if(ifp1);
666 /* Overwrite with Nbr address as NH addr */
667 if (nbr)
668 nexthop->gate.ipv4 = nbr->source_addr;
669 else {
670 // Mark nexthop address to 0 until PIM
671 // Nbr is resolved.
672 nexthop->gate.ipv4.s_addr =
673 PIM_NET_INADDR_ANY;
674 }
675
676 break;
677 }
678
679 ifp = if_lookup_by_index(nexthop->ifindex, pim->vrf_id);
680 if (!ifp) {
681 if (PIM_DEBUG_PIM_NHT) {
682 char buf[NEXTHOP_STRLEN];
683 zlog_debug(
684 "%s: could not find interface for ifindex %d(%s) (addr %s)",
685 __PRETTY_FUNCTION__,
686 nexthop->ifindex,
687 pim->vrf->name,
688 nexthop2str(nexthop, buf,
689 sizeof(buf)));
690 }
691 nexthop_free(nexthop);
692 continue;
693 }
694
695 if (PIM_DEBUG_PIM_NHT) {
696 char p_str[PREFIX2STR_BUFFER];
697
698 prefix2str(&nhr.prefix, p_str, sizeof(p_str));
699 zlog_debug(
700 "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
701 __PRETTY_FUNCTION__, p_str,
702 pim->vrf->name, i + 1,
703 inet_ntoa(nexthop->gate.ipv4),
704 ifp->name, nexthop->type, nhr.distance,
705 nhr.metric);
706 }
707
708 if (!ifp->info) {
709 if (PIM_DEBUG_PIM_NHT) {
710 char buf[NEXTHOP_STRLEN];
711
712 zlog_debug(
713 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
714 __PRETTY_FUNCTION__, ifp->name,
715 pim->vrf->name,
716 nexthop->ifindex,
717 nexthop2str(nexthop, buf,
718 sizeof(buf)));
719 }
720 nexthop_free(nexthop);
721 continue;
722 }
723
724 if (nhlist_tail) {
725 nhlist_tail->next = nexthop;
726 nhlist_tail = nexthop;
727 } else {
728 nhlist_tail = nexthop;
729 nhlist_head = nexthop;
730 }
731 // Only keep track of nexthops which are PIM enabled.
732 pnc->nexthop_num++;
733 }
734 /* Reset existing pnc->nexthop before assigning new list */
735 nexthops_free(pnc->nexthop);
736 pnc->nexthop = nhlist_head;
737 if (pnc->nexthop_num) {
738 pnc->flags |= PIM_NEXTHOP_VALID;
739 pnc->distance = nhr.distance;
740 pnc->metric = nhr.metric;
741 }
742 } else {
743 pnc->flags &= ~PIM_NEXTHOP_VALID;
744 pnc->nexthop_num = nhr.nexthop_num;
745 nexthops_free(pnc->nexthop);
746 pnc->nexthop = NULL;
747 }
748
749 if (PIM_DEBUG_PIM_NHT) {
750 char buf[PREFIX2STR_BUFFER];
751 prefix2str(&nhr.prefix, buf, sizeof(buf));
752 zlog_debug(
753 "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
754 __PRETTY_FUNCTION__, buf, pim->vrf->name,
755 nhr.nexthop_num, pnc->nexthop_num, vrf_id,
756 pnc->upstream_hash->count, listcount(pnc->rp_list));
757 }
758
759 pim_rpf_set_refresh_time(pim);
760
761 if (listcount(pnc->rp_list))
762 pim_update_rp_nh(pim, pnc);
763 if (pnc->upstream_hash->count)
764 pim_update_upstream_nh(pim, pnc);
765
766 return 0;
767 }
768
769 int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
770 struct pim_nexthop *nexthop, struct in_addr addr,
771 struct prefix *src, struct prefix *grp,
772 int neighbor_needed)
773 {
774 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
775 struct pim_neighbor *nbr = NULL;
776 int num_ifindex;
777 struct interface *ifp;
778 int first_ifindex;
779 int found = 0;
780 uint8_t i = 0;
781 uint32_t hash_val = 0, mod_val = 0;
782
783 if (PIM_DEBUG_PIM_NHT) {
784 char addr_str[INET_ADDRSTRLEN];
785 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
786 zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
787 __PRETTY_FUNCTION__, addr_str, pim->vrf->name,
788 nexthop->last_lookup_time);
789 }
790
791 memset(nexthop_tab, 0,
792 sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
793 num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
794 addr, PIM_NEXTHOP_LOOKUP_MAX);
795 if (num_ifindex < 1) {
796 if (PIM_DEBUG_PIM_NHT) {
797 char addr_str[INET_ADDRSTRLEN];
798 pim_inet4_dump("<addr?>", addr, addr_str,
799 sizeof(addr_str));
800 zlog_warn(
801 "%s: could not find nexthop ifindex for address %s(%s)",
802 __PRETTY_FUNCTION__, addr_str, pim->vrf->name);
803 }
804 return 0;
805 }
806
807 // If PIM ECMP enable then choose ECMP path.
808 if (pim->ecmp_enable) {
809 hash_val = pim_compute_ecmp_hash(src, grp);
810 mod_val = hash_val % num_ifindex;
811 if (PIM_DEBUG_PIM_NHT_DETAIL)
812 zlog_debug("%s: hash_val %u mod_val %u",
813 __PRETTY_FUNCTION__, hash_val, mod_val);
814 }
815
816 while (!found && (i < num_ifindex)) {
817 first_ifindex = nexthop_tab[i].ifindex;
818
819 ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
820 if (!ifp) {
821 if (PIM_DEBUG_PIM_NHT) {
822 char addr_str[INET_ADDRSTRLEN];
823 pim_inet4_dump("<addr?>", addr, addr_str,
824 sizeof(addr_str));
825 zlog_debug(
826 "%s %s: could not find interface for ifindex %d (address %s(%s))",
827 __FILE__, __PRETTY_FUNCTION__,
828 first_ifindex, addr_str,
829 pim->vrf->name);
830 }
831 if (i == mod_val)
832 mod_val++;
833 i++;
834 continue;
835 }
836
837 if (!ifp->info) {
838 if (PIM_DEBUG_PIM_NHT) {
839 char addr_str[INET_ADDRSTRLEN];
840 pim_inet4_dump("<addr?>", addr, addr_str,
841 sizeof(addr_str));
842 zlog_debug(
843 "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
844 __PRETTY_FUNCTION__, ifp->name,
845 pim->vrf->name, first_ifindex,
846 addr_str);
847 }
848 if (i == mod_val)
849 mod_val++;
850 i++;
851 continue;
852 }
853 if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) {
854 nbr = pim_neighbor_find(
855 ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
856 if (PIM_DEBUG_PIM_NHT_DETAIL)
857 zlog_debug("ifp name: %s(%s), pim nbr: %p",
858 ifp->name, pim->vrf->name, nbr);
859 if (!nbr && !if_is_loopback(ifp)) {
860 if (i == mod_val)
861 mod_val++;
862 i++;
863 if (PIM_DEBUG_PIM_NHT) {
864 char addr_str[INET_ADDRSTRLEN];
865 pim_inet4_dump("<addr?>", addr,
866 addr_str,
867 sizeof(addr_str));
868 zlog_debug(
869 "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
870 __PRETTY_FUNCTION__, ifp->name,
871 pim->vrf->name, addr_str);
872 }
873 continue;
874 }
875 }
876
877 if (i == mod_val) {
878 if (PIM_DEBUG_PIM_NHT) {
879 char nexthop_str[PREFIX_STRLEN];
880 char addr_str[INET_ADDRSTRLEN];
881 pim_addr_dump("<nexthop?>",
882 &nexthop_tab[i].nexthop_addr,
883 nexthop_str, sizeof(nexthop_str));
884 pim_inet4_dump("<addr?>", addr, addr_str,
885 sizeof(addr_str));
886 zlog_debug(
887 "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
888 __PRETTY_FUNCTION__, nexthop_str,
889 addr_str, ifp->name, pim->vrf->name,
890 nexthop_tab[i].route_metric,
891 nexthop_tab[i].protocol_distance);
892 }
893 /* update nexthop data */
894 nexthop->interface = ifp;
895 nexthop->mrib_nexthop_addr =
896 nexthop_tab[i].nexthop_addr;
897 nexthop->mrib_metric_preference =
898 nexthop_tab[i].protocol_distance;
899 nexthop->mrib_route_metric =
900 nexthop_tab[i].route_metric;
901 nexthop->last_lookup = addr;
902 nexthop->last_lookup_time = pim_time_monotonic_usec();
903 nexthop->nbr = nbr;
904 found = 1;
905 }
906 i++;
907 }
908
909 if (found)
910 return 1;
911 else
912 return 0;
913 }
914
915 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
916 struct in_addr addr, struct prefix *src,
917 struct prefix *grp)
918 {
919 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
920 int num_ifindex;
921 int vif_index;
922 ifindex_t first_ifindex;
923 uint32_t hash_val = 0, mod_val = 0;
924
925 memset(nexthop_tab, 0,
926 sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
927 num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
928 addr, PIM_NEXTHOP_LOOKUP_MAX);
929 if (num_ifindex < 1) {
930 if (PIM_DEBUG_PIM_NHT) {
931 char addr_str[INET_ADDRSTRLEN];
932 pim_inet4_dump("<addr?>", addr, addr_str,
933 sizeof(addr_str));
934 zlog_debug(
935 "%s: could not find nexthop ifindex for address %s(%s)",
936 __PRETTY_FUNCTION__, addr_str, pim->vrf->name);
937 }
938 return -1;
939 }
940
941 // If PIM ECMP enable then choose ECMP path.
942 if (pim->ecmp_enable) {
943 hash_val = pim_compute_ecmp_hash(src, grp);
944 mod_val = hash_val % num_ifindex;
945 if (PIM_DEBUG_PIM_NHT_DETAIL)
946 zlog_debug("%s: hash_val %u mod_val %u",
947 __PRETTY_FUNCTION__, hash_val, mod_val);
948 }
949
950 first_ifindex = nexthop_tab[mod_val].ifindex;
951
952 if (PIM_DEBUG_PIM_NHT) {
953 char addr_str[INET_ADDRSTRLEN];
954 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
955 zlog_debug(
956 "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
957 __PRETTY_FUNCTION__, first_ifindex,
958 ifindex2ifname(first_ifindex, pim->vrf_id),
959 pim->vrf->name, addr_str);
960 }
961
962 vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex);
963
964 if (vif_index < 0) {
965 if (PIM_DEBUG_PIM_NHT) {
966 char addr_str[INET_ADDRSTRLEN];
967 pim_inet4_dump("<addr?>", addr, addr_str,
968 sizeof(addr_str));
969 zlog_debug(
970 "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
971 __PRETTY_FUNCTION__, vif_index, pim->vrf->name,
972 addr_str);
973 }
974 return -2;
975 }
976
977 return vif_index;
978 }