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