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