]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_nht.c
pimd: Add `debug pim nht` command
[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 */
64c86530 47void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
d62a17ae 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);
cf663ceb 61 zclient_create_header(s, command, pim->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 */
25bdac42
DS
155int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
156 struct pim_upstream *up, struct rp_info *rp,
d62a17ae 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
25bdac42 170 pnc = pim_nexthop_cache_find(pim, &rpf);
d62a17ae 171 if (!pnc) {
25bdac42 172 pnc = pim_nexthop_cache_add(pim, &rpf);
d62a17ae 173 if (pnc)
64c86530 174 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
d62a17ae 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) {
64c86530 249 pim_sendmsg_zebra_rnh(pim, zclient, pnc,
d62a17ae 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.*/
25b787a2 264int pim_update_rp_nh(struct pim_instance *pim, 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
25b787a2
DS
276 ret = pim_ecmp_nexthop_search(
277 pim, pnc, &rp_info->rp.source_nexthop,
278 &rp_info->rp.rpf_addr, &rp_info->group, 1);
d62a17ae 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*/
25b787a2 302void pim_resolve_upstream_nh(struct pim_instance *pim, 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));
25b787a2 309 if (!pim_find_or_track_nexthop(pim, nht_p, NULL, NULL, &pnc))
cb9c7c50
DS
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 =
25b787a2 317 if_lookup_by_index(nh_node->ifindex, pim->vrf_id);
cb9c7c50
DS
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.*/
cf663ceb
DS
337static int pim_update_upstream_nh(struct pim_instance *pim,
338 struct pim_nexthop_cache *pnc)
1bc98276 339{
d62a17ae 340 struct listnode *up_node;
341 struct listnode *ifnode;
342 struct listnode *up_nextnode;
343 struct listnode *node;
344 struct pim_upstream *up = NULL;
345 struct interface *ifp = NULL;
346 int vif_index = 0;
347
348 for (ALL_LIST_ELEMENTS(pnc->upstream_list, up_node, up_nextnode, up)) {
349 enum pim_rpf_result rpf_result;
350 struct pim_rpf old;
351
352 old.source_nexthop.interface = up->rpf.source_nexthop.interface;
2002dcdb 353 rpf_result = pim_rpf_update(pim, up, &old, 0);
d62a17ae 354 if (rpf_result == PIM_RPF_FAILURE)
355 continue;
356
357 /* update kernel multicast forwarding cache (MFC) */
358 if (up->channel_oil) {
359 ifindex_t ifindex =
360 up->rpf.source_nexthop.interface->ifindex;
7cfc7bcf
DS
361 vif_index =
362 pim_if_find_vifindex_by_ifindex(pim, ifindex);
d62a17ae 363 /* Pass Current selected NH vif index to mroute download
364 */
365 if (vif_index)
366 pim_scan_individual_oil(up->channel_oil,
367 vif_index);
368 else {
369 if (PIM_DEBUG_ZEBRA)
370 zlog_debug(
371 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
372 __PRETTY_FUNCTION__, up->sg_str,
373 up->rpf.source_nexthop
374 .interface->name);
375 }
376 }
377
378 if (rpf_result == PIM_RPF_CHANGED) {
379 struct pim_neighbor *nbr;
380
381 nbr = pim_neighbor_find(old.source_nexthop.interface,
382 old.rpf_addr.u.prefix4);
383 if (nbr)
384 pim_jp_agg_remove_group(nbr->upstream_jp_agg,
385 up);
386
387 /*
388 * We have detected a case where we might need to rescan
389 * the inherited o_list so do it.
390 */
391 if (up->channel_oil
392 && up->channel_oil->oil_inherited_rescan) {
9b29ea95 393 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 394 up->channel_oil->oil_inherited_rescan = 0;
395 }
396
397 if (up->join_state == PIM_UPSTREAM_JOINED) {
398 /*
399 * If we come up real fast we can be here
400 * where the mroute has not been installed
401 * so install it.
402 */
403 if (up->channel_oil
404 && !up->channel_oil->installed)
405 pim_mroute_add(up->channel_oil,
406 __PRETTY_FUNCTION__);
407
408 /*
409 RFC 4601: 4.5.7. Sending (S,G) Join/Prune
410 Messages
411
412 Transitions from Joined State
413
414 RPF'(S,G) changes not due to an Assert
415
416 The upstream (S,G) state machine remains in
417 Joined
418 state. Send Join(S,G) to the new upstream
419 neighbor, which is
420 the new value of RPF'(S,G). Send Prune(S,G)
421 to the old
422 upstream neighbor, which is the old value of
423 RPF'(S,G). Set
424 the Join Timer (JT) to expire after
425 t_periodic seconds.
426 */
427 pim_jp_agg_switch_interface(&old, &up->rpf, up);
428
429 pim_upstream_join_timer_restart(up, &old);
430 } /* up->join_state == PIM_UPSTREAM_JOINED */
431
432 /* FIXME can join_desired actually be changed by
433 pim_rpf_update()
434 returning PIM_RPF_CHANGED ? */
9b29ea95 435 pim_upstream_update_join_desired(pim, up);
d62a17ae 436
437 } /* PIM_RPF_CHANGED */
438
439 if (PIM_DEBUG_TRACE) {
440 zlog_debug("%s: NHT upstream %s old ifp %s new ifp %s",
441 __PRETTY_FUNCTION__, up->sg_str,
442 old.source_nexthop.interface->name,
443 up->rpf.source_nexthop.interface->name);
444 }
445 } /* for (pnc->upstream_list) */
446
25b787a2 447 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp))
d62a17ae 448 if (ifp->info) {
449 struct pim_interface *pim_ifp = ifp->info;
450 struct pim_iface_upstream_switch *us;
451
452 for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list,
453 node, us)) {
454 struct pim_rpf rpf;
455 rpf.source_nexthop.interface = ifp;
456 rpf.rpf_addr.u.prefix4 = us->address;
457 pim_joinprune_send(&rpf, us->us);
458 pim_jp_agg_clear_group(us->us);
459 }
460 }
461
462 return 0;
1bc98276
CS
463}
464
d62a17ae 465uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
633988a7 466{
d62a17ae 467 uint32_t hash_val;
468 uint32_t s = 0, g = 0;
469
470 if ((!src))
471 return 0;
472
473 switch (src->family) {
474 case AF_INET: {
475 s = src->u.prefix4.s_addr;
476 s = s == 0 ? 1 : s;
477 if (grp)
478 g = grp->u.prefix4.s_addr;
479 } break;
480 default:
481 break;
482 }
483
484 hash_val = jhash_2words(g, s, 101);
485 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
486 char buf[PREFIX2STR_BUFFER];
487 char bufg[PREFIX2STR_BUFFER];
488 prefix2str(src, buf, sizeof(buf));
489 if (grp)
490 prefix2str(grp, bufg, sizeof(bufg));
491 zlog_debug("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__,
492 buf, grp ? bufg : "", hash_val);
493 }
494 return hash_val;
633988a7
CS
495}
496
25b787a2
DS
497int pim_ecmp_nexthop_search(struct pim_instance *pim,
498 struct pim_nexthop_cache *pnc,
d62a17ae 499 struct pim_nexthop *nexthop, struct prefix *src,
500 struct prefix *grp, int neighbor_needed)
633988a7 501{
d62a17ae 502 struct pim_neighbor *nbr = NULL;
503 struct nexthop *nh_node = NULL;
504 ifindex_t first_ifindex;
505 struct interface *ifp = NULL;
506 uint32_t hash_val = 0, mod_val = 0;
507 uint8_t nh_iter = 0, found = 0;
508
509 if (!pnc || !pnc->nexthop_num || !nexthop)
cb9c7c50 510 return 0;
d62a17ae 511
512 // Current Nexthop is VALID, check to stay on the current path.
513 if (nexthop->interface && nexthop->interface->info
514 && nexthop->mrib_nexthop_addr.u.prefix4.s_addr
515 != PIM_NET_INADDR_ANY) {
516 /* User configured knob to explicitly switch
517 to new path is disabled or current path
518 metric is less than nexthop update.
519 */
520
521 if (qpim_ecmp_rebalance_enable == 0) {
522 uint8_t curr_route_valid = 0;
523 // Check if current nexthop is present in new updated
524 // Nexthop list.
525 // If the current nexthop is not valid, candidate to
526 // choose new Nexthop.
527 for (nh_node = pnc->nexthop; nh_node;
528 nh_node = nh_node->next)
529 curr_route_valid = (nexthop->interface->ifindex
530 == nh_node->ifindex);
531
532 if (curr_route_valid
533 && !pim_if_connected_to_source(nexthop->interface,
534 src->u.prefix4)) {
535 nbr = pim_neighbor_find(
536 nexthop->interface,
537 nexthop->mrib_nexthop_addr.u.prefix4);
538 if (!nbr
539 && !if_is_loopback(nexthop->interface)) {
540 if (PIM_DEBUG_TRACE)
541 zlog_debug(
542 "%s: current nexthop does not have nbr ",
543 __PRETTY_FUNCTION__);
544 } else {
545 if (PIM_DEBUG_TRACE) {
546 char src_str[INET_ADDRSTRLEN];
547 pim_inet4_dump("<addr?>",
548 src->u.prefix4,
549 src_str,
550 sizeof(src_str));
551 char grp_str[INET_ADDRSTRLEN];
552 pim_inet4_dump("<addr?>",
553 grp->u.prefix4,
554 grp_str,
555 sizeof(grp_str));
556 zlog_debug(
a895ac30 557 "%s: (%s,%s) current nexthop %s is valid, skipping new path selection",
d62a17ae 558 __PRETTY_FUNCTION__,
559 src_str, grp_str,
560 nexthop->interface->name);
561 }
562 return 0;
563 }
564 }
565 }
566 }
567 if (qpim_ecmp_enable) {
568 // PIM ECMP flag is enable then choose ECMP path.
569 hash_val = pim_compute_ecmp_hash(src, grp);
570 mod_val = hash_val % pnc->nexthop_num;
571 if (PIM_DEBUG_PIM_TRACE_DETAIL)
572 zlog_debug("%s: hash_val %u mod_val %u ",
573 __PRETTY_FUNCTION__, hash_val, mod_val);
574 }
575
576 for (nh_node = pnc->nexthop; nh_node && (found == 0);
577 nh_node = nh_node->next) {
578 first_ifindex = nh_node->ifindex;
25b787a2 579 ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
d62a17ae 580 if (!ifp) {
581 if (PIM_DEBUG_ZEBRA) {
582 char addr_str[INET_ADDRSTRLEN];
583 pim_inet4_dump("<addr?>", src->u.prefix4,
584 addr_str, sizeof(addr_str));
585 zlog_debug(
586 "%s %s: could not find interface for ifindex %d (address %s)",
587 __FILE__, __PRETTY_FUNCTION__,
588 first_ifindex, addr_str);
589 }
590 if (nh_iter == mod_val)
591 mod_val++; // Select nexthpath
592 nh_iter++;
593 continue;
594 }
595 if (!ifp->info) {
596 if (PIM_DEBUG_ZEBRA) {
597 char addr_str[INET_ADDRSTRLEN];
598 pim_inet4_dump("<addr?>", src->u.prefix4,
599 addr_str, sizeof(addr_str));
600 zlog_debug(
601 "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
602 __PRETTY_FUNCTION__, ifp->name,
603 first_ifindex, addr_str);
604 }
605 if (nh_iter == mod_val)
606 mod_val++; // Select nexthpath
607 nh_iter++;
608 continue;
609 }
610
611 if (neighbor_needed
612 && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
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",
616 ifp->name, nbr);
617 if (!nbr && !if_is_loopback(ifp)) {
618 if (PIM_DEBUG_ZEBRA)
619 zlog_debug(
620 "%s: pim nbr not found on input interface %s",
621 __PRETTY_FUNCTION__, ifp->name);
622 if (nh_iter == mod_val)
623 mod_val++; // Select nexthpath
624 nh_iter++;
625 continue;
626 }
627 }
628
629 if (nh_iter == mod_val) {
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 =
634 nh_node->gate.ipv4;
635 nexthop->mrib_metric_preference = pnc->distance;
636 nexthop->mrib_route_metric = pnc->metric;
637 nexthop->last_lookup = src->u.prefix4;
638 nexthop->last_lookup_time = pim_time_monotonic_usec();
639 nexthop->nbr = nbr;
640 found = 1;
641 if (PIM_DEBUG_ZEBRA) {
642 char buf[INET_ADDRSTRLEN];
643 char buf2[INET_ADDRSTRLEN];
644 char buf3[INET_ADDRSTRLEN];
645 pim_inet4_dump("<src?>", src->u.prefix4, buf2,
646 sizeof(buf2));
647 pim_inet4_dump("<grp?>", grp->u.prefix4, buf3,
648 sizeof(buf3));
649 pim_inet4_dump(
650 "<rpf?>",
651 nexthop->mrib_nexthop_addr.u.prefix4,
652 buf, sizeof(buf));
653 zlog_debug(
a895ac30 654 "%s: (%s,%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
d62a17ae 655 __PRETTY_FUNCTION__, buf2, buf3,
656 ifp->name, buf, mod_val, nh_iter,
657 qpim_ecmp_enable);
658 }
659 }
660 nh_iter++;
661 }
662
663 if (found)
cb9c7c50 664 return 1;
d62a17ae 665 else
cb9c7c50 666 return 0;
633988a7
CS
667}
668
d62a17ae 669/* This API is used to parse Registered address nexthop update coming from Zebra
670 */
671int pim_parse_nexthop_update(int command, struct zclient *zclient,
672 zebra_size_t length, vrf_id_t vrf_id)
1bc98276 673{
d62a17ae 674 struct stream *s;
675 struct prefix p;
676 struct nexthop *nexthop;
677 struct nexthop *nhlist_head = NULL;
678 struct nexthop *nhlist_tail = NULL;
679 uint32_t metric, distance;
680 u_char nexthop_num = 0;
681 int i;
682 struct pim_rpf rpf;
683 struct pim_nexthop_cache *pnc = NULL;
684 struct pim_neighbor *nbr = NULL;
685 struct interface *ifp = NULL;
686 struct interface *ifp1 = NULL;
687 struct pim_interface *pim_ifp = NULL;
688 char str[INET_ADDRSTRLEN];
cf663ceb
DS
689 struct vrf *vrf = vrf_lookup_by_id(vrf_id);
690 struct pim_instance *pim = vrf->info;
d62a17ae 691
692 s = zclient->ibuf;
693 memset(&p, 0, sizeof(struct prefix));
694 p.family = stream_getw(s);
695 p.prefixlen = stream_getc(s);
696 switch (p.family) {
697 case AF_INET:
698 p.u.prefix4.s_addr = stream_get_ipv4(s);
699 break;
700 case AF_INET6:
701 stream_get(&p.u.prefix6, s, 16);
702 break;
703 default:
704 break;
705 }
706
707 if (command == ZEBRA_NEXTHOP_UPDATE) {
708 rpf.rpf_addr.family = p.family;
709 rpf.rpf_addr.prefixlen = p.prefixlen;
710 rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr;
25b787a2 711 pnc = pim_nexthop_cache_find(pim, &rpf);
d62a17ae 712 if (!pnc) {
713 if (PIM_DEBUG_TRACE) {
714 char buf[PREFIX2STR_BUFFER];
715 prefix2str(&rpf.rpf_addr, buf, sizeof(buf));
716 zlog_debug(
717 "%s: Skipping NHT update, addr %s is not in local cached DB.",
718 __PRETTY_FUNCTION__, buf);
719 }
720 return 0;
721 }
722 } else {
723 /*
724 * We do not currently handle ZEBRA_IMPORT_CHECK_UPDATE
725 */
726 return 0;
727 }
728
729 pnc->last_update = pim_time_monotonic_usec();
730 distance = stream_getc(s);
731 metric = stream_getl(s);
732 nexthop_num = stream_getc(s);
733
734 if (nexthop_num) {
735 pnc->nexthop_num = 0; // Only increment for pim enabled rpf.
736
737 for (i = 0; i < nexthop_num; i++) {
738 nexthop = nexthop_new();
739 nexthop->type = stream_getc(s);
740 switch (nexthop->type) {
741 case NEXTHOP_TYPE_IPV4:
742 nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
743 nexthop->ifindex = stream_getl(s);
744 break;
745 case NEXTHOP_TYPE_IFINDEX:
746 nexthop->ifindex = stream_getl(s);
747 break;
748 case NEXTHOP_TYPE_IPV4_IFINDEX:
749 nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
750 nexthop->ifindex = stream_getl(s);
751 break;
752 case NEXTHOP_TYPE_IPV6:
753 stream_get(&nexthop->gate.ipv6, s, 16);
754 break;
755 case NEXTHOP_TYPE_IPV6_IFINDEX:
756 stream_get(&nexthop->gate.ipv6, s, 16);
757 nexthop->ifindex = stream_getl(s);
758 ifp1 = if_lookup_by_index(nexthop->ifindex,
25b787a2 759 pim->vrf_id);
d62a17ae 760 nbr = pim_neighbor_find_if(ifp1);
761 /* Overwrite with Nbr address as NH addr */
762 if (nbr) {
763 nexthop->gate.ipv4 = nbr->source_addr;
764 if (PIM_DEBUG_TRACE) {
765 pim_inet4_dump("<nht_nbr?>",
766 nbr->source_addr,
767 str,
768 sizeof(str));
769 zlog_debug(
770 "%s: NHT using pim nbr addr %s interface %s as rpf",
771 __PRETTY_FUNCTION__,
772 str, ifp1->name);
773 }
774 } else {
775 if (PIM_DEBUG_TRACE) {
776 pim_ifp = ifp1->info;
777 zlog_debug(
778 "%s: NHT pim nbr not found on interface %s nbr count:%d ",
779 __PRETTY_FUNCTION__,
780 ifp1->name,
01460fbc
DS
781 pim_ifp
782 ? pim_ifp->pim_neighbor_list
783 ->count
784 : 0);
d62a17ae 785 }
786 // Mark nexthop address to 0 until PIM
787 // Nbr is resolved.
788 nexthop->gate.ipv4.s_addr =
789 PIM_NET_INADDR_ANY;
790 }
791
792 break;
793 default:
794 /* do nothing */
795 break;
796 }
797
798 if (PIM_DEBUG_TRACE) {
799 char p_str[PREFIX2STR_BUFFER];
800 prefix2str(&p, p_str, sizeof(p_str));
801 zlog_debug(
802 "%s: NHT addr %s %d-nhop via %s type %d distance:%u metric:%u ",
803 __PRETTY_FUNCTION__, p_str, i + 1,
804 inet_ntoa(nexthop->gate.ipv4),
805 nexthop->type, distance, metric);
806 }
807
25b787a2 808 ifp = if_lookup_by_index(nexthop->ifindex, pim->vrf_id);
d62a17ae 809 if (!ifp) {
810 if (PIM_DEBUG_ZEBRA) {
811 char buf[NEXTHOP_STRLEN];
812 zlog_debug(
813 "%s: could not find interface for ifindex %d (addr %s)",
814 __PRETTY_FUNCTION__,
815 nexthop->ifindex,
816 nexthop2str(nexthop, buf,
817 sizeof(buf)));
818 }
819 nexthop_free(nexthop);
820 continue;
821 }
822
823 if (!ifp->info) {
824 if (PIM_DEBUG_ZEBRA) {
825 char buf[NEXTHOP_STRLEN];
826 zlog_debug(
827 "%s: multicast not enabled on input interface %s (ifindex=%d, addr %s)",
828 __PRETTY_FUNCTION__, ifp->name,
829 nexthop->ifindex,
830 nexthop2str(nexthop, buf,
831 sizeof(buf)));
832 }
833 nexthop_free(nexthop);
834 continue;
835 }
836
837 if (nhlist_tail) {
838 nhlist_tail->next = nexthop;
839 nhlist_tail = nexthop;
840 } else {
841 nhlist_tail = nexthop;
842 nhlist_head = nexthop;
843 }
844 // Only keep track of nexthops which are PIM enabled.
845 pnc->nexthop_num++;
846 }
847 /* Reset existing pnc->nexthop before assigning new list */
848 nexthops_free(pnc->nexthop);
849 pnc->nexthop = nhlist_head;
850 if (pnc->nexthop_num) {
851 pnc->flags |= PIM_NEXTHOP_VALID;
852 pnc->distance = distance;
853 pnc->metric = metric;
854 }
855 } else {
856 pnc->flags &= ~PIM_NEXTHOP_VALID;
857 pnc->nexthop_num = nexthop_num;
858 nexthops_free(pnc->nexthop);
859 pnc->nexthop = NULL;
860 }
861
862 if (PIM_DEBUG_TRACE) {
863 char buf[PREFIX2STR_BUFFER];
864 prefix2str(&p, buf, sizeof(buf));
865 zlog_debug(
866 "%s: NHT Update for %s num_nh %d num_pim_nh %d vrf:%d up %d rp %d",
867 __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num,
868 vrf_id, listcount(pnc->upstream_list),
869 listcount(pnc->rp_list));
870 }
871
872 pim_rpf_set_refresh_time();
873
874 if (listcount(pnc->rp_list))
25b787a2 875 pim_update_rp_nh(pim, pnc);
d62a17ae 876 if (listcount(pnc->upstream_list))
cf663ceb 877 pim_update_upstream_nh(pim, pnc);
d62a17ae 878
879 return 0;
1bc98276 880}
633988a7 881
25b787a2
DS
882int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
883 struct pim_nexthop *nexthop, struct in_addr addr,
d62a17ae 884 struct prefix *src, struct prefix *grp,
885 int neighbor_needed)
633988a7 886{
d62a17ae 887 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
888 struct pim_neighbor *nbr = NULL;
889 int num_ifindex;
890 struct interface *ifp;
891 int first_ifindex;
892 int found = 0;
893 uint8_t i = 0;
894 uint32_t hash_val = 0, mod_val = 0;
895
896 if (PIM_DEBUG_TRACE) {
897 char addr_str[INET_ADDRSTRLEN];
898 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
899 zlog_debug("%s: Looking up: %s, last lookup time: %lld",
900 __PRETTY_FUNCTION__, addr_str,
901 nexthop->last_lookup_time);
902 }
903
904 memset(nexthop_tab, 0,
905 sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
71edad0f
DS
906 num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
907 addr, PIM_NEXTHOP_LOOKUP_MAX);
d62a17ae 908 if (num_ifindex < 1) {
909 char addr_str[INET_ADDRSTRLEN];
910 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
911 zlog_warn(
912 "%s %s: could not find nexthop ifindex for address %s",
913 __FILE__, __PRETTY_FUNCTION__, addr_str);
cb9c7c50 914 return 0;
d62a17ae 915 }
916
917 // If PIM ECMP enable then choose ECMP path.
918 if (qpim_ecmp_enable) {
919 hash_val = pim_compute_ecmp_hash(src, grp);
920 mod_val = hash_val % num_ifindex;
921 if (PIM_DEBUG_PIM_TRACE_DETAIL)
922 zlog_debug("%s: hash_val %u mod_val %u",
923 __PRETTY_FUNCTION__, hash_val, mod_val);
924 }
925
926 while (!found && (i < num_ifindex)) {
927 first_ifindex = nexthop_tab[i].ifindex;
928
25b787a2 929 ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
d62a17ae 930 if (!ifp) {
931 if (PIM_DEBUG_ZEBRA) {
932 char addr_str[INET_ADDRSTRLEN];
933 pim_inet4_dump("<addr?>", addr, addr_str,
934 sizeof(addr_str));
935 zlog_debug(
936 "%s %s: could not find interface for ifindex %d (address %s)",
937 __FILE__, __PRETTY_FUNCTION__,
938 first_ifindex, addr_str);
939 }
940 if (i == mod_val)
941 mod_val++;
942 i++;
943 continue;
944 }
945
946 if (!ifp->info) {
947 if (PIM_DEBUG_ZEBRA) {
948 char addr_str[INET_ADDRSTRLEN];
949 pim_inet4_dump("<addr?>", addr, addr_str,
950 sizeof(addr_str));
951 zlog_debug(
952 "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
953 __PRETTY_FUNCTION__, ifp->name,
954 first_ifindex, addr_str);
955 }
956 if (i == mod_val)
957 mod_val++;
958 i++;
959 continue;
960 }
961 if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) {
962 nbr = pim_neighbor_find(
963 ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
964 if (PIM_DEBUG_PIM_TRACE_DETAIL)
965 zlog_debug("ifp name: %s, pim nbr: %p",
966 ifp->name, nbr);
967 if (!nbr && !if_is_loopback(ifp)) {
968 if (i == mod_val)
969 mod_val++;
970 i++;
971 if (PIM_DEBUG_ZEBRA) {
972 char addr_str[INET_ADDRSTRLEN];
973 pim_inet4_dump("<addr?>", addr,
974 addr_str,
975 sizeof(addr_str));
976 zlog_debug(
977 "%s: NBR not found on input interface %s (RPF for source %s)",
978 __PRETTY_FUNCTION__, ifp->name,
979 addr_str);
980 }
981 continue;
982 }
983 }
984
985 if (i == mod_val) {
986 if (PIM_DEBUG_ZEBRA) {
987 char nexthop_str[PREFIX_STRLEN];
988 char addr_str[INET_ADDRSTRLEN];
989 pim_addr_dump("<nexthop?>",
990 &nexthop_tab[i].nexthop_addr,
991 nexthop_str, sizeof(nexthop_str));
992 pim_inet4_dump("<addr?>", addr, addr_str,
993 sizeof(addr_str));
994 zlog_debug(
995 "%s %s: found nhop %s for addr %s interface %s metric %d dist %d",
996 __FILE__, __PRETTY_FUNCTION__,
997 nexthop_str, addr_str, ifp->name,
998 nexthop_tab[i].route_metric,
999 nexthop_tab[i].protocol_distance);
1000 }
1001 /* update nextop data */
1002 nexthop->interface = ifp;
1003 nexthop->mrib_nexthop_addr =
1004 nexthop_tab[i].nexthop_addr;
1005 nexthop->mrib_metric_preference =
1006 nexthop_tab[i].protocol_distance;
1007 nexthop->mrib_route_metric =
1008 nexthop_tab[i].route_metric;
1009 nexthop->last_lookup = addr;
1010 nexthop->last_lookup_time = pim_time_monotonic_usec();
1011 nexthop->nbr = nbr;
1012 found = 1;
1013 }
1014 i++;
1015 }
cb9c7c50 1016
d62a17ae 1017 if (found)
cb9c7c50 1018 return 1;
d62a17ae 1019 else
cb9c7c50 1020 return 0;
633988a7 1021}
815c33c9 1022
25b787a2
DS
1023int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
1024 struct in_addr addr, struct prefix *src,
d62a17ae 1025 struct prefix *grp)
815c33c9 1026{
d62a17ae 1027 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
1028 int num_ifindex;
1029 int vif_index;
1030 ifindex_t first_ifindex;
1031 uint32_t hash_val = 0, mod_val = 0;
1032
1033 memset(nexthop_tab, 0,
1034 sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
71edad0f
DS
1035 num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
1036 addr, PIM_NEXTHOP_LOOKUP_MAX);
d62a17ae 1037 if (num_ifindex < 1) {
1038 if (PIM_DEBUG_ZEBRA) {
1039 char addr_str[INET_ADDRSTRLEN];
1040 pim_inet4_dump("<addr?>", addr, addr_str,
1041 sizeof(addr_str));
1042 zlog_debug(
1043 "%s %s: could not find nexthop ifindex for address %s",
1044 __FILE__, __PRETTY_FUNCTION__, addr_str);
1045 }
1046 return -1;
1047 }
1048
1049 // If PIM ECMP enable then choose ECMP path.
1050 if (qpim_ecmp_enable) {
1051 hash_val = pim_compute_ecmp_hash(src, grp);
1052 mod_val = hash_val % num_ifindex;
1053 if (PIM_DEBUG_PIM_TRACE_DETAIL)
1054 zlog_debug("%s: hash_val %u mod_val %u",
1055 __PRETTY_FUNCTION__, hash_val, mod_val);
1056 }
1057
1058 first_ifindex = nexthop_tab[mod_val].ifindex;
1059
1060 if (PIM_DEBUG_ZEBRA) {
1061 char addr_str[INET_ADDRSTRLEN];
1062 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
1063 zlog_debug(
1064 "%s %s: found nexthop ifindex=%d (interface %s) for address %s",
1065 __FILE__, __PRETTY_FUNCTION__, first_ifindex,
25b787a2 1066 ifindex2ifname(first_ifindex, pim->vrf_id), addr_str);
d62a17ae 1067 }
1068
7cfc7bcf 1069 vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex);
d62a17ae 1070
1071 if (vif_index < 0) {
1072 if (PIM_DEBUG_ZEBRA) {
1073 char addr_str[INET_ADDRSTRLEN];
1074 pim_inet4_dump("<addr?>", addr, addr_str,
1075 sizeof(addr_str));
1076 zlog_debug(
1077 "%s %s: low vif_index=%d < 1 nexthop for address %s",
1078 __FILE__, __PRETTY_FUNCTION__, vif_index,
1079 addr_str);
1080 }
1081 return -2;
1082 }
1083
1084 return vif_index;
815c33c9 1085}