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