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