]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_nhg.c
doc: add instructions for static linking (#5668)
[mirror_frr.git] / zebra / zebra_nhg.c
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"
26 #include "lib/nexthop_group_private.h"
27 #include "lib/routemap.h"
28 #include "lib/mpls.h"
29 #include "lib/jhash.h"
30 #include "lib/debug.h"
31
32 #include "zebra/connected.h"
33 #include "zebra/debug.h"
34 #include "zebra/zebra_router.h"
35 #include "zebra/zebra_nhg_private.h"
36 #include "zebra/zebra_rnh.h"
37 #include "zebra/zebra_routemap.h"
38 #include "zebra/zebra_memory.h"
39 #include "zebra/zserv.h"
40 #include "zebra/rt.h"
41 #include "zebra_errors.h"
42 #include "zebra_dplane.h"
43 #include "zebra/interface.h"
44
45 DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
46 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
47 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
48
49 /* id counter to keep in sync with kernel */
50 uint32_t id_counter;
51
52 static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
53 afi_t afi);
54 static void depends_add(struct nhg_connected_tree_head *head,
55 struct nhg_hash_entry *depend);
56 static struct nhg_hash_entry *
57 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
58 afi_t afi);
59 static struct nhg_hash_entry *
60 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
61 static void depends_decrement_free(struct nhg_connected_tree_head *head);
62
63
64 static void nhg_connected_free(struct nhg_connected *dep)
65 {
66 XFREE(MTYPE_NHG_CONNECTED, dep);
67 }
68
69 static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
70 {
71 struct nhg_connected *new = NULL;
72
73 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
74 new->nhe = nhe;
75
76 return new;
77 }
78
79 void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
80 {
81 struct nhg_connected *rb_node_dep = NULL;
82
83 if (!nhg_connected_tree_is_empty(head)) {
84 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
85 nhg_connected_tree_del(head, rb_node_dep);
86 nhg_connected_free(rb_node_dep);
87 }
88 }
89 }
90
91 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
92 {
93 return nhg_connected_tree_count(head) ? false : true;
94 }
95
96 struct nhg_connected *
97 nhg_connected_tree_root(struct nhg_connected_tree_head *head)
98 {
99 return nhg_connected_tree_first(head);
100 }
101
102 void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
103 struct nhg_hash_entry *depend)
104 {
105 struct nhg_connected lookup = {};
106 struct nhg_connected *remove = NULL;
107
108 lookup.nhe = depend;
109
110 /* Lookup to find the element, then remove it */
111 remove = nhg_connected_tree_find(head, &lookup);
112 remove = nhg_connected_tree_del(head, remove);
113
114 if (remove)
115 nhg_connected_free(remove);
116 }
117
118 void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
119 struct nhg_hash_entry *depend)
120 {
121 struct nhg_connected *new = NULL;
122
123 new = nhg_connected_new(depend);
124
125 if (new)
126 nhg_connected_tree_add(head, new);
127 }
128
129 static void
130 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
131 {
132 struct nhg_connected *rb_node_dep = NULL;
133
134 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
135 zebra_nhg_decrement_ref(rb_node_dep->nhe);
136 }
137 }
138
139 static void
140 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
141 {
142 struct nhg_connected *rb_node_dep = NULL;
143
144 frr_each(nhg_connected_tree, head, rb_node_dep) {
145 zebra_nhg_increment_ref(rb_node_dep->nhe);
146 }
147 }
148
149 struct 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)) {
153 nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
154 return zebra_nhg_resolve(nhe);
155 }
156
157 return nhe;
158 }
159
160 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
161 {
162 return nhg_connected_tree_count(&nhe->nhg_depends);
163 }
164
165 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
166 {
167 return nhg_connected_tree_is_empty(&nhe->nhg_depends);
168 }
169
170 static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
171 struct nhg_hash_entry *depend)
172 {
173 nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
174 }
175
176 static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
177 {
178 nhg_connected_tree_init(&nhe->nhg_depends);
179 }
180
181 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
182 {
183 return nhg_connected_tree_count(&nhe->nhg_dependents);
184 }
185
186
187 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
188 {
189 return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
190 }
191
192 static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
193 struct nhg_hash_entry *dependent)
194 {
195 nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
196 }
197
198 static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
199 struct nhg_hash_entry *dependent)
200 {
201 nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
202 }
203
204 static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
205 {
206 nhg_connected_tree_init(&nhe->nhg_dependents);
207 }
208
209 /* Release this nhe from anything depending on it */
210 static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
211 {
212 struct nhg_connected *rb_node_dep = NULL;
213
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);
218 }
219 }
220
221 /* Release this nhe from anything that it depends on */
222 static 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
235 struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
236 {
237 struct nhg_hash_entry lookup = {};
238
239 lookup.id = id;
240 return hash_lookup(zrouter.nhgs_id, &lookup);
241 }
242
243 static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
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 }
257
258 static 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
264 static void
265 zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
266 struct nhg_connected_tree_head nhg_depends)
267 {
268 struct nhg_connected *rb_node_dep = NULL;
269
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;
276
277 /* Attach backpointer to anything that it depends on */
278 zebra_nhg_dependents_init(nhe);
279 if (!zebra_nhg_depends_is_empty(nhe)) {
280 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
281 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
282 }
283 }
284
285 /* Add the ifp now if its not a group or recursive and has ifindex */
286 if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop
287 && nhe->nhg->nexthop->ifindex) {
288 struct interface *ifp = NULL;
289
290 ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
291 nhe->vrf_id);
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);
300 }
301 }
302
303 struct nhg_hash_entry *zebra_nhg_alloc(void)
304 {
305 struct nhg_hash_entry *nhe;
306
307 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
308
309 return nhe;
310 }
311
312 static 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
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 */
334 static void *zebra_nhg_hash_alloc(void *arg)
335 {
336 struct nhg_hash_entry *nhe = NULL;
337 struct nhg_hash_entry *copy = arg;
338
339 nhe = zebra_nhg_copy(copy, copy->id);
340
341 /* Mark duplicate nexthops in a group at creation time. */
342 nexthop_group_mark_duplicates(nhe->nhg);
343
344 zebra_nhg_connect_depends(nhe, copy->nhg_depends);
345 zebra_nhg_insert_id(nhe);
346
347 return nhe;
348 }
349
350 uint32_t zebra_nhg_hash_key(const void *arg)
351 {
352 const struct nhg_hash_entry *nhe = arg;
353
354 uint32_t key = 0x5a351234;
355
356 key = jhash_3words(nhe->vrf_id, nhe->afi, nexthop_group_hash(nhe->nhg),
357 key);
358
359 return key;
360 }
361
362 uint32_t zebra_nhg_id_key(const void *arg)
363 {
364 const struct nhg_hash_entry *nhe = arg;
365
366 return nhe->id;
367 }
368
369 bool 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;
373 struct nexthop *nexthop1;
374 struct nexthop *nexthop2;
375
376 /* No matter what if they equal IDs, assume equal */
377 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
378 return true;
379
380 if (nhe1->vrf_id != nhe2->vrf_id)
381 return false;
382
383 if (nhe1->afi != nhe2->afi)
384 return false;
385
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 }
427
428 return true;
429 }
430
431 bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
432 {
433 const struct nhg_hash_entry *nhe1 = arg1;
434 const struct nhg_hash_entry *nhe2 = arg2;
435
436 return nhe1->id == nhe2->id;
437 }
438
439 static int zebra_nhg_process_grp(struct nexthop_group *nhg,
440 struct nhg_connected_tree_head *depends,
441 struct nh_grp *grp, uint8_t count)
442 {
443 nhg_connected_tree_init(depends);
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 */
452 depend = depends_find_id_add(depends, grp[i].id);
453
454 if (!depend) {
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);
459 return -1;
460 }
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);
470 }
471
472 return 0;
473 }
474
475 static 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
481 resolved_ng.nexthop = nh;
482
483 depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
484 depends_add(nhg_depends, depend);
485 }
486
487 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
488 struct nexthop_group *nhg,
489 struct nhg_connected_tree_head *nhg_depends,
490 vrf_id_t vrf_id, afi_t afi, int type)
491 {
492 struct nhg_hash_entry lookup = {};
493
494 uint32_t old_id_counter = id_counter;
495
496 bool created = false;
497 bool recursive = false;
498
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;
503
504 lookup.type = type ? type : ZEBRA_ROUTE_NHG;
505 lookup.nhg = nhg;
506
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 = VRF_DEFAULT;
511 } else {
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
535 lookup.vrf_id = vrf_id;
536 }
537
538 if (id)
539 (*nhe) = zebra_nhg_lookup_id(id);
540 else
541 (*nhe) = hash_lookup(zrouter.nhgs, &lookup);
542
543 /* If it found an nhe in our tables, this new ID is unused */
544 if (*nhe)
545 id_counter = old_id_counter;
546
547 if (!(*nhe)) {
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) {
561 zebra_nhg_depends_init(&lookup);
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)) {
571 zebra_nhg_depends_init(&lookup);
572 handle_recursive_depend(&lookup.nhg_depends,
573 nhg->nexthop->resolved,
574 afi);
575 recursive = true;
576 }
577 }
578
579 (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
580 created = true;
581
582 if (recursive)
583 SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
584 }
585 return created;
586 }
587
588 /* Find/create a single nexthop */
589 static struct nhg_hash_entry *
590 zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
591 {
592 struct nhg_hash_entry *nhe = NULL;
593 struct nexthop_group nhg = {};
594
595 nexthop_group_add_sorted(&nhg, nh);
596
597 zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, type);
598
599 return nhe;
600 }
601
602 static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
603 {
604 return ctx->id;
605 }
606
607 static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
608 {
609 ctx->status = status;
610 }
611
612 static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
613 {
614 return ctx->status;
615 }
616
617 static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
618 {
619 ctx->op = op;
620 }
621
622 static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
623 {
624 return ctx->op;
625 }
626
627 static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
628 {
629 return ctx->vrf_id;
630 }
631
632 static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
633 {
634 return ctx->type;
635 }
636
637 static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
638 {
639 return ctx->afi;
640 }
641
642 static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
643 {
644 return &ctx->u.nh;
645 }
646
647 static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
648 {
649 return ctx->count;
650 }
651
652 static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
653 {
654 return ctx->u.grp;
655 }
656
657 static 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
666 static 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
682 done:
683 XFREE(MTYPE_NHG_CTX, *ctx);
684 *ctx = NULL;
685 }
686
687 static 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
710 static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
711 {
712 struct nhg_connected *rb_node_dep = NULL;
713
714 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
715 if (CHECK_FLAG(rb_node_dep->nhe->flags,
716 NEXTHOP_GROUP_UNHASHABLE))
717 return true;
718 }
719
720 return false;
721 }
722
723 static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
724 {
725 SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
726 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
727
728 flog_warn(
729 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
730 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
731 nhe->id);
732 }
733
734 static 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
744 static 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
755 void 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
768 done:
769 if (valid)
770 zebra_nhg_set_valid(nhe);
771 else
772 zebra_nhg_set_invalid(nhe);
773 }
774
775
776 static void zebra_nhg_release(struct nhg_hash_entry *nhe)
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 /*
785 * If its unhashable, we didn't store it here and have to be
786 * sure we don't clear one thats actually being used.
787 */
788 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
789 hash_release(zrouter.nhgs, nhe);
790
791 hash_release(zrouter.nhgs_id, nhe);
792 }
793
794 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
795 {
796 zebra_nhg_release(nhe);
797 zebra_nhg_free(nhe);
798 }
799
800 static 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
809 /*
810 * The kernel/other program has changed the state of a nexthop object we are
811 * using.
812 */
813 static 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);
824 } else
825 zebra_nhg_handle_uninstall(nhe);
826 }
827
828 static int nhg_ctx_process_new(struct nhg_ctx *ctx)
829 {
830 struct nexthop_group *nhg = NULL;
831 struct nhg_connected_tree_head nhg_depends = {};
832 struct nhg_hash_entry *lookup = NULL;
833 struct nhg_hash_entry *nhe = NULL;
834
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);
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
851 if (nhg_ctx_get_count(ctx)) {
852 nhg = nexthop_group_new();
853 if (zebra_nhg_process_grp(nhg, &nhg_depends,
854 nhg_ctx_get_grp(ctx), count)) {
855 depends_decrement_free(&nhg_depends);
856 nexthop_group_delete(&nhg);
857 return -ENOENT;
858 }
859
860 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
861 afi))
862 depends_decrement_free(&nhg_depends);
863
864 /* These got copied over in zebra_nhg_alloc() */
865 nexthop_group_delete(&nhg);
866 } else
867 nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
868 type);
869
870 if (nhe) {
871 if (id != nhe->id) {
872 struct nhg_hash_entry *kernel_nhe = NULL;
873
874 /* Duplicate but with different ID from
875 * the kernel
876 */
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.
883 *
884 * We maintain them *ONLY* in the ID hash table to
885 * track them and set the flag to indicated
886 * their attributes are unhashable.
887 */
888
889 kernel_nhe = zebra_nhg_copy(nhe, id);
890 zebra_nhg_insert_id(kernel_nhe);
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.
896 */
897 hash_release(zrouter.nhgs, nhe);
898 zebra_nhg_set_unhashable(nhe);
899 } else {
900 /* It actually created a new nhe */
901 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
902 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
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)",
908 id);
909 return -1;
910 }
911
912 return 0;
913 }
914
915 static int nhg_ctx_process_del(struct nhg_ctx *ctx)
916 {
917 struct nhg_hash_entry *nhe = NULL;
918 uint32_t id = nhg_ctx_get_id(ctx);
919
920 nhe = zebra_nhg_lookup_id(id);
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",
926 id);
927 return -1;
928 }
929
930 zebra_nhg_handle_kernel_state_change(nhe, true);
931
932 return 0;
933 }
934
935 static void nhg_ctx_fini(struct nhg_ctx **ctx)
936 {
937 /*
938 * Just freeing for now, maybe do something more in the future
939 * based on flag.
940 */
941
942 nhg_ctx_free(ctx);
943 }
944
945 static 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
961 int 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);
968 if (nhg_ctx_get_count(ctx) && ret == -ENOENT
969 && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
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.
975 *
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.
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 }
988 break;
989 case NHG_CTX_OP_DEL:
990 ret = nhg_ctx_process_del(ctx);
991 case NHG_CTX_OP_NONE:
992 break;
993 }
994
995 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
996
997 nhg_ctx_fini(&ctx);
998
999 return ret;
1000 }
1001
1002 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1003 int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
1004 uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
1005 int startup)
1006 {
1007 struct nhg_ctx *ctx = NULL;
1008
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
1015 ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
1016 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
1017
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
1025 if (queue_add(ctx)) {
1026 nhg_ctx_fini(&ctx);
1027 return -1;
1028 }
1029
1030 return 0;
1031 }
1032
1033 /* Kernel-side, received delete message */
1034 int zebra_nhg_kernel_del(uint32_t id)
1035 {
1036 struct nhg_ctx *ctx = NULL;
1037
1038 ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
1039
1040 nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
1041
1042 if (queue_add(ctx)) {
1043 nhg_ctx_fini(&ctx);
1044 return -1;
1045 }
1046
1047 return 0;
1048 }
1049
1050 /* Some dependency helper functions */
1051 static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
1052 afi_t afi)
1053 {
1054 struct nhg_hash_entry *nhe;
1055 struct nexthop *lookup = NULL;
1056
1057 lookup = nexthop_dup(nh, NULL);
1058
1059 nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
1060
1061 nexthops_free(lookup);
1062
1063 return nhe;
1064 }
1065
1066 static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
1067 afi_t afi)
1068 {
1069 struct nhg_hash_entry *nhe;
1070 struct nexthop lookup = {};
1071
1072 /* Capture a snapshot of this single nh; it might be part of a list,
1073 * so we need to make a standalone copy.
1074 */
1075 nexthop_copy_no_recurse(&lookup, nh, NULL);
1076
1077 nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
1078
1079 /* The copy may have allocated labels; free them if necessary. */
1080 nexthop_del_labels(&lookup);
1081
1082 return nhe;
1083 }
1084
1085 static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
1086 {
1087 struct nhg_hash_entry *nhe = NULL;
1088
1089 if (!nh)
1090 goto done;
1091
1092 /* We are separating these functions out to increase handling speed
1093 * in the non-recursive case (by not alloc/freeing)
1094 */
1095 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
1096 nhe = depends_find_recursive(nh, afi);
1097 else
1098 nhe = depends_find_singleton(nh, afi);
1099
1100 done:
1101 return nhe;
1102 }
1103
1104 static void depends_add(struct nhg_connected_tree_head *head,
1105 struct nhg_hash_entry *depend)
1106 {
1107 nhg_connected_tree_add_nhe(head, depend);
1108 zebra_nhg_increment_ref(depend);
1109 }
1110
1111 static struct nhg_hash_entry *
1112 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1113 afi_t afi)
1114 {
1115 struct nhg_hash_entry *depend = NULL;
1116
1117 depend = depends_find(nh, afi);
1118
1119 if (depend)
1120 depends_add(head, depend);
1121
1122 return depend;
1123 }
1124
1125 static struct nhg_hash_entry *
1126 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1127 {
1128 struct nhg_hash_entry *depend = NULL;
1129
1130 depend = zebra_nhg_lookup_id(id);
1131
1132 if (depend)
1133 depends_add(head, depend);
1134
1135 return depend;
1136 }
1137
1138 static void depends_decrement_free(struct nhg_connected_tree_head *head)
1139 {
1140 nhg_connected_tree_decrement_ref(head);
1141 nhg_connected_tree_free(head);
1142 }
1143
1144 /* Rib-side, you get a nexthop group struct */
1145 struct nhg_hash_entry *
1146 zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
1147 {
1148 struct nhg_hash_entry *nhe = NULL;
1149
1150 if (!(nhg && nhg->nexthop)) {
1151 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1152 "No nexthop passed to %s", __func__);
1153 return NULL;
1154 }
1155
1156 zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
1157
1158 return nhe;
1159 }
1160
1161 static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
1162 {
1163 nexthop_group_delete(&nhe->nhg);
1164 /* Decrement to remove connection ref */
1165 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1166 nhg_connected_tree_free(&nhe->nhg_depends);
1167 nhg_connected_tree_free(&nhe->nhg_dependents);
1168 }
1169
1170 void zebra_nhg_free(struct nhg_hash_entry *nhe)
1171 {
1172 if (nhe->refcnt)
1173 zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
1174
1175 zebra_nhg_free_members(nhe);
1176
1177 XFREE(MTYPE_NHG, nhe);
1178 }
1179
1180 void zebra_nhg_hash_free(void *p)
1181 {
1182 zebra_nhg_free((struct nhg_hash_entry *)p);
1183 }
1184
1185 void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1186 {
1187 nhe->refcnt--;
1188
1189 if (!zebra_nhg_depends_is_empty(nhe))
1190 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1191
1192 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1193 zebra_nhg_uninstall_kernel(nhe);
1194 }
1195
1196 void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1197 {
1198 nhe->refcnt++;
1199
1200 if (!zebra_nhg_depends_is_empty(nhe))
1201 nhg_connected_tree_increment_ref(&nhe->nhg_depends);
1202 }
1203
1204 static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
1205 struct nexthop *nexthop)
1206 {
1207 struct nexthop *resolved_hop;
1208 uint8_t num_labels = 0;
1209 mpls_label_t labels[MPLS_MAX_LABELS];
1210 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1211 int i = 0;
1212
1213 resolved_hop = nexthop_new();
1214 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1215
1216 resolved_hop->vrf_id = nexthop->vrf_id;
1217 switch (newhop->type) {
1218 case NEXTHOP_TYPE_IPV4:
1219 case NEXTHOP_TYPE_IPV4_IFINDEX:
1220 /* If the resolving route specifies a gateway, use it */
1221 resolved_hop->type = newhop->type;
1222 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1223
1224 if (newhop->ifindex) {
1225 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1226 resolved_hop->ifindex = newhop->ifindex;
1227 }
1228 break;
1229 case NEXTHOP_TYPE_IPV6:
1230 case NEXTHOP_TYPE_IPV6_IFINDEX:
1231 resolved_hop->type = newhop->type;
1232 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1233
1234 if (newhop->ifindex) {
1235 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1236 resolved_hop->ifindex = newhop->ifindex;
1237 }
1238 break;
1239 case NEXTHOP_TYPE_IFINDEX:
1240 /* If the resolving route is an interface route,
1241 * it means the gateway we are looking up is connected
1242 * to that interface. (The actual network is _not_ onlink).
1243 * Therefore, the resolved route should have the original
1244 * gateway as nexthop as it is directly connected.
1245 *
1246 * On Linux, we have to set the onlink netlink flag because
1247 * otherwise, the kernel won't accept the route.
1248 */
1249 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1250 if (afi == AFI_IP) {
1251 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1252 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1253 } else if (afi == AFI_IP6) {
1254 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1255 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1256 }
1257 resolved_hop->ifindex = newhop->ifindex;
1258 break;
1259 case NEXTHOP_TYPE_BLACKHOLE:
1260 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
1261 resolved_hop->bh_type = newhop->bh_type;
1262 break;
1263 }
1264
1265 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1266 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1267
1268 /* Copy labels of the resolved route and the parent resolving to it */
1269 if (newhop->nh_label) {
1270 for (i = 0; i < newhop->nh_label->num_labels; i++)
1271 labels[num_labels++] = newhop->nh_label->label[i];
1272 label_type = newhop->nh_label_type;
1273 }
1274
1275 if (nexthop->nh_label) {
1276 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1277 labels[num_labels++] = nexthop->nh_label->label[i];
1278
1279 /* If the parent has labels, use its type */
1280 label_type = nexthop->nh_label_type;
1281 }
1282
1283 if (num_labels)
1284 nexthop_add_labels(resolved_hop, label_type, num_labels,
1285 labels);
1286
1287 resolved_hop->rparent = nexthop;
1288 _nexthop_add(&nexthop->resolved, resolved_hop);
1289 }
1290
1291 /* Checks if nexthop we are trying to resolve to is valid */
1292 static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1293 const struct nexthop *resolved)
1294 {
1295 /* Can't resolve to a recursive nexthop */
1296 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1297 return false;
1298
1299 switch (nexthop->type) {
1300 case NEXTHOP_TYPE_IPV4_IFINDEX:
1301 case NEXTHOP_TYPE_IPV6_IFINDEX:
1302 /* If the nexthop we are resolving to does not match the
1303 * ifindex for the nexthop the route wanted, its not valid.
1304 */
1305 if (nexthop->ifindex != resolved->ifindex)
1306 return false;
1307 break;
1308 case NEXTHOP_TYPE_IPV4:
1309 case NEXTHOP_TYPE_IPV6:
1310 case NEXTHOP_TYPE_IFINDEX:
1311 case NEXTHOP_TYPE_BLACKHOLE:
1312 break;
1313 }
1314
1315 return true;
1316 }
1317
1318 /*
1319 * Given a nexthop we need to properly recursively resolve
1320 * the route. As such, do a table lookup to find and match
1321 * if at all possible. Set the nexthop->ifindex and resolved_id
1322 * as appropriate
1323 */
1324 static int nexthop_active(afi_t afi, struct route_entry *re,
1325 struct nexthop *nexthop, struct route_node *top)
1326 {
1327 struct prefix p;
1328 struct route_table *table;
1329 struct route_node *rn;
1330 struct route_entry *match = NULL;
1331 int resolved;
1332 struct nexthop *newhop;
1333 struct interface *ifp;
1334 rib_dest_t *dest;
1335 struct zebra_vrf *zvrf;
1336
1337 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
1338 || nexthop->type == NEXTHOP_TYPE_IPV6)
1339 nexthop->ifindex = 0;
1340
1341
1342 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
1343 nexthops_free(nexthop->resolved);
1344 nexthop->resolved = NULL;
1345 re->nexthop_mtu = 0;
1346
1347 /*
1348 * If the kernel has sent us a NEW route, then
1349 * by golly gee whiz it's a good route.
1350 *
1351 * If its an already INSTALLED route we have already handled, then the
1352 * kernel route's nexthop might have became unreachable
1353 * and we have to handle that.
1354 */
1355 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
1356 && (re->type == ZEBRA_ROUTE_KERNEL
1357 || re->type == ZEBRA_ROUTE_SYSTEM))
1358 return 1;
1359
1360 /*
1361 * Check to see if we should trust the passed in information
1362 * for UNNUMBERED interfaces as that we won't find the GW
1363 * address in the routing table.
1364 * This check should suffice to handle IPv4 or IPv6 routes
1365 * sourced from EVPN routes which are installed with the
1366 * next hop as the remote VTEP IP.
1367 */
1368 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
1369 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1370 if (!ifp) {
1371 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1372 zlog_debug(
1373 "\t%s: Onlink and interface: %u[%u] does not exist",
1374 __PRETTY_FUNCTION__, nexthop->ifindex,
1375 nexthop->vrf_id);
1376 return 0;
1377 }
1378 if (connected_is_unnumbered(ifp)) {
1379 if (if_is_operative(ifp))
1380 return 1;
1381
1382 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1383 zlog_debug(
1384 "\t%s: Onlink and interface %s is not operative",
1385 __PRETTY_FUNCTION__, ifp->name);
1386 return 0;
1387 }
1388 if (!if_is_operative(ifp)) {
1389 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1390 zlog_debug(
1391 "\t%s: Interface %s is not unnumbered",
1392 __PRETTY_FUNCTION__, ifp->name);
1393 return 0;
1394 }
1395 }
1396
1397 if ((top->p.family == AF_INET && top->p.prefixlen == 32
1398 && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
1399 || (top->p.family == AF_INET6 && top->p.prefixlen == 128
1400 && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
1401 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1402 zlog_debug(
1403 "\t:%s: Attempting to install a max prefixlength route through itself",
1404 __PRETTY_FUNCTION__);
1405 return 0;
1406 }
1407
1408 /* Make lookup prefix. */
1409 memset(&p, 0, sizeof(struct prefix));
1410 switch (afi) {
1411 case AFI_IP:
1412 p.family = AF_INET;
1413 p.prefixlen = IPV4_MAX_PREFIXLEN;
1414 p.u.prefix4 = nexthop->gate.ipv4;
1415 break;
1416 case AFI_IP6:
1417 p.family = AF_INET6;
1418 p.prefixlen = IPV6_MAX_PREFIXLEN;
1419 p.u.prefix6 = nexthop->gate.ipv6;
1420 break;
1421 default:
1422 assert(afi != AFI_IP && afi != AFI_IP6);
1423 break;
1424 }
1425 /* Lookup table. */
1426 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
1427 /* get zvrf */
1428 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1429 if (!table || !zvrf) {
1430 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1431 zlog_debug("\t%s: Table not found",
1432 __PRETTY_FUNCTION__);
1433 return 0;
1434 }
1435
1436 rn = route_node_match(table, (struct prefix *)&p);
1437 while (rn) {
1438 route_unlock_node(rn);
1439
1440 /* Lookup should halt if we've matched against ourselves ('top',
1441 * if specified) - i.e., we cannot have a nexthop NH1 is
1442 * resolved by a route NH1. The exception is if the route is a
1443 * host route.
1444 */
1445 if (top && rn == top)
1446 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
1447 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
1448 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1449 zlog_debug(
1450 "\t%s: Matched against ourself and prefix length is not max bit length",
1451 __PRETTY_FUNCTION__);
1452 return 0;
1453 }
1454
1455 /* Pick up selected route. */
1456 /* However, do not resolve over default route unless explicitly
1457 * allowed.
1458 */
1459 if (is_default_prefix(&rn->p)
1460 && !rnh_resolve_via_default(zvrf, p.family)) {
1461 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1462 zlog_debug(
1463 "\t:%s: Resolved against default route",
1464 __PRETTY_FUNCTION__);
1465 return 0;
1466 }
1467
1468 dest = rib_dest_from_rnode(rn);
1469 if (dest && dest->selected_fib
1470 && !CHECK_FLAG(dest->selected_fib->status,
1471 ROUTE_ENTRY_REMOVED)
1472 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
1473 match = dest->selected_fib;
1474
1475 /* If there is no selected route or matched route is EGP, go up
1476 * tree.
1477 */
1478 if (!match) {
1479 do {
1480 rn = rn->parent;
1481 } while (rn && rn->info == NULL);
1482 if (rn)
1483 route_lock_node(rn);
1484
1485 continue;
1486 }
1487
1488 if (match->type == ZEBRA_ROUTE_CONNECT) {
1489 /* Directly point connected route. */
1490 newhop = match->nhe->nhg->nexthop;
1491 if (newhop) {
1492 if (nexthop->type == NEXTHOP_TYPE_IPV4
1493 || nexthop->type == NEXTHOP_TYPE_IPV6)
1494 nexthop->ifindex = newhop->ifindex;
1495 }
1496 return 1;
1497 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
1498 resolved = 0;
1499 for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) {
1500 if (!CHECK_FLAG(match->status,
1501 ROUTE_ENTRY_INSTALLED))
1502 continue;
1503 if (!nexthop_valid_resolve(nexthop, newhop))
1504 continue;
1505
1506 SET_FLAG(nexthop->flags,
1507 NEXTHOP_FLAG_RECURSIVE);
1508 nexthop_set_resolved(afi, newhop, nexthop);
1509 resolved = 1;
1510 }
1511 if (resolved)
1512 re->nexthop_mtu = match->mtu;
1513
1514 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1515 zlog_debug("\t%s: Recursion failed to find",
1516 __PRETTY_FUNCTION__);
1517 return resolved;
1518 } else if (re->type == ZEBRA_ROUTE_STATIC) {
1519 resolved = 0;
1520 for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) {
1521 if (!CHECK_FLAG(match->status,
1522 ROUTE_ENTRY_INSTALLED))
1523 continue;
1524 if (!nexthop_valid_resolve(nexthop, newhop))
1525 continue;
1526
1527 SET_FLAG(nexthop->flags,
1528 NEXTHOP_FLAG_RECURSIVE);
1529 nexthop_set_resolved(afi, newhop, nexthop);
1530 resolved = 1;
1531 }
1532 if (resolved)
1533 re->nexthop_mtu = match->mtu;
1534
1535 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1536 zlog_debug(
1537 "\t%s: Static route unable to resolve",
1538 __PRETTY_FUNCTION__);
1539 return resolved;
1540 } else {
1541 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
1542 zlog_debug(
1543 "\t%s: Route Type %s has not turned on recursion",
1544 __PRETTY_FUNCTION__,
1545 zebra_route_string(re->type));
1546 if (re->type == ZEBRA_ROUTE_BGP
1547 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
1548 zlog_debug(
1549 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1550 }
1551 return 0;
1552 }
1553 }
1554 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1555 zlog_debug("\t%s: Nexthop did not lookup in table",
1556 __PRETTY_FUNCTION__);
1557 return 0;
1558 }
1559
1560 /* This function verifies reachability of one given nexthop, which can be
1561 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1562 * in nexthop->flags field. The nexthop->ifindex will be updated
1563 * appropriately as well. An existing route map can turn
1564 * (otherwise active) nexthop into inactive, but not vice versa.
1565 *
1566 * If it finds a nexthop recursivedly, set the resolved_id
1567 * to match that nexthop's nhg_hash_entry ID;
1568 *
1569 * The return value is the final value of 'ACTIVE' flag.
1570 */
1571 static unsigned nexthop_active_check(struct route_node *rn,
1572 struct route_entry *re,
1573 struct nexthop *nexthop)
1574 {
1575 struct interface *ifp;
1576 route_map_result_t ret = RMAP_PERMITMATCH;
1577 int family;
1578 char buf[SRCDEST2STR_BUFFER];
1579 const struct prefix *p, *src_p;
1580 struct zebra_vrf *zvrf;
1581
1582 srcdest_rnode_prefixes(rn, &p, &src_p);
1583
1584 if (rn->p.family == AF_INET)
1585 family = AFI_IP;
1586 else if (rn->p.family == AF_INET6)
1587 family = AFI_IP6;
1588 else
1589 family = 0;
1590 switch (nexthop->type) {
1591 case NEXTHOP_TYPE_IFINDEX:
1592 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1593 if (ifp && if_is_operative(ifp))
1594 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1595 else
1596 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1597 break;
1598 case NEXTHOP_TYPE_IPV4:
1599 case NEXTHOP_TYPE_IPV4_IFINDEX:
1600 family = AFI_IP;
1601 if (nexthop_active(AFI_IP, re, nexthop, rn))
1602 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1603 else
1604 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1605 break;
1606 case NEXTHOP_TYPE_IPV6:
1607 family = AFI_IP6;
1608 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1609 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1610 else
1611 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1612 break;
1613 case NEXTHOP_TYPE_IPV6_IFINDEX:
1614 /* RFC 5549, v4 prefix with v6 NH */
1615 if (rn->p.family != AF_INET)
1616 family = AFI_IP6;
1617 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
1618 ifp = if_lookup_by_index(nexthop->ifindex,
1619 nexthop->vrf_id);
1620 if (ifp && if_is_operative(ifp))
1621 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1622 else
1623 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1624 } else {
1625 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1626 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1627 else
1628 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1629 }
1630 break;
1631 case NEXTHOP_TYPE_BLACKHOLE:
1632 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1633 break;
1634 default:
1635 break;
1636 }
1637 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1638 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1639 zlog_debug("\t%s: Unable to find a active nexthop",
1640 __PRETTY_FUNCTION__);
1641 return 0;
1642 }
1643
1644 /* XXX: What exactly do those checks do? Do we support
1645 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1646 */
1647 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
1648 || (family == AFI_IP6 && p->family != AF_INET6))
1649 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1650
1651 /* The original code didn't determine the family correctly
1652 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1653 * from the rib_table_info in those cases.
1654 * Possibly it may be better to use only the rib_table_info
1655 * in every case.
1656 */
1657 if (!family) {
1658 rib_table_info_t *info;
1659
1660 info = srcdest_rnode_table_info(rn);
1661 family = info->afi;
1662 }
1663
1664 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
1665
1666 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1667 if (!zvrf) {
1668 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1669 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
1670 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1671 }
1672
1673 /* It'll get set if required inside */
1674 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
1675 zvrf, re->tag);
1676 if (ret == RMAP_DENYMATCH) {
1677 if (IS_ZEBRA_DEBUG_RIB) {
1678 srcdest_rnode2str(rn, buf, sizeof(buf));
1679 zlog_debug(
1680 "%u:%s: Filtering out with NH out %s due to route map",
1681 re->vrf_id, buf,
1682 ifindex2ifname(nexthop->ifindex,
1683 nexthop->vrf_id));
1684 }
1685 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1686 }
1687 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1688 }
1689
1690 /*
1691 * Iterate over all nexthops of the given RIB entry and refresh their
1692 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1693 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
1694 *
1695 * Return value is the new number of active nexthops.
1696 */
1697 int nexthop_active_update(struct route_node *rn, struct route_entry *re)
1698 {
1699 struct nexthop_group new_grp = {};
1700 struct nexthop *nexthop;
1701 union g_addr prev_src;
1702 unsigned int prev_active, new_active;
1703 ifindex_t prev_index;
1704 uint8_t curr_active = 0;
1705
1706 afi_t rt_afi = family2afi(rn->p.family);
1707
1708 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1709
1710 /* Copy over the nexthops in current state */
1711 nexthop_group_copy(&new_grp, re->nhe->nhg);
1712
1713 for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
1714
1715 /* No protocol daemon provides src and so we're skipping
1716 * tracking it */
1717 prev_src = nexthop->rmap_src;
1718 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1719 prev_index = nexthop->ifindex;
1720 /*
1721 * We need to respect the multipath_num here
1722 * as that what we should be able to install from
1723 * a multipath perpsective should not be a data plane
1724 * decision point.
1725 */
1726 new_active =
1727 nexthop_active_check(rn, re, nexthop);
1728
1729 if (new_active && curr_active >= zrouter.multipath_num) {
1730 struct nexthop *nh;
1731
1732 /* Set it and its resolved nexthop as inactive. */
1733 for (nh = nexthop; nh; nh = nh->resolved)
1734 UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
1735
1736 new_active = 0;
1737 }
1738
1739 if (new_active)
1740 curr_active++;
1741
1742 /* Don't allow src setting on IPv6 addr for now */
1743 if (prev_active != new_active || prev_index != nexthop->ifindex
1744 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
1745 && nexthop->type < NEXTHOP_TYPE_IPV6)
1746 && prev_src.ipv4.s_addr
1747 != nexthop->rmap_src.ipv4.s_addr)
1748 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
1749 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
1750 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
1751 &nexthop->rmap_src.ipv6)))
1752 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
1753 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1754 }
1755
1756 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
1757 struct nhg_hash_entry *new_nhe = NULL;
1758
1759 new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
1760
1761 route_entry_update_nhe(re, new_nhe);
1762 }
1763
1764 if (curr_active) {
1765 struct nhg_hash_entry *nhe = NULL;
1766
1767 nhe = zebra_nhg_lookup_id(re->nhe_id);
1768
1769 if (nhe)
1770 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1771 else
1772 flog_err(
1773 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1774 "Active update on NHE id=%u that we do not have in our tables",
1775 re->nhe_id);
1776 }
1777
1778 /*
1779 * Do not need these nexthops anymore since they
1780 * were either copied over into an nhe or not
1781 * used at all.
1782 */
1783 nexthops_free(new_grp.nexthop);
1784 return curr_active;
1785 }
1786
1787 /* Convert a nhe into a group array */
1788 uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
1789 int max_num)
1790 {
1791 struct nhg_connected *rb_node_dep = NULL;
1792 struct nhg_hash_entry *depend = NULL;
1793 uint8_t i = 0;
1794
1795 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1796 bool duplicate = false;
1797
1798 depend = rb_node_dep->nhe;
1799
1800 /*
1801 * If its recursive, use its resolved nhe in the group
1802 */
1803 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
1804 depend = zebra_nhg_resolve(depend);
1805 if (!depend) {
1806 flog_err(
1807 EC_ZEBRA_NHG_FIB_UPDATE,
1808 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
1809 nhe->id);
1810 continue;
1811 }
1812 }
1813
1814 /* Check for duplicate IDs, kernel doesn't like that */
1815 for (int j = 0; j < i; j++) {
1816 if (depend->id == grp[j].id)
1817 duplicate = true;
1818 }
1819
1820 if (!duplicate) {
1821 grp[i].id = depend->id;
1822 /* We aren't using weights for anything right now */
1823 grp[i].weight = depend->nhg->nexthop->weight;
1824 i++;
1825 }
1826
1827 if (i >= max_num)
1828 goto done;
1829 }
1830
1831 done:
1832 return i;
1833 }
1834
1835 void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
1836 {
1837 struct nhg_connected *rb_node_dep = NULL;
1838
1839 /* Resolve it first */
1840 nhe = zebra_nhg_resolve(nhe);
1841
1842 /* Make sure all depends are installed/queued */
1843 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1844 zebra_nhg_install_kernel(rb_node_dep->nhe);
1845 }
1846
1847 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
1848 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
1849 /* Change its type to us since we are installing it */
1850 nhe->type = ZEBRA_ROUTE_NHG;
1851
1852 int ret = dplane_nexthop_add(nhe);
1853
1854 switch (ret) {
1855 case ZEBRA_DPLANE_REQUEST_QUEUED:
1856 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1857 break;
1858 case ZEBRA_DPLANE_REQUEST_FAILURE:
1859 flog_err(
1860 EC_ZEBRA_DP_INSTALL_FAIL,
1861 "Failed to install Nexthop ID (%u) into the kernel",
1862 nhe->id);
1863 break;
1864 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1865 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1866 zebra_nhg_handle_install(nhe);
1867 break;
1868 }
1869 }
1870 }
1871
1872 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
1873 {
1874 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1875 int ret = dplane_nexthop_delete(nhe);
1876
1877 switch (ret) {
1878 case ZEBRA_DPLANE_REQUEST_QUEUED:
1879 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1880 break;
1881 case ZEBRA_DPLANE_REQUEST_FAILURE:
1882 flog_err(
1883 EC_ZEBRA_DP_DELETE_FAIL,
1884 "Failed to uninstall Nexthop ID (%u) from the kernel",
1885 nhe->id);
1886 break;
1887 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1888 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1889 break;
1890 }
1891 }
1892
1893 zebra_nhg_handle_uninstall(nhe);
1894 }
1895
1896 void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
1897 {
1898 enum dplane_op_e op;
1899 enum zebra_dplane_result status;
1900 uint32_t id = 0;
1901 struct nhg_hash_entry *nhe = NULL;
1902
1903 op = dplane_ctx_get_op(ctx);
1904 status = dplane_ctx_get_status(ctx);
1905
1906 id = dplane_ctx_get_nhe_id(ctx);
1907
1908 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1909 zlog_debug(
1910 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1911 ctx, dplane_op2str(op), id, dplane_res2str(status));
1912
1913 switch (op) {
1914 case DPLANE_OP_NH_DELETE:
1915 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
1916 flog_err(
1917 EC_ZEBRA_DP_DELETE_FAIL,
1918 "Failed to uninstall Nexthop ID (%u) from the kernel",
1919 id);
1920 /* We already free'd the data, nothing to do */
1921 break;
1922 case DPLANE_OP_NH_INSTALL:
1923 case DPLANE_OP_NH_UPDATE:
1924 nhe = zebra_nhg_lookup_id(id);
1925
1926 if (!nhe) {
1927 flog_err(
1928 EC_ZEBRA_NHG_SYNC,
1929 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1930 dplane_op2str(op), id);
1931 break;
1932 }
1933
1934 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1935 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1936 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1937 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1938 zebra_nhg_handle_install(nhe);
1939 } else
1940 flog_err(
1941 EC_ZEBRA_DP_INSTALL_FAIL,
1942 "Failed to install Nexthop ID (%u) into the kernel",
1943 nhe->id);
1944 break;
1945 case DPLANE_OP_ROUTE_INSTALL:
1946 case DPLANE_OP_ROUTE_UPDATE:
1947 case DPLANE_OP_ROUTE_DELETE:
1948 case DPLANE_OP_ROUTE_NOTIFY:
1949 case DPLANE_OP_LSP_INSTALL:
1950 case DPLANE_OP_LSP_UPDATE:
1951 case DPLANE_OP_LSP_DELETE:
1952 case DPLANE_OP_LSP_NOTIFY:
1953 case DPLANE_OP_PW_INSTALL:
1954 case DPLANE_OP_PW_UNINSTALL:
1955 case DPLANE_OP_SYS_ROUTE_ADD:
1956 case DPLANE_OP_SYS_ROUTE_DELETE:
1957 case DPLANE_OP_ADDR_INSTALL:
1958 case DPLANE_OP_ADDR_UNINSTALL:
1959 case DPLANE_OP_MAC_INSTALL:
1960 case DPLANE_OP_MAC_DELETE:
1961 case DPLANE_OP_NEIGH_INSTALL:
1962 case DPLANE_OP_NEIGH_UPDATE:
1963 case DPLANE_OP_NEIGH_DELETE:
1964 case DPLANE_OP_VTEP_ADD:
1965 case DPLANE_OP_VTEP_DELETE:
1966 case DPLANE_OP_NONE:
1967 break;
1968 }
1969
1970 dplane_ctx_fini(&ctx);
1971 }
1972
1973 static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
1974 {
1975 struct nhg_hash_entry *nhe = NULL;
1976
1977 nhe = (struct nhg_hash_entry *)bucket->data;
1978
1979 /* If its being ref'd, just let it be uninstalled via a route removal */
1980 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1981 zebra_nhg_uninstall_kernel(nhe);
1982 }
1983
1984 void zebra_nhg_sweep_table(struct hash *hash)
1985 {
1986 hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
1987 }