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