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