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