]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
lib: test vrfs in nexthop_same_firsthop()
[mirror_frr.git] / zebra / zebra_nhg.c
CommitLineData
ad28e79a
SW
1/* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 * Stephen Worley
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23#include <zebra.h>
24
25#include "lib/nexthop.h"
50d89650 26#include "lib/nexthop_group_private.h"
ad28e79a 27#include "lib/routemap.h"
b43434ad 28#include "lib/mpls.h"
69171da2 29#include "lib/jhash.h"
51d80884 30#include "lib/debug.h"
ad28e79a
SW
31
32#include "zebra/connected.h"
33#include "zebra/debug.h"
34#include "zebra/zebra_router.h"
5948f013 35#include "zebra/zebra_nhg_private.h"
ad28e79a
SW
36#include "zebra/zebra_rnh.h"
37#include "zebra/zebra_routemap.h"
51d80884
SW
38#include "zebra/zebra_memory.h"
39#include "zebra/zserv.h"
ad28e79a 40#include "zebra/rt.h"
d9f5b2f5 41#include "zebra_errors.h"
0c8215cb 42#include "zebra_dplane.h"
fe593b78 43#include "zebra/interface.h"
d9f5b2f5 44
51d80884 45DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
a15d4c00 46DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
e22e8001 47DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
0c8215cb 48
38e40db1
SW
49/* id counter to keep in sync with kernel */
50uint32_t id_counter;
51
7c99d51b
MS
52/* */
53static bool g_nexthops_enabled = true;
54
cb86eba3
MS
55static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
56 afi_t afi);
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,
61 afi_t afi);
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
e22e8001 69
5948f013 70static void nhg_connected_free(struct nhg_connected *dep)
0c8215cb 71{
a15d4c00 72 XFREE(MTYPE_NHG_CONNECTED, dep);
0c8215cb
SW
73}
74
5948f013 75static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
0c8215cb 76{
a15d4c00 77 struct nhg_connected *new = NULL;
0c8215cb 78
a15d4c00 79 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
0c8215cb
SW
80 new->nhe = nhe;
81
82 return new;
83}
84
37c6708b 85void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
0c8215cb 86{
a15d4c00 87 struct nhg_connected *rb_node_dep = NULL;
0c8215cb 88
37c6708b 89 if (!nhg_connected_tree_is_empty(head)) {
fec211ad 90 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
37c6708b 91 nhg_connected_tree_del(head, rb_node_dep);
fe593b78
SW
92 nhg_connected_free(rb_node_dep);
93 }
0c8215cb 94 }
0c8215cb
SW
95}
96
37c6708b 97bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
0c8215cb 98{
fec211ad 99 return nhg_connected_tree_count(head) ? false : true;
0c8215cb
SW
100}
101
98cda54a 102struct nhg_connected *
37c6708b 103nhg_connected_tree_root(struct nhg_connected_tree_head *head)
98cda54a 104{
37c6708b 105 return nhg_connected_tree_first(head);
98cda54a
SW
106}
107
5bf15faa
SW
108struct nhg_hash_entry *
109nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
110 struct nhg_hash_entry *depend)
0c8215cb 111{
a15d4c00 112 struct nhg_connected lookup = {};
085304dc 113 struct nhg_connected *remove = NULL;
5bf15faa 114 struct nhg_hash_entry *removed_nhe;
0c8215cb
SW
115
116 lookup.nhe = depend;
3119f6a1 117
085304dc 118 /* Lookup to find the element, then remove it */
37c6708b 119 remove = nhg_connected_tree_find(head, &lookup);
085304dc 120 if (remove)
5bf15faa
SW
121 /* Re-returning here just in case this API changes..
122 * the _del list api's are a bit undefined at the moment.
123 *
124 * So hopefully returning here will make it fail if the api
125 * changes to something different than currently expected.
126 */
127 remove = nhg_connected_tree_del(head, remove);
128
129 /* If the entry was sucessfully removed, free the 'connected` struct */
130 if (remove) {
131 removed_nhe = remove->nhe;
085304dc 132 nhg_connected_free(remove);
5bf15faa
SW
133 return removed_nhe;
134 }
135
136 return NULL;
3119f6a1
SW
137}
138
5bf15faa
SW
139/* Assuming UNIQUE RB tree. If this changes, assumptions here about
140 * insertion need to change.
141 */
142struct nhg_hash_entry *
143nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
144 struct nhg_hash_entry *depend)
3119f6a1 145{
a15d4c00 146 struct nhg_connected *new = NULL;
0c8215cb 147
a15d4c00 148 new = nhg_connected_new(depend);
0c8215cb 149
5bf15faa
SW
150 /* On success, NULL will be returned from the
151 * RB code.
152 */
153 if (new && (nhg_connected_tree_add(head, new) == NULL))
154 return NULL;
155
156 /* If it wasn't successful, it must be a duplicate. We enforce the
157 * unique property for the `nhg_connected` tree.
158 */
159 nhg_connected_free(new);
160
161 return depend;
3119f6a1
SW
162}
163
37c6708b
SW
164static void
165nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
32e29e79
SW
166{
167 struct nhg_connected *rb_node_dep = NULL;
32e29e79 168
fec211ad 169 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
32e29e79
SW
170 zebra_nhg_decrement_ref(rb_node_dep->nhe);
171 }
172}
173
37c6708b
SW
174static void
175nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
32e29e79
SW
176{
177 struct nhg_connected *rb_node_dep = NULL;
178
fec211ad 179 frr_each(nhg_connected_tree, head, rb_node_dep) {
32e29e79
SW
180 zebra_nhg_increment_ref(rb_node_dep->nhe);
181 }
182}
183
98cda54a
SW
184struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
185{
186 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
187 && !zebra_nhg_depends_is_empty(nhe)) {
37c6708b 188 nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
98cda54a
SW
189 return zebra_nhg_resolve(nhe);
190 }
191
192 return nhe;
193}
194
fe593b78 195unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
a15d4c00 196{
37c6708b 197 return nhg_connected_tree_count(&nhe->nhg_depends);
a15d4c00
SW
198}
199
fe593b78 200bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
a15d4c00 201{
37c6708b 202 return nhg_connected_tree_is_empty(&nhe->nhg_depends);
a15d4c00
SW
203}
204
5948f013
SW
205static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
206 struct nhg_hash_entry *depend)
3119f6a1 207{
37c6708b 208 nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
3119f6a1
SW
209}
210
5948f013 211static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
148a0103 212{
37c6708b 213 nhg_connected_tree_init(&nhe->nhg_depends);
148a0103
SW
214}
215
fe593b78
SW
216unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
217{
37c6708b 218 return nhg_connected_tree_count(&nhe->nhg_dependents);
fe593b78
SW
219}
220
5948f013 221
fe593b78
SW
222bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
223{
37c6708b 224 return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
fe593b78
SW
225}
226
5948f013
SW
227static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
228 struct nhg_hash_entry *dependent)
fe593b78 229{
37c6708b 230 nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
fe593b78
SW
231}
232
5948f013
SW
233static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
234 struct nhg_hash_entry *dependent)
fe593b78 235{
37c6708b 236 nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
fe593b78
SW
237}
238
5948f013 239static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
fe593b78 240{
37c6708b 241 nhg_connected_tree_init(&nhe->nhg_dependents);
fe593b78
SW
242}
243
21615102
SW
244/* Release this nhe from anything depending on it */
245static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
246{
80286aa5 247 struct nhg_connected *rb_node_dep = NULL;
21615102 248
80286aa5
SW
249 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
250 zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
251 /* recheck validity of the dependent */
252 zebra_nhg_check_valid(rb_node_dep->nhe);
21615102
SW
253 }
254}
255
5948f013
SW
256/* Release this nhe from anything that it depends on */
257static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
258{
259 if (!zebra_nhg_depends_is_empty(nhe)) {
260 struct nhg_connected *rb_node_dep = NULL;
261
262 frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
263 rb_node_dep) {
264 zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
265 }
266 }
267}
268
269
d9f5b2f5
SW
270struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
271{
0c8215cb 272 struct nhg_hash_entry lookup = {};
d9f5b2f5
SW
273
274 lookup.id = id;
275 return hash_lookup(zrouter.nhgs_id, &lookup);
276}
277
5948f013 278static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
d9f5b2f5
SW
279{
280 if (hash_lookup(zrouter.nhgs_id, nhe)) {
281 flog_err(
282 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
283 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
284 nhe->id);
285 return -1;
286 }
287
288 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
289
290 return 0;
291}
ad28e79a 292
5948f013
SW
293static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
294{
295 nhe->ifp = ifp;
296 if_nhg_dependents_add(ifp, nhe);
297}
298
38e40db1
SW
299static void
300zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
377e29f7 301 struct nhg_connected_tree_head *nhg_depends)
4e49c8b8 302{
a15d4c00
SW
303 struct nhg_connected *rb_node_dep = NULL;
304
38e40db1
SW
305 /* This has been allocated higher above in the stack. Could probably
306 * re-allocate and free the old stuff but just using the same memory
307 * for now. Otherwise, their might be a time trade-off for repeated
308 * alloc/frees as startup.
309 */
377e29f7 310 nhe->nhg_depends = *nhg_depends;
4e49c8b8 311
a15d4c00 312 /* Attach backpointer to anything that it depends on */
fe593b78 313 zebra_nhg_dependents_init(nhe);
a15d4c00 314 if (!zebra_nhg_depends_is_empty(nhe)) {
fec211ad 315 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
377e29f7
MS
316 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
317 zlog_debug("%s: nhe %p (%u), dep %p (%u)",
318 __func__, nhe, nhe->id,
319 rb_node_dep->nhe,
320 rb_node_dep->nhe->id);
321
a15d4c00
SW
322 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
323 }
324 }
377e29f7 325}
4e49c8b8 326
377e29f7
MS
327/* Init an nhe, for use in a hash lookup for example */
328void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
329 const struct nexthop *nh)
330{
331 memset(nhe, 0, sizeof(struct nhg_hash_entry));
332 nhe->vrf_id = VRF_DEFAULT;
333 nhe->type = ZEBRA_ROUTE_NHG;
334 nhe->afi = AFI_UNSPEC;
7b683a96 335
377e29f7
MS
336 /* There are some special rules that apply to groups representing
337 * a single nexthop.
338 */
339 if (nh && (nh->next == NULL)) {
340 switch (nh->type) {
341 case (NEXTHOP_TYPE_IFINDEX):
342 case (NEXTHOP_TYPE_BLACKHOLE):
343 /*
344 * This switch case handles setting the afi different
345 * for ipv4/v6 routes. Ifindex/blackhole nexthop
346 * objects cannot be ambiguous, they must be Address
347 * Family specific. If we get here, we will either use
348 * the AF of the route, or the one we got passed from
349 * here from the kernel.
350 */
351 nhe->afi = afi;
352 break;
353 case (NEXTHOP_TYPE_IPV4_IFINDEX):
354 case (NEXTHOP_TYPE_IPV4):
355 nhe->afi = AFI_IP;
356 break;
357 case (NEXTHOP_TYPE_IPV6_IFINDEX):
358 case (NEXTHOP_TYPE_IPV6):
359 nhe->afi = AFI_IP6;
360 break;
361 }
7b683a96 362 }
38e40db1
SW
363}
364
0eb97b86 365struct nhg_hash_entry *zebra_nhg_alloc(void)
38e40db1
SW
366{
367 struct nhg_hash_entry *nhe;
368
369 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
370
0eb97b86
MS
371 return nhe;
372}
373
f727646a
MS
374/*
375 * Allocate new nhe and make shallow copy of 'orig'; no
376 * recursive info is copied.
377 */
378struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
379 uint32_t id)
0eb97b86
MS
380{
381 struct nhg_hash_entry *nhe;
382
383 nhe = zebra_nhg_alloc();
384
38e40db1
SW
385 nhe->id = id;
386
1d48702e 387 nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
38e40db1 388
1d48702e
MS
389 nhe->vrf_id = orig->vrf_id;
390 nhe->afi = orig->afi;
391 nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
38e40db1
SW
392 nhe->refcnt = 0;
393 nhe->dplane_ref = zebra_router_get_next_sequence();
394
1d48702e
MS
395 /* Copy backup info also, if present */
396 if (orig->backup_info)
397 nhe->backup_info = nhg_backup_copy(orig->backup_info);
398
38e40db1
SW
399 return nhe;
400}
401
402/* Allocation via hash handler */
403static void *zebra_nhg_hash_alloc(void *arg)
404{
405 struct nhg_hash_entry *nhe = NULL;
406 struct nhg_hash_entry *copy = arg;
7b683a96 407
f727646a 408 nhe = zebra_nhe_copy(copy, copy->id);
9ef49038
SW
409
410 /* Mark duplicate nexthops in a group at creation time. */
c415d895 411 nexthop_group_mark_duplicates(&(nhe->nhg));
9ef49038 412
377e29f7
MS
413 zebra_nhg_connect_depends(nhe, &(copy->nhg_depends));
414
415 /* Add the ifp now if it's not a group or recursive and has ifindex */
416 if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop
417 && nhe->nhg.nexthop->ifindex) {
418 struct interface *ifp = NULL;
419
420 ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
421 nhe->nhg.nexthop->vrf_id);
422 if (ifp)
423 zebra_nhg_set_if(nhe, ifp);
424 else
425 flog_err(
426 EC_ZEBRA_IF_LOOKUP_FAILED,
427 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
428 nhe->nhg.nexthop->ifindex,
429 nhe->nhg.nexthop->vrf_id, nhe->id);
430 }
431
d9f5b2f5
SW
432 zebra_nhg_insert_id(nhe);
433
4e49c8b8
DS
434 return nhe;
435}
436
4e49c8b8
DS
437uint32_t zebra_nhg_hash_key(const void *arg)
438{
439 const struct nhg_hash_entry *nhe = arg;
1d48702e
MS
440 uint32_t val, key = 0x5a351234;
441
442 val = nexthop_group_hash(&(nhe->nhg));
443 if (nhe->backup_info) {
444 val = jhash_2words(val,
445 nexthop_group_hash(
446 &(nhe->backup_info->nhe->nhg)),
447 key);
448 }
d9f5b2f5 449
1d48702e 450 key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
d9f5b2f5 451
d9f5b2f5 452 return key;
4e49c8b8
DS
453}
454
a95b8020
SW
455uint32_t zebra_nhg_id_key(const void *arg)
456{
457 const struct nhg_hash_entry *nhe = arg;
458
459 return nhe->id;
460}
461
1d48702e
MS
462/* Helper with common nhg/nhe nexthop comparison logic */
463static bool nhg_compare_nexthops(const struct nexthop *nh1,
464 const struct nexthop *nh2)
465{
f924db49 466 assert(nh1 != NULL && nh2 != NULL);
1d48702e
MS
467
468 /*
469 * We have to check the active flag of each individual one,
470 * not just the overall active_num. This solves the special case
471 * issue of a route with a nexthop group with one nexthop
472 * resolving to itself and thus marking it inactive. If we
473 * have two different routes each wanting to mark a different
474 * nexthop inactive, they need to hash to two different groups.
475 *
476 * If we just hashed on num_active, they would hash the same
477 * which is incorrect.
478 *
479 * ex)
480 * 1.1.1.0/24
481 * -> 1.1.1.1 dummy1 (inactive)
482 * -> 1.1.2.1 dummy2
483 *
484 * 1.1.2.0/24
485 * -> 1.1.1.1 dummy1
486 * -> 1.1.2.1 dummy2 (inactive)
487 *
488 * Without checking each individual one, they would hash to
489 * the same group and both have 1.1.1.1 dummy1 marked inactive.
490 *
491 */
492 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE)
493 != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
494 return false;
495
496 if (!nexthop_same(nh1, nh2))
497 return false;
498
499 return true;
500}
501
4e49c8b8
DS
502bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
503{
504 const struct nhg_hash_entry *nhe1 = arg1;
505 const struct nhg_hash_entry *nhe2 = arg2;
148813c2
SW
506 struct nexthop *nexthop1;
507 struct nexthop *nexthop2;
4e49c8b8 508
98cda54a
SW
509 /* No matter what if they equal IDs, assume equal */
510 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
511 return true;
512
4e49c8b8
DS
513 if (nhe1->vrf_id != nhe2->vrf_id)
514 return false;
515
77b76fc9
SW
516 if (nhe1->afi != nhe2->afi)
517 return false;
518
1d48702e 519 /* Nexthops should be in-order, so we simply compare them in-place */
c415d895 520 for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
f924db49 521 nexthop1 && nexthop2;
148813c2 522 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
148813c2 523
1d48702e 524 if (!nhg_compare_nexthops(nexthop1, nexthop2))
148813c2 525 return false;
1d48702e 526 }
148813c2 527
f924db49
MS
528 /* Check for unequal list lengths */
529 if (nexthop1 || nexthop2)
530 return false;
531
1d48702e
MS
532 /* If there's no backup info, comparison is done. */
533 if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
534 return true;
535
536 /* Compare backup info also - test the easy things first */
537 if (nhe1->backup_info && (nhe2->backup_info == NULL))
538 return false;
539 if (nhe2->backup_info && (nhe1->backup_info == NULL))
540 return false;
541
542 /* Compare number of backups before actually comparing any */
543 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
544 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
545 nexthop1 && nexthop2;
546 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
547 ;
548 }
549
550 /* Did we find the end of one list before the other? */
551 if (nexthop1 || nexthop2)
552 return false;
553
554 /* Have to compare the backup nexthops */
555 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
556 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
f924db49 557 nexthop1 && nexthop2;
1d48702e 558 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
148813c2 559
1d48702e 560 if (!nhg_compare_nexthops(nexthop1, nexthop2))
148813c2
SW
561 return false;
562 }
e4ac313b 563
4e49c8b8
DS
564 return true;
565}
566
d9f5b2f5 567bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 568{
d9f5b2f5
SW
569 const struct nhg_hash_entry *nhe1 = arg1;
570 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 571
d9f5b2f5
SW
572 return nhe1->id == nhe2->id;
573}
4e49c8b8 574
1b366e63
SW
575static int zebra_nhg_process_grp(struct nexthop_group *nhg,
576 struct nhg_connected_tree_head *depends,
577 struct nh_grp *grp, uint8_t count)
e22e8001 578{
37c6708b 579 nhg_connected_tree_init(depends);
e22e8001
SW
580
581 for (int i = 0; i < count; i++) {
582 struct nhg_hash_entry *depend = NULL;
583 /* We do not care about nexthop_grp.weight at
584 * this time. But we should figure out
585 * how to adapt this to our code in
586 * the future.
587 */
38e40db1 588 depend = depends_find_id_add(depends, grp[i].id);
e22e8001 589
38e40db1 590 if (!depend) {
e22e8001
SW
591 flog_err(
592 EC_ZEBRA_NHG_SYNC,
593 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
594 grp[i].id);
1b366e63 595 return -1;
e22e8001 596 }
38e40db1
SW
597
598 /*
599 * If this is a nexthop with its own group
600 * dependencies, add them as well. Not sure its
601 * even possible to have a group within a group
602 * in the kernel.
603 */
604
c415d895 605 copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL);
e22e8001 606 }
1b366e63
SW
607
608 return 0;
e22e8001
SW
609}
610
6384cbcb
SW
611static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
612 struct nexthop *nh, afi_t afi)
613{
614 struct nhg_hash_entry *depend = NULL;
615 struct nexthop_group resolved_ng = {};
616
1d049aba 617 resolved_ng.nexthop = nh;
6384cbcb 618
377e29f7
MS
619 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
620 zlog_debug("%s: head %p, nh %pNHv",
621 __func__, nhg_depends, nh);
622
6384cbcb 623 depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
a7e1b02d 624
377e29f7
MS
625 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
626 zlog_debug("%s: nh %pNHv => %p (%u)",
627 __func__, nh, depend,
628 depend ? depend->id : 0);
629
a7e1b02d
SW
630 if (depend)
631 depends_add(nhg_depends, depend);
6384cbcb 632}
e22e8001 633
377e29f7
MS
634/*
635 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
636 * has an id value, that's used. Create a new global/shared nhe if not found.
637 */
638static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
639 struct nhg_hash_entry *lookup,
640 struct nhg_connected_tree_head *nhg_depends,
641 afi_t afi)
642{
643 bool created = false;
644 bool recursive = false;
0328a5bd 645 struct nhg_hash_entry *newnhe, *backup_nhe;
377e29f7
MS
646 struct nexthop *nh = NULL;
647
648 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
649 zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p",
650 __func__, lookup->id, lookup,
651 lookup->vrf_id, lookup->type,
652 nhg_depends);
653
654 if (lookup->id)
655 (*nhe) = zebra_nhg_lookup_id(lookup->id);
656 else
657 (*nhe) = hash_lookup(zrouter.nhgs, lookup);
658
659 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
660 zlog_debug("%s: lookup => %p (%u)",
661 __func__, (*nhe),
662 (*nhe) ? (*nhe)->id : 0);
663
664 /* If we found an existing object, we're done */
665 if (*nhe)
666 goto done;
667
668 /* We're going to create/insert a new nhe:
669 * assign the next global id value if necessary.
670 */
671 if (lookup->id == 0)
672 lookup->id = ++id_counter;
673 newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
674 created = true;
675
676 /* Mail back the new object */
677 *nhe = newnhe;
678
679 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
680 zlog_debug("%s: => created %p (%u)", __func__, newnhe,
681 newnhe->id);
682
683 /* Only hash/lookup the depends if the first lookup
684 * fails to find something. This should hopefully save a
685 * lot of cycles for larger ecmp sizes.
686 */
687 if (nhg_depends) {
688 /* If you don't want to hash on each nexthop in the
689 * nexthop group struct you can pass the depends
690 * directly. Kernel-side we do this since it just looks
691 * them up via IDs.
692 */
693 zebra_nhg_connect_depends(newnhe, nhg_depends);
694 goto done;
695 }
696
697 /* Prepare dependency relationships if this is not a
698 * singleton nexthop. There are two cases: a single
699 * recursive nexthop, where we need a relationship to the
700 * resolving nexthop; or a group of nexthops, where we need
701 * relationships with the corresponding singletons.
702 */
703 zebra_nhg_depends_init(lookup);
704
705 nh = newnhe->nhg.nexthop;
706
707 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
708 SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
709
710 if (nh->next == NULL) {
711 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
712 /* Single recursive nexthop */
713 handle_recursive_depend(&newnhe->nhg_depends,
714 nh->resolved, afi);
715 recursive = true;
716 }
717 } else {
718 /* List of nexthops */
719 for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
720 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
721 zlog_debug("%s: depends NH %pNHv %s",
722 __func__, nh,
723 CHECK_FLAG(nh->flags,
724 NEXTHOP_FLAG_RECURSIVE) ?
725 "(R)" : "");
726
727 depends_find_add(&newnhe->nhg_depends, nh, afi);
728 }
729 }
730
0328a5bd
MS
731 if (recursive)
732 SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
733
377e29f7
MS
734 if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
735 zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
0328a5bd
MS
736 goto done;
737
738 /* If there are backup nexthops, add them to the backup
739 * depends tree. The rules here are a little different.
740 */
741 recursive = false;
742 backup_nhe = newnhe->backup_info->nhe;
377e29f7 743
0328a5bd 744 nh = backup_nhe->nhg.nexthop;
377e29f7
MS
745
746 /* Singleton recursive NH */
747 if (nh->next == NULL &&
748 CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
749 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
750 zlog_debug("%s: backup depend NH %pNHv (R)",
751 __func__, nh);
752
753 /* Single recursive nexthop */
0328a5bd 754 handle_recursive_depend(&backup_nhe->nhg_depends,
377e29f7
MS
755 nh->resolved, afi);
756 recursive = true;
757 } else {
758 /* One or more backup NHs */
759 for (; nh; nh = nh->next) {
760 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
761 zlog_debug("%s: backup depend NH %pNHv %s",
762 __func__, nh,
763 CHECK_FLAG(nh->flags,
764 NEXTHOP_FLAG_RECURSIVE) ?
765 "(R)" : "");
766
0328a5bd 767 depends_find_add(&backup_nhe->nhg_depends,
377e29f7
MS
768 nh, afi);
769 }
770 }
771
377e29f7 772 if (recursive)
0328a5bd 773 SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
377e29f7
MS
774
775done:
776
777 return created;
778}
779
780/*
781 * Lookup or create an nhe, based on an nhg or an nhe id.
782 */
4505578b
SW
783static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
784 struct nexthop_group *nhg,
37c6708b 785 struct nhg_connected_tree_head *nhg_depends,
38e40db1 786 vrf_id_t vrf_id, afi_t afi, int type)
a95b8020 787{
0c8215cb 788 struct nhg_hash_entry lookup = {};
4505578b
SW
789 bool created = false;
790
1d48702e
MS
791 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
792 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
793 __func__, id, nhg, vrf_id, type,
794 nhg_depends);
795
377e29f7
MS
796 /* Use a temporary nhe and call into the superset/common code */
797 lookup.id = id;
9a1588c4 798 lookup.type = type ? type : ZEBRA_ROUTE_NHG;
c415d895 799 lookup.nhg = *nhg;
e22e8001 800
88cafda7 801 lookup.vrf_id = vrf_id;
c415d895 802 if (lookup.nhg.nexthop->next) {
6384cbcb
SW
803 /* Groups can have all vrfs and AF's in them */
804 lookup.afi = AFI_UNSPEC;
6384cbcb 805 } else {
c415d895 806 switch (lookup.nhg.nexthop->type) {
4d21c7c0
SW
807 case (NEXTHOP_TYPE_IFINDEX):
808 case (NEXTHOP_TYPE_BLACKHOLE):
809 /*
810 * This switch case handles setting the afi different
811 * for ipv4/v6 routes. Ifindex/blackhole nexthop
812 * objects cannot be ambiguous, they must be Address
813 * Family specific. If we get here, we will either use
814 * the AF of the route, or the one we got passed from
815 * here from the kernel.
816 */
817 lookup.afi = afi;
818 break;
819 case (NEXTHOP_TYPE_IPV4_IFINDEX):
820 case (NEXTHOP_TYPE_IPV4):
821 lookup.afi = AFI_IP;
822 break;
823 case (NEXTHOP_TYPE_IPV6_IFINDEX):
824 case (NEXTHOP_TYPE_IPV6):
825 lookup.afi = AFI_IP6;
826 break;
827 }
6384cbcb 828 }
a95b8020 829
377e29f7 830 created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi);
d9f5b2f5 831
4505578b 832 return created;
a95b8020
SW
833}
834
e22e8001 835/* Find/create a single nexthop */
6384cbcb
SW
836static struct nhg_hash_entry *
837zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
3057df51 838{
6384cbcb 839 struct nhg_hash_entry *nhe = NULL;
e22e8001 840 struct nexthop_group nhg = {};
88cafda7 841 vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
e22e8001 842
0eb97b86 843 nexthop_group_add_sorted(&nhg, nh);
e22e8001 844
88cafda7 845 zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
8a507796 846
377e29f7
MS
847 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
848 zlog_debug("%s: nh %pNHv => %p (%u)",
849 __func__, nh, nhe, nhe ? nhe->id : 0);
850
6384cbcb 851 return nhe;
e22e8001
SW
852}
853
10200d40
SW
854static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
855{
856 return ctx->id;
857}
858
1b366e63 859static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
e22e8001
SW
860{
861 ctx->status = status;
862}
863
1b366e63 864static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
e22e8001
SW
865{
866 return ctx->status;
867}
868
869static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
870{
871 ctx->op = op;
872}
873
874static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
875{
876 return ctx->op;
877}
878
10200d40
SW
879static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
880{
881 return ctx->vrf_id;
882}
883
884static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
885{
886 return ctx->type;
887}
888
889static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
890{
891 return ctx->afi;
892}
893
894static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
895{
896 return &ctx->u.nh;
897}
898
899static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
900{
901 return ctx->count;
902}
903
904static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
905{
906 return ctx->u.grp;
907}
908
99e7ab12 909static struct nhg_ctx *nhg_ctx_new(void)
7c6d5f25 910{
99e7ab12 911 struct nhg_ctx *new;
7c6d5f25
SW
912
913 new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
914
915 return new;
916}
917
918static void nhg_ctx_free(struct nhg_ctx **ctx)
919{
920 struct nexthop *nh;
921
922 if (ctx == NULL)
923 return;
924
925 assert((*ctx) != NULL);
926
927 if (nhg_ctx_get_count(*ctx))
928 goto done;
929
930 nh = nhg_ctx_get_nh(*ctx);
931
932 nexthop_del_labels(nh);
933
934done:
935 XFREE(MTYPE_NHG_CTX, *ctx);
7c6d5f25
SW
936}
937
81505946
SW
938static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
939 struct nh_grp *grp, vrf_id_t vrf_id,
940 afi_t afi, int type, uint8_t count)
941{
942 struct nhg_ctx *ctx = NULL;
943
944 ctx = nhg_ctx_new();
945
946 ctx->id = id;
947 ctx->vrf_id = vrf_id;
948 ctx->afi = afi;
949 ctx->type = type;
950 ctx->count = count;
951
952 if (count)
953 /* Copy over the array */
954 memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
955 else if (nh)
956 ctx->u.nh = *nh;
957
958 return ctx;
959}
960
c1da832a 961static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
38e40db1
SW
962{
963 struct nhg_connected *rb_node_dep = NULL;
964
fec211ad 965 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
38e40db1 966 if (CHECK_FLAG(rb_node_dep->nhe->flags,
c1da832a 967 NEXTHOP_GROUP_UNHASHABLE))
38e40db1
SW
968 return true;
969 }
970
971 return false;
972}
973
c1da832a 974static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
38e40db1 975{
c1da832a 976 SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
38e40db1
SW
977 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
978
cb3e512d
MS
979 flog(LOG_INFO,
980 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
981 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
982 nhe->id);
38e40db1
SW
983}
984
80286aa5
SW
985static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
986{
987 struct nhg_connected *rb_node_dep;
988
989 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
990
991 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
992 zebra_nhg_set_valid(rb_node_dep->nhe);
993}
994
995static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
996{
997 struct nhg_connected *rb_node_dep;
998
999 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1000
1001 /* Update validity of nexthops depending on it */
1002 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1003 zebra_nhg_check_valid(rb_node_dep->nhe);
1004}
1005
1006void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
1007{
1008 struct nhg_connected *rb_node_dep = NULL;
1009 bool valid = false;
1010
1011 /* If anthing else in the group is valid, the group is valid */
1012 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1013 if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
1014 valid = true;
1015 goto done;
1016 }
1017 }
1018
1019done:
1020 if (valid)
1021 zebra_nhg_set_valid(nhe);
1022 else
1023 zebra_nhg_set_invalid(nhe);
1024}
1025
1026
177e711d 1027static void zebra_nhg_release(struct nhg_hash_entry *nhe)
9a1588c4 1028{
377e29f7
MS
1029 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1030 zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
1031
9a1588c4
SW
1032 /* Remove it from any lists it may be on */
1033 zebra_nhg_depends_release(nhe);
1034 zebra_nhg_dependents_release(nhe);
1035 if (nhe->ifp)
1036 if_nhg_dependents_del(nhe->ifp, nhe);
1037
1038 /*
c1da832a 1039 * If its unhashable, we didn't store it here and have to be
9a1588c4
SW
1040 * sure we don't clear one thats actually being used.
1041 */
c1da832a 1042 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
9a1588c4 1043 hash_release(zrouter.nhgs, nhe);
9a1588c4 1044
9a1588c4
SW
1045 hash_release(zrouter.nhgs_id, nhe);
1046}
1047
9a1588c4
SW
1048static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
1049{
177e711d 1050 zebra_nhg_release(nhe);
9a1588c4
SW
1051 zebra_nhg_free(nhe);
1052}
1053
80286aa5
SW
1054static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
1055{
1056 /* Update validity of groups depending on it */
1057 struct nhg_connected *rb_node_dep;
1058
1059 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1060 zebra_nhg_set_valid(rb_node_dep->nhe);
1061}
1062
9a1588c4
SW
1063/*
1064 * The kernel/other program has changed the state of a nexthop object we are
1065 * using.
1066 */
1067static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
1068 bool is_delete)
1069{
1070 if (nhe->refcnt) {
1071 flog_err(
1072 EC_ZEBRA_NHG_SYNC,
1073 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
1074 (is_delete ? "deleted" : "updated"), nhe->id);
1075
1076 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1077 zebra_nhg_install_kernel(nhe);
177e711d 1078 } else
9a1588c4 1079 zebra_nhg_handle_uninstall(nhe);
9a1588c4
SW
1080}
1081
e22e8001
SW
1082static int nhg_ctx_process_new(struct nhg_ctx *ctx)
1083{
1084 struct nexthop_group *nhg = NULL;
37c6708b 1085 struct nhg_connected_tree_head nhg_depends = {};
9a1588c4 1086 struct nhg_hash_entry *lookup = NULL;
3057df51
SW
1087 struct nhg_hash_entry *nhe = NULL;
1088
10200d40
SW
1089 uint32_t id = nhg_ctx_get_id(ctx);
1090 uint8_t count = nhg_ctx_get_count(ctx);
1091 vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
1092 int type = nhg_ctx_get_type(ctx);
1093 afi_t afi = nhg_ctx_get_afi(ctx);
1094
1095 lookup = zebra_nhg_lookup_id(id);
9a1588c4 1096
377e29f7
MS
1097 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1098 zlog_debug("%s: id %u, count %d, lookup => %p",
1099 __func__, id, count, lookup);
1100
9a1588c4
SW
1101 if (lookup) {
1102 /* This is already present in our table, hence an update
1103 * that we did not initate.
1104 */
1105 zebra_nhg_handle_kernel_state_change(lookup, false);
1106 return 0;
1107 }
1108
10200d40 1109 if (nhg_ctx_get_count(ctx)) {
e22e8001 1110 nhg = nexthop_group_new();
1b366e63
SW
1111 if (zebra_nhg_process_grp(nhg, &nhg_depends,
1112 nhg_ctx_get_grp(ctx), count)) {
1113 depends_decrement_free(&nhg_depends);
d3a35138 1114 nexthop_group_delete(&nhg);
fec211ad 1115 return -ENOENT;
1b366e63
SW
1116 }
1117
10200d40
SW
1118 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
1119 afi))
38e40db1 1120 depends_decrement_free(&nhg_depends);
4505578b 1121
e22e8001 1122 /* These got copied over in zebra_nhg_alloc() */
d3a35138 1123 nexthop_group_delete(&nhg);
38e40db1 1124 } else
10200d40
SW
1125 nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
1126 type);
e22e8001
SW
1127
1128 if (nhe) {
10200d40 1129 if (id != nhe->id) {
38e40db1
SW
1130 struct nhg_hash_entry *kernel_nhe = NULL;
1131
e22e8001 1132 /* Duplicate but with different ID from
2d3c57e6
SW
1133 * the kernel
1134 */
e22e8001
SW
1135
1136 /* The kernel allows duplicate nexthops
1137 * as long as they have different IDs.
1138 * We are ignoring those to prevent
1139 * syncing problems with the kernel
1140 * changes.
38e40db1
SW
1141 *
1142 * We maintain them *ONLY* in the ID hash table to
c1da832a
SW
1143 * track them and set the flag to indicated
1144 * their attributes are unhashable.
38e40db1
SW
1145 */
1146
f727646a 1147 kernel_nhe = zebra_nhe_copy(nhe, id);
377e29f7
MS
1148
1149 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1150 zlog_debug("%s: copying kernel nhe (%u), dup of %u",
1151 __func__, id, nhe->id);
1152
38e40db1 1153 zebra_nhg_insert_id(kernel_nhe);
c1da832a
SW
1154 zebra_nhg_set_unhashable(kernel_nhe);
1155 } else if (zebra_nhg_contains_unhashable(nhe)) {
1156 /* The group we got contains an unhashable/duplicated
1157 * depend, so lets mark this group as unhashable as well
1158 * and release it from the non-ID hash.
e22e8001 1159 */
377e29f7
MS
1160 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1161 zlog_debug("%s: nhe %p (%u) unhashable",
1162 __func__, nhe, nhe->id);
1163
38e40db1 1164 hash_release(zrouter.nhgs, nhe);
c1da832a 1165 zebra_nhg_set_unhashable(nhe);
38e40db1 1166 } else {
e22e8001 1167 /* It actually created a new nhe */
377e29f7
MS
1168 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1169 zlog_debug("%s: nhe %p (%u) is new",
1170 __func__, nhe, nhe->id);
1171
38e40db1
SW
1172 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1173 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
e22e8001
SW
1174 }
1175 } else {
1176 flog_err(
1177 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1178 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
10200d40 1179 id);
e22e8001
SW
1180 return -1;
1181 }
1182
1183 return 0;
1184}
1185
9a1588c4
SW
1186static int nhg_ctx_process_del(struct nhg_ctx *ctx)
1187{
1188 struct nhg_hash_entry *nhe = NULL;
10200d40 1189 uint32_t id = nhg_ctx_get_id(ctx);
9a1588c4 1190
10200d40 1191 nhe = zebra_nhg_lookup_id(id);
9a1588c4
SW
1192
1193 if (!nhe) {
1194 flog_warn(
1195 EC_ZEBRA_BAD_NHG_MESSAGE,
1196 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
10200d40 1197 id);
81505946 1198 return -1;
9a1588c4
SW
1199 }
1200
1201 zebra_nhg_handle_kernel_state_change(nhe, true);
1202
1203 return 0;
1204}
1205
7c6d5f25 1206static void nhg_ctx_fini(struct nhg_ctx **ctx)
e22e8001
SW
1207{
1208 /*
1209 * Just freeing for now, maybe do something more in the future
1210 * based on flag.
1211 */
1212
7134ba70 1213 nhg_ctx_free(ctx);
e22e8001
SW
1214}
1215
1b366e63
SW
1216static int queue_add(struct nhg_ctx *ctx)
1217{
1218 /* If its queued or already processed do nothing */
1219 if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
1220 return 0;
1221
1222 if (rib_queue_nhg_add(ctx)) {
1223 nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
1224 return -1;
1225 }
1226
1227 nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
1228
1229 return 0;
1230}
1231
e22e8001
SW
1232int nhg_ctx_process(struct nhg_ctx *ctx)
1233{
1234 int ret = 0;
1235
1236 switch (nhg_ctx_get_op(ctx)) {
1237 case NHG_CTX_OP_NEW:
1238 ret = nhg_ctx_process_new(ctx);
fec211ad 1239 if (nhg_ctx_get_count(ctx) && ret == -ENOENT
1b366e63 1240 && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
e1292378
SW
1241 /**
1242 * We have entered a situation where we are
1243 * processing a group from the kernel
1244 * that has a contained nexthop which
1245 * we have not yet processed.
1b366e63 1246 *
e1292378
SW
1247 * Re-enqueue this ctx to be handled exactly one
1248 * more time (indicated by the flag).
1249 *
1250 * By the time we get back to it, we
1251 * should have processed its depends.
1b366e63
SW
1252 */
1253 nhg_ctx_set_status(ctx, NHG_CTX_NONE);
1254 if (queue_add(ctx) == 0) {
1255 nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
1256 return 0;
1257 }
1258 }
e22e8001
SW
1259 break;
1260 case NHG_CTX_OP_DEL:
9a1588c4 1261 ret = nhg_ctx_process_del(ctx);
e22e8001
SW
1262 case NHG_CTX_OP_NONE:
1263 break;
1264 }
1265
1266 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
1267
7c6d5f25 1268 nhg_ctx_fini(&ctx);
e22e8001
SW
1269
1270 return ret;
1271}
3057df51 1272
e22e8001
SW
1273/* Kernel-side, you either get a single new nexthop or a array of ID's */
1274int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
38e40db1
SW
1275 uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
1276 int startup)
e22e8001 1277{
e22e8001
SW
1278 struct nhg_ctx *ctx = NULL;
1279
377e29f7
MS
1280 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1281 zlog_debug("%s: nh %pNHv, id %u, count %d",
1282 __func__, nh, id, (int)count);
1283
38e40db1
SW
1284 if (id > id_counter)
1285 /* Increase our counter so we don't try to create
1286 * an ID that already exists
1287 */
1288 id_counter = id;
1289
81505946 1290 ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
e22e8001
SW
1291 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
1292
38e40db1
SW
1293 /* Under statup conditions, we need to handle them immediately
1294 * like we do for routes. Otherwise, we are going to get a route
1295 * with a nhe_id that we have not handled.
1296 */
1297 if (startup)
1298 return nhg_ctx_process(ctx);
1299
e22e8001 1300 if (queue_add(ctx)) {
7c6d5f25 1301 nhg_ctx_fini(&ctx);
e22e8001
SW
1302 return -1;
1303 }
1304
1305 return 0;
1306}
1307
9a1588c4 1308/* Kernel-side, received delete message */
88cafda7 1309int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
9a1588c4
SW
1310{
1311 struct nhg_ctx *ctx = NULL;
1312
88cafda7 1313 ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
9a1588c4
SW
1314
1315 nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
1316
1317 if (queue_add(ctx)) {
7c6d5f25 1318 nhg_ctx_fini(&ctx);
9a1588c4
SW
1319 return -1;
1320 }
1321
1322 return 0;
1323}
1324
5657e7e9 1325/* Some dependency helper functions */
0fff714e
SW
1326static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
1327 afi_t afi)
98cda54a 1328{
0fff714e
SW
1329 struct nhg_hash_entry *nhe;
1330 struct nexthop *lookup = NULL;
98cda54a 1331
77bf9504 1332 lookup = nexthop_dup(nh, NULL);
0fff714e
SW
1333
1334 nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
1335
1336 nexthops_free(lookup);
1337
1338 return nhe;
1339}
1340
1341static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
1342 afi_t afi)
1343{
1344 struct nhg_hash_entry *nhe;
1345 struct nexthop lookup = {};
606fa9e5 1346
cb86eba3
MS
1347 /* Capture a snapshot of this single nh; it might be part of a list,
1348 * so we need to make a standalone copy.
1349 */
77bf9504 1350 nexthop_copy_no_recurse(&lookup, nh, NULL);
8a507796 1351
cb86eba3 1352 nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
8a507796 1353
cb86eba3
MS
1354 /* The copy may have allocated labels; free them if necessary. */
1355 nexthop_del_labels(&lookup);
4505578b 1356
377e29f7
MS
1357 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1358 zlog_debug("%s: nh %pNHv => %p (%u)",
1359 __func__, nh, nhe, nhe ? nhe->id : 0);
1360
0fff714e
SW
1361 return nhe;
1362}
1363
1364static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
1365{
1366 struct nhg_hash_entry *nhe = NULL;
377e29f7 1367 char rbuf[10];
0fff714e
SW
1368
1369 if (!nh)
1370 goto done;
1371
1372 /* We are separating these functions out to increase handling speed
1373 * in the non-recursive case (by not alloc/freeing)
1374 */
377e29f7 1375 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
0fff714e 1376 nhe = depends_find_recursive(nh, afi);
377e29f7
MS
1377 strlcpy(rbuf, "(R)", sizeof(rbuf));
1378 } else {
0fff714e 1379 nhe = depends_find_singleton(nh, afi);
377e29f7
MS
1380 rbuf[0] = '\0';
1381 }
1382
1383 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1384 zlog_debug("%s: nh %pNHv %s => %p (%u)",
1385 __func__, nh, rbuf,
1386 nhe, nhe ? nhe->id : 0);
0fff714e 1387
606fa9e5 1388done:
4505578b 1389 return nhe;
98cda54a
SW
1390}
1391
37c6708b 1392static void depends_add(struct nhg_connected_tree_head *head,
5657e7e9
SW
1393 struct nhg_hash_entry *depend)
1394{
377e29f7
MS
1395 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1396 zlog_debug("%s: head %p nh %pNHv",
1397 __func__, head, depend->nhg.nexthop);
1398
5bf15faa
SW
1399 /* If NULL is returned, it was successfully added and
1400 * needs to have its refcnt incremented.
1401 *
1402 * Else the NHE is already present in the tree and doesn't
1403 * need to increment the refcnt.
1404 */
1405 if (nhg_connected_tree_add_nhe(head, depend) == NULL)
1406 zebra_nhg_increment_ref(depend);
5657e7e9
SW
1407}
1408
38e40db1
SW
1409static struct nhg_hash_entry *
1410depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1411 afi_t afi)
5657e7e9
SW
1412{
1413 struct nhg_hash_entry *depend = NULL;
1414
1415 depend = depends_find(nh, afi);
1b366e63 1416
1d48702e
MS
1417 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1418 zlog_debug("%s: nh %pNHv => %p",
1419 __func__, nh, depend);
1420
1b366e63
SW
1421 if (depend)
1422 depends_add(head, depend);
38e40db1
SW
1423
1424 return depend;
1425}
1426
1427static struct nhg_hash_entry *
1428depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1429{
1430 struct nhg_hash_entry *depend = NULL;
1431
1432 depend = zebra_nhg_lookup_id(id);
1b366e63
SW
1433
1434 if (depend)
1435 depends_add(head, depend);
38e40db1
SW
1436
1437 return depend;
5657e7e9
SW
1438}
1439
37c6708b 1440static void depends_decrement_free(struct nhg_connected_tree_head *head)
5657e7e9 1441{
37c6708b
SW
1442 nhg_connected_tree_decrement_ref(head);
1443 nhg_connected_tree_free(head);
5657e7e9
SW
1444}
1445
377e29f7 1446/* Find an nhe based on a list of nexthops */
7f997721
SW
1447struct nhg_hash_entry *
1448zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
e22e8001
SW
1449{
1450 struct nhg_hash_entry *nhe = NULL;
88cafda7
DS
1451 vrf_id_t vrf_id;
1452
1453 /*
1454 * CLANG SA is complaining that nexthop may be NULL
1455 * Make it happy but this is ridonc
1456 */
1457 assert(nhg->nexthop);
1458 vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
98cda54a 1459
88cafda7 1460 zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
4505578b 1461
377e29f7
MS
1462 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1463 zlog_debug("%s: => nhe %p (%u)",
1464 __func__, nhe, nhe ? nhe->id : 0);
1465
1466 return nhe;
1467}
1468
1469/* Find an nhe based on a route's nhe */
1470struct nhg_hash_entry *
1471zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
1472{
1473 struct nhg_hash_entry *nhe = NULL;
1474
1475 if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
1476 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1477 "No nexthop passed to %s", __func__);
1478 return NULL;
1479 }
1480
1481 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
f924db49 1482 zlog_debug("%s: rt_nhe %p (%u)", __func__, rt_nhe, rt_nhe->id);
377e29f7
MS
1483
1484 zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi);
1485
1486 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1487 zlog_debug("%s: => nhe %p (%u)",
1488 __func__, nhe, nhe ? nhe->id : 0);
1489
3057df51
SW
1490 return nhe;
1491}
1492
1d48702e
MS
1493/*
1494 * Allocate backup nexthop info object. Typically these are embedded in
1495 * nhg_hash_entry objects.
1496 */
1497struct nhg_backup_info *zebra_nhg_backup_alloc(void)
1498{
1499 struct nhg_backup_info *p;
1500
1501 p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
1502
1503 p->nhe = zebra_nhg_alloc();
1504
1505 /* Identify the embedded group used to hold the list of backups */
1506 SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
1507
1508 return p;
1509}
1510
1511/*
1512 * Free backup nexthop info object, deal with any embedded allocations
1513 */
1514void zebra_nhg_backup_free(struct nhg_backup_info **p)
1515{
1516 if (p && *p) {
1517 if ((*p)->nhe)
1518 zebra_nhg_free((*p)->nhe);
1519
1520 XFREE(MTYPE_NHG, (*p));
1521 }
1522}
1523
1d48702e
MS
1524/* Accessor for backup nexthop group */
1525struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
1526{
1527 struct nexthop_group *p = NULL;
1528
1529 if (nhe) {
1530 if (nhe->backup_info && nhe->backup_info->nhe)
1531 p = &(nhe->backup_info->nhe->nhg);
1532 }
1533
1534 return p;
1535}
1536
1537/*
1538 * Helper to return a copy of a backup_info - note that this is a shallow
1539 * copy, meant to be used when creating a new nhe from info passed in with
1540 * a route e.g.
1541 */
1542static struct nhg_backup_info *
1543nhg_backup_copy(const struct nhg_backup_info *orig)
1544{
1545 struct nhg_backup_info *b;
1546
1547 b = zebra_nhg_backup_alloc();
1548
1549 /* Copy list of nexthops */
1550 nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
1551
1552 return b;
1553}
1554
5948f013 1555static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
b599cd2a 1556{
c415d895
MS
1557 nexthops_free(nhe->nhg.nexthop);
1558
1d48702e
MS
1559 zebra_nhg_backup_free(&nhe->backup_info);
1560
58396544 1561 /* Decrement to remove connection ref */
37c6708b
SW
1562 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1563 nhg_connected_tree_free(&nhe->nhg_depends);
1564 nhg_connected_tree_free(&nhe->nhg_dependents);
b599cd2a
SW
1565}
1566
0eb97b86 1567void zebra_nhg_free(struct nhg_hash_entry *nhe)
a95b8020 1568{
377e29f7
MS
1569 if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1570 /* Group or singleton? */
1571 if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1572 zlog_debug("%s: nhe %p (%u), refcnt %d",
f924db49 1573 __func__, nhe, nhe->id, nhe->refcnt);
377e29f7
MS
1574 else
1575 zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
f924db49 1576 __func__, nhe, nhe->id, nhe->refcnt,
377e29f7
MS
1577 nhe->nhg.nexthop);
1578 }
1579
38e40db1
SW
1580 if (nhe->refcnt)
1581 zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
1582
8e401b25 1583 zebra_nhg_free_members(nhe);
51d80884
SW
1584
1585 XFREE(MTYPE_NHG, nhe);
a95b8020
SW
1586}
1587
0eb97b86
MS
1588void zebra_nhg_hash_free(void *p)
1589{
1590 zebra_nhg_free((struct nhg_hash_entry *)p);
1591}
1592
d9f5b2f5
SW
1593void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1594{
377e29f7
MS
1595 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1596 zlog_debug("%s: nhe %p (%u) %d => %d",
1597 __func__, nhe, nhe->id, nhe->refcnt,
1598 nhe->refcnt - 1);
1599
e22e8001
SW
1600 nhe->refcnt--;
1601
32e29e79 1602 if (!zebra_nhg_depends_is_empty(nhe))
37c6708b 1603 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
f54ef6a5 1604
38e40db1 1605 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
cb50cbc9 1606 zebra_nhg_uninstall_kernel(nhe);
7fd392cc
SW
1607}
1608
7fd392cc
SW
1609void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1610{
377e29f7
MS
1611 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1612 zlog_debug("%s: nhe %p (%u) %d => %d",
1613 __func__, nhe, nhe->id, nhe->refcnt,
1614 nhe->refcnt + 1);
1615
e22e8001
SW
1616 nhe->refcnt++;
1617
32e29e79 1618 if (!zebra_nhg_depends_is_empty(nhe))
37c6708b 1619 nhg_connected_tree_increment_ref(&nhe->nhg_depends);
e22e8001 1620}
d9f5b2f5 1621
ad28e79a
SW
1622static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
1623 struct nexthop *nexthop)
1624{
1625 struct nexthop *resolved_hop;
b43434ad
SW
1626 uint8_t num_labels = 0;
1627 mpls_label_t labels[MPLS_MAX_LABELS];
1628 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1629 int i = 0;
ad28e79a
SW
1630
1631 resolved_hop = nexthop_new();
1632 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1633
1634 resolved_hop->vrf_id = nexthop->vrf_id;
1635 switch (newhop->type) {
1636 case NEXTHOP_TYPE_IPV4:
1637 case NEXTHOP_TYPE_IPV4_IFINDEX:
1638 /* If the resolving route specifies a gateway, use it */
1639 resolved_hop->type = newhop->type;
1640 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1641
1642 if (newhop->ifindex) {
1643 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1644 resolved_hop->ifindex = newhop->ifindex;
1645 }
1646 break;
1647 case NEXTHOP_TYPE_IPV6:
1648 case NEXTHOP_TYPE_IPV6_IFINDEX:
1649 resolved_hop->type = newhop->type;
1650 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1651
1652 if (newhop->ifindex) {
1653 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1654 resolved_hop->ifindex = newhop->ifindex;
1655 }
1656 break;
1657 case NEXTHOP_TYPE_IFINDEX:
1658 /* If the resolving route is an interface route,
1659 * it means the gateway we are looking up is connected
1660 * to that interface. (The actual network is _not_ onlink).
1661 * Therefore, the resolved route should have the original
1662 * gateway as nexthop as it is directly connected.
1663 *
1664 * On Linux, we have to set the onlink netlink flag because
1665 * otherwise, the kernel won't accept the route.
1666 */
1667 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1668 if (afi == AFI_IP) {
1669 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1670 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1671 } else if (afi == AFI_IP6) {
1672 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1673 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1674 }
1675 resolved_hop->ifindex = newhop->ifindex;
1676 break;
1677 case NEXTHOP_TYPE_BLACKHOLE:
1678 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 1679 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
1680 break;
1681 }
1682
1683 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1684 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1685
b43434ad
SW
1686 /* Copy labels of the resolved route and the parent resolving to it */
1687 if (newhop->nh_label) {
6bc5d977
MS
1688 for (i = 0; i < newhop->nh_label->num_labels; i++) {
1689 /* Be a bit picky about overrunning the local array */
1690 if (num_labels >= MPLS_MAX_LABELS) {
1691 if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1692 zlog_debug("%s: too many labels in newhop %pNHv",
1693 __func__, newhop);
1694 break;
1695 }
b43434ad 1696 labels[num_labels++] = newhop->nh_label->label[i];
6bc5d977
MS
1697 }
1698 /* Use the "outer" type */
b43434ad
SW
1699 label_type = newhop->nh_label_type;
1700 }
1701
1702 if (nexthop->nh_label) {
6bc5d977
MS
1703 for (i = 0; i < nexthop->nh_label->num_labels; i++) {
1704 /* Be a bit picky about overrunning the local array */
1705 if (num_labels >= MPLS_MAX_LABELS) {
1706 if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1707 zlog_debug("%s: too many labels in nexthop %pNHv",
1708 __func__, nexthop);
1709 break;
1710 }
b43434ad 1711 labels[num_labels++] = nexthop->nh_label->label[i];
6bc5d977 1712 }
b43434ad 1713
6bc5d977
MS
1714 /* If the parent has labels, use its type if
1715 * we don't already have one.
1716 */
1717 if (label_type == ZEBRA_LSP_NONE)
1718 label_type = nexthop->nh_label_type;
b43434ad
SW
1719 }
1720
1721 if (num_labels)
1722 nexthop_add_labels(resolved_hop, label_type, num_labels,
1723 labels);
ad28e79a
SW
1724
1725 resolved_hop->rparent = nexthop;
50d89650 1726 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
1727}
1728
6913cb1b
SW
1729/* Checks if nexthop we are trying to resolve to is valid */
1730static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1731 const struct nexthop *resolved)
1732{
1733 /* Can't resolve to a recursive nexthop */
1734 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1735 return false;
1736
9d43854d
MS
1737 /* Must be ACTIVE */
1738 if (!CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_ACTIVE))
1739 return false;
1740
6913cb1b
SW
1741 switch (nexthop->type) {
1742 case NEXTHOP_TYPE_IPV4_IFINDEX:
1743 case NEXTHOP_TYPE_IPV6_IFINDEX:
1744 /* If the nexthop we are resolving to does not match the
1745 * ifindex for the nexthop the route wanted, its not valid.
1746 */
1747 if (nexthop->ifindex != resolved->ifindex)
1748 return false;
1749 break;
1750 case NEXTHOP_TYPE_IPV4:
1751 case NEXTHOP_TYPE_IPV6:
1752 case NEXTHOP_TYPE_IFINDEX:
1753 case NEXTHOP_TYPE_BLACKHOLE:
1754 break;
1755 }
1756
1757 return true;
1758}
1759
ad28e79a
SW
1760/*
1761 * Given a nexthop we need to properly recursively resolve
1762 * the route. As such, do a table lookup to find and match
98cda54a
SW
1763 * if at all possible. Set the nexthop->ifindex and resolved_id
1764 * as appropriate
ad28e79a
SW
1765 */
1766static int nexthop_active(afi_t afi, struct route_entry *re,
8a507796 1767 struct nexthop *nexthop, struct route_node *top)
ad28e79a
SW
1768{
1769 struct prefix p;
1770 struct route_table *table;
1771 struct route_node *rn;
1772 struct route_entry *match = NULL;
1773 int resolved;
1774 struct nexthop *newhop;
1775 struct interface *ifp;
1776 rib_dest_t *dest;
5a0bdc78 1777 struct zebra_vrf *zvrf;
ad28e79a
SW
1778
1779 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
1780 || nexthop->type == NEXTHOP_TYPE_IPV6)
1781 nexthop->ifindex = 0;
1782
8a507796 1783
ad28e79a
SW
1784 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
1785 nexthops_free(nexthop->resolved);
1786 nexthop->resolved = NULL;
1787 re->nexthop_mtu = 0;
1788
377e29f7
MS
1789 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1790 zlog_debug("%s: re %p, nexthop %pNHv",
1791 __func__, re, nexthop);
1792
ad28e79a 1793 /*
a8c427ee 1794 * If the kernel has sent us a NEW route, then
ad28e79a 1795 * by golly gee whiz it's a good route.
a8c427ee
SW
1796 *
1797 * If its an already INSTALLED route we have already handled, then the
1798 * kernel route's nexthop might have became unreachable
1799 * and we have to handle that.
ad28e79a 1800 */
a8c427ee
SW
1801 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
1802 && (re->type == ZEBRA_ROUTE_KERNEL
1803 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
1804 return 1;
1805
1806 /*
12b4d77b 1807 * If the nexthop has been marked as 'onlink' we just need to make
1808 * sure the nexthop's interface is known and is operational.
ad28e79a
SW
1809 */
1810 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
1811 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1812 if (!ifp) {
12b4d77b 1813 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1814 zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
1815 nexthop, nexthop->ifindex);
ad28e79a
SW
1816 return 0;
1817 }
12b4d77b 1818 if (!if_is_operative(ifp)) {
1819 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1820 zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
1821 nexthop, ifp->name);
2d3c57e6 1822 return 0;
ad28e79a 1823 }
12b4d77b 1824 return 1;
ad28e79a
SW
1825 }
1826
4dcc2276
DS
1827 if ((top->p.family == AF_INET && top->p.prefixlen == 32
1828 && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
1829 || (top->p.family == AF_INET6 && top->p.prefixlen == 128
1830 && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
1831 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1832 zlog_debug(
d6951e5e 1833 " :%s: Attempting to install a max prefixlength route through itself",
5e81f5dd 1834 __func__);
4dcc2276
DS
1835 return 0;
1836 }
1837
ad28e79a
SW
1838 /* Make lookup prefix. */
1839 memset(&p, 0, sizeof(struct prefix));
1840 switch (afi) {
1841 case AFI_IP:
1842 p.family = AF_INET;
1843 p.prefixlen = IPV4_MAX_PREFIXLEN;
1844 p.u.prefix4 = nexthop->gate.ipv4;
1845 break;
1846 case AFI_IP6:
1847 p.family = AF_INET6;
1848 p.prefixlen = IPV6_MAX_PREFIXLEN;
1849 p.u.prefix6 = nexthop->gate.ipv6;
1850 break;
1851 default:
1852 assert(afi != AFI_IP && afi != AFI_IP6);
1853 break;
1854 }
1855 /* Lookup table. */
1856 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
1857 /* get zvrf */
1858 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1859 if (!table || !zvrf) {
ad28e79a 1860 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e 1861 zlog_debug(" %s: Table not found", __func__);
ad28e79a
SW
1862 return 0;
1863 }
1864
1865 rn = route_node_match(table, (struct prefix *)&p);
1866 while (rn) {
1867 route_unlock_node(rn);
1868
1869 /* Lookup should halt if we've matched against ourselves ('top',
1870 * if specified) - i.e., we cannot have a nexthop NH1 is
1871 * resolved by a route NH1. The exception is if the route is a
1872 * host route.
1873 */
92756825 1874 if (rn == top)
ad28e79a
SW
1875 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
1876 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
1877 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1878 zlog_debug(
d6951e5e 1879 " %s: Matched against ourself and prefix length is not max bit length",
5e81f5dd 1880 __func__);
ad28e79a
SW
1881 return 0;
1882 }
1883
1884 /* Pick up selected route. */
1885 /* However, do not resolve over default route unless explicitly
2d3c57e6
SW
1886 * allowed.
1887 */
ad28e79a 1888 if (is_default_prefix(&rn->p)
5a0bdc78 1889 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
1890 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1891 zlog_debug(
d6951e5e 1892 " :%s: Resolved against default route",
5e81f5dd 1893 __func__);
ad28e79a
SW
1894 return 0;
1895 }
1896
1897 dest = rib_dest_from_rnode(rn);
1898 if (dest && dest->selected_fib
1899 && !CHECK_FLAG(dest->selected_fib->status,
1900 ROUTE_ENTRY_REMOVED)
1901 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
1902 match = dest->selected_fib;
1903
1904 /* If there is no selected route or matched route is EGP, go up
2d3c57e6
SW
1905 * tree.
1906 */
ad28e79a
SW
1907 if (!match) {
1908 do {
1909 rn = rn->parent;
1910 } while (rn && rn->info == NULL);
1911 if (rn)
1912 route_lock_node(rn);
1913
1914 continue;
1915 }
1916
1917 if (match->type == ZEBRA_ROUTE_CONNECT) {
1918 /* Directly point connected route. */
c415d895 1919 newhop = match->nhe->nhg.nexthop;
ad28e79a
SW
1920 if (newhop) {
1921 if (nexthop->type == NEXTHOP_TYPE_IPV4
1922 || nexthop->type == NEXTHOP_TYPE_IPV6)
1923 nexthop->ifindex = newhop->ifindex;
1924 }
377e29f7
MS
1925
1926 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1927 zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
1928 __func__, match,
1929 match->nhe->id, newhop);
1930
ad28e79a
SW
1931 return 1;
1932 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
f2646720
MS
1933 struct nexthop_group *nhg;
1934
ad28e79a 1935 resolved = 0;
f2646720
MS
1936
1937 /* Examine installed nexthops */
1938 nhg = &match->nhe->nhg;
1939 for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
ad28e79a
SW
1940 if (!CHECK_FLAG(match->status,
1941 ROUTE_ENTRY_INSTALLED))
1942 continue;
6913cb1b 1943 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
1944 continue;
1945
377e29f7
MS
1946 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1947 zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
1948 __func__, match,
1949 match->nhe->id, newhop);
1950
ad28e79a
SW
1951 SET_FLAG(nexthop->flags,
1952 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
1953 nexthop_set_resolved(afi, newhop, nexthop);
1954 resolved = 1;
1955 }
f924db49 1956
f2646720
MS
1957 /* Examine installed backup nexthops, if any */
1958 nhg = zebra_nhg_get_backup_nhg(match->nhe);
1959 if (nhg == NULL)
1960 goto done_with_match;
1961
1962 for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
1963 if (!CHECK_FLAG(match->status,
1964 ROUTE_ENTRY_INSTALLED))
1965 continue;
1966 if (!nexthop_valid_resolve(nexthop, newhop))
1967 continue;
1968
1969 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1970 zlog_debug("%s: RECURSIVE match backup %p (%u), newhop %pNHv",
1971 __func__, match,
1972 match->nhe->id, newhop);
1973
1974 SET_FLAG(nexthop->flags,
1975 NEXTHOP_FLAG_RECURSIVE);
1976 nexthop_set_resolved(afi, newhop, nexthop);
1977 resolved = 1;
1978 }
1979done_with_match:
8a507796 1980 if (resolved)
ad28e79a 1981 re->nexthop_mtu = match->mtu;
f924db49 1982 else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e
DL
1983 zlog_debug(
1984 " %s: Recursion failed to find",
1985 __func__);
f924db49 1986
ad28e79a 1987 return resolved;
ad28e79a
SW
1988 } else {
1989 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
1990 zlog_debug(
d6951e5e 1991 " %s: Route Type %s has not turned on recursion",
5e81f5dd 1992 __func__, zebra_route_string(re->type));
ad28e79a
SW
1993 if (re->type == ZEBRA_ROUTE_BGP
1994 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
1995 zlog_debug(
d6951e5e 1996 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
ad28e79a
SW
1997 }
1998 return 0;
1999 }
2000 }
2001 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e
DL
2002 zlog_debug(" %s: Nexthop did not lookup in table",
2003 __func__);
ad28e79a
SW
2004 return 0;
2005}
2006
2007/* This function verifies reachability of one given nexthop, which can be
2008 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2009 * in nexthop->flags field. The nexthop->ifindex will be updated
2010 * appropriately as well. An existing route map can turn
2011 * (otherwise active) nexthop into inactive, but not vice versa.
2012 *
98cda54a
SW
2013 * If it finds a nexthop recursivedly, set the resolved_id
2014 * to match that nexthop's nhg_hash_entry ID;
2015 *
ad28e79a
SW
2016 * The return value is the final value of 'ACTIVE' flag.
2017 */
2018static unsigned nexthop_active_check(struct route_node *rn,
2019 struct route_entry *re,
8a507796 2020 struct nexthop *nexthop)
ad28e79a
SW
2021{
2022 struct interface *ifp;
b68885f9 2023 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
2024 int family;
2025 char buf[SRCDEST2STR_BUFFER];
2026 const struct prefix *p, *src_p;
2027 struct zebra_vrf *zvrf;
2028
2029 srcdest_rnode_prefixes(rn, &p, &src_p);
2030
2031 if (rn->p.family == AF_INET)
2032 family = AFI_IP;
2033 else if (rn->p.family == AF_INET6)
2034 family = AFI_IP6;
2035 else
2036 family = 0;
2037 switch (nexthop->type) {
2038 case NEXTHOP_TYPE_IFINDEX:
2039 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
fc8a02c4
SW
2040 /*
2041 * If the interface exists and its operative or its a kernel
2042 * route and interface is up, its active. We trust kernel routes
2043 * to be good.
2044 */
2045 if (ifp
2046 && (if_is_operative(ifp)
2047 || (if_is_up(ifp)
2048 && (re->type == ZEBRA_ROUTE_KERNEL
2049 || re->type == ZEBRA_ROUTE_SYSTEM))))
ad28e79a
SW
2050 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2051 else
2052 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2053 break;
2054 case NEXTHOP_TYPE_IPV4:
2055 case NEXTHOP_TYPE_IPV4_IFINDEX:
2056 family = AFI_IP;
8a507796 2057 if (nexthop_active(AFI_IP, re, nexthop, rn))
ad28e79a
SW
2058 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2059 else
2060 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2061 break;
2062 case NEXTHOP_TYPE_IPV6:
2063 family = AFI_IP6;
8a507796 2064 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
2065 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2066 else
2067 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2068 break;
2069 case NEXTHOP_TYPE_IPV6_IFINDEX:
2070 /* RFC 5549, v4 prefix with v6 NH */
2071 if (rn->p.family != AF_INET)
2072 family = AFI_IP6;
2073 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
2074 ifp = if_lookup_by_index(nexthop->ifindex,
2075 nexthop->vrf_id);
2076 if (ifp && if_is_operative(ifp))
2077 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2078 else
2079 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2080 } else {
8a507796 2081 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
2082 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2083 else
2084 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2085 }
2086 break;
2087 case NEXTHOP_TYPE_BLACKHOLE:
2088 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2089 break;
2090 default:
2091 break;
2092 }
377e29f7 2093
ad28e79a
SW
2094 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
2095 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
377e29f7
MS
2096 zlog_debug(" %s: Unable to find active nexthop",
2097 __func__);
ad28e79a
SW
2098 return 0;
2099 }
2100
2101 /* XXX: What exactly do those checks do? Do we support
2102 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2103 */
2104 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
2105 || (family == AFI_IP6 && p->family != AF_INET6))
2106 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2107
2108 /* The original code didn't determine the family correctly
2109 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2110 * from the rib_table_info in those cases.
2111 * Possibly it may be better to use only the rib_table_info
2112 * in every case.
2113 */
2114 if (!family) {
630d5962 2115 struct rib_table_info *info;
ad28e79a
SW
2116
2117 info = srcdest_rnode_table_info(rn);
2118 family = info->afi;
2119 }
2120
2121 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
2122
2123 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
2124 if (!zvrf) {
2125 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
d6951e5e 2126 zlog_debug(" %s: zvrf is NULL", __func__);
ad28e79a
SW
2127 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2128 }
2129
2130 /* It'll get set if required inside */
2131 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
2132 zvrf, re->tag);
2133 if (ret == RMAP_DENYMATCH) {
2134 if (IS_ZEBRA_DEBUG_RIB) {
2135 srcdest_rnode2str(rn, buf, sizeof(buf));
2136 zlog_debug(
2137 "%u:%s: Filtering out with NH out %s due to route map",
2138 re->vrf_id, buf,
2139 ifindex2ifname(nexthop->ifindex,
2140 nexthop->vrf_id));
2141 }
2142 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2143 }
2144 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2145}
2146
086e4e02
SW
2147/* Helper function called after resolution to walk nhg rb trees
2148 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2149 * is active on singleton NHEs.
2150 */
2151static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe)
2152{
2153 struct nhg_connected *rb_node_dep = NULL;
2154 bool valid = false;
2155
2156 if (!zebra_nhg_depends_is_empty(nhe)) {
2157 /* Is at least one depend valid? */
2158 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2159 if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe))
2160 valid = true;
2161 }
2162
2163 goto done;
2164 }
2165
2166 /* should be fully resolved singleton at this point */
2167 if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE))
2168 valid = true;
2169
2170done:
2171 if (valid)
2172 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2173
2174 return valid;
2175}
2176
ad28e79a 2177/*
f2646720 2178 * Process a list of nexthops, given an nhg, determining
377e29f7 2179 * whether each one is ACTIVE/installable at this time.
ad28e79a 2180 */
377e29f7
MS
2181static uint32_t nexthop_list_active_update(struct route_node *rn,
2182 struct route_entry *re,
f2646720 2183 struct nexthop_group *nhg)
ad28e79a 2184{
ad28e79a
SW
2185 union g_addr prev_src;
2186 unsigned int prev_active, new_active;
2187 ifindex_t prev_index;
377e29f7 2188 uint32_t counter = 0;
f2646720
MS
2189 struct nexthop *nexthop;
2190
2191 nexthop = nhg->nexthop;
e22e8001 2192
377e29f7
MS
2193 /* Process nexthops one-by-one */
2194 for ( ; nexthop; nexthop = nexthop->next) {
ad28e79a 2195
ad28e79a 2196 /* No protocol daemon provides src and so we're skipping
377e29f7
MS
2197 * tracking it
2198 */
ad28e79a
SW
2199 prev_src = nexthop->rmap_src;
2200 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2201 prev_index = nexthop->ifindex;
2202 /*
2203 * We need to respect the multipath_num here
2204 * as that what we should be able to install from
377e29f7 2205 * a multipath perspective should not be a data plane
ad28e79a
SW
2206 * decision point.
2207 */
98cda54a 2208 new_active =
8a507796 2209 nexthop_active_check(rn, re, nexthop);
98cda54a 2210
377e29f7 2211 if (new_active && counter >= zrouter.multipath_num) {
4c55b5ff
SW
2212 struct nexthop *nh;
2213
2214 /* Set it and its resolved nexthop as inactive. */
2215 for (nh = nexthop; nh; nh = nh->resolved)
2216 UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2217
ad28e79a
SW
2218 new_active = 0;
2219 }
9a0d4dd3 2220
df31a989 2221 if (new_active)
377e29f7 2222 counter++;
9a0d4dd3 2223
ad28e79a
SW
2224 /* Don't allow src setting on IPv6 addr for now */
2225 if (prev_active != new_active || prev_index != nexthop->ifindex
2226 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
2227 && nexthop->type < NEXTHOP_TYPE_IPV6)
2228 && prev_src.ipv4.s_addr
2229 != nexthop->rmap_src.ipv4.s_addr)
2230 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
2231 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
2232 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
2233 &nexthop->rmap_src.ipv6)))
8a507796 2234 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 2235 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
2236 }
2237
377e29f7
MS
2238 return counter;
2239}
2240
2241/*
2242 * Iterate over all nexthops of the given RIB entry and refresh their
2243 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2244 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2245 *
2246 * Return value is the new number of active nexthops.
2247 */
2248int nexthop_active_update(struct route_node *rn, struct route_entry *re)
2249{
2250 struct nhg_hash_entry *curr_nhe;
2251 uint32_t curr_active = 0, backup_active = 0;
2252
2253 afi_t rt_afi = family2afi(rn->p.family);
2254
2255 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2256
2257 /* Make a local copy of the existing nhe, so we don't work on/modify
2258 * the shared nhe.
2259 */
f727646a 2260 curr_nhe = zebra_nhe_copy(re->nhe, re->nhe->id);
377e29f7
MS
2261
2262 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2263 zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
2264 __func__, re, re->nhe, re->nhe->id,
2265 curr_nhe);
2266
2267 /* Clear the existing id, if any: this will avoid any confusion
2268 * if the id exists, and will also force the creation
2269 * of a new nhe reflecting the changes we may make in this local copy.
2270 */
2271 curr_nhe->id = 0;
2272
2273 /* Process nexthops */
f2646720 2274 curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg);
377e29f7
MS
2275
2276 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2277 zlog_debug("%s: re %p curr_active %u", __func__, re,
2278 curr_active);
2279
2280 /* If there are no backup nexthops, we are done */
2281 if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
2282 goto backups_done;
2283
2284 backup_active = nexthop_list_active_update(
f2646720 2285 rn, re, zebra_nhg_get_backup_nhg(curr_nhe));
377e29f7
MS
2286
2287 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2288 zlog_debug("%s: re %p backup_active %u", __func__, re,
2289 backup_active);
2290
2291backups_done:
2292
2293 /*
2294 * Ref or create an nhe that matches the current state of the
2295 * nexthop(s).
2296 */
8a507796 2297 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
98cda54a 2298 struct nhg_hash_entry *new_nhe = NULL;
98cda54a 2299
377e29f7
MS
2300 new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
2301
2302 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2303 zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
2304 __func__, re, re->nhe,
2305 re->nhe->id, new_nhe, new_nhe->id);
98cda54a 2306
5463ce26 2307 route_entry_update_nhe(re, new_nhe);
e22e8001
SW
2308 }
2309
377e29f7 2310
086e4e02
SW
2311 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2312 * flag where appropriate.
2313 */
715e5c70 2314 if (curr_active)
086e4e02 2315 zebra_nhg_set_valid_if_active(re->nhe);
98cda54a
SW
2316
2317 /*
377e29f7
MS
2318 * Do not need the old / copied nhe anymore since it
2319 * was either copied over into a new nhe or not
98cda54a
SW
2320 * used at all.
2321 */
377e29f7 2322 zebra_nhg_free(curr_nhe);
9a0d4dd3 2323 return curr_active;
ad28e79a 2324}
5be96a2d 2325
497ff579
SW
2326/* Recursively construct a grp array of fully resolved IDs.
2327 *
2328 * This function allows us to account for groups within groups,
2329 * by converting them into a flat array of IDs.
2330 *
2331 * nh_grp is modified at every level of recursion to append
2332 * to it the next unique, fully resolved ID from the entire tree.
2333 *
2334 *
2335 * Note:
2336 * I'm pretty sure we only allow ONE level of group within group currently.
2337 * But making this recursive just in case that ever changes.
2338 */
2339static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
2340 uint8_t curr_index,
2341 struct nhg_hash_entry *nhe,
2342 int max_num)
98cda54a
SW
2343{
2344 struct nhg_connected *rb_node_dep = NULL;
2345 struct nhg_hash_entry *depend = NULL;
497ff579 2346 uint8_t i = curr_index;
98cda54a 2347
fec211ad 2348 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
8dbc800f
SW
2349 bool duplicate = false;
2350
497ff579
SW
2351 if (i >= max_num)
2352 goto done;
2353
98cda54a
SW
2354 depend = rb_node_dep->nhe;
2355
2356 /*
2357 * If its recursive, use its resolved nhe in the group
2358 */
2359 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
2360 depend = zebra_nhg_resolve(depend);
2361 if (!depend) {
2362 flog_err(
2363 EC_ZEBRA_NHG_FIB_UPDATE,
df31a989
SW
2364 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
2365 nhe->id);
98cda54a
SW
2366 continue;
2367 }
2368 }
2369
497ff579
SW
2370 if (!zebra_nhg_depends_is_empty(depend)) {
2371 /* This is a group within a group */
2372 i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
2373 } else {
086e4e02
SW
2374 if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
2375 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2376 || IS_ZEBRA_DEBUG_NHG)
2377 zlog_debug(
2378 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2379 __func__, depend->id);
2380 continue;
2381 }
2382
1866b3af
SW
2383 /* If the nexthop not installed/queued for install don't
2384 * put in the ID array.
2385 */
2386 if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED)
2387 || CHECK_FLAG(depend->flags,
2388 NEXTHOP_GROUP_QUEUED))) {
2389 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2390 || IS_ZEBRA_DEBUG_NHG)
2391 zlog_debug(
2392 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2393 __func__, depend->id);
2394 continue;
2395 }
2396
b1c3f7ef 2397 /* Check for duplicate IDs, ignore if found. */
497ff579 2398 for (int j = 0; j < i; j++) {
d43122b5 2399 if (depend->id == grp[j].id) {
497ff579 2400 duplicate = true;
d43122b5
SW
2401 break;
2402 }
497ff579 2403 }
8dbc800f 2404
b1c3f7ef
SW
2405 if (duplicate) {
2406 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2407 || IS_ZEBRA_DEBUG_NHG)
2408 zlog_debug(
2409 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2410 __func__, depend->id);
2411 continue;
497ff579 2412 }
b1c3f7ef
SW
2413
2414 grp[i].id = depend->id;
2415 grp[i].weight = depend->nhg.nexthop->weight;
2416 i++;
8dbc800f 2417 }
98cda54a 2418 }
8dbc800f 2419
0328a5bd
MS
2420 if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
2421 goto done;
2422
2423 /* TODO -- For now, we are not trying to use or install any
2424 * backup info in this nexthop-id path: we aren't prepared
2425 * to use the backups here yet. We're just debugging what we find.
2426 */
2427 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2428 zlog_debug("%s: skipping backup nhe", __func__);
2429
8dbc800f 2430done:
98cda54a
SW
2431 return i;
2432}
2433
497ff579
SW
2434/* Convert a nhe into a group array */
2435uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
2436 int max_num)
2437{
2438 /* Call into the recursive function */
2439 return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
2440}
2441
5be96a2d
SW
2442void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
2443{
f429bd1b
SW
2444 struct nhg_connected *rb_node_dep = NULL;
2445
2446 /* Resolve it first */
2447 nhe = zebra_nhg_resolve(nhe);
2448
2449 /* Make sure all depends are installed/queued */
fec211ad 2450 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
f429bd1b
SW
2451 zebra_nhg_install_kernel(rb_node_dep->nhe);
2452 }
2453
086e4e02
SW
2454 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
2455 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
e22e8001 2456 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
724583ed
SW
2457 /* Change its type to us since we are installing it */
2458 nhe->type = ZEBRA_ROUTE_NHG;
2459
147bad16 2460 int ret = dplane_nexthop_add(nhe);
2d3c57e6 2461
147bad16
SW
2462 switch (ret) {
2463 case ZEBRA_DPLANE_REQUEST_QUEUED:
2464 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2465 break;
2466 case ZEBRA_DPLANE_REQUEST_FAILURE:
2467 flog_err(
2468 EC_ZEBRA_DP_INSTALL_FAIL,
2469 "Failed to install Nexthop ID (%u) into the kernel",
2470 nhe->id);
2471 break;
2472 case ZEBRA_DPLANE_REQUEST_SUCCESS:
2473 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
80286aa5 2474 zebra_nhg_handle_install(nhe);
147bad16
SW
2475 break;
2476 }
2477 }
2478}
2479
147bad16
SW
2480void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
2481{
2482 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
2483 int ret = dplane_nexthop_delete(nhe);
2d3c57e6 2484
147bad16
SW
2485 switch (ret) {
2486 case ZEBRA_DPLANE_REQUEST_QUEUED:
2487 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2488 break;
2489 case ZEBRA_DPLANE_REQUEST_FAILURE:
2490 flog_err(
2491 EC_ZEBRA_DP_DELETE_FAIL,
2492 "Failed to uninstall Nexthop ID (%u) from the kernel",
2493 nhe->id);
2494 break;
2495 case ZEBRA_DPLANE_REQUEST_SUCCESS:
2496 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
2497 break;
2498 }
177e711d
SW
2499 }
2500
2501 zebra_nhg_handle_uninstall(nhe);
147bad16
SW
2502}
2503
5f3c9e52
SW
2504void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
2505{
2506 enum dplane_op_e op;
2507 enum zebra_dplane_result status;
2508 uint32_t id = 0;
2509 struct nhg_hash_entry *nhe = NULL;
2510
2511 op = dplane_ctx_get_op(ctx);
2512 status = dplane_ctx_get_status(ctx);
2513
0c8215cb 2514 id = dplane_ctx_get_nhe_id(ctx);
e22e8001 2515
377e29f7 2516 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
177e711d
SW
2517 zlog_debug(
2518 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
2519 ctx, dplane_op2str(op), id, dplane_res2str(status));
5f3c9e52 2520
177e711d
SW
2521 switch (op) {
2522 case DPLANE_OP_NH_DELETE:
2523 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
2524 flog_err(
2525 EC_ZEBRA_DP_DELETE_FAIL,
2526 "Failed to uninstall Nexthop ID (%u) from the kernel",
2527 id);
2528 /* We already free'd the data, nothing to do */
2529 break;
2530 case DPLANE_OP_NH_INSTALL:
2531 case DPLANE_OP_NH_UPDATE:
2532 nhe = zebra_nhg_lookup_id(id);
2533
2534 if (!nhe) {
2535 flog_err(
2536 EC_ZEBRA_NHG_SYNC,
2537 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
2538 dplane_op2str(op), id);
5f3c9e52
SW
2539 break;
2540 }
177e711d
SW
2541
2542 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2543 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
2544 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2545 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
80286aa5 2546 zebra_nhg_handle_install(nhe);
177e711d
SW
2547 } else
2548 flog_err(
2549 EC_ZEBRA_DP_INSTALL_FAIL,
2550 "Failed to install Nexthop ID (%u) into the kernel",
2551 nhe->id);
2552 break;
2553 case DPLANE_OP_ROUTE_INSTALL:
2554 case DPLANE_OP_ROUTE_UPDATE:
2555 case DPLANE_OP_ROUTE_DELETE:
2556 case DPLANE_OP_ROUTE_NOTIFY:
2557 case DPLANE_OP_LSP_INSTALL:
2558 case DPLANE_OP_LSP_UPDATE:
2559 case DPLANE_OP_LSP_DELETE:
2560 case DPLANE_OP_LSP_NOTIFY:
2561 case DPLANE_OP_PW_INSTALL:
2562 case DPLANE_OP_PW_UNINSTALL:
2563 case DPLANE_OP_SYS_ROUTE_ADD:
2564 case DPLANE_OP_SYS_ROUTE_DELETE:
2565 case DPLANE_OP_ADDR_INSTALL:
2566 case DPLANE_OP_ADDR_UNINSTALL:
2567 case DPLANE_OP_MAC_INSTALL:
2568 case DPLANE_OP_MAC_DELETE:
2569 case DPLANE_OP_NEIGH_INSTALL:
2570 case DPLANE_OP_NEIGH_UPDATE:
2571 case DPLANE_OP_NEIGH_DELETE:
2572 case DPLANE_OP_VTEP_ADD:
2573 case DPLANE_OP_VTEP_DELETE:
60d8d43b
JU
2574 case DPLANE_OP_RULE_ADD:
2575 case DPLANE_OP_RULE_DELETE:
2576 case DPLANE_OP_RULE_UPDATE:
177e711d
SW
2577 case DPLANE_OP_NONE:
2578 break;
2579 }
71593b3f
SW
2580
2581 dplane_ctx_fini(&ctx);
5be96a2d
SW
2582}
2583
38e40db1
SW
2584static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
2585{
2586 struct nhg_hash_entry *nhe = NULL;
2587
2588 nhe = (struct nhg_hash_entry *)bucket->data;
2589
2590 /* If its being ref'd, just let it be uninstalled via a route removal */
2591 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
2592 zebra_nhg_uninstall_kernel(nhe);
2593}
2594
2595void zebra_nhg_sweep_table(struct hash *hash)
2596{
2597 hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
2598}
7c99d51b
MS
2599
2600/* Global control to disable use of kernel nexthops, if available. We can't
2601 * force the kernel to support nexthop ids, of course, but we can disable
2602 * zebra's use of them, for testing e.g. By default, if the kernel supports
2603 * nexthop ids, zebra uses them.
2604 */
2605void zebra_nhg_enable_kernel_nexthops(bool set)
2606{
2607 g_nexthops_enabled = set;
2608}
2609
2610bool zebra_nhg_kernel_nexthops_enabled(void)
2611{
2612 return g_nexthops_enabled;
2613}