]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
Merge pull request #6379 from donaldsharp/ip_as_path_removal_really
[mirror_frr.git] / zebra / zebra_nhg.c
CommitLineData
ad28e79a
SW
1/* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 * Stephen Worley
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23#include <zebra.h>
24
25#include "lib/nexthop.h"
50d89650 26#include "lib/nexthop_group_private.h"
ad28e79a 27#include "lib/routemap.h"
b43434ad 28#include "lib/mpls.h"
69171da2 29#include "lib/jhash.h"
51d80884 30#include "lib/debug.h"
ad28e79a
SW
31
32#include "zebra/connected.h"
33#include "zebra/debug.h"
34#include "zebra/zebra_router.h"
5948f013 35#include "zebra/zebra_nhg_private.h"
ad28e79a
SW
36#include "zebra/zebra_rnh.h"
37#include "zebra/zebra_routemap.h"
51d80884
SW
38#include "zebra/zebra_memory.h"
39#include "zebra/zserv.h"
ad28e79a 40#include "zebra/rt.h"
d9f5b2f5 41#include "zebra_errors.h"
0c8215cb 42#include "zebra_dplane.h"
fe593b78 43#include "zebra/interface.h"
d9f5b2f5 44
51d80884 45DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
a15d4c00 46DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
e22e8001 47DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
0c8215cb 48
38e40db1
SW
49/* id counter to keep in sync with kernel */
50uint32_t id_counter;
51
7c99d51b
MS
52/* */
53static bool g_nexthops_enabled = true;
54
cb86eba3
MS
55static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
56 afi_t afi);
37c6708b 57static void depends_add(struct nhg_connected_tree_head *head,
5657e7e9 58 struct nhg_hash_entry *depend);
38e40db1
SW
59static struct nhg_hash_entry *
60depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
61 afi_t afi);
62static struct nhg_hash_entry *
63depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
37c6708b 64static void depends_decrement_free(struct nhg_connected_tree_head *head);
0c8215cb 65
1d48702e
MS
66static struct nhg_backup_info *
67nhg_backup_copy(const struct nhg_backup_info *orig);
68
e22e8001 69
5948f013 70static void nhg_connected_free(struct nhg_connected *dep)
0c8215cb 71{
a15d4c00 72 XFREE(MTYPE_NHG_CONNECTED, dep);
0c8215cb
SW
73}
74
5948f013 75static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
0c8215cb 76{
a15d4c00 77 struct nhg_connected *new = NULL;
0c8215cb 78
a15d4c00 79 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
0c8215cb
SW
80 new->nhe = nhe;
81
82 return new;
83}
84
37c6708b 85void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
0c8215cb 86{
a15d4c00 87 struct nhg_connected *rb_node_dep = NULL;
0c8215cb 88
37c6708b 89 if (!nhg_connected_tree_is_empty(head)) {
fec211ad 90 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
37c6708b 91 nhg_connected_tree_del(head, rb_node_dep);
fe593b78
SW
92 nhg_connected_free(rb_node_dep);
93 }
0c8215cb 94 }
0c8215cb
SW
95}
96
37c6708b 97bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
0c8215cb 98{
fec211ad 99 return nhg_connected_tree_count(head) ? false : true;
0c8215cb
SW
100}
101
98cda54a 102struct nhg_connected *
37c6708b 103nhg_connected_tree_root(struct nhg_connected_tree_head *head)
98cda54a 104{
37c6708b 105 return nhg_connected_tree_first(head);
98cda54a
SW
106}
107
5bf15faa
SW
108struct nhg_hash_entry *
109nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
110 struct nhg_hash_entry *depend)
0c8215cb 111{
a15d4c00 112 struct nhg_connected lookup = {};
085304dc 113 struct nhg_connected *remove = NULL;
5bf15faa 114 struct nhg_hash_entry *removed_nhe;
0c8215cb
SW
115
116 lookup.nhe = depend;
3119f6a1 117
085304dc 118 /* Lookup to find the element, then remove it */
37c6708b 119 remove = nhg_connected_tree_find(head, &lookup);
085304dc 120 if (remove)
5bf15faa
SW
121 /* Re-returning here just in case this API changes..
122 * the _del list api's are a bit undefined at the moment.
123 *
124 * So hopefully returning here will make it fail if the api
125 * changes to something different than currently expected.
126 */
127 remove = nhg_connected_tree_del(head, remove);
128
129 /* If the entry was sucessfully removed, free the 'connected` struct */
130 if (remove) {
131 removed_nhe = remove->nhe;
085304dc 132 nhg_connected_free(remove);
5bf15faa
SW
133 return removed_nhe;
134 }
135
136 return NULL;
3119f6a1
SW
137}
138
5bf15faa
SW
139/* Assuming UNIQUE RB tree. If this changes, assumptions here about
140 * insertion need to change.
141 */
142struct nhg_hash_entry *
143nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
144 struct nhg_hash_entry *depend)
3119f6a1 145{
a15d4c00 146 struct nhg_connected *new = NULL;
0c8215cb 147
a15d4c00 148 new = nhg_connected_new(depend);
0c8215cb 149
5bf15faa
SW
150 /* On success, NULL will be returned from the
151 * RB code.
152 */
153 if (new && (nhg_connected_tree_add(head, new) == NULL))
154 return NULL;
155
156 /* If it wasn't successful, it must be a duplicate. We enforce the
157 * unique property for the `nhg_connected` tree.
158 */
159 nhg_connected_free(new);
160
161 return depend;
3119f6a1
SW
162}
163
37c6708b
SW
164static void
165nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
32e29e79
SW
166{
167 struct nhg_connected *rb_node_dep = NULL;
32e29e79 168
fec211ad 169 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
32e29e79
SW
170 zebra_nhg_decrement_ref(rb_node_dep->nhe);
171 }
172}
173
37c6708b
SW
174static void
175nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
32e29e79
SW
176{
177 struct nhg_connected *rb_node_dep = NULL;
178
fec211ad 179 frr_each(nhg_connected_tree, head, rb_node_dep) {
32e29e79
SW
180 zebra_nhg_increment_ref(rb_node_dep->nhe);
181 }
182}
183
98cda54a
SW
184struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
185{
186 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
187 && !zebra_nhg_depends_is_empty(nhe)) {
37c6708b 188 nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
98cda54a
SW
189 return zebra_nhg_resolve(nhe);
190 }
191
192 return nhe;
193}
194
fe593b78 195unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
a15d4c00 196{
37c6708b 197 return nhg_connected_tree_count(&nhe->nhg_depends);
a15d4c00
SW
198}
199
fe593b78 200bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
a15d4c00 201{
37c6708b 202 return nhg_connected_tree_is_empty(&nhe->nhg_depends);
a15d4c00
SW
203}
204
5948f013
SW
205static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
206 struct nhg_hash_entry *depend)
3119f6a1 207{
37c6708b 208 nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
3119f6a1
SW
209}
210
5948f013 211static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
148a0103 212{
37c6708b 213 nhg_connected_tree_init(&nhe->nhg_depends);
148a0103
SW
214}
215
fe593b78
SW
216unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
217{
37c6708b 218 return nhg_connected_tree_count(&nhe->nhg_dependents);
fe593b78
SW
219}
220
5948f013 221
fe593b78
SW
222bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
223{
37c6708b 224 return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
fe593b78
SW
225}
226
5948f013
SW
227static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
228 struct nhg_hash_entry *dependent)
fe593b78 229{
37c6708b 230 nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
fe593b78
SW
231}
232
5948f013
SW
233static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
234 struct nhg_hash_entry *dependent)
fe593b78 235{
37c6708b 236 nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
fe593b78
SW
237}
238
5948f013 239static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
fe593b78 240{
37c6708b 241 nhg_connected_tree_init(&nhe->nhg_dependents);
fe593b78
SW
242}
243
21615102
SW
244/* Release this nhe from anything depending on it */
245static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
246{
80286aa5 247 struct nhg_connected *rb_node_dep = NULL;
21615102 248
80286aa5
SW
249 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
250 zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
251 /* recheck validity of the dependent */
252 zebra_nhg_check_valid(rb_node_dep->nhe);
21615102
SW
253 }
254}
255
5948f013
SW
256/* Release this nhe from anything that it depends on */
257static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
258{
259 if (!zebra_nhg_depends_is_empty(nhe)) {
260 struct nhg_connected *rb_node_dep = NULL;
261
262 frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
263 rb_node_dep) {
264 zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
265 }
266 }
267}
268
269
d9f5b2f5
SW
270struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
271{
0c8215cb 272 struct nhg_hash_entry lookup = {};
d9f5b2f5
SW
273
274 lookup.id = id;
275 return hash_lookup(zrouter.nhgs_id, &lookup);
276}
277
5948f013 278static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
d9f5b2f5
SW
279{
280 if (hash_lookup(zrouter.nhgs_id, nhe)) {
281 flog_err(
282 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
283 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
284 nhe->id);
285 return -1;
286 }
287
288 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
289
290 return 0;
291}
ad28e79a 292
5948f013
SW
293static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
294{
295 nhe->ifp = ifp;
296 if_nhg_dependents_add(ifp, nhe);
297}
298
38e40db1
SW
299static void
300zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
377e29f7 301 struct nhg_connected_tree_head *nhg_depends)
4e49c8b8 302{
a15d4c00
SW
303 struct nhg_connected *rb_node_dep = NULL;
304
38e40db1
SW
305 /* This has been allocated higher above in the stack. Could probably
306 * re-allocate and free the old stuff but just using the same memory
307 * for now. Otherwise, their might be a time trade-off for repeated
308 * alloc/frees as startup.
309 */
377e29f7 310 nhe->nhg_depends = *nhg_depends;
4e49c8b8 311
a15d4c00 312 /* Attach backpointer to anything that it depends on */
fe593b78 313 zebra_nhg_dependents_init(nhe);
a15d4c00 314 if (!zebra_nhg_depends_is_empty(nhe)) {
fec211ad 315 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
377e29f7
MS
316 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
317 zlog_debug("%s: nhe %p (%u), dep %p (%u)",
318 __func__, nhe, nhe->id,
319 rb_node_dep->nhe,
320 rb_node_dep->nhe->id);
321
a15d4c00
SW
322 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
323 }
324 }
377e29f7 325}
4e49c8b8 326
377e29f7
MS
327/* Init an nhe, for use in a hash lookup for example */
328void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
329 const struct nexthop *nh)
330{
331 memset(nhe, 0, sizeof(struct nhg_hash_entry));
332 nhe->vrf_id = VRF_DEFAULT;
333 nhe->type = ZEBRA_ROUTE_NHG;
334 nhe->afi = AFI_UNSPEC;
7b683a96 335
377e29f7
MS
336 /* There are some special rules that apply to groups representing
337 * a single nexthop.
338 */
339 if (nh && (nh->next == NULL)) {
340 switch (nh->type) {
341 case (NEXTHOP_TYPE_IFINDEX):
342 case (NEXTHOP_TYPE_BLACKHOLE):
343 /*
344 * This switch case handles setting the afi different
345 * for ipv4/v6 routes. Ifindex/blackhole nexthop
346 * objects cannot be ambiguous, they must be Address
347 * Family specific. If we get here, we will either use
348 * the AF of the route, or the one we got passed from
349 * here from the kernel.
350 */
351 nhe->afi = afi;
352 break;
353 case (NEXTHOP_TYPE_IPV4_IFINDEX):
354 case (NEXTHOP_TYPE_IPV4):
355 nhe->afi = AFI_IP;
356 break;
357 case (NEXTHOP_TYPE_IPV6_IFINDEX):
358 case (NEXTHOP_TYPE_IPV6):
359 nhe->afi = AFI_IP6;
360 break;
361 }
7b683a96 362 }
38e40db1
SW
363}
364
0eb97b86 365struct nhg_hash_entry *zebra_nhg_alloc(void)
38e40db1
SW
366{
367 struct nhg_hash_entry *nhe;
368
369 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
370
0eb97b86
MS
371 return nhe;
372}
373
1d48702e 374static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *orig,
0eb97b86
MS
375 uint32_t id)
376{
377 struct nhg_hash_entry *nhe;
378
379 nhe = zebra_nhg_alloc();
380
38e40db1
SW
381 nhe->id = id;
382
1d48702e 383 nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
38e40db1 384
1d48702e
MS
385 nhe->vrf_id = orig->vrf_id;
386 nhe->afi = orig->afi;
387 nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
38e40db1
SW
388 nhe->refcnt = 0;
389 nhe->dplane_ref = zebra_router_get_next_sequence();
390
1d48702e
MS
391 /* Copy backup info also, if present */
392 if (orig->backup_info)
393 nhe->backup_info = nhg_backup_copy(orig->backup_info);
394
38e40db1
SW
395 return nhe;
396}
397
398/* Allocation via hash handler */
399static void *zebra_nhg_hash_alloc(void *arg)
400{
401 struct nhg_hash_entry *nhe = NULL;
402 struct nhg_hash_entry *copy = arg;
7b683a96 403
38e40db1 404 nhe = zebra_nhg_copy(copy, copy->id);
9ef49038
SW
405
406 /* Mark duplicate nexthops in a group at creation time. */
c415d895 407 nexthop_group_mark_duplicates(&(nhe->nhg));
9ef49038 408
377e29f7
MS
409 zebra_nhg_connect_depends(nhe, &(copy->nhg_depends));
410
411 /* Add the ifp now if it's not a group or recursive and has ifindex */
412 if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
413 && nhe->nhg.nexthop->ifindex) {
414 struct interface *ifp = NULL;
415
416 ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
417 nhe->nhg.nexthop->vrf_id);
418 if (ifp)
419 zebra_nhg_set_if(nhe, ifp);
420 else
421 flog_err(
422 EC_ZEBRA_IF_LOOKUP_FAILED,
423 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
424 nhe->nhg.nexthop->ifindex,
425 nhe->nhg.nexthop->vrf_id, nhe->id);
426 }
427
d9f5b2f5
SW
428 zebra_nhg_insert_id(nhe);
429
4e49c8b8
DS
430 return nhe;
431}
432
4e49c8b8
DS
433uint32_t zebra_nhg_hash_key(const void *arg)
434{
435 const struct nhg_hash_entry *nhe = arg;
1d48702e
MS
436 uint32_t val, key = 0x5a351234;
437
438 val = nexthop_group_hash(&(nhe->nhg));
439 if (nhe->backup_info) {
440 val = jhash_2words(val,
441 nexthop_group_hash(
442 &(nhe->backup_info->nhe->nhg)),
443 key);
444 }
d9f5b2f5 445
1d48702e 446 key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
d9f5b2f5 447
d9f5b2f5 448 return key;
4e49c8b8
DS
449}
450
a95b8020
SW
451uint32_t zebra_nhg_id_key(const void *arg)
452{
453 const struct nhg_hash_entry *nhe = arg;
454
455 return nhe->id;
456}
457
1d48702e
MS
458/* Helper with common nhg/nhe nexthop comparison logic */
459static bool nhg_compare_nexthops(const struct nexthop *nh1,
460 const struct nexthop *nh2)
461{
f924db49 462 assert(nh1 != NULL && nh2 != NULL);
1d48702e
MS
463
464 /*
465 * We have to check the active flag of each individual one,
466 * not just the overall active_num. This solves the special case
467 * issue of a route with a nexthop group with one nexthop
468 * resolving to itself and thus marking it inactive. If we
469 * have two different routes each wanting to mark a different
470 * nexthop inactive, they need to hash to two different groups.
471 *
472 * If we just hashed on num_active, they would hash the same
473 * which is incorrect.
474 *
475 * ex)
476 * 1.1.1.0/24
477 * -> 1.1.1.1 dummy1 (inactive)
478 * -> 1.1.2.1 dummy2
479 *
480 * 1.1.2.0/24
481 * -> 1.1.1.1 dummy1
482 * -> 1.1.2.1 dummy2 (inactive)
483 *
484 * Without checking each individual one, they would hash to
485 * the same group and both have 1.1.1.1 dummy1 marked inactive.
486 *
487 */
488 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE)
489 != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
490 return false;
491
492 if (!nexthop_same(nh1, nh2))
493 return false;
494
495 return true;
496}
497
4e49c8b8
DS
498bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
499{
500 const struct nhg_hash_entry *nhe1 = arg1;
501 const struct nhg_hash_entry *nhe2 = arg2;
148813c2
SW
502 struct nexthop *nexthop1;
503 struct nexthop *nexthop2;
4e49c8b8 504
98cda54a
SW
505 /* No matter what if they equal IDs, assume equal */
506 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
507 return true;
508
4e49c8b8
DS
509 if (nhe1->vrf_id != nhe2->vrf_id)
510 return false;
511
77b76fc9
SW
512 if (nhe1->afi != nhe2->afi)
513 return false;
514
1d48702e 515 /* Nexthops should be in-order, so we simply compare them in-place */
c415d895 516 for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
f924db49 517 nexthop1 && nexthop2;
148813c2 518 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
148813c2 519
1d48702e 520 if (!nhg_compare_nexthops(nexthop1, nexthop2))
148813c2 521 return false;
1d48702e 522 }
148813c2 523
f924db49
MS
524 /* Check for unequal list lengths */
525 if (nexthop1 || nexthop2)
526 return false;
527
1d48702e
MS
528 /* If there's no backup info, comparison is done. */
529 if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
530 return true;
531
532 /* Compare backup info also - test the easy things first */
533 if (nhe1->backup_info && (nhe2->backup_info == NULL))
534 return false;
535 if (nhe2->backup_info && (nhe1->backup_info == NULL))
536 return false;
537
538 /* Compare number of backups before actually comparing any */
539 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
540 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
541 nexthop1 && nexthop2;
542 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
543 ;
544 }
545
546 /* Did we find the end of one list before the other? */
547 if (nexthop1 || nexthop2)
548 return false;
549
550 /* Have to compare the backup nexthops */
551 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
552 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
f924db49 553 nexthop1 && nexthop2;
1d48702e 554 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
148813c2 555
1d48702e 556 if (!nhg_compare_nexthops(nexthop1, nexthop2))
148813c2
SW
557 return false;
558 }
e4ac313b 559
4e49c8b8
DS
560 return true;
561}
562
d9f5b2f5 563bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 564{
d9f5b2f5
SW
565 const struct nhg_hash_entry *nhe1 = arg1;
566 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 567
d9f5b2f5
SW
568 return nhe1->id == nhe2->id;
569}
4e49c8b8 570
1b366e63
SW
571static int zebra_nhg_process_grp(struct nexthop_group *nhg,
572 struct nhg_connected_tree_head *depends,
573 struct nh_grp *grp, uint8_t count)
e22e8001 574{
37c6708b 575 nhg_connected_tree_init(depends);
e22e8001
SW
576
577 for (int i = 0; i < count; i++) {
578 struct nhg_hash_entry *depend = NULL;
579 /* We do not care about nexthop_grp.weight at
580 * this time. But we should figure out
581 * how to adapt this to our code in
582 * the future.
583 */
38e40db1 584 depend = depends_find_id_add(depends, grp[i].id);
e22e8001 585
38e40db1 586 if (!depend) {
e22e8001
SW
587 flog_err(
588 EC_ZEBRA_NHG_SYNC,
589 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
590 grp[i].id);
1b366e63 591 return -1;
e22e8001 592 }
38e40db1
SW
593
594 /*
595 * If this is a nexthop with its own group
596 * dependencies, add them as well. Not sure its
597 * even possible to have a group within a group
598 * in the kernel.
599 */
600
c415d895 601 copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL);
e22e8001 602 }
1b366e63
SW
603
604 return 0;
e22e8001
SW
605}
606
6384cbcb
SW
607static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
608 struct nexthop *nh, afi_t afi)
609{
610 struct nhg_hash_entry *depend = NULL;
611 struct nexthop_group resolved_ng = {};
612
1d049aba 613 resolved_ng.nexthop = nh;
6384cbcb 614
377e29f7
MS
615 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
616 zlog_debug("%s: head %p, nh %pNHv",
617 __func__, nhg_depends, nh);
618
6384cbcb 619 depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
a7e1b02d 620
377e29f7
MS
621 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
622 zlog_debug("%s: nh %pNHv => %p (%u)",
623 __func__, nh, depend,
624 depend ? depend->id : 0);
625
a7e1b02d
SW
626 if (depend)
627 depends_add(nhg_depends, depend);
6384cbcb 628}
e22e8001 629
377e29f7
MS
630/*
631 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
632 * has an id value, that's used. Create a new global/shared nhe if not found.
633 */
634static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
635 struct nhg_hash_entry *lookup,
636 struct nhg_connected_tree_head *nhg_depends,
637 afi_t afi)
638{
639 bool created = false;
640 bool recursive = false;
0328a5bd 641 struct nhg_hash_entry *newnhe, *backup_nhe;
377e29f7
MS
642 struct nexthop *nh = NULL;
643
644 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
645 zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p",
646 __func__, lookup->id, lookup,
647 lookup->vrf_id, lookup->type,
648 nhg_depends);
649
650 if (lookup->id)
651 (*nhe) = zebra_nhg_lookup_id(lookup->id);
652 else
653 (*nhe) = hash_lookup(zrouter.nhgs, lookup);
654
655 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
656 zlog_debug("%s: lookup => %p (%u)",
657 __func__, (*nhe),
658 (*nhe) ? (*nhe)->id : 0);
659
660 /* If we found an existing object, we're done */
661 if (*nhe)
662 goto done;
663
664 /* We're going to create/insert a new nhe:
665 * assign the next global id value if necessary.
666 */
667 if (lookup->id == 0)
668 lookup->id = ++id_counter;
669 newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
670 created = true;
671
672 /* Mail back the new object */
673 *nhe = newnhe;
674
675 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
676 zlog_debug("%s: => created %p (%u)", __func__, newnhe,
677 newnhe->id);
678
679 /* Only hash/lookup the depends if the first lookup
680 * fails to find something. This should hopefully save a
681 * lot of cycles for larger ecmp sizes.
682 */
683 if (nhg_depends) {
684 /* If you don't want to hash on each nexthop in the
685 * nexthop group struct you can pass the depends
686 * directly. Kernel-side we do this since it just looks
687 * them up via IDs.
688 */
689 zebra_nhg_connect_depends(newnhe, nhg_depends);
690 goto done;
691 }
692
693 /* Prepare dependency relationships if this is not a
694 * singleton nexthop. There are two cases: a single
695 * recursive nexthop, where we need a relationship to the
696 * resolving nexthop; or a group of nexthops, where we need
697 * relationships with the corresponding singletons.
698 */
699 zebra_nhg_depends_init(lookup);
700
701 nh = newnhe->nhg.nexthop;
702
703 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
704 SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
705
706 if (nh->next == NULL) {
707 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
708 /* Single recursive nexthop */
709 handle_recursive_depend(&newnhe->nhg_depends,
710 nh->resolved, afi);
711 recursive = true;
712 }
713 } else {
714 /* List of nexthops */
715 for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
716 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
717 zlog_debug("%s: depends NH %pNHv %s",
718 __func__, nh,
719 CHECK_FLAG(nh->flags,
720 NEXTHOP_FLAG_RECURSIVE) ?
721 "(R)" : "");
722
723 depends_find_add(&newnhe->nhg_depends, nh, afi);
724 }
725 }
726
0328a5bd
MS
727 if (recursive)
728 SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
729
377e29f7
MS
730 if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
731 zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
0328a5bd
MS
732 goto done;
733
734 /* If there are backup nexthops, add them to the backup
735 * depends tree. The rules here are a little different.
736 */
737 recursive = false;
738 backup_nhe = newnhe->backup_info->nhe;
377e29f7 739
0328a5bd 740 nh = backup_nhe->nhg.nexthop;
377e29f7
MS
741
742 /* Singleton recursive NH */
743 if (nh->next == NULL &&
744 CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
745 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
746 zlog_debug("%s: backup depend NH %pNHv (R)",
747 __func__, nh);
748
749 /* Single recursive nexthop */
0328a5bd 750 handle_recursive_depend(&backup_nhe->nhg_depends,
377e29f7
MS
751 nh->resolved, afi);
752 recursive = true;
753 } else {
754 /* One or more backup NHs */
755 for (; nh; nh = nh->next) {
756 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
757 zlog_debug("%s: backup depend NH %pNHv %s",
758 __func__, nh,
759 CHECK_FLAG(nh->flags,
760 NEXTHOP_FLAG_RECURSIVE) ?
761 "(R)" : "");
762
0328a5bd 763 depends_find_add(&backup_nhe->nhg_depends,
377e29f7
MS
764 nh, afi);
765 }
766 }
767
377e29f7 768 if (recursive)
0328a5bd 769 SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
377e29f7
MS
770
771done:
772
773 return created;
774}
775
776/*
777 * Lookup or create an nhe, based on an nhg or an nhe id.
778 */
4505578b
SW
779static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
780 struct nexthop_group *nhg,
37c6708b 781 struct nhg_connected_tree_head *nhg_depends,
38e40db1 782 vrf_id_t vrf_id, afi_t afi, int type)
a95b8020 783{
0c8215cb 784 struct nhg_hash_entry lookup = {};
4505578b
SW
785 bool created = false;
786
1d48702e
MS
787 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
788 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
789 __func__, id, nhg, vrf_id, type,
790 nhg_depends);
791
377e29f7
MS
792 /* Use a temporary nhe and call into the superset/common code */
793 lookup.id = id;
9a1588c4 794 lookup.type = type ? type : ZEBRA_ROUTE_NHG;
c415d895 795 lookup.nhg = *nhg;
e22e8001 796
88cafda7 797 lookup.vrf_id = vrf_id;
c415d895 798 if (lookup.nhg.nexthop->next) {
6384cbcb
SW
799 /* Groups can have all vrfs and AF's in them */
800 lookup.afi = AFI_UNSPEC;
6384cbcb 801 } else {
c415d895 802 switch (lookup.nhg.nexthop->type) {
4d21c7c0
SW
803 case (NEXTHOP_TYPE_IFINDEX):
804 case (NEXTHOP_TYPE_BLACKHOLE):
805 /*
806 * This switch case handles setting the afi different
807 * for ipv4/v6 routes. Ifindex/blackhole nexthop
808 * objects cannot be ambiguous, they must be Address
809 * Family specific. If we get here, we will either use
810 * the AF of the route, or the one we got passed from
811 * here from the kernel.
812 */
813 lookup.afi = afi;
814 break;
815 case (NEXTHOP_TYPE_IPV4_IFINDEX):
816 case (NEXTHOP_TYPE_IPV4):
817 lookup.afi = AFI_IP;
818 break;
819 case (NEXTHOP_TYPE_IPV6_IFINDEX):
820 case (NEXTHOP_TYPE_IPV6):
821 lookup.afi = AFI_IP6;
822 break;
823 }
6384cbcb 824 }
a95b8020 825
377e29f7 826 created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi);
d9f5b2f5 827
4505578b 828 return created;
a95b8020
SW
829}
830
e22e8001 831/* Find/create a single nexthop */
6384cbcb
SW
832static struct nhg_hash_entry *
833zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
3057df51 834{
6384cbcb 835 struct nhg_hash_entry *nhe = NULL;
e22e8001 836 struct nexthop_group nhg = {};
88cafda7 837 vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
e22e8001 838
0eb97b86 839 nexthop_group_add_sorted(&nhg, nh);
e22e8001 840
88cafda7 841 zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
8a507796 842
377e29f7
MS
843 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
844 zlog_debug("%s: nh %pNHv => %p (%u)",
845 __func__, nh, nhe, nhe ? nhe->id : 0);
846
6384cbcb 847 return nhe;
e22e8001
SW
848}
849
10200d40
SW
850static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
851{
852 return ctx->id;
853}
854
1b366e63 855static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
e22e8001
SW
856{
857 ctx->status = status;
858}
859
1b366e63 860static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
e22e8001
SW
861{
862 return ctx->status;
863}
864
865static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
866{
867 ctx->op = op;
868}
869
870static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
871{
872 return ctx->op;
873}
874
10200d40
SW
875static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
876{
877 return ctx->vrf_id;
878}
879
880static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
881{
882 return ctx->type;
883}
884
885static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
886{
887 return ctx->afi;
888}
889
890static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
891{
892 return &ctx->u.nh;
893}
894
895static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
896{
897 return ctx->count;
898}
899
900static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
901{
902 return ctx->u.grp;
903}
904
99e7ab12 905static struct nhg_ctx *nhg_ctx_new(void)
7c6d5f25 906{
99e7ab12 907 struct nhg_ctx *new;
7c6d5f25
SW
908
909 new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
910
911 return new;
912}
913
914static void nhg_ctx_free(struct nhg_ctx **ctx)
915{
916 struct nexthop *nh;
917
918 if (ctx == NULL)
919 return;
920
921 assert((*ctx) != NULL);
922
923 if (nhg_ctx_get_count(*ctx))
924 goto done;
925
926 nh = nhg_ctx_get_nh(*ctx);
927
928 nexthop_del_labels(nh);
929
930done:
931 XFREE(MTYPE_NHG_CTX, *ctx);
7c6d5f25
SW
932}
933
81505946
SW
934static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
935 struct nh_grp *grp, vrf_id_t vrf_id,
936 afi_t afi, int type, uint8_t count)
937{
938 struct nhg_ctx *ctx = NULL;
939
940 ctx = nhg_ctx_new();
941
942 ctx->id = id;
943 ctx->vrf_id = vrf_id;
944 ctx->afi = afi;
945 ctx->type = type;
946 ctx->count = count;
947
948 if (count)
949 /* Copy over the array */
950 memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
951 else if (nh)
952 ctx->u.nh = *nh;
953
954 return ctx;
955}
956
c1da832a 957static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
38e40db1
SW
958{
959 struct nhg_connected *rb_node_dep = NULL;
960
fec211ad 961 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
38e40db1 962 if (CHECK_FLAG(rb_node_dep->nhe->flags,
c1da832a 963 NEXTHOP_GROUP_UNHASHABLE))
38e40db1
SW
964 return true;
965 }
966
967 return false;
968}
969
c1da832a 970static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
38e40db1 971{
c1da832a 972 SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
38e40db1
SW
973 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
974
c1da832a
SW
975 flog_warn(
976 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
977 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
978 nhe->id);
38e40db1
SW
979}
980
80286aa5
SW
981static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
982{
983 struct nhg_connected *rb_node_dep;
984
985 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
986
987 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
988 zebra_nhg_set_valid(rb_node_dep->nhe);
989}
990
991static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
992{
993 struct nhg_connected *rb_node_dep;
994
995 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
996
997 /* Update validity of nexthops depending on it */
998 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
999 zebra_nhg_check_valid(rb_node_dep->nhe);
1000}
1001
1002void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
1003{
1004 struct nhg_connected *rb_node_dep = NULL;
1005 bool valid = false;
1006
1007 /* If anthing else in the group is valid, the group is valid */
1008 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1009 if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
1010 valid = true;
1011 goto done;
1012 }
1013 }
1014
1015done:
1016 if (valid)
1017 zebra_nhg_set_valid(nhe);
1018 else
1019 zebra_nhg_set_invalid(nhe);
1020}
1021
1022
177e711d 1023static void zebra_nhg_release(struct nhg_hash_entry *nhe)
9a1588c4 1024{
377e29f7
MS
1025 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1026 zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
1027
9a1588c4
SW
1028 /* Remove it from any lists it may be on */
1029 zebra_nhg_depends_release(nhe);
1030 zebra_nhg_dependents_release(nhe);
1031 if (nhe->ifp)
1032 if_nhg_dependents_del(nhe->ifp, nhe);
1033
1034 /*
c1da832a 1035 * If its unhashable, we didn't store it here and have to be
9a1588c4
SW
1036 * sure we don't clear one thats actually being used.
1037 */
c1da832a 1038 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
9a1588c4 1039 hash_release(zrouter.nhgs, nhe);
9a1588c4 1040
9a1588c4
SW
1041 hash_release(zrouter.nhgs_id, nhe);
1042}
1043
9a1588c4
SW
1044static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
1045{
177e711d 1046 zebra_nhg_release(nhe);
9a1588c4
SW
1047 zebra_nhg_free(nhe);
1048}
1049
80286aa5
SW
1050static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
1051{
1052 /* Update validity of groups depending on it */
1053 struct nhg_connected *rb_node_dep;
1054
1055 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1056 zebra_nhg_set_valid(rb_node_dep->nhe);
1057}
1058
9a1588c4
SW
1059/*
1060 * The kernel/other program has changed the state of a nexthop object we are
1061 * using.
1062 */
1063static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
1064 bool is_delete)
1065{
1066 if (nhe->refcnt) {
1067 flog_err(
1068 EC_ZEBRA_NHG_SYNC,
1069 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
1070 (is_delete ? "deleted" : "updated"), nhe->id);
1071
1072 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1073 zebra_nhg_install_kernel(nhe);
177e711d 1074 } else
9a1588c4 1075 zebra_nhg_handle_uninstall(nhe);
9a1588c4
SW
1076}
1077
e22e8001
SW
1078static int nhg_ctx_process_new(struct nhg_ctx *ctx)
1079{
1080 struct nexthop_group *nhg = NULL;
37c6708b 1081 struct nhg_connected_tree_head nhg_depends = {};
9a1588c4 1082 struct nhg_hash_entry *lookup = NULL;
3057df51
SW
1083 struct nhg_hash_entry *nhe = NULL;
1084
10200d40
SW
1085 uint32_t id = nhg_ctx_get_id(ctx);
1086 uint8_t count = nhg_ctx_get_count(ctx);
1087 vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
1088 int type = nhg_ctx_get_type(ctx);
1089 afi_t afi = nhg_ctx_get_afi(ctx);
1090
1091 lookup = zebra_nhg_lookup_id(id);
9a1588c4 1092
377e29f7
MS
1093 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1094 zlog_debug("%s: id %u, count %d, lookup => %p",
1095 __func__, id, count, lookup);
1096
9a1588c4
SW
1097 if (lookup) {
1098 /* This is already present in our table, hence an update
1099 * that we did not initate.
1100 */
1101 zebra_nhg_handle_kernel_state_change(lookup, false);
1102 return 0;
1103 }
1104
10200d40 1105 if (nhg_ctx_get_count(ctx)) {
e22e8001 1106 nhg = nexthop_group_new();
1b366e63
SW
1107 if (zebra_nhg_process_grp(nhg, &nhg_depends,
1108 nhg_ctx_get_grp(ctx), count)) {
1109 depends_decrement_free(&nhg_depends);
d3a35138 1110 nexthop_group_delete(&nhg);
fec211ad 1111 return -ENOENT;
1b366e63
SW
1112 }
1113
10200d40
SW
1114 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
1115 afi))
38e40db1 1116 depends_decrement_free(&nhg_depends);
4505578b 1117
e22e8001 1118 /* These got copied over in zebra_nhg_alloc() */
d3a35138 1119 nexthop_group_delete(&nhg);
38e40db1 1120 } else
10200d40
SW
1121 nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
1122 type);
e22e8001
SW
1123
1124 if (nhe) {
10200d40 1125 if (id != nhe->id) {
38e40db1
SW
1126 struct nhg_hash_entry *kernel_nhe = NULL;
1127
e22e8001 1128 /* Duplicate but with different ID from
2d3c57e6
SW
1129 * the kernel
1130 */
e22e8001
SW
1131
1132 /* The kernel allows duplicate nexthops
1133 * as long as they have different IDs.
1134 * We are ignoring those to prevent
1135 * syncing problems with the kernel
1136 * changes.
38e40db1
SW
1137 *
1138 * We maintain them *ONLY* in the ID hash table to
c1da832a
SW
1139 * track them and set the flag to indicated
1140 * their attributes are unhashable.
38e40db1
SW
1141 */
1142
10200d40 1143 kernel_nhe = zebra_nhg_copy(nhe, id);
377e29f7
MS
1144
1145 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1146 zlog_debug("%s: copying kernel nhe (%u), dup of %u",
1147 __func__, id, nhe->id);
1148
38e40db1 1149 zebra_nhg_insert_id(kernel_nhe);
c1da832a
SW
1150 zebra_nhg_set_unhashable(kernel_nhe);
1151 } else if (zebra_nhg_contains_unhashable(nhe)) {
1152 /* The group we got contains an unhashable/duplicated
1153 * depend, so lets mark this group as unhashable as well
1154 * and release it from the non-ID hash.
e22e8001 1155 */
377e29f7
MS
1156 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1157 zlog_debug("%s: nhe %p (%u) unhashable",
1158 __func__, nhe, nhe->id);
1159
38e40db1 1160 hash_release(zrouter.nhgs, nhe);
c1da832a 1161 zebra_nhg_set_unhashable(nhe);
38e40db1 1162 } else {
e22e8001 1163 /* It actually created a new nhe */
377e29f7
MS
1164 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1165 zlog_debug("%s: nhe %p (%u) is new",
1166 __func__, nhe, nhe->id);
1167
38e40db1
SW
1168 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1169 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
e22e8001
SW
1170 }
1171 } else {
1172 flog_err(
1173 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1174 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
10200d40 1175 id);
e22e8001
SW
1176 return -1;
1177 }
1178
1179 return 0;
1180}
1181
9a1588c4
SW
1182static int nhg_ctx_process_del(struct nhg_ctx *ctx)
1183{
1184 struct nhg_hash_entry *nhe = NULL;
10200d40 1185 uint32_t id = nhg_ctx_get_id(ctx);
9a1588c4 1186
10200d40 1187 nhe = zebra_nhg_lookup_id(id);
9a1588c4
SW
1188
1189 if (!nhe) {
1190 flog_warn(
1191 EC_ZEBRA_BAD_NHG_MESSAGE,
1192 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
10200d40 1193 id);
81505946 1194 return -1;
9a1588c4
SW
1195 }
1196
1197 zebra_nhg_handle_kernel_state_change(nhe, true);
1198
1199 return 0;
1200}
1201
7c6d5f25 1202static void nhg_ctx_fini(struct nhg_ctx **ctx)
e22e8001
SW
1203{
1204 /*
1205 * Just freeing for now, maybe do something more in the future
1206 * based on flag.
1207 */
1208
7134ba70 1209 nhg_ctx_free(ctx);
e22e8001
SW
1210}
1211
1b366e63
SW
1212static int queue_add(struct nhg_ctx *ctx)
1213{
1214 /* If its queued or already processed do nothing */
1215 if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
1216 return 0;
1217
1218 if (rib_queue_nhg_add(ctx)) {
1219 nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
1220 return -1;
1221 }
1222
1223 nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
1224
1225 return 0;
1226}
1227
e22e8001
SW
1228int nhg_ctx_process(struct nhg_ctx *ctx)
1229{
1230 int ret = 0;
1231
1232 switch (nhg_ctx_get_op(ctx)) {
1233 case NHG_CTX_OP_NEW:
1234 ret = nhg_ctx_process_new(ctx);
fec211ad 1235 if (nhg_ctx_get_count(ctx) && ret == -ENOENT
1b366e63 1236 && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
e1292378
SW
1237 /**
1238 * We have entered a situation where we are
1239 * processing a group from the kernel
1240 * that has a contained nexthop which
1241 * we have not yet processed.
1b366e63 1242 *
e1292378
SW
1243 * Re-enqueue this ctx to be handled exactly one
1244 * more time (indicated by the flag).
1245 *
1246 * By the time we get back to it, we
1247 * should have processed its depends.
1b366e63
SW
1248 */
1249 nhg_ctx_set_status(ctx, NHG_CTX_NONE);
1250 if (queue_add(ctx) == 0) {
1251 nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
1252 return 0;
1253 }
1254 }
e22e8001
SW
1255 break;
1256 case NHG_CTX_OP_DEL:
9a1588c4 1257 ret = nhg_ctx_process_del(ctx);
e22e8001
SW
1258 case NHG_CTX_OP_NONE:
1259 break;
1260 }
1261
1262 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
1263
7c6d5f25 1264 nhg_ctx_fini(&ctx);
e22e8001
SW
1265
1266 return ret;
1267}
3057df51 1268
e22e8001
SW
1269/* Kernel-side, you either get a single new nexthop or a array of ID's */
1270int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
38e40db1
SW
1271 uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
1272 int startup)
e22e8001 1273{
e22e8001
SW
1274 struct nhg_ctx *ctx = NULL;
1275
377e29f7
MS
1276 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1277 zlog_debug("%s: nh %pNHv, id %u, count %d",
1278 __func__, nh, id, (int)count);
1279
38e40db1
SW
1280 if (id > id_counter)
1281 /* Increase our counter so we don't try to create
1282 * an ID that already exists
1283 */
1284 id_counter = id;
1285
81505946 1286 ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
e22e8001
SW
1287 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
1288
38e40db1
SW
1289 /* Under statup conditions, we need to handle them immediately
1290 * like we do for routes. Otherwise, we are going to get a route
1291 * with a nhe_id that we have not handled.
1292 */
1293 if (startup)
1294 return nhg_ctx_process(ctx);
1295
e22e8001 1296 if (queue_add(ctx)) {
7c6d5f25 1297 nhg_ctx_fini(&ctx);
e22e8001
SW
1298 return -1;
1299 }
1300
1301 return 0;
1302}
1303
9a1588c4 1304/* Kernel-side, received delete message */
88cafda7 1305int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
9a1588c4
SW
1306{
1307 struct nhg_ctx *ctx = NULL;
1308
88cafda7 1309 ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
9a1588c4
SW
1310
1311 nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
1312
1313 if (queue_add(ctx)) {
7c6d5f25 1314 nhg_ctx_fini(&ctx);
9a1588c4
SW
1315 return -1;
1316 }
1317
1318 return 0;
1319}
1320
5657e7e9 1321/* Some dependency helper functions */
0fff714e
SW
1322static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
1323 afi_t afi)
98cda54a 1324{
0fff714e
SW
1325 struct nhg_hash_entry *nhe;
1326 struct nexthop *lookup = NULL;
98cda54a 1327
77bf9504 1328 lookup = nexthop_dup(nh, NULL);
0fff714e
SW
1329
1330 nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
1331
1332 nexthops_free(lookup);
1333
1334 return nhe;
1335}
1336
1337static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
1338 afi_t afi)
1339{
1340 struct nhg_hash_entry *nhe;
1341 struct nexthop lookup = {};
606fa9e5 1342
cb86eba3
MS
1343 /* Capture a snapshot of this single nh; it might be part of a list,
1344 * so we need to make a standalone copy.
1345 */
77bf9504 1346 nexthop_copy_no_recurse(&lookup, nh, NULL);
8a507796 1347
cb86eba3 1348 nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
8a507796 1349
cb86eba3
MS
1350 /* The copy may have allocated labels; free them if necessary. */
1351 nexthop_del_labels(&lookup);
4505578b 1352
377e29f7
MS
1353 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1354 zlog_debug("%s: nh %pNHv => %p (%u)",
1355 __func__, nh, nhe, nhe ? nhe->id : 0);
1356
0fff714e
SW
1357 return nhe;
1358}
1359
1360static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
1361{
1362 struct nhg_hash_entry *nhe = NULL;
377e29f7 1363 char rbuf[10];
0fff714e
SW
1364
1365 if (!nh)
1366 goto done;
1367
1368 /* We are separating these functions out to increase handling speed
1369 * in the non-recursive case (by not alloc/freeing)
1370 */
377e29f7 1371 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
0fff714e 1372 nhe = depends_find_recursive(nh, afi);
377e29f7
MS
1373 strlcpy(rbuf, "(R)", sizeof(rbuf));
1374 } else {
0fff714e 1375 nhe = depends_find_singleton(nh, afi);
377e29f7
MS
1376 rbuf[0] = '\0';
1377 }
1378
1379 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1380 zlog_debug("%s: nh %pNHv %s => %p (%u)",
1381 __func__, nh, rbuf,
1382 nhe, nhe ? nhe->id : 0);
0fff714e 1383
606fa9e5 1384done:
4505578b 1385 return nhe;
98cda54a
SW
1386}
1387
37c6708b 1388static void depends_add(struct nhg_connected_tree_head *head,
5657e7e9
SW
1389 struct nhg_hash_entry *depend)
1390{
377e29f7
MS
1391 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1392 zlog_debug("%s: head %p nh %pNHv",
1393 __func__, head, depend->nhg.nexthop);
1394
5bf15faa
SW
1395 /* If NULL is returned, it was successfully added and
1396 * needs to have its refcnt incremented.
1397 *
1398 * Else the NHE is already present in the tree and doesn't
1399 * need to increment the refcnt.
1400 */
1401 if (nhg_connected_tree_add_nhe(head, depend) == NULL)
1402 zebra_nhg_increment_ref(depend);
5657e7e9
SW
1403}
1404
38e40db1
SW
1405static struct nhg_hash_entry *
1406depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1407 afi_t afi)
5657e7e9
SW
1408{
1409 struct nhg_hash_entry *depend = NULL;
1410
1411 depend = depends_find(nh, afi);
1b366e63 1412
1d48702e
MS
1413 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1414 zlog_debug("%s: nh %pNHv => %p",
1415 __func__, nh, depend);
1416
1b366e63
SW
1417 if (depend)
1418 depends_add(head, depend);
38e40db1
SW
1419
1420 return depend;
1421}
1422
1423static struct nhg_hash_entry *
1424depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1425{
1426 struct nhg_hash_entry *depend = NULL;
1427
1428 depend = zebra_nhg_lookup_id(id);
1b366e63
SW
1429
1430 if (depend)
1431 depends_add(head, depend);
38e40db1
SW
1432
1433 return depend;
5657e7e9
SW
1434}
1435
37c6708b 1436static void depends_decrement_free(struct nhg_connected_tree_head *head)
5657e7e9 1437{
37c6708b
SW
1438 nhg_connected_tree_decrement_ref(head);
1439 nhg_connected_tree_free(head);
5657e7e9
SW
1440}
1441
377e29f7 1442/* Find an nhe based on a list of nexthops */
7f997721
SW
1443struct nhg_hash_entry *
1444zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
e22e8001
SW
1445{
1446 struct nhg_hash_entry *nhe = NULL;
88cafda7
DS
1447 vrf_id_t vrf_id;
1448
1449 /*
1450 * CLANG SA is complaining that nexthop may be NULL
1451 * Make it happy but this is ridonc
1452 */
1453 assert(nhg->nexthop);
1454 vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
98cda54a 1455
88cafda7 1456 zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
4505578b 1457
377e29f7
MS
1458 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1459 zlog_debug("%s: => nhe %p (%u)",
1460 __func__, nhe, nhe ? nhe->id : 0);
1461
1462 return nhe;
1463}
1464
1465/* Find an nhe based on a route's nhe */
1466struct nhg_hash_entry *
1467zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
1468{
1469 struct nhg_hash_entry *nhe = NULL;
1470
1471 if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
1472 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1473 "No nexthop passed to %s", __func__);
1474 return NULL;
1475 }
1476
1477 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
f924db49 1478 zlog_debug("%s: rt_nhe %p (%u)", __func__, rt_nhe, rt_nhe->id);
377e29f7
MS
1479
1480 zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi);
1481
1482 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1483 zlog_debug("%s: => nhe %p (%u)",
1484 __func__, nhe, nhe ? nhe->id : 0);
1485
3057df51
SW
1486 return nhe;
1487}
1488
1d48702e
MS
1489/*
1490 * Allocate backup nexthop info object. Typically these are embedded in
1491 * nhg_hash_entry objects.
1492 */
1493struct nhg_backup_info *zebra_nhg_backup_alloc(void)
1494{
1495 struct nhg_backup_info *p;
1496
1497 p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
1498
1499 p->nhe = zebra_nhg_alloc();
1500
1501 /* Identify the embedded group used to hold the list of backups */
1502 SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
1503
1504 return p;
1505}
1506
1507/*
1508 * Free backup nexthop info object, deal with any embedded allocations
1509 */
1510void zebra_nhg_backup_free(struct nhg_backup_info **p)
1511{
1512 if (p && *p) {
1513 if ((*p)->nhe)
1514 zebra_nhg_free((*p)->nhe);
1515
1516 XFREE(MTYPE_NHG, (*p));
1517 }
1518}
1519
1d48702e
MS
1520/* Accessor for backup nexthop group */
1521struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
1522{
1523 struct nexthop_group *p = NULL;
1524
1525 if (nhe) {
1526 if (nhe->backup_info && nhe->backup_info->nhe)
1527 p = &(nhe->backup_info->nhe->nhg);
1528 }
1529
1530 return p;
1531}
1532
1533/*
1534 * Helper to return a copy of a backup_info - note that this is a shallow
1535 * copy, meant to be used when creating a new nhe from info passed in with
1536 * a route e.g.
1537 */
1538static struct nhg_backup_info *
1539nhg_backup_copy(const struct nhg_backup_info *orig)
1540{
1541 struct nhg_backup_info *b;
1542
1543 b = zebra_nhg_backup_alloc();
1544
1545 /* Copy list of nexthops */
1546 nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
1547
1548 return b;
1549}
1550
5948f013 1551static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
b599cd2a 1552{
c415d895
MS
1553 nexthops_free(nhe->nhg.nexthop);
1554
1d48702e
MS
1555 zebra_nhg_backup_free(&nhe->backup_info);
1556
58396544 1557 /* Decrement to remove connection ref */
37c6708b
SW
1558 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1559 nhg_connected_tree_free(&nhe->nhg_depends);
1560 nhg_connected_tree_free(&nhe->nhg_dependents);
b599cd2a
SW
1561}
1562
0eb97b86 1563void zebra_nhg_free(struct nhg_hash_entry *nhe)
a95b8020 1564{
377e29f7
MS
1565 if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1566 /* Group or singleton? */
1567 if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1568 zlog_debug("%s: nhe %p (%u), refcnt %d",
f924db49 1569 __func__, nhe, nhe->id, nhe->refcnt);
377e29f7
MS
1570 else
1571 zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
f924db49 1572 __func__, nhe, nhe->id, nhe->refcnt,
377e29f7
MS
1573 nhe->nhg.nexthop);
1574 }
1575
38e40db1
SW
1576 if (nhe->refcnt)
1577 zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
1578
8e401b25 1579 zebra_nhg_free_members(nhe);
51d80884
SW
1580
1581 XFREE(MTYPE_NHG, nhe);
a95b8020
SW
1582}
1583
0eb97b86
MS
1584void zebra_nhg_hash_free(void *p)
1585{
1586 zebra_nhg_free((struct nhg_hash_entry *)p);
1587}
1588
d9f5b2f5
SW
1589void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1590{
377e29f7
MS
1591 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1592 zlog_debug("%s: nhe %p (%u) %d => %d",
1593 __func__, nhe, nhe->id, nhe->refcnt,
1594 nhe->refcnt - 1);
1595
e22e8001
SW
1596 nhe->refcnt--;
1597
32e29e79 1598 if (!zebra_nhg_depends_is_empty(nhe))
37c6708b 1599 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
f54ef6a5 1600
38e40db1 1601 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
cb50cbc9 1602 zebra_nhg_uninstall_kernel(nhe);
7fd392cc
SW
1603}
1604
7fd392cc
SW
1605void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1606{
377e29f7
MS
1607 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1608 zlog_debug("%s: nhe %p (%u) %d => %d",
1609 __func__, nhe, nhe->id, nhe->refcnt,
1610 nhe->refcnt + 1);
1611
e22e8001
SW
1612 nhe->refcnt++;
1613
32e29e79 1614 if (!zebra_nhg_depends_is_empty(nhe))
37c6708b 1615 nhg_connected_tree_increment_ref(&nhe->nhg_depends);
e22e8001 1616}
d9f5b2f5 1617
ad28e79a
SW
1618static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
1619 struct nexthop *nexthop)
1620{
1621 struct nexthop *resolved_hop;
b43434ad
SW
1622 uint8_t num_labels = 0;
1623 mpls_label_t labels[MPLS_MAX_LABELS];
1624 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1625 int i = 0;
ad28e79a
SW
1626
1627 resolved_hop = nexthop_new();
1628 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1629
1630 resolved_hop->vrf_id = nexthop->vrf_id;
1631 switch (newhop->type) {
1632 case NEXTHOP_TYPE_IPV4:
1633 case NEXTHOP_TYPE_IPV4_IFINDEX:
1634 /* If the resolving route specifies a gateway, use it */
1635 resolved_hop->type = newhop->type;
1636 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1637
1638 if (newhop->ifindex) {
1639 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1640 resolved_hop->ifindex = newhop->ifindex;
1641 }
1642 break;
1643 case NEXTHOP_TYPE_IPV6:
1644 case NEXTHOP_TYPE_IPV6_IFINDEX:
1645 resolved_hop->type = newhop->type;
1646 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1647
1648 if (newhop->ifindex) {
1649 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1650 resolved_hop->ifindex = newhop->ifindex;
1651 }
1652 break;
1653 case NEXTHOP_TYPE_IFINDEX:
1654 /* If the resolving route is an interface route,
1655 * it means the gateway we are looking up is connected
1656 * to that interface. (The actual network is _not_ onlink).
1657 * Therefore, the resolved route should have the original
1658 * gateway as nexthop as it is directly connected.
1659 *
1660 * On Linux, we have to set the onlink netlink flag because
1661 * otherwise, the kernel won't accept the route.
1662 */
1663 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1664 if (afi == AFI_IP) {
1665 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1666 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1667 } else if (afi == AFI_IP6) {
1668 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1669 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1670 }
1671 resolved_hop->ifindex = newhop->ifindex;
1672 break;
1673 case NEXTHOP_TYPE_BLACKHOLE:
1674 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 1675 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
1676 break;
1677 }
1678
1679 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1680 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1681
b43434ad
SW
1682 /* Copy labels of the resolved route and the parent resolving to it */
1683 if (newhop->nh_label) {
1684 for (i = 0; i < newhop->nh_label->num_labels; i++)
1685 labels[num_labels++] = newhop->nh_label->label[i];
1686 label_type = newhop->nh_label_type;
1687 }
1688
1689 if (nexthop->nh_label) {
1690 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1691 labels[num_labels++] = nexthop->nh_label->label[i];
1692
1693 /* If the parent has labels, use its type */
1694 label_type = nexthop->nh_label_type;
1695 }
1696
1697 if (num_labels)
1698 nexthop_add_labels(resolved_hop, label_type, num_labels,
1699 labels);
ad28e79a
SW
1700
1701 resolved_hop->rparent = nexthop;
50d89650 1702 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
1703}
1704
6913cb1b
SW
1705/* Checks if nexthop we are trying to resolve to is valid */
1706static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1707 const struct nexthop *resolved)
1708{
1709 /* Can't resolve to a recursive nexthop */
1710 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1711 return false;
1712
1713 switch (nexthop->type) {
1714 case NEXTHOP_TYPE_IPV4_IFINDEX:
1715 case NEXTHOP_TYPE_IPV6_IFINDEX:
1716 /* If the nexthop we are resolving to does not match the
1717 * ifindex for the nexthop the route wanted, its not valid.
1718 */
1719 if (nexthop->ifindex != resolved->ifindex)
1720 return false;
1721 break;
1722 case NEXTHOP_TYPE_IPV4:
1723 case NEXTHOP_TYPE_IPV6:
1724 case NEXTHOP_TYPE_IFINDEX:
1725 case NEXTHOP_TYPE_BLACKHOLE:
1726 break;
1727 }
1728
1729 return true;
1730}
1731
ad28e79a
SW
1732/*
1733 * Given a nexthop we need to properly recursively resolve
1734 * the route. As such, do a table lookup to find and match
98cda54a
SW
1735 * if at all possible. Set the nexthop->ifindex and resolved_id
1736 * as appropriate
ad28e79a
SW
1737 */
1738static int nexthop_active(afi_t afi, struct route_entry *re,
8a507796 1739 struct nexthop *nexthop, struct route_node *top)
ad28e79a
SW
1740{
1741 struct prefix p;
1742 struct route_table *table;
1743 struct route_node *rn;
1744 struct route_entry *match = NULL;
1745 int resolved;
1746 struct nexthop *newhop;
1747 struct interface *ifp;
1748 rib_dest_t *dest;
5a0bdc78 1749 struct zebra_vrf *zvrf;
ad28e79a
SW
1750
1751 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
1752 || nexthop->type == NEXTHOP_TYPE_IPV6)
1753 nexthop->ifindex = 0;
1754
8a507796 1755
ad28e79a
SW
1756 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
1757 nexthops_free(nexthop->resolved);
1758 nexthop->resolved = NULL;
1759 re->nexthop_mtu = 0;
1760
377e29f7
MS
1761 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1762 zlog_debug("%s: re %p, nexthop %pNHv",
1763 __func__, re, nexthop);
1764
ad28e79a 1765 /*
a8c427ee 1766 * If the kernel has sent us a NEW route, then
ad28e79a 1767 * by golly gee whiz it's a good route.
a8c427ee
SW
1768 *
1769 * If its an already INSTALLED route we have already handled, then the
1770 * kernel route's nexthop might have became unreachable
1771 * and we have to handle that.
ad28e79a 1772 */
a8c427ee
SW
1773 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
1774 && (re->type == ZEBRA_ROUTE_KERNEL
1775 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
1776 return 1;
1777
1778 /*
1779 * Check to see if we should trust the passed in information
1780 * for UNNUMBERED interfaces as that we won't find the GW
1781 * address in the routing table.
1782 * This check should suffice to handle IPv4 or IPv6 routes
1783 * sourced from EVPN routes which are installed with the
1784 * next hop as the remote VTEP IP.
1785 */
1786 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
1787 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1788 if (!ifp) {
1789 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1790 zlog_debug(
d6951e5e 1791 " %s: Onlink and interface: %u[%u] does not exist",
5e81f5dd 1792 __func__, nexthop->ifindex,
ad28e79a
SW
1793 nexthop->vrf_id);
1794 return 0;
1795 }
2d3c57e6 1796
5cfaa2d9
DS
1797 if (if_is_operative(ifp))
1798 return 1;
1799 else {
2d3c57e6
SW
1800 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1801 zlog_debug(
d6951e5e 1802 " %s: Onlink and interface %s is not operative",
5e81f5dd 1803 __func__, ifp->name);
2d3c57e6 1804 return 0;
ad28e79a 1805 }
ad28e79a
SW
1806 }
1807
4dcc2276
DS
1808 if ((top->p.family == AF_INET && top->p.prefixlen == 32
1809 && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
1810 || (top->p.family == AF_INET6 && top->p.prefixlen == 128
1811 && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
1812 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1813 zlog_debug(
d6951e5e 1814 " :%s: Attempting to install a max prefixlength route through itself",
5e81f5dd 1815 __func__);
4dcc2276
DS
1816 return 0;
1817 }
1818
ad28e79a
SW
1819 /* Make lookup prefix. */
1820 memset(&p, 0, sizeof(struct prefix));
1821 switch (afi) {
1822 case AFI_IP:
1823 p.family = AF_INET;
1824 p.prefixlen = IPV4_MAX_PREFIXLEN;
1825 p.u.prefix4 = nexthop->gate.ipv4;
1826 break;
1827 case AFI_IP6:
1828 p.family = AF_INET6;
1829 p.prefixlen = IPV6_MAX_PREFIXLEN;
1830 p.u.prefix6 = nexthop->gate.ipv6;
1831 break;
1832 default:
1833 assert(afi != AFI_IP && afi != AFI_IP6);
1834 break;
1835 }
1836 /* Lookup table. */
1837 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
1838 /* get zvrf */
1839 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1840 if (!table || !zvrf) {
ad28e79a 1841 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e 1842 zlog_debug(" %s: Table not found", __func__);
ad28e79a
SW
1843 return 0;
1844 }
1845
1846 rn = route_node_match(table, (struct prefix *)&p);
1847 while (rn) {
1848 route_unlock_node(rn);
1849
1850 /* Lookup should halt if we've matched against ourselves ('top',
1851 * if specified) - i.e., we cannot have a nexthop NH1 is
1852 * resolved by a route NH1. The exception is if the route is a
1853 * host route.
1854 */
92756825 1855 if (rn == top)
ad28e79a
SW
1856 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
1857 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
1858 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1859 zlog_debug(
d6951e5e 1860 " %s: Matched against ourself and prefix length is not max bit length",
5e81f5dd 1861 __func__);
ad28e79a
SW
1862 return 0;
1863 }
1864
1865 /* Pick up selected route. */
1866 /* However, do not resolve over default route unless explicitly
2d3c57e6
SW
1867 * allowed.
1868 */
ad28e79a 1869 if (is_default_prefix(&rn->p)
5a0bdc78 1870 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
1871 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1872 zlog_debug(
d6951e5e 1873 " :%s: Resolved against default route",
5e81f5dd 1874 __func__);
ad28e79a
SW
1875 return 0;
1876 }
1877
1878 dest = rib_dest_from_rnode(rn);
1879 if (dest && dest->selected_fib
1880 && !CHECK_FLAG(dest->selected_fib->status,
1881 ROUTE_ENTRY_REMOVED)
1882 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
1883 match = dest->selected_fib;
1884
1885 /* If there is no selected route or matched route is EGP, go up
2d3c57e6
SW
1886 * tree.
1887 */
ad28e79a
SW
1888 if (!match) {
1889 do {
1890 rn = rn->parent;
1891 } while (rn && rn->info == NULL);
1892 if (rn)
1893 route_lock_node(rn);
1894
1895 continue;
1896 }
1897
1898 if (match->type == ZEBRA_ROUTE_CONNECT) {
1899 /* Directly point connected route. */
c415d895 1900 newhop = match->nhe->nhg.nexthop;
ad28e79a
SW
1901 if (newhop) {
1902 if (nexthop->type == NEXTHOP_TYPE_IPV4
1903 || nexthop->type == NEXTHOP_TYPE_IPV6)
1904 nexthop->ifindex = newhop->ifindex;
1905 }
377e29f7
MS
1906
1907 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1908 zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
1909 __func__, match,
1910 match->nhe->id, newhop);
1911
ad28e79a
SW
1912 return 1;
1913 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
1914 resolved = 0;
c415d895 1915 for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) {
ad28e79a
SW
1916 if (!CHECK_FLAG(match->status,
1917 ROUTE_ENTRY_INSTALLED))
1918 continue;
6913cb1b 1919 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
1920 continue;
1921
377e29f7
MS
1922 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1923 zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
1924 __func__, match,
1925 match->nhe->id, newhop);
1926
ad28e79a
SW
1927 SET_FLAG(nexthop->flags,
1928 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
1929 nexthop_set_resolved(afi, newhop, nexthop);
1930 resolved = 1;
1931 }
f924db49 1932
8a507796 1933 if (resolved)
ad28e79a 1934 re->nexthop_mtu = match->mtu;
f924db49 1935 else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e
DL
1936 zlog_debug(
1937 " %s: Recursion failed to find",
1938 __func__);
f924db49 1939
ad28e79a
SW
1940 return resolved;
1941 } else if (re->type == ZEBRA_ROUTE_STATIC) {
1942 resolved = 0;
c415d895 1943 for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) {
ad28e79a
SW
1944 if (!CHECK_FLAG(match->status,
1945 ROUTE_ENTRY_INSTALLED))
1946 continue;
6913cb1b 1947 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
1948 continue;
1949
377e29f7
MS
1950 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1951 zlog_debug("%s: STATIC match %p (%u), newhop %pNHv",
1952 __func__, match,
1953 match->nhe->id, newhop);
1954
ad28e79a
SW
1955 SET_FLAG(nexthop->flags,
1956 NEXTHOP_FLAG_RECURSIVE);
1957 nexthop_set_resolved(afi, newhop, nexthop);
1958 resolved = 1;
1959 }
8a507796 1960 if (resolved)
ad28e79a 1961 re->nexthop_mtu = match->mtu;
8a507796 1962
ad28e79a
SW
1963 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1964 zlog_debug(
d6951e5e 1965 " %s: Static route unable to resolve",
5e81f5dd 1966 __func__);
ad28e79a
SW
1967 return resolved;
1968 } else {
1969 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
1970 zlog_debug(
d6951e5e 1971 " %s: Route Type %s has not turned on recursion",
5e81f5dd 1972 __func__, zebra_route_string(re->type));
ad28e79a
SW
1973 if (re->type == ZEBRA_ROUTE_BGP
1974 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
1975 zlog_debug(
d6951e5e 1976 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
ad28e79a
SW
1977 }
1978 return 0;
1979 }
1980 }
1981 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e
DL
1982 zlog_debug(" %s: Nexthop did not lookup in table",
1983 __func__);
ad28e79a
SW
1984 return 0;
1985}
1986
1987/* This function verifies reachability of one given nexthop, which can be
1988 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1989 * in nexthop->flags field. The nexthop->ifindex will be updated
1990 * appropriately as well. An existing route map can turn
1991 * (otherwise active) nexthop into inactive, but not vice versa.
1992 *
98cda54a
SW
1993 * If it finds a nexthop recursivedly, set the resolved_id
1994 * to match that nexthop's nhg_hash_entry ID;
1995 *
ad28e79a
SW
1996 * The return value is the final value of 'ACTIVE' flag.
1997 */
1998static unsigned nexthop_active_check(struct route_node *rn,
1999 struct route_entry *re,
8a507796 2000 struct nexthop *nexthop)
ad28e79a
SW
2001{
2002 struct interface *ifp;
b68885f9 2003 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
2004 int family;
2005 char buf[SRCDEST2STR_BUFFER];
2006 const struct prefix *p, *src_p;
2007 struct zebra_vrf *zvrf;
2008
2009 srcdest_rnode_prefixes(rn, &p, &src_p);
2010
2011 if (rn->p.family == AF_INET)
2012 family = AFI_IP;
2013 else if (rn->p.family == AF_INET6)
2014 family = AFI_IP6;
2015 else
2016 family = 0;
2017 switch (nexthop->type) {
2018 case NEXTHOP_TYPE_IFINDEX:
2019 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
fc8a02c4
SW
2020 /*
2021 * If the interface exists and its operative or its a kernel
2022 * route and interface is up, its active. We trust kernel routes
2023 * to be good.
2024 */
2025 if (ifp
2026 && (if_is_operative(ifp)
2027 || (if_is_up(ifp)
2028 && (re->type == ZEBRA_ROUTE_KERNEL
2029 || re->type == ZEBRA_ROUTE_SYSTEM))))
ad28e79a
SW
2030 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2031 else
2032 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2033 break;
2034 case NEXTHOP_TYPE_IPV4:
2035 case NEXTHOP_TYPE_IPV4_IFINDEX:
2036 family = AFI_IP;
8a507796 2037 if (nexthop_active(AFI_IP, re, nexthop, rn))
ad28e79a
SW
2038 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2039 else
2040 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2041 break;
2042 case NEXTHOP_TYPE_IPV6:
2043 family = AFI_IP6;
8a507796 2044 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
2045 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2046 else
2047 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2048 break;
2049 case NEXTHOP_TYPE_IPV6_IFINDEX:
2050 /* RFC 5549, v4 prefix with v6 NH */
2051 if (rn->p.family != AF_INET)
2052 family = AFI_IP6;
2053 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
2054 ifp = if_lookup_by_index(nexthop->ifindex,
2055 nexthop->vrf_id);
2056 if (ifp && if_is_operative(ifp))
2057 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2058 else
2059 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2060 } else {
8a507796 2061 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
2062 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2063 else
2064 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2065 }
2066 break;
2067 case NEXTHOP_TYPE_BLACKHOLE:
2068 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2069 break;
2070 default:
2071 break;
2072 }
377e29f7 2073
ad28e79a
SW
2074 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
2075 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
377e29f7
MS
2076 zlog_debug(" %s: Unable to find active nexthop",
2077 __func__);
ad28e79a
SW
2078 return 0;
2079 }
2080
2081 /* XXX: What exactly do those checks do? Do we support
2082 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2083 */
2084 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
2085 || (family == AFI_IP6 && p->family != AF_INET6))
2086 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2087
2088 /* The original code didn't determine the family correctly
2089 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2090 * from the rib_table_info in those cases.
2091 * Possibly it may be better to use only the rib_table_info
2092 * in every case.
2093 */
2094 if (!family) {
630d5962 2095 struct rib_table_info *info;
ad28e79a
SW
2096
2097 info = srcdest_rnode_table_info(rn);
2098 family = info->afi;
2099 }
2100
2101 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
2102
2103 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
2104 if (!zvrf) {
2105 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e 2106 zlog_debug(" %s: zvrf is NULL", __func__);
ad28e79a
SW
2107 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2108 }
2109
2110 /* It'll get set if required inside */
2111 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
2112 zvrf, re->tag);
2113 if (ret == RMAP_DENYMATCH) {
2114 if (IS_ZEBRA_DEBUG_RIB) {
2115 srcdest_rnode2str(rn, buf, sizeof(buf));
2116 zlog_debug(
2117 "%u:%s: Filtering out with NH out %s due to route map",
2118 re->vrf_id, buf,
2119 ifindex2ifname(nexthop->ifindex,
2120 nexthop->vrf_id));
2121 }
2122 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2123 }
2124 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2125}
2126
086e4e02
SW
2127/* Helper function called after resolution to walk nhg rb trees
2128 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2129 * is active on singleton NHEs.
2130 */
2131static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe)
2132{
2133 struct nhg_connected *rb_node_dep = NULL;
2134 bool valid = false;
2135
2136 if (!zebra_nhg_depends_is_empty(nhe)) {
2137 /* Is at least one depend valid? */
2138 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2139 if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe))
2140 valid = true;
2141 }
2142
2143 goto done;
2144 }
2145
2146 /* should be fully resolved singleton at this point */
2147 if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE))
2148 valid = true;
2149
2150done:
2151 if (valid)
2152 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2153
2154 return valid;
2155}
2156
ad28e79a 2157/*
377e29f7
MS
2158 * Process a list of nexthops, given the head of the list, determining
2159 * whether each one is ACTIVE/installable at this time.
ad28e79a 2160 */
377e29f7
MS
2161static uint32_t nexthop_list_active_update(struct route_node *rn,
2162 struct route_entry *re,
2163 struct nexthop *nexthop)
ad28e79a 2164{
ad28e79a
SW
2165 union g_addr prev_src;
2166 unsigned int prev_active, new_active;
2167 ifindex_t prev_index;
377e29f7 2168 uint32_t counter = 0;
e22e8001 2169
377e29f7
MS
2170 /* Process nexthops one-by-one */
2171 for ( ; nexthop; nexthop = nexthop->next) {
ad28e79a 2172
ad28e79a 2173 /* No protocol daemon provides src and so we're skipping
377e29f7
MS
2174 * tracking it
2175 */
ad28e79a
SW
2176 prev_src = nexthop->rmap_src;
2177 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2178 prev_index = nexthop->ifindex;
2179 /*
2180 * We need to respect the multipath_num here
2181 * as that what we should be able to install from
377e29f7 2182 * a multipath perspective should not be a data plane
ad28e79a
SW
2183 * decision point.
2184 */
98cda54a 2185 new_active =
8a507796 2186 nexthop_active_check(rn, re, nexthop);
98cda54a 2187
377e29f7 2188 if (new_active && counter >= zrouter.multipath_num) {
4c55b5ff
SW
2189 struct nexthop *nh;
2190
2191 /* Set it and its resolved nexthop as inactive. */
2192 for (nh = nexthop; nh; nh = nh->resolved)
2193 UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2194
ad28e79a
SW
2195 new_active = 0;
2196 }
9a0d4dd3 2197
df31a989 2198 if (new_active)
377e29f7 2199 counter++;
9a0d4dd3 2200
ad28e79a
SW
2201 /* Don't allow src setting on IPv6 addr for now */
2202 if (prev_active != new_active || prev_index != nexthop->ifindex
2203 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
2204 && nexthop->type < NEXTHOP_TYPE_IPV6)
2205 && prev_src.ipv4.s_addr
2206 != nexthop->rmap_src.ipv4.s_addr)
2207 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
2208 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
2209 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
2210 &nexthop->rmap_src.ipv6)))
8a507796 2211 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 2212 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
2213 }
2214
377e29f7
MS
2215 return counter;
2216}
2217
2218/*
2219 * Iterate over all nexthops of the given RIB entry and refresh their
2220 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2221 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2222 *
2223 * Return value is the new number of active nexthops.
2224 */
2225int nexthop_active_update(struct route_node *rn, struct route_entry *re)
2226{
2227 struct nhg_hash_entry *curr_nhe;
2228 uint32_t curr_active = 0, backup_active = 0;
2229
2230 afi_t rt_afi = family2afi(rn->p.family);
2231
2232 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2233
2234 /* Make a local copy of the existing nhe, so we don't work on/modify
2235 * the shared nhe.
2236 */
2237 curr_nhe = zebra_nhg_copy(re->nhe, re->nhe->id);
2238
2239 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2240 zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
2241 __func__, re, re->nhe, re->nhe->id,
2242 curr_nhe);
2243
2244 /* Clear the existing id, if any: this will avoid any confusion
2245 * if the id exists, and will also force the creation
2246 * of a new nhe reflecting the changes we may make in this local copy.
2247 */
2248 curr_nhe->id = 0;
2249
2250 /* Process nexthops */
2251 curr_active = nexthop_list_active_update(rn, re, curr_nhe->nhg.nexthop);
2252
2253 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2254 zlog_debug("%s: re %p curr_active %u", __func__, re,
2255 curr_active);
2256
2257 /* If there are no backup nexthops, we are done */
2258 if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
2259 goto backups_done;
2260
2261 backup_active = nexthop_list_active_update(
2262 rn, re, zebra_nhg_get_backup_nhg(curr_nhe)->nexthop);
2263
2264 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2265 zlog_debug("%s: re %p backup_active %u", __func__, re,
2266 backup_active);
2267
2268backups_done:
2269
2270 /*
2271 * Ref or create an nhe that matches the current state of the
2272 * nexthop(s).
2273 */
8a507796 2274 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
98cda54a 2275 struct nhg_hash_entry *new_nhe = NULL;
98cda54a 2276
377e29f7
MS
2277 new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
2278
2279 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2280 zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
2281 __func__, re, re->nhe,
2282 re->nhe->id, new_nhe, new_nhe->id);
98cda54a 2283
5463ce26 2284 route_entry_update_nhe(re, new_nhe);
e22e8001
SW
2285 }
2286
377e29f7 2287
086e4e02
SW
2288 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2289 * flag where appropriate.
2290 */
715e5c70 2291 if (curr_active)
086e4e02 2292 zebra_nhg_set_valid_if_active(re->nhe);
98cda54a
SW
2293
2294 /*
377e29f7
MS
2295 * Do not need the old / copied nhe anymore since it
2296 * was either copied over into a new nhe or not
98cda54a
SW
2297 * used at all.
2298 */
377e29f7 2299 zebra_nhg_free(curr_nhe);
9a0d4dd3 2300 return curr_active;
ad28e79a 2301}
5be96a2d 2302
497ff579
SW
2303/* Recursively construct a grp array of fully resolved IDs.
2304 *
2305 * This function allows us to account for groups within groups,
2306 * by converting them into a flat array of IDs.
2307 *
2308 * nh_grp is modified at every level of recursion to append
2309 * to it the next unique, fully resolved ID from the entire tree.
2310 *
2311 *
2312 * Note:
2313 * I'm pretty sure we only allow ONE level of group within group currently.
2314 * But making this recursive just in case that ever changes.
2315 */
2316static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
2317 uint8_t curr_index,
2318 struct nhg_hash_entry *nhe,
2319 int max_num)
98cda54a
SW
2320{
2321 struct nhg_connected *rb_node_dep = NULL;
2322 struct nhg_hash_entry *depend = NULL;
497ff579 2323 uint8_t i = curr_index;
98cda54a 2324
fec211ad 2325 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
8dbc800f
SW
2326 bool duplicate = false;
2327
497ff579
SW
2328 if (i >= max_num)
2329 goto done;
2330
98cda54a
SW
2331 depend = rb_node_dep->nhe;
2332
2333 /*
2334 * If its recursive, use its resolved nhe in the group
2335 */
2336 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
2337 depend = zebra_nhg_resolve(depend);
2338 if (!depend) {
2339 flog_err(
2340 EC_ZEBRA_NHG_FIB_UPDATE,
df31a989
SW
2341 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
2342 nhe->id);
98cda54a
SW
2343 continue;
2344 }
2345 }
2346
497ff579
SW
2347 if (!zebra_nhg_depends_is_empty(depend)) {
2348 /* This is a group within a group */
2349 i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
2350 } else {
086e4e02
SW
2351 if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
2352 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2353 || IS_ZEBRA_DEBUG_NHG)
2354 zlog_debug(
2355 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2356 __func__, depend->id);
2357 continue;
2358 }
2359
1866b3af
SW
2360 /* If the nexthop not installed/queued for install don't
2361 * put in the ID array.
2362 */
2363 if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED)
2364 || CHECK_FLAG(depend->flags,
2365 NEXTHOP_GROUP_QUEUED))) {
2366 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2367 || IS_ZEBRA_DEBUG_NHG)
2368 zlog_debug(
2369 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2370 __func__, depend->id);
2371 continue;
2372 }
2373
b1c3f7ef 2374 /* Check for duplicate IDs, ignore if found. */
497ff579 2375 for (int j = 0; j < i; j++) {
d43122b5 2376 if (depend->id == grp[j].id) {
497ff579 2377 duplicate = true;
d43122b5
SW
2378 break;
2379 }
497ff579 2380 }
8dbc800f 2381
b1c3f7ef
SW
2382 if (duplicate) {
2383 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2384 || IS_ZEBRA_DEBUG_NHG)
2385 zlog_debug(
2386 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2387 __func__, depend->id);
2388 continue;
497ff579 2389 }
b1c3f7ef
SW
2390
2391 grp[i].id = depend->id;
2392 grp[i].weight = depend->nhg.nexthop->weight;
2393 i++;
8dbc800f 2394 }
98cda54a 2395 }
8dbc800f 2396
0328a5bd
MS
2397 if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
2398 goto done;
2399
2400 /* TODO -- For now, we are not trying to use or install any
2401 * backup info in this nexthop-id path: we aren't prepared
2402 * to use the backups here yet. We're just debugging what we find.
2403 */
2404 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2405 zlog_debug("%s: skipping backup nhe", __func__);
2406
8dbc800f 2407done:
98cda54a
SW
2408 return i;
2409}
2410
497ff579
SW
2411/* Convert a nhe into a group array */
2412uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
2413 int max_num)
2414{
2415 /* Call into the recursive function */
2416 return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
2417}
2418
5be96a2d
SW
2419void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
2420{
f429bd1b
SW
2421 struct nhg_connected *rb_node_dep = NULL;
2422
2423 /* Resolve it first */
2424 nhe = zebra_nhg_resolve(nhe);
2425
2426 /* Make sure all depends are installed/queued */
fec211ad 2427 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
f429bd1b
SW
2428 zebra_nhg_install_kernel(rb_node_dep->nhe);
2429 }
2430
086e4e02
SW
2431 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
2432 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
e22e8001 2433 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
724583ed
SW
2434 /* Change its type to us since we are installing it */
2435 nhe->type = ZEBRA_ROUTE_NHG;
2436
147bad16 2437 int ret = dplane_nexthop_add(nhe);
2d3c57e6 2438
147bad16
SW
2439 switch (ret) {
2440 case ZEBRA_DPLANE_REQUEST_QUEUED:
2441 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2442 break;
2443 case ZEBRA_DPLANE_REQUEST_FAILURE:
2444 flog_err(
2445 EC_ZEBRA_DP_INSTALL_FAIL,
2446 "Failed to install Nexthop ID (%u) into the kernel",
2447 nhe->id);
2448 break;
2449 case ZEBRA_DPLANE_REQUEST_SUCCESS:
2450 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
80286aa5 2451 zebra_nhg_handle_install(nhe);
147bad16
SW
2452 break;
2453 }
2454 }
2455}
2456
147bad16
SW
2457void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
2458{
2459 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
2460 int ret = dplane_nexthop_delete(nhe);
2d3c57e6 2461
147bad16
SW
2462 switch (ret) {
2463 case ZEBRA_DPLANE_REQUEST_QUEUED:
2464 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2465 break;
2466 case ZEBRA_DPLANE_REQUEST_FAILURE:
2467 flog_err(
2468 EC_ZEBRA_DP_DELETE_FAIL,
2469 "Failed to uninstall Nexthop ID (%u) from the kernel",
2470 nhe->id);
2471 break;
2472 case ZEBRA_DPLANE_REQUEST_SUCCESS:
2473 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
2474 break;
2475 }
177e711d
SW
2476 }
2477
2478 zebra_nhg_handle_uninstall(nhe);
147bad16
SW
2479}
2480
5f3c9e52
SW
2481void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
2482{
2483 enum dplane_op_e op;
2484 enum zebra_dplane_result status;
2485 uint32_t id = 0;
2486 struct nhg_hash_entry *nhe = NULL;
2487
2488 op = dplane_ctx_get_op(ctx);
2489 status = dplane_ctx_get_status(ctx);
2490
0c8215cb 2491 id = dplane_ctx_get_nhe_id(ctx);
e22e8001 2492
377e29f7 2493 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
177e711d
SW
2494 zlog_debug(
2495 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
2496 ctx, dplane_op2str(op), id, dplane_res2str(status));
5f3c9e52 2497
177e711d
SW
2498 switch (op) {
2499 case DPLANE_OP_NH_DELETE:
2500 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
2501 flog_err(
2502 EC_ZEBRA_DP_DELETE_FAIL,
2503 "Failed to uninstall Nexthop ID (%u) from the kernel",
2504 id);
2505 /* We already free'd the data, nothing to do */
2506 break;
2507 case DPLANE_OP_NH_INSTALL:
2508 case DPLANE_OP_NH_UPDATE:
2509 nhe = zebra_nhg_lookup_id(id);
2510
2511 if (!nhe) {
2512 flog_err(
2513 EC_ZEBRA_NHG_SYNC,
2514 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
2515 dplane_op2str(op), id);
5f3c9e52
SW
2516 break;
2517 }
177e711d
SW
2518
2519 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2520 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
2521 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2522 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
80286aa5 2523 zebra_nhg_handle_install(nhe);
177e711d
SW
2524 } else
2525 flog_err(
2526 EC_ZEBRA_DP_INSTALL_FAIL,
2527 "Failed to install Nexthop ID (%u) into the kernel",
2528 nhe->id);
2529 break;
2530 case DPLANE_OP_ROUTE_INSTALL:
2531 case DPLANE_OP_ROUTE_UPDATE:
2532 case DPLANE_OP_ROUTE_DELETE:
2533 case DPLANE_OP_ROUTE_NOTIFY:
2534 case DPLANE_OP_LSP_INSTALL:
2535 case DPLANE_OP_LSP_UPDATE:
2536 case DPLANE_OP_LSP_DELETE:
2537 case DPLANE_OP_LSP_NOTIFY:
2538 case DPLANE_OP_PW_INSTALL:
2539 case DPLANE_OP_PW_UNINSTALL:
2540 case DPLANE_OP_SYS_ROUTE_ADD:
2541 case DPLANE_OP_SYS_ROUTE_DELETE:
2542 case DPLANE_OP_ADDR_INSTALL:
2543 case DPLANE_OP_ADDR_UNINSTALL:
2544 case DPLANE_OP_MAC_INSTALL:
2545 case DPLANE_OP_MAC_DELETE:
2546 case DPLANE_OP_NEIGH_INSTALL:
2547 case DPLANE_OP_NEIGH_UPDATE:
2548 case DPLANE_OP_NEIGH_DELETE:
2549 case DPLANE_OP_VTEP_ADD:
2550 case DPLANE_OP_VTEP_DELETE:
2551 case DPLANE_OP_NONE:
2552 break;
2553 }
71593b3f
SW
2554
2555 dplane_ctx_fini(&ctx);
5be96a2d
SW
2556}
2557
38e40db1
SW
2558static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
2559{
2560 struct nhg_hash_entry *nhe = NULL;
2561
2562 nhe = (struct nhg_hash_entry *)bucket->data;
2563
2564 /* If its being ref'd, just let it be uninstalled via a route removal */
2565 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
2566 zebra_nhg_uninstall_kernel(nhe);
2567}
2568
2569void zebra_nhg_sweep_table(struct hash *hash)
2570{
2571 hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
2572}
7c99d51b
MS
2573
2574/* Global control to disable use of kernel nexthops, if available. We can't
2575 * force the kernel to support nexthop ids, of course, but we can disable
2576 * zebra's use of them, for testing e.g. By default, if the kernel supports
2577 * nexthop ids, zebra uses them.
2578 */
2579void zebra_nhg_enable_kernel_nexthops(bool set)
2580{
2581 g_nexthops_enabled = set;
2582}
2583
2584bool zebra_nhg_kernel_nexthops_enabled(void)
2585{
2586 return g_nexthops_enabled;
2587}