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