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