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