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"
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"
41 #include "zebra_errors.h"
42 #include "zebra_dplane.h"
43 #include "zebra/interface.h"
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");
49 /* id counter to keep in sync with kernel */
53 static bool g_nexthops_enabled
= true;
55 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
,
57 static void depends_add(struct nhg_connected_tree_head
*head
,
58 struct nhg_hash_entry
*depend
);
59 static struct nhg_hash_entry
*
60 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
62 static struct nhg_hash_entry
*
63 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
);
64 static void depends_decrement_free(struct nhg_connected_tree_head
*head
);
66 static struct nhg_backup_info
*
67 nhg_backup_copy(const struct nhg_backup_info
*orig
);
70 static void nhg_connected_free(struct nhg_connected
*dep
)
72 XFREE(MTYPE_NHG_CONNECTED
, dep
);
75 static struct nhg_connected
*nhg_connected_new(struct nhg_hash_entry
*nhe
)
77 struct nhg_connected
*new = NULL
;
79 new = XCALLOC(MTYPE_NHG_CONNECTED
, sizeof(struct nhg_connected
));
85 void nhg_connected_tree_free(struct nhg_connected_tree_head
*head
)
87 struct nhg_connected
*rb_node_dep
= NULL
;
89 if (!nhg_connected_tree_is_empty(head
)) {
90 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
91 nhg_connected_tree_del(head
, rb_node_dep
);
92 nhg_connected_free(rb_node_dep
);
97 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head
*head
)
99 return nhg_connected_tree_count(head
) ? false : true;
102 struct nhg_connected
*
103 nhg_connected_tree_root(struct nhg_connected_tree_head
*head
)
105 return nhg_connected_tree_first(head
);
108 struct nhg_hash_entry
*
109 nhg_connected_tree_del_nhe(struct nhg_connected_tree_head
*head
,
110 struct nhg_hash_entry
*depend
)
112 struct nhg_connected lookup
= {};
113 struct nhg_connected
*remove
= NULL
;
114 struct nhg_hash_entry
*removed_nhe
;
118 /* Lookup to find the element, then remove it */
119 remove
= nhg_connected_tree_find(head
, &lookup
);
121 /* Re-returning here just in case this API changes..
122 * the _del list api's are a bit undefined at the moment.
124 * So hopefully returning here will make it fail if the api
125 * changes to something different than currently expected.
127 remove
= nhg_connected_tree_del(head
, remove
);
129 /* If the entry was sucessfully removed, free the 'connected` struct */
131 removed_nhe
= remove
->nhe
;
132 nhg_connected_free(remove
);
139 /* Assuming UNIQUE RB tree. If this changes, assumptions here about
140 * insertion need to change.
142 struct nhg_hash_entry
*
143 nhg_connected_tree_add_nhe(struct nhg_connected_tree_head
*head
,
144 struct nhg_hash_entry
*depend
)
146 struct nhg_connected
*new = NULL
;
148 new = nhg_connected_new(depend
);
150 /* On success, NULL will be returned from the
153 if (new && (nhg_connected_tree_add(head
, new) == NULL
))
156 /* If it wasn't successful, it must be a duplicate. We enforce the
157 * unique property for the `nhg_connected` tree.
159 nhg_connected_free(new);
165 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head
*head
)
167 struct nhg_connected
*rb_node_dep
= NULL
;
169 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
170 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
175 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head
*head
)
177 struct nhg_connected
*rb_node_dep
= NULL
;
179 frr_each(nhg_connected_tree
, head
, rb_node_dep
) {
180 zebra_nhg_increment_ref(rb_node_dep
->nhe
);
184 struct nhg_hash_entry
*zebra_nhg_resolve(struct nhg_hash_entry
*nhe
)
186 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
)
187 && !zebra_nhg_depends_is_empty(nhe
)) {
188 nhe
= nhg_connected_tree_root(&nhe
->nhg_depends
)->nhe
;
189 return zebra_nhg_resolve(nhe
);
195 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry
*nhe
)
197 return nhg_connected_tree_count(&nhe
->nhg_depends
);
200 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry
*nhe
)
202 return nhg_connected_tree_is_empty(&nhe
->nhg_depends
);
205 static void zebra_nhg_depends_del(struct nhg_hash_entry
*from
,
206 struct nhg_hash_entry
*depend
)
208 nhg_connected_tree_del_nhe(&from
->nhg_depends
, depend
);
211 static void zebra_nhg_depends_init(struct nhg_hash_entry
*nhe
)
213 nhg_connected_tree_init(&nhe
->nhg_depends
);
216 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry
*nhe
)
218 return nhg_connected_tree_count(&nhe
->nhg_dependents
);
222 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry
*nhe
)
224 return nhg_connected_tree_is_empty(&nhe
->nhg_dependents
);
227 static void zebra_nhg_dependents_del(struct nhg_hash_entry
*from
,
228 struct nhg_hash_entry
*dependent
)
230 nhg_connected_tree_del_nhe(&from
->nhg_dependents
, dependent
);
233 static void zebra_nhg_dependents_add(struct nhg_hash_entry
*to
,
234 struct nhg_hash_entry
*dependent
)
236 nhg_connected_tree_add_nhe(&to
->nhg_dependents
, dependent
);
239 static void zebra_nhg_dependents_init(struct nhg_hash_entry
*nhe
)
241 nhg_connected_tree_init(&nhe
->nhg_dependents
);
244 /* Release this nhe from anything depending on it */
245 static void zebra_nhg_dependents_release(struct nhg_hash_entry
*nhe
)
247 struct nhg_connected
*rb_node_dep
= NULL
;
249 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
) {
250 zebra_nhg_depends_del(rb_node_dep
->nhe
, nhe
);
251 /* recheck validity of the dependent */
252 zebra_nhg_check_valid(rb_node_dep
->nhe
);
256 /* Release this nhe from anything that it depends on */
257 static void zebra_nhg_depends_release(struct nhg_hash_entry
*nhe
)
259 if (!zebra_nhg_depends_is_empty(nhe
)) {
260 struct nhg_connected
*rb_node_dep
= NULL
;
262 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_depends
,
264 zebra_nhg_dependents_del(rb_node_dep
->nhe
, nhe
);
270 struct nhg_hash_entry
*zebra_nhg_lookup_id(uint32_t id
)
272 struct nhg_hash_entry lookup
= {};
275 return hash_lookup(zrouter
.nhgs_id
, &lookup
);
278 static int zebra_nhg_insert_id(struct nhg_hash_entry
*nhe
)
280 if (hash_lookup(zrouter
.nhgs_id
, nhe
)) {
282 EC_ZEBRA_NHG_TABLE_INSERT_FAILED
,
283 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
288 hash_get(zrouter
.nhgs_id
, nhe
, hash_alloc_intern
);
293 static void zebra_nhg_set_if(struct nhg_hash_entry
*nhe
, struct interface
*ifp
)
296 if_nhg_dependents_add(ifp
, nhe
);
300 zebra_nhg_connect_depends(struct nhg_hash_entry
*nhe
,
301 struct nhg_connected_tree_head
*nhg_depends
)
303 struct nhg_connected
*rb_node_dep
= NULL
;
305 /* This has been allocated higher above in the stack. Could probably
306 * re-allocate and free the old stuff but just using the same memory
307 * for now. Otherwise, their might be a time trade-off for repeated
308 * alloc/frees as startup.
310 nhe
->nhg_depends
= *nhg_depends
;
312 /* Attach backpointer to anything that it depends on */
313 zebra_nhg_dependents_init(nhe
);
314 if (!zebra_nhg_depends_is_empty(nhe
)) {
315 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
316 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
317 zlog_debug("%s: nhe %p (%u), dep %p (%u)",
318 __func__
, nhe
, nhe
->id
,
320 rb_node_dep
->nhe
->id
);
322 zebra_nhg_dependents_add(rb_node_dep
->nhe
, nhe
);
327 /* Init an nhe, for use in a hash lookup for example */
328 void zebra_nhe_init(struct nhg_hash_entry
*nhe
, afi_t afi
,
329 const struct nexthop
*nh
)
331 memset(nhe
, 0, sizeof(struct nhg_hash_entry
));
332 nhe
->vrf_id
= VRF_DEFAULT
;
333 nhe
->type
= ZEBRA_ROUTE_NHG
;
334 nhe
->afi
= AFI_UNSPEC
;
336 /* There are some special rules that apply to groups representing
339 if (nh
&& (nh
->next
== NULL
)) {
341 case (NEXTHOP_TYPE_IFINDEX
):
342 case (NEXTHOP_TYPE_BLACKHOLE
):
344 * This switch case handles setting the afi different
345 * for ipv4/v6 routes. Ifindex/blackhole nexthop
346 * objects cannot be ambiguous, they must be Address
347 * Family specific. If we get here, we will either use
348 * the AF of the route, or the one we got passed from
349 * here from the kernel.
353 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
354 case (NEXTHOP_TYPE_IPV4
):
357 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
358 case (NEXTHOP_TYPE_IPV6
):
365 struct nhg_hash_entry
*zebra_nhg_alloc(void)
367 struct nhg_hash_entry
*nhe
;
369 nhe
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_hash_entry
));
375 * Allocate new nhe and make shallow copy of 'orig'; no
376 * recursive info is copied.
378 struct nhg_hash_entry
*zebra_nhe_copy(const struct nhg_hash_entry
*orig
,
381 struct nhg_hash_entry
*nhe
;
383 nhe
= zebra_nhg_alloc();
387 nexthop_group_copy(&(nhe
->nhg
), &(orig
->nhg
));
389 nhe
->vrf_id
= orig
->vrf_id
;
390 nhe
->afi
= orig
->afi
;
391 nhe
->type
= orig
->type
? orig
->type
: ZEBRA_ROUTE_NHG
;
393 nhe
->dplane_ref
= zebra_router_get_next_sequence();
395 /* Copy backup info also, if present */
396 if (orig
->backup_info
)
397 nhe
->backup_info
= nhg_backup_copy(orig
->backup_info
);
402 /* Allocation via hash handler */
403 static void *zebra_nhg_hash_alloc(void *arg
)
405 struct nhg_hash_entry
*nhe
= NULL
;
406 struct nhg_hash_entry
*copy
= arg
;
408 nhe
= zebra_nhe_copy(copy
, copy
->id
);
410 /* Mark duplicate nexthops in a group at creation time. */
411 nexthop_group_mark_duplicates(&(nhe
->nhg
));
413 zebra_nhg_connect_depends(nhe
, &(copy
->nhg_depends
));
415 /* Add the ifp now if it's not a group or recursive and has ifindex */
416 if (zebra_nhg_depends_is_empty(nhe
) && nhe
->nhg
.nexthop
417 && nhe
->nhg
.nexthop
->ifindex
) {
418 struct interface
*ifp
= NULL
;
420 ifp
= if_lookup_by_index(nhe
->nhg
.nexthop
->ifindex
,
421 nhe
->nhg
.nexthop
->vrf_id
);
423 zebra_nhg_set_if(nhe
, ifp
);
426 EC_ZEBRA_IF_LOOKUP_FAILED
,
427 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
428 nhe
->nhg
.nexthop
->ifindex
,
429 nhe
->nhg
.nexthop
->vrf_id
, nhe
->id
);
432 zebra_nhg_insert_id(nhe
);
437 uint32_t zebra_nhg_hash_key(const void *arg
)
439 const struct nhg_hash_entry
*nhe
= arg
;
440 uint32_t val
, key
= 0x5a351234;
442 val
= nexthop_group_hash(&(nhe
->nhg
));
443 if (nhe
->backup_info
) {
444 val
= jhash_2words(val
,
446 &(nhe
->backup_info
->nhe
->nhg
)),
450 key
= jhash_3words(nhe
->vrf_id
, nhe
->afi
, val
, key
);
455 uint32_t zebra_nhg_id_key(const void *arg
)
457 const struct nhg_hash_entry
*nhe
= arg
;
462 /* Helper with common nhg/nhe nexthop comparison logic */
463 static bool nhg_compare_nexthops(const struct nexthop
*nh1
,
464 const struct nexthop
*nh2
)
466 assert(nh1
!= NULL
&& nh2
!= NULL
);
469 * We have to check the active flag of each individual one,
470 * not just the overall active_num. This solves the special case
471 * issue of a route with a nexthop group with one nexthop
472 * resolving to itself and thus marking it inactive. If we
473 * have two different routes each wanting to mark a different
474 * nexthop inactive, they need to hash to two different groups.
476 * If we just hashed on num_active, they would hash the same
477 * which is incorrect.
481 * -> 1.1.1.1 dummy1 (inactive)
486 * -> 1.1.2.1 dummy2 (inactive)
488 * Without checking each individual one, they would hash to
489 * the same group and both have 1.1.1.1 dummy1 marked inactive.
492 if (CHECK_FLAG(nh1
->flags
, NEXTHOP_FLAG_ACTIVE
)
493 != CHECK_FLAG(nh2
->flags
, NEXTHOP_FLAG_ACTIVE
))
496 if (!nexthop_same(nh1
, nh2
))
502 bool zebra_nhg_hash_equal(const void *arg1
, const void *arg2
)
504 const struct nhg_hash_entry
*nhe1
= arg1
;
505 const struct nhg_hash_entry
*nhe2
= arg2
;
506 struct nexthop
*nexthop1
;
507 struct nexthop
*nexthop2
;
509 /* No matter what if they equal IDs, assume equal */
510 if (nhe1
->id
&& nhe2
->id
&& (nhe1
->id
== nhe2
->id
))
513 if (nhe1
->vrf_id
!= nhe2
->vrf_id
)
516 if (nhe1
->afi
!= nhe2
->afi
)
519 /* Nexthops should be in-order, so we simply compare them in-place */
520 for (nexthop1
= nhe1
->nhg
.nexthop
, nexthop2
= nhe2
->nhg
.nexthop
;
521 nexthop1
&& nexthop2
;
522 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
524 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
528 /* Check for unequal list lengths */
529 if (nexthop1
|| nexthop2
)
532 /* If there's no backup info, comparison is done. */
533 if ((nhe1
->backup_info
== NULL
) && (nhe2
->backup_info
== NULL
))
536 /* Compare backup info also - test the easy things first */
537 if (nhe1
->backup_info
&& (nhe2
->backup_info
== NULL
))
539 if (nhe2
->backup_info
&& (nhe1
->backup_info
== NULL
))
542 /* Compare number of backups before actually comparing any */
543 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
544 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
545 nexthop1
&& nexthop2
;
546 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
550 /* Did we find the end of one list before the other? */
551 if (nexthop1
|| nexthop2
)
554 /* Have to compare the backup nexthops */
555 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
556 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
557 nexthop1
&& nexthop2
;
558 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
560 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
567 bool zebra_nhg_hash_id_equal(const void *arg1
, const void *arg2
)
569 const struct nhg_hash_entry
*nhe1
= arg1
;
570 const struct nhg_hash_entry
*nhe2
= arg2
;
572 return nhe1
->id
== nhe2
->id
;
575 static int zebra_nhg_process_grp(struct nexthop_group
*nhg
,
576 struct nhg_connected_tree_head
*depends
,
577 struct nh_grp
*grp
, uint8_t count
)
579 nhg_connected_tree_init(depends
);
581 for (int i
= 0; i
< count
; i
++) {
582 struct nhg_hash_entry
*depend
= NULL
;
583 /* We do not care about nexthop_grp.weight at
584 * this time. But we should figure out
585 * how to adapt this to our code in
588 depend
= depends_find_id_add(depends
, grp
[i
].id
);
593 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
599 * If this is a nexthop with its own group
600 * dependencies, add them as well. Not sure its
601 * even possible to have a group within a group
605 copy_nexthops(&nhg
->nexthop
, depend
->nhg
.nexthop
, NULL
);
611 static void handle_recursive_depend(struct nhg_connected_tree_head
*nhg_depends
,
612 struct nexthop
*nh
, afi_t afi
)
614 struct nhg_hash_entry
*depend
= NULL
;
615 struct nexthop_group resolved_ng
= {};
617 resolved_ng
.nexthop
= nh
;
619 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
620 zlog_debug("%s: head %p, nh %pNHv",
621 __func__
, nhg_depends
, nh
);
623 depend
= zebra_nhg_rib_find(0, &resolved_ng
, afi
);
625 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
626 zlog_debug("%s: nh %pNHv => %p (%u)",
627 __func__
, nh
, depend
,
628 depend
? depend
->id
: 0);
631 depends_add(nhg_depends
, depend
);
635 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
636 * has an id value, that's used. Create a new global/shared nhe if not found.
638 static bool zebra_nhe_find(struct nhg_hash_entry
**nhe
, /* return value */
639 struct nhg_hash_entry
*lookup
,
640 struct nhg_connected_tree_head
*nhg_depends
,
643 bool created
= false;
644 bool recursive
= false;
645 struct nhg_hash_entry
*newnhe
, *backup_nhe
;
646 struct nexthop
*nh
= NULL
;
648 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
649 zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p",
650 __func__
, lookup
->id
, lookup
,
651 lookup
->vrf_id
, lookup
->type
,
655 (*nhe
) = zebra_nhg_lookup_id(lookup
->id
);
657 (*nhe
) = hash_lookup(zrouter
.nhgs
, lookup
);
659 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
660 zlog_debug("%s: lookup => %p (%u)",
662 (*nhe
) ? (*nhe
)->id
: 0);
664 /* If we found an existing object, we're done */
668 /* We're going to create/insert a new nhe:
669 * assign the next global id value if necessary.
672 lookup
->id
= ++id_counter
;
673 newnhe
= hash_get(zrouter
.nhgs
, lookup
, zebra_nhg_hash_alloc
);
676 /* Mail back the new object */
679 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
680 zlog_debug("%s: => created %p (%u)", __func__
, newnhe
,
683 /* Only hash/lookup the depends if the first lookup
684 * fails to find something. This should hopefully save a
685 * lot of cycles for larger ecmp sizes.
688 /* If you don't want to hash on each nexthop in the
689 * nexthop group struct you can pass the depends
690 * directly. Kernel-side we do this since it just looks
693 zebra_nhg_connect_depends(newnhe
, nhg_depends
);
697 /* Prepare dependency relationships if this is not a
698 * singleton nexthop. There are two cases: a single
699 * recursive nexthop, where we need a relationship to the
700 * resolving nexthop; or a group of nexthops, where we need
701 * relationships with the corresponding singletons.
703 zebra_nhg_depends_init(lookup
);
705 nh
= newnhe
->nhg
.nexthop
;
707 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
))
708 SET_FLAG(newnhe
->flags
, NEXTHOP_GROUP_VALID
);
710 if (nh
->next
== NULL
) {
711 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
712 /* Single recursive nexthop */
713 handle_recursive_depend(&newnhe
->nhg_depends
,
718 /* List of nexthops */
719 for (nh
= newnhe
->nhg
.nexthop
; nh
; nh
= nh
->next
) {
720 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
721 zlog_debug("%s: depends NH %pNHv %s",
723 CHECK_FLAG(nh
->flags
,
724 NEXTHOP_FLAG_RECURSIVE
) ?
727 depends_find_add(&newnhe
->nhg_depends
, nh
, afi
);
732 SET_FLAG((*nhe
)->flags
, NEXTHOP_GROUP_RECURSIVE
);
734 if (zebra_nhg_get_backup_nhg(newnhe
) == NULL
||
735 zebra_nhg_get_backup_nhg(newnhe
)->nexthop
== NULL
)
738 /* If there are backup nexthops, add them to the backup
739 * depends tree. The rules here are a little different.
742 backup_nhe
= newnhe
->backup_info
->nhe
;
744 nh
= backup_nhe
->nhg
.nexthop
;
746 /* Singleton recursive NH */
747 if (nh
->next
== NULL
&&
748 CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
749 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
750 zlog_debug("%s: backup depend NH %pNHv (R)",
753 /* Single recursive nexthop */
754 handle_recursive_depend(&backup_nhe
->nhg_depends
,
758 /* One or more backup NHs */
759 for (; nh
; nh
= nh
->next
) {
760 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
761 zlog_debug("%s: backup depend NH %pNHv %s",
763 CHECK_FLAG(nh
->flags
,
764 NEXTHOP_FLAG_RECURSIVE
) ?
767 depends_find_add(&backup_nhe
->nhg_depends
,
773 SET_FLAG(backup_nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
);
781 * Lookup or create an nhe, based on an nhg or an nhe id.
783 static bool zebra_nhg_find(struct nhg_hash_entry
**nhe
, uint32_t id
,
784 struct nexthop_group
*nhg
,
785 struct nhg_connected_tree_head
*nhg_depends
,
786 vrf_id_t vrf_id
, afi_t afi
, int type
)
788 struct nhg_hash_entry lookup
= {};
789 bool created
= false;
791 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
792 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
793 __func__
, id
, nhg
, vrf_id
, type
,
796 /* Use a temporary nhe and call into the superset/common code */
798 lookup
.type
= type
? type
: ZEBRA_ROUTE_NHG
;
801 lookup
.vrf_id
= vrf_id
;
802 if (lookup
.nhg
.nexthop
->next
) {
803 /* Groups can have all vrfs and AF's in them */
804 lookup
.afi
= AFI_UNSPEC
;
806 switch (lookup
.nhg
.nexthop
->type
) {
807 case (NEXTHOP_TYPE_IFINDEX
):
808 case (NEXTHOP_TYPE_BLACKHOLE
):
810 * This switch case handles setting the afi different
811 * for ipv4/v6 routes. Ifindex/blackhole nexthop
812 * objects cannot be ambiguous, they must be Address
813 * Family specific. If we get here, we will either use
814 * the AF of the route, or the one we got passed from
815 * here from the kernel.
819 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
820 case (NEXTHOP_TYPE_IPV4
):
823 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
824 case (NEXTHOP_TYPE_IPV6
):
825 lookup
.afi
= AFI_IP6
;
830 created
= zebra_nhe_find(nhe
, &lookup
, nhg_depends
, afi
);
835 /* Find/create a single nexthop */
836 static struct nhg_hash_entry
*
837 zebra_nhg_find_nexthop(uint32_t id
, struct nexthop
*nh
, afi_t afi
, int type
)
839 struct nhg_hash_entry
*nhe
= NULL
;
840 struct nexthop_group nhg
= {};
841 vrf_id_t vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nh
->vrf_id
;
843 nexthop_group_add_sorted(&nhg
, nh
);
845 zebra_nhg_find(&nhe
, id
, &nhg
, NULL
, vrf_id
, afi
, type
);
847 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
848 zlog_debug("%s: nh %pNHv => %p (%u)",
849 __func__
, nh
, nhe
, nhe
? nhe
->id
: 0);
854 static uint32_t nhg_ctx_get_id(const struct nhg_ctx
*ctx
)
859 static void nhg_ctx_set_status(struct nhg_ctx
*ctx
, enum nhg_ctx_status status
)
861 ctx
->status
= status
;
864 static enum nhg_ctx_status
nhg_ctx_get_status(const struct nhg_ctx
*ctx
)
869 static void nhg_ctx_set_op(struct nhg_ctx
*ctx
, enum nhg_ctx_op_e op
)
874 static enum nhg_ctx_op_e
nhg_ctx_get_op(const struct nhg_ctx
*ctx
)
879 static vrf_id_t
nhg_ctx_get_vrf_id(const struct nhg_ctx
*ctx
)
884 static int nhg_ctx_get_type(const struct nhg_ctx
*ctx
)
889 static int nhg_ctx_get_afi(const struct nhg_ctx
*ctx
)
894 static struct nexthop
*nhg_ctx_get_nh(struct nhg_ctx
*ctx
)
899 static uint8_t nhg_ctx_get_count(const struct nhg_ctx
*ctx
)
904 static struct nh_grp
*nhg_ctx_get_grp(struct nhg_ctx
*ctx
)
909 static struct nhg_ctx
*nhg_ctx_new(void)
913 new = XCALLOC(MTYPE_NHG_CTX
, sizeof(struct nhg_ctx
));
918 static void nhg_ctx_free(struct nhg_ctx
**ctx
)
925 assert((*ctx
) != NULL
);
927 if (nhg_ctx_get_count(*ctx
))
930 nh
= nhg_ctx_get_nh(*ctx
);
932 nexthop_del_labels(nh
);
935 XFREE(MTYPE_NHG_CTX
, *ctx
);
938 static struct nhg_ctx
*nhg_ctx_init(uint32_t id
, struct nexthop
*nh
,
939 struct nh_grp
*grp
, vrf_id_t vrf_id
,
940 afi_t afi
, int type
, uint8_t count
)
942 struct nhg_ctx
*ctx
= NULL
;
947 ctx
->vrf_id
= vrf_id
;
953 /* Copy over the array */
954 memcpy(&ctx
->u
.grp
, grp
, count
* sizeof(struct nh_grp
));
961 static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry
*nhe
)
963 struct nhg_connected
*rb_node_dep
= NULL
;
965 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
966 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
,
967 NEXTHOP_GROUP_UNHASHABLE
))
974 static void zebra_nhg_set_unhashable(struct nhg_hash_entry
*nhe
)
976 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
);
977 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
980 EC_ZEBRA_DUPLICATE_NHG_MESSAGE
,
981 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
985 static void zebra_nhg_set_valid(struct nhg_hash_entry
*nhe
)
987 struct nhg_connected
*rb_node_dep
;
989 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
991 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
992 zebra_nhg_set_valid(rb_node_dep
->nhe
);
995 static void zebra_nhg_set_invalid(struct nhg_hash_entry
*nhe
)
997 struct nhg_connected
*rb_node_dep
;
999 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1001 /* Update validity of nexthops depending on it */
1002 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1003 zebra_nhg_check_valid(rb_node_dep
->nhe
);
1006 void zebra_nhg_check_valid(struct nhg_hash_entry
*nhe
)
1008 struct nhg_connected
*rb_node_dep
= NULL
;
1011 /* If anthing else in the group is valid, the group is valid */
1012 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1013 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
, NEXTHOP_GROUP_VALID
)) {
1021 zebra_nhg_set_valid(nhe
);
1023 zebra_nhg_set_invalid(nhe
);
1027 static void zebra_nhg_release(struct nhg_hash_entry
*nhe
)
1029 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1030 zlog_debug("%s: nhe %p (%u)", __func__
, nhe
, nhe
->id
);
1032 /* Remove it from any lists it may be on */
1033 zebra_nhg_depends_release(nhe
);
1034 zebra_nhg_dependents_release(nhe
);
1036 if_nhg_dependents_del(nhe
->ifp
, nhe
);
1039 * If its unhashable, we didn't store it here and have to be
1040 * sure we don't clear one thats actually being used.
1042 if (!CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
))
1043 hash_release(zrouter
.nhgs
, nhe
);
1045 hash_release(zrouter
.nhgs_id
, nhe
);
1048 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry
*nhe
)
1050 zebra_nhg_release(nhe
);
1051 zebra_nhg_free(nhe
);
1054 static void zebra_nhg_handle_install(struct nhg_hash_entry
*nhe
)
1056 /* Update validity of groups depending on it */
1057 struct nhg_connected
*rb_node_dep
;
1059 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1060 zebra_nhg_set_valid(rb_node_dep
->nhe
);
1064 * The kernel/other program has changed the state of a nexthop object we are
1067 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry
*nhe
,
1073 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
1074 (is_delete
? "deleted" : "updated"), nhe
->id
);
1076 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1077 zebra_nhg_install_kernel(nhe
);
1079 zebra_nhg_handle_uninstall(nhe
);
1082 static int nhg_ctx_process_new(struct nhg_ctx
*ctx
)
1084 struct nexthop_group
*nhg
= NULL
;
1085 struct nhg_connected_tree_head nhg_depends
= {};
1086 struct nhg_hash_entry
*lookup
= NULL
;
1087 struct nhg_hash_entry
*nhe
= NULL
;
1089 uint32_t id
= nhg_ctx_get_id(ctx
);
1090 uint8_t count
= nhg_ctx_get_count(ctx
);
1091 vrf_id_t vrf_id
= nhg_ctx_get_vrf_id(ctx
);
1092 int type
= nhg_ctx_get_type(ctx
);
1093 afi_t afi
= nhg_ctx_get_afi(ctx
);
1095 lookup
= zebra_nhg_lookup_id(id
);
1097 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1098 zlog_debug("%s: id %u, count %d, lookup => %p",
1099 __func__
, id
, count
, lookup
);
1102 /* This is already present in our table, hence an update
1103 * that we did not initate.
1105 zebra_nhg_handle_kernel_state_change(lookup
, false);
1109 if (nhg_ctx_get_count(ctx
)) {
1110 nhg
= nexthop_group_new();
1111 if (zebra_nhg_process_grp(nhg
, &nhg_depends
,
1112 nhg_ctx_get_grp(ctx
), count
)) {
1113 depends_decrement_free(&nhg_depends
);
1114 nexthop_group_delete(&nhg
);
1118 if (!zebra_nhg_find(&nhe
, id
, nhg
, &nhg_depends
, vrf_id
, type
,
1120 depends_decrement_free(&nhg_depends
);
1122 /* These got copied over in zebra_nhg_alloc() */
1123 nexthop_group_delete(&nhg
);
1125 nhe
= zebra_nhg_find_nexthop(id
, nhg_ctx_get_nh(ctx
), afi
,
1129 if (id
!= nhe
->id
) {
1130 struct nhg_hash_entry
*kernel_nhe
= NULL
;
1132 /* Duplicate but with different ID from
1136 /* The kernel allows duplicate nexthops
1137 * as long as they have different IDs.
1138 * We are ignoring those to prevent
1139 * syncing problems with the kernel
1142 * We maintain them *ONLY* in the ID hash table to
1143 * track them and set the flag to indicated
1144 * their attributes are unhashable.
1147 kernel_nhe
= zebra_nhe_copy(nhe
, id
);
1149 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1150 zlog_debug("%s: copying kernel nhe (%u), dup of %u",
1151 __func__
, id
, nhe
->id
);
1153 zebra_nhg_insert_id(kernel_nhe
);
1154 zebra_nhg_set_unhashable(kernel_nhe
);
1155 } else if (zebra_nhg_contains_unhashable(nhe
)) {
1156 /* The group we got contains an unhashable/duplicated
1157 * depend, so lets mark this group as unhashable as well
1158 * and release it from the non-ID hash.
1160 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1161 zlog_debug("%s: nhe %p (%u) unhashable",
1162 __func__
, nhe
, nhe
->id
);
1164 hash_release(zrouter
.nhgs
, nhe
);
1165 zebra_nhg_set_unhashable(nhe
);
1167 /* It actually created a new nhe */
1168 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1169 zlog_debug("%s: nhe %p (%u) is new",
1170 __func__
, nhe
, nhe
->id
);
1172 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1173 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1177 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1178 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
1186 static int nhg_ctx_process_del(struct nhg_ctx
*ctx
)
1188 struct nhg_hash_entry
*nhe
= NULL
;
1189 uint32_t id
= nhg_ctx_get_id(ctx
);
1191 nhe
= zebra_nhg_lookup_id(id
);
1195 EC_ZEBRA_BAD_NHG_MESSAGE
,
1196 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
1201 zebra_nhg_handle_kernel_state_change(nhe
, true);
1206 static void nhg_ctx_fini(struct nhg_ctx
**ctx
)
1209 * Just freeing for now, maybe do something more in the future
1216 static int queue_add(struct nhg_ctx
*ctx
)
1218 /* If its queued or already processed do nothing */
1219 if (nhg_ctx_get_status(ctx
) == NHG_CTX_QUEUED
)
1222 if (rib_queue_nhg_add(ctx
)) {
1223 nhg_ctx_set_status(ctx
, NHG_CTX_FAILURE
);
1227 nhg_ctx_set_status(ctx
, NHG_CTX_QUEUED
);
1232 int nhg_ctx_process(struct nhg_ctx
*ctx
)
1236 switch (nhg_ctx_get_op(ctx
)) {
1237 case NHG_CTX_OP_NEW
:
1238 ret
= nhg_ctx_process_new(ctx
);
1239 if (nhg_ctx_get_count(ctx
) && ret
== -ENOENT
1240 && nhg_ctx_get_status(ctx
) != NHG_CTX_REQUEUED
) {
1242 * We have entered a situation where we are
1243 * processing a group from the kernel
1244 * that has a contained nexthop which
1245 * we have not yet processed.
1247 * Re-enqueue this ctx to be handled exactly one
1248 * more time (indicated by the flag).
1250 * By the time we get back to it, we
1251 * should have processed its depends.
1253 nhg_ctx_set_status(ctx
, NHG_CTX_NONE
);
1254 if (queue_add(ctx
) == 0) {
1255 nhg_ctx_set_status(ctx
, NHG_CTX_REQUEUED
);
1260 case NHG_CTX_OP_DEL
:
1261 ret
= nhg_ctx_process_del(ctx
);
1262 case NHG_CTX_OP_NONE
:
1266 nhg_ctx_set_status(ctx
, (ret
? NHG_CTX_FAILURE
: NHG_CTX_SUCCESS
));
1273 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1274 int zebra_nhg_kernel_find(uint32_t id
, struct nexthop
*nh
, struct nh_grp
*grp
,
1275 uint8_t count
, vrf_id_t vrf_id
, afi_t afi
, int type
,
1278 struct nhg_ctx
*ctx
= NULL
;
1280 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1281 zlog_debug("%s: nh %pNHv, id %u, count %d",
1282 __func__
, nh
, id
, (int)count
);
1284 if (id
> id_counter
)
1285 /* Increase our counter so we don't try to create
1286 * an ID that already exists
1290 ctx
= nhg_ctx_init(id
, nh
, grp
, vrf_id
, afi
, type
, count
);
1291 nhg_ctx_set_op(ctx
, NHG_CTX_OP_NEW
);
1293 /* Under statup conditions, we need to handle them immediately
1294 * like we do for routes. Otherwise, we are going to get a route
1295 * with a nhe_id that we have not handled.
1298 return nhg_ctx_process(ctx
);
1300 if (queue_add(ctx
)) {
1308 /* Kernel-side, received delete message */
1309 int zebra_nhg_kernel_del(uint32_t id
, vrf_id_t vrf_id
)
1311 struct nhg_ctx
*ctx
= NULL
;
1313 ctx
= nhg_ctx_init(id
, NULL
, NULL
, vrf_id
, 0, 0, 0);
1315 nhg_ctx_set_op(ctx
, NHG_CTX_OP_DEL
);
1317 if (queue_add(ctx
)) {
1325 /* Some dependency helper functions */
1326 static struct nhg_hash_entry
*depends_find_recursive(const struct nexthop
*nh
,
1329 struct nhg_hash_entry
*nhe
;
1330 struct nexthop
*lookup
= NULL
;
1332 lookup
= nexthop_dup(nh
, NULL
);
1334 nhe
= zebra_nhg_find_nexthop(0, lookup
, afi
, 0);
1336 nexthops_free(lookup
);
1341 static struct nhg_hash_entry
*depends_find_singleton(const struct nexthop
*nh
,
1344 struct nhg_hash_entry
*nhe
;
1345 struct nexthop lookup
= {};
1347 /* Capture a snapshot of this single nh; it might be part of a list,
1348 * so we need to make a standalone copy.
1350 nexthop_copy_no_recurse(&lookup
, nh
, NULL
);
1352 nhe
= zebra_nhg_find_nexthop(0, &lookup
, afi
, 0);
1354 /* The copy may have allocated labels; free them if necessary. */
1355 nexthop_del_labels(&lookup
);
1357 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1358 zlog_debug("%s: nh %pNHv => %p (%u)",
1359 __func__
, nh
, nhe
, nhe
? nhe
->id
: 0);
1364 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
)
1366 struct nhg_hash_entry
*nhe
= NULL
;
1372 /* We are separating these functions out to increase handling speed
1373 * in the non-recursive case (by not alloc/freeing)
1375 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
1376 nhe
= depends_find_recursive(nh
, afi
);
1377 strlcpy(rbuf
, "(R)", sizeof(rbuf
));
1379 nhe
= depends_find_singleton(nh
, afi
);
1383 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1384 zlog_debug("%s: nh %pNHv %s => %p (%u)",
1386 nhe
, nhe
? nhe
->id
: 0);
1392 static void depends_add(struct nhg_connected_tree_head
*head
,
1393 struct nhg_hash_entry
*depend
)
1395 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1396 zlog_debug("%s: head %p nh %pNHv",
1397 __func__
, head
, depend
->nhg
.nexthop
);
1399 /* If NULL is returned, it was successfully added and
1400 * needs to have its refcnt incremented.
1402 * Else the NHE is already present in the tree and doesn't
1403 * need to increment the refcnt.
1405 if (nhg_connected_tree_add_nhe(head
, depend
) == NULL
)
1406 zebra_nhg_increment_ref(depend
);
1409 static struct nhg_hash_entry
*
1410 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
1413 struct nhg_hash_entry
*depend
= NULL
;
1415 depend
= depends_find(nh
, afi
);
1417 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1418 zlog_debug("%s: nh %pNHv => %p",
1419 __func__
, nh
, depend
);
1422 depends_add(head
, depend
);
1427 static struct nhg_hash_entry
*
1428 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
)
1430 struct nhg_hash_entry
*depend
= NULL
;
1432 depend
= zebra_nhg_lookup_id(id
);
1435 depends_add(head
, depend
);
1440 static void depends_decrement_free(struct nhg_connected_tree_head
*head
)
1442 nhg_connected_tree_decrement_ref(head
);
1443 nhg_connected_tree_free(head
);
1446 /* Find an nhe based on a list of nexthops */
1447 struct nhg_hash_entry
*
1448 zebra_nhg_rib_find(uint32_t id
, struct nexthop_group
*nhg
, afi_t rt_afi
)
1450 struct nhg_hash_entry
*nhe
= NULL
;
1454 * CLANG SA is complaining that nexthop may be NULL
1455 * Make it happy but this is ridonc
1457 assert(nhg
->nexthop
);
1458 vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nhg
->nexthop
->vrf_id
;
1460 zebra_nhg_find(&nhe
, id
, nhg
, NULL
, vrf_id
, rt_afi
, 0);
1462 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1463 zlog_debug("%s: => nhe %p (%u)",
1464 __func__
, nhe
, nhe
? nhe
->id
: 0);
1469 /* Find an nhe based on a route's nhe */
1470 struct nhg_hash_entry
*
1471 zebra_nhg_rib_find_nhe(struct nhg_hash_entry
*rt_nhe
, afi_t rt_afi
)
1473 struct nhg_hash_entry
*nhe
= NULL
;
1475 if (!(rt_nhe
&& rt_nhe
->nhg
.nexthop
)) {
1476 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1477 "No nexthop passed to %s", __func__
);
1481 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1482 zlog_debug("%s: rt_nhe %p (%u)", __func__
, rt_nhe
, rt_nhe
->id
);
1484 zebra_nhe_find(&nhe
, rt_nhe
, NULL
, rt_afi
);
1486 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1487 zlog_debug("%s: => nhe %p (%u)",
1488 __func__
, nhe
, nhe
? nhe
->id
: 0);
1494 * Allocate backup nexthop info object. Typically these are embedded in
1495 * nhg_hash_entry objects.
1497 struct nhg_backup_info
*zebra_nhg_backup_alloc(void)
1499 struct nhg_backup_info
*p
;
1501 p
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_backup_info
));
1503 p
->nhe
= zebra_nhg_alloc();
1505 /* Identify the embedded group used to hold the list of backups */
1506 SET_FLAG(p
->nhe
->flags
, NEXTHOP_GROUP_BACKUP
);
1512 * Free backup nexthop info object, deal with any embedded allocations
1514 void zebra_nhg_backup_free(struct nhg_backup_info
**p
)
1518 zebra_nhg_free((*p
)->nhe
);
1520 XFREE(MTYPE_NHG
, (*p
));
1524 /* Accessor for backup nexthop group */
1525 struct nexthop_group
*zebra_nhg_get_backup_nhg(struct nhg_hash_entry
*nhe
)
1527 struct nexthop_group
*p
= NULL
;
1530 if (nhe
->backup_info
&& nhe
->backup_info
->nhe
)
1531 p
= &(nhe
->backup_info
->nhe
->nhg
);
1538 * Helper to return a copy of a backup_info - note that this is a shallow
1539 * copy, meant to be used when creating a new nhe from info passed in with
1542 static struct nhg_backup_info
*
1543 nhg_backup_copy(const struct nhg_backup_info
*orig
)
1545 struct nhg_backup_info
*b
;
1547 b
= zebra_nhg_backup_alloc();
1549 /* Copy list of nexthops */
1550 nexthop_group_copy(&(b
->nhe
->nhg
), &(orig
->nhe
->nhg
));
1555 static void zebra_nhg_free_members(struct nhg_hash_entry
*nhe
)
1557 nexthops_free(nhe
->nhg
.nexthop
);
1559 zebra_nhg_backup_free(&nhe
->backup_info
);
1561 /* Decrement to remove connection ref */
1562 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1563 nhg_connected_tree_free(&nhe
->nhg_depends
);
1564 nhg_connected_tree_free(&nhe
->nhg_dependents
);
1567 void zebra_nhg_free(struct nhg_hash_entry
*nhe
)
1569 if (IS_ZEBRA_DEBUG_NHG_DETAIL
) {
1570 /* Group or singleton? */
1571 if (nhe
->nhg
.nexthop
&& nhe
->nhg
.nexthop
->next
)
1572 zlog_debug("%s: nhe %p (%u), refcnt %d",
1573 __func__
, nhe
, nhe
->id
, nhe
->refcnt
);
1575 zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
1576 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1581 zlog_debug("nhe_id=%u hash refcnt=%d", nhe
->id
, nhe
->refcnt
);
1583 zebra_nhg_free_members(nhe
);
1585 XFREE(MTYPE_NHG
, nhe
);
1588 void zebra_nhg_hash_free(void *p
)
1590 zebra_nhg_free((struct nhg_hash_entry
*)p
);
1593 void zebra_nhg_decrement_ref(struct nhg_hash_entry
*nhe
)
1595 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1596 zlog_debug("%s: nhe %p (%u) %d => %d",
1597 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1602 if (!zebra_nhg_depends_is_empty(nhe
))
1603 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1605 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1606 zebra_nhg_uninstall_kernel(nhe
);
1609 void zebra_nhg_increment_ref(struct nhg_hash_entry
*nhe
)
1611 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1612 zlog_debug("%s: nhe %p (%u) %d => %d",
1613 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1618 if (!zebra_nhg_depends_is_empty(nhe
))
1619 nhg_connected_tree_increment_ref(&nhe
->nhg_depends
);
1622 static void nexthop_set_resolved(afi_t afi
, const struct nexthop
*newhop
,
1623 struct nexthop
*nexthop
)
1625 struct nexthop
*resolved_hop
;
1626 uint8_t num_labels
= 0;
1627 mpls_label_t labels
[MPLS_MAX_LABELS
];
1628 enum lsp_types_t label_type
= ZEBRA_LSP_NONE
;
1631 resolved_hop
= nexthop_new();
1632 SET_FLAG(resolved_hop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1634 resolved_hop
->vrf_id
= nexthop
->vrf_id
;
1635 switch (newhop
->type
) {
1636 case NEXTHOP_TYPE_IPV4
:
1637 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1638 /* If the resolving route specifies a gateway, use it */
1639 resolved_hop
->type
= newhop
->type
;
1640 resolved_hop
->gate
.ipv4
= newhop
->gate
.ipv4
;
1642 if (newhop
->ifindex
) {
1643 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1644 resolved_hop
->ifindex
= newhop
->ifindex
;
1647 case NEXTHOP_TYPE_IPV6
:
1648 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1649 resolved_hop
->type
= newhop
->type
;
1650 resolved_hop
->gate
.ipv6
= newhop
->gate
.ipv6
;
1652 if (newhop
->ifindex
) {
1653 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1654 resolved_hop
->ifindex
= newhop
->ifindex
;
1657 case NEXTHOP_TYPE_IFINDEX
:
1658 /* If the resolving route is an interface route,
1659 * it means the gateway we are looking up is connected
1660 * to that interface. (The actual network is _not_ onlink).
1661 * Therefore, the resolved route should have the original
1662 * gateway as nexthop as it is directly connected.
1664 * On Linux, we have to set the onlink netlink flag because
1665 * otherwise, the kernel won't accept the route.
1667 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1668 if (afi
== AFI_IP
) {
1669 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1670 resolved_hop
->gate
.ipv4
= nexthop
->gate
.ipv4
;
1671 } else if (afi
== AFI_IP6
) {
1672 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1673 resolved_hop
->gate
.ipv6
= nexthop
->gate
.ipv6
;
1675 resolved_hop
->ifindex
= newhop
->ifindex
;
1677 case NEXTHOP_TYPE_BLACKHOLE
:
1678 resolved_hop
->type
= NEXTHOP_TYPE_BLACKHOLE
;
1679 resolved_hop
->bh_type
= newhop
->bh_type
;
1683 if (newhop
->flags
& NEXTHOP_FLAG_ONLINK
)
1684 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1686 /* Copy labels of the resolved route and the parent resolving to it */
1687 if (newhop
->nh_label
) {
1688 for (i
= 0; i
< newhop
->nh_label
->num_labels
; i
++) {
1689 /* Be a bit picky about overrunning the local array */
1690 if (num_labels
>= MPLS_MAX_LABELS
) {
1691 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1692 zlog_debug("%s: too many labels in newhop %pNHv",
1696 labels
[num_labels
++] = newhop
->nh_label
->label
[i
];
1698 /* Use the "outer" type */
1699 label_type
= newhop
->nh_label_type
;
1702 if (nexthop
->nh_label
) {
1703 for (i
= 0; i
< nexthop
->nh_label
->num_labels
; i
++) {
1704 /* Be a bit picky about overrunning the local array */
1705 if (num_labels
>= MPLS_MAX_LABELS
) {
1706 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1707 zlog_debug("%s: too many labels in nexthop %pNHv",
1711 labels
[num_labels
++] = nexthop
->nh_label
->label
[i
];
1714 /* If the parent has labels, use its type if
1715 * we don't already have one.
1717 if (label_type
== ZEBRA_LSP_NONE
)
1718 label_type
= nexthop
->nh_label_type
;
1722 nexthop_add_labels(resolved_hop
, label_type
, num_labels
,
1725 resolved_hop
->rparent
= nexthop
;
1726 _nexthop_add(&nexthop
->resolved
, resolved_hop
);
1729 /* Checks if nexthop we are trying to resolve to is valid */
1730 static bool nexthop_valid_resolve(const struct nexthop
*nexthop
,
1731 const struct nexthop
*resolved
)
1733 /* Can't resolve to a recursive nexthop */
1734 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1737 switch (nexthop
->type
) {
1738 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1739 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1740 /* If the nexthop we are resolving to does not match the
1741 * ifindex for the nexthop the route wanted, its not valid.
1743 if (nexthop
->ifindex
!= resolved
->ifindex
)
1746 case NEXTHOP_TYPE_IPV4
:
1747 case NEXTHOP_TYPE_IPV6
:
1748 case NEXTHOP_TYPE_IFINDEX
:
1749 case NEXTHOP_TYPE_BLACKHOLE
:
1757 * Given a nexthop we need to properly recursively resolve
1758 * the route. As such, do a table lookup to find and match
1759 * if at all possible. Set the nexthop->ifindex and resolved_id
1762 static int nexthop_active(afi_t afi
, struct route_entry
*re
,
1763 struct nexthop
*nexthop
, struct route_node
*top
)
1766 struct route_table
*table
;
1767 struct route_node
*rn
;
1768 struct route_entry
*match
= NULL
;
1770 struct nexthop
*newhop
;
1771 struct interface
*ifp
;
1773 struct zebra_vrf
*zvrf
;
1775 if ((nexthop
->type
== NEXTHOP_TYPE_IPV4
)
1776 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1777 nexthop
->ifindex
= 0;
1780 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
);
1781 nexthops_free(nexthop
->resolved
);
1782 nexthop
->resolved
= NULL
;
1783 re
->nexthop_mtu
= 0;
1785 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1786 zlog_debug("%s: re %p, nexthop %pNHv",
1787 __func__
, re
, nexthop
);
1790 * If the kernel has sent us a NEW route, then
1791 * by golly gee whiz it's a good route.
1793 * If its an already INSTALLED route we have already handled, then the
1794 * kernel route's nexthop might have became unreachable
1795 * and we have to handle that.
1797 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
)
1798 && (re
->type
== ZEBRA_ROUTE_KERNEL
1799 || re
->type
== ZEBRA_ROUTE_SYSTEM
))
1803 * If the nexthop has been marked as 'onlink' we just need to make
1804 * sure the nexthop's interface is known and is operational.
1806 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ONLINK
)) {
1807 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1809 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1810 zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
1811 nexthop
, nexthop
->ifindex
);
1814 if (!if_is_operative(ifp
)) {
1815 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1816 zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
1817 nexthop
, ifp
->name
);
1823 if ((top
->p
.family
== AF_INET
&& top
->p
.prefixlen
== 32
1824 && nexthop
->gate
.ipv4
.s_addr
== top
->p
.u
.prefix4
.s_addr
)
1825 || (top
->p
.family
== AF_INET6
&& top
->p
.prefixlen
== 128
1826 && memcmp(&nexthop
->gate
.ipv6
, &top
->p
.u
.prefix6
, 16) == 0)) {
1827 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1829 " :%s: Attempting to install a max prefixlength route through itself",
1834 /* Make lookup prefix. */
1835 memset(&p
, 0, sizeof(struct prefix
));
1839 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1840 p
.u
.prefix4
= nexthop
->gate
.ipv4
;
1843 p
.family
= AF_INET6
;
1844 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
1845 p
.u
.prefix6
= nexthop
->gate
.ipv6
;
1848 assert(afi
!= AFI_IP
&& afi
!= AFI_IP6
);
1852 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, nexthop
->vrf_id
);
1854 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
1855 if (!table
|| !zvrf
) {
1856 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1857 zlog_debug(" %s: Table not found", __func__
);
1861 rn
= route_node_match(table
, (struct prefix
*)&p
);
1863 route_unlock_node(rn
);
1865 /* Lookup should halt if we've matched against ourselves ('top',
1866 * if specified) - i.e., we cannot have a nexthop NH1 is
1867 * resolved by a route NH1. The exception is if the route is a
1871 if (((afi
== AFI_IP
) && (rn
->p
.prefixlen
!= 32))
1872 || ((afi
== AFI_IP6
) && (rn
->p
.prefixlen
!= 128))) {
1873 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1875 " %s: Matched against ourself and prefix length is not max bit length",
1880 /* Pick up selected route. */
1881 /* However, do not resolve over default route unless explicitly
1884 if (is_default_prefix(&rn
->p
)
1885 && !rnh_resolve_via_default(zvrf
, p
.family
)) {
1886 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1888 " :%s: Resolved against default route",
1893 dest
= rib_dest_from_rnode(rn
);
1894 if (dest
&& dest
->selected_fib
1895 && !CHECK_FLAG(dest
->selected_fib
->status
,
1896 ROUTE_ENTRY_REMOVED
)
1897 && dest
->selected_fib
->type
!= ZEBRA_ROUTE_TABLE
)
1898 match
= dest
->selected_fib
;
1900 /* If there is no selected route or matched route is EGP, go up
1906 } while (rn
&& rn
->info
== NULL
);
1908 route_lock_node(rn
);
1913 if (match
->type
== ZEBRA_ROUTE_CONNECT
) {
1914 /* Directly point connected route. */
1915 newhop
= match
->nhe
->nhg
.nexthop
;
1917 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
1918 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1919 nexthop
->ifindex
= newhop
->ifindex
;
1922 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1923 zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
1925 match
->nhe
->id
, newhop
);
1928 } else if (CHECK_FLAG(re
->flags
, ZEBRA_FLAG_ALLOW_RECURSION
)) {
1930 for (ALL_NEXTHOPS(match
->nhe
->nhg
, newhop
)) {
1931 if (!CHECK_FLAG(match
->status
,
1932 ROUTE_ENTRY_INSTALLED
))
1934 if (!nexthop_valid_resolve(nexthop
, newhop
))
1937 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1938 zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
1940 match
->nhe
->id
, newhop
);
1942 SET_FLAG(nexthop
->flags
,
1943 NEXTHOP_FLAG_RECURSIVE
);
1944 nexthop_set_resolved(afi
, newhop
, nexthop
);
1949 re
->nexthop_mtu
= match
->mtu
;
1950 else if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1952 " %s: Recursion failed to find",
1956 } else if (re
->type
== ZEBRA_ROUTE_STATIC
) {
1958 for (ALL_NEXTHOPS(match
->nhe
->nhg
, newhop
)) {
1959 if (!CHECK_FLAG(match
->status
,
1960 ROUTE_ENTRY_INSTALLED
))
1962 if (!nexthop_valid_resolve(nexthop
, newhop
))
1965 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1966 zlog_debug("%s: STATIC match %p (%u), newhop %pNHv",
1968 match
->nhe
->id
, newhop
);
1970 SET_FLAG(nexthop
->flags
,
1971 NEXTHOP_FLAG_RECURSIVE
);
1972 nexthop_set_resolved(afi
, newhop
, nexthop
);
1976 re
->nexthop_mtu
= match
->mtu
;
1978 if (!resolved
&& IS_ZEBRA_DEBUG_RIB_DETAILED
)
1980 " %s: Static route unable to resolve",
1984 if (IS_ZEBRA_DEBUG_RIB_DETAILED
) {
1986 " %s: Route Type %s has not turned on recursion",
1987 __func__
, zebra_route_string(re
->type
));
1988 if (re
->type
== ZEBRA_ROUTE_BGP
1989 && !CHECK_FLAG(re
->flags
, ZEBRA_FLAG_IBGP
))
1991 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1996 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1997 zlog_debug(" %s: Nexthop did not lookup in table",
2002 /* This function verifies reachability of one given nexthop, which can be
2003 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2004 * in nexthop->flags field. The nexthop->ifindex will be updated
2005 * appropriately as well. An existing route map can turn
2006 * (otherwise active) nexthop into inactive, but not vice versa.
2008 * If it finds a nexthop recursivedly, set the resolved_id
2009 * to match that nexthop's nhg_hash_entry ID;
2011 * The return value is the final value of 'ACTIVE' flag.
2013 static unsigned nexthop_active_check(struct route_node
*rn
,
2014 struct route_entry
*re
,
2015 struct nexthop
*nexthop
)
2017 struct interface
*ifp
;
2018 route_map_result_t ret
= RMAP_PERMITMATCH
;
2020 char buf
[SRCDEST2STR_BUFFER
];
2021 const struct prefix
*p
, *src_p
;
2022 struct zebra_vrf
*zvrf
;
2024 srcdest_rnode_prefixes(rn
, &p
, &src_p
);
2026 if (rn
->p
.family
== AF_INET
)
2028 else if (rn
->p
.family
== AF_INET6
)
2032 switch (nexthop
->type
) {
2033 case NEXTHOP_TYPE_IFINDEX
:
2034 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
2036 * If the interface exists and its operative or its a kernel
2037 * route and interface is up, its active. We trust kernel routes
2041 && (if_is_operative(ifp
)
2043 && (re
->type
== ZEBRA_ROUTE_KERNEL
2044 || re
->type
== ZEBRA_ROUTE_SYSTEM
))))
2045 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2047 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2049 case NEXTHOP_TYPE_IPV4
:
2050 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2052 if (nexthop_active(AFI_IP
, re
, nexthop
, rn
))
2053 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2055 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2057 case NEXTHOP_TYPE_IPV6
:
2059 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
2060 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2062 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2064 case NEXTHOP_TYPE_IPV6_IFINDEX
:
2065 /* RFC 5549, v4 prefix with v6 NH */
2066 if (rn
->p
.family
!= AF_INET
)
2068 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
2069 ifp
= if_lookup_by_index(nexthop
->ifindex
,
2071 if (ifp
&& if_is_operative(ifp
))
2072 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2074 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2076 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
2077 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2079 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2082 case NEXTHOP_TYPE_BLACKHOLE
:
2083 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2089 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
2090 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2091 zlog_debug(" %s: Unable to find active nexthop",
2096 /* XXX: What exactly do those checks do? Do we support
2097 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2099 if (RIB_SYSTEM_ROUTE(re
) || (family
== AFI_IP
&& p
->family
!= AF_INET
)
2100 || (family
== AFI_IP6
&& p
->family
!= AF_INET6
))
2101 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2103 /* The original code didn't determine the family correctly
2104 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2105 * from the rib_table_info in those cases.
2106 * Possibly it may be better to use only the rib_table_info
2110 struct rib_table_info
*info
;
2112 info
= srcdest_rnode_table_info(rn
);
2116 memset(&nexthop
->rmap_src
.ipv6
, 0, sizeof(union g_addr
));
2118 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
2120 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2121 zlog_debug(" %s: zvrf is NULL", __func__
);
2122 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2125 /* It'll get set if required inside */
2126 ret
= zebra_route_map_check(family
, re
->type
, re
->instance
, p
, nexthop
,
2128 if (ret
== RMAP_DENYMATCH
) {
2129 if (IS_ZEBRA_DEBUG_RIB
) {
2130 srcdest_rnode2str(rn
, buf
, sizeof(buf
));
2132 "%u:%s: Filtering out with NH out %s due to route map",
2134 ifindex2ifname(nexthop
->ifindex
,
2137 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2139 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2142 /* Helper function called after resolution to walk nhg rb trees
2143 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2144 * is active on singleton NHEs.
2146 static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry
*nhe
)
2148 struct nhg_connected
*rb_node_dep
= NULL
;
2151 if (!zebra_nhg_depends_is_empty(nhe
)) {
2152 /* Is at least one depend valid? */
2153 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2154 if (zebra_nhg_set_valid_if_active(rb_node_dep
->nhe
))
2161 /* should be fully resolved singleton at this point */
2162 if (CHECK_FLAG(nhe
->nhg
.nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
2167 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
2173 * Process a list of nexthops, given the head of the list, determining
2174 * whether each one is ACTIVE/installable at this time.
2176 static uint32_t nexthop_list_active_update(struct route_node
*rn
,
2177 struct route_entry
*re
,
2178 struct nexthop
*nexthop
)
2180 union g_addr prev_src
;
2181 unsigned int prev_active
, new_active
;
2182 ifindex_t prev_index
;
2183 uint32_t counter
= 0;
2185 /* Process nexthops one-by-one */
2186 for ( ; nexthop
; nexthop
= nexthop
->next
) {
2188 /* No protocol daemon provides src and so we're skipping
2191 prev_src
= nexthop
->rmap_src
;
2192 prev_active
= CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2193 prev_index
= nexthop
->ifindex
;
2195 * We need to respect the multipath_num here
2196 * as that what we should be able to install from
2197 * a multipath perspective should not be a data plane
2201 nexthop_active_check(rn
, re
, nexthop
);
2203 if (new_active
&& counter
>= zrouter
.multipath_num
) {
2206 /* Set it and its resolved nexthop as inactive. */
2207 for (nh
= nexthop
; nh
; nh
= nh
->resolved
)
2208 UNSET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
2216 /* Don't allow src setting on IPv6 addr for now */
2217 if (prev_active
!= new_active
|| prev_index
!= nexthop
->ifindex
2218 || ((nexthop
->type
>= NEXTHOP_TYPE_IFINDEX
2219 && nexthop
->type
< NEXTHOP_TYPE_IPV6
)
2220 && prev_src
.ipv4
.s_addr
2221 != nexthop
->rmap_src
.ipv4
.s_addr
)
2222 || ((nexthop
->type
>= NEXTHOP_TYPE_IPV6
2223 && nexthop
->type
< NEXTHOP_TYPE_BLACKHOLE
)
2224 && !(IPV6_ADDR_SAME(&prev_src
.ipv6
,
2225 &nexthop
->rmap_src
.ipv6
)))
2226 || CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
2227 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2234 * Iterate over all nexthops of the given RIB entry and refresh their
2235 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2236 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2238 * Return value is the new number of active nexthops.
2240 int nexthop_active_update(struct route_node
*rn
, struct route_entry
*re
)
2242 struct nhg_hash_entry
*curr_nhe
;
2243 uint32_t curr_active
= 0, backup_active
= 0;
2245 afi_t rt_afi
= family2afi(rn
->p
.family
);
2247 UNSET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2249 /* Make a local copy of the existing nhe, so we don't work on/modify
2252 curr_nhe
= zebra_nhe_copy(re
->nhe
, re
->nhe
->id
);
2254 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2255 zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
2256 __func__
, re
, re
->nhe
, re
->nhe
->id
,
2259 /* Clear the existing id, if any: this will avoid any confusion
2260 * if the id exists, and will also force the creation
2261 * of a new nhe reflecting the changes we may make in this local copy.
2265 /* Process nexthops */
2266 curr_active
= nexthop_list_active_update(rn
, re
, curr_nhe
->nhg
.nexthop
);
2268 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2269 zlog_debug("%s: re %p curr_active %u", __func__
, re
,
2272 /* If there are no backup nexthops, we are done */
2273 if (zebra_nhg_get_backup_nhg(curr_nhe
) == NULL
)
2276 backup_active
= nexthop_list_active_update(
2277 rn
, re
, zebra_nhg_get_backup_nhg(curr_nhe
)->nexthop
);
2279 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2280 zlog_debug("%s: re %p backup_active %u", __func__
, re
,
2286 * Ref or create an nhe that matches the current state of the
2289 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
)) {
2290 struct nhg_hash_entry
*new_nhe
= NULL
;
2292 new_nhe
= zebra_nhg_rib_find_nhe(curr_nhe
, rt_afi
);
2294 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2295 zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
2296 __func__
, re
, re
->nhe
,
2297 re
->nhe
->id
, new_nhe
, new_nhe
->id
);
2299 route_entry_update_nhe(re
, new_nhe
);
2303 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2304 * flag where appropriate.
2307 zebra_nhg_set_valid_if_active(re
->nhe
);
2310 * Do not need the old / copied nhe anymore since it
2311 * was either copied over into a new nhe or not
2314 zebra_nhg_free(curr_nhe
);
2318 /* Recursively construct a grp array of fully resolved IDs.
2320 * This function allows us to account for groups within groups,
2321 * by converting them into a flat array of IDs.
2323 * nh_grp is modified at every level of recursion to append
2324 * to it the next unique, fully resolved ID from the entire tree.
2328 * I'm pretty sure we only allow ONE level of group within group currently.
2329 * But making this recursive just in case that ever changes.
2331 static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp
*grp
,
2333 struct nhg_hash_entry
*nhe
,
2336 struct nhg_connected
*rb_node_dep
= NULL
;
2337 struct nhg_hash_entry
*depend
= NULL
;
2338 uint8_t i
= curr_index
;
2340 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2341 bool duplicate
= false;
2346 depend
= rb_node_dep
->nhe
;
2349 * If its recursive, use its resolved nhe in the group
2351 if (CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_RECURSIVE
)) {
2352 depend
= zebra_nhg_resolve(depend
);
2355 EC_ZEBRA_NHG_FIB_UPDATE
,
2356 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
2362 if (!zebra_nhg_depends_is_empty(depend
)) {
2363 /* This is a group within a group */
2364 i
= zebra_nhg_nhe2grp_internal(grp
, i
, depend
, max_num
);
2366 if (!CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_VALID
)) {
2367 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2368 || IS_ZEBRA_DEBUG_NHG
)
2370 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2371 __func__
, depend
->id
);
2375 /* If the nexthop not installed/queued for install don't
2376 * put in the ID array.
2378 if (!(CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_INSTALLED
)
2379 || CHECK_FLAG(depend
->flags
,
2380 NEXTHOP_GROUP_QUEUED
))) {
2381 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2382 || IS_ZEBRA_DEBUG_NHG
)
2384 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2385 __func__
, depend
->id
);
2389 /* Check for duplicate IDs, ignore if found. */
2390 for (int j
= 0; j
< i
; j
++) {
2391 if (depend
->id
== grp
[j
].id
) {
2398 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2399 || IS_ZEBRA_DEBUG_NHG
)
2401 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2402 __func__
, depend
->id
);
2406 grp
[i
].id
= depend
->id
;
2407 grp
[i
].weight
= depend
->nhg
.nexthop
->weight
;
2412 if (nhe
->backup_info
== NULL
|| nhe
->backup_info
->nhe
== NULL
)
2415 /* TODO -- For now, we are not trying to use or install any
2416 * backup info in this nexthop-id path: we aren't prepared
2417 * to use the backups here yet. We're just debugging what we find.
2419 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2420 zlog_debug("%s: skipping backup nhe", __func__
);
2426 /* Convert a nhe into a group array */
2427 uint8_t zebra_nhg_nhe2grp(struct nh_grp
*grp
, struct nhg_hash_entry
*nhe
,
2430 /* Call into the recursive function */
2431 return zebra_nhg_nhe2grp_internal(grp
, 0, nhe
, max_num
);
2434 void zebra_nhg_install_kernel(struct nhg_hash_entry
*nhe
)
2436 struct nhg_connected
*rb_node_dep
= NULL
;
2438 /* Resolve it first */
2439 nhe
= zebra_nhg_resolve(nhe
);
2441 /* Make sure all depends are installed/queued */
2442 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2443 zebra_nhg_install_kernel(rb_node_dep
->nhe
);
2446 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
)
2447 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)
2448 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
)) {
2449 /* Change its type to us since we are installing it */
2450 nhe
->type
= ZEBRA_ROUTE_NHG
;
2452 int ret
= dplane_nexthop_add(nhe
);
2455 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2456 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2458 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2460 EC_ZEBRA_DP_INSTALL_FAIL
,
2461 "Failed to install Nexthop ID (%u) into the kernel",
2464 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2465 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2466 zebra_nhg_handle_install(nhe
);
2472 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry
*nhe
)
2474 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)) {
2475 int ret
= dplane_nexthop_delete(nhe
);
2478 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2479 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2481 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2483 EC_ZEBRA_DP_DELETE_FAIL
,
2484 "Failed to uninstall Nexthop ID (%u) from the kernel",
2487 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2488 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2493 zebra_nhg_handle_uninstall(nhe
);
2496 void zebra_nhg_dplane_result(struct zebra_dplane_ctx
*ctx
)
2498 enum dplane_op_e op
;
2499 enum zebra_dplane_result status
;
2501 struct nhg_hash_entry
*nhe
= NULL
;
2503 op
= dplane_ctx_get_op(ctx
);
2504 status
= dplane_ctx_get_status(ctx
);
2506 id
= dplane_ctx_get_nhe_id(ctx
);
2508 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
|| IS_ZEBRA_DEBUG_NHG_DETAIL
)
2510 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
2511 ctx
, dplane_op2str(op
), id
, dplane_res2str(status
));
2514 case DPLANE_OP_NH_DELETE
:
2515 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
2517 EC_ZEBRA_DP_DELETE_FAIL
,
2518 "Failed to uninstall Nexthop ID (%u) from the kernel",
2520 /* We already free'd the data, nothing to do */
2522 case DPLANE_OP_NH_INSTALL
:
2523 case DPLANE_OP_NH_UPDATE
:
2524 nhe
= zebra_nhg_lookup_id(id
);
2529 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
2530 dplane_op2str(op
), id
);
2534 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2535 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
2536 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
2537 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2538 zebra_nhg_handle_install(nhe
);
2541 EC_ZEBRA_DP_INSTALL_FAIL
,
2542 "Failed to install Nexthop ID (%u) into the kernel",
2545 case DPLANE_OP_ROUTE_INSTALL
:
2546 case DPLANE_OP_ROUTE_UPDATE
:
2547 case DPLANE_OP_ROUTE_DELETE
:
2548 case DPLANE_OP_ROUTE_NOTIFY
:
2549 case DPLANE_OP_LSP_INSTALL
:
2550 case DPLANE_OP_LSP_UPDATE
:
2551 case DPLANE_OP_LSP_DELETE
:
2552 case DPLANE_OP_LSP_NOTIFY
:
2553 case DPLANE_OP_PW_INSTALL
:
2554 case DPLANE_OP_PW_UNINSTALL
:
2555 case DPLANE_OP_SYS_ROUTE_ADD
:
2556 case DPLANE_OP_SYS_ROUTE_DELETE
:
2557 case DPLANE_OP_ADDR_INSTALL
:
2558 case DPLANE_OP_ADDR_UNINSTALL
:
2559 case DPLANE_OP_MAC_INSTALL
:
2560 case DPLANE_OP_MAC_DELETE
:
2561 case DPLANE_OP_NEIGH_INSTALL
:
2562 case DPLANE_OP_NEIGH_UPDATE
:
2563 case DPLANE_OP_NEIGH_DELETE
:
2564 case DPLANE_OP_VTEP_ADD
:
2565 case DPLANE_OP_VTEP_DELETE
:
2566 case DPLANE_OP_NONE
:
2570 dplane_ctx_fini(&ctx
);
2573 static void zebra_nhg_sweep_entry(struct hash_bucket
*bucket
, void *arg
)
2575 struct nhg_hash_entry
*nhe
= NULL
;
2577 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
2579 /* If its being ref'd, just let it be uninstalled via a route removal */
2580 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
2581 zebra_nhg_uninstall_kernel(nhe
);
2584 void zebra_nhg_sweep_table(struct hash
*hash
)
2586 hash_iterate(hash
, zebra_nhg_sweep_entry
, NULL
);
2589 /* Global control to disable use of kernel nexthops, if available. We can't
2590 * force the kernel to support nexthop ids, of course, but we can disable
2591 * zebra's use of them, for testing e.g. By default, if the kernel supports
2592 * nexthop ids, zebra uses them.
2594 void zebra_nhg_enable_kernel_nexthops(bool set
)
2596 g_nexthops_enabled
= set
;
2599 bool zebra_nhg_kernel_nexthops_enabled(void)
2601 return g_nexthops_enabled
;