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