1 /* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
6 * This file is part of FRR.
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
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.
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
25 #include "lib/nexthop.h"
26 #include "lib/nexthop_group_private.h"
27 #include "lib/routemap.h"
29 #include "lib/jhash.h"
30 #include "lib/debug.h"
31 #include "lib/lib_errors.h"
33 #include "zebra/connected.h"
34 #include "zebra/debug.h"
35 #include "zebra/zebra_router.h"
36 #include "zebra/zebra_nhg_private.h"
37 #include "zebra/zebra_rnh.h"
38 #include "zebra/zebra_routemap.h"
39 #include "zebra/zebra_srte.h"
40 #include "zebra/zserv.h"
42 #include "zebra_errors.h"
43 #include "zebra_dplane.h"
44 #include "zebra/interface.h"
45 #include "zebra/zapi_msg.h"
46 #include "zebra/rib.h"
48 DEFINE_MTYPE_STATIC(ZEBRA
, NHG
, "Nexthop Group Entry");
49 DEFINE_MTYPE_STATIC(ZEBRA
, NHG_CONNECTED
, "Nexthop Group Connected");
50 DEFINE_MTYPE_STATIC(ZEBRA
, NHG_CTX
, "Nexthop Group Context");
52 /* Map backup nexthop indices between two nhes */
53 struct backup_nh_map_s
{
62 /* id counter to keep in sync with kernel */
65 /* Controlled through ui */
66 static bool g_nexthops_enabled
= true;
67 static bool proto_nexthops_only
;
68 static bool use_recursive_backups
= true;
70 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
,
71 int type
, bool from_dplane
);
72 static void depends_add(struct nhg_connected_tree_head
*head
,
73 struct nhg_hash_entry
*depend
);
74 static struct nhg_hash_entry
*
75 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
76 afi_t afi
, int type
, bool from_dplane
);
77 static struct nhg_hash_entry
*
78 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
);
79 static void depends_decrement_free(struct nhg_connected_tree_head
*head
);
81 static struct nhg_backup_info
*
82 nhg_backup_copy(const struct nhg_backup_info
*orig
);
84 /* Helper function for getting the next allocatable ID */
85 static uint32_t nhg_get_next_id(void)
90 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
91 zlog_debug("%s: ID %u checking", __func__
, id_counter
);
93 if (id_counter
== ZEBRA_NHG_PROTO_LOWER
) {
94 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
95 zlog_debug("%s: ID counter wrapped", __func__
);
101 if (zebra_nhg_lookup_id(id_counter
)) {
102 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
103 zlog_debug("%s: ID already exists", __func__
);
114 static void nhg_connected_free(struct nhg_connected
*dep
)
116 XFREE(MTYPE_NHG_CONNECTED
, dep
);
119 static struct nhg_connected
*nhg_connected_new(struct nhg_hash_entry
*nhe
)
121 struct nhg_connected
*new = NULL
;
123 new = XCALLOC(MTYPE_NHG_CONNECTED
, sizeof(struct nhg_connected
));
129 void nhg_connected_tree_free(struct nhg_connected_tree_head
*head
)
131 struct nhg_connected
*rb_node_dep
= NULL
;
133 if (!nhg_connected_tree_is_empty(head
)) {
134 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
135 nhg_connected_tree_del(head
, rb_node_dep
);
136 nhg_connected_free(rb_node_dep
);
141 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head
*head
)
143 return nhg_connected_tree_count(head
) ? false : true;
146 struct nhg_connected
*
147 nhg_connected_tree_root(struct nhg_connected_tree_head
*head
)
149 return nhg_connected_tree_first(head
);
152 struct nhg_hash_entry
*
153 nhg_connected_tree_del_nhe(struct nhg_connected_tree_head
*head
,
154 struct nhg_hash_entry
*depend
)
156 struct nhg_connected lookup
= {};
157 struct nhg_connected
*remove
= NULL
;
158 struct nhg_hash_entry
*removed_nhe
;
162 /* Lookup to find the element, then remove it */
163 remove
= nhg_connected_tree_find(head
, &lookup
);
165 /* Re-returning here just in case this API changes..
166 * the _del list api's are a bit undefined at the moment.
168 * So hopefully returning here will make it fail if the api
169 * changes to something different than currently expected.
171 remove
= nhg_connected_tree_del(head
, remove
);
173 /* If the entry was sucessfully removed, free the 'connected` struct */
175 removed_nhe
= remove
->nhe
;
176 nhg_connected_free(remove
);
183 /* Assuming UNIQUE RB tree. If this changes, assumptions here about
184 * insertion need to change.
186 struct nhg_hash_entry
*
187 nhg_connected_tree_add_nhe(struct nhg_connected_tree_head
*head
,
188 struct nhg_hash_entry
*depend
)
190 struct nhg_connected
*new = NULL
;
192 new = nhg_connected_new(depend
);
194 /* On success, NULL will be returned from the
197 if (new && (nhg_connected_tree_add(head
, new) == NULL
))
200 /* If it wasn't successful, it must be a duplicate. We enforce the
201 * unique property for the `nhg_connected` tree.
203 nhg_connected_free(new);
209 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head
*head
)
211 struct nhg_connected
*rb_node_dep
= NULL
;
213 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
214 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
219 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head
*head
)
221 struct nhg_connected
*rb_node_dep
= NULL
;
223 frr_each(nhg_connected_tree
, head
, rb_node_dep
) {
224 zebra_nhg_increment_ref(rb_node_dep
->nhe
);
228 struct nhg_hash_entry
*zebra_nhg_resolve(struct nhg_hash_entry
*nhe
)
230 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
)
231 && !zebra_nhg_depends_is_empty(nhe
)) {
232 nhe
= nhg_connected_tree_root(&nhe
->nhg_depends
)->nhe
;
233 return zebra_nhg_resolve(nhe
);
239 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry
*nhe
)
241 return nhg_connected_tree_count(&nhe
->nhg_depends
);
244 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry
*nhe
)
246 return nhg_connected_tree_is_empty(&nhe
->nhg_depends
);
249 static void zebra_nhg_depends_del(struct nhg_hash_entry
*from
,
250 struct nhg_hash_entry
*depend
)
252 nhg_connected_tree_del_nhe(&from
->nhg_depends
, depend
);
255 static void zebra_nhg_depends_init(struct nhg_hash_entry
*nhe
)
257 nhg_connected_tree_init(&nhe
->nhg_depends
);
260 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry
*nhe
)
262 return nhg_connected_tree_count(&nhe
->nhg_dependents
);
266 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry
*nhe
)
268 return nhg_connected_tree_is_empty(&nhe
->nhg_dependents
);
271 static void zebra_nhg_dependents_del(struct nhg_hash_entry
*from
,
272 struct nhg_hash_entry
*dependent
)
274 nhg_connected_tree_del_nhe(&from
->nhg_dependents
, dependent
);
277 static void zebra_nhg_dependents_add(struct nhg_hash_entry
*to
,
278 struct nhg_hash_entry
*dependent
)
280 nhg_connected_tree_add_nhe(&to
->nhg_dependents
, dependent
);
283 static void zebra_nhg_dependents_init(struct nhg_hash_entry
*nhe
)
285 nhg_connected_tree_init(&nhe
->nhg_dependents
);
288 /* Release this nhe from anything depending on it */
289 static void zebra_nhg_dependents_release(struct nhg_hash_entry
*nhe
)
291 struct nhg_connected
*rb_node_dep
= NULL
;
293 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
) {
294 zebra_nhg_depends_del(rb_node_dep
->nhe
, nhe
);
295 /* recheck validity of the dependent */
296 zebra_nhg_check_valid(rb_node_dep
->nhe
);
300 /* Release this nhe from anything that it depends on */
301 static void zebra_nhg_depends_release(struct nhg_hash_entry
*nhe
)
303 if (!zebra_nhg_depends_is_empty(nhe
)) {
304 struct nhg_connected
*rb_node_dep
= NULL
;
306 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_depends
,
308 zebra_nhg_dependents_del(rb_node_dep
->nhe
, nhe
);
314 struct nhg_hash_entry
*zebra_nhg_lookup_id(uint32_t id
)
316 struct nhg_hash_entry lookup
= {};
319 return hash_lookup(zrouter
.nhgs_id
, &lookup
);
322 static int zebra_nhg_insert_id(struct nhg_hash_entry
*nhe
)
324 if (hash_lookup(zrouter
.nhgs_id
, nhe
)) {
326 EC_ZEBRA_NHG_TABLE_INSERT_FAILED
,
327 "Failed inserting NHG %pNG into the ID hash table, entry already exists",
332 (void)hash_get(zrouter
.nhgs_id
, nhe
, hash_alloc_intern
);
337 static void zebra_nhg_set_if(struct nhg_hash_entry
*nhe
, struct interface
*ifp
)
340 if_nhg_dependents_add(ifp
, nhe
);
344 zebra_nhg_connect_depends(struct nhg_hash_entry
*nhe
,
345 struct nhg_connected_tree_head
*nhg_depends
)
347 struct nhg_connected
*rb_node_dep
= NULL
;
349 /* This has been allocated higher above in the stack. Could probably
350 * re-allocate and free the old stuff but just using the same memory
351 * for now. Otherwise, their might be a time trade-off for repeated
352 * alloc/frees as startup.
354 nhe
->nhg_depends
= *nhg_depends
;
356 /* Attach backpointer to anything that it depends on */
357 zebra_nhg_dependents_init(nhe
);
358 if (!zebra_nhg_depends_is_empty(nhe
)) {
359 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
360 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
361 zlog_debug("%s: nhe %p (%pNG), dep %p (%pNG)",
362 __func__
, nhe
, nhe
, rb_node_dep
->nhe
,
365 zebra_nhg_dependents_add(rb_node_dep
->nhe
, nhe
);
370 /* Init an nhe, for use in a hash lookup for example */
371 void zebra_nhe_init(struct nhg_hash_entry
*nhe
, afi_t afi
,
372 const struct nexthop
*nh
)
374 memset(nhe
, 0, sizeof(struct nhg_hash_entry
));
375 nhe
->vrf_id
= VRF_DEFAULT
;
376 nhe
->type
= ZEBRA_ROUTE_NHG
;
377 nhe
->afi
= AFI_UNSPEC
;
379 /* There are some special rules that apply to groups representing
382 if (nh
&& (nh
->next
== NULL
)) {
384 case NEXTHOP_TYPE_IFINDEX
:
385 case NEXTHOP_TYPE_BLACKHOLE
:
387 * This switch case handles setting the afi different
388 * for ipv4/v6 routes. Ifindex/blackhole nexthop
389 * objects cannot be ambiguous, they must be Address
390 * Family specific. If we get here, we will either use
391 * the AF of the route, or the one we got passed from
392 * here from the kernel.
396 case NEXTHOP_TYPE_IPV4_IFINDEX
:
397 case NEXTHOP_TYPE_IPV4
:
400 case NEXTHOP_TYPE_IPV6_IFINDEX
:
401 case NEXTHOP_TYPE_IPV6
:
408 struct nhg_hash_entry
*zebra_nhg_alloc(void)
410 struct nhg_hash_entry
*nhe
;
412 nhe
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_hash_entry
));
418 * Allocate new nhe and make shallow copy of 'orig'; no
419 * recursive info is copied.
421 struct nhg_hash_entry
*zebra_nhe_copy(const struct nhg_hash_entry
*orig
,
424 struct nhg_hash_entry
*nhe
;
426 nhe
= zebra_nhg_alloc();
430 nexthop_group_copy(&(nhe
->nhg
), &(orig
->nhg
));
432 nhe
->vrf_id
= orig
->vrf_id
;
433 nhe
->afi
= orig
->afi
;
434 nhe
->type
= orig
->type
? orig
->type
: ZEBRA_ROUTE_NHG
;
436 nhe
->dplane_ref
= zebra_router_get_next_sequence();
438 /* Copy backup info also, if present */
439 if (orig
->backup_info
)
440 nhe
->backup_info
= nhg_backup_copy(orig
->backup_info
);
445 /* Allocation via hash handler */
446 static void *zebra_nhg_hash_alloc(void *arg
)
448 struct nhg_hash_entry
*nhe
= NULL
;
449 struct nhg_hash_entry
*copy
= arg
;
451 nhe
= zebra_nhe_copy(copy
, copy
->id
);
453 /* Mark duplicate nexthops in a group at creation time. */
454 nexthop_group_mark_duplicates(&(nhe
->nhg
));
457 * Add the ifp now if it's not a group or recursive and has ifindex.
459 * A proto-owned ID is always a group.
461 if (!PROTO_OWNED(nhe
) && nhe
->nhg
.nexthop
&& !nhe
->nhg
.nexthop
->next
462 && !nhe
->nhg
.nexthop
->resolved
&& nhe
->nhg
.nexthop
->ifindex
) {
463 struct interface
*ifp
= NULL
;
465 ifp
= if_lookup_by_index(nhe
->nhg
.nexthop
->ifindex
,
466 nhe
->nhg
.nexthop
->vrf_id
);
468 zebra_nhg_set_if(nhe
, ifp
);
470 if (IS_ZEBRA_DEBUG_NHG
)
472 "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE %pNG",
473 nhe
->nhg
.nexthop
->ifindex
,
474 nhe
->nhg
.nexthop
->vrf_id
, nhe
);
481 uint32_t zebra_nhg_hash_key(const void *arg
)
483 const struct nhg_hash_entry
*nhe
= arg
;
484 uint32_t key
= 0x5a351234;
485 uint32_t primary
= 0;
488 primary
= nexthop_group_hash(&(nhe
->nhg
));
489 if (nhe
->backup_info
)
490 backup
= nexthop_group_hash(&(nhe
->backup_info
->nhe
->nhg
));
492 key
= jhash_3words(primary
, backup
, nhe
->type
, key
);
494 key
= jhash_2words(nhe
->vrf_id
, nhe
->afi
, key
);
499 uint32_t zebra_nhg_id_key(const void *arg
)
501 const struct nhg_hash_entry
*nhe
= arg
;
506 /* Helper with common nhg/nhe nexthop comparison logic */
507 static bool nhg_compare_nexthops(const struct nexthop
*nh1
,
508 const struct nexthop
*nh2
)
510 assert(nh1
!= NULL
&& nh2
!= NULL
);
513 * We have to check the active flag of each individual one,
514 * not just the overall active_num. This solves the special case
515 * issue of a route with a nexthop group with one nexthop
516 * resolving to itself and thus marking it inactive. If we
517 * have two different routes each wanting to mark a different
518 * nexthop inactive, they need to hash to two different groups.
520 * If we just hashed on num_active, they would hash the same
521 * which is incorrect.
525 * -> 1.1.1.1 dummy1 (inactive)
530 * -> 1.1.2.1 dummy2 (inactive)
532 * Without checking each individual one, they would hash to
533 * the same group and both have 1.1.1.1 dummy1 marked inactive.
536 if (CHECK_FLAG(nh1
->flags
, NEXTHOP_FLAG_ACTIVE
)
537 != CHECK_FLAG(nh2
->flags
, NEXTHOP_FLAG_ACTIVE
))
540 if (!nexthop_same(nh1
, nh2
))
546 bool zebra_nhg_hash_equal(const void *arg1
, const void *arg2
)
548 const struct nhg_hash_entry
*nhe1
= arg1
;
549 const struct nhg_hash_entry
*nhe2
= arg2
;
550 struct nexthop
*nexthop1
;
551 struct nexthop
*nexthop2
;
553 /* No matter what if they equal IDs, assume equal */
554 if (nhe1
->id
&& nhe2
->id
&& (nhe1
->id
== nhe2
->id
))
557 if (nhe1
->type
!= nhe2
->type
)
560 if (nhe1
->vrf_id
!= nhe2
->vrf_id
)
563 if (nhe1
->afi
!= nhe2
->afi
)
566 /* Nexthops should be in-order, so we simply compare them in-place */
567 for (nexthop1
= nhe1
->nhg
.nexthop
, nexthop2
= nhe2
->nhg
.nexthop
;
568 nexthop1
&& nexthop2
;
569 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
571 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
575 /* Check for unequal list lengths */
576 if (nexthop1
|| nexthop2
)
579 /* If there's no backup info, comparison is done. */
580 if ((nhe1
->backup_info
== NULL
) && (nhe2
->backup_info
== NULL
))
583 /* Compare backup info also - test the easy things first */
584 if (nhe1
->backup_info
&& (nhe2
->backup_info
== NULL
))
586 if (nhe2
->backup_info
&& (nhe1
->backup_info
== NULL
))
589 /* Compare number of backups before actually comparing any */
590 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
591 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
592 nexthop1
&& nexthop2
;
593 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
597 /* Did we find the end of one list before the other? */
598 if (nexthop1
|| nexthop2
)
601 /* Have to compare the backup nexthops */
602 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
603 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
604 nexthop1
&& nexthop2
;
605 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
607 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
614 bool zebra_nhg_hash_id_equal(const void *arg1
, const void *arg2
)
616 const struct nhg_hash_entry
*nhe1
= arg1
;
617 const struct nhg_hash_entry
*nhe2
= arg2
;
619 return nhe1
->id
== nhe2
->id
;
622 static int zebra_nhg_process_grp(struct nexthop_group
*nhg
,
623 struct nhg_connected_tree_head
*depends
,
624 struct nh_grp
*grp
, uint8_t count
)
626 nhg_connected_tree_init(depends
);
628 for (int i
= 0; i
< count
; i
++) {
629 struct nhg_hash_entry
*depend
= NULL
;
630 /* We do not care about nexthop_grp.weight at
631 * this time. But we should figure out
632 * how to adapt this to our code in
635 depend
= depends_find_id_add(depends
, grp
[i
].id
);
640 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
646 * If this is a nexthop with its own group
647 * dependencies, add them as well. Not sure its
648 * even possible to have a group within a group
652 copy_nexthops(&nhg
->nexthop
, depend
->nhg
.nexthop
, NULL
);
658 static void handle_recursive_depend(struct nhg_connected_tree_head
*nhg_depends
,
659 struct nexthop
*nh
, afi_t afi
, int type
)
661 struct nhg_hash_entry
*depend
= NULL
;
662 struct nexthop_group resolved_ng
= {};
664 resolved_ng
.nexthop
= nh
;
666 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
667 zlog_debug("%s: head %p, nh %pNHv",
668 __func__
, nhg_depends
, nh
);
670 depend
= zebra_nhg_rib_find(0, &resolved_ng
, afi
, type
);
672 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
673 zlog_debug("%s: nh %pNHv => %p (%u)",
674 __func__
, nh
, depend
,
675 depend
? depend
->id
: 0);
678 depends_add(nhg_depends
, depend
);
682 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
683 * has an id value, that's used. Create a new global/shared nhe if not found.
685 static bool zebra_nhe_find(struct nhg_hash_entry
**nhe
, /* return value */
686 struct nhg_hash_entry
*lookup
,
687 struct nhg_connected_tree_head
*nhg_depends
,
688 afi_t afi
, bool from_dplane
)
690 bool created
= false;
691 bool recursive
= false;
692 struct nhg_hash_entry
*newnhe
, *backup_nhe
;
693 struct nexthop
*nh
= NULL
;
695 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
697 "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s",
698 __func__
, lookup
->id
, lookup
, lookup
->vrf_id
,
699 lookup
->type
, nhg_depends
,
700 (from_dplane
? " (from dplane)" : ""));
703 (*nhe
) = zebra_nhg_lookup_id(lookup
->id
);
705 (*nhe
) = hash_lookup(zrouter
.nhgs
, lookup
);
707 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
708 zlog_debug("%s: lookup => %p (%pNG)", __func__
, *nhe
, *nhe
);
710 /* If we found an existing object, we're done */
714 /* We're going to create/insert a new nhe:
715 * assign the next global id value if necessary.
718 lookup
->id
= nhg_get_next_id();
720 if (!from_dplane
&& lookup
->id
< ZEBRA_NHG_PROTO_LOWER
) {
722 * This is a zebra hashed/owned NHG.
724 * It goes in HASH and ID table.
726 newnhe
= hash_get(zrouter
.nhgs
, lookup
, zebra_nhg_hash_alloc
);
727 zebra_nhg_insert_id(newnhe
);
730 * This is upperproto owned NHG or one we read in from dataplane
731 * and should not be hashed to.
733 * It goes in ID table.
736 hash_get(zrouter
.nhgs_id
, lookup
, zebra_nhg_hash_alloc
);
741 /* Mail back the new object */
744 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
745 zlog_debug("%s: => created %p (%pNG)", __func__
, newnhe
,
748 /* Only hash/lookup the depends if the first lookup
749 * fails to find something. This should hopefully save a
750 * lot of cycles for larger ecmp sizes.
753 /* If you don't want to hash on each nexthop in the
754 * nexthop group struct you can pass the depends
755 * directly. Kernel-side we do this since it just looks
758 zebra_nhg_connect_depends(newnhe
, nhg_depends
);
762 /* Prepare dependency relationships if this is not a
763 * singleton nexthop. There are two cases: a single
764 * recursive nexthop, where we need a relationship to the
765 * resolving nexthop; or a group of nexthops, where we need
766 * relationships with the corresponding singletons.
768 zebra_nhg_depends_init(newnhe
);
770 nh
= newnhe
->nhg
.nexthop
;
772 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
))
773 SET_FLAG(newnhe
->flags
, NEXTHOP_GROUP_VALID
);
775 if (nh
->next
== NULL
&& newnhe
->id
< ZEBRA_NHG_PROTO_LOWER
) {
776 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
777 /* Single recursive nexthop */
778 handle_recursive_depend(&newnhe
->nhg_depends
,
784 /* Proto-owned are groups by default */
785 /* List of nexthops */
786 for (nh
= newnhe
->nhg
.nexthop
; nh
; nh
= nh
->next
) {
787 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
788 zlog_debug("%s: depends NH %pNHv %s",
790 CHECK_FLAG(nh
->flags
,
791 NEXTHOP_FLAG_RECURSIVE
) ?
794 depends_find_add(&newnhe
->nhg_depends
, nh
, afi
,
795 newnhe
->type
, from_dplane
);
800 SET_FLAG(newnhe
->flags
, NEXTHOP_GROUP_RECURSIVE
);
802 /* Attach dependent backpointers to singletons */
803 zebra_nhg_connect_depends(newnhe
, &newnhe
->nhg_depends
);
809 if (zebra_nhg_get_backup_nhg(newnhe
) == NULL
||
810 zebra_nhg_get_backup_nhg(newnhe
)->nexthop
== NULL
)
813 /* If there are backup nexthops, add them to the backup
814 * depends tree. The rules here are a little different.
817 backup_nhe
= newnhe
->backup_info
->nhe
;
819 nh
= backup_nhe
->nhg
.nexthop
;
821 /* Singleton recursive NH */
822 if (nh
->next
== NULL
&&
823 CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
824 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
825 zlog_debug("%s: backup depend NH %pNHv (R)",
828 /* Single recursive nexthop */
829 handle_recursive_depend(&backup_nhe
->nhg_depends
, nh
->resolved
,
830 afi
, backup_nhe
->type
);
833 /* One or more backup NHs */
834 for (; nh
; nh
= nh
->next
) {
835 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
836 zlog_debug("%s: backup depend NH %pNHv %s",
838 CHECK_FLAG(nh
->flags
,
839 NEXTHOP_FLAG_RECURSIVE
) ?
842 depends_find_add(&backup_nhe
->nhg_depends
, nh
, afi
,
843 backup_nhe
->type
, from_dplane
);
848 SET_FLAG(backup_nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
);
851 /* Reset time since last update */
852 (*nhe
)->uptime
= monotime(NULL
);
858 * Lookup or create an nhe, based on an nhg or an nhe id.
860 static bool zebra_nhg_find(struct nhg_hash_entry
**nhe
, uint32_t id
,
861 struct nexthop_group
*nhg
,
862 struct nhg_connected_tree_head
*nhg_depends
,
863 vrf_id_t vrf_id
, afi_t afi
, int type
,
866 struct nhg_hash_entry lookup
= {};
867 bool created
= false;
869 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
870 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
871 __func__
, id
, nhg
, vrf_id
, type
,
874 /* Use a temporary nhe and call into the superset/common code */
876 lookup
.type
= type
? type
: ZEBRA_ROUTE_NHG
;
879 lookup
.vrf_id
= vrf_id
;
880 if (nhg_depends
|| lookup
.nhg
.nexthop
->next
) {
881 /* Groups can have all vrfs and AF's in them */
882 lookup
.afi
= AFI_UNSPEC
;
884 switch (lookup
.nhg
.nexthop
->type
) {
885 case (NEXTHOP_TYPE_IFINDEX
):
886 case (NEXTHOP_TYPE_BLACKHOLE
):
888 * This switch case handles setting the afi different
889 * for ipv4/v6 routes. Ifindex/blackhole nexthop
890 * objects cannot be ambiguous, they must be Address
891 * Family specific. If we get here, we will either use
892 * the AF of the route, or the one we got passed from
893 * here from the kernel.
897 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
898 case (NEXTHOP_TYPE_IPV4
):
901 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
902 case (NEXTHOP_TYPE_IPV6
):
903 lookup
.afi
= AFI_IP6
;
908 created
= zebra_nhe_find(nhe
, &lookup
, nhg_depends
, afi
, from_dplane
);
913 /* Find/create a single nexthop */
914 static struct nhg_hash_entry
*zebra_nhg_find_nexthop(uint32_t id
,
919 struct nhg_hash_entry
*nhe
= NULL
;
920 struct nexthop_group nhg
= {};
921 vrf_id_t vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nh
->vrf_id
;
923 nexthop_group_add_sorted(&nhg
, nh
);
925 zebra_nhg_find(&nhe
, id
, &nhg
, NULL
, vrf_id
, afi
, type
, from_dplane
);
927 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
928 zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__
, nh
, nhe
, nhe
);
933 static uint32_t nhg_ctx_get_id(const struct nhg_ctx
*ctx
)
938 static void nhg_ctx_set_status(struct nhg_ctx
*ctx
, enum nhg_ctx_status status
)
940 ctx
->status
= status
;
943 static enum nhg_ctx_status
nhg_ctx_get_status(const struct nhg_ctx
*ctx
)
948 static void nhg_ctx_set_op(struct nhg_ctx
*ctx
, enum nhg_ctx_op_e op
)
953 static enum nhg_ctx_op_e
nhg_ctx_get_op(const struct nhg_ctx
*ctx
)
958 static vrf_id_t
nhg_ctx_get_vrf_id(const struct nhg_ctx
*ctx
)
963 static int nhg_ctx_get_type(const struct nhg_ctx
*ctx
)
968 static int nhg_ctx_get_afi(const struct nhg_ctx
*ctx
)
973 static struct nexthop
*nhg_ctx_get_nh(struct nhg_ctx
*ctx
)
978 static uint8_t nhg_ctx_get_count(const struct nhg_ctx
*ctx
)
983 static struct nh_grp
*nhg_ctx_get_grp(struct nhg_ctx
*ctx
)
988 static struct nhg_ctx
*nhg_ctx_new(void)
992 new = XCALLOC(MTYPE_NHG_CTX
, sizeof(struct nhg_ctx
));
997 void nhg_ctx_free(struct nhg_ctx
**ctx
)
1004 assert((*ctx
) != NULL
);
1006 if (nhg_ctx_get_count(*ctx
))
1009 nh
= nhg_ctx_get_nh(*ctx
);
1011 nexthop_del_labels(nh
);
1012 nexthop_del_srv6_seg6local(nh
);
1013 nexthop_del_srv6_seg6(nh
);
1016 XFREE(MTYPE_NHG_CTX
, *ctx
);
1019 static struct nhg_ctx
*nhg_ctx_init(uint32_t id
, struct nexthop
*nh
,
1020 struct nh_grp
*grp
, vrf_id_t vrf_id
,
1021 afi_t afi
, int type
, uint8_t count
)
1023 struct nhg_ctx
*ctx
= NULL
;
1025 ctx
= nhg_ctx_new();
1028 ctx
->vrf_id
= vrf_id
;
1034 /* Copy over the array */
1035 memcpy(&ctx
->u
.grp
, grp
, count
* sizeof(struct nh_grp
));
1042 static void zebra_nhg_set_valid(struct nhg_hash_entry
*nhe
)
1044 struct nhg_connected
*rb_node_dep
;
1046 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1048 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1049 zebra_nhg_set_valid(rb_node_dep
->nhe
);
1052 static void zebra_nhg_set_invalid(struct nhg_hash_entry
*nhe
)
1054 struct nhg_connected
*rb_node_dep
;
1056 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1058 /* If we're in shutdown, this interface event needs to clean
1059 * up installed NHGs, so don't clear that flag directly.
1061 if (!zrouter
.in_shutdown
)
1062 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1064 /* Update validity of nexthops depending on it */
1065 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1066 zebra_nhg_check_valid(rb_node_dep
->nhe
);
1069 void zebra_nhg_check_valid(struct nhg_hash_entry
*nhe
)
1071 struct nhg_connected
*rb_node_dep
= NULL
;
1074 /* If anthing else in the group is valid, the group is valid */
1075 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1076 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
, NEXTHOP_GROUP_VALID
)) {
1084 zebra_nhg_set_valid(nhe
);
1086 zebra_nhg_set_invalid(nhe
);
1089 static void zebra_nhg_release_all_deps(struct nhg_hash_entry
*nhe
)
1091 /* Remove it from any lists it may be on */
1092 zebra_nhg_depends_release(nhe
);
1093 zebra_nhg_dependents_release(nhe
);
1095 if_nhg_dependents_del(nhe
->ifp
, nhe
);
1098 static void zebra_nhg_release(struct nhg_hash_entry
*nhe
)
1100 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1101 zlog_debug("%s: nhe %p (%pNG)", __func__
, nhe
, nhe
);
1103 zebra_nhg_release_all_deps(nhe
);
1106 * If its not zebra owned, we didn't store it here and have to be
1107 * sure we don't clear one thats actually being used.
1109 if (nhe
->id
< ZEBRA_NHG_PROTO_LOWER
)
1110 hash_release(zrouter
.nhgs
, nhe
);
1112 hash_release(zrouter
.nhgs_id
, nhe
);
1115 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry
*nhe
)
1117 zebra_nhg_release(nhe
);
1118 zebra_nhg_free(nhe
);
1121 static void zebra_nhg_handle_install(struct nhg_hash_entry
*nhe
)
1123 /* Update validity of groups depending on it */
1124 struct nhg_connected
*rb_node_dep
;
1126 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1127 zebra_nhg_set_valid(rb_node_dep
->nhe
);
1131 * The kernel/other program has changed the state of a nexthop object we are
1134 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry
*nhe
,
1140 "Kernel %s a nexthop group with ID (%pNG) that we are still using for a route, sending it back down",
1141 (is_delete
? "deleted" : "updated"), nhe
);
1143 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1144 zebra_nhg_install_kernel(nhe
);
1146 zebra_nhg_handle_uninstall(nhe
);
1149 static int nhg_ctx_process_new(struct nhg_ctx
*ctx
)
1151 struct nexthop_group
*nhg
= NULL
;
1152 struct nhg_connected_tree_head nhg_depends
= {};
1153 struct nhg_hash_entry
*lookup
= NULL
;
1154 struct nhg_hash_entry
*nhe
= NULL
;
1156 uint32_t id
= nhg_ctx_get_id(ctx
);
1157 uint8_t count
= nhg_ctx_get_count(ctx
);
1158 vrf_id_t vrf_id
= nhg_ctx_get_vrf_id(ctx
);
1159 int type
= nhg_ctx_get_type(ctx
);
1160 afi_t afi
= nhg_ctx_get_afi(ctx
);
1162 lookup
= zebra_nhg_lookup_id(id
);
1164 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1165 zlog_debug("%s: id %u, count %d, lookup => %p",
1166 __func__
, id
, count
, lookup
);
1169 /* This is already present in our table, hence an update
1170 * that we did not initate.
1172 zebra_nhg_handle_kernel_state_change(lookup
, false);
1176 if (nhg_ctx_get_count(ctx
)) {
1177 nhg
= nexthop_group_new();
1178 if (zebra_nhg_process_grp(nhg
, &nhg_depends
,
1179 nhg_ctx_get_grp(ctx
), count
)) {
1180 depends_decrement_free(&nhg_depends
);
1181 nexthop_group_delete(&nhg
);
1185 if (!zebra_nhg_find(&nhe
, id
, nhg
, &nhg_depends
, vrf_id
, afi
,
1187 depends_decrement_free(&nhg_depends
);
1189 /* These got copied over in zebra_nhg_alloc() */
1190 nexthop_group_delete(&nhg
);
1192 nhe
= zebra_nhg_find_nexthop(id
, nhg_ctx_get_nh(ctx
), afi
, type
,
1197 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1198 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
1203 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1204 zlog_debug("%s: nhe %p (%pNG) is new", __func__
, nhe
, nhe
);
1207 * If daemon nhg from the kernel, add a refcnt here to indicate the
1210 if (PROTO_OWNED(nhe
))
1211 zebra_nhg_increment_ref(nhe
);
1213 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1214 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1219 static int nhg_ctx_process_del(struct nhg_ctx
*ctx
)
1221 struct nhg_hash_entry
*nhe
= NULL
;
1222 uint32_t id
= nhg_ctx_get_id(ctx
);
1224 nhe
= zebra_nhg_lookup_id(id
);
1228 EC_ZEBRA_BAD_NHG_MESSAGE
,
1229 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
1234 zebra_nhg_handle_kernel_state_change(nhe
, true);
1239 static void nhg_ctx_fini(struct nhg_ctx
**ctx
)
1242 * Just freeing for now, maybe do something more in the future
1249 static int queue_add(struct nhg_ctx
*ctx
)
1251 /* If its queued or already processed do nothing */
1252 if (nhg_ctx_get_status(ctx
) == NHG_CTX_QUEUED
)
1255 if (rib_queue_nhg_ctx_add(ctx
)) {
1256 nhg_ctx_set_status(ctx
, NHG_CTX_FAILURE
);
1260 nhg_ctx_set_status(ctx
, NHG_CTX_QUEUED
);
1265 int nhg_ctx_process(struct nhg_ctx
*ctx
)
1269 switch (nhg_ctx_get_op(ctx
)) {
1270 case NHG_CTX_OP_NEW
:
1271 ret
= nhg_ctx_process_new(ctx
);
1272 if (nhg_ctx_get_count(ctx
) && ret
== -ENOENT
1273 && nhg_ctx_get_status(ctx
) != NHG_CTX_REQUEUED
) {
1275 * We have entered a situation where we are
1276 * processing a group from the kernel
1277 * that has a contained nexthop which
1278 * we have not yet processed.
1280 * Re-enqueue this ctx to be handled exactly one
1281 * more time (indicated by the flag).
1283 * By the time we get back to it, we
1284 * should have processed its depends.
1286 nhg_ctx_set_status(ctx
, NHG_CTX_NONE
);
1287 if (queue_add(ctx
) == 0) {
1288 nhg_ctx_set_status(ctx
, NHG_CTX_REQUEUED
);
1293 case NHG_CTX_OP_DEL
:
1294 ret
= nhg_ctx_process_del(ctx
);
1295 case NHG_CTX_OP_NONE
:
1299 nhg_ctx_set_status(ctx
, (ret
? NHG_CTX_FAILURE
: NHG_CTX_SUCCESS
));
1306 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1307 int zebra_nhg_kernel_find(uint32_t id
, struct nexthop
*nh
, struct nh_grp
*grp
,
1308 uint8_t count
, vrf_id_t vrf_id
, afi_t afi
, int type
,
1311 struct nhg_ctx
*ctx
= NULL
;
1313 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1314 zlog_debug("%s: nh %pNHv, id %u, count %d",
1315 __func__
, nh
, id
, (int)count
);
1317 if (id
> id_counter
&& id
< ZEBRA_NHG_PROTO_LOWER
)
1318 /* Increase our counter so we don't try to create
1319 * an ID that already exists
1323 ctx
= nhg_ctx_init(id
, nh
, grp
, vrf_id
, afi
, type
, count
);
1324 nhg_ctx_set_op(ctx
, NHG_CTX_OP_NEW
);
1326 /* Under statup conditions, we need to handle them immediately
1327 * like we do for routes. Otherwise, we are going to get a route
1328 * with a nhe_id that we have not handled.
1331 return nhg_ctx_process(ctx
);
1333 if (queue_add(ctx
)) {
1341 /* Kernel-side, received delete message */
1342 int zebra_nhg_kernel_del(uint32_t id
, vrf_id_t vrf_id
)
1344 struct nhg_ctx
*ctx
= NULL
;
1346 ctx
= nhg_ctx_init(id
, NULL
, NULL
, vrf_id
, 0, 0, 0);
1348 nhg_ctx_set_op(ctx
, NHG_CTX_OP_DEL
);
1350 if (queue_add(ctx
)) {
1358 /* Some dependency helper functions */
1359 static struct nhg_hash_entry
*depends_find_recursive(const struct nexthop
*nh
,
1360 afi_t afi
, int type
)
1362 struct nhg_hash_entry
*nhe
;
1363 struct nexthop
*lookup
= NULL
;
1365 lookup
= nexthop_dup(nh
, NULL
);
1367 nhe
= zebra_nhg_find_nexthop(0, lookup
, afi
, type
, false);
1369 nexthops_free(lookup
);
1374 static struct nhg_hash_entry
*depends_find_singleton(const struct nexthop
*nh
,
1375 afi_t afi
, int type
,
1378 struct nhg_hash_entry
*nhe
;
1379 struct nexthop lookup
= {};
1381 /* Capture a snapshot of this single nh; it might be part of a list,
1382 * so we need to make a standalone copy.
1384 nexthop_copy_no_recurse(&lookup
, nh
, NULL
);
1386 nhe
= zebra_nhg_find_nexthop(0, &lookup
, afi
, type
, from_dplane
);
1388 /* The copy may have allocated labels; free them if necessary. */
1389 nexthop_del_labels(&lookup
);
1390 nexthop_del_srv6_seg6local(&lookup
);
1391 nexthop_del_srv6_seg6(&lookup
);
1393 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1394 zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__
, nh
, nhe
, nhe
);
1399 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
,
1400 int type
, bool from_dplane
)
1402 struct nhg_hash_entry
*nhe
= NULL
;
1407 /* We are separating these functions out to increase handling speed
1408 * in the non-recursive case (by not alloc/freeing)
1410 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1411 nhe
= depends_find_recursive(nh
, afi
, type
);
1413 nhe
= depends_find_singleton(nh
, afi
, type
, from_dplane
);
1416 if (IS_ZEBRA_DEBUG_NHG_DETAIL
) {
1417 zlog_debug("%s: nh %pNHv %s => %p (%pNG)", __func__
, nh
,
1418 CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
) ? "(R)"
1427 static void depends_add(struct nhg_connected_tree_head
*head
,
1428 struct nhg_hash_entry
*depend
)
1430 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1431 zlog_debug("%s: head %p nh %pNHv",
1432 __func__
, head
, depend
->nhg
.nexthop
);
1434 /* If NULL is returned, it was successfully added and
1435 * needs to have its refcnt incremented.
1437 * Else the NHE is already present in the tree and doesn't
1438 * need to increment the refcnt.
1440 if (nhg_connected_tree_add_nhe(head
, depend
) == NULL
)
1441 zebra_nhg_increment_ref(depend
);
1444 static struct nhg_hash_entry
*
1445 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
1446 afi_t afi
, int type
, bool from_dplane
)
1448 struct nhg_hash_entry
*depend
= NULL
;
1450 depend
= depends_find(nh
, afi
, type
, from_dplane
);
1452 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1453 zlog_debug("%s: nh %pNHv => %p",
1454 __func__
, nh
, depend
);
1457 depends_add(head
, depend
);
1462 static struct nhg_hash_entry
*
1463 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
)
1465 struct nhg_hash_entry
*depend
= NULL
;
1467 depend
= zebra_nhg_lookup_id(id
);
1470 depends_add(head
, depend
);
1475 static void depends_decrement_free(struct nhg_connected_tree_head
*head
)
1477 nhg_connected_tree_decrement_ref(head
);
1478 nhg_connected_tree_free(head
);
1481 /* Find an nhe based on a list of nexthops */
1482 struct nhg_hash_entry
*zebra_nhg_rib_find(uint32_t id
,
1483 struct nexthop_group
*nhg
,
1484 afi_t rt_afi
, int type
)
1486 struct nhg_hash_entry
*nhe
= NULL
;
1490 * CLANG SA is complaining that nexthop may be NULL
1491 * Make it happy but this is ridonc
1493 assert(nhg
->nexthop
);
1494 vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nhg
->nexthop
->vrf_id
;
1496 zebra_nhg_find(&nhe
, id
, nhg
, NULL
, vrf_id
, rt_afi
, type
, false);
1498 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1499 zlog_debug("%s: => nhe %p (%pNG)", __func__
, nhe
, nhe
);
1504 /* Find an nhe based on a route's nhe */
1505 struct nhg_hash_entry
*
1506 zebra_nhg_rib_find_nhe(struct nhg_hash_entry
*rt_nhe
, afi_t rt_afi
)
1508 struct nhg_hash_entry
*nhe
= NULL
;
1510 if (!(rt_nhe
&& rt_nhe
->nhg
.nexthop
)) {
1511 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1512 "No nexthop passed to %s", __func__
);
1516 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1517 zlog_debug("%s: rt_nhe %p (%pNG)", __func__
, rt_nhe
, rt_nhe
);
1519 zebra_nhe_find(&nhe
, rt_nhe
, NULL
, rt_afi
, false);
1521 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1522 zlog_debug("%s: => nhe %p (%pNG)", __func__
, nhe
, nhe
);
1528 * Allocate backup nexthop info object. Typically these are embedded in
1529 * nhg_hash_entry objects.
1531 struct nhg_backup_info
*zebra_nhg_backup_alloc(void)
1533 struct nhg_backup_info
*p
;
1535 p
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_backup_info
));
1537 p
->nhe
= zebra_nhg_alloc();
1539 /* Identify the embedded group used to hold the list of backups */
1540 SET_FLAG(p
->nhe
->flags
, NEXTHOP_GROUP_BACKUP
);
1546 * Free backup nexthop info object, deal with any embedded allocations
1548 void zebra_nhg_backup_free(struct nhg_backup_info
**p
)
1552 zebra_nhg_free((*p
)->nhe
);
1554 XFREE(MTYPE_NHG
, (*p
));
1558 /* Accessor for backup nexthop group */
1559 struct nexthop_group
*zebra_nhg_get_backup_nhg(struct nhg_hash_entry
*nhe
)
1561 struct nexthop_group
*p
= NULL
;
1564 if (nhe
->backup_info
&& nhe
->backup_info
->nhe
)
1565 p
= &(nhe
->backup_info
->nhe
->nhg
);
1572 * Helper to return a copy of a backup_info - note that this is a shallow
1573 * copy, meant to be used when creating a new nhe from info passed in with
1576 static struct nhg_backup_info
*
1577 nhg_backup_copy(const struct nhg_backup_info
*orig
)
1579 struct nhg_backup_info
*b
;
1581 b
= zebra_nhg_backup_alloc();
1583 /* Copy list of nexthops */
1584 nexthop_group_copy(&(b
->nhe
->nhg
), &(orig
->nhe
->nhg
));
1589 static void zebra_nhg_free_members(struct nhg_hash_entry
*nhe
)
1591 nexthops_free(nhe
->nhg
.nexthop
);
1593 zebra_nhg_backup_free(&nhe
->backup_info
);
1595 /* Decrement to remove connection ref */
1596 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1597 nhg_connected_tree_free(&nhe
->nhg_depends
);
1598 nhg_connected_tree_free(&nhe
->nhg_dependents
);
1601 void zebra_nhg_free(struct nhg_hash_entry
*nhe
)
1603 if (IS_ZEBRA_DEBUG_NHG_DETAIL
) {
1604 /* Group or singleton? */
1605 if (nhe
->nhg
.nexthop
&& nhe
->nhg
.nexthop
->next
)
1606 zlog_debug("%s: nhe %p (%pNG), refcnt %d", __func__
,
1607 nhe
, nhe
, nhe
->refcnt
);
1609 zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
1610 __func__
, nhe
, nhe
, nhe
->refcnt
,
1615 zlog_debug("nhe_id=%pNG hash refcnt=%d", nhe
, nhe
->refcnt
);
1617 zebra_nhg_free_members(nhe
);
1619 XFREE(MTYPE_NHG
, nhe
);
1622 void zebra_nhg_hash_free(void *p
)
1624 zebra_nhg_release_all_deps((struct nhg_hash_entry
*)p
);
1625 zebra_nhg_free((struct nhg_hash_entry
*)p
);
1628 static void zebra_nhg_timer(struct thread
*thread
)
1630 struct nhg_hash_entry
*nhe
= THREAD_ARG(thread
);
1632 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1633 zlog_debug("Nexthop Timer for nhe: %pNG", nhe
);
1635 if (nhe
->refcnt
== 1)
1636 zebra_nhg_decrement_ref(nhe
);
1639 void zebra_nhg_decrement_ref(struct nhg_hash_entry
*nhe
)
1641 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1642 zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__
, nhe
, nhe
,
1643 nhe
->refcnt
, nhe
->refcnt
- 1);
1647 if (!zrouter
.in_shutdown
&& nhe
->refcnt
<= 0 &&
1648 CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
) &&
1649 !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_KEEP_AROUND
)) {
1651 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_KEEP_AROUND
);
1652 thread_add_timer(zrouter
.master
, zebra_nhg_timer
, nhe
,
1653 zrouter
.nhg_keep
, &nhe
->timer
);
1656 if (!zebra_nhg_depends_is_empty(nhe
))
1657 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1659 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1660 zebra_nhg_uninstall_kernel(nhe
);
1663 void zebra_nhg_increment_ref(struct nhg_hash_entry
*nhe
)
1665 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1666 zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__
, nhe
, nhe
,
1667 nhe
->refcnt
, nhe
->refcnt
+ 1);
1671 if (thread_is_scheduled(nhe
->timer
)) {
1672 THREAD_OFF(nhe
->timer
);
1674 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_KEEP_AROUND
);
1677 if (!zebra_nhg_depends_is_empty(nhe
))
1678 nhg_connected_tree_increment_ref(&nhe
->nhg_depends
);
1681 static struct nexthop
*nexthop_set_resolved(afi_t afi
,
1682 const struct nexthop
*newhop
,
1683 struct nexthop
*nexthop
,
1684 struct zebra_sr_policy
*policy
)
1686 struct nexthop
*resolved_hop
;
1687 uint8_t num_labels
= 0;
1688 mpls_label_t labels
[MPLS_MAX_LABELS
];
1689 enum lsp_types_t label_type
= ZEBRA_LSP_NONE
;
1692 resolved_hop
= nexthop_new();
1693 SET_FLAG(resolved_hop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1695 resolved_hop
->vrf_id
= nexthop
->vrf_id
;
1696 switch (newhop
->type
) {
1697 case NEXTHOP_TYPE_IPV4
:
1698 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1699 /* If the resolving route specifies a gateway, use it */
1700 resolved_hop
->type
= newhop
->type
;
1701 resolved_hop
->gate
.ipv4
= newhop
->gate
.ipv4
;
1703 if (newhop
->ifindex
) {
1704 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1705 resolved_hop
->ifindex
= newhop
->ifindex
;
1708 case NEXTHOP_TYPE_IPV6
:
1709 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1710 resolved_hop
->type
= newhop
->type
;
1711 resolved_hop
->gate
.ipv6
= newhop
->gate
.ipv6
;
1713 if (newhop
->ifindex
) {
1714 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1715 resolved_hop
->ifindex
= newhop
->ifindex
;
1718 case NEXTHOP_TYPE_IFINDEX
:
1719 /* If the resolving route is an interface route,
1720 * it means the gateway we are looking up is connected
1721 * to that interface. (The actual network is _not_ onlink).
1722 * Therefore, the resolved route should have the original
1723 * gateway as nexthop as it is directly connected.
1725 * On Linux, we have to set the onlink netlink flag because
1726 * otherwise, the kernel won't accept the route.
1728 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1729 if (afi
== AFI_IP
) {
1730 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1731 resolved_hop
->gate
.ipv4
= nexthop
->gate
.ipv4
;
1732 } else if (afi
== AFI_IP6
) {
1733 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1734 resolved_hop
->gate
.ipv6
= nexthop
->gate
.ipv6
;
1736 resolved_hop
->ifindex
= newhop
->ifindex
;
1738 case NEXTHOP_TYPE_BLACKHOLE
:
1739 resolved_hop
->type
= NEXTHOP_TYPE_BLACKHOLE
;
1740 resolved_hop
->bh_type
= newhop
->bh_type
;
1744 if (newhop
->flags
& NEXTHOP_FLAG_ONLINK
)
1745 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1747 /* Copy labels of the resolved route and the parent resolving to it */
1752 * Don't push the first SID if the corresponding action in the
1755 if (!newhop
->nh_label
|| !newhop
->nh_label
->num_labels
1756 || newhop
->nh_label
->label
[0] == MPLS_LABEL_IMPLICIT_NULL
)
1759 for (; i
< policy
->segment_list
.label_num
; i
++)
1760 labels
[num_labels
++] = policy
->segment_list
.labels
[i
];
1761 label_type
= policy
->segment_list
.type
;
1762 } else if (newhop
->nh_label
) {
1763 for (i
= 0; i
< newhop
->nh_label
->num_labels
; i
++) {
1764 /* Be a bit picky about overrunning the local array */
1765 if (num_labels
>= MPLS_MAX_LABELS
) {
1766 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1767 zlog_debug("%s: too many labels in newhop %pNHv",
1771 labels
[num_labels
++] = newhop
->nh_label
->label
[i
];
1773 /* Use the "outer" type */
1774 label_type
= newhop
->nh_label_type
;
1777 if (nexthop
->nh_label
) {
1778 for (i
= 0; i
< nexthop
->nh_label
->num_labels
; i
++) {
1779 /* Be a bit picky about overrunning the local array */
1780 if (num_labels
>= MPLS_MAX_LABELS
) {
1781 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1782 zlog_debug("%s: too many labels in nexthop %pNHv",
1786 labels
[num_labels
++] = nexthop
->nh_label
->label
[i
];
1789 /* If the parent has labels, use its type if
1790 * we don't already have one.
1792 if (label_type
== ZEBRA_LSP_NONE
)
1793 label_type
= nexthop
->nh_label_type
;
1797 nexthop_add_labels(resolved_hop
, label_type
, num_labels
,
1800 if (nexthop
->nh_srv6
) {
1801 nexthop_add_srv6_seg6local(resolved_hop
,
1802 nexthop
->nh_srv6
->seg6local_action
,
1803 &nexthop
->nh_srv6
->seg6local_ctx
);
1804 nexthop_add_srv6_seg6(resolved_hop
,
1805 &nexthop
->nh_srv6
->seg6_segs
);
1808 resolved_hop
->rparent
= nexthop
;
1809 _nexthop_add(&nexthop
->resolved
, resolved_hop
);
1811 return resolved_hop
;
1814 /* Checks if nexthop we are trying to resolve to is valid */
1815 static bool nexthop_valid_resolve(const struct nexthop
*nexthop
,
1816 const struct nexthop
*resolved
)
1818 /* Can't resolve to a recursive nexthop */
1819 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1822 /* Must be ACTIVE */
1823 if (!CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_ACTIVE
))
1826 /* Must not be duplicate */
1827 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_DUPLICATE
))
1830 switch (nexthop
->type
) {
1831 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1832 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1833 /* If the nexthop we are resolving to does not match the
1834 * ifindex for the nexthop the route wanted, its not valid.
1836 if (nexthop
->ifindex
!= resolved
->ifindex
)
1839 case NEXTHOP_TYPE_IPV4
:
1840 case NEXTHOP_TYPE_IPV6
:
1841 case NEXTHOP_TYPE_IFINDEX
:
1842 case NEXTHOP_TYPE_BLACKHOLE
:
1850 * When resolving a recursive nexthop, capture backup nexthop(s) also
1851 * so they can be conveyed through the dataplane to the FIB. We'll look
1852 * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
1853 * into the route's resolved nh 'resolved' and its nhe 'nhe'.
1855 static int resolve_backup_nexthops(const struct nexthop
*nexthop
,
1856 const struct nhg_hash_entry
*nhe
,
1857 struct nexthop
*resolved
,
1858 struct nhg_hash_entry
*resolve_nhe
,
1859 struct backup_nh_map_s
*map
)
1862 const struct nexthop
*bnh
;
1863 struct nexthop
*nh
, *newnh
;
1864 mpls_label_t labels
[MPLS_MAX_LABELS
];
1867 assert(nexthop
->backup_num
<= NEXTHOP_MAX_BACKUPS
);
1869 /* Locate backups from the original nexthop's backup index and nhe */
1870 for (i
= 0; i
< nexthop
->backup_num
; i
++) {
1871 idx
= nexthop
->backup_idx
[i
];
1873 /* Do we already know about this particular backup? */
1874 for (j
= 0; j
< map
->map_count
; j
++) {
1875 if (map
->map
[j
].orig_idx
== idx
)
1879 if (j
< map
->map_count
) {
1880 resolved
->backup_idx
[resolved
->backup_num
] =
1881 map
->map
[j
].new_idx
;
1882 resolved
->backup_num
++;
1884 SET_FLAG(resolved
->flags
, NEXTHOP_FLAG_HAS_BACKUP
);
1886 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1887 zlog_debug("%s: found map idx orig %d, new %d",
1888 __func__
, map
->map
[j
].orig_idx
,
1889 map
->map
[j
].new_idx
);
1894 /* We can't handle any new map entries at this point. */
1895 if (map
->map_count
== MULTIPATH_NUM
)
1898 /* Need to create/copy a new backup */
1899 bnh
= nhe
->backup_info
->nhe
->nhg
.nexthop
;
1900 for (j
= 0; j
< idx
; j
++) {
1906 /* Whoops - bad index in the nexthop? */
1910 if (resolve_nhe
->backup_info
== NULL
)
1911 resolve_nhe
->backup_info
= zebra_nhg_backup_alloc();
1913 /* Update backup info in the resolving nexthop and its nhe */
1914 newnh
= nexthop_dup_no_recurse(bnh
, NULL
);
1916 /* We may need some special handling for mpls labels: the new
1917 * backup needs to carry the recursive nexthop's labels,
1918 * if any: they may be vrf labels e.g.
1919 * The original/inner labels are in the stack of 'resolve_nhe',
1920 * if that is longer than the stack in 'nexthop'.
1922 if (newnh
->nh_label
&& resolved
->nh_label
&&
1923 nexthop
->nh_label
) {
1924 if (resolved
->nh_label
->num_labels
>
1925 nexthop
->nh_label
->num_labels
) {
1926 /* Prepare new label stack */
1928 for (j
= 0; j
< newnh
->nh_label
->num_labels
;
1930 labels
[j
] = newnh
->nh_label
->label
[j
];
1934 /* Include inner labels */
1935 for (j
= nexthop
->nh_label
->num_labels
;
1936 j
< resolved
->nh_label
->num_labels
;
1938 labels
[num_labels
] =
1939 resolved
->nh_label
->label
[j
];
1943 /* Replace existing label stack in the backup */
1944 nexthop_del_labels(newnh
);
1945 nexthop_add_labels(newnh
, bnh
->nh_label_type
,
1946 num_labels
, labels
);
1950 /* Need to compute the new backup index in the new
1951 * backup list, and add to map struct.
1954 nh
= resolve_nhe
->backup_info
->nhe
->nhg
.nexthop
;
1964 } else /* First one */
1965 resolve_nhe
->backup_info
->nhe
->nhg
.nexthop
= newnh
;
1968 resolved
->backup_idx
[resolved
->backup_num
] = j
;
1969 resolved
->backup_num
++;
1971 SET_FLAG(resolved
->flags
, NEXTHOP_FLAG_HAS_BACKUP
);
1973 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1974 zlog_debug("%s: added idx orig %d, new %d",
1977 /* Update map/cache */
1978 map
->map
[map
->map_count
].orig_idx
= idx
;
1979 map
->map
[map
->map_count
].new_idx
= j
;
1987 * So this nexthop resolution has decided that a connected route
1988 * is the correct choice. At this point in time if FRR has multiple
1989 * connected routes that all point to the same prefix one will be
1990 * selected, *but* the particular interface may not be the one
1991 * that the nexthop points at. Let's look at all the available
1992 * connected routes on this node and if any of them auto match
1993 * the routes nexthops ifindex that is good enough for a match
1995 * This code is depending on the fact that a nexthop->ifindex is 0
1996 * if it is not known, if this assumption changes, yummy!
1997 * Additionally a ifindx of 0 means figure it out for us.
1999 static struct route_entry
*
2000 zebra_nhg_connected_ifindex(struct route_node
*rn
, struct route_entry
*match
,
2001 int32_t curr_ifindex
)
2003 struct nexthop
*newhop
= match
->nhe
->nhg
.nexthop
;
2004 struct route_entry
*re
;
2006 assert(newhop
); /* What a kick in the patooey */
2008 if (curr_ifindex
== 0)
2011 if (curr_ifindex
== newhop
->ifindex
)
2015 * At this point we know that this route is matching a connected
2016 * but there are possibly a bunch of connected routes that are
2017 * alive that should be considered as well. So let's iterate over
2018 * all the re's and see if they are connected as well and maybe one
2019 * of those ifindexes match as well.
2021 RNODE_FOREACH_RE (rn
, re
) {
2022 if (re
->type
!= ZEBRA_ROUTE_CONNECT
)
2025 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
2029 * zebra has a connected route that is not removed
2030 * let's test if it is good
2032 newhop
= re
->nhe
->nhg
.nexthop
;
2034 if (curr_ifindex
== newhop
->ifindex
)
2042 * Given a nexthop we need to properly recursively resolve,
2043 * do a table lookup to find and match if at all possible.
2044 * Set the nexthop->ifindex and resolution info as appropriate.
2046 static int nexthop_active(struct nexthop
*nexthop
, struct nhg_hash_entry
*nhe
,
2047 const struct prefix
*top
, int type
, uint32_t flags
,
2048 uint32_t *pmtu
, vrf_id_t vrf_id
)
2051 struct route_table
*table
;
2052 struct route_node
*rn
;
2053 struct route_entry
*match
= NULL
;
2055 struct zebra_nhlfe
*nhlfe
;
2056 struct nexthop
*newhop
;
2057 struct interface
*ifp
;
2059 struct zebra_vrf
*zvrf
;
2060 struct in_addr local_ipv4
;
2061 struct in_addr
*ipv4
;
2064 /* Reset some nexthop attributes that we'll recompute if necessary */
2065 if ((nexthop
->type
== NEXTHOP_TYPE_IPV4
)
2066 || (nexthop
->type
== NEXTHOP_TYPE_IPV6
))
2067 nexthop
->ifindex
= 0;
2069 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
);
2070 nexthops_free(nexthop
->resolved
);
2071 nexthop
->resolved
= NULL
;
2074 * Set afi based on nexthop type.
2075 * Some nexthop types get special handling, possibly skipping
2076 * the normal processing.
2078 switch (nexthop
->type
) {
2079 case NEXTHOP_TYPE_IFINDEX
:
2081 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
2083 * If the interface exists and its operative or its a kernel
2084 * route and interface is up, its active. We trust kernel routes
2088 && (if_is_operative(ifp
)
2090 && (type
== ZEBRA_ROUTE_KERNEL
2091 || type
== ZEBRA_ROUTE_SYSTEM
))))
2097 case NEXTHOP_TYPE_IPV6_IFINDEX
:
2100 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
2101 ifp
= if_lookup_by_index(nexthop
->ifindex
,
2103 if (ifp
&& if_is_operative(ifp
))
2110 case NEXTHOP_TYPE_IPV4
:
2111 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2114 case NEXTHOP_TYPE_IPV6
:
2118 case NEXTHOP_TYPE_BLACKHOLE
:
2123 * If the nexthop has been marked as 'onlink' we just need to make
2124 * sure the nexthop's interface is known and is operational.
2126 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ONLINK
)) {
2127 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
2129 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2130 zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
2131 nexthop
, nexthop
->ifindex
);
2134 if (!if_is_operative(ifp
)) {
2135 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2136 zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
2137 nexthop
, ifp
->name
);
2144 ((top
->family
== AF_INET
&& top
->prefixlen
== IPV4_MAX_BITLEN
&&
2145 nexthop
->gate
.ipv4
.s_addr
== top
->u
.prefix4
.s_addr
) ||
2146 (top
->family
== AF_INET6
&& top
->prefixlen
== IPV6_MAX_BITLEN
&&
2147 memcmp(&nexthop
->gate
.ipv6
, &top
->u
.prefix6
, IPV6_MAX_BYTELEN
) ==
2149 nexthop
->vrf_id
== vrf_id
) {
2150 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2152 " :%s: Attempting to install a max prefixlength route through itself",
2157 /* Validation for ipv4 mapped ipv6 nexthop. */
2158 if (IS_MAPPED_IPV6(&nexthop
->gate
.ipv6
)) {
2161 ipv4_mapped_ipv6_to_ipv4(&nexthop
->gate
.ipv6
, ipv4
);
2163 ipv4
= &nexthop
->gate
.ipv4
;
2166 /* Processing for nexthops with SR 'color' attribute, using
2167 * the corresponding SR policy object.
2169 if (nexthop
->srte_color
) {
2170 struct ipaddr endpoint
= {0};
2171 struct zebra_sr_policy
*policy
;
2175 endpoint
.ipa_type
= IPADDR_V4
;
2176 endpoint
.ipaddr_v4
= *ipv4
;
2179 endpoint
.ipa_type
= IPADDR_V6
;
2180 endpoint
.ipaddr_v6
= nexthop
->gate
.ipv6
;
2183 flog_err(EC_LIB_DEVELOPMENT
,
2184 "%s: unknown address-family: %u", __func__
,
2189 policy
= zebra_sr_policy_find(nexthop
->srte_color
, &endpoint
);
2190 if (policy
&& policy
->status
== ZEBRA_SR_POLICY_UP
) {
2192 frr_each_safe (nhlfe_list
, &policy
->lsp
->nhlfe_list
,
2194 if (!CHECK_FLAG(nhlfe
->flags
,
2195 NHLFE_FLAG_SELECTED
)
2196 || CHECK_FLAG(nhlfe
->flags
,
2197 NHLFE_FLAG_DELETED
))
2199 SET_FLAG(nexthop
->flags
,
2200 NEXTHOP_FLAG_RECURSIVE
);
2201 nexthop_set_resolved(afi
, nhlfe
->nexthop
,
2210 /* Make lookup prefix. */
2211 memset(&p
, 0, sizeof(struct prefix
));
2215 p
.prefixlen
= IPV4_MAX_BITLEN
;
2216 p
.u
.prefix4
= *ipv4
;
2219 p
.family
= AF_INET6
;
2220 p
.prefixlen
= IPV6_MAX_BITLEN
;
2221 p
.u
.prefix6
= nexthop
->gate
.ipv6
;
2224 assert(afi
!= AFI_IP
&& afi
!= AFI_IP6
);
2228 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, nexthop
->vrf_id
);
2230 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
2231 if (!table
|| !zvrf
) {
2232 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2233 zlog_debug(" %s: Table not found", __func__
);
2237 rn
= route_node_match(table
, (struct prefix
*)&p
);
2239 route_unlock_node(rn
);
2241 /* Lookup should halt if we've matched against ourselves ('top',
2242 * if specified) - i.e., we cannot have a nexthop NH1 is
2243 * resolved by a route NH1. The exception is if the route is a
2246 if (prefix_same(&rn
->p
, top
))
2247 if (((afi
== AFI_IP
)
2248 && (rn
->p
.prefixlen
!= IPV4_MAX_BITLEN
))
2249 || ((afi
== AFI_IP6
)
2250 && (rn
->p
.prefixlen
!= IPV6_MAX_BITLEN
))) {
2251 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2253 " %s: Matched against ourself and prefix length is not max bit length",
2258 /* Pick up selected route. */
2259 /* However, do not resolve over default route unless explicitly
2262 if (is_default_prefix(&rn
->p
)
2263 && !rnh_resolve_via_default(zvrf
, p
.family
)) {
2264 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2266 " :%s: Resolved against default route",
2271 dest
= rib_dest_from_rnode(rn
);
2272 if (dest
&& dest
->selected_fib
2273 && !CHECK_FLAG(dest
->selected_fib
->status
,
2274 ROUTE_ENTRY_REMOVED
)
2275 && dest
->selected_fib
->type
!= ZEBRA_ROUTE_TABLE
)
2276 match
= dest
->selected_fib
;
2278 /* If there is no selected route or matched route is EGP, go up
2284 } while (rn
&& rn
->info
== NULL
);
2286 route_lock_node(rn
);
2291 if ((match
->type
== ZEBRA_ROUTE_CONNECT
) ||
2292 (RIB_SYSTEM_ROUTE(match
) && RSYSTEM_ROUTE(type
))) {
2293 match
= zebra_nhg_connected_ifindex(rn
, match
,
2296 newhop
= match
->nhe
->nhg
.nexthop
;
2297 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
2298 nexthop
->type
== NEXTHOP_TYPE_IPV6
)
2299 nexthop
->ifindex
= newhop
->ifindex
;
2300 else if (nexthop
->ifindex
!= newhop
->ifindex
) {
2301 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2303 "%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
2304 __func__
, nexthop
, newhop
);
2306 * NEXTHOP_TYPE_*_IFINDEX but ifindex
2307 * doesn't match what we found.
2312 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2314 "%s: CONNECT match %p (%pNG), newhop %pNHv",
2315 __func__
, match
, match
->nhe
, newhop
);
2318 } else if (CHECK_FLAG(flags
, ZEBRA_FLAG_ALLOW_RECURSION
)) {
2319 struct nexthop_group
*nhg
;
2320 struct nexthop
*resolver
;
2321 struct backup_nh_map_s map
= {};
2325 /* Only useful if installed */
2326 if (!CHECK_FLAG(match
->status
, ROUTE_ENTRY_INSTALLED
)) {
2327 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2329 "%s: match %p (%pNG) not installed",
2330 __func__
, match
, match
->nhe
);
2332 goto done_with_match
;
2335 /* Examine installed nexthops; note that there
2336 * may not be any installed primary nexthops if
2337 * only backups are installed.
2339 nhg
= rib_get_fib_nhg(match
);
2340 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
2341 if (!nexthop_valid_resolve(nexthop
, newhop
))
2344 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2346 "%s: RECURSIVE match %p (%pNG), newhop %pNHv",
2347 __func__
, match
, match
->nhe
,
2350 SET_FLAG(nexthop
->flags
,
2351 NEXTHOP_FLAG_RECURSIVE
);
2352 resolver
= nexthop_set_resolved(afi
, newhop
,
2356 /* If there are backup nexthops, capture
2357 * that info with the resolving nexthop.
2359 if (resolver
&& newhop
->backup_num
> 0) {
2360 resolve_backup_nexthops(newhop
,
2367 /* Examine installed backup nexthops, if any. There
2368 * are only installed backups *if* there is a
2369 * dedicated fib list. The UI can also control use
2370 * of backups for resolution.
2372 nhg
= rib_get_fib_backup_nhg(match
);
2373 if (!use_recursive_backups
||
2374 nhg
== NULL
|| nhg
->nexthop
== NULL
)
2375 goto done_with_match
;
2377 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
2378 if (!nexthop_valid_resolve(nexthop
, newhop
))
2381 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2383 "%s: RECURSIVE match backup %p (%pNG), newhop %pNHv",
2384 __func__
, match
, match
->nhe
,
2387 SET_FLAG(nexthop
->flags
,
2388 NEXTHOP_FLAG_RECURSIVE
);
2389 nexthop_set_resolved(afi
, newhop
, nexthop
,
2395 /* Capture resolving mtu */
2400 } else if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2402 " %s: Recursion failed to find",
2407 if (IS_ZEBRA_DEBUG_RIB_DETAILED
) {
2409 " %s: Route Type %s has not turned on recursion",
2410 __func__
, zebra_route_string(type
));
2411 if (type
== ZEBRA_ROUTE_BGP
2412 && !CHECK_FLAG(flags
, ZEBRA_FLAG_IBGP
))
2414 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
2419 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2420 zlog_debug(" %s: Nexthop did not lookup in table",
2425 /* This function verifies reachability of one given nexthop, which can be
2426 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2427 * in nexthop->flags field. The nexthop->ifindex will be updated
2428 * appropriately as well.
2430 * An existing route map can turn an otherwise active nexthop into inactive,
2431 * but not vice versa.
2433 * The return value is the final value of 'ACTIVE' flag.
2435 static unsigned nexthop_active_check(struct route_node
*rn
,
2436 struct route_entry
*re
,
2437 struct nexthop
*nexthop
,
2438 struct nhg_hash_entry
*nhe
)
2440 route_map_result_t ret
= RMAP_PERMITMATCH
;
2442 const struct prefix
*p
, *src_p
;
2443 struct zebra_vrf
*zvrf
;
2447 srcdest_rnode_prefixes(rn
, &p
, &src_p
);
2449 if (rn
->p
.family
== AF_INET
)
2451 else if (rn
->p
.family
== AF_INET6
)
2456 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2457 zlog_debug("%s: re %p, nexthop %pNHv", __func__
, re
, nexthop
);
2460 * If the kernel has sent us a NEW route, then
2461 * by golly gee whiz it's a good route.
2463 * If its an already INSTALLED route we have already handled, then the
2464 * kernel route's nexthop might have became unreachable
2465 * and we have to handle that.
2467 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
) &&
2468 (re
->type
== ZEBRA_ROUTE_KERNEL
||
2469 re
->type
== ZEBRA_ROUTE_SYSTEM
)) {
2470 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2475 vrf_id
= zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn
)));
2476 switch (nexthop
->type
) {
2477 case NEXTHOP_TYPE_IFINDEX
:
2478 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
, re
->flags
,
2480 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2482 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2484 case NEXTHOP_TYPE_IPV4
:
2485 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2487 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
, re
->flags
,
2489 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2491 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2493 case NEXTHOP_TYPE_IPV6
:
2495 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
, re
->flags
,
2497 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2499 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2501 case NEXTHOP_TYPE_IPV6_IFINDEX
:
2502 /* RFC 5549, v4 prefix with v6 NH */
2503 if (rn
->p
.family
!= AF_INET
)
2506 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
, re
->flags
,
2508 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2510 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2512 case NEXTHOP_TYPE_BLACKHOLE
:
2513 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2521 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
2522 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2523 zlog_debug(" %s: Unable to find active nexthop",
2528 /* Capture recursive nexthop mtu.
2529 * TODO -- the code used to just reset the re's value to zero
2530 * for each nexthop, and then jam any resolving route's mtu value in,
2531 * whether or not that was zero, or lt/gt any existing value? The
2532 * way this is used appears to be as a floor value, so let's try
2533 * using it that way here.
2536 if (re
->nexthop_mtu
== 0 || re
->nexthop_mtu
> mtu
)
2537 re
->nexthop_mtu
= mtu
;
2540 /* XXX: What exactly do those checks do? Do we support
2541 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2543 if (RIB_SYSTEM_ROUTE(re
) || (family
== AFI_IP
&& p
->family
!= AF_INET
)
2544 || (family
== AFI_IP6
&& p
->family
!= AF_INET6
))
2545 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2547 /* The original code didn't determine the family correctly
2548 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2549 * from the rib_table_info in those cases.
2550 * Possibly it may be better to use only the rib_table_info
2554 struct rib_table_info
*info
;
2556 info
= srcdest_rnode_table_info(rn
);
2560 memset(&nexthop
->rmap_src
.ipv6
, 0, sizeof(union g_addr
));
2562 zvrf
= zebra_vrf_lookup_by_id(re
->vrf_id
);
2564 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2565 zlog_debug(" %s: zvrf is NULL", __func__
);
2566 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2569 /* It'll get set if required inside */
2570 ret
= zebra_route_map_check(family
, re
->type
, re
->instance
, p
, nexthop
,
2572 if (ret
== RMAP_DENYMATCH
) {
2573 if (IS_ZEBRA_DEBUG_RIB
) {
2575 "%u:%pRN: Filtering out with NH out %s due to route map",
2577 ifindex2ifname(nexthop
->ifindex
,
2580 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2582 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2585 /* Helper function called after resolution to walk nhg rb trees
2586 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2587 * is active on singleton NHEs.
2589 static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry
*nhe
)
2591 struct nhg_connected
*rb_node_dep
= NULL
;
2594 if (!zebra_nhg_depends_is_empty(nhe
)) {
2595 /* Is at least one depend valid? */
2596 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2597 if (zebra_nhg_set_valid_if_active(rb_node_dep
->nhe
))
2604 /* should be fully resolved singleton at this point */
2605 if (CHECK_FLAG(nhe
->nhg
.nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
2610 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
2616 * Process a list of nexthops, given an nhe, determining
2617 * whether each one is ACTIVE/installable at this time.
2619 static uint32_t nexthop_list_active_update(struct route_node
*rn
,
2620 struct route_entry
*re
,
2621 struct nhg_hash_entry
*nhe
,
2624 union g_addr prev_src
;
2625 unsigned int prev_active
, new_active
;
2626 ifindex_t prev_index
;
2627 uint32_t counter
= 0;
2628 struct nexthop
*nexthop
;
2629 struct nexthop_group
*nhg
= &nhe
->nhg
;
2631 nexthop
= nhg
->nexthop
;
2633 /* Init recursive nh mtu */
2634 re
->nexthop_mtu
= 0;
2636 /* Process nexthops one-by-one */
2637 for ( ; nexthop
; nexthop
= nexthop
->next
) {
2639 /* No protocol daemon provides src and so we're skipping
2642 prev_src
= nexthop
->rmap_src
;
2643 prev_active
= CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2644 prev_index
= nexthop
->ifindex
;
2646 /* Include the containing nhe for primary nexthops: if there's
2647 * recursive resolution, we capture the backup info also.
2650 nexthop_active_check(rn
, re
, nexthop
,
2651 (is_backup
? NULL
: nhe
));
2654 * We need to respect the multipath_num here
2655 * as that what we should be able to install from
2656 * a multipath perspective should not be a data plane
2659 if (new_active
&& counter
>= zrouter
.multipath_num
) {
2662 /* Set it and its resolved nexthop as inactive. */
2663 for (nh
= nexthop
; nh
; nh
= nh
->resolved
)
2664 UNSET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
2672 /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
2673 if (prev_active
!= new_active
|| prev_index
!= nexthop
->ifindex
2674 || ((nexthop
->type
>= NEXTHOP_TYPE_IFINDEX
2675 && nexthop
->type
< NEXTHOP_TYPE_IPV6
)
2676 && prev_src
.ipv4
.s_addr
2677 != nexthop
->rmap_src
.ipv4
.s_addr
)
2678 || ((nexthop
->type
>= NEXTHOP_TYPE_IPV6
2679 && nexthop
->type
< NEXTHOP_TYPE_BLACKHOLE
)
2680 && !(IPV6_ADDR_SAME(&prev_src
.ipv6
,
2681 &nexthop
->rmap_src
.ipv6
)))
2682 || CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
2683 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2690 static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group
*nhg
)
2693 uint32_t curr_active
= 0;
2695 /* Assume all active for now */
2697 for (nh
= nhg
->nexthop
; nh
; nh
= nh
->next
) {
2698 SET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
2706 * Iterate over all nexthops of the given RIB entry and refresh their
2707 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2708 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2710 * Return value is the new number of active nexthops.
2712 int nexthop_active_update(struct route_node
*rn
, struct route_entry
*re
)
2714 struct nhg_hash_entry
*curr_nhe
;
2715 uint32_t curr_active
= 0, backup_active
= 0;
2717 if (PROTO_OWNED(re
->nhe
))
2718 return proto_nhg_nexthop_active_update(&re
->nhe
->nhg
);
2720 afi_t rt_afi
= family2afi(rn
->p
.family
);
2722 UNSET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2724 /* Make a local copy of the existing nhe, so we don't work on/modify
2727 curr_nhe
= zebra_nhe_copy(re
->nhe
, re
->nhe
->id
);
2729 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2730 zlog_debug("%s: re %p nhe %p (%pNG), curr_nhe %p", __func__
, re
,
2731 re
->nhe
, re
->nhe
, curr_nhe
);
2733 /* Clear the existing id, if any: this will avoid any confusion
2734 * if the id exists, and will also force the creation
2735 * of a new nhe reflecting the changes we may make in this local copy.
2739 /* Process nexthops */
2740 curr_active
= nexthop_list_active_update(rn
, re
, curr_nhe
, false);
2742 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2743 zlog_debug("%s: re %p curr_active %u", __func__
, re
,
2746 /* If there are no backup nexthops, we are done */
2747 if (zebra_nhg_get_backup_nhg(curr_nhe
) == NULL
)
2750 backup_active
= nexthop_list_active_update(
2751 rn
, re
, curr_nhe
->backup_info
->nhe
, true /*is_backup*/);
2753 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2754 zlog_debug("%s: re %p backup_active %u", __func__
, re
,
2760 * Ref or create an nhe that matches the current state of the
2763 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
)) {
2764 struct nhg_hash_entry
*new_nhe
= NULL
;
2766 new_nhe
= zebra_nhg_rib_find_nhe(curr_nhe
, rt_afi
);
2768 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2770 "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",
2771 __func__
, re
, re
->nhe
, re
->nhe
, new_nhe
,
2774 route_entry_update_nhe(re
, new_nhe
);
2778 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2779 * flag where appropriate.
2782 zebra_nhg_set_valid_if_active(re
->nhe
);
2785 * Do not need the old / copied nhe anymore since it
2786 * was either copied over into a new nhe or not
2789 zebra_nhg_free(curr_nhe
);
2793 /* Recursively construct a grp array of fully resolved IDs.
2795 * This function allows us to account for groups within groups,
2796 * by converting them into a flat array of IDs.
2798 * nh_grp is modified at every level of recursion to append
2799 * to it the next unique, fully resolved ID from the entire tree.
2803 * I'm pretty sure we only allow ONE level of group within group currently.
2804 * But making this recursive just in case that ever changes.
2806 static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp
*grp
,
2808 struct nhg_hash_entry
*nhe
,
2811 struct nhg_connected
*rb_node_dep
= NULL
;
2812 struct nhg_hash_entry
*depend
= NULL
;
2813 uint8_t i
= curr_index
;
2815 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2816 bool duplicate
= false;
2821 depend
= rb_node_dep
->nhe
;
2824 * If its recursive, use its resolved nhe in the group
2826 if (CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_RECURSIVE
)) {
2827 depend
= zebra_nhg_resolve(depend
);
2830 EC_ZEBRA_NHG_FIB_UPDATE
,
2831 "Failed to recursively resolve Nexthop Hash Entry in the group id=%pNG",
2837 if (!zebra_nhg_depends_is_empty(depend
)) {
2838 /* This is a group within a group */
2839 i
= zebra_nhg_nhe2grp_internal(grp
, i
, depend
, max_num
);
2841 if (!CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_VALID
)) {
2842 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2843 || IS_ZEBRA_DEBUG_NHG
)
2845 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2846 __func__
, depend
->id
);
2850 /* If the nexthop not installed/queued for install don't
2851 * put in the ID array.
2853 if (!(CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_INSTALLED
)
2854 || CHECK_FLAG(depend
->flags
,
2855 NEXTHOP_GROUP_QUEUED
))) {
2856 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2857 || IS_ZEBRA_DEBUG_NHG
)
2859 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2860 __func__
, depend
->id
);
2864 /* Check for duplicate IDs, ignore if found. */
2865 for (int j
= 0; j
< i
; j
++) {
2866 if (depend
->id
== grp
[j
].id
) {
2873 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2874 || IS_ZEBRA_DEBUG_NHG
)
2876 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2877 __func__
, depend
->id
);
2881 grp
[i
].id
= depend
->id
;
2882 grp
[i
].weight
= depend
->nhg
.nexthop
->weight
;
2887 if (nhe
->backup_info
== NULL
|| nhe
->backup_info
->nhe
== NULL
)
2890 /* TODO -- For now, we are not trying to use or install any
2891 * backup info in this nexthop-id path: we aren't prepared
2892 * to use the backups here yet. We're just debugging what we find.
2894 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2895 zlog_debug("%s: skipping backup nhe", __func__
);
2901 /* Convert a nhe into a group array */
2902 uint8_t zebra_nhg_nhe2grp(struct nh_grp
*grp
, struct nhg_hash_entry
*nhe
,
2905 /* Call into the recursive function */
2906 return zebra_nhg_nhe2grp_internal(grp
, 0, nhe
, max_num
);
2909 void zebra_nhg_install_kernel(struct nhg_hash_entry
*nhe
)
2911 struct nhg_connected
*rb_node_dep
= NULL
;
2913 /* Resolve it first */
2914 nhe
= zebra_nhg_resolve(nhe
);
2916 /* Make sure all depends are installed/queued */
2917 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2918 zebra_nhg_install_kernel(rb_node_dep
->nhe
);
2921 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
)
2922 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)
2923 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
)) {
2924 /* Change its type to us since we are installing it */
2925 if (!ZEBRA_NHG_CREATED(nhe
))
2926 nhe
->type
= ZEBRA_ROUTE_NHG
;
2928 int ret
= dplane_nexthop_add(nhe
);
2931 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2932 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2934 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2936 EC_ZEBRA_DP_INSTALL_FAIL
,
2937 "Failed to install Nexthop ID (%pNG) into the kernel",
2940 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2941 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2942 zebra_nhg_handle_install(nhe
);
2948 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry
*nhe
)
2950 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)) {
2951 int ret
= dplane_nexthop_delete(nhe
);
2954 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2955 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2957 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2959 EC_ZEBRA_DP_DELETE_FAIL
,
2960 "Failed to uninstall Nexthop ID (%pNG) from the kernel",
2963 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2964 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2969 zebra_nhg_handle_uninstall(nhe
);
2972 void zebra_nhg_dplane_result(struct zebra_dplane_ctx
*ctx
)
2974 enum dplane_op_e op
;
2975 enum zebra_dplane_result status
;
2977 struct nhg_hash_entry
*nhe
= NULL
;
2979 op
= dplane_ctx_get_op(ctx
);
2980 status
= dplane_ctx_get_status(ctx
);
2982 id
= dplane_ctx_get_nhe_id(ctx
);
2984 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
|| IS_ZEBRA_DEBUG_NHG_DETAIL
)
2986 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
2987 ctx
, dplane_op2str(op
), id
, dplane_res2str(status
));
2990 case DPLANE_OP_NH_DELETE
:
2991 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
2993 EC_ZEBRA_DP_DELETE_FAIL
,
2994 "Failed to uninstall Nexthop ID (%u) from the kernel",
2997 /* We already free'd the data, nothing to do */
2999 case DPLANE_OP_NH_INSTALL
:
3000 case DPLANE_OP_NH_UPDATE
:
3001 nhe
= zebra_nhg_lookup_id(id
);
3004 if (IS_ZEBRA_DEBUG_NHG
)
3006 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
3007 dplane_op2str(op
), id
);
3012 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
3013 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
3014 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
3015 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
3016 zebra_nhg_handle_install(nhe
);
3018 /* If daemon nhg, send it an update */
3019 if (PROTO_OWNED(nhe
))
3020 zsend_nhg_notify(nhe
->type
, nhe
->zapi_instance
,
3021 nhe
->zapi_session
, nhe
->id
,
3022 ZAPI_NHG_INSTALLED
);
3024 /* If daemon nhg, send it an update */
3025 if (PROTO_OWNED(nhe
))
3026 zsend_nhg_notify(nhe
->type
, nhe
->zapi_instance
,
3027 nhe
->zapi_session
, nhe
->id
,
3028 ZAPI_NHG_FAIL_INSTALL
);
3030 if (!(zebra_nhg_proto_nexthops_only() &&
3033 EC_ZEBRA_DP_INSTALL_FAIL
,
3034 "Failed to install Nexthop (%pNG) into the kernel",
3039 case DPLANE_OP_ROUTE_INSTALL
:
3040 case DPLANE_OP_ROUTE_UPDATE
:
3041 case DPLANE_OP_ROUTE_DELETE
:
3042 case DPLANE_OP_ROUTE_NOTIFY
:
3043 case DPLANE_OP_LSP_INSTALL
:
3044 case DPLANE_OP_LSP_UPDATE
:
3045 case DPLANE_OP_LSP_DELETE
:
3046 case DPLANE_OP_LSP_NOTIFY
:
3047 case DPLANE_OP_PW_INSTALL
:
3048 case DPLANE_OP_PW_UNINSTALL
:
3049 case DPLANE_OP_SYS_ROUTE_ADD
:
3050 case DPLANE_OP_SYS_ROUTE_DELETE
:
3051 case DPLANE_OP_ADDR_INSTALL
:
3052 case DPLANE_OP_ADDR_UNINSTALL
:
3053 case DPLANE_OP_MAC_INSTALL
:
3054 case DPLANE_OP_MAC_DELETE
:
3055 case DPLANE_OP_NEIGH_INSTALL
:
3056 case DPLANE_OP_NEIGH_UPDATE
:
3057 case DPLANE_OP_NEIGH_DELETE
:
3058 case DPLANE_OP_NEIGH_IP_INSTALL
:
3059 case DPLANE_OP_NEIGH_IP_DELETE
:
3060 case DPLANE_OP_VTEP_ADD
:
3061 case DPLANE_OP_VTEP_DELETE
:
3062 case DPLANE_OP_RULE_ADD
:
3063 case DPLANE_OP_RULE_DELETE
:
3064 case DPLANE_OP_RULE_UPDATE
:
3065 case DPLANE_OP_NEIGH_DISCOVER
:
3066 case DPLANE_OP_BR_PORT_UPDATE
:
3067 case DPLANE_OP_NONE
:
3068 case DPLANE_OP_IPTABLE_ADD
:
3069 case DPLANE_OP_IPTABLE_DELETE
:
3070 case DPLANE_OP_IPSET_ADD
:
3071 case DPLANE_OP_IPSET_DELETE
:
3072 case DPLANE_OP_IPSET_ENTRY_ADD
:
3073 case DPLANE_OP_IPSET_ENTRY_DELETE
:
3074 case DPLANE_OP_NEIGH_TABLE_UPDATE
:
3075 case DPLANE_OP_GRE_SET
:
3076 case DPLANE_OP_INTF_ADDR_ADD
:
3077 case DPLANE_OP_INTF_ADDR_DEL
:
3078 case DPLANE_OP_INTF_NETCONFIG
:
3079 case DPLANE_OP_INTF_INSTALL
:
3080 case DPLANE_OP_INTF_UPDATE
:
3081 case DPLANE_OP_INTF_DELETE
:
3085 dplane_ctx_fini(&ctx
);
3088 static int zebra_nhg_sweep_entry(struct hash_bucket
*bucket
, void *arg
)
3090 struct nhg_hash_entry
*nhe
= NULL
;
3092 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
3095 * same logic as with routes.
3097 * If older than startup time, we know we read them in from the
3098 * kernel and have not gotten and update for them since startup
3099 * from an upper level proto.
3101 if (zrouter
.startup_time
< nhe
->uptime
)
3102 return HASHWALK_CONTINUE
;
3105 * If it's proto-owned and not being used by a route, remove it since
3106 * we haven't gotten an update about it from the proto since startup.
3107 * This means that either the config for it was removed or the daemon
3108 * didn't get started. This handles graceful restart & retain scenario.
3110 if (PROTO_OWNED(nhe
) && nhe
->refcnt
== 1) {
3111 zebra_nhg_decrement_ref(nhe
);
3112 return HASHWALK_ABORT
;
3116 * If its being ref'd by routes, just let it be uninstalled via a route
3119 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0) {
3120 zebra_nhg_uninstall_kernel(nhe
);
3121 return HASHWALK_ABORT
;
3124 return HASHWALK_CONTINUE
;
3127 void zebra_nhg_sweep_table(struct hash
*hash
)
3132 * Yes this is extremely odd. Effectively nhg's have
3133 * other nexthop groups that depend on them and when you
3134 * remove them, you can have other entries blown up.
3135 * our hash code does not work with deleting multiple
3136 * entries at a time and will possibly cause crashes
3137 * So what to do? Whenever zebra_nhg_sweep_entry
3138 * deletes an entry it will return HASHWALK_ABORT,
3139 * cause that deletion might have triggered more.
3140 * then we can just keep sweeping this table
3141 * until nothing more is found to do.
3144 count
= hashcount(hash
);
3145 hash_walk(hash
, zebra_nhg_sweep_entry
, NULL
);
3146 } while (count
!= hashcount(hash
));
3149 static void zebra_nhg_mark_keep_entry(struct hash_bucket
*bucket
, void *arg
)
3151 struct nhg_hash_entry
*nhe
= bucket
->data
;
3153 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
3157 * When we are shutting down and we have retain mode enabled
3158 * in zebra the process is to mark each vrf that it's
3159 * routes should not be deleted. The problem with that
3160 * is that shutdown actually free's up memory which
3161 * causes the nexthop group's ref counts to go to zero
3162 * we need a way to subtly tell the system to not remove
3163 * the nexthop groups from the kernel at the same time.
3164 * The easiest just looks like that we should not mark
3165 * the nhg's as installed any more and when the ref count
3166 * goes to zero we'll attempt to delete and do nothing
3168 void zebra_nhg_mark_keep(void)
3170 hash_iterate(zrouter
.nhgs_id
, zebra_nhg_mark_keep_entry
, NULL
);
3173 /* Global control to disable use of kernel nexthops, if available. We can't
3174 * force the kernel to support nexthop ids, of course, but we can disable
3175 * zebra's use of them, for testing e.g. By default, if the kernel supports
3176 * nexthop ids, zebra uses them.
3178 void zebra_nhg_enable_kernel_nexthops(bool set
)
3180 g_nexthops_enabled
= set
;
3183 bool zebra_nhg_kernel_nexthops_enabled(void)
3185 return g_nexthops_enabled
;
3188 /* Global control for use of activated backups for recursive resolution. */
3189 void zebra_nhg_set_recursive_use_backups(bool set
)
3191 use_recursive_backups
= set
;
3194 bool zebra_nhg_recursive_use_backups(void)
3196 return use_recursive_backups
;
3200 * Global control to only use kernel nexthops for protocol created NHGs.
3201 * There are some use cases where you may not want zebra to implicitly
3202 * create kernel nexthops for all routes and only create them for NHGs
3203 * passed down by upper level protos.
3207 void zebra_nhg_set_proto_nexthops_only(bool set
)
3209 proto_nexthops_only
= set
;
3212 bool zebra_nhg_proto_nexthops_only(void)
3214 return proto_nexthops_only
;
3217 /* Add NHE from upper level proto */
3218 struct nhg_hash_entry
*zebra_nhg_proto_add(uint32_t id
, int type
,
3219 uint16_t instance
, uint32_t session
,
3220 struct nexthop_group
*nhg
, afi_t afi
)
3222 struct nhg_hash_entry lookup
;
3223 struct nhg_hash_entry
*new, *old
;
3224 struct nhg_connected
*rb_node_dep
= NULL
;
3225 struct nexthop
*newhop
;
3226 bool replace
= false;
3228 if (!nhg
->nexthop
) {
3229 if (IS_ZEBRA_DEBUG_NHG
)
3230 zlog_debug("%s: id %u, no nexthops passed to add",
3236 /* Set nexthop list as active, since they wont go through rib
3239 * Assuming valid/onlink for now.
3241 * Once resolution is figured out, we won't need this!
3243 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
3244 if (CHECK_FLAG(newhop
->flags
, NEXTHOP_FLAG_HAS_BACKUP
)) {
3245 if (IS_ZEBRA_DEBUG_NHG
)
3247 "%s: id %u, backup nexthops not supported",
3252 if (newhop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
3253 if (IS_ZEBRA_DEBUG_NHG
)
3255 "%s: id %u, blackhole nexthop not supported",
3260 if (newhop
->type
== NEXTHOP_TYPE_IFINDEX
) {
3261 if (IS_ZEBRA_DEBUG_NHG
)
3263 "%s: id %u, nexthop without gateway not supported",
3268 if (!newhop
->ifindex
) {
3269 if (IS_ZEBRA_DEBUG_NHG
)
3271 "%s: id %u, nexthop without ifindex is not supported",
3275 SET_FLAG(newhop
->flags
, NEXTHOP_FLAG_ACTIVE
);
3278 zebra_nhe_init(&lookup
, afi
, nhg
->nexthop
);
3279 lookup
.nhg
.nexthop
= nhg
->nexthop
;
3283 old
= zebra_nhg_lookup_id(id
);
3287 * This is a replace, just release NHE from ID for now, The
3288 * depends/dependents may still be used in the replacement so
3289 * we don't touch them other than to remove their refs to their
3293 hash_release(zrouter
.nhgs_id
, old
);
3295 /* Free all the things */
3296 zebra_nhg_release_all_deps(old
);
3299 new = zebra_nhg_rib_find_nhe(&lookup
, afi
);
3301 zebra_nhg_increment_ref(new);
3303 /* Capture zapi client info */
3304 new->zapi_instance
= instance
;
3305 new->zapi_session
= session
;
3307 zebra_nhg_set_valid_if_active(new);
3309 zebra_nhg_install_kernel(new);
3313 * Check to handle recving DEL while routes still in use then
3316 * In this case we would have decremented the refcnt already
3317 * but set the FLAG here. Go ahead and increment once to fix
3318 * the misordering we have been sent.
3320 if (CHECK_FLAG(old
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
))
3321 zebra_nhg_increment_ref(old
);
3323 rib_handle_nhg_replace(old
, new);
3325 /* We have to decrement its singletons
3326 * because some might not exist in NEW.
3328 if (!zebra_nhg_depends_is_empty(old
)) {
3329 frr_each (nhg_connected_tree
, &old
->nhg_depends
,
3331 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
3334 /* Dont call the dec API, we dont want to uninstall the ID */
3336 THREAD_OFF(old
->timer
);
3337 zebra_nhg_free(old
);
3341 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3342 zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__
,
3343 (replace
? "replaced" : "added"), new, new->id
,
3344 new->vrf_id
, zebra_route_string(new->type
));
3349 /* Delete NHE from upper level proto, caller must decrement ref */
3350 struct nhg_hash_entry
*zebra_nhg_proto_del(uint32_t id
, int type
)
3352 struct nhg_hash_entry
*nhe
;
3354 nhe
= zebra_nhg_lookup_id(id
);
3357 if (IS_ZEBRA_DEBUG_NHG
)
3358 zlog_debug("%s: id %u, lookup failed", __func__
, id
);
3363 if (type
!= nhe
->type
) {
3364 if (IS_ZEBRA_DEBUG_NHG
)
3366 "%s: id %u, type %s mismatch, sent by %s, ignoring",
3367 __func__
, id
, zebra_route_string(nhe
->type
),
3368 zebra_route_string(type
));
3372 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
)) {
3373 if (IS_ZEBRA_DEBUG_NHG
)
3374 zlog_debug("%s: id %u, already released", __func__
, id
);
3379 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
);
3381 if (nhe
->refcnt
> 1) {
3382 if (IS_ZEBRA_DEBUG_NHG
)
3384 "%s: %pNG, still being used by routes refcnt %u",
3385 __func__
, nhe
, nhe
->refcnt
);
3389 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3390 zlog_debug("%s: deleted nhe %p (%pNG), vrf %d, type %s",
3391 __func__
, nhe
, nhe
, nhe
->vrf_id
,
3392 zebra_route_string(nhe
->type
));
3397 struct nhg_score_proto_iter
{
3402 static void zebra_nhg_score_proto_entry(struct hash_bucket
*bucket
, void *arg
)
3404 struct nhg_hash_entry
*nhe
;
3405 struct nhg_score_proto_iter
*iter
;
3407 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
3410 /* Needs to match type and outside zebra ID space */
3411 if (nhe
->type
== iter
->type
&& PROTO_OWNED(nhe
)) {
3412 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3414 "%s: found nhe %p (%pNG), vrf %d, type %s after client disconnect",
3415 __func__
, nhe
, nhe
, nhe
->vrf_id
,
3416 zebra_route_string(nhe
->type
));
3418 /* Add to removal list */
3419 listnode_add(iter
->found
, nhe
);
3423 /* Remove specific by proto NHGs */
3424 unsigned long zebra_nhg_score_proto(int type
)
3426 struct nhg_hash_entry
*nhe
;
3427 struct nhg_score_proto_iter iter
= {};
3428 struct listnode
*ln
;
3429 unsigned long count
;
3432 iter
.found
= list_new();
3434 /* Find matching entries to remove */
3435 hash_iterate(zrouter
.nhgs_id
, zebra_nhg_score_proto_entry
, &iter
);
3437 /* Now remove them */
3438 for (ALL_LIST_ELEMENTS_RO(iter
.found
, ln
, nhe
)) {
3440 * This should be the last ref if we remove client routes too,
3441 * and thus should remove and free them.
3443 zebra_nhg_decrement_ref(nhe
);
3446 count
= iter
.found
->count
;
3447 list_delete(&iter
.found
);
3452 printfrr_ext_autoreg_p("NG", printfrr_nhghe
);
3453 static ssize_t
printfrr_nhghe(struct fbuf
*buf
, struct printfrr_eargs
*ea
,
3456 const struct nhg_hash_entry
*nhe
= ptr
;
3457 const struct nhg_connected
*dep
;
3461 return bputs(buf
, "[NULL]");
3463 ret
+= bprintfrr(buf
, "%u[", nhe
->id
);
3465 ret
+= printfrr_nhs(buf
, nhe
->nhg
.nexthop
);
3467 int count
= zebra_nhg_depends_count(nhe
);
3469 frr_each (nhg_connected_tree_const
, &nhe
->nhg_depends
, dep
) {
3470 ret
+= bprintfrr(buf
, "%u", dep
->nhe
->id
);
3472 ret
+= bputs(buf
, "/");
3477 ret
+= bputs(buf
, "]");