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