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