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