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