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