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