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