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