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 */
52 static struct nhg_hash_entry
*depends_find(struct nexthop
*nh
, afi_t afi
);
53 static void depends_add(struct nhg_connected_tree_head
*head
,
54 struct nhg_hash_entry
*depend
);
55 static struct nhg_hash_entry
*
56 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
58 static struct nhg_hash_entry
*
59 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
);
60 static void depends_decrement_free(struct nhg_connected_tree_head
*head
);
63 static void nhg_connected_free(struct nhg_connected
*dep
)
65 XFREE(MTYPE_NHG_CONNECTED
, dep
);
68 static struct nhg_connected
*nhg_connected_new(struct nhg_hash_entry
*nhe
)
70 struct nhg_connected
*new = NULL
;
72 new = XCALLOC(MTYPE_NHG_CONNECTED
, sizeof(struct nhg_connected
));
78 void nhg_connected_tree_free(struct nhg_connected_tree_head
*head
)
80 struct nhg_connected
*rb_node_dep
= NULL
;
82 if (!nhg_connected_tree_is_empty(head
)) {
83 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
84 nhg_connected_tree_del(head
, rb_node_dep
);
85 nhg_connected_free(rb_node_dep
);
90 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head
*head
)
92 return nhg_connected_tree_count(head
) ? false : true;
95 struct nhg_connected
*
96 nhg_connected_tree_root(struct nhg_connected_tree_head
*head
)
98 return nhg_connected_tree_first(head
);
101 void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head
*head
,
102 struct nhg_hash_entry
*depend
)
104 struct nhg_connected lookup
= {};
105 struct nhg_connected
*remove
= NULL
;
109 /* Lookup to find the element, then remove it */
110 remove
= nhg_connected_tree_find(head
, &lookup
);
111 remove
= nhg_connected_tree_del(head
, remove
);
114 nhg_connected_free(remove
);
117 void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head
*head
,
118 struct nhg_hash_entry
*depend
)
120 struct nhg_connected
*new = NULL
;
122 new = nhg_connected_new(depend
);
125 nhg_connected_tree_add(head
, new);
129 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head
*head
)
131 struct nhg_connected
*rb_node_dep
= NULL
;
133 frr_each_safe(nhg_connected_tree
, head
, rb_node_dep
) {
134 zebra_nhg_decrement_ref(rb_node_dep
->nhe
);
139 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head
*head
)
141 struct nhg_connected
*rb_node_dep
= NULL
;
143 frr_each(nhg_connected_tree
, head
, rb_node_dep
) {
144 zebra_nhg_increment_ref(rb_node_dep
->nhe
);
148 struct nhg_hash_entry
*zebra_nhg_resolve(struct nhg_hash_entry
*nhe
)
150 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_RECURSIVE
)
151 && !zebra_nhg_depends_is_empty(nhe
)) {
152 nhe
= nhg_connected_tree_root(&nhe
->nhg_depends
)->nhe
;
153 return zebra_nhg_resolve(nhe
);
159 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry
*nhe
)
161 return nhg_connected_tree_count(&nhe
->nhg_depends
);
164 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry
*nhe
)
166 return nhg_connected_tree_is_empty(&nhe
->nhg_depends
);
169 static void zebra_nhg_depends_del(struct nhg_hash_entry
*from
,
170 struct nhg_hash_entry
*depend
)
172 nhg_connected_tree_del_nhe(&from
->nhg_depends
, depend
);
175 static void zebra_nhg_depends_init(struct nhg_hash_entry
*nhe
)
177 nhg_connected_tree_init(&nhe
->nhg_depends
);
180 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry
*nhe
)
182 return nhg_connected_tree_count(&nhe
->nhg_dependents
);
186 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry
*nhe
)
188 return nhg_connected_tree_is_empty(&nhe
->nhg_dependents
);
191 static void zebra_nhg_dependents_del(struct nhg_hash_entry
*from
,
192 struct nhg_hash_entry
*dependent
)
194 nhg_connected_tree_del_nhe(&from
->nhg_dependents
, dependent
);
197 static void zebra_nhg_dependents_add(struct nhg_hash_entry
*to
,
198 struct nhg_hash_entry
*dependent
)
200 nhg_connected_tree_add_nhe(&to
->nhg_dependents
, dependent
);
203 static void zebra_nhg_dependents_init(struct nhg_hash_entry
*nhe
)
205 nhg_connected_tree_init(&nhe
->nhg_dependents
);
208 /* Release this nhe from anything depending on it */
209 static void zebra_nhg_dependents_release(struct nhg_hash_entry
*nhe
)
211 struct nhg_connected
*rb_node_dep
= NULL
;
213 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
) {
214 zebra_nhg_depends_del(rb_node_dep
->nhe
, nhe
);
215 /* recheck validity of the dependent */
216 zebra_nhg_check_valid(rb_node_dep
->nhe
);
220 /* Release this nhe from anything that it depends on */
221 static void zebra_nhg_depends_release(struct nhg_hash_entry
*nhe
)
223 if (!zebra_nhg_depends_is_empty(nhe
)) {
224 struct nhg_connected
*rb_node_dep
= NULL
;
226 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_depends
,
228 zebra_nhg_dependents_del(rb_node_dep
->nhe
, nhe
);
234 struct nhg_hash_entry
*zebra_nhg_lookup_id(uint32_t id
)
236 struct nhg_hash_entry lookup
= {};
239 return hash_lookup(zrouter
.nhgs_id
, &lookup
);
242 static int zebra_nhg_insert_id(struct nhg_hash_entry
*nhe
)
244 if (hash_lookup(zrouter
.nhgs_id
, nhe
)) {
246 EC_ZEBRA_NHG_TABLE_INSERT_FAILED
,
247 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
252 hash_get(zrouter
.nhgs_id
, nhe
, hash_alloc_intern
);
257 static void zebra_nhg_set_if(struct nhg_hash_entry
*nhe
, struct interface
*ifp
)
260 if_nhg_dependents_add(ifp
, nhe
);
264 zebra_nhg_connect_depends(struct nhg_hash_entry
*nhe
,
265 struct nhg_connected_tree_head nhg_depends
)
267 struct nhg_connected
*rb_node_dep
= NULL
;
269 /* This has been allocated higher above in the stack. Could probably
270 * re-allocate and free the old stuff but just using the same memory
271 * for now. Otherwise, their might be a time trade-off for repeated
272 * alloc/frees as startup.
274 nhe
->nhg_depends
= nhg_depends
;
276 /* Attach backpointer to anything that it depends on */
277 zebra_nhg_dependents_init(nhe
);
278 if (!zebra_nhg_depends_is_empty(nhe
)) {
279 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
280 zebra_nhg_dependents_add(rb_node_dep
->nhe
, nhe
);
284 /* Add the ifp now if its not a group or recursive and has ifindex */
285 if (zebra_nhg_depends_is_empty(nhe
) && nhe
->nhg
->nexthop
286 && nhe
->nhg
->nexthop
->ifindex
) {
287 struct interface
*ifp
= NULL
;
289 ifp
= if_lookup_by_index(nhe
->nhg
->nexthop
->ifindex
,
292 zebra_nhg_set_if(nhe
, ifp
);
295 EC_ZEBRA_IF_LOOKUP_FAILED
,
296 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
297 nhe
->nhg
->nexthop
->ifindex
, nhe
->vrf_id
,
302 static struct nhg_hash_entry
*zebra_nhg_copy(struct nhg_hash_entry
*copy
,
305 struct nhg_hash_entry
*nhe
;
307 nhe
= XCALLOC(MTYPE_NHG
, sizeof(struct nhg_hash_entry
));
311 nhe
->nhg
= nexthop_group_new();
312 nexthop_group_copy(nhe
->nhg
, copy
->nhg
);
314 nhe
->vrf_id
= copy
->vrf_id
;
315 nhe
->afi
= copy
->afi
;
316 nhe
->type
= copy
->type
? copy
->type
: ZEBRA_ROUTE_NHG
;
318 nhe
->dplane_ref
= zebra_router_get_next_sequence();
323 /* Allocation via hash handler */
324 static void *zebra_nhg_hash_alloc(void *arg
)
326 struct nhg_hash_entry
*nhe
= NULL
;
327 struct nhg_hash_entry
*copy
= arg
;
329 nhe
= zebra_nhg_copy(copy
, copy
->id
);
331 /* Mark duplicate nexthops in a group at creation time. */
332 nexthop_group_mark_duplicates(nhe
->nhg
);
334 zebra_nhg_connect_depends(nhe
, copy
->nhg_depends
);
335 zebra_nhg_insert_id(nhe
);
340 uint32_t zebra_nhg_hash_key(const void *arg
)
342 const struct nhg_hash_entry
*nhe
= arg
;
344 uint32_t key
= 0x5a351234;
346 key
= jhash_3words(nhe
->vrf_id
, nhe
->afi
, nexthop_group_hash(nhe
->nhg
),
352 uint32_t zebra_nhg_id_key(const void *arg
)
354 const struct nhg_hash_entry
*nhe
= arg
;
359 bool zebra_nhg_hash_equal(const void *arg1
, const void *arg2
)
361 const struct nhg_hash_entry
*nhe1
= arg1
;
362 const struct nhg_hash_entry
*nhe2
= arg2
;
364 /* No matter what if they equal IDs, assume equal */
365 if (nhe1
->id
&& nhe2
->id
&& (nhe1
->id
== nhe2
->id
))
368 if (nhe1
->vrf_id
!= nhe2
->vrf_id
)
371 if (nhe1
->afi
!= nhe2
->afi
)
374 if (nexthop_group_active_nexthop_num_no_recurse(nhe1
->nhg
)
375 != nexthop_group_active_nexthop_num_no_recurse(nhe2
->nhg
))
378 if (!nexthop_group_equal_no_recurse(nhe1
->nhg
, nhe2
->nhg
))
384 bool zebra_nhg_hash_id_equal(const void *arg1
, const void *arg2
)
386 const struct nhg_hash_entry
*nhe1
= arg1
;
387 const struct nhg_hash_entry
*nhe2
= arg2
;
389 return nhe1
->id
== nhe2
->id
;
392 static int zebra_nhg_process_grp(struct nexthop_group
*nhg
,
393 struct nhg_connected_tree_head
*depends
,
394 struct nh_grp
*grp
, uint8_t count
)
396 nhg_connected_tree_init(depends
);
398 for (int i
= 0; i
< count
; i
++) {
399 struct nhg_hash_entry
*depend
= NULL
;
400 /* We do not care about nexthop_grp.weight at
401 * this time. But we should figure out
402 * how to adapt this to our code in
405 depend
= depends_find_id_add(depends
, grp
[i
].id
);
410 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
416 * If this is a nexthop with its own group
417 * dependencies, add them as well. Not sure its
418 * even possible to have a group within a group
422 copy_nexthops(&nhg
->nexthop
, depend
->nhg
->nexthop
, NULL
);
428 static void handle_recursive_depend(struct nhg_connected_tree_head
*nhg_depends
,
429 struct nexthop
*nh
, afi_t afi
)
431 struct nhg_hash_entry
*depend
= NULL
;
432 struct nexthop_group resolved_ng
= {};
434 _nexthop_group_add_sorted(&resolved_ng
, nh
);
436 depend
= zebra_nhg_rib_find(0, &resolved_ng
, afi
);
437 depends_add(nhg_depends
, depend
);
440 static bool zebra_nhg_find(struct nhg_hash_entry
**nhe
, uint32_t id
,
441 struct nexthop_group
*nhg
,
442 struct nhg_connected_tree_head
*nhg_depends
,
443 vrf_id_t vrf_id
, afi_t afi
, int type
)
445 struct nhg_hash_entry lookup
= {};
447 uint32_t old_id_counter
= id_counter
;
449 bool created
= false;
450 bool recursive
= false;
453 * If it has an id at this point, we must have gotten it from the kernel
455 lookup
.id
= id
? id
: ++id_counter
;
457 lookup
.type
= type
? type
: ZEBRA_ROUTE_NHG
;
460 if (lookup
.nhg
->nexthop
->next
) {
461 /* Groups can have all vrfs and AF's in them */
462 lookup
.afi
= AFI_UNSPEC
;
465 switch (lookup
.nhg
->nexthop
->type
) {
466 case (NEXTHOP_TYPE_IFINDEX
):
467 case (NEXTHOP_TYPE_BLACKHOLE
):
469 * This switch case handles setting the afi different
470 * for ipv4/v6 routes. Ifindex/blackhole nexthop
471 * objects cannot be ambiguous, they must be Address
472 * Family specific. If we get here, we will either use
473 * the AF of the route, or the one we got passed from
474 * here from the kernel.
478 case (NEXTHOP_TYPE_IPV4_IFINDEX
):
479 case (NEXTHOP_TYPE_IPV4
):
482 case (NEXTHOP_TYPE_IPV6_IFINDEX
):
483 case (NEXTHOP_TYPE_IPV6
):
484 lookup
.afi
= AFI_IP6
;
488 lookup
.vrf_id
= vrf_id
;
492 (*nhe
) = zebra_nhg_lookup_id(id
);
494 (*nhe
) = hash_lookup(zrouter
.nhgs
, &lookup
);
496 /* If it found an nhe in our tables, this new ID is unused */
498 id_counter
= old_id_counter
;
501 /* Only hash/lookup the depends if the first lookup
502 * fails to find something. This should hopefully save a
503 * lot of cycles for larger ecmp sizes.
506 /* If you don't want to hash on each nexthop in the
507 * nexthop group struct you can pass the depends
508 * directly. Kernel-side we do this since it just looks
511 lookup
.nhg_depends
= *nhg_depends
;
513 if (nhg
->nexthop
->next
) {
514 zebra_nhg_depends_init(&lookup
);
516 /* If its a group, create a dependency tree */
517 struct nexthop
*nh
= NULL
;
519 for (nh
= nhg
->nexthop
; nh
; nh
= nh
->next
)
520 depends_find_add(&lookup
.nhg_depends
,
522 } else if (CHECK_FLAG(nhg
->nexthop
->flags
,
523 NEXTHOP_FLAG_RECURSIVE
)) {
524 zebra_nhg_depends_init(&lookup
);
525 handle_recursive_depend(&lookup
.nhg_depends
,
526 nhg
->nexthop
->resolved
,
532 (*nhe
) = hash_get(zrouter
.nhgs
, &lookup
, zebra_nhg_hash_alloc
);
536 SET_FLAG((*nhe
)->flags
, NEXTHOP_GROUP_RECURSIVE
);
541 /* Find/create a single nexthop */
542 static struct nhg_hash_entry
*
543 zebra_nhg_find_nexthop(uint32_t id
, struct nexthop
*nh
, afi_t afi
, int type
)
545 struct nhg_hash_entry
*nhe
= NULL
;
546 struct nexthop_group nhg
= {};
548 _nexthop_group_add_sorted(&nhg
, nh
);
550 zebra_nhg_find(&nhe
, id
, &nhg
, NULL
, nh
->vrf_id
, afi
, 0);
555 static struct nhg_ctx
*nhg_ctx_new()
557 struct nhg_ctx
*new = NULL
;
559 new = XCALLOC(MTYPE_NHG_CTX
, sizeof(struct nhg_ctx
));
564 static void nhg_ctx_free(struct nhg_ctx
*ctx
)
566 XFREE(MTYPE_NHG_CTX
, ctx
);
569 static uint32_t nhg_ctx_get_id(const struct nhg_ctx
*ctx
)
574 static void nhg_ctx_set_status(struct nhg_ctx
*ctx
, enum nhg_ctx_status status
)
576 ctx
->status
= status
;
579 static enum nhg_ctx_status
nhg_ctx_get_status(const struct nhg_ctx
*ctx
)
584 static void nhg_ctx_set_op(struct nhg_ctx
*ctx
, enum nhg_ctx_op_e op
)
589 static enum nhg_ctx_op_e
nhg_ctx_get_op(const struct nhg_ctx
*ctx
)
594 static vrf_id_t
nhg_ctx_get_vrf_id(const struct nhg_ctx
*ctx
)
599 static int nhg_ctx_get_type(const struct nhg_ctx
*ctx
)
604 static int nhg_ctx_get_afi(const struct nhg_ctx
*ctx
)
609 static struct nexthop
*nhg_ctx_get_nh(struct nhg_ctx
*ctx
)
614 static uint8_t nhg_ctx_get_count(const struct nhg_ctx
*ctx
)
619 static struct nh_grp
*nhg_ctx_get_grp(struct nhg_ctx
*ctx
)
624 static struct nhg_ctx
*nhg_ctx_init(uint32_t id
, struct nexthop
*nh
,
625 struct nh_grp
*grp
, vrf_id_t vrf_id
,
626 afi_t afi
, int type
, uint8_t count
)
628 struct nhg_ctx
*ctx
= NULL
;
633 ctx
->vrf_id
= vrf_id
;
639 /* Copy over the array */
640 memcpy(&ctx
->u
.grp
, grp
, count
* sizeof(struct nh_grp
));
647 static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry
*nhe
)
649 struct nhg_connected
*rb_node_dep
= NULL
;
651 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
652 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
,
653 NEXTHOP_GROUP_UNHASHABLE
))
660 static void zebra_nhg_set_unhashable(struct nhg_hash_entry
*nhe
)
662 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
);
663 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
666 EC_ZEBRA_DUPLICATE_NHG_MESSAGE
,
667 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
671 static void zebra_nhg_set_valid(struct nhg_hash_entry
*nhe
)
673 struct nhg_connected
*rb_node_dep
;
675 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
677 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
678 zebra_nhg_set_valid(rb_node_dep
->nhe
);
681 static void zebra_nhg_set_invalid(struct nhg_hash_entry
*nhe
)
683 struct nhg_connected
*rb_node_dep
;
685 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
687 /* Update validity of nexthops depending on it */
688 frr_each(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
689 zebra_nhg_check_valid(rb_node_dep
->nhe
);
692 void zebra_nhg_check_valid(struct nhg_hash_entry
*nhe
)
694 struct nhg_connected
*rb_node_dep
= NULL
;
697 /* If anthing else in the group is valid, the group is valid */
698 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
699 if (CHECK_FLAG(rb_node_dep
->nhe
->flags
, NEXTHOP_GROUP_VALID
)) {
707 zebra_nhg_set_valid(nhe
);
709 zebra_nhg_set_invalid(nhe
);
713 static void zebra_nhg_release(struct nhg_hash_entry
*nhe
)
715 /* Remove it from any lists it may be on */
716 zebra_nhg_depends_release(nhe
);
717 zebra_nhg_dependents_release(nhe
);
719 if_nhg_dependents_del(nhe
->ifp
, nhe
);
722 * If its unhashable, we didn't store it here and have to be
723 * sure we don't clear one thats actually being used.
725 if (!CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_UNHASHABLE
))
726 hash_release(zrouter
.nhgs
, nhe
);
728 hash_release(zrouter
.nhgs_id
, nhe
);
731 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry
*nhe
)
733 zebra_nhg_release(nhe
);
737 static void zebra_nhg_handle_install(struct nhg_hash_entry
*nhe
)
739 /* Update validity of groups depending on it */
740 struct nhg_connected
*rb_node_dep
;
742 frr_each_safe(nhg_connected_tree
, &nhe
->nhg_dependents
, rb_node_dep
)
743 zebra_nhg_set_valid(rb_node_dep
->nhe
);
747 * The kernel/other program has changed the state of a nexthop object we are
750 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry
*nhe
,
756 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
757 (is_delete
? "deleted" : "updated"), nhe
->id
);
759 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
760 zebra_nhg_install_kernel(nhe
);
762 zebra_nhg_handle_uninstall(nhe
);
765 static int nhg_ctx_process_new(struct nhg_ctx
*ctx
)
767 struct nexthop_group
*nhg
= NULL
;
768 struct nhg_connected_tree_head nhg_depends
= {};
769 struct nhg_hash_entry
*lookup
= NULL
;
770 struct nhg_hash_entry
*nhe
= NULL
;
772 uint32_t id
= nhg_ctx_get_id(ctx
);
773 uint8_t count
= nhg_ctx_get_count(ctx
);
774 vrf_id_t vrf_id
= nhg_ctx_get_vrf_id(ctx
);
775 int type
= nhg_ctx_get_type(ctx
);
776 afi_t afi
= nhg_ctx_get_afi(ctx
);
778 lookup
= zebra_nhg_lookup_id(id
);
781 /* This is already present in our table, hence an update
782 * that we did not initate.
784 zebra_nhg_handle_kernel_state_change(lookup
, false);
788 if (nhg_ctx_get_count(ctx
)) {
789 nhg
= nexthop_group_new();
790 if (zebra_nhg_process_grp(nhg
, &nhg_depends
,
791 nhg_ctx_get_grp(ctx
), count
)) {
792 depends_decrement_free(&nhg_depends
);
793 nexthop_group_delete(&nhg
);
797 if (!zebra_nhg_find(&nhe
, id
, nhg
, &nhg_depends
, vrf_id
, type
,
799 depends_decrement_free(&nhg_depends
);
801 /* These got copied over in zebra_nhg_alloc() */
802 nexthop_group_delete(&nhg
);
804 nhe
= zebra_nhg_find_nexthop(id
, nhg_ctx_get_nh(ctx
), afi
,
809 struct nhg_hash_entry
*kernel_nhe
= NULL
;
811 /* Duplicate but with different ID from
815 /* The kernel allows duplicate nexthops
816 * as long as they have different IDs.
817 * We are ignoring those to prevent
818 * syncing problems with the kernel
821 * We maintain them *ONLY* in the ID hash table to
822 * track them and set the flag to indicated
823 * their attributes are unhashable.
826 kernel_nhe
= zebra_nhg_copy(nhe
, id
);
827 zebra_nhg_insert_id(kernel_nhe
);
828 zebra_nhg_set_unhashable(kernel_nhe
);
829 } else if (zebra_nhg_contains_unhashable(nhe
)) {
830 /* The group we got contains an unhashable/duplicated
831 * depend, so lets mark this group as unhashable as well
832 * and release it from the non-ID hash.
834 hash_release(zrouter
.nhgs
, nhe
);
835 zebra_nhg_set_unhashable(nhe
);
837 /* It actually created a new nhe */
838 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
839 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
843 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
844 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
852 static int nhg_ctx_process_del(struct nhg_ctx
*ctx
)
854 struct nhg_hash_entry
*nhe
= NULL
;
855 uint32_t id
= nhg_ctx_get_id(ctx
);
857 nhe
= zebra_nhg_lookup_id(id
);
861 EC_ZEBRA_BAD_NHG_MESSAGE
,
862 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
867 zebra_nhg_handle_kernel_state_change(nhe
, true);
872 static void nhg_ctx_process_finish(struct nhg_ctx
*ctx
)
877 * Just freeing for now, maybe do something more in the future
881 if (nhg_ctx_get_count(ctx
))
884 nh
= nhg_ctx_get_nh(ctx
);
886 nexthop_del_labels(nh
);
892 static int queue_add(struct nhg_ctx
*ctx
)
894 /* If its queued or already processed do nothing */
895 if (nhg_ctx_get_status(ctx
) == NHG_CTX_QUEUED
)
898 if (rib_queue_nhg_add(ctx
)) {
899 nhg_ctx_set_status(ctx
, NHG_CTX_FAILURE
);
903 nhg_ctx_set_status(ctx
, NHG_CTX_QUEUED
);
908 int nhg_ctx_process(struct nhg_ctx
*ctx
)
912 switch (nhg_ctx_get_op(ctx
)) {
914 ret
= nhg_ctx_process_new(ctx
);
915 if (nhg_ctx_get_count(ctx
) && ret
== -ENOENT
916 && nhg_ctx_get_status(ctx
) != NHG_CTX_REQUEUED
) {
918 * We have entered a situation where we are
919 * processing a group from the kernel
920 * that has a contained nexthop which
921 * we have not yet processed.
923 * Re-enqueue this ctx to be handled exactly one
924 * more time (indicated by the flag).
926 * By the time we get back to it, we
927 * should have processed its depends.
929 nhg_ctx_set_status(ctx
, NHG_CTX_NONE
);
930 if (queue_add(ctx
) == 0) {
931 nhg_ctx_set_status(ctx
, NHG_CTX_REQUEUED
);
937 ret
= nhg_ctx_process_del(ctx
);
938 case NHG_CTX_OP_NONE
:
942 nhg_ctx_set_status(ctx
, (ret
? NHG_CTX_FAILURE
: NHG_CTX_SUCCESS
));
944 nhg_ctx_process_finish(ctx
);
949 /* Kernel-side, you either get a single new nexthop or a array of ID's */
950 int zebra_nhg_kernel_find(uint32_t id
, struct nexthop
*nh
, struct nh_grp
*grp
,
951 uint8_t count
, vrf_id_t vrf_id
, afi_t afi
, int type
,
954 struct nhg_ctx
*ctx
= NULL
;
957 /* Increase our counter so we don't try to create
958 * an ID that already exists
962 ctx
= nhg_ctx_init(id
, nh
, grp
, vrf_id
, afi
, type
, count
);
963 nhg_ctx_set_op(ctx
, NHG_CTX_OP_NEW
);
965 /* Under statup conditions, we need to handle them immediately
966 * like we do for routes. Otherwise, we are going to get a route
967 * with a nhe_id that we have not handled.
970 return nhg_ctx_process(ctx
);
972 if (queue_add(ctx
)) {
973 nhg_ctx_process_finish(ctx
);
980 /* Kernel-side, received delete message */
981 int zebra_nhg_kernel_del(uint32_t id
)
983 struct nhg_ctx
*ctx
= NULL
;
985 ctx
= nhg_ctx_init(id
, NULL
, NULL
, 0, 0, 0, 0);
987 nhg_ctx_set_op(ctx
, NHG_CTX_OP_DEL
);
989 if (queue_add(ctx
)) {
990 nhg_ctx_process_finish(ctx
);
997 /* Some dependency helper functions */
998 static struct nhg_hash_entry
*depends_find(struct nexthop
*nh
, afi_t afi
)
1000 struct nexthop
*lookup
= NULL
;
1001 struct nhg_hash_entry
*nhe
= NULL
;
1003 copy_nexthops(&lookup
, nh
, NULL
);
1005 /* Clear it, in case its a group */
1006 nexthops_free(lookup
->next
);
1007 nexthops_free(lookup
->prev
);
1008 lookup
->next
= NULL
;
1009 lookup
->prev
= NULL
;
1011 nhe
= zebra_nhg_find_nexthop(0, lookup
, afi
, 0);
1013 nexthops_free(lookup
);
1018 static void depends_add(struct nhg_connected_tree_head
*head
,
1019 struct nhg_hash_entry
*depend
)
1021 nhg_connected_tree_add_nhe(head
, depend
);
1022 zebra_nhg_increment_ref(depend
);
1025 static struct nhg_hash_entry
*
1026 depends_find_add(struct nhg_connected_tree_head
*head
, struct nexthop
*nh
,
1029 struct nhg_hash_entry
*depend
= NULL
;
1031 depend
= depends_find(nh
, afi
);
1034 depends_add(head
, depend
);
1039 static struct nhg_hash_entry
*
1040 depends_find_id_add(struct nhg_connected_tree_head
*head
, uint32_t id
)
1042 struct nhg_hash_entry
*depend
= NULL
;
1044 depend
= zebra_nhg_lookup_id(id
);
1047 depends_add(head
, depend
);
1052 static void depends_decrement_free(struct nhg_connected_tree_head
*head
)
1054 nhg_connected_tree_decrement_ref(head
);
1055 nhg_connected_tree_free(head
);
1058 /* Rib-side, you get a nexthop group struct */
1059 struct nhg_hash_entry
*
1060 zebra_nhg_rib_find(uint32_t id
, struct nexthop_group
*nhg
, afi_t rt_afi
)
1062 struct nhg_hash_entry
*nhe
= NULL
;
1064 if (!(nhg
&& nhg
->nexthop
)) {
1065 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1066 "No nexthop passed to %s", __func__
);
1070 zebra_nhg_find(&nhe
, id
, nhg
, NULL
, nhg
->nexthop
->vrf_id
, rt_afi
, 0);
1075 static void zebra_nhg_free_members(struct nhg_hash_entry
*nhe
)
1077 nexthop_group_delete(&nhe
->nhg
);
1078 /* Decrement to remove connection ref */
1079 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1080 nhg_connected_tree_free(&nhe
->nhg_depends
);
1081 nhg_connected_tree_free(&nhe
->nhg_dependents
);
1084 void zebra_nhg_free(void *arg
)
1086 struct nhg_hash_entry
*nhe
= NULL
;
1088 nhe
= (struct nhg_hash_entry
*)arg
;
1091 zlog_debug("nhe_id=%u hash refcnt=%d", nhe
->id
, nhe
->refcnt
);
1093 zebra_nhg_free_members(nhe
);
1095 XFREE(MTYPE_NHG
, nhe
);
1098 void zebra_nhg_decrement_ref(struct nhg_hash_entry
*nhe
)
1102 if (!zebra_nhg_depends_is_empty(nhe
))
1103 nhg_connected_tree_decrement_ref(&nhe
->nhg_depends
);
1105 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1106 zebra_nhg_uninstall_kernel(nhe
);
1109 void zebra_nhg_increment_ref(struct nhg_hash_entry
*nhe
)
1113 if (!zebra_nhg_depends_is_empty(nhe
))
1114 nhg_connected_tree_increment_ref(&nhe
->nhg_depends
);
1117 static void nexthop_set_resolved(afi_t afi
, const struct nexthop
*newhop
,
1118 struct nexthop
*nexthop
)
1120 struct nexthop
*resolved_hop
;
1121 uint8_t num_labels
= 0;
1122 mpls_label_t labels
[MPLS_MAX_LABELS
];
1123 enum lsp_types_t label_type
= ZEBRA_LSP_NONE
;
1126 resolved_hop
= nexthop_new();
1127 SET_FLAG(resolved_hop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1129 resolved_hop
->vrf_id
= nexthop
->vrf_id
;
1130 switch (newhop
->type
) {
1131 case NEXTHOP_TYPE_IPV4
:
1132 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1133 /* If the resolving route specifies a gateway, use it */
1134 resolved_hop
->type
= newhop
->type
;
1135 resolved_hop
->gate
.ipv4
= newhop
->gate
.ipv4
;
1137 if (newhop
->ifindex
) {
1138 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1139 resolved_hop
->ifindex
= newhop
->ifindex
;
1142 case NEXTHOP_TYPE_IPV6
:
1143 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1144 resolved_hop
->type
= newhop
->type
;
1145 resolved_hop
->gate
.ipv6
= newhop
->gate
.ipv6
;
1147 if (newhop
->ifindex
) {
1148 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1149 resolved_hop
->ifindex
= newhop
->ifindex
;
1152 case NEXTHOP_TYPE_IFINDEX
:
1153 /* If the resolving route is an interface route,
1154 * it means the gateway we are looking up is connected
1155 * to that interface. (The actual network is _not_ onlink).
1156 * Therefore, the resolved route should have the original
1157 * gateway as nexthop as it is directly connected.
1159 * On Linux, we have to set the onlink netlink flag because
1160 * otherwise, the kernel won't accept the route.
1162 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1163 if (afi
== AFI_IP
) {
1164 resolved_hop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
1165 resolved_hop
->gate
.ipv4
= nexthop
->gate
.ipv4
;
1166 } else if (afi
== AFI_IP6
) {
1167 resolved_hop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
1168 resolved_hop
->gate
.ipv6
= nexthop
->gate
.ipv6
;
1170 resolved_hop
->ifindex
= newhop
->ifindex
;
1172 case NEXTHOP_TYPE_BLACKHOLE
:
1173 resolved_hop
->type
= NEXTHOP_TYPE_BLACKHOLE
;
1174 resolved_hop
->bh_type
= newhop
->bh_type
;
1178 if (newhop
->flags
& NEXTHOP_FLAG_ONLINK
)
1179 resolved_hop
->flags
|= NEXTHOP_FLAG_ONLINK
;
1181 /* Copy labels of the resolved route and the parent resolving to it */
1182 if (newhop
->nh_label
) {
1183 for (i
= 0; i
< newhop
->nh_label
->num_labels
; i
++)
1184 labels
[num_labels
++] = newhop
->nh_label
->label
[i
];
1185 label_type
= newhop
->nh_label_type
;
1188 if (nexthop
->nh_label
) {
1189 for (i
= 0; i
< nexthop
->nh_label
->num_labels
; i
++)
1190 labels
[num_labels
++] = nexthop
->nh_label
->label
[i
];
1192 /* If the parent has labels, use its type */
1193 label_type
= nexthop
->nh_label_type
;
1197 nexthop_add_labels(resolved_hop
, label_type
, num_labels
,
1200 resolved_hop
->rparent
= nexthop
;
1201 _nexthop_add(&nexthop
->resolved
, resolved_hop
);
1204 /* Checks if nexthop we are trying to resolve to is valid */
1205 static bool nexthop_valid_resolve(const struct nexthop
*nexthop
,
1206 const struct nexthop
*resolved
)
1208 /* Can't resolve to a recursive nexthop */
1209 if (CHECK_FLAG(resolved
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1212 switch (nexthop
->type
) {
1213 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1214 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1215 /* If the nexthop we are resolving to does not match the
1216 * ifindex for the nexthop the route wanted, its not valid.
1218 if (nexthop
->ifindex
!= resolved
->ifindex
)
1221 case NEXTHOP_TYPE_IPV4
:
1222 case NEXTHOP_TYPE_IPV6
:
1223 case NEXTHOP_TYPE_IFINDEX
:
1224 case NEXTHOP_TYPE_BLACKHOLE
:
1232 * Given a nexthop we need to properly recursively resolve
1233 * the route. As such, do a table lookup to find and match
1234 * if at all possible. Set the nexthop->ifindex and resolved_id
1237 static int nexthop_active(afi_t afi
, struct route_entry
*re
,
1238 struct nexthop
*nexthop
, struct route_node
*top
)
1241 struct route_table
*table
;
1242 struct route_node
*rn
;
1243 struct route_entry
*match
= NULL
;
1245 struct nexthop
*newhop
;
1246 struct interface
*ifp
;
1248 struct zebra_vrf
*zvrf
;
1250 if ((nexthop
->type
== NEXTHOP_TYPE_IPV4
)
1251 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1252 nexthop
->ifindex
= 0;
1255 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
);
1256 nexthops_free(nexthop
->resolved
);
1257 nexthop
->resolved
= NULL
;
1258 re
->nexthop_mtu
= 0;
1261 * If the kernel has sent us a NEW route, then
1262 * by golly gee whiz it's a good route.
1264 * If its an already INSTALLED route we have already handled, then the
1265 * kernel route's nexthop might have became unreachable
1266 * and we have to handle that.
1268 if (!CHECK_FLAG(re
->status
, ROUTE_ENTRY_INSTALLED
)
1269 && (re
->type
== ZEBRA_ROUTE_KERNEL
1270 || re
->type
== ZEBRA_ROUTE_SYSTEM
))
1274 * Check to see if we should trust the passed in information
1275 * for UNNUMBERED interfaces as that we won't find the GW
1276 * address in the routing table.
1277 * This check should suffice to handle IPv4 or IPv6 routes
1278 * sourced from EVPN routes which are installed with the
1279 * next hop as the remote VTEP IP.
1281 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ONLINK
)) {
1282 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1284 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1286 "\t%s: Onlink and interface: %u[%u] does not exist",
1287 __PRETTY_FUNCTION__
, nexthop
->ifindex
,
1291 if (connected_is_unnumbered(ifp
)) {
1292 if (if_is_operative(ifp
))
1295 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1297 "\t%s: Onlink and interface %s is not operative",
1298 __PRETTY_FUNCTION__
, ifp
->name
);
1301 if (!if_is_operative(ifp
)) {
1302 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1304 "\t%s: Interface %s is not unnumbered",
1305 __PRETTY_FUNCTION__
, ifp
->name
);
1310 /* Make lookup prefix. */
1311 memset(&p
, 0, sizeof(struct prefix
));
1315 p
.prefixlen
= IPV4_MAX_PREFIXLEN
;
1316 p
.u
.prefix4
= nexthop
->gate
.ipv4
;
1319 p
.family
= AF_INET6
;
1320 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
1321 p
.u
.prefix6
= nexthop
->gate
.ipv6
;
1324 assert(afi
!= AFI_IP
&& afi
!= AFI_IP6
);
1328 table
= zebra_vrf_table(afi
, SAFI_UNICAST
, nexthop
->vrf_id
);
1330 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
1331 if (!table
|| !zvrf
) {
1332 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1333 zlog_debug("\t%s: Table not found",
1334 __PRETTY_FUNCTION__
);
1338 rn
= route_node_match(table
, (struct prefix
*)&p
);
1340 route_unlock_node(rn
);
1342 /* Lookup should halt if we've matched against ourselves ('top',
1343 * if specified) - i.e., we cannot have a nexthop NH1 is
1344 * resolved by a route NH1. The exception is if the route is a
1347 if (top
&& rn
== top
)
1348 if (((afi
== AFI_IP
) && (rn
->p
.prefixlen
!= 32))
1349 || ((afi
== AFI_IP6
) && (rn
->p
.prefixlen
!= 128))) {
1350 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1352 "\t%s: Matched against ourself and prefix length is not max bit length",
1353 __PRETTY_FUNCTION__
);
1357 /* Pick up selected route. */
1358 /* However, do not resolve over default route unless explicitly
1361 if (is_default_prefix(&rn
->p
)
1362 && !rnh_resolve_via_default(zvrf
, p
.family
)) {
1363 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1365 "\t:%s: Resolved against default route",
1366 __PRETTY_FUNCTION__
);
1370 dest
= rib_dest_from_rnode(rn
);
1371 if (dest
&& dest
->selected_fib
1372 && !CHECK_FLAG(dest
->selected_fib
->status
,
1373 ROUTE_ENTRY_REMOVED
)
1374 && dest
->selected_fib
->type
!= ZEBRA_ROUTE_TABLE
)
1375 match
= dest
->selected_fib
;
1377 /* If there is no selected route or matched route is EGP, go up
1383 } while (rn
&& rn
->info
== NULL
);
1385 route_lock_node(rn
);
1390 if (match
->type
== ZEBRA_ROUTE_CONNECT
) {
1391 /* Directly point connected route. */
1392 newhop
= match
->ng
->nexthop
;
1394 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
1395 || nexthop
->type
== NEXTHOP_TYPE_IPV6
)
1396 nexthop
->ifindex
= newhop
->ifindex
;
1399 } else if (CHECK_FLAG(re
->flags
, ZEBRA_FLAG_ALLOW_RECURSION
)) {
1401 for (ALL_NEXTHOPS_PTR(match
->ng
, newhop
)) {
1402 if (!CHECK_FLAG(match
->status
,
1403 ROUTE_ENTRY_INSTALLED
))
1405 if (!nexthop_valid_resolve(nexthop
, newhop
))
1408 SET_FLAG(nexthop
->flags
,
1409 NEXTHOP_FLAG_RECURSIVE
);
1410 nexthop_set_resolved(afi
, newhop
, nexthop
);
1414 re
->nexthop_mtu
= match
->mtu
;
1416 if (!resolved
&& IS_ZEBRA_DEBUG_RIB_DETAILED
)
1417 zlog_debug("\t%s: Recursion failed to find",
1418 __PRETTY_FUNCTION__
);
1420 } else if (re
->type
== ZEBRA_ROUTE_STATIC
) {
1422 for (ALL_NEXTHOPS_PTR(match
->ng
, newhop
)) {
1423 if (!CHECK_FLAG(match
->status
,
1424 ROUTE_ENTRY_INSTALLED
))
1426 if (!nexthop_valid_resolve(nexthop
, newhop
))
1429 SET_FLAG(nexthop
->flags
,
1430 NEXTHOP_FLAG_RECURSIVE
);
1431 nexthop_set_resolved(afi
, newhop
, nexthop
);
1435 re
->nexthop_mtu
= match
->mtu
;
1437 if (!resolved
&& IS_ZEBRA_DEBUG_RIB_DETAILED
)
1439 "\t%s: Static route unable to resolve",
1440 __PRETTY_FUNCTION__
);
1443 if (IS_ZEBRA_DEBUG_RIB_DETAILED
) {
1445 "\t%s: Route Type %s has not turned on recursion",
1446 __PRETTY_FUNCTION__
,
1447 zebra_route_string(re
->type
));
1448 if (re
->type
== ZEBRA_ROUTE_BGP
1449 && !CHECK_FLAG(re
->flags
, ZEBRA_FLAG_IBGP
))
1451 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1456 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1457 zlog_debug("\t%s: Nexthop did not lookup in table",
1458 __PRETTY_FUNCTION__
);
1462 /* This function verifies reachability of one given nexthop, which can be
1463 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1464 * in nexthop->flags field. The nexthop->ifindex will be updated
1465 * appropriately as well. An existing route map can turn
1466 * (otherwise active) nexthop into inactive, but not vice versa.
1468 * If it finds a nexthop recursivedly, set the resolved_id
1469 * to match that nexthop's nhg_hash_entry ID;
1471 * The return value is the final value of 'ACTIVE' flag.
1473 static unsigned nexthop_active_check(struct route_node
*rn
,
1474 struct route_entry
*re
,
1475 struct nexthop
*nexthop
)
1477 struct interface
*ifp
;
1478 route_map_result_t ret
= RMAP_PERMITMATCH
;
1480 char buf
[SRCDEST2STR_BUFFER
];
1481 const struct prefix
*p
, *src_p
;
1482 struct zebra_vrf
*zvrf
;
1484 srcdest_rnode_prefixes(rn
, &p
, &src_p
);
1486 if (rn
->p
.family
== AF_INET
)
1488 else if (rn
->p
.family
== AF_INET6
)
1492 switch (nexthop
->type
) {
1493 case NEXTHOP_TYPE_IFINDEX
:
1494 ifp
= if_lookup_by_index(nexthop
->ifindex
, nexthop
->vrf_id
);
1495 if (ifp
&& if_is_operative(ifp
))
1496 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1498 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1500 case NEXTHOP_TYPE_IPV4
:
1501 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1503 if (nexthop_active(AFI_IP
, re
, nexthop
, rn
))
1504 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1506 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1508 case NEXTHOP_TYPE_IPV6
:
1510 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
1511 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1513 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1515 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1516 /* RFC 5549, v4 prefix with v6 NH */
1517 if (rn
->p
.family
!= AF_INET
)
1519 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
->gate
.ipv6
)) {
1520 ifp
= if_lookup_by_index(nexthop
->ifindex
,
1522 if (ifp
&& if_is_operative(ifp
))
1523 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1525 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1527 if (nexthop_active(AFI_IP6
, re
, nexthop
, rn
))
1528 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1530 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1533 case NEXTHOP_TYPE_BLACKHOLE
:
1534 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1539 if (!CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)) {
1540 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1541 zlog_debug("\t%s: Unable to find a active nexthop",
1542 __PRETTY_FUNCTION__
);
1546 /* XXX: What exactly do those checks do? Do we support
1547 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1549 if (RIB_SYSTEM_ROUTE(re
) || (family
== AFI_IP
&& p
->family
!= AF_INET
)
1550 || (family
== AFI_IP6
&& p
->family
!= AF_INET6
))
1551 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1553 /* The original code didn't determine the family correctly
1554 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1555 * from the rib_table_info in those cases.
1556 * Possibly it may be better to use only the rib_table_info
1560 rib_table_info_t
*info
;
1562 info
= srcdest_rnode_table_info(rn
);
1566 memset(&nexthop
->rmap_src
.ipv6
, 0, sizeof(union g_addr
));
1568 zvrf
= zebra_vrf_lookup_by_id(nexthop
->vrf_id
);
1570 if (IS_ZEBRA_DEBUG_RIB_DETAILED
)
1571 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__
);
1572 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1575 /* It'll get set if required inside */
1576 ret
= zebra_route_map_check(family
, re
->type
, re
->instance
, p
, nexthop
,
1578 if (ret
== RMAP_DENYMATCH
) {
1579 if (IS_ZEBRA_DEBUG_RIB
) {
1580 srcdest_rnode2str(rn
, buf
, sizeof(buf
));
1582 "%u:%s: Filtering out with NH out %s due to route map",
1584 ifindex2ifname(nexthop
->ifindex
,
1587 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1589 return CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1593 * Iterate over all nexthops of the given RIB entry and refresh their
1594 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1595 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
1597 * Return value is the new number of active nexthops.
1599 int nexthop_active_update(struct route_node
*rn
, struct route_entry
*re
)
1601 struct nexthop_group new_grp
= {};
1602 struct nexthop
*nexthop
;
1603 union g_addr prev_src
;
1604 unsigned int prev_active
, new_active
;
1605 ifindex_t prev_index
;
1606 uint8_t curr_active
= 0;
1608 afi_t rt_afi
= family2afi(rn
->p
.family
);
1610 UNSET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
1612 /* Copy over the nexthops in current state */
1613 nexthop_group_copy(&new_grp
, re
->ng
);
1615 for (nexthop
= new_grp
.nexthop
; nexthop
; nexthop
= nexthop
->next
) {
1617 /* No protocol daemon provides src and so we're skipping
1619 prev_src
= nexthop
->rmap_src
;
1620 prev_active
= CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1621 prev_index
= nexthop
->ifindex
;
1623 * We need to respect the multipath_num here
1624 * as that what we should be able to install from
1625 * a multipath perpsective should not be a data plane
1629 nexthop_active_check(rn
, re
, nexthop
);
1632 && nexthop_group_active_nexthop_num(&new_grp
)
1633 >= zrouter
.multipath_num
) {
1634 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
1641 /* Don't allow src setting on IPv6 addr for now */
1642 if (prev_active
!= new_active
|| prev_index
!= nexthop
->ifindex
1643 || ((nexthop
->type
>= NEXTHOP_TYPE_IFINDEX
1644 && nexthop
->type
< NEXTHOP_TYPE_IPV6
)
1645 && prev_src
.ipv4
.s_addr
1646 != nexthop
->rmap_src
.ipv4
.s_addr
)
1647 || ((nexthop
->type
>= NEXTHOP_TYPE_IPV6
1648 && nexthop
->type
< NEXTHOP_TYPE_BLACKHOLE
)
1649 && !(IPV6_ADDR_SAME(&prev_src
.ipv6
,
1650 &nexthop
->rmap_src
.ipv6
)))
1651 || CHECK_FLAG(re
->status
, ROUTE_ENTRY_LABELS_CHANGED
))
1652 SET_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
);
1655 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_CHANGED
)) {
1656 struct nhg_hash_entry
*new_nhe
= NULL
;
1658 new_nhe
= zebra_nhg_rib_find(0, &new_grp
, rt_afi
);
1660 zebra_nhg_re_update_ref(re
, new_nhe
);
1664 struct nhg_hash_entry
*nhe
= NULL
;
1666 nhe
= zebra_nhg_lookup_id(re
->nhe_id
);
1669 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1672 EC_ZEBRA_TABLE_LOOKUP_FAILED
,
1673 "Active update on NHE id=%u that we do not have in our tables",
1678 * Do not need these nexthops anymore since they
1679 * were either copied over into an nhe or not
1682 nexthops_free(new_grp
.nexthop
);
1686 static void zebra_nhg_re_attach_ref(struct route_entry
*re
,
1687 struct nhg_hash_entry
*new)
1690 re
->nhe_id
= new->id
;
1692 zebra_nhg_increment_ref(new);
1695 int zebra_nhg_re_update_ref(struct route_entry
*re
, struct nhg_hash_entry
*new)
1697 struct nhg_hash_entry
*old
= NULL
;
1705 if (re
->nhe_id
!= new->id
) {
1706 old
= zebra_nhg_lookup_id(re
->nhe_id
);
1708 zebra_nhg_re_attach_ref(re
, new);
1711 zebra_nhg_decrement_ref(old
);
1713 /* This is the first time it's being attached */
1714 zebra_nhg_re_attach_ref(re
, new);
1720 /* Convert a nhe into a group array */
1721 uint8_t zebra_nhg_nhe2grp(struct nh_grp
*grp
, struct nhg_hash_entry
*nhe
,
1724 struct nhg_connected
*rb_node_dep
= NULL
;
1725 struct nhg_hash_entry
*depend
= NULL
;
1728 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1729 bool duplicate
= false;
1731 depend
= rb_node_dep
->nhe
;
1734 * If its recursive, use its resolved nhe in the group
1736 if (CHECK_FLAG(depend
->flags
, NEXTHOP_GROUP_RECURSIVE
)) {
1737 depend
= zebra_nhg_resolve(depend
);
1740 EC_ZEBRA_NHG_FIB_UPDATE
,
1741 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
1747 /* Check for duplicate IDs, kernel doesn't like that */
1748 for (int j
= 0; j
< i
; j
++) {
1749 if (depend
->id
== grp
[j
].id
)
1754 grp
[i
].id
= depend
->id
;
1755 /* We aren't using weights for anything right now */
1768 void zebra_nhg_install_kernel(struct nhg_hash_entry
*nhe
)
1770 struct nhg_connected
*rb_node_dep
= NULL
;
1772 /* Resolve it first */
1773 nhe
= zebra_nhg_resolve(nhe
);
1775 /* Make sure all depends are installed/queued */
1776 frr_each(nhg_connected_tree
, &nhe
->nhg_depends
, rb_node_dep
) {
1777 zebra_nhg_install_kernel(rb_node_dep
->nhe
);
1780 if (!CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)
1781 && !CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
)) {
1782 /* Change its type to us since we are installing it */
1783 nhe
->type
= ZEBRA_ROUTE_NHG
;
1785 int ret
= dplane_nexthop_add(nhe
);
1788 case ZEBRA_DPLANE_REQUEST_QUEUED
:
1789 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1791 case ZEBRA_DPLANE_REQUEST_FAILURE
:
1793 EC_ZEBRA_DP_INSTALL_FAIL
,
1794 "Failed to install Nexthop ID (%u) into the kernel",
1797 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
1798 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1799 zebra_nhg_handle_install(nhe
);
1805 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry
*nhe
)
1807 if (CHECK_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
)) {
1808 int ret
= dplane_nexthop_delete(nhe
);
1811 case ZEBRA_DPLANE_REQUEST_QUEUED
:
1812 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1814 case ZEBRA_DPLANE_REQUEST_FAILURE
:
1816 EC_ZEBRA_DP_DELETE_FAIL
,
1817 "Failed to uninstall Nexthop ID (%u) from the kernel",
1820 case ZEBRA_DPLANE_REQUEST_SUCCESS
:
1821 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1826 zebra_nhg_handle_uninstall(nhe
);
1829 void zebra_nhg_dplane_result(struct zebra_dplane_ctx
*ctx
)
1831 enum dplane_op_e op
;
1832 enum zebra_dplane_result status
;
1834 struct nhg_hash_entry
*nhe
= NULL
;
1836 op
= dplane_ctx_get_op(ctx
);
1837 status
= dplane_ctx_get_status(ctx
);
1839 id
= dplane_ctx_get_nhe_id(ctx
);
1841 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL
)
1843 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1844 ctx
, dplane_op2str(op
), id
, dplane_res2str(status
));
1847 case DPLANE_OP_NH_DELETE
:
1848 if (status
!= ZEBRA_DPLANE_REQUEST_SUCCESS
)
1850 EC_ZEBRA_DP_DELETE_FAIL
,
1851 "Failed to uninstall Nexthop ID (%u) from the kernel",
1853 /* We already free'd the data, nothing to do */
1855 case DPLANE_OP_NH_INSTALL
:
1856 case DPLANE_OP_NH_UPDATE
:
1857 nhe
= zebra_nhg_lookup_id(id
);
1862 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1863 dplane_op2str(op
), id
);
1867 UNSET_FLAG(nhe
->flags
, NEXTHOP_GROUP_QUEUED
);
1868 if (status
== ZEBRA_DPLANE_REQUEST_SUCCESS
) {
1869 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_VALID
);
1870 SET_FLAG(nhe
->flags
, NEXTHOP_GROUP_INSTALLED
);
1871 zebra_nhg_handle_install(nhe
);
1874 EC_ZEBRA_DP_INSTALL_FAIL
,
1875 "Failed to install Nexthop ID (%u) into the kernel",
1878 case DPLANE_OP_ROUTE_INSTALL
:
1879 case DPLANE_OP_ROUTE_UPDATE
:
1880 case DPLANE_OP_ROUTE_DELETE
:
1881 case DPLANE_OP_ROUTE_NOTIFY
:
1882 case DPLANE_OP_LSP_INSTALL
:
1883 case DPLANE_OP_LSP_UPDATE
:
1884 case DPLANE_OP_LSP_DELETE
:
1885 case DPLANE_OP_LSP_NOTIFY
:
1886 case DPLANE_OP_PW_INSTALL
:
1887 case DPLANE_OP_PW_UNINSTALL
:
1888 case DPLANE_OP_SYS_ROUTE_ADD
:
1889 case DPLANE_OP_SYS_ROUTE_DELETE
:
1890 case DPLANE_OP_ADDR_INSTALL
:
1891 case DPLANE_OP_ADDR_UNINSTALL
:
1892 case DPLANE_OP_MAC_INSTALL
:
1893 case DPLANE_OP_MAC_DELETE
:
1894 case DPLANE_OP_NEIGH_INSTALL
:
1895 case DPLANE_OP_NEIGH_UPDATE
:
1896 case DPLANE_OP_NEIGH_DELETE
:
1897 case DPLANE_OP_VTEP_ADD
:
1898 case DPLANE_OP_VTEP_DELETE
:
1899 case DPLANE_OP_NONE
:
1903 dplane_ctx_fini(&ctx
);
1906 static void zebra_nhg_sweep_entry(struct hash_bucket
*bucket
, void *arg
)
1908 struct nhg_hash_entry
*nhe
= NULL
;
1910 nhe
= (struct nhg_hash_entry
*)bucket
->data
;
1912 /* If its being ref'd, just let it be uninstalled via a route removal */
1913 if (ZEBRA_NHG_CREATED(nhe
) && nhe
->refcnt
<= 0)
1914 zebra_nhg_uninstall_kernel(nhe
);
1917 void zebra_nhg_sweep_table(struct hash
*hash
)
1919 hash_iterate(hash
, zebra_nhg_sweep_entry
, NULL
);