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