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
);
67 static void nhg_connected_free(struct nhg_connected
*dep
)
69 XFREE(MTYPE_NHG_CONNECTED
, dep
);
72 static struct nhg_connected
*nhg_connected_new(struct nhg_hash_entry
*nhe
)
74 struct nhg_connected
*new = NULL
;
76 new = XCALLOC(MTYPE_NHG_CONNECTED
, sizeof(struct nhg_connected
));
82 void nhg_connected_tree_free(struct nhg_connected_tree_head
*head
)
84 struct nhg_connected
*rb_node_dep
= NULL
;
86 if (!nhg_connected_tree_is_empty(head
)) {
87 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
88 nhg_connected_tree_del(head
, rb_node_dep
);
89 nhg_connected_free(rb_node_dep
);
94 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head
*head
)
96 return nhg_connected_tree_count(head
) ? false : true;
99 struct nhg_connected
*
100 nhg_connected_tree_root(struct nhg_connected_tree_head
*head
)
102 return nhg_connected_tree_first(head
);
105 struct nhg_hash_entry
*
106 nhg_connected_tree_del_nhe(struct nhg_connected_tree_head
*head
,
107 struct nhg_hash_entry
*depend
)
109 struct nhg_connected lookup
= {};
110 struct nhg_connected
*remove
= NULL
;
111 struct nhg_hash_entry
*removed_nhe
;
115 /* Lookup to find the element, then remove it */
116 remove
= nhg_connected_tree_find(head
, &lookup
);
118 /* Re-returning here just in case this API changes..
119 * the _del list api's are a bit undefined at the moment.
121 * So hopefully returning here will make it fail if the api
122 * changes to something different than currently expected.
124 remove
= nhg_connected_tree_del(head
, remove
);
126 /* If the entry was sucessfully removed, free the 'connected` struct */
128 removed_nhe
= remove
->nhe
;
129 nhg_connected_free(remove
);
136 /* Assuming UNIQUE RB tree. If this changes, assumptions here about
137 * insertion need to change.
139 struct nhg_hash_entry
*
140 nhg_connected_tree_add_nhe(struct nhg_connected_tree_head
*head
,
141 struct nhg_hash_entry
*depend
)
143 struct nhg_connected
*new = NULL
;
145 new = nhg_connected_new(depend
);
147 /* On success, NULL will be returned from the
150 if (new && (nhg_connected_tree_add(head
, new) == NULL
))
153 /* If it wasn't successful, it must be a duplicate. We enforce the
154 * unique property for the `nhg_connected` tree.
156 nhg_connected_free(new);
162 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head
*head
)
164 struct nhg_connected
*rb_node_dep
= NULL
;
166 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
167 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
172 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head
*head
)
174 struct nhg_connected
*rb_node_dep
= NULL
;
176 frr_each(nhg_connected_tree
, head
, rb_node_dep
) {
177 zebra_nhg_increment_ref(rb_node_dep
->nhe
);
181 struct nhg_hash_entry
*zebra_nhg_resolve(struct nhg_hash_entry
*nhe
)
183 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
)
184 && !zebra_nhg_depends_is_empty(nhe
)) {
185 nhe
= nhg_connected_tree_root(&nhe
->nhg_depends
)->nhe
;
186 return zebra_nhg_resolve(nhe
);
192 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry
*nhe
)
194 return nhg_connected_tree_count(&nhe
->nhg_depends
);
197 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry
*nhe
)
199 return nhg_connected_tree_is_empty(&nhe
->nhg_depends
);
202 static void zebra_nhg_depends_del(struct nhg_hash_entry
*from
,
203 struct nhg_hash_entry
*depend
)
205 nhg_connected_tree_del_nhe(&from
->nhg_depends
, depend
);
208 static void zebra_nhg_depends_init(struct nhg_hash_entry
*nhe
)
210 nhg_connected_tree_init(&nhe
->nhg_depends
);
213 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry
*nhe
)
215 return nhg_connected_tree_count(&nhe
->nhg_dependents
);
219 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry
*nhe
)
221 return nhg_connected_tree_is_empty(&nhe
->nhg_dependents
);
224 static void zebra_nhg_dependents_del(struct nhg_hash_entry
*from
,
225 struct nhg_hash_entry
*dependent
)
227 nhg_connected_tree_del_nhe(&from
->nhg_dependents
, dependent
);
230 static void zebra_nhg_dependents_add(struct nhg_hash_entry
*to
,
231 struct nhg_hash_entry
*dependent
)
233 nhg_connected_tree_add_nhe(&to
->nhg_dependents
, dependent
);
236 static void zebra_nhg_dependents_init(struct nhg_hash_entry
*nhe
)
238 nhg_connected_tree_init(&nhe
->nhg_dependents
);
241 /* Release this nhe from anything depending on it */
242 static void zebra_nhg_dependents_release(struct nhg_hash_entry
*nhe
)
244 struct nhg_connected
*rb_node_dep
= NULL
;
246 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
) {
247 zebra_nhg_depends_del(rb_node_dep
->nhe
, nhe
);
248 /* recheck validity of the dependent */
249 zebra_nhg_check_valid(rb_node_dep
->nhe
);
253 /* Release this nhe from anything that it depends on */
254 static void zebra_nhg_depends_release(struct nhg_hash_entry
*nhe
)
256 if (!zebra_nhg_depends_is_empty(nhe
)) {
257 struct nhg_connected
*rb_node_dep
= NULL
;
259 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_depends
,
261 zebra_nhg_dependents_del(rb_node_dep
->nhe
, nhe
);
267 struct nhg_hash_entry
*zebra_nhg_lookup_id(uint32_t id
)
269 struct nhg_hash_entry lookup
= {};
272 return hash_lookup(zrouter
.nhgs_id
, &lookup
);
275 static int zebra_nhg_insert_id(struct nhg_hash_entry
*nhe
)
277 if (hash_lookup(zrouter
.nhgs_id
, nhe
)) {
279 EC_ZEBRA_NHG_TABLE_INSERT_FAILED
,
280 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
285 hash_get(zrouter
.nhgs_id
, nhe
, hash_alloc_intern
);
290 static void zebra_nhg_set_if(struct nhg_hash_entry
*nhe
, struct interface
*ifp
)
293 if_nhg_dependents_add(ifp
, nhe
);
297 zebra_nhg_connect_depends(struct nhg_hash_entry
*nhe
,
298 struct nhg_connected_tree_head nhg_depends
)
300 struct nhg_connected
*rb_node_dep
= NULL
;
302 /* This has been allocated higher above in the stack. Could probably
303 * re-allocate and free the old stuff but just using the same memory
304 * for now. Otherwise, their might be a time trade-off for repeated
305 * alloc/frees as startup.
307 nhe
->nhg_depends
= nhg_depends
;
309 /* Attach backpointer to anything that it depends on */
310 zebra_nhg_dependents_init(nhe
);
311 if (!zebra_nhg_depends_is_empty(nhe
)) {
312 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
313 zebra_nhg_dependents_add(rb_node_dep
->nhe
, nhe
);
317 /* Add the ifp now if its not a group or recursive and has ifindex */
318 if (zebra_nhg_depends_is_empty(nhe
) && nhe
->nhg
->nexthop
319 && nhe
->nhg
->nexthop
->ifindex
) {
320 struct interface
*ifp
= NULL
;
322 ifp
= if_lookup_by_index(nhe
->nhg
->nexthop
->ifindex
,
323 nhe
->nhg
->nexthop
->vrf_id
);
325 zebra_nhg_set_if(nhe
, ifp
);
328 EC_ZEBRA_IF_LOOKUP_FAILED
,
329 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
330 nhe
->nhg
->nexthop
->ifindex
,
331 nhe
->nhg
->nexthop
->vrf_id
, nhe
->id
);
335 struct nhg_hash_entry
*zebra_nhg_alloc(void)
337 struct nhg_hash_entry
*nhe
;
339 nhe
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_hash_entry
));
344 static struct nhg_hash_entry
*zebra_nhg_copy(const struct nhg_hash_entry
*copy
,
347 struct nhg_hash_entry
*nhe
;
349 nhe
= zebra_nhg_alloc();
353 nhe
->nhg
= nexthop_group_new();
354 nexthop_group_copy(nhe
->nhg
, copy
->nhg
);
356 nhe
->vrf_id
= copy
->vrf_id
;
357 nhe
->afi
= copy
->afi
;
358 nhe
->type
= copy
->type
? copy
->type
: ZEBRA_ROUTE_NHG
;
360 nhe
->dplane_ref
= zebra_router_get_next_sequence();
365 /* Allocation via hash handler */
366 static void *zebra_nhg_hash_alloc(void *arg
)
368 struct nhg_hash_entry
*nhe
= NULL
;
369 struct nhg_hash_entry
*copy
= arg
;
371 nhe
= zebra_nhg_copy(copy
, copy
->id
);
373 /* Mark duplicate nexthops in a group at creation time. */
374 nexthop_group_mark_duplicates(nhe
->nhg
);
376 zebra_nhg_connect_depends(nhe
, copy
->nhg_depends
);
377 zebra_nhg_insert_id(nhe
);
382 uint32_t zebra_nhg_hash_key(const void *arg
)
384 const struct nhg_hash_entry
*nhe
= arg
;
386 uint32_t key
= 0x5a351234;
388 key
= jhash_3words(nhe
->vrf_id
, nhe
->afi
, nexthop_group_hash(nhe
->nhg
),
394 uint32_t zebra_nhg_id_key(const void *arg
)
396 const struct nhg_hash_entry
*nhe
= arg
;
401 bool zebra_nhg_hash_equal(const void *arg1
, const void *arg2
)
403 const struct nhg_hash_entry
*nhe1
= arg1
;
404 const struct nhg_hash_entry
*nhe2
= arg2
;
405 struct nexthop
*nexthop1
;
406 struct nexthop
*nexthop2
;
408 /* No matter what if they equal IDs, assume equal */
409 if (nhe1
->id
&& nhe2
->id
&& (nhe1
->id
== nhe2
->id
))
412 if (nhe1
->vrf_id
!= nhe2
->vrf_id
)
415 if (nhe1
->afi
!= nhe2
->afi
)
418 /* Nexthops should be sorted */
419 for (nexthop1
= nhe1
->nhg
->nexthop
, nexthop2
= nhe2
->nhg
->nexthop
;
420 nexthop1
|| nexthop2
;
421 nexthop1
= nexthop1
->next
, nexthop2
= nexthop2
->next
) {
422 if (nexthop1
&& !nexthop2
)
425 if (!nexthop1
&& nexthop2
)
429 * We have to check the active flag of each individual one,
430 * not just the overall active_num. This solves the special case
431 * issue of a route with a nexthop group with one nexthop
432 * resolving to itself and thus marking it inactive. If we
433 * have two different routes each wanting to mark a different
434 * nexthop inactive, they need to hash to two different groups.
436 * If we just hashed on num_active, they would hash the same
437 * which is incorrect.
441 * -> 1.1.1.1 dummy1 (inactive)
446 * -> 1.1.2.1 dummy2 (inactive)
448 * Without checking each individual one, they would hash to
449 * the same group and both have 1.1.1.1 dummy1 marked inactive.
452 if (CHECK_FLAG(nexthop1
->flags
, NEXTHOP_FLAG_ACTIVE
)
453 != CHECK_FLAG(nexthop2
->flags
, NEXTHOP_FLAG_ACTIVE
))
456 if (!nexthop_same(nexthop1
, nexthop2
))
463 bool zebra_nhg_hash_id_equal(const void *arg1
, const void *arg2
)
465 const struct nhg_hash_entry
*nhe1
= arg1
;
466 const struct nhg_hash_entry
*nhe2
= arg2
;
468 return nhe1
->id
== nhe2
->id
;
471 static int zebra_nhg_process_grp(struct nexthop_group
*nhg
,
472 struct nhg_connected_tree_head
*depends
,
473 struct nh_grp
*grp
, uint8_t count
)
475 nhg_connected_tree_init(depends
);
477 for (int i
= 0; i
< count
; i
++) {
478 struct nhg_hash_entry
*depend
= NULL
;
479 /* We do not care about nexthop_grp.weight at
480 * this time. But we should figure out
481 * how to adapt this to our code in
484 depend
= depends_find_id_add(depends
, grp
[i
].id
);
489 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
495 * If this is a nexthop with its own group
496 * dependencies, add them as well. Not sure its
497 * even possible to have a group within a group
501 copy_nexthops(&nhg
->nexthop
, depend
->nhg
->nexthop
, NULL
);
507 static void handle_recursive_depend(struct nhg_connected_tree_head
*nhg_depends
,
508 struct nexthop
*nh
, afi_t afi
)
510 struct nhg_hash_entry
*depend
= NULL
;
511 struct nexthop_group resolved_ng
= {};
513 resolved_ng
.nexthop
= nh
;
515 depend
= zebra_nhg_rib_find(0, &resolved_ng
, afi
);
518 depends_add(nhg_depends
, depend
);
521 static bool zebra_nhg_find(struct nhg_hash_entry
**nhe
, uint32_t id
,
522 struct nexthop_group
*nhg
,
523 struct nhg_connected_tree_head
*nhg_depends
,
524 vrf_id_t vrf_id
, afi_t afi
, int type
)
526 struct nhg_hash_entry lookup
= {};
528 uint32_t old_id_counter
= id_counter
;
530 bool created
= false;
531 bool recursive
= false;
534 * If it has an id at this point, we must have gotten it from the kernel
536 lookup
.id
= id
? id
: ++id_counter
;
538 lookup
.type
= type
? type
: ZEBRA_ROUTE_NHG
;
541 lookup
.vrf_id
= vrf_id
;
542 if (lookup
.nhg
->nexthop
->next
) {
543 /* Groups can have all vrfs and AF's in them */
544 lookup
.afi
= AFI_UNSPEC
;
546 switch (lookup
.nhg
->nexthop
->type
) {
547 case (NEXTHOP_TYPE_IFINDEX
):
548 case (NEXTHOP_TYPE_BLACKHOLE
):
550 * This switch case handles setting the afi different
551 * for ipv4/v6 routes. Ifindex/blackhole nexthop
552 * objects cannot be ambiguous, they must be Address
553 * Family specific. If we get here, we will either use
554 * the AF of the route, or the one we got passed from
555 * here from the kernel.
559 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
560 case (NEXTHOP_TYPE_IPV4
):
563 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
564 case (NEXTHOP_TYPE_IPV6
):
565 lookup
.afi
= AFI_IP6
;
571 (*nhe
) = zebra_nhg_lookup_id(id
);
573 (*nhe
) = hash_lookup(zrouter
.nhgs
, &lookup
);
575 /* If it found an nhe in our tables, this new ID is unused */
577 id_counter
= old_id_counter
;
580 /* Only hash/lookup the depends if the first lookup
581 * fails to find something. This should hopefully save a
582 * lot of cycles for larger ecmp sizes.
585 /* If you don't want to hash on each nexthop in the
586 * nexthop group struct you can pass the depends
587 * directly. Kernel-side we do this since it just looks
590 lookup
.nhg_depends
= *nhg_depends
;
592 if (nhg
->nexthop
->next
) {
593 zebra_nhg_depends_init(&lookup
);
595 /* If its a group, create a dependency tree */
596 struct nexthop
*nh
= NULL
;
598 for (nh
= nhg
->nexthop
; nh
; nh
= nh
->next
)
599 depends_find_add(&lookup
.nhg_depends
,
601 } else if (CHECK_FLAG(nhg
->nexthop
->flags
,
602 NEXTHOP_FLAG_RECURSIVE
)) {
603 zebra_nhg_depends_init(&lookup
);
604 handle_recursive_depend(&lookup
.nhg_depends
,
605 nhg
->nexthop
->resolved
,
611 (*nhe
) = hash_get(zrouter
.nhgs
, &lookup
, zebra_nhg_hash_alloc
);
615 SET_FLAG((*nhe
)->flags
, NEXTHOP_GROUP_RECURSIVE
);
620 /* Find/create a single nexthop */
621 static struct nhg_hash_entry
*
622 zebra_nhg_find_nexthop(uint32_t id
, struct nexthop
*nh
, afi_t afi
, int type
)
624 struct nhg_hash_entry
*nhe
= NULL
;
625 struct nexthop_group nhg
= {};
626 vrf_id_t vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nh
->vrf_id
;
628 nexthop_group_add_sorted(&nhg
, nh
);
630 zebra_nhg_find(&nhe
, id
, &nhg
, NULL
, vrf_id
, afi
, type
);
635 static uint32_t nhg_ctx_get_id(const struct nhg_ctx
*ctx
)
640 static void nhg_ctx_set_status(struct nhg_ctx
*ctx
, enum nhg_ctx_status status
)
642 ctx
->status
= status
;
645 static enum nhg_ctx_status
nhg_ctx_get_status(const struct nhg_ctx
*ctx
)
650 static void nhg_ctx_set_op(struct nhg_ctx
*ctx
, enum nhg_ctx_op_e op
)
655 static enum nhg_ctx_op_e
nhg_ctx_get_op(const struct nhg_ctx
*ctx
)
660 static vrf_id_t
nhg_ctx_get_vrf_id(const struct nhg_ctx
*ctx
)
665 static int nhg_ctx_get_type(const struct nhg_ctx
*ctx
)
670 static int nhg_ctx_get_afi(const struct nhg_ctx
*ctx
)
675 static struct nexthop
*nhg_ctx_get_nh(struct nhg_ctx
*ctx
)
680 static uint8_t nhg_ctx_get_count(const struct nhg_ctx
*ctx
)
685 static struct nh_grp
*nhg_ctx_get_grp(struct nhg_ctx
*ctx
)
690 static struct nhg_ctx
*nhg_ctx_new()
692 struct nhg_ctx
*new = NULL
;
694 new = XCALLOC(MTYPE_NHG_CTX
, sizeof(struct nhg_ctx
));
699 static void nhg_ctx_free(struct nhg_ctx
**ctx
)
706 assert((*ctx
) != NULL
);
708 if (nhg_ctx_get_count(*ctx
))
711 nh
= nhg_ctx_get_nh(*ctx
);
713 nexthop_del_labels(nh
);
716 XFREE(MTYPE_NHG_CTX
, *ctx
);
719 static struct nhg_ctx
*nhg_ctx_init(uint32_t id
, struct nexthop
*nh
,
720 struct nh_grp
*grp
, vrf_id_t vrf_id
,
721 afi_t afi
, int type
, uint8_t count
)
723 struct nhg_ctx
*ctx
= NULL
;
728 ctx
->vrf_id
= vrf_id
;
734 /* Copy over the array */
735 memcpy(&ctx
->u
.grp
, grp
, count
* sizeof(struct nh_grp
));
742 static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry
*nhe
)
744 struct nhg_connected
*rb_node_dep
= NULL
;
746 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
747 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
,
748 NEXTHOP_GROUP_UNHASHABLE
))
755 static void zebra_nhg_set_unhashable(struct nhg_hash_entry
*nhe
)
757 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
);
758 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
761 EC_ZEBRA_DUPLICATE_NHG_MESSAGE
,
762 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
766 static void zebra_nhg_set_valid(struct nhg_hash_entry
*nhe
)
768 struct nhg_connected
*rb_node_dep
;
770 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
772 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
773 zebra_nhg_set_valid(rb_node_dep
->nhe
);
776 static void zebra_nhg_set_invalid(struct nhg_hash_entry
*nhe
)
778 struct nhg_connected
*rb_node_dep
;
780 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
782 /* Update validity of nexthops depending on it */
783 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
784 zebra_nhg_check_valid(rb_node_dep
->nhe
);
787 void zebra_nhg_check_valid(struct nhg_hash_entry
*nhe
)
789 struct nhg_connected
*rb_node_dep
= NULL
;
792 /* If anthing else in the group is valid, the group is valid */
793 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
794 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
, NEXTHOP_GROUP_VALID
)) {
802 zebra_nhg_set_valid(nhe
);
804 zebra_nhg_set_invalid(nhe
);
808 static void zebra_nhg_release(struct nhg_hash_entry
*nhe
)
810 /* Remove it from any lists it may be on */
811 zebra_nhg_depends_release(nhe
);
812 zebra_nhg_dependents_release(nhe
);
814 if_nhg_dependents_del(nhe
->ifp
, nhe
);
817 * If its unhashable, we didn't store it here and have to be
818 * sure we don't clear one thats actually being used.
820 if (!CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
))
821 hash_release(zrouter
.nhgs
, nhe
);
823 hash_release(zrouter
.nhgs_id
, nhe
);
826 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry
*nhe
)
828 zebra_nhg_release(nhe
);
832 static void zebra_nhg_handle_install(struct nhg_hash_entry
*nhe
)
834 /* Update validity of groups depending on it */
835 struct nhg_connected
*rb_node_dep
;
837 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
838 zebra_nhg_set_valid(rb_node_dep
->nhe
);
842 * The kernel/other program has changed the state of a nexthop object we are
845 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry
*nhe
,
851 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
852 (is_delete
? "deleted" : "updated"), nhe
->id
);
854 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
855 zebra_nhg_install_kernel(nhe
);
857 zebra_nhg_handle_uninstall(nhe
);
860 static int nhg_ctx_process_new(struct nhg_ctx
*ctx
)
862 struct nexthop_group
*nhg
= NULL
;
863 struct nhg_connected_tree_head nhg_depends
= {};
864 struct nhg_hash_entry
*lookup
= NULL
;
865 struct nhg_hash_entry
*nhe
= NULL
;
867 uint32_t id
= nhg_ctx_get_id(ctx
);
868 uint8_t count
= nhg_ctx_get_count(ctx
);
869 vrf_id_t vrf_id
= nhg_ctx_get_vrf_id(ctx
);
870 int type
= nhg_ctx_get_type(ctx
);
871 afi_t afi
= nhg_ctx_get_afi(ctx
);
873 lookup
= zebra_nhg_lookup_id(id
);
876 /* This is already present in our table, hence an update
877 * that we did not initate.
879 zebra_nhg_handle_kernel_state_change(lookup
, false);
883 if (nhg_ctx_get_count(ctx
)) {
884 nhg
= nexthop_group_new();
885 if (zebra_nhg_process_grp(nhg
, &nhg_depends
,
886 nhg_ctx_get_grp(ctx
), count
)) {
887 depends_decrement_free(&nhg_depends
);
888 nexthop_group_delete(&nhg
);
892 if (!zebra_nhg_find(&nhe
, id
, nhg
, &nhg_depends
, vrf_id
, type
,
894 depends_decrement_free(&nhg_depends
);
896 /* These got copied over in zebra_nhg_alloc() */
897 nexthop_group_delete(&nhg
);
899 nhe
= zebra_nhg_find_nexthop(id
, nhg_ctx_get_nh(ctx
), afi
,
904 struct nhg_hash_entry
*kernel_nhe
= NULL
;
906 /* Duplicate but with different ID from
910 /* The kernel allows duplicate nexthops
911 * as long as they have different IDs.
912 * We are ignoring those to prevent
913 * syncing problems with the kernel
916 * We maintain them *ONLY* in the ID hash table to
917 * track them and set the flag to indicated
918 * their attributes are unhashable.
921 kernel_nhe
= zebra_nhg_copy(nhe
, id
);
922 zebra_nhg_insert_id(kernel_nhe
);
923 zebra_nhg_set_unhashable(kernel_nhe
);
924 } else if (zebra_nhg_contains_unhashable(nhe
)) {
925 /* The group we got contains an unhashable/duplicated
926 * depend, so lets mark this group as unhashable as well
927 * and release it from the non-ID hash.
929 hash_release(zrouter
.nhgs
, nhe
);
930 zebra_nhg_set_unhashable(nhe
);
932 /* It actually created a new nhe */
933 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
934 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
938 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
939 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
947 static int nhg_ctx_process_del(struct nhg_ctx
*ctx
)
949 struct nhg_hash_entry
*nhe
= NULL
;
950 uint32_t id
= nhg_ctx_get_id(ctx
);
952 nhe
= zebra_nhg_lookup_id(id
);
956 EC_ZEBRA_BAD_NHG_MESSAGE
,
957 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
962 zebra_nhg_handle_kernel_state_change(nhe
, true);
967 static void nhg_ctx_fini(struct nhg_ctx
**ctx
)
970 * Just freeing for now, maybe do something more in the future
977 static int queue_add(struct nhg_ctx
*ctx
)
979 /* If its queued or already processed do nothing */
980 if (nhg_ctx_get_status(ctx
) == NHG_CTX_QUEUED
)
983 if (rib_queue_nhg_add(ctx
)) {
984 nhg_ctx_set_status(ctx
, NHG_CTX_FAILURE
);
988 nhg_ctx_set_status(ctx
, NHG_CTX_QUEUED
);
993 int nhg_ctx_process(struct nhg_ctx
*ctx
)
997 switch (nhg_ctx_get_op(ctx
)) {
999 ret
= nhg_ctx_process_new(ctx
);
1000 if (nhg_ctx_get_count(ctx
) && ret
== -ENOENT
1001 && nhg_ctx_get_status(ctx
) != NHG_CTX_REQUEUED
) {
1003 * We have entered a situation where we are
1004 * processing a group from the kernel
1005 * that has a contained nexthop which
1006 * we have not yet processed.
1008 * Re-enqueue this ctx to be handled exactly one
1009 * more time (indicated by the flag).
1011 * By the time we get back to it, we
1012 * should have processed its depends.
1014 nhg_ctx_set_status(ctx
, NHG_CTX_NONE
);
1015 if (queue_add(ctx
) == 0) {
1016 nhg_ctx_set_status(ctx
, NHG_CTX_REQUEUED
);
1021 case NHG_CTX_OP_DEL
:
1022 ret
= nhg_ctx_process_del(ctx
);
1023 case NHG_CTX_OP_NONE
:
1027 nhg_ctx_set_status(ctx
, (ret
? NHG_CTX_FAILURE
: NHG_CTX_SUCCESS
));
1034 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1035 int zebra_nhg_kernel_find(uint32_t id
, struct nexthop
*nh
, struct nh_grp
*grp
,
1036 uint8_t count
, vrf_id_t vrf_id
, afi_t afi
, int type
,
1039 struct nhg_ctx
*ctx
= NULL
;
1041 if (id
> id_counter
)
1042 /* Increase our counter so we don't try to create
1043 * an ID that already exists
1047 ctx
= nhg_ctx_init(id
, nh
, grp
, vrf_id
, afi
, type
, count
);
1048 nhg_ctx_set_op(ctx
, NHG_CTX_OP_NEW
);
1050 /* Under statup conditions, we need to handle them immediately
1051 * like we do for routes. Otherwise, we are going to get a route
1052 * with a nhe_id that we have not handled.
1055 return nhg_ctx_process(ctx
);
1057 if (queue_add(ctx
)) {
1065 /* Kernel-side, received delete message */
1066 int zebra_nhg_kernel_del(uint32_t id
, vrf_id_t vrf_id
)
1068 struct nhg_ctx
*ctx
= NULL
;
1070 ctx
= nhg_ctx_init(id
, NULL
, NULL
, vrf_id
, 0, 0, 0);
1072 nhg_ctx_set_op(ctx
, NHG_CTX_OP_DEL
);
1074 if (queue_add(ctx
)) {
1082 /* Some dependency helper functions */
1083 static struct nhg_hash_entry
*depends_find_recursive(const struct nexthop
*nh
,
1086 struct nhg_hash_entry
*nhe
;
1087 struct nexthop
*lookup
= NULL
;
1089 lookup
= nexthop_dup(nh
, NULL
);
1091 nhe
= zebra_nhg_find_nexthop(0, lookup
, afi
, 0);
1093 nexthops_free(lookup
);
1098 static struct nhg_hash_entry
*depends_find_singleton(const struct nexthop
*nh
,
1101 struct nhg_hash_entry
*nhe
;
1102 struct nexthop lookup
= {};
1104 /* Capture a snapshot of this single nh; it might be part of a list,
1105 * so we need to make a standalone copy.
1107 nexthop_copy_no_recurse(&lookup
, nh
, NULL
);
1109 nhe
= zebra_nhg_find_nexthop(0, &lookup
, afi
, 0);
1111 /* The copy may have allocated labels; free them if necessary. */
1112 nexthop_del_labels(&lookup
);
1117 static struct nhg_hash_entry
*depends_find(const struct nexthop
*nh
, afi_t afi
)
1119 struct nhg_hash_entry
*nhe
= NULL
;
1124 /* We are separating these functions out to increase handling speed
1125 * in the non-recursive case (by not alloc/freeing)
1127 if (CHECK_FLAG(nh
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1128 nhe
= depends_find_recursive(nh
, afi
);
1130 nhe
= depends_find_singleton(nh
, afi
);
1136 static void depends_add(struct nhg_connected_tree_head
*head
,
1137 struct nhg_hash_entry
*depend
)
1139 /* If NULL is returned, it was successfully added and
1140 * needs to have its refcnt incremented.
1142 * Else the NHE is already present in the tree and doesn't
1143 * need to increment the refcnt.
1145 if (nhg_connected_tree_add_nhe(head
, depend
) == NULL
)
1146 zebra_nhg_increment_ref(depend
);
1149 static struct nhg_hash_entry
*
1150 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
1153 struct nhg_hash_entry
*depend
= NULL
;
1155 depend
= depends_find(nh
, afi
);
1158 depends_add(head
, depend
);
1163 static struct nhg_hash_entry
*
1164 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
)
1166 struct nhg_hash_entry
*depend
= NULL
;
1168 depend
= zebra_nhg_lookup_id(id
);
1171 depends_add(head
, depend
);
1176 static void depends_decrement_free(struct nhg_connected_tree_head
*head
)
1178 nhg_connected_tree_decrement_ref(head
);
1179 nhg_connected_tree_free(head
);
1182 /* Rib-side, you get a nexthop group struct */
1183 struct nhg_hash_entry
*
1184 zebra_nhg_rib_find(uint32_t id
, struct nexthop_group
*nhg
, afi_t rt_afi
)
1186 struct nhg_hash_entry
*nhe
= NULL
;
1190 * CLANG SA is complaining that nexthop may be NULL
1191 * Make it happy but this is ridonc
1193 assert(nhg
->nexthop
);
1194 vrf_id
= !vrf_is_backend_netns() ? VRF_DEFAULT
: nhg
->nexthop
->vrf_id
;
1196 if (!(nhg
&& nhg
->nexthop
)) {
1197 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1198 "No nexthop passed to %s", __func__
);
1202 zebra_nhg_find(&nhe
, id
, nhg
, NULL
, vrf_id
, rt_afi
, 0);
1207 static void zebra_nhg_free_members(struct nhg_hash_entry
*nhe
)
1209 nexthop_group_delete(&nhe
->nhg
);
1210 /* Decrement to remove connection ref */
1211 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1212 nhg_connected_tree_free(&nhe
->nhg_depends
);
1213 nhg_connected_tree_free(&nhe
->nhg_dependents
);
1216 void zebra_nhg_free(struct nhg_hash_entry
*nhe
)
1219 zlog_debug("nhe_id=%u hash refcnt=%d", nhe
->id
, nhe
->refcnt
);
1221 zebra_nhg_free_members(nhe
);
1223 XFREE(MTYPE_NHG
, nhe
);
1226 void zebra_nhg_hash_free(void *p
)
1228 zebra_nhg_free((struct nhg_hash_entry
*)p
);
1231 void zebra_nhg_decrement_ref(struct nhg_hash_entry
*nhe
)
1235 if (!zebra_nhg_depends_is_empty(nhe
))
1236 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1238 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1239 zebra_nhg_uninstall_kernel(nhe
);
1242 void zebra_nhg_increment_ref(struct nhg_hash_entry
*nhe
)
1246 if (!zebra_nhg_depends_is_empty(nhe
))
1247 nhg_connected_tree_increment_ref(&nhe
->nhg_depends
);
1250 static void nexthop_set_resolved(afi_t afi
, const struct nexthop
*newhop
,
1251 struct nexthop
*nexthop
)
1253 struct nexthop
*resolved_hop
;
1254 uint8_t num_labels
= 0;
1255 mpls_label_t labels
[MPLS_MAX_LABELS
];
1256 enum lsp_types_t label_type
= ZEBRA_LSP_NONE
;
1259 resolved_hop
= nexthop_new();
1260 SET_FLAG(resolved_hop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1262 resolved_hop
->vrf_id
= nexthop
->vrf_id
;
1263 switch (newhop
->type
) {
1264 case NEXTHOP_TYPE_IPV4
:
1265 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1266 /* If the resolving route specifies a gateway, use it */
1267 resolved_hop
->type
= newhop
->type
;
1268 resolved_hop
->gate
.ipv4
= newhop
->gate
.ipv4
;
1270 if (newhop
->ifindex
) {
1271 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1272 resolved_hop
->ifindex
= newhop
->ifindex
;
1275 case NEXTHOP_TYPE_IPV6
:
1276 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1277 resolved_hop
->type
= newhop
->type
;
1278 resolved_hop
->gate
.ipv6
= newhop
->gate
.ipv6
;
1280 if (newhop
->ifindex
) {
1281 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1282 resolved_hop
->ifindex
= newhop
->ifindex
;
1285 case NEXTHOP_TYPE_IFINDEX
:
1286 /* If the resolving route is an interface route,
1287 * it means the gateway we are looking up is connected
1288 * to that interface. (The actual network is _not_ onlink).
1289 * Therefore, the resolved route should have the original
1290 * gateway as nexthop as it is directly connected.
1292 * On Linux, we have to set the onlink netlink flag because
1293 * otherwise, the kernel won't accept the route.
1295 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1296 if (afi
== AFI_IP
) {
1297 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1298 resolved_hop
->gate
.ipv4
= nexthop
->gate
.ipv4
;
1299 } else if (afi
== AFI_IP6
) {
1300 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1301 resolved_hop
->gate
.ipv6
= nexthop
->gate
.ipv6
;
1303 resolved_hop
->ifindex
= newhop
->ifindex
;
1305 case NEXTHOP_TYPE_BLACKHOLE
:
1306 resolved_hop
->type
= NEXTHOP_TYPE_BLACKHOLE
;
1307 resolved_hop
->bh_type
= newhop
->bh_type
;
1311 if (newhop
->flags
& NEXTHOP_FLAG_ONLINK
)
1312 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1314 /* Copy labels of the resolved route and the parent resolving to it */
1315 if (newhop
->nh_label
) {
1316 for (i
= 0; i
< newhop
->nh_label
->num_labels
; i
++)
1317 labels
[num_labels
++] = newhop
->nh_label
->label
[i
];
1318 label_type
= newhop
->nh_label_type
;
1321 if (nexthop
->nh_label
) {
1322 for (i
= 0; i
< nexthop
->nh_label
->num_labels
; i
++)
1323 labels
[num_labels
++] = nexthop
->nh_label
->label
[i
];
1325 /* If the parent has labels, use its type */
1326 label_type
= nexthop
->nh_label_type
;
1330 nexthop_add_labels(resolved_hop
, label_type
, num_labels
,
1333 resolved_hop
->rparent
= nexthop
;
1334 _nexthop_add(&nexthop
->resolved
, resolved_hop
);
1337 /* Checks if nexthop we are trying to resolve to is valid */
1338 static bool nexthop_valid_resolve(const struct nexthop
*nexthop
,
1339 const struct nexthop
*resolved
)
1341 /* Can't resolve to a recursive nexthop */
1342 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1345 switch (nexthop
->type
) {
1346 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1347 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1348 /* If the nexthop we are resolving to does not match the
1349 * ifindex for the nexthop the route wanted, its not valid.
1351 if (nexthop
->ifindex
!= resolved
->ifindex
)
1354 case NEXTHOP_TYPE_IPV4
:
1355 case NEXTHOP_TYPE_IPV6
:
1356 case NEXTHOP_TYPE_IFINDEX
:
1357 case NEXTHOP_TYPE_BLACKHOLE
:
1365 * Given a nexthop we need to properly recursively resolve
1366 * the route. As such, do a table lookup to find and match
1367 * if at all possible. Set the nexthop->ifindex and resolved_id
1370 static int nexthop_active(afi_t afi
, struct route_entry
*re
,
1371 struct nexthop
*nexthop
, struct route_node
*top
)
1374 struct route_table
*table
;
1375 struct route_node
*rn
;
1376 struct route_entry
*match
= NULL
;
1378 struct nexthop
*newhop
;
1379 struct interface
*ifp
;
1381 struct zebra_vrf
*zvrf
;
1383 if ((nexthop
->type
== NEXTHOP_TYPE_IPV4
)
1384 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1385 nexthop
->ifindex
= 0;
1388 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
);
1389 nexthops_free(nexthop
->resolved
);
1390 nexthop
->resolved
= NULL
;
1391 re
->nexthop_mtu
= 0;
1394 * If the kernel has sent us a NEW route, then
1395 * by golly gee whiz it's a good route.
1397 * If its an already INSTALLED route we have already handled, then the
1398 * kernel route's nexthop might have became unreachable
1399 * and we have to handle that.
1401 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
)
1402 && (re
->type
== ZEBRA_ROUTE_KERNEL
1403 || re
->type
== ZEBRA_ROUTE_SYSTEM
))
1407 * Check to see if we should trust the passed in information
1408 * for UNNUMBERED interfaces as that we won't find the GW
1409 * address in the routing table.
1410 * This check should suffice to handle IPv4 or IPv6 routes
1411 * sourced from EVPN routes which are installed with the
1412 * next hop as the remote VTEP IP.
1414 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ONLINK
)) {
1415 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1417 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1419 "\t%s: Onlink and interface: %u[%u] does not exist",
1420 __PRETTY_FUNCTION__
, nexthop
->ifindex
,
1424 if (connected_is_unnumbered(ifp
)) {
1425 if (if_is_operative(ifp
))
1428 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1430 "\t%s: Onlink and interface %s is not operative",
1431 __PRETTY_FUNCTION__
, ifp
->name
);
1434 if (!if_is_operative(ifp
)) {
1435 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1437 "\t%s: Interface %s is not unnumbered",
1438 __PRETTY_FUNCTION__
, ifp
->name
);
1443 if ((top
->p
.family
== AF_INET
&& top
->p
.prefixlen
== 32
1444 && nexthop
->gate
.ipv4
.s_addr
== top
->p
.u
.prefix4
.s_addr
)
1445 || (top
->p
.family
== AF_INET6
&& top
->p
.prefixlen
== 128
1446 && memcmp(&nexthop
->gate
.ipv6
, &top
->p
.u
.prefix6
, 16) == 0)) {
1447 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1449 "\t:%s: Attempting to install a max prefixlength route through itself",
1450 __PRETTY_FUNCTION__
);
1454 /* Make lookup prefix. */
1455 memset(&p
, 0, sizeof(struct prefix
));
1459 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1460 p
.u
.prefix4
= nexthop
->gate
.ipv4
;
1463 p
.family
= AF_INET6
;
1464 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
1465 p
.u
.prefix6
= nexthop
->gate
.ipv6
;
1468 assert(afi
!= AFI_IP
&& afi
!= AFI_IP6
);
1472 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, nexthop
->vrf_id
);
1474 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
1475 if (!table
|| !zvrf
) {
1476 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1477 zlog_debug("\t%s: Table not found",
1478 __PRETTY_FUNCTION__
);
1482 rn
= route_node_match(table
, (struct prefix
*)&p
);
1484 route_unlock_node(rn
);
1486 /* Lookup should halt if we've matched against ourselves ('top',
1487 * if specified) - i.e., we cannot have a nexthop NH1 is
1488 * resolved by a route NH1. The exception is if the route is a
1492 if (((afi
== AFI_IP
) && (rn
->p
.prefixlen
!= 32))
1493 || ((afi
== AFI_IP6
) && (rn
->p
.prefixlen
!= 128))) {
1494 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1496 "\t%s: Matched against ourself and prefix length is not max bit length",
1497 __PRETTY_FUNCTION__
);
1501 /* Pick up selected route. */
1502 /* However, do not resolve over default route unless explicitly
1505 if (is_default_prefix(&rn
->p
)
1506 && !rnh_resolve_via_default(zvrf
, p
.family
)) {
1507 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1509 "\t:%s: Resolved against default route",
1510 __PRETTY_FUNCTION__
);
1514 dest
= rib_dest_from_rnode(rn
);
1515 if (dest
&& dest
->selected_fib
1516 && !CHECK_FLAG(dest
->selected_fib
->status
,
1517 ROUTE_ENTRY_REMOVED
)
1518 && dest
->selected_fib
->type
!= ZEBRA_ROUTE_TABLE
)
1519 match
= dest
->selected_fib
;
1521 /* If there is no selected route or matched route is EGP, go up
1527 } while (rn
&& rn
->info
== NULL
);
1529 route_lock_node(rn
);
1534 if (match
->type
== ZEBRA_ROUTE_CONNECT
) {
1535 /* Directly point connected route. */
1536 newhop
= match
->nhe
->nhg
->nexthop
;
1538 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
1539 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1540 nexthop
->ifindex
= newhop
->ifindex
;
1543 } else if (CHECK_FLAG(re
->flags
, ZEBRA_FLAG_ALLOW_RECURSION
)) {
1545 for (ALL_NEXTHOPS_PTR(match
->nhe
->nhg
, newhop
)) {
1546 if (!CHECK_FLAG(match
->status
,
1547 ROUTE_ENTRY_INSTALLED
))
1549 if (!nexthop_valid_resolve(nexthop
, newhop
))
1552 SET_FLAG(nexthop
->flags
,
1553 NEXTHOP_FLAG_RECURSIVE
);
1554 nexthop_set_resolved(afi
, newhop
, nexthop
);
1558 re
->nexthop_mtu
= match
->mtu
;
1560 if (!resolved
&& IS_ZEBRA_DEBUG_RIB_DETAILED
)
1561 zlog_debug("\t%s: Recursion failed to find",
1562 __PRETTY_FUNCTION__
);
1564 } else if (re
->type
== ZEBRA_ROUTE_STATIC
) {
1566 for (ALL_NEXTHOPS_PTR(match
->nhe
->nhg
, newhop
)) {
1567 if (!CHECK_FLAG(match
->status
,
1568 ROUTE_ENTRY_INSTALLED
))
1570 if (!nexthop_valid_resolve(nexthop
, newhop
))
1573 SET_FLAG(nexthop
->flags
,
1574 NEXTHOP_FLAG_RECURSIVE
);
1575 nexthop_set_resolved(afi
, newhop
, nexthop
);
1579 re
->nexthop_mtu
= match
->mtu
;
1581 if (!resolved
&& IS_ZEBRA_DEBUG_RIB_DETAILED
)
1583 "\t%s: Static route unable to resolve",
1584 __PRETTY_FUNCTION__
);
1587 if (IS_ZEBRA_DEBUG_RIB_DETAILED
) {
1589 "\t%s: Route Type %s has not turned on recursion",
1590 __PRETTY_FUNCTION__
,
1591 zebra_route_string(re
->type
));
1592 if (re
->type
== ZEBRA_ROUTE_BGP
1593 && !CHECK_FLAG(re
->flags
, ZEBRA_FLAG_IBGP
))
1595 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1600 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1601 zlog_debug("\t%s: Nexthop did not lookup in table",
1602 __PRETTY_FUNCTION__
);
1606 /* This function verifies reachability of one given nexthop, which can be
1607 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1608 * in nexthop->flags field. The nexthop->ifindex will be updated
1609 * appropriately as well. An existing route map can turn
1610 * (otherwise active) nexthop into inactive, but not vice versa.
1612 * If it finds a nexthop recursivedly, set the resolved_id
1613 * to match that nexthop's nhg_hash_entry ID;
1615 * The return value is the final value of 'ACTIVE' flag.
1617 static unsigned nexthop_active_check(struct route_node
*rn
,
1618 struct route_entry
*re
,
1619 struct nexthop
*nexthop
)
1621 struct interface
*ifp
;
1622 route_map_result_t ret
= RMAP_PERMITMATCH
;
1624 char buf
[SRCDEST2STR_BUFFER
];
1625 const struct prefix
*p
, *src_p
;
1626 struct zebra_vrf
*zvrf
;
1628 srcdest_rnode_prefixes(rn
, &p
, &src_p
);
1630 if (rn
->p
.family
== AF_INET
)
1632 else if (rn
->p
.family
== AF_INET6
)
1636 switch (nexthop
->type
) {
1637 case NEXTHOP_TYPE_IFINDEX
:
1638 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1639 if (ifp
&& if_is_operative(ifp
))
1640 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1642 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1644 case NEXTHOP_TYPE_IPV4
:
1645 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1647 if (nexthop_active(AFI_IP
, re
, nexthop
, rn
))
1648 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1650 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1652 case NEXTHOP_TYPE_IPV6
:
1654 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
1655 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1657 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1659 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1660 /* RFC 5549, v4 prefix with v6 NH */
1661 if (rn
->p
.family
!= AF_INET
)
1663 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
1664 ifp
= if_lookup_by_index(nexthop
->ifindex
,
1666 if (ifp
&& if_is_operative(ifp
))
1667 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1669 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1671 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
1672 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1674 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1677 case NEXTHOP_TYPE_BLACKHOLE
:
1678 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1683 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
1684 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1685 zlog_debug("\t%s: Unable to find a active nexthop",
1686 __PRETTY_FUNCTION__
);
1690 /* XXX: What exactly do those checks do? Do we support
1691 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1693 if (RIB_SYSTEM_ROUTE(re
) || (family
== AFI_IP
&& p
->family
!= AF_INET
)
1694 || (family
== AFI_IP6
&& p
->family
!= AF_INET6
))
1695 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1697 /* The original code didn't determine the family correctly
1698 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1699 * from the rib_table_info in those cases.
1700 * Possibly it may be better to use only the rib_table_info
1704 rib_table_info_t
*info
;
1706 info
= srcdest_rnode_table_info(rn
);
1710 memset(&nexthop
->rmap_src
.ipv6
, 0, sizeof(union g_addr
));
1712 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
1714 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1715 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__
);
1716 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1719 /* It'll get set if required inside */
1720 ret
= zebra_route_map_check(family
, re
->type
, re
->instance
, p
, nexthop
,
1722 if (ret
== RMAP_DENYMATCH
) {
1723 if (IS_ZEBRA_DEBUG_RIB
) {
1724 srcdest_rnode2str(rn
, buf
, sizeof(buf
));
1726 "%u:%s: Filtering out with NH out %s due to route map",
1728 ifindex2ifname(nexthop
->ifindex
,
1731 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1733 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1737 * Iterate over all nexthops of the given RIB entry and refresh their
1738 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1739 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
1741 * Return value is the new number of active nexthops.
1743 int nexthop_active_update(struct route_node
*rn
, struct route_entry
*re
)
1745 struct nexthop_group new_grp
= {};
1746 struct nexthop
*nexthop
;
1747 union g_addr prev_src
;
1748 unsigned int prev_active
, new_active
;
1749 ifindex_t prev_index
;
1750 uint8_t curr_active
= 0;
1752 afi_t rt_afi
= family2afi(rn
->p
.family
);
1754 UNSET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
1756 /* Copy over the nexthops in current state */
1757 nexthop_group_copy(&new_grp
, re
->nhe
->nhg
);
1759 for (nexthop
= new_grp
.nexthop
; nexthop
; nexthop
= nexthop
->next
) {
1761 /* No protocol daemon provides src and so we're skipping
1763 prev_src
= nexthop
->rmap_src
;
1764 prev_active
= CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1765 prev_index
= nexthop
->ifindex
;
1767 * We need to respect the multipath_num here
1768 * as that what we should be able to install from
1769 * a multipath perpsective should not be a data plane
1773 nexthop_active_check(rn
, re
, nexthop
);
1775 if (new_active
&& curr_active
>= zrouter
.multipath_num
) {
1778 /* Set it and its resolved nexthop as inactive. */
1779 for (nh
= nexthop
; nh
; nh
= nh
->resolved
)
1780 UNSET_FLAG(nh
->flags
, NEXTHOP_FLAG_ACTIVE
);
1788 /* Don't allow src setting on IPv6 addr for now */
1789 if (prev_active
!= new_active
|| prev_index
!= nexthop
->ifindex
1790 || ((nexthop
->type
>= NEXTHOP_TYPE_IFINDEX
1791 && nexthop
->type
< NEXTHOP_TYPE_IPV6
)
1792 && prev_src
.ipv4
.s_addr
1793 != nexthop
->rmap_src
.ipv4
.s_addr
)
1794 || ((nexthop
->type
>= NEXTHOP_TYPE_IPV6
1795 && nexthop
->type
< NEXTHOP_TYPE_BLACKHOLE
)
1796 && !(IPV6_ADDR_SAME(&prev_src
.ipv6
,
1797 &nexthop
->rmap_src
.ipv6
)))
1798 || CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
1799 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
1802 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
)) {
1803 struct nhg_hash_entry
*new_nhe
= NULL
;
1805 new_nhe
= zebra_nhg_rib_find(0, &new_grp
, rt_afi
);
1807 route_entry_update_nhe(re
, new_nhe
);
1811 struct nhg_hash_entry
*nhe
= NULL
;
1813 nhe
= zebra_nhg_lookup_id(re
->nhe_id
);
1816 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1819 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1820 "Active update on NHE id=%u that we do not have in our tables",
1825 * Do not need these nexthops anymore since they
1826 * were either copied over into an nhe or not
1829 nexthops_free(new_grp
.nexthop
);
1833 /* Convert a nhe into a group array */
1834 uint8_t zebra_nhg_nhe2grp(struct nh_grp
*grp
, struct nhg_hash_entry
*nhe
,
1837 struct nhg_connected
*rb_node_dep
= NULL
;
1838 struct nhg_hash_entry
*depend
= NULL
;
1841 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1842 bool duplicate
= false;
1844 depend
= rb_node_dep
->nhe
;
1847 * If its recursive, use its resolved nhe in the group
1849 if (CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_RECURSIVE
)) {
1850 depend
= zebra_nhg_resolve(depend
);
1853 EC_ZEBRA_NHG_FIB_UPDATE
,
1854 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
1860 /* Check for duplicate IDs, kernel doesn't like that */
1861 for (int j
= 0; j
< i
; j
++) {
1862 if (depend
->id
== grp
[j
].id
)
1867 grp
[i
].id
= depend
->id
;
1868 /* We aren't using weights for anything right now */
1869 grp
[i
].weight
= depend
->nhg
->nexthop
->weight
;
1881 void zebra_nhg_install_kernel(struct nhg_hash_entry
*nhe
)
1883 struct nhg_connected
*rb_node_dep
= NULL
;
1885 /* Resolve it first */
1886 nhe
= zebra_nhg_resolve(nhe
);
1888 /* Make sure all depends are installed/queued */
1889 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1890 zebra_nhg_install_kernel(rb_node_dep
->nhe
);
1893 if (!CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)
1894 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
)) {
1895 /* Change its type to us since we are installing it */
1896 nhe
->type
= ZEBRA_ROUTE_NHG
;
1898 int ret
= dplane_nexthop_add(nhe
);
1901 case ZEBRA_DPLANE_REQUEST_QUEUED
:
1902 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1904 case ZEBRA_DPLANE_REQUEST_FAILURE
:
1906 EC_ZEBRA_DP_INSTALL_FAIL
,
1907 "Failed to install Nexthop ID (%u) into the kernel",
1910 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
1911 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1912 zebra_nhg_handle_install(nhe
);
1918 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry
*nhe
)
1920 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)) {
1921 int ret
= dplane_nexthop_delete(nhe
);
1924 case ZEBRA_DPLANE_REQUEST_QUEUED
:
1925 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1927 case ZEBRA_DPLANE_REQUEST_FAILURE
:
1929 EC_ZEBRA_DP_DELETE_FAIL
,
1930 "Failed to uninstall Nexthop ID (%u) from the kernel",
1933 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
1934 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1939 zebra_nhg_handle_uninstall(nhe
);
1942 void zebra_nhg_dplane_result(struct zebra_dplane_ctx
*ctx
)
1944 enum dplane_op_e op
;
1945 enum zebra_dplane_result status
;
1947 struct nhg_hash_entry
*nhe
= NULL
;
1949 op
= dplane_ctx_get_op(ctx
);
1950 status
= dplane_ctx_get_status(ctx
);
1952 id
= dplane_ctx_get_nhe_id(ctx
);
1954 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
)
1956 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1957 ctx
, dplane_op2str(op
), id
, dplane_res2str(status
));
1960 case DPLANE_OP_NH_DELETE
:
1961 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
1963 EC_ZEBRA_DP_DELETE_FAIL
,
1964 "Failed to uninstall Nexthop ID (%u) from the kernel",
1966 /* We already free'd the data, nothing to do */
1968 case DPLANE_OP_NH_INSTALL
:
1969 case DPLANE_OP_NH_UPDATE
:
1970 nhe
= zebra_nhg_lookup_id(id
);
1975 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1976 dplane_op2str(op
), id
);
1980 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1981 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
1982 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1983 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1984 zebra_nhg_handle_install(nhe
);
1987 EC_ZEBRA_DP_INSTALL_FAIL
,
1988 "Failed to install Nexthop ID (%u) into the kernel",
1991 case DPLANE_OP_ROUTE_INSTALL
:
1992 case DPLANE_OP_ROUTE_UPDATE
:
1993 case DPLANE_OP_ROUTE_DELETE
:
1994 case DPLANE_OP_ROUTE_NOTIFY
:
1995 case DPLANE_OP_LSP_INSTALL
:
1996 case DPLANE_OP_LSP_UPDATE
:
1997 case DPLANE_OP_LSP_DELETE
:
1998 case DPLANE_OP_LSP_NOTIFY
:
1999 case DPLANE_OP_PW_INSTALL
:
2000 case DPLANE_OP_PW_UNINSTALL
:
2001 case DPLANE_OP_SYS_ROUTE_ADD
:
2002 case DPLANE_OP_SYS_ROUTE_DELETE
:
2003 case DPLANE_OP_ADDR_INSTALL
:
2004 case DPLANE_OP_ADDR_UNINSTALL
:
2005 case DPLANE_OP_MAC_INSTALL
:
2006 case DPLANE_OP_MAC_DELETE
:
2007 case DPLANE_OP_NEIGH_INSTALL
:
2008 case DPLANE_OP_NEIGH_UPDATE
:
2009 case DPLANE_OP_NEIGH_DELETE
:
2010 case DPLANE_OP_VTEP_ADD
:
2011 case DPLANE_OP_VTEP_DELETE
:
2012 case DPLANE_OP_NONE
:
2016 dplane_ctx_fini(&ctx
);
2019 static void zebra_nhg_sweep_entry(struct hash_bucket
*bucket
, void *arg
)
2021 struct nhg_hash_entry
*nhe
= NULL
;
2023 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
2025 /* If its being ref'd, just let it be uninstalled via a route removal */
2026 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
2027 zebra_nhg_uninstall_kernel(nhe
);
2030 void zebra_nhg_sweep_table(struct hash
*hash
)
2032 hash_iterate(hash
, zebra_nhg_sweep_entry
, NULL
);
2035 /* Global control to disable use of kernel nexthops, if available. We can't
2036 * force the kernel to support nexthop ids, of course, but we can disable
2037 * zebra's use of them, for testing e.g. By default, if the kernel supports
2038 * nexthop ids, zebra uses them.
2040 void zebra_nhg_enable_kernel_nexthops(bool set
)
2042 g_nexthops_enabled
= set
;
2045 bool zebra_nhg_kernel_nexthops_enabled(void)
2047 return g_nexthops_enabled
;