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