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