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