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"
47 DEFINE_MTYPE_STATIC(ZEBRA
, NHG
, "Nexthop Group Entry");
48 DEFINE_MTYPE_STATIC(ZEBRA
, NHG_CONNECTED
, "Nexthop Group Connected");
49 DEFINE_MTYPE_STATIC(ZEBRA
, NHG_CTX
, "Nexthop Group Context");
51 /* Map backup nexthop indices between two nhes */
52 struct backup_nh_map_s
{
61 /* id counter to keep in sync with kernel */
64 /* Controlled through ui */
65 static bool g_nexthops_enabled
= true;
66 static bool proto_nexthops_only
;
67 static bool use_recursive_backups
= true;
69 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
,
70 int type
, bool from_dplane
);
71 static void depends_add(struct nhg_connected_tree_head
*head
,
72 struct nhg_hash_entry
*depend
);
73 static struct nhg_hash_entry
*
74 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
75 afi_t afi
, int type
, bool from_dplane
);
76 static struct nhg_hash_entry
*
77 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
);
78 static void depends_decrement_free(struct nhg_connected_tree_head
*head
);
80 static struct nhg_backup_info
*
81 nhg_backup_copy(const struct nhg_backup_info
*orig
);
83 /* Helper function for getting the next allocatable ID */
84 static uint32_t nhg_get_next_id(void)
89 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
90 zlog_debug("%s: ID %u checking", __func__
, id_counter
);
92 if (id_counter
== ZEBRA_NHG_PROTO_LOWER
) {
93 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
94 zlog_debug("%s: ID counter wrapped", __func__
);
100 if (zebra_nhg_lookup_id(id_counter
)) {
101 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
102 zlog_debug("%s: ID already exists", __func__
);
113 static void nhg_connected_free(struct nhg_connected
*dep
)
115 XFREE(MTYPE_NHG_CONNECTED
, dep
);
118 static struct nhg_connected
*nhg_connected_new(struct nhg_hash_entry
*nhe
)
120 struct nhg_connected
*new = NULL
;
122 new = XCALLOC(MTYPE_NHG_CONNECTED
, sizeof(struct nhg_connected
));
128 void nhg_connected_tree_free(struct nhg_connected_tree_head
*head
)
130 struct nhg_connected
*rb_node_dep
= NULL
;
132 if (!nhg_connected_tree_is_empty(head
)) {
133 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
134 nhg_connected_tree_del(head
, rb_node_dep
);
135 nhg_connected_free(rb_node_dep
);
140 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head
*head
)
142 return nhg_connected_tree_count(head
) ? false : true;
145 struct nhg_connected
*
146 nhg_connected_tree_root(struct nhg_connected_tree_head
*head
)
148 return nhg_connected_tree_first(head
);
151 struct nhg_hash_entry
*
152 nhg_connected_tree_del_nhe(struct nhg_connected_tree_head
*head
,
153 struct nhg_hash_entry
*depend
)
155 struct nhg_connected lookup
= {};
156 struct nhg_connected
*remove
= NULL
;
157 struct nhg_hash_entry
*removed_nhe
;
161 /* Lookup to find the element, then remove it */
162 remove
= nhg_connected_tree_find(head
, &lookup
);
164 /* Re-returning here just in case this API changes..
165 * the _del list api's are a bit undefined at the moment.
167 * So hopefully returning here will make it fail if the api
168 * changes to something different than currently expected.
170 remove
= nhg_connected_tree_del(head
, remove
);
172 /* If the entry was sucessfully removed, free the 'connected` struct */
174 removed_nhe
= remove
->nhe
;
175 nhg_connected_free(remove
);
182 /* Assuming UNIQUE RB tree. If this changes, assumptions here about
183 * insertion need to change.
185 struct nhg_hash_entry
*
186 nhg_connected_tree_add_nhe(struct nhg_connected_tree_head
*head
,
187 struct nhg_hash_entry
*depend
)
189 struct nhg_connected
*new = NULL
;
191 new = nhg_connected_new(depend
);
193 /* On success, NULL will be returned from the
196 if (new && (nhg_connected_tree_add(head
, new) == NULL
))
199 /* If it wasn't successful, it must be a duplicate. We enforce the
200 * unique property for the `nhg_connected` tree.
202 nhg_connected_free(new);
208 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head
*head
)
210 struct nhg_connected
*rb_node_dep
= NULL
;
212 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
213 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
218 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head
*head
)
220 struct nhg_connected
*rb_node_dep
= NULL
;
222 frr_each(nhg_connected_tree
, head
, rb_node_dep
) {
223 zebra_nhg_increment_ref(rb_node_dep
->nhe
);
227 struct nhg_hash_entry
*zebra_nhg_resolve(struct nhg_hash_entry
*nhe
)
229 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
)
230 && !zebra_nhg_depends_is_empty(nhe
)) {
231 nhe
= nhg_connected_tree_root(&nhe
->nhg_depends
)->nhe
;
232 return zebra_nhg_resolve(nhe
);
238 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry
*nhe
)
240 return nhg_connected_tree_count(&nhe
->nhg_depends
);
243 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry
*nhe
)
245 return nhg_connected_tree_is_empty(&nhe
->nhg_depends
);
248 static void zebra_nhg_depends_del(struct nhg_hash_entry
*from
,
249 struct nhg_hash_entry
*depend
)
251 nhg_connected_tree_del_nhe(&from
->nhg_depends
, depend
);
254 static void zebra_nhg_depends_init(struct nhg_hash_entry
*nhe
)
256 nhg_connected_tree_init(&nhe
->nhg_depends
);
259 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry
*nhe
)
261 return nhg_connected_tree_count(&nhe
->nhg_dependents
);
265 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry
*nhe
)
267 return nhg_connected_tree_is_empty(&nhe
->nhg_dependents
);
270 static void zebra_nhg_dependents_del(struct nhg_hash_entry
*from
,
271 struct nhg_hash_entry
*dependent
)
273 nhg_connected_tree_del_nhe(&from
->nhg_dependents
, dependent
);
276 static void zebra_nhg_dependents_add(struct nhg_hash_entry
*to
,
277 struct nhg_hash_entry
*dependent
)
279 nhg_connected_tree_add_nhe(&to
->nhg_dependents
, dependent
);
282 static void zebra_nhg_dependents_init(struct nhg_hash_entry
*nhe
)
284 nhg_connected_tree_init(&nhe
->nhg_dependents
);
287 /* Release this nhe from anything depending on it */
288 static void zebra_nhg_dependents_release(struct nhg_hash_entry
*nhe
)
290 struct nhg_connected
*rb_node_dep
= NULL
;
292 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
) {
293 zebra_nhg_depends_del(rb_node_dep
->nhe
, nhe
);
294 /* recheck validity of the dependent */
295 zebra_nhg_check_valid(rb_node_dep
->nhe
);
299 /* Release this nhe from anything that it depends on */
300 static void zebra_nhg_depends_release(struct nhg_hash_entry
*nhe
)
302 if (!zebra_nhg_depends_is_empty(nhe
)) {
303 struct nhg_connected
*rb_node_dep
= NULL
;
305 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_depends
,
307 zebra_nhg_dependents_del(rb_node_dep
->nhe
, nhe
);
313 struct nhg_hash_entry
*zebra_nhg_lookup_id(uint32_t id
)
315 struct nhg_hash_entry lookup
= {};
318 return hash_lookup(zrouter
.nhgs_id
, &lookup
);
321 static int zebra_nhg_insert_id(struct nhg_hash_entry
*nhe
)
323 if (hash_lookup(zrouter
.nhgs_id
, nhe
)) {
325 EC_ZEBRA_NHG_TABLE_INSERT_FAILED
,
326 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
331 hash_get(zrouter
.nhgs_id
, nhe
, hash_alloc_intern
);
336 static void zebra_nhg_set_if(struct nhg_hash_entry
*nhe
, struct interface
*ifp
)
339 if_nhg_dependents_add(ifp
, nhe
);
343 zebra_nhg_connect_depends(struct nhg_hash_entry
*nhe
,
344 struct nhg_connected_tree_head
*nhg_depends
)
346 struct nhg_connected
*rb_node_dep
= NULL
;
348 /* This has been allocated higher above in the stack. Could probably
349 * re-allocate and free the old stuff but just using the same memory
350 * for now. Otherwise, their might be a time trade-off for repeated
351 * alloc/frees as startup.
353 nhe
->nhg_depends
= *nhg_depends
;
355 /* Attach backpointer to anything that it depends on */
356 zebra_nhg_dependents_init(nhe
);
357 if (!zebra_nhg_depends_is_empty(nhe
)) {
358 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
359 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
360 zlog_debug("%s: nhe %p (%u), dep %p (%u)",
361 __func__
, nhe
, nhe
->id
,
363 rb_node_dep
->nhe
->id
);
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
));
456 /* Add the ifp now if it's not a group or recursive and has ifindex */
457 if (nhe
->nhg
.nexthop
&& nhe
->nhg
.nexthop
->ifindex
) {
458 struct interface
*ifp
= NULL
;
460 ifp
= if_lookup_by_index(nhe
->nhg
.nexthop
->ifindex
,
461 nhe
->nhg
.nexthop
->vrf_id
);
463 zebra_nhg_set_if(nhe
, ifp
);
465 if (IS_ZEBRA_DEBUG_NHG
)
467 "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
468 nhe
->nhg
.nexthop
->ifindex
,
469 nhe
->nhg
.nexthop
->vrf_id
, nhe
->id
);
476 uint32_t zebra_nhg_hash_key(const void *arg
)
478 const struct nhg_hash_entry
*nhe
= arg
;
479 uint32_t key
= 0x5a351234;
480 uint32_t primary
= 0;
483 primary
= nexthop_group_hash(&(nhe
->nhg
));
484 if (nhe
->backup_info
)
485 backup
= nexthop_group_hash(&(nhe
->backup_info
->nhe
->nhg
));
487 key
= jhash_3words(primary
, backup
, nhe
->type
, key
);
489 key
= jhash_2words(nhe
->vrf_id
, nhe
->afi
, key
);
494 uint32_t zebra_nhg_id_key(const void *arg
)
496 const struct nhg_hash_entry
*nhe
= arg
;
501 /* Helper with common nhg/nhe nexthop comparison logic */
502 static bool nhg_compare_nexthops(const struct nexthop
*nh1
,
503 const struct nexthop
*nh2
)
505 assert(nh1
!= NULL
&& nh2
!= NULL
);
508 * We have to check the active flag of each individual one,
509 * not just the overall active_num. This solves the special case
510 * issue of a route with a nexthop group with one nexthop
511 * resolving to itself and thus marking it inactive. If we
512 * have two different routes each wanting to mark a different
513 * nexthop inactive, they need to hash to two different groups.
515 * If we just hashed on num_active, they would hash the same
516 * which is incorrect.
520 * -> 1.1.1.1 dummy1 (inactive)
525 * -> 1.1.2.1 dummy2 (inactive)
527 * Without checking each individual one, they would hash to
528 * the same group and both have 1.1.1.1 dummy1 marked inactive.
531 if (CHECK_FLAG(nh1
->flags
, NEXTHOP_FLAG_ACTIVE
)
532 != CHECK_FLAG(nh2
->flags
, NEXTHOP_FLAG_ACTIVE
))
535 if (!nexthop_same(nh1
, nh2
))
541 bool zebra_nhg_hash_equal(const void *arg1
, const void *arg2
)
543 const struct nhg_hash_entry
*nhe1
= arg1
;
544 const struct nhg_hash_entry
*nhe2
= arg2
;
545 struct nexthop
*nexthop1
;
546 struct nexthop
*nexthop2
;
548 /* No matter what if they equal IDs, assume equal */
549 if (nhe1
->id
&& nhe2
->id
&& (nhe1
->id
== nhe2
->id
))
552 if (nhe1
->type
!= nhe2
->type
)
555 if (nhe1
->vrf_id
!= nhe2
->vrf_id
)
558 if (nhe1
->afi
!= nhe2
->afi
)
561 /* Nexthops should be in-order, so we simply compare them in-place */
562 for (nexthop1
= nhe1
->nhg
.nexthop
, nexthop2
= nhe2
->nhg
.nexthop
;
563 nexthop1
&& nexthop2
;
564 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
566 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
570 /* Check for unequal list lengths */
571 if (nexthop1
|| nexthop2
)
574 /* If there's no backup info, comparison is done. */
575 if ((nhe1
->backup_info
== NULL
) && (nhe2
->backup_info
== NULL
))
578 /* Compare backup info also - test the easy things first */
579 if (nhe1
->backup_info
&& (nhe2
->backup_info
== NULL
))
581 if (nhe2
->backup_info
&& (nhe1
->backup_info
== NULL
))
584 /* Compare number of backups before actually comparing any */
585 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
586 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
587 nexthop1
&& nexthop2
;
588 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
592 /* Did we find the end of one list before the other? */
593 if (nexthop1
|| nexthop2
)
596 /* Have to compare the backup nexthops */
597 for (nexthop1
= nhe1
->backup_info
->nhe
->nhg
.nexthop
,
598 nexthop2
= nhe2
->backup_info
->nhe
->nhg
.nexthop
;
599 nexthop1
&& nexthop2
;
600 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
602 if (!nhg_compare_nexthops(nexthop1
, nexthop2
))
609 bool zebra_nhg_hash_id_equal(const void *arg1
, const void *arg2
)
611 const struct nhg_hash_entry
*nhe1
= arg1
;
612 const struct nhg_hash_entry
*nhe2
= arg2
;
614 return nhe1
->id
== nhe2
->id
;
617 static int zebra_nhg_process_grp(struct nexthop_group
*nhg
,
618 struct nhg_connected_tree_head
*depends
,
619 struct nh_grp
*grp
, uint8_t count
)
621 nhg_connected_tree_init(depends
);
623 for (int i
= 0; i
< count
; i
++) {
624 struct nhg_hash_entry
*depend
= NULL
;
625 /* We do not care about nexthop_grp.weight at
626 * this time. But we should figure out
627 * how to adapt this to our code in
630 depend
= depends_find_id_add(depends
, grp
[i
].id
);
635 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
641 * If this is a nexthop with its own group
642 * dependencies, add them as well. Not sure its
643 * even possible to have a group within a group
647 copy_nexthops(&nhg
->nexthop
, depend
->nhg
.nexthop
, NULL
);
653 static void handle_recursive_depend(struct nhg_connected_tree_head
*nhg_depends
,
654 struct nexthop
*nh
, afi_t afi
, int type
)
656 struct nhg_hash_entry
*depend
= NULL
;
657 struct nexthop_group resolved_ng
= {};
659 resolved_ng
.nexthop
= nh
;
661 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
662 zlog_debug("%s: head %p, nh %pNHv",
663 __func__
, nhg_depends
, nh
);
665 depend
= zebra_nhg_rib_find(0, &resolved_ng
, afi
, type
);
667 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
668 zlog_debug("%s: nh %pNHv => %p (%u)",
669 __func__
, nh
, depend
,
670 depend
? depend
->id
: 0);
673 depends_add(nhg_depends
, depend
);
677 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
678 * has an id value, that's used. Create a new global/shared nhe if not found.
680 static bool zebra_nhe_find(struct nhg_hash_entry
**nhe
, /* return value */
681 struct nhg_hash_entry
*lookup
,
682 struct nhg_connected_tree_head
*nhg_depends
,
683 afi_t afi
, bool from_dplane
)
685 bool created
= false;
686 bool recursive
= false;
687 struct nhg_hash_entry
*newnhe
, *backup_nhe
;
688 struct nexthop
*nh
= NULL
;
690 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
692 "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s",
693 __func__
, lookup
->id
, lookup
, lookup
->vrf_id
,
694 lookup
->type
, nhg_depends
,
695 (from_dplane
? " (from dplane)" : ""));
698 (*nhe
) = zebra_nhg_lookup_id(lookup
->id
);
700 (*nhe
) = hash_lookup(zrouter
.nhgs
, lookup
);
702 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
703 zlog_debug("%s: lookup => %p (%u)",
705 (*nhe
) ? (*nhe
)->id
: 0);
707 /* If we found an existing object, we're done */
711 /* We're going to create/insert a new nhe:
712 * assign the next global id value if necessary.
715 lookup
->id
= nhg_get_next_id();
717 if (!from_dplane
&& lookup
->id
< ZEBRA_NHG_PROTO_LOWER
) {
719 * This is a zebra hashed/owned NHG.
721 * It goes in HASH and ID table.
723 newnhe
= hash_get(zrouter
.nhgs
, lookup
, zebra_nhg_hash_alloc
);
724 zebra_nhg_insert_id(newnhe
);
727 * This is upperproto owned NHG or one we read in from dataplane
728 * and should not be hashed to.
730 * It goes in ID table.
733 hash_get(zrouter
.nhgs_id
, lookup
, zebra_nhg_hash_alloc
);
738 /* Mail back the new object */
741 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
742 zlog_debug("%s: => created %p (%u)", __func__
, newnhe
,
745 /* Only hash/lookup the depends if the first lookup
746 * fails to find something. This should hopefully save a
747 * lot of cycles for larger ecmp sizes.
750 /* If you don't want to hash on each nexthop in the
751 * nexthop group struct you can pass the depends
752 * directly. Kernel-side we do this since it just looks
755 zebra_nhg_connect_depends(newnhe
, nhg_depends
);
759 /* Prepare dependency relationships if this is not a
760 * singleton nexthop. There are two cases: a single
761 * recursive nexthop, where we need a relationship to the
762 * resolving nexthop; or a group of nexthops, where we need
763 * relationships with the corresponding singletons.
765 zebra_nhg_depends_init(newnhe
);
767 nh
= newnhe
->nhg
.nexthop
;
769 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
))
770 SET_FLAG(newnhe
->flags
, NEXTHOP_GROUP_VALID
);
772 if (nh
->next
== NULL
&& newnhe
->id
< ZEBRA_NHG_PROTO_LOWER
) {
773 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
774 /* Single recursive nexthop */
775 handle_recursive_depend(&newnhe
->nhg_depends
,
781 /* Proto-owned are groups by default */
782 /* List of nexthops */
783 for (nh
= newnhe
->nhg
.nexthop
; nh
; nh
= nh
->next
) {
784 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
785 zlog_debug("%s: depends NH %pNHv %s",
787 CHECK_FLAG(nh
->flags
,
788 NEXTHOP_FLAG_RECURSIVE
) ?
791 depends_find_add(&newnhe
->nhg_depends
, nh
, afi
,
792 newnhe
->type
, from_dplane
);
797 SET_FLAG(newnhe
->flags
, NEXTHOP_GROUP_RECURSIVE
);
799 /* Attach dependent backpointers to singletons */
800 zebra_nhg_connect_depends(newnhe
, &newnhe
->nhg_depends
);
806 if (zebra_nhg_get_backup_nhg(newnhe
) == NULL
||
807 zebra_nhg_get_backup_nhg(newnhe
)->nexthop
== NULL
)
810 /* If there are backup nexthops, add them to the backup
811 * depends tree. The rules here are a little different.
814 backup_nhe
= newnhe
->backup_info
->nhe
;
816 nh
= backup_nhe
->nhg
.nexthop
;
818 /* Singleton recursive NH */
819 if (nh
->next
== NULL
&&
820 CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
)) {
821 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
822 zlog_debug("%s: backup depend NH %pNHv (R)",
825 /* Single recursive nexthop */
826 handle_recursive_depend(&backup_nhe
->nhg_depends
, nh
->resolved
,
827 afi
, backup_nhe
->type
);
830 /* One or more backup NHs */
831 for (; nh
; nh
= nh
->next
) {
832 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
833 zlog_debug("%s: backup depend NH %pNHv %s",
835 CHECK_FLAG(nh
->flags
,
836 NEXTHOP_FLAG_RECURSIVE
) ?
839 depends_find_add(&backup_nhe
->nhg_depends
, nh
, afi
,
840 backup_nhe
->type
, from_dplane
);
845 SET_FLAG(backup_nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
);
853 * Lookup or create an nhe, based on an nhg or an nhe id.
855 static bool zebra_nhg_find(struct nhg_hash_entry
**nhe
, uint32_t id
,
856 struct nexthop_group
*nhg
,
857 struct nhg_connected_tree_head
*nhg_depends
,
858 vrf_id_t vrf_id
, afi_t afi
, int type
,
861 struct nhg_hash_entry lookup
= {};
862 bool created
= false;
864 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
865 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
866 __func__
, id
, nhg
, vrf_id
, type
,
869 /* Use a temporary nhe and call into the superset/common code */
871 lookup
.type
= type
? type
: ZEBRA_ROUTE_NHG
;
874 lookup
.vrf_id
= vrf_id
;
875 if (nhg_depends
|| lookup
.nhg
.nexthop
->next
) {
876 /* Groups can have all vrfs and AF's in them */
877 lookup
.afi
= AFI_UNSPEC
;
879 switch (lookup
.nhg
.nexthop
->type
) {
880 case (NEXTHOP_TYPE_IFINDEX
):
881 case (NEXTHOP_TYPE_BLACKHOLE
):
883 * This switch case handles setting the afi different
884 * for ipv4/v6 routes. Ifindex/blackhole nexthop
885 * objects cannot be ambiguous, they must be Address
886 * Family specific. If we get here, we will either use
887 * the AF of the route, or the one we got passed from
888 * here from the kernel.
892 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
893 case (NEXTHOP_TYPE_IPV4
):
896 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
897 case (NEXTHOP_TYPE_IPV6
):
898 lookup
.afi
= AFI_IP6
;
903 created
= zebra_nhe_find(nhe
, &lookup
, nhg_depends
, afi
, from_dplane
);
908 /* Find/create a single nexthop */
909 static struct nhg_hash_entry
*zebra_nhg_find_nexthop(uint32_t id
,
914 struct nhg_hash_entry
*nhe
= NULL
;
915 struct nexthop_group nhg
= {};
916 vrf_id_t vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nh
->vrf_id
;
918 nexthop_group_add_sorted(&nhg
, nh
);
920 zebra_nhg_find(&nhe
, id
, &nhg
, NULL
, vrf_id
, afi
, type
, from_dplane
);
922 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
923 zlog_debug("%s: nh %pNHv => %p (%u)",
924 __func__
, nh
, nhe
, nhe
? nhe
->id
: 0);
929 static uint32_t nhg_ctx_get_id(const struct nhg_ctx
*ctx
)
934 static void nhg_ctx_set_status(struct nhg_ctx
*ctx
, enum nhg_ctx_status status
)
936 ctx
->status
= status
;
939 static enum nhg_ctx_status
nhg_ctx_get_status(const struct nhg_ctx
*ctx
)
944 static void nhg_ctx_set_op(struct nhg_ctx
*ctx
, enum nhg_ctx_op_e op
)
949 static enum nhg_ctx_op_e
nhg_ctx_get_op(const struct nhg_ctx
*ctx
)
954 static vrf_id_t
nhg_ctx_get_vrf_id(const struct nhg_ctx
*ctx
)
959 static int nhg_ctx_get_type(const struct nhg_ctx
*ctx
)
964 static int nhg_ctx_get_afi(const struct nhg_ctx
*ctx
)
969 static struct nexthop
*nhg_ctx_get_nh(struct nhg_ctx
*ctx
)
974 static uint8_t nhg_ctx_get_count(const struct nhg_ctx
*ctx
)
979 static struct nh_grp
*nhg_ctx_get_grp(struct nhg_ctx
*ctx
)
984 static struct nhg_ctx
*nhg_ctx_new(void)
988 new = XCALLOC(MTYPE_NHG_CTX
, sizeof(struct nhg_ctx
));
993 static void nhg_ctx_free(struct nhg_ctx
**ctx
)
1000 assert((*ctx
) != NULL
);
1002 if (nhg_ctx_get_count(*ctx
))
1005 nh
= nhg_ctx_get_nh(*ctx
);
1007 nexthop_del_labels(nh
);
1010 XFREE(MTYPE_NHG_CTX
, *ctx
);
1013 static struct nhg_ctx
*nhg_ctx_init(uint32_t id
, struct nexthop
*nh
,
1014 struct nh_grp
*grp
, vrf_id_t vrf_id
,
1015 afi_t afi
, int type
, uint8_t count
)
1017 struct nhg_ctx
*ctx
= NULL
;
1019 ctx
= nhg_ctx_new();
1022 ctx
->vrf_id
= vrf_id
;
1028 /* Copy over the array */
1029 memcpy(&ctx
->u
.grp
, grp
, count
* sizeof(struct nh_grp
));
1036 static void zebra_nhg_set_valid(struct nhg_hash_entry
*nhe
)
1038 struct nhg_connected
*rb_node_dep
;
1040 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1042 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1043 zebra_nhg_set_valid(rb_node_dep
->nhe
);
1046 static void zebra_nhg_set_invalid(struct nhg_hash_entry
*nhe
)
1048 struct nhg_connected
*rb_node_dep
;
1050 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1052 /* Update validity of nexthops depending on it */
1053 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1054 zebra_nhg_check_valid(rb_node_dep
->nhe
);
1057 void zebra_nhg_check_valid(struct nhg_hash_entry
*nhe
)
1059 struct nhg_connected
*rb_node_dep
= NULL
;
1062 /* If anthing else in the group is valid, the group is valid */
1063 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1064 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
, NEXTHOP_GROUP_VALID
)) {
1072 zebra_nhg_set_valid(nhe
);
1074 zebra_nhg_set_invalid(nhe
);
1077 static void zebra_nhg_release_all_deps(struct nhg_hash_entry
*nhe
)
1079 /* Remove it from any lists it may be on */
1080 zebra_nhg_depends_release(nhe
);
1081 zebra_nhg_dependents_release(nhe
);
1083 if_nhg_dependents_del(nhe
->ifp
, nhe
);
1086 static void zebra_nhg_release(struct nhg_hash_entry
*nhe
)
1088 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1089 zlog_debug("%s: nhe %p (%u)", __func__
, nhe
, nhe
->id
);
1091 zebra_nhg_release_all_deps(nhe
);
1094 * If its not zebra owned, we didn't store it here and have to be
1095 * sure we don't clear one thats actually being used.
1097 if (nhe
->id
< ZEBRA_NHG_PROTO_LOWER
)
1098 hash_release(zrouter
.nhgs
, nhe
);
1100 hash_release(zrouter
.nhgs_id
, nhe
);
1103 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry
*nhe
)
1105 zebra_nhg_release(nhe
);
1106 zebra_nhg_free(nhe
);
1109 static void zebra_nhg_handle_install(struct nhg_hash_entry
*nhe
)
1111 /* Update validity of groups depending on it */
1112 struct nhg_connected
*rb_node_dep
;
1114 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
1115 zebra_nhg_set_valid(rb_node_dep
->nhe
);
1119 * The kernel/other program has changed the state of a nexthop object we are
1122 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry
*nhe
,
1128 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
1129 (is_delete
? "deleted" : "updated"), nhe
->id
);
1131 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1132 zebra_nhg_install_kernel(nhe
);
1134 zebra_nhg_handle_uninstall(nhe
);
1137 static int nhg_ctx_process_new(struct nhg_ctx
*ctx
)
1139 struct nexthop_group
*nhg
= NULL
;
1140 struct nhg_connected_tree_head nhg_depends
= {};
1141 struct nhg_hash_entry
*lookup
= NULL
;
1142 struct nhg_hash_entry
*nhe
= NULL
;
1144 uint32_t id
= nhg_ctx_get_id(ctx
);
1145 uint8_t count
= nhg_ctx_get_count(ctx
);
1146 vrf_id_t vrf_id
= nhg_ctx_get_vrf_id(ctx
);
1147 int type
= nhg_ctx_get_type(ctx
);
1148 afi_t afi
= nhg_ctx_get_afi(ctx
);
1150 lookup
= zebra_nhg_lookup_id(id
);
1152 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1153 zlog_debug("%s: id %u, count %d, lookup => %p",
1154 __func__
, id
, count
, lookup
);
1157 /* This is already present in our table, hence an update
1158 * that we did not initate.
1160 zebra_nhg_handle_kernel_state_change(lookup
, false);
1164 if (nhg_ctx_get_count(ctx
)) {
1165 nhg
= nexthop_group_new();
1166 if (zebra_nhg_process_grp(nhg
, &nhg_depends
,
1167 nhg_ctx_get_grp(ctx
), count
)) {
1168 depends_decrement_free(&nhg_depends
);
1169 nexthop_group_delete(&nhg
);
1173 if (!zebra_nhg_find(&nhe
, id
, nhg
, &nhg_depends
, vrf_id
, afi
,
1175 depends_decrement_free(&nhg_depends
);
1177 /* These got copied over in zebra_nhg_alloc() */
1178 nexthop_group_delete(&nhg
);
1180 nhe
= zebra_nhg_find_nexthop(id
, nhg_ctx_get_nh(ctx
), afi
, type
,
1185 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1186 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
1191 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1192 zlog_debug("%s: nhe %p (%u) is new", __func__
, nhe
, nhe
->id
);
1194 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1195 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1200 static int nhg_ctx_process_del(struct nhg_ctx
*ctx
)
1202 struct nhg_hash_entry
*nhe
= NULL
;
1203 uint32_t id
= nhg_ctx_get_id(ctx
);
1205 nhe
= zebra_nhg_lookup_id(id
);
1209 EC_ZEBRA_BAD_NHG_MESSAGE
,
1210 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
1215 zebra_nhg_handle_kernel_state_change(nhe
, true);
1220 static void nhg_ctx_fini(struct nhg_ctx
**ctx
)
1223 * Just freeing for now, maybe do something more in the future
1230 static int queue_add(struct nhg_ctx
*ctx
)
1232 /* If its queued or already processed do nothing */
1233 if (nhg_ctx_get_status(ctx
) == NHG_CTX_QUEUED
)
1236 if (rib_queue_nhg_add(ctx
)) {
1237 nhg_ctx_set_status(ctx
, NHG_CTX_FAILURE
);
1241 nhg_ctx_set_status(ctx
, NHG_CTX_QUEUED
);
1246 int nhg_ctx_process(struct nhg_ctx
*ctx
)
1250 switch (nhg_ctx_get_op(ctx
)) {
1251 case NHG_CTX_OP_NEW
:
1252 ret
= nhg_ctx_process_new(ctx
);
1253 if (nhg_ctx_get_count(ctx
) && ret
== -ENOENT
1254 && nhg_ctx_get_status(ctx
) != NHG_CTX_REQUEUED
) {
1256 * We have entered a situation where we are
1257 * processing a group from the kernel
1258 * that has a contained nexthop which
1259 * we have not yet processed.
1261 * Re-enqueue this ctx to be handled exactly one
1262 * more time (indicated by the flag).
1264 * By the time we get back to it, we
1265 * should have processed its depends.
1267 nhg_ctx_set_status(ctx
, NHG_CTX_NONE
);
1268 if (queue_add(ctx
) == 0) {
1269 nhg_ctx_set_status(ctx
, NHG_CTX_REQUEUED
);
1274 case NHG_CTX_OP_DEL
:
1275 ret
= nhg_ctx_process_del(ctx
);
1276 case NHG_CTX_OP_NONE
:
1280 nhg_ctx_set_status(ctx
, (ret
? NHG_CTX_FAILURE
: NHG_CTX_SUCCESS
));
1287 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1288 int zebra_nhg_kernel_find(uint32_t id
, struct nexthop
*nh
, struct nh_grp
*grp
,
1289 uint8_t count
, vrf_id_t vrf_id
, afi_t afi
, int type
,
1292 struct nhg_ctx
*ctx
= NULL
;
1294 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1295 zlog_debug("%s: nh %pNHv, id %u, count %d",
1296 __func__
, nh
, id
, (int)count
);
1298 if (id
> id_counter
&& id
< ZEBRA_NHG_PROTO_LOWER
)
1299 /* Increase our counter so we don't try to create
1300 * an ID that already exists
1304 ctx
= nhg_ctx_init(id
, nh
, grp
, vrf_id
, afi
, type
, count
);
1305 nhg_ctx_set_op(ctx
, NHG_CTX_OP_NEW
);
1307 /* Under statup conditions, we need to handle them immediately
1308 * like we do for routes. Otherwise, we are going to get a route
1309 * with a nhe_id that we have not handled.
1312 return nhg_ctx_process(ctx
);
1314 if (queue_add(ctx
)) {
1322 /* Kernel-side, received delete message */
1323 int zebra_nhg_kernel_del(uint32_t id
, vrf_id_t vrf_id
)
1325 struct nhg_ctx
*ctx
= NULL
;
1327 ctx
= nhg_ctx_init(id
, NULL
, NULL
, vrf_id
, 0, 0, 0);
1329 nhg_ctx_set_op(ctx
, NHG_CTX_OP_DEL
);
1331 if (queue_add(ctx
)) {
1339 /* Some dependency helper functions */
1340 static struct nhg_hash_entry
*depends_find_recursive(const struct nexthop
*nh
,
1341 afi_t afi
, int type
)
1343 struct nhg_hash_entry
*nhe
;
1344 struct nexthop
*lookup
= NULL
;
1346 lookup
= nexthop_dup(nh
, NULL
);
1348 nhe
= zebra_nhg_find_nexthop(0, lookup
, afi
, type
, false);
1350 nexthops_free(lookup
);
1355 static struct nhg_hash_entry
*depends_find_singleton(const struct nexthop
*nh
,
1356 afi_t afi
, int type
,
1359 struct nhg_hash_entry
*nhe
;
1360 struct nexthop lookup
= {};
1362 /* Capture a snapshot of this single nh; it might be part of a list,
1363 * so we need to make a standalone copy.
1365 nexthop_copy_no_recurse(&lookup
, nh
, NULL
);
1367 nhe
= zebra_nhg_find_nexthop(0, &lookup
, afi
, type
, from_dplane
);
1369 /* The copy may have allocated labels; free them if necessary. */
1370 nexthop_del_labels(&lookup
);
1372 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1373 zlog_debug("%s: nh %pNHv => %p (%u)",
1374 __func__
, nh
, nhe
, nhe
? nhe
->id
: 0);
1379 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
,
1380 int type
, bool from_dplane
)
1382 struct nhg_hash_entry
*nhe
= NULL
;
1387 /* We are separating these functions out to increase handling speed
1388 * in the non-recursive case (by not alloc/freeing)
1390 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1391 nhe
= depends_find_recursive(nh
, afi
, type
);
1393 nhe
= depends_find_singleton(nh
, afi
, type
, from_dplane
);
1396 if (IS_ZEBRA_DEBUG_NHG_DETAIL
) {
1397 zlog_debug("%s: nh %pNHv %s => %p (%u)", __func__
, nh
,
1398 CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
) ? "(R)"
1400 nhe
, nhe
? nhe
->id
: 0);
1407 static void depends_add(struct nhg_connected_tree_head
*head
,
1408 struct nhg_hash_entry
*depend
)
1410 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1411 zlog_debug("%s: head %p nh %pNHv",
1412 __func__
, head
, depend
->nhg
.nexthop
);
1414 /* If NULL is returned, it was successfully added and
1415 * needs to have its refcnt incremented.
1417 * Else the NHE is already present in the tree and doesn't
1418 * need to increment the refcnt.
1420 if (nhg_connected_tree_add_nhe(head
, depend
) == NULL
)
1421 zebra_nhg_increment_ref(depend
);
1424 static struct nhg_hash_entry
*
1425 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
1426 afi_t afi
, int type
, bool from_dplane
)
1428 struct nhg_hash_entry
*depend
= NULL
;
1430 depend
= depends_find(nh
, afi
, type
, from_dplane
);
1432 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1433 zlog_debug("%s: nh %pNHv => %p",
1434 __func__
, nh
, depend
);
1437 depends_add(head
, depend
);
1442 static struct nhg_hash_entry
*
1443 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
)
1445 struct nhg_hash_entry
*depend
= NULL
;
1447 depend
= zebra_nhg_lookup_id(id
);
1450 depends_add(head
, depend
);
1455 static void depends_decrement_free(struct nhg_connected_tree_head
*head
)
1457 nhg_connected_tree_decrement_ref(head
);
1458 nhg_connected_tree_free(head
);
1461 /* Find an nhe based on a list of nexthops */
1462 struct nhg_hash_entry
*zebra_nhg_rib_find(uint32_t id
,
1463 struct nexthop_group
*nhg
,
1464 afi_t rt_afi
, int type
)
1466 struct nhg_hash_entry
*nhe
= NULL
;
1470 * CLANG SA is complaining that nexthop may be NULL
1471 * Make it happy but this is ridonc
1473 assert(nhg
->nexthop
);
1474 vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nhg
->nexthop
->vrf_id
;
1476 zebra_nhg_find(&nhe
, id
, nhg
, NULL
, vrf_id
, rt_afi
, type
, false);
1478 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1479 zlog_debug("%s: => nhe %p (%u)",
1480 __func__
, nhe
, nhe
? nhe
->id
: 0);
1485 /* Find an nhe based on a route's nhe */
1486 struct nhg_hash_entry
*
1487 zebra_nhg_rib_find_nhe(struct nhg_hash_entry
*rt_nhe
, afi_t rt_afi
)
1489 struct nhg_hash_entry
*nhe
= NULL
;
1491 if (!(rt_nhe
&& rt_nhe
->nhg
.nexthop
)) {
1492 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1493 "No nexthop passed to %s", __func__
);
1497 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1498 zlog_debug("%s: rt_nhe %p (%u)", __func__
, rt_nhe
, rt_nhe
->id
);
1500 zebra_nhe_find(&nhe
, rt_nhe
, NULL
, rt_afi
, false);
1502 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1503 zlog_debug("%s: => nhe %p (%u)",
1504 __func__
, nhe
, nhe
? nhe
->id
: 0);
1510 * Allocate backup nexthop info object. Typically these are embedded in
1511 * nhg_hash_entry objects.
1513 struct nhg_backup_info
*zebra_nhg_backup_alloc(void)
1515 struct nhg_backup_info
*p
;
1517 p
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_backup_info
));
1519 p
->nhe
= zebra_nhg_alloc();
1521 /* Identify the embedded group used to hold the list of backups */
1522 SET_FLAG(p
->nhe
->flags
, NEXTHOP_GROUP_BACKUP
);
1528 * Free backup nexthop info object, deal with any embedded allocations
1530 void zebra_nhg_backup_free(struct nhg_backup_info
**p
)
1534 zebra_nhg_free((*p
)->nhe
);
1536 XFREE(MTYPE_NHG
, (*p
));
1540 /* Accessor for backup nexthop group */
1541 struct nexthop_group
*zebra_nhg_get_backup_nhg(struct nhg_hash_entry
*nhe
)
1543 struct nexthop_group
*p
= NULL
;
1546 if (nhe
->backup_info
&& nhe
->backup_info
->nhe
)
1547 p
= &(nhe
->backup_info
->nhe
->nhg
);
1554 * Helper to return a copy of a backup_info - note that this is a shallow
1555 * copy, meant to be used when creating a new nhe from info passed in with
1558 static struct nhg_backup_info
*
1559 nhg_backup_copy(const struct nhg_backup_info
*orig
)
1561 struct nhg_backup_info
*b
;
1563 b
= zebra_nhg_backup_alloc();
1565 /* Copy list of nexthops */
1566 nexthop_group_copy(&(b
->nhe
->nhg
), &(orig
->nhe
->nhg
));
1571 static void zebra_nhg_free_members(struct nhg_hash_entry
*nhe
)
1573 nexthops_free(nhe
->nhg
.nexthop
);
1575 zebra_nhg_backup_free(&nhe
->backup_info
);
1577 /* Decrement to remove connection ref */
1578 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1579 nhg_connected_tree_free(&nhe
->nhg_depends
);
1580 nhg_connected_tree_free(&nhe
->nhg_dependents
);
1583 void zebra_nhg_free(struct nhg_hash_entry
*nhe
)
1585 if (IS_ZEBRA_DEBUG_NHG_DETAIL
) {
1586 /* Group or singleton? */
1587 if (nhe
->nhg
.nexthop
&& nhe
->nhg
.nexthop
->next
)
1588 zlog_debug("%s: nhe %p (%u), refcnt %d",
1589 __func__
, nhe
, nhe
->id
, nhe
->refcnt
);
1591 zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
1592 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1597 zlog_debug("nhe_id=%u hash refcnt=%d", nhe
->id
, nhe
->refcnt
);
1599 zebra_nhg_free_members(nhe
);
1601 XFREE(MTYPE_NHG
, nhe
);
1604 void zebra_nhg_hash_free(void *p
)
1606 zebra_nhg_release_all_deps((struct nhg_hash_entry
*)p
);
1607 zebra_nhg_free((struct nhg_hash_entry
*)p
);
1610 void zebra_nhg_decrement_ref(struct nhg_hash_entry
*nhe
)
1612 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1613 zlog_debug("%s: nhe %p (%u) %d => %d",
1614 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1619 if (!zebra_nhg_depends_is_empty(nhe
))
1620 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1622 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1623 zebra_nhg_uninstall_kernel(nhe
);
1626 void zebra_nhg_increment_ref(struct nhg_hash_entry
*nhe
)
1628 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
1629 zlog_debug("%s: nhe %p (%u) %d => %d",
1630 __func__
, nhe
, nhe
->id
, nhe
->refcnt
,
1635 if (!zebra_nhg_depends_is_empty(nhe
))
1636 nhg_connected_tree_increment_ref(&nhe
->nhg_depends
);
1639 static struct nexthop
*nexthop_set_resolved(afi_t afi
,
1640 const struct nexthop
*newhop
,
1641 struct nexthop
*nexthop
,
1642 struct zebra_sr_policy
*policy
)
1644 struct nexthop
*resolved_hop
;
1645 uint8_t num_labels
= 0;
1646 mpls_label_t labels
[MPLS_MAX_LABELS
];
1647 enum lsp_types_t label_type
= ZEBRA_LSP_NONE
;
1650 resolved_hop
= nexthop_new();
1651 SET_FLAG(resolved_hop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1653 resolved_hop
->vrf_id
= nexthop
->vrf_id
;
1654 switch (newhop
->type
) {
1655 case NEXTHOP_TYPE_IPV4
:
1656 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1657 /* If the resolving route specifies a gateway, use it */
1658 resolved_hop
->type
= newhop
->type
;
1659 resolved_hop
->gate
.ipv4
= newhop
->gate
.ipv4
;
1661 if (newhop
->ifindex
) {
1662 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1663 resolved_hop
->ifindex
= newhop
->ifindex
;
1666 case NEXTHOP_TYPE_IPV6
:
1667 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1668 resolved_hop
->type
= newhop
->type
;
1669 resolved_hop
->gate
.ipv6
= newhop
->gate
.ipv6
;
1671 if (newhop
->ifindex
) {
1672 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1673 resolved_hop
->ifindex
= newhop
->ifindex
;
1676 case NEXTHOP_TYPE_IFINDEX
:
1677 /* If the resolving route is an interface route,
1678 * it means the gateway we are looking up is connected
1679 * to that interface. (The actual network is _not_ onlink).
1680 * Therefore, the resolved route should have the original
1681 * gateway as nexthop as it is directly connected.
1683 * On Linux, we have to set the onlink netlink flag because
1684 * otherwise, the kernel won't accept the route.
1686 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1687 if (afi
== AFI_IP
) {
1688 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1689 resolved_hop
->gate
.ipv4
= nexthop
->gate
.ipv4
;
1690 } else if (afi
== AFI_IP6
) {
1691 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1692 resolved_hop
->gate
.ipv6
= nexthop
->gate
.ipv6
;
1694 resolved_hop
->ifindex
= newhop
->ifindex
;
1696 case NEXTHOP_TYPE_BLACKHOLE
:
1697 resolved_hop
->type
= NEXTHOP_TYPE_BLACKHOLE
;
1698 resolved_hop
->bh_type
= newhop
->bh_type
;
1702 if (newhop
->flags
& NEXTHOP_FLAG_ONLINK
)
1703 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1705 /* Copy labels of the resolved route and the parent resolving to it */
1710 * Don't push the first SID if the corresponding action in the
1713 if (!newhop
->nh_label
|| !newhop
->nh_label
->num_labels
1714 || newhop
->nh_label
->label
[0] == MPLS_LABEL_IMPLICIT_NULL
)
1717 for (; i
< policy
->segment_list
.label_num
; i
++)
1718 labels
[num_labels
++] = policy
->segment_list
.labels
[i
];
1719 label_type
= policy
->segment_list
.type
;
1720 } else if (newhop
->nh_label
) {
1721 for (i
= 0; i
< newhop
->nh_label
->num_labels
; i
++) {
1722 /* Be a bit picky about overrunning the local array */
1723 if (num_labels
>= MPLS_MAX_LABELS
) {
1724 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1725 zlog_debug("%s: too many labels in newhop %pNHv",
1729 labels
[num_labels
++] = newhop
->nh_label
->label
[i
];
1731 /* Use the "outer" type */
1732 label_type
= newhop
->nh_label_type
;
1735 if (nexthop
->nh_label
) {
1736 for (i
= 0; i
< nexthop
->nh_label
->num_labels
; i
++) {
1737 /* Be a bit picky about overrunning the local array */
1738 if (num_labels
>= MPLS_MAX_LABELS
) {
1739 if (IS_ZEBRA_DEBUG_NHG
|| IS_ZEBRA_DEBUG_RIB
)
1740 zlog_debug("%s: too many labels in nexthop %pNHv",
1744 labels
[num_labels
++] = nexthop
->nh_label
->label
[i
];
1747 /* If the parent has labels, use its type if
1748 * we don't already have one.
1750 if (label_type
== ZEBRA_LSP_NONE
)
1751 label_type
= nexthop
->nh_label_type
;
1755 nexthop_add_labels(resolved_hop
, label_type
, num_labels
,
1758 resolved_hop
->rparent
= nexthop
;
1759 _nexthop_add(&nexthop
->resolved
, resolved_hop
);
1761 return resolved_hop
;
1764 /* Checks if nexthop we are trying to resolve to is valid */
1765 static bool nexthop_valid_resolve(const struct nexthop
*nexthop
,
1766 const struct nexthop
*resolved
)
1768 /* Can't resolve to a recursive nexthop */
1769 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1772 /* Must be ACTIVE */
1773 if (!CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_ACTIVE
))
1776 /* Must not be duplicate */
1777 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_DUPLICATE
))
1780 switch (nexthop
->type
) {
1781 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1782 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1783 /* If the nexthop we are resolving to does not match the
1784 * ifindex for the nexthop the route wanted, its not valid.
1786 if (nexthop
->ifindex
!= resolved
->ifindex
)
1789 case NEXTHOP_TYPE_IPV4
:
1790 case NEXTHOP_TYPE_IPV6
:
1791 case NEXTHOP_TYPE_IFINDEX
:
1792 case NEXTHOP_TYPE_BLACKHOLE
:
1800 * When resolving a recursive nexthop, capture backup nexthop(s) also
1801 * so they can be conveyed through the dataplane to the FIB. We'll look
1802 * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
1803 * into the route's resolved nh 'resolved' and its nhe 'nhe'.
1805 static int resolve_backup_nexthops(const struct nexthop
*nexthop
,
1806 const struct nhg_hash_entry
*nhe
,
1807 struct nexthop
*resolved
,
1808 struct nhg_hash_entry
*resolve_nhe
,
1809 struct backup_nh_map_s
*map
)
1812 const struct nexthop
*bnh
;
1813 struct nexthop
*nh
, *newnh
;
1814 mpls_label_t labels
[MPLS_MAX_LABELS
];
1817 assert(nexthop
->backup_num
<= NEXTHOP_MAX_BACKUPS
);
1819 /* Locate backups from the original nexthop's backup index and nhe */
1820 for (i
= 0; i
< nexthop
->backup_num
; i
++) {
1821 idx
= nexthop
->backup_idx
[i
];
1823 /* Do we already know about this particular backup? */
1824 for (j
= 0; j
< map
->map_count
; j
++) {
1825 if (map
->map
[j
].orig_idx
== idx
)
1829 if (j
< map
->map_count
) {
1830 resolved
->backup_idx
[resolved
->backup_num
] =
1831 map
->map
[j
].new_idx
;
1832 resolved
->backup_num
++;
1834 SET_FLAG(resolved
->flags
, NEXTHOP_FLAG_HAS_BACKUP
);
1836 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1837 zlog_debug("%s: found map idx orig %d, new %d",
1838 __func__
, map
->map
[j
].orig_idx
,
1839 map
->map
[j
].new_idx
);
1844 /* We can't handle any new map entries at this point. */
1845 if (map
->map_count
== MULTIPATH_NUM
)
1848 /* Need to create/copy a new backup */
1849 bnh
= nhe
->backup_info
->nhe
->nhg
.nexthop
;
1850 for (j
= 0; j
< idx
; j
++) {
1856 /* Whoops - bad index in the nexthop? */
1860 if (resolve_nhe
->backup_info
== NULL
)
1861 resolve_nhe
->backup_info
= zebra_nhg_backup_alloc();
1863 /* Update backup info in the resolving nexthop and its nhe */
1864 newnh
= nexthop_dup_no_recurse(bnh
, NULL
);
1866 /* We may need some special handling for mpls labels: the new
1867 * backup needs to carry the recursive nexthop's labels,
1868 * if any: they may be vrf labels e.g.
1869 * The original/inner labels are in the stack of 'resolve_nhe',
1870 * if that is longer than the stack in 'nexthop'.
1872 if (newnh
->nh_label
&& resolved
->nh_label
&&
1873 nexthop
->nh_label
) {
1874 if (resolved
->nh_label
->num_labels
>
1875 nexthop
->nh_label
->num_labels
) {
1876 /* Prepare new label stack */
1878 for (j
= 0; j
< newnh
->nh_label
->num_labels
;
1880 labels
[j
] = newnh
->nh_label
->label
[j
];
1884 /* Include inner labels */
1885 for (j
= nexthop
->nh_label
->num_labels
;
1886 j
< resolved
->nh_label
->num_labels
;
1888 labels
[num_labels
] =
1889 resolved
->nh_label
->label
[j
];
1893 /* Replace existing label stack in the backup */
1894 nexthop_del_labels(newnh
);
1895 nexthop_add_labels(newnh
, bnh
->nh_label_type
,
1896 num_labels
, labels
);
1900 /* Need to compute the new backup index in the new
1901 * backup list, and add to map struct.
1904 nh
= resolve_nhe
->backup_info
->nhe
->nhg
.nexthop
;
1914 } else /* First one */
1915 resolve_nhe
->backup_info
->nhe
->nhg
.nexthop
= newnh
;
1918 resolved
->backup_idx
[resolved
->backup_num
] = j
;
1919 resolved
->backup_num
++;
1921 SET_FLAG(resolved
->flags
, NEXTHOP_FLAG_HAS_BACKUP
);
1923 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1924 zlog_debug("%s: added idx orig %d, new %d",
1927 /* Update map/cache */
1928 map
->map
[map
->map_count
].orig_idx
= idx
;
1929 map
->map
[map
->map_count
].new_idx
= j
;
1937 * Given a nexthop we need to properly recursively resolve,
1938 * do a table lookup to find and match if at all possible.
1939 * Set the nexthop->ifindex and resolution info as appropriate.
1941 static int nexthop_active(struct nexthop
*nexthop
, struct nhg_hash_entry
*nhe
,
1942 const struct prefix
*top
, int type
, uint32_t flags
,
1946 struct route_table
*table
;
1947 struct route_node
*rn
;
1948 struct route_entry
*match
= NULL
;
1950 zebra_nhlfe_t
*nhlfe
;
1951 struct nexthop
*newhop
;
1952 struct interface
*ifp
;
1954 struct zebra_vrf
*zvrf
;
1955 struct in_addr local_ipv4
;
1956 struct in_addr
*ipv4
;
1959 /* Reset some nexthop attributes that we'll recompute if necessary */
1960 if ((nexthop
->type
== NEXTHOP_TYPE_IPV4
)
1961 || (nexthop
->type
== NEXTHOP_TYPE_IPV6
))
1962 nexthop
->ifindex
= 0;
1964 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
);
1965 nexthops_free(nexthop
->resolved
);
1966 nexthop
->resolved
= NULL
;
1969 * Set afi based on nexthop type.
1970 * Some nexthop types get special handling, possibly skipping
1971 * the normal processing.
1973 switch (nexthop
->type
) {
1974 case NEXTHOP_TYPE_IFINDEX
:
1976 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1978 * If the interface exists and its operative or its a kernel
1979 * route and interface is up, its active. We trust kernel routes
1983 && (if_is_operative(ifp
)
1985 && (type
== ZEBRA_ROUTE_KERNEL
1986 || type
== ZEBRA_ROUTE_SYSTEM
))))
1992 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1995 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
1996 ifp
= if_lookup_by_index(nexthop
->ifindex
,
1998 if (ifp
&& if_is_operative(ifp
))
2005 case NEXTHOP_TYPE_IPV4
:
2006 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2009 case NEXTHOP_TYPE_IPV6
:
2013 case NEXTHOP_TYPE_BLACKHOLE
:
2018 * If the nexthop has been marked as 'onlink' we just need to make
2019 * sure the nexthop's interface is known and is operational.
2021 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ONLINK
)) {
2022 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
2024 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2025 zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
2026 nexthop
, nexthop
->ifindex
);
2029 if (!if_is_operative(ifp
)) {
2030 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2031 zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
2032 nexthop
, ifp
->name
);
2039 ((top
->family
== AF_INET
&& top
->prefixlen
== 32
2040 && nexthop
->gate
.ipv4
.s_addr
== top
->u
.prefix4
.s_addr
)
2041 || (top
->family
== AF_INET6
&& top
->prefixlen
== 128
2042 && memcmp(&nexthop
->gate
.ipv6
, &top
->u
.prefix6
, 16) == 0))) {
2043 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2045 " :%s: Attempting to install a max prefixlength route through itself",
2050 /* Validation for ipv4 mapped ipv6 nexthop. */
2051 if (IS_MAPPED_IPV6(&nexthop
->gate
.ipv6
)) {
2054 ipv4_mapped_ipv6_to_ipv4(&nexthop
->gate
.ipv6
, ipv4
);
2056 ipv4
= &nexthop
->gate
.ipv4
;
2059 /* Processing for nexthops with SR 'color' attribute, using
2060 * the corresponding SR policy object.
2062 if (nexthop
->srte_color
) {
2063 struct ipaddr endpoint
= {0};
2064 struct zebra_sr_policy
*policy
;
2068 endpoint
.ipa_type
= IPADDR_V4
;
2069 endpoint
.ipaddr_v4
= *ipv4
;
2072 endpoint
.ipa_type
= IPADDR_V6
;
2073 endpoint
.ipaddr_v6
= nexthop
->gate
.ipv6
;
2076 flog_err(EC_LIB_DEVELOPMENT
,
2077 "%s: unknown address-family: %u", __func__
,
2082 policy
= zebra_sr_policy_find(nexthop
->srte_color
, &endpoint
);
2083 if (policy
&& policy
->status
== ZEBRA_SR_POLICY_UP
) {
2085 frr_each_safe (nhlfe_list
, &policy
->lsp
->nhlfe_list
,
2087 if (!CHECK_FLAG(nhlfe
->flags
,
2088 NHLFE_FLAG_SELECTED
)
2089 || CHECK_FLAG(nhlfe
->flags
,
2090 NHLFE_FLAG_DELETED
))
2092 SET_FLAG(nexthop
->flags
,
2093 NEXTHOP_FLAG_RECURSIVE
);
2094 nexthop_set_resolved(afi
, nhlfe
->nexthop
,
2103 /* Make lookup prefix. */
2104 memset(&p
, 0, sizeof(struct prefix
));
2108 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
2109 p
.u
.prefix4
= *ipv4
;
2112 p
.family
= AF_INET6
;
2113 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
2114 p
.u
.prefix6
= nexthop
->gate
.ipv6
;
2117 assert(afi
!= AFI_IP
&& afi
!= AFI_IP6
);
2121 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, nexthop
->vrf_id
);
2123 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
2124 if (!table
|| !zvrf
) {
2125 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2126 zlog_debug(" %s: Table not found", __func__
);
2130 rn
= route_node_match(table
, (struct prefix
*)&p
);
2132 route_unlock_node(rn
);
2134 /* Lookup should halt if we've matched against ourselves ('top',
2135 * if specified) - i.e., we cannot have a nexthop NH1 is
2136 * resolved by a route NH1. The exception is if the route is a
2139 if (prefix_same(&rn
->p
, top
))
2140 if (((afi
== AFI_IP
) && (rn
->p
.prefixlen
!= 32))
2141 || ((afi
== AFI_IP6
) && (rn
->p
.prefixlen
!= 128))) {
2142 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2144 " %s: Matched against ourself and prefix length is not max bit length",
2149 /* Pick up selected route. */
2150 /* However, do not resolve over default route unless explicitly
2153 if (is_default_prefix(&rn
->p
)
2154 && !rnh_resolve_via_default(zvrf
, p
.family
)) {
2155 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2157 " :%s: Resolved against default route",
2162 dest
= rib_dest_from_rnode(rn
);
2163 if (dest
&& dest
->selected_fib
2164 && !CHECK_FLAG(dest
->selected_fib
->status
,
2165 ROUTE_ENTRY_REMOVED
)
2166 && dest
->selected_fib
->type
!= ZEBRA_ROUTE_TABLE
)
2167 match
= dest
->selected_fib
;
2169 /* If there is no selected route or matched route is EGP, go up
2175 } while (rn
&& rn
->info
== NULL
);
2177 route_lock_node(rn
);
2182 if (match
->type
== ZEBRA_ROUTE_CONNECT
) {
2183 /* Directly point connected route. */
2184 newhop
= match
->nhe
->nhg
.nexthop
;
2186 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
2187 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
2188 nexthop
->ifindex
= newhop
->ifindex
;
2189 else if (nexthop
->ifindex
!= newhop
->ifindex
) {
2190 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2192 "%s: %pNHv given ifindex does not match nexthops ifindex found found: %pNHv",
2196 * NEXTHOP_TYPE_*_IFINDEX but ifindex
2197 * doesn't match what we found.
2203 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2204 zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
2206 match
->nhe
->id
, newhop
);
2209 } else if (CHECK_FLAG(flags
, ZEBRA_FLAG_ALLOW_RECURSION
)) {
2210 struct nexthop_group
*nhg
;
2211 struct nexthop
*resolver
;
2212 struct backup_nh_map_s map
= {};
2216 /* Only useful if installed */
2217 if (!CHECK_FLAG(match
->status
, ROUTE_ENTRY_INSTALLED
)) {
2218 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2219 zlog_debug("%s: match %p (%u) not installed",
2223 goto done_with_match
;
2226 /* Examine installed nexthops; note that there
2227 * may not be any installed primary nexthops if
2228 * only backups are installed.
2230 nhg
= rib_get_fib_nhg(match
);
2231 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
2232 if (!nexthop_valid_resolve(nexthop
, newhop
))
2235 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2236 zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
2238 match
->nhe
->id
, newhop
);
2240 SET_FLAG(nexthop
->flags
,
2241 NEXTHOP_FLAG_RECURSIVE
);
2242 resolver
= nexthop_set_resolved(afi
, newhop
,
2246 /* If there are backup nexthops, capture
2247 * that info with the resolving nexthop.
2249 if (resolver
&& newhop
->backup_num
> 0) {
2250 resolve_backup_nexthops(newhop
,
2257 /* Examine installed backup nexthops, if any. There
2258 * are only installed backups *if* there is a
2259 * dedicated fib list. The UI can also control use
2260 * of backups for resolution.
2262 nhg
= rib_get_fib_backup_nhg(match
);
2263 if (!use_recursive_backups
||
2264 nhg
== NULL
|| nhg
->nexthop
== NULL
)
2265 goto done_with_match
;
2267 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
2268 if (!nexthop_valid_resolve(nexthop
, newhop
))
2271 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2272 zlog_debug("%s: RECURSIVE match backup %p (%u), newhop %pNHv",
2274 match
->nhe
->id
, newhop
);
2276 SET_FLAG(nexthop
->flags
,
2277 NEXTHOP_FLAG_RECURSIVE
);
2278 nexthop_set_resolved(afi
, newhop
, nexthop
,
2284 /* Capture resolving mtu */
2289 } else if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2291 " %s: Recursion failed to find",
2296 if (IS_ZEBRA_DEBUG_RIB_DETAILED
) {
2298 " %s: Route Type %s has not turned on recursion",
2299 __func__
, zebra_route_string(type
));
2300 if (type
== ZEBRA_ROUTE_BGP
2301 && !CHECK_FLAG(flags
, ZEBRA_FLAG_IBGP
))
2303 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
2308 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2309 zlog_debug(" %s: Nexthop did not lookup in table",
2314 /* This function verifies reachability of one given nexthop, which can be
2315 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2316 * in nexthop->flags field. The nexthop->ifindex will be updated
2317 * appropriately as well.
2319 * An existing route map can turn an otherwise active nexthop into inactive,
2320 * but not vice versa.
2322 * The return value is the final value of 'ACTIVE' flag.
2324 static unsigned nexthop_active_check(struct route_node
*rn
,
2325 struct route_entry
*re
,
2326 struct nexthop
*nexthop
,
2327 struct nhg_hash_entry
*nhe
)
2329 route_map_result_t ret
= RMAP_PERMITMATCH
;
2331 const struct prefix
*p
, *src_p
;
2332 struct zebra_vrf
*zvrf
;
2335 srcdest_rnode_prefixes(rn
, &p
, &src_p
);
2337 if (rn
->p
.family
== AF_INET
)
2339 else if (rn
->p
.family
== AF_INET6
)
2344 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2345 zlog_debug("%s: re %p, nexthop %pNHv", __func__
, re
, nexthop
);
2348 * If the kernel has sent us a NEW route, then
2349 * by golly gee whiz it's a good route.
2351 * If its an already INSTALLED route we have already handled, then the
2352 * kernel route's nexthop might have became unreachable
2353 * and we have to handle that.
2355 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
) &&
2356 (re
->type
== ZEBRA_ROUTE_KERNEL
||
2357 re
->type
== ZEBRA_ROUTE_SYSTEM
)) {
2358 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2362 switch (nexthop
->type
) {
2363 case NEXTHOP_TYPE_IFINDEX
:
2364 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
,
2366 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2368 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2370 case NEXTHOP_TYPE_IPV4
:
2371 case NEXTHOP_TYPE_IPV4_IFINDEX
:
2373 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
,
2375 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2377 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2379 case NEXTHOP_TYPE_IPV6
:
2381 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
,
2383 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2385 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2387 case NEXTHOP_TYPE_IPV6_IFINDEX
:
2388 /* RFC 5549, v4 prefix with v6 NH */
2389 if (rn
->p
.family
!= AF_INET
)
2392 if (nexthop_active(nexthop
, nhe
, &rn
->p
, re
->type
,
2394 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2396 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2398 case NEXTHOP_TYPE_BLACKHOLE
:
2399 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2407 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
2408 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2409 zlog_debug(" %s: Unable to find active nexthop",
2414 /* Capture recursive nexthop mtu.
2415 * TODO -- the code used to just reset the re's value to zero
2416 * for each nexthop, and then jam any resolving route's mtu value in,
2417 * whether or not that was zero, or lt/gt any existing value? The
2418 * way this is used appears to be as a floor value, so let's try
2419 * using it that way here.
2422 if (re
->nexthop_mtu
== 0 || re
->nexthop_mtu
> mtu
)
2423 re
->nexthop_mtu
= mtu
;
2426 /* XXX: What exactly do those checks do? Do we support
2427 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2429 if (RIB_SYSTEM_ROUTE(re
) || (family
== AFI_IP
&& p
->family
!= AF_INET
)
2430 || (family
== AFI_IP6
&& p
->family
!= AF_INET6
))
2431 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2433 /* The original code didn't determine the family correctly
2434 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2435 * from the rib_table_info in those cases.
2436 * Possibly it may be better to use only the rib_table_info
2440 struct rib_table_info
*info
;
2442 info
= srcdest_rnode_table_info(rn
);
2446 memset(&nexthop
->rmap_src
.ipv6
, 0, sizeof(union g_addr
));
2448 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
2450 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
2451 zlog_debug(" %s: zvrf is NULL", __func__
);
2452 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2455 /* It'll get set if required inside */
2456 ret
= zebra_route_map_check(family
, re
->type
, re
->instance
, p
, nexthop
,
2458 if (ret
== RMAP_DENYMATCH
) {
2459 if (IS_ZEBRA_DEBUG_RIB
) {
2461 "%u:%pRN: Filtering out with NH out %s due to route map",
2463 ifindex2ifname(nexthop
->ifindex
,
2466 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2468 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2471 /* Helper function called after resolution to walk nhg rb trees
2472 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2473 * is active on singleton NHEs.
2475 static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry
*nhe
)
2477 struct nhg_connected
*rb_node_dep
= NULL
;
2480 if (!zebra_nhg_depends_is_empty(nhe
)) {
2481 /* Is at least one depend valid? */
2482 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2483 if (zebra_nhg_set_valid_if_active(rb_node_dep
->nhe
))
2490 /* should be fully resolved singleton at this point */
2491 if (CHECK_FLAG(nhe
->nhg
.nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
2496 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
2502 * Process a list of nexthops, given an nhe, determining
2503 * whether each one is ACTIVE/installable at this time.
2505 static uint32_t nexthop_list_active_update(struct route_node
*rn
,
2506 struct route_entry
*re
,
2507 struct nhg_hash_entry
*nhe
,
2510 union g_addr prev_src
;
2511 unsigned int prev_active
, new_active
;
2512 ifindex_t prev_index
;
2513 uint32_t counter
= 0;
2514 struct nexthop
*nexthop
;
2515 struct nexthop_group
*nhg
= &nhe
->nhg
;
2517 nexthop
= nhg
->nexthop
;
2519 /* Init recursive nh mtu */
2520 re
->nexthop_mtu
= 0;
2522 /* Process nexthops one-by-one */
2523 for ( ; nexthop
; nexthop
= nexthop
->next
) {
2525 /* No protocol daemon provides src and so we're skipping
2528 prev_src
= nexthop
->rmap_src
;
2529 prev_active
= CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
2530 prev_index
= nexthop
->ifindex
;
2532 /* Include the containing nhe for primary nexthops: if there's
2533 * recursive resolution, we capture the backup info also.
2536 nexthop_active_check(rn
, re
, nexthop
,
2537 (is_backup
? NULL
: nhe
));
2540 * We need to respect the multipath_num here
2541 * as that what we should be able to install from
2542 * a multipath perspective should not be a data plane
2545 if (new_active
&& counter
>= zrouter
.multipath_num
) {
2548 /* Set it and its resolved nexthop as inactive. */
2549 for (nh
= nexthop
; nh
; nh
= nh
->resolved
)
2550 UNSET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
2558 /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
2559 if (prev_active
!= new_active
|| prev_index
!= nexthop
->ifindex
2560 || ((nexthop
->type
>= NEXTHOP_TYPE_IFINDEX
2561 && nexthop
->type
< NEXTHOP_TYPE_IPV6
)
2562 && prev_src
.ipv4
.s_addr
2563 != nexthop
->rmap_src
.ipv4
.s_addr
)
2564 || ((nexthop
->type
>= NEXTHOP_TYPE_IPV6
2565 && nexthop
->type
< NEXTHOP_TYPE_BLACKHOLE
)
2566 && !(IPV6_ADDR_SAME(&prev_src
.ipv6
,
2567 &nexthop
->rmap_src
.ipv6
)))
2568 || CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
2569 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2576 static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group
*nhg
)
2579 uint32_t curr_active
= 0;
2581 /* Assume all active for now */
2583 for (nh
= nhg
->nexthop
; nh
; nh
= nh
->next
) {
2584 SET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
2592 * Iterate over all nexthops of the given RIB entry and refresh their
2593 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2594 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2596 * Return value is the new number of active nexthops.
2598 int nexthop_active_update(struct route_node
*rn
, struct route_entry
*re
)
2600 struct nhg_hash_entry
*curr_nhe
;
2601 uint32_t curr_active
= 0, backup_active
= 0;
2603 if (re
->nhe
->id
>= ZEBRA_NHG_PROTO_LOWER
)
2604 return proto_nhg_nexthop_active_update(&re
->nhe
->nhg
);
2606 afi_t rt_afi
= family2afi(rn
->p
.family
);
2608 UNSET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
2610 /* Make a local copy of the existing nhe, so we don't work on/modify
2613 curr_nhe
= zebra_nhe_copy(re
->nhe
, re
->nhe
->id
);
2615 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2616 zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
2617 __func__
, re
, re
->nhe
, re
->nhe
->id
,
2620 /* Clear the existing id, if any: this will avoid any confusion
2621 * if the id exists, and will also force the creation
2622 * of a new nhe reflecting the changes we may make in this local copy.
2626 /* Process nexthops */
2627 curr_active
= nexthop_list_active_update(rn
, re
, curr_nhe
, false);
2629 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2630 zlog_debug("%s: re %p curr_active %u", __func__
, re
,
2633 /* If there are no backup nexthops, we are done */
2634 if (zebra_nhg_get_backup_nhg(curr_nhe
) == NULL
)
2637 backup_active
= nexthop_list_active_update(
2638 rn
, re
, curr_nhe
->backup_info
->nhe
, true /*is_backup*/);
2640 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2641 zlog_debug("%s: re %p backup_active %u", __func__
, re
,
2647 * Ref or create an nhe that matches the current state of the
2650 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
)) {
2651 struct nhg_hash_entry
*new_nhe
= NULL
;
2653 new_nhe
= zebra_nhg_rib_find_nhe(curr_nhe
, rt_afi
);
2655 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2656 zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
2657 __func__
, re
, re
->nhe
,
2658 re
->nhe
->id
, new_nhe
, new_nhe
->id
);
2660 route_entry_update_nhe(re
, new_nhe
);
2664 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2665 * flag where appropriate.
2668 zebra_nhg_set_valid_if_active(re
->nhe
);
2671 * Do not need the old / copied nhe anymore since it
2672 * was either copied over into a new nhe or not
2675 zebra_nhg_free(curr_nhe
);
2679 /* Recursively construct a grp array of fully resolved IDs.
2681 * This function allows us to account for groups within groups,
2682 * by converting them into a flat array of IDs.
2684 * nh_grp is modified at every level of recursion to append
2685 * to it the next unique, fully resolved ID from the entire tree.
2689 * I'm pretty sure we only allow ONE level of group within group currently.
2690 * But making this recursive just in case that ever changes.
2692 static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp
*grp
,
2694 struct nhg_hash_entry
*nhe
,
2697 struct nhg_connected
*rb_node_dep
= NULL
;
2698 struct nhg_hash_entry
*depend
= NULL
;
2699 uint8_t i
= curr_index
;
2701 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2702 bool duplicate
= false;
2707 depend
= rb_node_dep
->nhe
;
2710 * If its recursive, use its resolved nhe in the group
2712 if (CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_RECURSIVE
)) {
2713 depend
= zebra_nhg_resolve(depend
);
2716 EC_ZEBRA_NHG_FIB_UPDATE
,
2717 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
2723 if (!zebra_nhg_depends_is_empty(depend
)) {
2724 /* This is a group within a group */
2725 i
= zebra_nhg_nhe2grp_internal(grp
, i
, depend
, max_num
);
2727 if (!CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_VALID
)) {
2728 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2729 || IS_ZEBRA_DEBUG_NHG
)
2731 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2732 __func__
, depend
->id
);
2736 /* If the nexthop not installed/queued for install don't
2737 * put in the ID array.
2739 if (!(CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_INSTALLED
)
2740 || CHECK_FLAG(depend
->flags
,
2741 NEXTHOP_GROUP_QUEUED
))) {
2742 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2743 || IS_ZEBRA_DEBUG_NHG
)
2745 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2746 __func__
, depend
->id
);
2750 /* Check for duplicate IDs, ignore if found. */
2751 for (int j
= 0; j
< i
; j
++) {
2752 if (depend
->id
== grp
[j
].id
) {
2759 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2760 || IS_ZEBRA_DEBUG_NHG
)
2762 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2763 __func__
, depend
->id
);
2767 grp
[i
].id
= depend
->id
;
2768 grp
[i
].weight
= depend
->nhg
.nexthop
->weight
;
2773 if (nhe
->backup_info
== NULL
|| nhe
->backup_info
->nhe
== NULL
)
2776 /* TODO -- For now, we are not trying to use or install any
2777 * backup info in this nexthop-id path: we aren't prepared
2778 * to use the backups here yet. We're just debugging what we find.
2780 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
2781 zlog_debug("%s: skipping backup nhe", __func__
);
2787 /* Convert a nhe into a group array */
2788 uint8_t zebra_nhg_nhe2grp(struct nh_grp
*grp
, struct nhg_hash_entry
*nhe
,
2791 /* Call into the recursive function */
2792 return zebra_nhg_nhe2grp_internal(grp
, 0, nhe
, max_num
);
2795 void zebra_nhg_install_kernel(struct nhg_hash_entry
*nhe
)
2797 struct nhg_connected
*rb_node_dep
= NULL
;
2799 /* Resolve it first */
2800 nhe
= zebra_nhg_resolve(nhe
);
2802 /* Make sure all depends are installed/queued */
2803 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
2804 zebra_nhg_install_kernel(rb_node_dep
->nhe
);
2807 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
)
2808 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)
2809 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
)) {
2810 /* Change its type to us since we are installing it */
2811 if (!ZEBRA_NHG_CREATED(nhe
))
2812 nhe
->type
= ZEBRA_ROUTE_NHG
;
2814 int ret
= dplane_nexthop_add(nhe
);
2817 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2818 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2820 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2822 EC_ZEBRA_DP_INSTALL_FAIL
,
2823 "Failed to install Nexthop ID (%u) into the kernel",
2826 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2827 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2828 zebra_nhg_handle_install(nhe
);
2834 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry
*nhe
)
2836 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)) {
2837 int ret
= dplane_nexthop_delete(nhe
);
2840 case ZEBRA_DPLANE_REQUEST_QUEUED
:
2841 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2843 case ZEBRA_DPLANE_REQUEST_FAILURE
:
2845 EC_ZEBRA_DP_DELETE_FAIL
,
2846 "Failed to uninstall Nexthop ID (%u) from the kernel",
2849 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
2850 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2855 zebra_nhg_handle_uninstall(nhe
);
2858 void zebra_nhg_dplane_result(struct zebra_dplane_ctx
*ctx
)
2860 enum dplane_op_e op
;
2861 enum zebra_dplane_result status
;
2863 struct nhg_hash_entry
*nhe
= NULL
;
2865 op
= dplane_ctx_get_op(ctx
);
2866 status
= dplane_ctx_get_status(ctx
);
2868 id
= dplane_ctx_get_nhe_id(ctx
);
2870 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
|| IS_ZEBRA_DEBUG_NHG_DETAIL
)
2872 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
2873 ctx
, dplane_op2str(op
), id
, dplane_res2str(status
));
2876 case DPLANE_OP_NH_DELETE
:
2877 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
2879 EC_ZEBRA_DP_DELETE_FAIL
,
2880 "Failed to uninstall Nexthop ID (%u) from the kernel",
2883 /* We already free'd the data, nothing to do */
2885 case DPLANE_OP_NH_INSTALL
:
2886 case DPLANE_OP_NH_UPDATE
:
2887 nhe
= zebra_nhg_lookup_id(id
);
2890 if (IS_ZEBRA_DEBUG_NHG
)
2892 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
2893 dplane_op2str(op
), id
);
2898 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
2899 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
2900 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
2901 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2902 zebra_nhg_handle_install(nhe
);
2904 /* If daemon nhg, send it an update */
2905 if (nhe
->id
>= ZEBRA_NHG_PROTO_LOWER
)
2906 zsend_nhg_notify(nhe
->type
, nhe
->zapi_instance
,
2907 nhe
->zapi_session
, nhe
->id
,
2908 ZAPI_NHG_INSTALLED
);
2910 /* If daemon nhg, send it an update */
2911 if (nhe
->id
>= ZEBRA_NHG_PROTO_LOWER
)
2912 zsend_nhg_notify(nhe
->type
, nhe
->zapi_instance
,
2913 nhe
->zapi_session
, nhe
->id
,
2914 ZAPI_NHG_FAIL_INSTALL
);
2917 EC_ZEBRA_DP_INSTALL_FAIL
,
2918 "Failed to install Nexthop ID (%u) into the kernel",
2923 case DPLANE_OP_ROUTE_INSTALL
:
2924 case DPLANE_OP_ROUTE_UPDATE
:
2925 case DPLANE_OP_ROUTE_DELETE
:
2926 case DPLANE_OP_ROUTE_NOTIFY
:
2927 case DPLANE_OP_LSP_INSTALL
:
2928 case DPLANE_OP_LSP_UPDATE
:
2929 case DPLANE_OP_LSP_DELETE
:
2930 case DPLANE_OP_LSP_NOTIFY
:
2931 case DPLANE_OP_PW_INSTALL
:
2932 case DPLANE_OP_PW_UNINSTALL
:
2933 case DPLANE_OP_SYS_ROUTE_ADD
:
2934 case DPLANE_OP_SYS_ROUTE_DELETE
:
2935 case DPLANE_OP_ADDR_INSTALL
:
2936 case DPLANE_OP_ADDR_UNINSTALL
:
2937 case DPLANE_OP_MAC_INSTALL
:
2938 case DPLANE_OP_MAC_DELETE
:
2939 case DPLANE_OP_NEIGH_INSTALL
:
2940 case DPLANE_OP_NEIGH_UPDATE
:
2941 case DPLANE_OP_NEIGH_DELETE
:
2942 case DPLANE_OP_NEIGH_IP_INSTALL
:
2943 case DPLANE_OP_NEIGH_IP_DELETE
:
2944 case DPLANE_OP_VTEP_ADD
:
2945 case DPLANE_OP_VTEP_DELETE
:
2946 case DPLANE_OP_RULE_ADD
:
2947 case DPLANE_OP_RULE_DELETE
:
2948 case DPLANE_OP_RULE_UPDATE
:
2949 case DPLANE_OP_NEIGH_DISCOVER
:
2950 case DPLANE_OP_BR_PORT_UPDATE
:
2951 case DPLANE_OP_NONE
:
2952 case DPLANE_OP_IPTABLE_ADD
:
2953 case DPLANE_OP_IPTABLE_DELETE
:
2954 case DPLANE_OP_IPSET_ADD
:
2955 case DPLANE_OP_IPSET_DELETE
:
2956 case DPLANE_OP_IPSET_ENTRY_ADD
:
2957 case DPLANE_OP_IPSET_ENTRY_DELETE
:
2958 case DPLANE_OP_NEIGH_TABLE_UPDATE
:
2962 dplane_ctx_fini(&ctx
);
2965 static void zebra_nhg_sweep_entry(struct hash_bucket
*bucket
, void *arg
)
2967 struct nhg_hash_entry
*nhe
= NULL
;
2969 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
2971 /* If its being ref'd, just let it be uninstalled via a route removal */
2972 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
2973 zebra_nhg_uninstall_kernel(nhe
);
2976 void zebra_nhg_sweep_table(struct hash
*hash
)
2978 hash_iterate(hash
, zebra_nhg_sweep_entry
, NULL
);
2981 static void zebra_nhg_mark_keep_entry(struct hash_bucket
*bucket
, void *arg
)
2983 struct nhg_hash_entry
*nhe
= bucket
->data
;
2985 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
2989 * When we are shutting down and we have retain mode enabled
2990 * in zebra the process is to mark each vrf that it's
2991 * routes should not be deleted. The problem with that
2992 * is that shutdown actually free's up memory which
2993 * causes the nexthop group's ref counts to go to zero
2994 * we need a way to subtly tell the system to not remove
2995 * the nexthop groups from the kernel at the same time.
2996 * The easiest just looks like that we should not mark
2997 * the nhg's as installed any more and when the ref count
2998 * goes to zero we'll attempt to delete and do nothing
3000 void zebra_nhg_mark_keep(void)
3002 hash_iterate(zrouter
.nhgs_id
, zebra_nhg_mark_keep_entry
, NULL
);
3005 /* Global control to disable use of kernel nexthops, if available. We can't
3006 * force the kernel to support nexthop ids, of course, but we can disable
3007 * zebra's use of them, for testing e.g. By default, if the kernel supports
3008 * nexthop ids, zebra uses them.
3010 void zebra_nhg_enable_kernel_nexthops(bool set
)
3012 g_nexthops_enabled
= set
;
3015 bool zebra_nhg_kernel_nexthops_enabled(void)
3017 return g_nexthops_enabled
;
3020 /* Global control for use of activated backups for recursive resolution. */
3021 void zebra_nhg_set_recursive_use_backups(bool set
)
3023 use_recursive_backups
= set
;
3026 bool zebra_nhg_recursive_use_backups(void)
3028 return use_recursive_backups
;
3032 * Global control to only use kernel nexthops for protocol created NHGs.
3033 * There are some use cases where you may not want zebra to implicitly
3034 * create kernel nexthops for all routes and only create them for NHGs
3035 * passed down by upper level protos.
3039 void zebra_nhg_set_proto_nexthops_only(bool set
)
3041 proto_nexthops_only
= set
;
3044 bool zebra_nhg_proto_nexthops_only(void)
3046 return proto_nexthops_only
;
3049 /* Add NHE from upper level proto */
3050 struct nhg_hash_entry
*zebra_nhg_proto_add(uint32_t id
, int type
,
3051 uint16_t instance
, uint32_t session
,
3052 struct nexthop_group
*nhg
, afi_t afi
)
3054 struct nhg_hash_entry lookup
;
3055 struct nhg_hash_entry
*new, *old
;
3056 struct nhg_connected
*rb_node_dep
= NULL
;
3057 struct nexthop
*newhop
;
3058 bool replace
= false;
3060 if (!nhg
->nexthop
) {
3061 if (IS_ZEBRA_DEBUG_NHG
)
3062 zlog_debug("%s: id %u, no nexthops passed to add",
3068 /* Set nexthop list as active, since they wont go through rib
3071 * Assuming valid/onlink for now.
3073 * Once resolution is figured out, we won't need this!
3075 for (ALL_NEXTHOPS_PTR(nhg
, newhop
)) {
3076 if (CHECK_FLAG(newhop
->flags
, NEXTHOP_FLAG_HAS_BACKUP
)) {
3077 if (IS_ZEBRA_DEBUG_NHG
)
3079 "%s: id %u, backup nexthops not supported",
3084 if (newhop
->type
== NEXTHOP_TYPE_BLACKHOLE
) {
3085 if (IS_ZEBRA_DEBUG_NHG
)
3087 "%s: id %u, blackhole nexthop not supported",
3092 if (newhop
->type
== NEXTHOP_TYPE_IFINDEX
) {
3093 if (IS_ZEBRA_DEBUG_NHG
)
3095 "%s: id %u, nexthop without gateway not supported",
3100 if (!newhop
->ifindex
) {
3101 if (IS_ZEBRA_DEBUG_NHG
)
3103 "%s: id %u, nexthop without ifindex is not supported",
3107 SET_FLAG(newhop
->flags
, NEXTHOP_FLAG_ACTIVE
);
3110 zebra_nhe_init(&lookup
, afi
, nhg
->nexthop
);
3111 lookup
.nhg
.nexthop
= nhg
->nexthop
;
3115 old
= zebra_nhg_lookup_id(id
);
3119 * This is a replace, just release NHE from ID for now, The
3120 * depends/dependents may still be used in the replacement so
3121 * we don't touch them other than to remove their refs to their
3125 hash_release(zrouter
.nhgs_id
, old
);
3127 /* Free all the things */
3128 zebra_nhg_release_all_deps(old
);
3131 new = zebra_nhg_rib_find_nhe(&lookup
, afi
);
3133 zebra_nhg_increment_ref(new);
3135 /* Capture zapi client info */
3136 new->zapi_instance
= instance
;
3137 new->zapi_session
= session
;
3139 zebra_nhg_set_valid_if_active(new);
3141 zebra_nhg_install_kernel(new);
3145 * Check to handle recving DEL while routes still in use then
3148 * In this case we would have decremented the refcnt already
3149 * but set the FLAG here. Go ahead and increment once to fix
3150 * the misordering we have been sent.
3152 if (CHECK_FLAG(old
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
))
3153 zebra_nhg_increment_ref(old
);
3155 rib_handle_nhg_replace(old
, new);
3157 /* if this != 1 at this point, we have a bug */
3158 assert(old
->refcnt
== 1);
3160 /* We have to decrement its singletons
3161 * because some might not exist in NEW.
3163 if (!zebra_nhg_depends_is_empty(old
)) {
3164 frr_each (nhg_connected_tree
, &old
->nhg_depends
,
3166 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
3169 /* Dont call the dec API, we dont want to uninstall the ID */
3171 zebra_nhg_free(old
);
3175 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3176 zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__
,
3177 (replace
? "replaced" : "added"), new, new->id
,
3178 new->vrf_id
, zebra_route_string(new->type
));
3183 /* Delete NHE from upper level proto, caller must decrement ref */
3184 struct nhg_hash_entry
*zebra_nhg_proto_del(uint32_t id
, int type
)
3186 struct nhg_hash_entry
*nhe
;
3188 nhe
= zebra_nhg_lookup_id(id
);
3191 if (IS_ZEBRA_DEBUG_NHG
)
3192 zlog_debug("%s: id %u, lookup failed", __func__
, id
);
3197 if (type
!= nhe
->type
) {
3198 if (IS_ZEBRA_DEBUG_NHG
)
3200 "%s: id %u, type %s mismatch, sent by %s, ignoring",
3201 __func__
, id
, zebra_route_string(nhe
->type
),
3202 zebra_route_string(type
));
3206 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
)) {
3207 if (IS_ZEBRA_DEBUG_NHG
)
3208 zlog_debug("%s: id %u, already released", __func__
, id
);
3213 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_PROTO_RELEASED
);
3215 if (nhe
->refcnt
> 1) {
3216 if (IS_ZEBRA_DEBUG_NHG
)
3218 "%s: id %u, still being used by routes refcnt %u",
3219 __func__
, nhe
->id
, nhe
->refcnt
);
3223 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3224 zlog_debug("%s: deleted nhe %p (%u), vrf %d, type %s", __func__
,
3225 nhe
, nhe
->id
, nhe
->vrf_id
,
3226 zebra_route_string(nhe
->type
));
3231 struct nhg_score_proto_iter
{
3236 static void zebra_nhg_score_proto_entry(struct hash_bucket
*bucket
, void *arg
)
3238 struct nhg_hash_entry
*nhe
;
3239 struct nhg_score_proto_iter
*iter
;
3241 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
3244 /* Needs to match type and outside zebra ID space */
3245 if (nhe
->type
== iter
->type
&& nhe
->id
>= ZEBRA_NHG_PROTO_LOWER
) {
3246 if (IS_ZEBRA_DEBUG_NHG_DETAIL
)
3248 "%s: found nhe %p (%u), vrf %d, type %s after client disconnect",
3249 __func__
, nhe
, nhe
->id
, nhe
->vrf_id
,
3250 zebra_route_string(nhe
->type
));
3252 /* Add to removal list */
3253 listnode_add(iter
->found
, nhe
);
3257 /* Remove specific by proto NHGs */
3258 unsigned long zebra_nhg_score_proto(int type
)
3260 struct nhg_hash_entry
*nhe
;
3261 struct nhg_score_proto_iter iter
= {};
3262 struct listnode
*ln
;
3263 unsigned long count
;
3266 iter
.found
= list_new();
3268 /* Find matching entries to remove */
3269 hash_iterate(zrouter
.nhgs_id
, zebra_nhg_score_proto_entry
, &iter
);
3271 /* Now remove them */
3272 for (ALL_LIST_ELEMENTS_RO(iter
.found
, ln
, nhe
)) {
3274 * This should be the last ref if we remove client routes too,
3275 * and thus should remove and free them.
3277 zebra_nhg_decrement_ref(nhe
);
3280 count
= iter
.found
->count
;
3281 list_delete(&iter
.found
);