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