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