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