]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_nhg.c
zebra: Fix memory leaks and use after frees in nhg's on shutdown
[mirror_frr.git] / zebra / zebra_nhg.c
1 /* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 * Stephen Worley
5 *
6 * This file is part of FRR.
7 *
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
11 * later version.
12 *
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.
17 *
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
21 * 02111-1307, USA.
22 */
23 #include <zebra.h>
24
25 #include "lib/nexthop.h"
26 #include "lib/nexthop_group_private.h"
27 #include "lib/routemap.h"
28 #include "lib/mpls.h"
29 #include "lib/jhash.h"
30 #include "lib/debug.h"
31 #include "lib/lib_errors.h"
32
33 #include "zebra/connected.h"
34 #include "zebra/debug.h"
35 #include "zebra/zebra_router.h"
36 #include "zebra/zebra_nhg_private.h"
37 #include "zebra/zebra_rnh.h"
38 #include "zebra/zebra_routemap.h"
39 #include "zebra/zebra_srte.h"
40 #include "zebra/zserv.h"
41 #include "zebra/rt.h"
42 #include "zebra_errors.h"
43 #include "zebra_dplane.h"
44 #include "zebra/interface.h"
45 #include "zebra/zapi_msg.h"
46 #include "zebra/rib.h"
47
48 DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
49 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
50 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
51
52 /* Map backup nexthop indices between two nhes */
53 struct backup_nh_map_s {
54 int map_count;
55
56 struct {
57 uint8_t orig_idx;
58 uint8_t new_idx;
59 } map[MULTIPATH_NUM];
60 };
61
62 /* id counter to keep in sync with kernel */
63 uint32_t id_counter;
64
65 /* Controlled through ui */
66 static bool g_nexthops_enabled = true;
67 static bool proto_nexthops_only;
68 static bool use_recursive_backups = true;
69
70 static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
71 int type, bool from_dplane);
72 static void depends_add(struct nhg_connected_tree_head *head,
73 struct nhg_hash_entry *depend);
74 static struct nhg_hash_entry *
75 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
76 afi_t afi, int type, bool from_dplane);
77 static struct nhg_hash_entry *
78 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
79 static void depends_decrement_free(struct nhg_connected_tree_head *head);
80
81 static struct nhg_backup_info *
82 nhg_backup_copy(const struct nhg_backup_info *orig);
83
84 /* Helper function for getting the next allocatable ID */
85 static uint32_t nhg_get_next_id(void)
86 {
87 while (1) {
88 id_counter++;
89
90 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
91 zlog_debug("%s: ID %u checking", __func__, id_counter);
92
93 if (id_counter == ZEBRA_NHG_PROTO_LOWER) {
94 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
95 zlog_debug("%s: ID counter wrapped", __func__);
96
97 id_counter = 0;
98 continue;
99 }
100
101 if (zebra_nhg_lookup_id(id_counter)) {
102 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
103 zlog_debug("%s: ID already exists", __func__);
104
105 continue;
106 }
107
108 break;
109 }
110
111 return id_counter;
112 }
113
114 static void nhg_connected_free(struct nhg_connected *dep)
115 {
116 XFREE(MTYPE_NHG_CONNECTED, dep);
117 }
118
119 static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
120 {
121 struct nhg_connected *new = NULL;
122
123 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
124 new->nhe = nhe;
125
126 return new;
127 }
128
129 void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
130 {
131 struct nhg_connected *rb_node_dep = NULL;
132
133 if (!nhg_connected_tree_is_empty(head)) {
134 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
135 nhg_connected_tree_del(head, rb_node_dep);
136 nhg_connected_free(rb_node_dep);
137 }
138 }
139 }
140
141 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
142 {
143 return nhg_connected_tree_count(head) ? false : true;
144 }
145
146 struct nhg_connected *
147 nhg_connected_tree_root(struct nhg_connected_tree_head *head)
148 {
149 return nhg_connected_tree_first(head);
150 }
151
152 struct nhg_hash_entry *
153 nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
154 struct nhg_hash_entry *depend)
155 {
156 struct nhg_connected lookup = {};
157 struct nhg_connected *remove = NULL;
158 struct nhg_hash_entry *removed_nhe;
159
160 lookup.nhe = depend;
161
162 /* Lookup to find the element, then remove it */
163 remove = nhg_connected_tree_find(head, &lookup);
164 if (remove)
165 /* Re-returning here just in case this API changes..
166 * the _del list api's are a bit undefined at the moment.
167 *
168 * So hopefully returning here will make it fail if the api
169 * changes to something different than currently expected.
170 */
171 remove = nhg_connected_tree_del(head, remove);
172
173 /* If the entry was sucessfully removed, free the 'connected` struct */
174 if (remove) {
175 removed_nhe = remove->nhe;
176 nhg_connected_free(remove);
177 return removed_nhe;
178 }
179
180 return NULL;
181 }
182
183 /* Assuming UNIQUE RB tree. If this changes, assumptions here about
184 * insertion need to change.
185 */
186 struct nhg_hash_entry *
187 nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
188 struct nhg_hash_entry *depend)
189 {
190 struct nhg_connected *new = NULL;
191
192 new = nhg_connected_new(depend);
193
194 /* On success, NULL will be returned from the
195 * RB code.
196 */
197 if (new && (nhg_connected_tree_add(head, new) == NULL))
198 return NULL;
199
200 /* If it wasn't successful, it must be a duplicate. We enforce the
201 * unique property for the `nhg_connected` tree.
202 */
203 nhg_connected_free(new);
204
205 return depend;
206 }
207
208 static void
209 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
210 {
211 struct nhg_connected *rb_node_dep = NULL;
212
213 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
214 zebra_nhg_decrement_ref(rb_node_dep->nhe);
215 }
216 }
217
218 static void
219 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
220 {
221 struct nhg_connected *rb_node_dep = NULL;
222
223 frr_each(nhg_connected_tree, head, rb_node_dep) {
224 zebra_nhg_increment_ref(rb_node_dep->nhe);
225 }
226 }
227
228 struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
229 {
230 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
231 && !zebra_nhg_depends_is_empty(nhe)) {
232 nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
233 return zebra_nhg_resolve(nhe);
234 }
235
236 return nhe;
237 }
238
239 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
240 {
241 return nhg_connected_tree_count(&nhe->nhg_depends);
242 }
243
244 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
245 {
246 return nhg_connected_tree_is_empty(&nhe->nhg_depends);
247 }
248
249 static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
250 struct nhg_hash_entry *depend)
251 {
252 nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
253 }
254
255 static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
256 {
257 nhg_connected_tree_init(&nhe->nhg_depends);
258 }
259
260 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
261 {
262 return nhg_connected_tree_count(&nhe->nhg_dependents);
263 }
264
265
266 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
267 {
268 return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
269 }
270
271 static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
272 struct nhg_hash_entry *dependent)
273 {
274 nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
275 }
276
277 static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
278 struct nhg_hash_entry *dependent)
279 {
280 nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
281 }
282
283 static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
284 {
285 nhg_connected_tree_init(&nhe->nhg_dependents);
286 }
287
288 /* Release this nhe from anything depending on it */
289 static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
290 {
291 struct nhg_connected *rb_node_dep = NULL;
292
293 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
294 zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
295 /* recheck validity of the dependent */
296 zebra_nhg_check_valid(rb_node_dep->nhe);
297 }
298 }
299
300 /* Release this nhe from anything that it depends on */
301 static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
302 {
303 if (!zebra_nhg_depends_is_empty(nhe)) {
304 struct nhg_connected *rb_node_dep = NULL;
305
306 frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
307 rb_node_dep) {
308 zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
309 }
310 }
311 }
312
313
314 struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
315 {
316 struct nhg_hash_entry lookup = {};
317
318 lookup.id = id;
319 return hash_lookup(zrouter.nhgs_id, &lookup);
320 }
321
322 static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
323 {
324 if (hash_lookup(zrouter.nhgs_id, nhe)) {
325 flog_err(
326 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
327 "Failed inserting NHG %pNG into the ID hash table, entry already exists",
328 nhe);
329 return -1;
330 }
331
332 (void)hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
333
334 return 0;
335 }
336
337 static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
338 {
339 nhe->ifp = ifp;
340 if_nhg_dependents_add(ifp, nhe);
341 }
342
343 static void
344 zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
345 struct nhg_connected_tree_head *nhg_depends)
346 {
347 struct nhg_connected *rb_node_dep = NULL;
348
349 /* This has been allocated higher above in the stack. Could probably
350 * re-allocate and free the old stuff but just using the same memory
351 * for now. Otherwise, their might be a time trade-off for repeated
352 * alloc/frees as startup.
353 */
354 nhe->nhg_depends = *nhg_depends;
355
356 /* Attach backpointer to anything that it depends on */
357 zebra_nhg_dependents_init(nhe);
358 if (!zebra_nhg_depends_is_empty(nhe)) {
359 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
360 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
361 zlog_debug("%s: nhe %p (%pNG), dep %p (%pNG)",
362 __func__, nhe, nhe, rb_node_dep->nhe,
363 rb_node_dep->nhe);
364
365 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
366 }
367 }
368 }
369
370 /* Init an nhe, for use in a hash lookup for example */
371 void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
372 const struct nexthop *nh)
373 {
374 memset(nhe, 0, sizeof(struct nhg_hash_entry));
375 nhe->vrf_id = VRF_DEFAULT;
376 nhe->type = ZEBRA_ROUTE_NHG;
377 nhe->afi = AFI_UNSPEC;
378
379 /* There are some special rules that apply to groups representing
380 * a single nexthop.
381 */
382 if (nh && (nh->next == NULL)) {
383 switch (nh->type) {
384 case NEXTHOP_TYPE_IFINDEX:
385 case NEXTHOP_TYPE_BLACKHOLE:
386 /*
387 * This switch case handles setting the afi different
388 * for ipv4/v6 routes. Ifindex/blackhole nexthop
389 * objects cannot be ambiguous, they must be Address
390 * Family specific. If we get here, we will either use
391 * the AF of the route, or the one we got passed from
392 * here from the kernel.
393 */
394 nhe->afi = afi;
395 break;
396 case NEXTHOP_TYPE_IPV4_IFINDEX:
397 case NEXTHOP_TYPE_IPV4:
398 nhe->afi = AFI_IP;
399 break;
400 case NEXTHOP_TYPE_IPV6_IFINDEX:
401 case NEXTHOP_TYPE_IPV6:
402 nhe->afi = AFI_IP6;
403 break;
404 }
405 }
406 }
407
408 struct nhg_hash_entry *zebra_nhg_alloc(void)
409 {
410 struct nhg_hash_entry *nhe;
411
412 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
413
414 return nhe;
415 }
416
417 /*
418 * Allocate new nhe and make shallow copy of 'orig'; no
419 * recursive info is copied.
420 */
421 struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
422 uint32_t id)
423 {
424 struct nhg_hash_entry *nhe;
425
426 nhe = zebra_nhg_alloc();
427
428 nhe->id = id;
429
430 nexthop_group_copy(&(nhe->nhg), &(orig->nhg));
431
432 nhe->vrf_id = orig->vrf_id;
433 nhe->afi = orig->afi;
434 nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG;
435 nhe->refcnt = 0;
436 nhe->dplane_ref = zebra_router_get_next_sequence();
437
438 /* Copy backup info also, if present */
439 if (orig->backup_info)
440 nhe->backup_info = nhg_backup_copy(orig->backup_info);
441
442 return nhe;
443 }
444
445 /* Allocation via hash handler */
446 static void *zebra_nhg_hash_alloc(void *arg)
447 {
448 struct nhg_hash_entry *nhe = NULL;
449 struct nhg_hash_entry *copy = arg;
450
451 nhe = zebra_nhe_copy(copy, copy->id);
452
453 /* Mark duplicate nexthops in a group at creation time. */
454 nexthop_group_mark_duplicates(&(nhe->nhg));
455
456 /*
457 * Add the ifp now if it's not a group or recursive and has ifindex.
458 *
459 * A proto-owned ID is always a group.
460 */
461 if (!PROTO_OWNED(nhe) && nhe->nhg.nexthop && !nhe->nhg.nexthop->next
462 && !nhe->nhg.nexthop->resolved && nhe->nhg.nexthop->ifindex) {
463 struct interface *ifp = NULL;
464
465 ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex,
466 nhe->nhg.nexthop->vrf_id);
467 if (ifp)
468 zebra_nhg_set_if(nhe, ifp);
469 else {
470 if (IS_ZEBRA_DEBUG_NHG)
471 zlog_debug(
472 "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE %pNG",
473 nhe->nhg.nexthop->ifindex,
474 nhe->nhg.nexthop->vrf_id, nhe);
475 }
476 }
477
478 return nhe;
479 }
480
481 uint32_t zebra_nhg_hash_key(const void *arg)
482 {
483 const struct nhg_hash_entry *nhe = arg;
484 uint32_t key = 0x5a351234;
485 uint32_t primary = 0;
486 uint32_t backup = 0;
487
488 primary = nexthop_group_hash(&(nhe->nhg));
489 if (nhe->backup_info)
490 backup = nexthop_group_hash(&(nhe->backup_info->nhe->nhg));
491
492 key = jhash_3words(primary, backup, nhe->type, key);
493
494 key = jhash_2words(nhe->vrf_id, nhe->afi, key);
495
496 return key;
497 }
498
499 uint32_t zebra_nhg_id_key(const void *arg)
500 {
501 const struct nhg_hash_entry *nhe = arg;
502
503 return nhe->id;
504 }
505
506 /* Helper with common nhg/nhe nexthop comparison logic */
507 static bool nhg_compare_nexthops(const struct nexthop *nh1,
508 const struct nexthop *nh2)
509 {
510 assert(nh1 != NULL && nh2 != NULL);
511
512 /*
513 * We have to check the active flag of each individual one,
514 * not just the overall active_num. This solves the special case
515 * issue of a route with a nexthop group with one nexthop
516 * resolving to itself and thus marking it inactive. If we
517 * have two different routes each wanting to mark a different
518 * nexthop inactive, they need to hash to two different groups.
519 *
520 * If we just hashed on num_active, they would hash the same
521 * which is incorrect.
522 *
523 * ex)
524 * 1.1.1.0/24
525 * -> 1.1.1.1 dummy1 (inactive)
526 * -> 1.1.2.1 dummy2
527 *
528 * 1.1.2.0/24
529 * -> 1.1.1.1 dummy1
530 * -> 1.1.2.1 dummy2 (inactive)
531 *
532 * Without checking each individual one, they would hash to
533 * the same group and both have 1.1.1.1 dummy1 marked inactive.
534 *
535 */
536 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE)
537 != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE))
538 return false;
539
540 if (!nexthop_same(nh1, nh2))
541 return false;
542
543 return true;
544 }
545
546 bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
547 {
548 const struct nhg_hash_entry *nhe1 = arg1;
549 const struct nhg_hash_entry *nhe2 = arg2;
550 struct nexthop *nexthop1;
551 struct nexthop *nexthop2;
552
553 /* No matter what if they equal IDs, assume equal */
554 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
555 return true;
556
557 if (nhe1->type != nhe2->type)
558 return false;
559
560 if (nhe1->vrf_id != nhe2->vrf_id)
561 return false;
562
563 if (nhe1->afi != nhe2->afi)
564 return false;
565
566 /* Nexthops should be in-order, so we simply compare them in-place */
567 for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
568 nexthop1 && nexthop2;
569 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
570
571 if (!nhg_compare_nexthops(nexthop1, nexthop2))
572 return false;
573 }
574
575 /* Check for unequal list lengths */
576 if (nexthop1 || nexthop2)
577 return false;
578
579 /* If there's no backup info, comparison is done. */
580 if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL))
581 return true;
582
583 /* Compare backup info also - test the easy things first */
584 if (nhe1->backup_info && (nhe2->backup_info == NULL))
585 return false;
586 if (nhe2->backup_info && (nhe1->backup_info == NULL))
587 return false;
588
589 /* Compare number of backups before actually comparing any */
590 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
591 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
592 nexthop1 && nexthop2;
593 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
594 ;
595 }
596
597 /* Did we find the end of one list before the other? */
598 if (nexthop1 || nexthop2)
599 return false;
600
601 /* Have to compare the backup nexthops */
602 for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop,
603 nexthop2 = nhe2->backup_info->nhe->nhg.nexthop;
604 nexthop1 && nexthop2;
605 nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
606
607 if (!nhg_compare_nexthops(nexthop1, nexthop2))
608 return false;
609 }
610
611 return true;
612 }
613
614 bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
615 {
616 const struct nhg_hash_entry *nhe1 = arg1;
617 const struct nhg_hash_entry *nhe2 = arg2;
618
619 return nhe1->id == nhe2->id;
620 }
621
622 static int zebra_nhg_process_grp(struct nexthop_group *nhg,
623 struct nhg_connected_tree_head *depends,
624 struct nh_grp *grp, uint8_t count)
625 {
626 nhg_connected_tree_init(depends);
627
628 for (int i = 0; i < count; i++) {
629 struct nhg_hash_entry *depend = NULL;
630 /* We do not care about nexthop_grp.weight at
631 * this time. But we should figure out
632 * how to adapt this to our code in
633 * the future.
634 */
635 depend = depends_find_id_add(depends, grp[i].id);
636
637 if (!depend) {
638 flog_err(
639 EC_ZEBRA_NHG_SYNC,
640 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
641 grp[i].id);
642 return -1;
643 }
644
645 /*
646 * If this is a nexthop with its own group
647 * dependencies, add them as well. Not sure its
648 * even possible to have a group within a group
649 * in the kernel.
650 */
651
652 copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL);
653 }
654
655 return 0;
656 }
657
658 static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
659 struct nexthop *nh, afi_t afi, int type)
660 {
661 struct nhg_hash_entry *depend = NULL;
662 struct nexthop_group resolved_ng = {};
663
664 resolved_ng.nexthop = nh;
665
666 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
667 zlog_debug("%s: head %p, nh %pNHv",
668 __func__, nhg_depends, nh);
669
670 depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type);
671
672 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
673 zlog_debug("%s: nh %pNHv => %p (%u)",
674 __func__, nh, depend,
675 depend ? depend->id : 0);
676
677 if (depend)
678 depends_add(nhg_depends, depend);
679 }
680
681 /*
682 * Lookup an nhe in the global hash, using data from another nhe. If 'lookup'
683 * has an id value, that's used. Create a new global/shared nhe if not found.
684 */
685 static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
686 struct nhg_hash_entry *lookup,
687 struct nhg_connected_tree_head *nhg_depends,
688 afi_t afi, bool from_dplane)
689 {
690 bool created = false;
691 bool recursive = false;
692 struct nhg_hash_entry *newnhe, *backup_nhe;
693 struct nexthop *nh = NULL;
694
695 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
696 zlog_debug(
697 "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s",
698 __func__, lookup->id, lookup, lookup->vrf_id,
699 lookup->type, nhg_depends,
700 (from_dplane ? " (from dplane)" : ""));
701
702 if (lookup->id)
703 (*nhe) = zebra_nhg_lookup_id(lookup->id);
704 else
705 (*nhe) = hash_lookup(zrouter.nhgs, lookup);
706
707 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
708 zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe);
709
710 /* If we found an existing object, we're done */
711 if (*nhe)
712 goto done;
713
714 /* We're going to create/insert a new nhe:
715 * assign the next global id value if necessary.
716 */
717 if (lookup->id == 0)
718 lookup->id = nhg_get_next_id();
719
720 if (!from_dplane && lookup->id < ZEBRA_NHG_PROTO_LOWER) {
721 /*
722 * This is a zebra hashed/owned NHG.
723 *
724 * It goes in HASH and ID table.
725 */
726 newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
727 zebra_nhg_insert_id(newnhe);
728 } else {
729 /*
730 * This is upperproto owned NHG or one we read in from dataplane
731 * and should not be hashed to.
732 *
733 * It goes in ID table.
734 */
735 newnhe =
736 hash_get(zrouter.nhgs_id, lookup, zebra_nhg_hash_alloc);
737 }
738
739 created = true;
740
741 /* Mail back the new object */
742 *nhe = newnhe;
743
744 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
745 zlog_debug("%s: => created %p (%pNG)", __func__, newnhe,
746 newnhe);
747
748 /* Only hash/lookup the depends if the first lookup
749 * fails to find something. This should hopefully save a
750 * lot of cycles for larger ecmp sizes.
751 */
752 if (nhg_depends) {
753 /* If you don't want to hash on each nexthop in the
754 * nexthop group struct you can pass the depends
755 * directly. Kernel-side we do this since it just looks
756 * them up via IDs.
757 */
758 zebra_nhg_connect_depends(newnhe, nhg_depends);
759 goto done;
760 }
761
762 /* Prepare dependency relationships if this is not a
763 * singleton nexthop. There are two cases: a single
764 * recursive nexthop, where we need a relationship to the
765 * resolving nexthop; or a group of nexthops, where we need
766 * relationships with the corresponding singletons.
767 */
768 zebra_nhg_depends_init(newnhe);
769
770 nh = newnhe->nhg.nexthop;
771
772 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
773 SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
774
775 if (nh->next == NULL && newnhe->id < ZEBRA_NHG_PROTO_LOWER) {
776 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
777 /* Single recursive nexthop */
778 handle_recursive_depend(&newnhe->nhg_depends,
779 nh->resolved, afi,
780 newnhe->type);
781 recursive = true;
782 }
783 } else {
784 /* Proto-owned are groups by default */
785 /* List of nexthops */
786 for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
787 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
788 zlog_debug("%s: depends NH %pNHv %s",
789 __func__, nh,
790 CHECK_FLAG(nh->flags,
791 NEXTHOP_FLAG_RECURSIVE) ?
792 "(R)" : "");
793
794 depends_find_add(&newnhe->nhg_depends, nh, afi,
795 newnhe->type, from_dplane);
796 }
797 }
798
799 if (recursive)
800 SET_FLAG(newnhe->flags, NEXTHOP_GROUP_RECURSIVE);
801
802 /* Attach dependent backpointers to singletons */
803 zebra_nhg_connect_depends(newnhe, &newnhe->nhg_depends);
804
805 /**
806 * Backup Nexthops
807 */
808
809 if (zebra_nhg_get_backup_nhg(newnhe) == NULL ||
810 zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL)
811 goto done;
812
813 /* If there are backup nexthops, add them to the backup
814 * depends tree. The rules here are a little different.
815 */
816 recursive = false;
817 backup_nhe = newnhe->backup_info->nhe;
818
819 nh = backup_nhe->nhg.nexthop;
820
821 /* Singleton recursive NH */
822 if (nh->next == NULL &&
823 CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
824 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
825 zlog_debug("%s: backup depend NH %pNHv (R)",
826 __func__, nh);
827
828 /* Single recursive nexthop */
829 handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved,
830 afi, backup_nhe->type);
831 recursive = true;
832 } else {
833 /* One or more backup NHs */
834 for (; nh; nh = nh->next) {
835 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
836 zlog_debug("%s: backup depend NH %pNHv %s",
837 __func__, nh,
838 CHECK_FLAG(nh->flags,
839 NEXTHOP_FLAG_RECURSIVE) ?
840 "(R)" : "");
841
842 depends_find_add(&backup_nhe->nhg_depends, nh, afi,
843 backup_nhe->type, from_dplane);
844 }
845 }
846
847 if (recursive)
848 SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
849
850 done:
851 /* Reset time since last update */
852 (*nhe)->uptime = monotime(NULL);
853
854 return created;
855 }
856
857 /*
858 * Lookup or create an nhe, based on an nhg or an nhe id.
859 */
860 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
861 struct nexthop_group *nhg,
862 struct nhg_connected_tree_head *nhg_depends,
863 vrf_id_t vrf_id, afi_t afi, int type,
864 bool from_dplane)
865 {
866 struct nhg_hash_entry lookup = {};
867 bool created = false;
868
869 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
870 zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p",
871 __func__, id, nhg, vrf_id, type,
872 nhg_depends);
873
874 /* Use a temporary nhe and call into the superset/common code */
875 lookup.id = id;
876 lookup.type = type ? type : ZEBRA_ROUTE_NHG;
877 lookup.nhg = *nhg;
878
879 lookup.vrf_id = vrf_id;
880 if (nhg_depends || lookup.nhg.nexthop->next) {
881 /* Groups can have all vrfs and AF's in them */
882 lookup.afi = AFI_UNSPEC;
883 } else {
884 switch (lookup.nhg.nexthop->type) {
885 case (NEXTHOP_TYPE_IFINDEX):
886 case (NEXTHOP_TYPE_BLACKHOLE):
887 /*
888 * This switch case handles setting the afi different
889 * for ipv4/v6 routes. Ifindex/blackhole nexthop
890 * objects cannot be ambiguous, they must be Address
891 * Family specific. If we get here, we will either use
892 * the AF of the route, or the one we got passed from
893 * here from the kernel.
894 */
895 lookup.afi = afi;
896 break;
897 case (NEXTHOP_TYPE_IPV4_IFINDEX):
898 case (NEXTHOP_TYPE_IPV4):
899 lookup.afi = AFI_IP;
900 break;
901 case (NEXTHOP_TYPE_IPV6_IFINDEX):
902 case (NEXTHOP_TYPE_IPV6):
903 lookup.afi = AFI_IP6;
904 break;
905 }
906 }
907
908 created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi, from_dplane);
909
910 return created;
911 }
912
913 /* Find/create a single nexthop */
914 static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id,
915 struct nexthop *nh,
916 afi_t afi, int type,
917 bool from_dplane)
918 {
919 struct nhg_hash_entry *nhe = NULL;
920 struct nexthop_group nhg = {};
921 vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
922
923 nexthop_group_add_sorted(&nhg, nh);
924
925 zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type, from_dplane);
926
927 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
928 zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
929
930 return nhe;
931 }
932
933 static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
934 {
935 return ctx->id;
936 }
937
938 static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
939 {
940 ctx->status = status;
941 }
942
943 static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
944 {
945 return ctx->status;
946 }
947
948 static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
949 {
950 ctx->op = op;
951 }
952
953 static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
954 {
955 return ctx->op;
956 }
957
958 static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
959 {
960 return ctx->vrf_id;
961 }
962
963 static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
964 {
965 return ctx->type;
966 }
967
968 static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
969 {
970 return ctx->afi;
971 }
972
973 static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
974 {
975 return &ctx->u.nh;
976 }
977
978 static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
979 {
980 return ctx->count;
981 }
982
983 static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
984 {
985 return ctx->u.grp;
986 }
987
988 static struct nhg_ctx *nhg_ctx_new(void)
989 {
990 struct nhg_ctx *new;
991
992 new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
993
994 return new;
995 }
996
997 void nhg_ctx_free(struct nhg_ctx **ctx)
998 {
999 struct nexthop *nh;
1000
1001 if (ctx == NULL)
1002 return;
1003
1004 assert((*ctx) != NULL);
1005
1006 if (nhg_ctx_get_count(*ctx))
1007 goto done;
1008
1009 nh = nhg_ctx_get_nh(*ctx);
1010
1011 nexthop_del_labels(nh);
1012 nexthop_del_srv6_seg6local(nh);
1013 nexthop_del_srv6_seg6(nh);
1014
1015 done:
1016 XFREE(MTYPE_NHG_CTX, *ctx);
1017 }
1018
1019 static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
1020 struct nh_grp *grp, vrf_id_t vrf_id,
1021 afi_t afi, int type, uint8_t count)
1022 {
1023 struct nhg_ctx *ctx = NULL;
1024
1025 ctx = nhg_ctx_new();
1026
1027 ctx->id = id;
1028 ctx->vrf_id = vrf_id;
1029 ctx->afi = afi;
1030 ctx->type = type;
1031 ctx->count = count;
1032
1033 if (count)
1034 /* Copy over the array */
1035 memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
1036 else if (nh)
1037 ctx->u.nh = *nh;
1038
1039 return ctx;
1040 }
1041
1042 static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
1043 {
1044 struct nhg_connected *rb_node_dep;
1045
1046 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1047
1048 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1049 zebra_nhg_set_valid(rb_node_dep->nhe);
1050 }
1051
1052 static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
1053 {
1054 struct nhg_connected *rb_node_dep;
1055
1056 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1057
1058 /* If we're in shutdown, this interface event needs to clean
1059 * up installed NHGs, so don't clear that flag directly.
1060 */
1061 if (!zrouter.in_shutdown)
1062 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1063
1064 /* Update validity of nexthops depending on it */
1065 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1066 zebra_nhg_check_valid(rb_node_dep->nhe);
1067 }
1068
1069 void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
1070 {
1071 struct nhg_connected *rb_node_dep = NULL;
1072 bool valid = false;
1073
1074 /* If anthing else in the group is valid, the group is valid */
1075 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1076 if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
1077 valid = true;
1078 goto done;
1079 }
1080 }
1081
1082 done:
1083 if (valid)
1084 zebra_nhg_set_valid(nhe);
1085 else
1086 zebra_nhg_set_invalid(nhe);
1087 }
1088
1089 static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe)
1090 {
1091 /* Remove it from any lists it may be on */
1092 zebra_nhg_depends_release(nhe);
1093 zebra_nhg_dependents_release(nhe);
1094 if (nhe->ifp)
1095 if_nhg_dependents_del(nhe->ifp, nhe);
1096 }
1097
1098 static void zebra_nhg_release(struct nhg_hash_entry *nhe)
1099 {
1100 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1101 zlog_debug("%s: nhe %p (%pNG)", __func__, nhe, nhe);
1102
1103 zebra_nhg_release_all_deps(nhe);
1104
1105 /*
1106 * If its not zebra owned, we didn't store it here and have to be
1107 * sure we don't clear one thats actually being used.
1108 */
1109 if (nhe->id < ZEBRA_NHG_PROTO_LOWER)
1110 hash_release(zrouter.nhgs, nhe);
1111
1112 hash_release(zrouter.nhgs_id, nhe);
1113 }
1114
1115 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
1116 {
1117 zebra_nhg_release(nhe);
1118 zebra_nhg_free(nhe);
1119 }
1120
1121 static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
1122 {
1123 /* Update validity of groups depending on it */
1124 struct nhg_connected *rb_node_dep;
1125
1126 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
1127 zebra_nhg_set_valid(rb_node_dep->nhe);
1128 }
1129
1130 /*
1131 * The kernel/other program has changed the state of a nexthop object we are
1132 * using.
1133 */
1134 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
1135 bool is_delete)
1136 {
1137 if (nhe->refcnt) {
1138 flog_err(
1139 EC_ZEBRA_NHG_SYNC,
1140 "Kernel %s a nexthop group with ID (%pNG) that we are still using for a route, sending it back down",
1141 (is_delete ? "deleted" : "updated"), nhe);
1142
1143 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1144 zebra_nhg_install_kernel(nhe);
1145 } else
1146 zebra_nhg_handle_uninstall(nhe);
1147 }
1148
1149 static int nhg_ctx_process_new(struct nhg_ctx *ctx)
1150 {
1151 struct nexthop_group *nhg = NULL;
1152 struct nhg_connected_tree_head nhg_depends = {};
1153 struct nhg_hash_entry *lookup = NULL;
1154 struct nhg_hash_entry *nhe = NULL;
1155
1156 uint32_t id = nhg_ctx_get_id(ctx);
1157 uint8_t count = nhg_ctx_get_count(ctx);
1158 vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
1159 int type = nhg_ctx_get_type(ctx);
1160 afi_t afi = nhg_ctx_get_afi(ctx);
1161
1162 lookup = zebra_nhg_lookup_id(id);
1163
1164 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1165 zlog_debug("%s: id %u, count %d, lookup => %p",
1166 __func__, id, count, lookup);
1167
1168 if (lookup) {
1169 /* This is already present in our table, hence an update
1170 * that we did not initate.
1171 */
1172 zebra_nhg_handle_kernel_state_change(lookup, false);
1173 return 0;
1174 }
1175
1176 if (nhg_ctx_get_count(ctx)) {
1177 nhg = nexthop_group_new();
1178 if (zebra_nhg_process_grp(nhg, &nhg_depends,
1179 nhg_ctx_get_grp(ctx), count)) {
1180 depends_decrement_free(&nhg_depends);
1181 nexthop_group_delete(&nhg);
1182 return -ENOENT;
1183 }
1184
1185 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi,
1186 type, true))
1187 depends_decrement_free(&nhg_depends);
1188
1189 /* These got copied over in zebra_nhg_alloc() */
1190 nexthop_group_delete(&nhg);
1191 } else
1192 nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, type,
1193 true);
1194
1195 if (!nhe) {
1196 flog_err(
1197 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1198 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
1199 id);
1200 return -1;
1201 }
1202
1203 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1204 zlog_debug("%s: nhe %p (%pNG) is new", __func__, nhe, nhe);
1205
1206 /*
1207 * If daemon nhg from the kernel, add a refcnt here to indicate the
1208 * daemon owns it.
1209 */
1210 if (PROTO_OWNED(nhe))
1211 zebra_nhg_increment_ref(nhe);
1212
1213 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1214 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1215
1216 return 0;
1217 }
1218
1219 static int nhg_ctx_process_del(struct nhg_ctx *ctx)
1220 {
1221 struct nhg_hash_entry *nhe = NULL;
1222 uint32_t id = nhg_ctx_get_id(ctx);
1223
1224 nhe = zebra_nhg_lookup_id(id);
1225
1226 if (!nhe) {
1227 flog_warn(
1228 EC_ZEBRA_BAD_NHG_MESSAGE,
1229 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
1230 id);
1231 return -1;
1232 }
1233
1234 zebra_nhg_handle_kernel_state_change(nhe, true);
1235
1236 return 0;
1237 }
1238
1239 static void nhg_ctx_fini(struct nhg_ctx **ctx)
1240 {
1241 /*
1242 * Just freeing for now, maybe do something more in the future
1243 * based on flag.
1244 */
1245
1246 nhg_ctx_free(ctx);
1247 }
1248
1249 static int queue_add(struct nhg_ctx *ctx)
1250 {
1251 /* If its queued or already processed do nothing */
1252 if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
1253 return 0;
1254
1255 if (rib_queue_nhg_ctx_add(ctx)) {
1256 nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
1257 return -1;
1258 }
1259
1260 nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
1261
1262 return 0;
1263 }
1264
1265 int nhg_ctx_process(struct nhg_ctx *ctx)
1266 {
1267 int ret = 0;
1268
1269 switch (nhg_ctx_get_op(ctx)) {
1270 case NHG_CTX_OP_NEW:
1271 ret = nhg_ctx_process_new(ctx);
1272 if (nhg_ctx_get_count(ctx) && ret == -ENOENT
1273 && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
1274 /**
1275 * We have entered a situation where we are
1276 * processing a group from the kernel
1277 * that has a contained nexthop which
1278 * we have not yet processed.
1279 *
1280 * Re-enqueue this ctx to be handled exactly one
1281 * more time (indicated by the flag).
1282 *
1283 * By the time we get back to it, we
1284 * should have processed its depends.
1285 */
1286 nhg_ctx_set_status(ctx, NHG_CTX_NONE);
1287 if (queue_add(ctx) == 0) {
1288 nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
1289 return 0;
1290 }
1291 }
1292 break;
1293 case NHG_CTX_OP_DEL:
1294 ret = nhg_ctx_process_del(ctx);
1295 case NHG_CTX_OP_NONE:
1296 break;
1297 }
1298
1299 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
1300
1301 nhg_ctx_fini(&ctx);
1302
1303 return ret;
1304 }
1305
1306 /* Kernel-side, you either get a single new nexthop or a array of ID's */
1307 int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
1308 uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
1309 int startup)
1310 {
1311 struct nhg_ctx *ctx = NULL;
1312
1313 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1314 zlog_debug("%s: nh %pNHv, id %u, count %d",
1315 __func__, nh, id, (int)count);
1316
1317 if (id > id_counter && id < ZEBRA_NHG_PROTO_LOWER)
1318 /* Increase our counter so we don't try to create
1319 * an ID that already exists
1320 */
1321 id_counter = id;
1322
1323 ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
1324 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
1325
1326 /* Under statup conditions, we need to handle them immediately
1327 * like we do for routes. Otherwise, we are going to get a route
1328 * with a nhe_id that we have not handled.
1329 */
1330 if (startup)
1331 return nhg_ctx_process(ctx);
1332
1333 if (queue_add(ctx)) {
1334 nhg_ctx_fini(&ctx);
1335 return -1;
1336 }
1337
1338 return 0;
1339 }
1340
1341 /* Kernel-side, received delete message */
1342 int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
1343 {
1344 struct nhg_ctx *ctx = NULL;
1345
1346 ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
1347
1348 nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
1349
1350 if (queue_add(ctx)) {
1351 nhg_ctx_fini(&ctx);
1352 return -1;
1353 }
1354
1355 return 0;
1356 }
1357
1358 /* Some dependency helper functions */
1359 static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
1360 afi_t afi, int type)
1361 {
1362 struct nhg_hash_entry *nhe;
1363 struct nexthop *lookup = NULL;
1364
1365 lookup = nexthop_dup(nh, NULL);
1366
1367 nhe = zebra_nhg_find_nexthop(0, lookup, afi, type, false);
1368
1369 nexthops_free(lookup);
1370
1371 return nhe;
1372 }
1373
1374 static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
1375 afi_t afi, int type,
1376 bool from_dplane)
1377 {
1378 struct nhg_hash_entry *nhe;
1379 struct nexthop lookup = {};
1380
1381 /* Capture a snapshot of this single nh; it might be part of a list,
1382 * so we need to make a standalone copy.
1383 */
1384 nexthop_copy_no_recurse(&lookup, nh, NULL);
1385
1386 nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane);
1387
1388 /* The copy may have allocated labels; free them if necessary. */
1389 nexthop_del_labels(&lookup);
1390 nexthop_del_srv6_seg6local(&lookup);
1391 nexthop_del_srv6_seg6(&lookup);
1392
1393 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1394 zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
1395
1396 return nhe;
1397 }
1398
1399 static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
1400 int type, bool from_dplane)
1401 {
1402 struct nhg_hash_entry *nhe = NULL;
1403
1404 if (!nh)
1405 goto done;
1406
1407 /* We are separating these functions out to increase handling speed
1408 * in the non-recursive case (by not alloc/freeing)
1409 */
1410 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
1411 nhe = depends_find_recursive(nh, afi, type);
1412 else
1413 nhe = depends_find_singleton(nh, afi, type, from_dplane);
1414
1415
1416 if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1417 zlog_debug("%s: nh %pNHv %s => %p (%pNG)", __func__, nh,
1418 CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE) ? "(R)"
1419 : "",
1420 nhe, nhe);
1421 }
1422
1423 done:
1424 return nhe;
1425 }
1426
1427 static void depends_add(struct nhg_connected_tree_head *head,
1428 struct nhg_hash_entry *depend)
1429 {
1430 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1431 zlog_debug("%s: head %p nh %pNHv",
1432 __func__, head, depend->nhg.nexthop);
1433
1434 /* If NULL is returned, it was successfully added and
1435 * needs to have its refcnt incremented.
1436 *
1437 * Else the NHE is already present in the tree and doesn't
1438 * need to increment the refcnt.
1439 */
1440 if (nhg_connected_tree_add_nhe(head, depend) == NULL)
1441 zebra_nhg_increment_ref(depend);
1442 }
1443
1444 static struct nhg_hash_entry *
1445 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1446 afi_t afi, int type, bool from_dplane)
1447 {
1448 struct nhg_hash_entry *depend = NULL;
1449
1450 depend = depends_find(nh, afi, type, from_dplane);
1451
1452 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1453 zlog_debug("%s: nh %pNHv => %p",
1454 __func__, nh, depend);
1455
1456 if (depend)
1457 depends_add(head, depend);
1458
1459 return depend;
1460 }
1461
1462 static struct nhg_hash_entry *
1463 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1464 {
1465 struct nhg_hash_entry *depend = NULL;
1466
1467 depend = zebra_nhg_lookup_id(id);
1468
1469 if (depend)
1470 depends_add(head, depend);
1471
1472 return depend;
1473 }
1474
1475 static void depends_decrement_free(struct nhg_connected_tree_head *head)
1476 {
1477 nhg_connected_tree_decrement_ref(head);
1478 nhg_connected_tree_free(head);
1479 }
1480
1481 /* Find an nhe based on a list of nexthops */
1482 struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
1483 struct nexthop_group *nhg,
1484 afi_t rt_afi, int type)
1485 {
1486 struct nhg_hash_entry *nhe = NULL;
1487 vrf_id_t vrf_id;
1488
1489 /*
1490 * CLANG SA is complaining that nexthop may be NULL
1491 * Make it happy but this is ridonc
1492 */
1493 assert(nhg->nexthop);
1494 vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
1495
1496 zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type, false);
1497
1498 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1499 zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
1500
1501 return nhe;
1502 }
1503
1504 /* Find an nhe based on a route's nhe */
1505 struct nhg_hash_entry *
1506 zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi)
1507 {
1508 struct nhg_hash_entry *nhe = NULL;
1509
1510 if (!(rt_nhe && rt_nhe->nhg.nexthop)) {
1511 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1512 "No nexthop passed to %s", __func__);
1513 return NULL;
1514 }
1515
1516 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1517 zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe);
1518
1519 zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false);
1520
1521 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1522 zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
1523
1524 return nhe;
1525 }
1526
1527 /*
1528 * Allocate backup nexthop info object. Typically these are embedded in
1529 * nhg_hash_entry objects.
1530 */
1531 struct nhg_backup_info *zebra_nhg_backup_alloc(void)
1532 {
1533 struct nhg_backup_info *p;
1534
1535 p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info));
1536
1537 p->nhe = zebra_nhg_alloc();
1538
1539 /* Identify the embedded group used to hold the list of backups */
1540 SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP);
1541
1542 return p;
1543 }
1544
1545 /*
1546 * Free backup nexthop info object, deal with any embedded allocations
1547 */
1548 void zebra_nhg_backup_free(struct nhg_backup_info **p)
1549 {
1550 if (p && *p) {
1551 if ((*p)->nhe)
1552 zebra_nhg_free((*p)->nhe);
1553
1554 XFREE(MTYPE_NHG, (*p));
1555 }
1556 }
1557
1558 /* Accessor for backup nexthop group */
1559 struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe)
1560 {
1561 struct nexthop_group *p = NULL;
1562
1563 if (nhe) {
1564 if (nhe->backup_info && nhe->backup_info->nhe)
1565 p = &(nhe->backup_info->nhe->nhg);
1566 }
1567
1568 return p;
1569 }
1570
1571 /*
1572 * Helper to return a copy of a backup_info - note that this is a shallow
1573 * copy, meant to be used when creating a new nhe from info passed in with
1574 * a route e.g.
1575 */
1576 static struct nhg_backup_info *
1577 nhg_backup_copy(const struct nhg_backup_info *orig)
1578 {
1579 struct nhg_backup_info *b;
1580
1581 b = zebra_nhg_backup_alloc();
1582
1583 /* Copy list of nexthops */
1584 nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg));
1585
1586 return b;
1587 }
1588
1589 static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
1590 {
1591 nexthops_free(nhe->nhg.nexthop);
1592
1593 zebra_nhg_backup_free(&nhe->backup_info);
1594
1595 /* Decrement to remove connection ref */
1596 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1597 nhg_connected_tree_free(&nhe->nhg_depends);
1598 nhg_connected_tree_free(&nhe->nhg_dependents);
1599 }
1600
1601 void zebra_nhg_free(struct nhg_hash_entry *nhe)
1602 {
1603 if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1604 /* Group or singleton? */
1605 if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1606 zlog_debug("%s: nhe %p (%pNG), refcnt %d", __func__,
1607 nhe, nhe, nhe->refcnt);
1608 else
1609 zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
1610 __func__, nhe, nhe, nhe->refcnt,
1611 nhe->nhg.nexthop);
1612 }
1613
1614 THREAD_OFF(nhe->timer);
1615
1616 if (nhe->refcnt)
1617 zlog_debug("nhe_id=%pNG hash refcnt=%d", nhe, nhe->refcnt);
1618
1619 zebra_nhg_free_members(nhe);
1620
1621 XFREE(MTYPE_NHG, nhe);
1622 }
1623
1624 /*
1625 * Let's just drop the memory associated with each item
1626 */
1627 void zebra_nhg_hash_free(void *p)
1628 {
1629 struct nhg_hash_entry *nhe = p;
1630
1631 if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
1632 /* Group or singleton? */
1633 if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
1634 zlog_debug("%s: nhe %p (%u), refcnt %d", __func__, nhe,
1635 nhe->id, nhe->refcnt);
1636 else
1637 zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
1638 __func__, nhe, nhe, nhe->refcnt,
1639 nhe->nhg.nexthop);
1640 }
1641
1642 THREAD_OFF(nhe->timer);
1643
1644 nexthops_free(nhe->nhg.nexthop);
1645
1646 XFREE(MTYPE_NHG, nhe);
1647 }
1648
1649 /*
1650 * On cleanup there are nexthop groups that have not
1651 * been resolved at all( a nhe->id of 0 ). As such
1652 * zebra needs to clean up the memory associated with
1653 * those entries.
1654 */
1655 void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg)
1656 {
1657 struct nhg_hash_entry *nhe = b->data;
1658 struct nhg_connected *dep;
1659
1660 while ((dep = nhg_connected_tree_pop(&nhe->nhg_depends))) {
1661 if (dep->nhe->id == 0)
1662 zebra_nhg_hash_free(dep->nhe);
1663
1664 nhg_connected_free(dep);
1665 }
1666
1667 while ((dep = nhg_connected_tree_pop(&nhe->nhg_dependents)))
1668 nhg_connected_free(dep);
1669
1670 if (nhe->backup_info && nhe->backup_info->nhe->id == 0) {
1671 while ((dep = nhg_connected_tree_pop(
1672 &nhe->backup_info->nhe->nhg_depends)))
1673 nhg_connected_free(dep);
1674
1675 zebra_nhg_hash_free(nhe->backup_info->nhe);
1676
1677 XFREE(MTYPE_NHG, nhe->backup_info);
1678 }
1679 }
1680
1681 static void zebra_nhg_timer(struct thread *thread)
1682 {
1683 struct nhg_hash_entry *nhe = THREAD_ARG(thread);
1684
1685 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1686 zlog_debug("Nexthop Timer for nhe: %pNG", nhe);
1687
1688 if (nhe->refcnt == 1)
1689 zebra_nhg_decrement_ref(nhe);
1690 }
1691
1692 void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1693 {
1694 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1695 zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
1696 nhe->refcnt, nhe->refcnt - 1);
1697
1698 nhe->refcnt--;
1699
1700 if (!zrouter.in_shutdown && nhe->refcnt <= 0 &&
1701 CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
1702 !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND)) {
1703 nhe->refcnt = 1;
1704 SET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
1705 thread_add_timer(zrouter.master, zebra_nhg_timer, nhe,
1706 zrouter.nhg_keep, &nhe->timer);
1707 return;
1708 }
1709
1710 if (!zebra_nhg_depends_is_empty(nhe))
1711 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1712
1713 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1714 zebra_nhg_uninstall_kernel(nhe);
1715 }
1716
1717 void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1718 {
1719 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
1720 zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
1721 nhe->refcnt, nhe->refcnt + 1);
1722
1723 nhe->refcnt++;
1724
1725 if (thread_is_scheduled(nhe->timer)) {
1726 THREAD_OFF(nhe->timer);
1727 nhe->refcnt--;
1728 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
1729 }
1730
1731 if (!zebra_nhg_depends_is_empty(nhe))
1732 nhg_connected_tree_increment_ref(&nhe->nhg_depends);
1733 }
1734
1735 static struct nexthop *nexthop_set_resolved(afi_t afi,
1736 const struct nexthop *newhop,
1737 struct nexthop *nexthop,
1738 struct zebra_sr_policy *policy)
1739 {
1740 struct nexthop *resolved_hop;
1741 uint8_t num_labels = 0;
1742 mpls_label_t labels[MPLS_MAX_LABELS];
1743 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1744 int i = 0;
1745
1746 resolved_hop = nexthop_new();
1747 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1748
1749 resolved_hop->vrf_id = nexthop->vrf_id;
1750 switch (newhop->type) {
1751 case NEXTHOP_TYPE_IPV4:
1752 case NEXTHOP_TYPE_IPV4_IFINDEX:
1753 /* If the resolving route specifies a gateway, use it */
1754 resolved_hop->type = newhop->type;
1755 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1756
1757 if (newhop->ifindex) {
1758 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1759 resolved_hop->ifindex = newhop->ifindex;
1760 }
1761 break;
1762 case NEXTHOP_TYPE_IPV6:
1763 case NEXTHOP_TYPE_IPV6_IFINDEX:
1764 resolved_hop->type = newhop->type;
1765 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1766
1767 if (newhop->ifindex) {
1768 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1769 resolved_hop->ifindex = newhop->ifindex;
1770 }
1771 break;
1772 case NEXTHOP_TYPE_IFINDEX:
1773 /* If the resolving route is an interface route,
1774 * it means the gateway we are looking up is connected
1775 * to that interface. (The actual network is _not_ onlink).
1776 * Therefore, the resolved route should have the original
1777 * gateway as nexthop as it is directly connected.
1778 *
1779 * On Linux, we have to set the onlink netlink flag because
1780 * otherwise, the kernel won't accept the route.
1781 */
1782 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1783 if (afi == AFI_IP) {
1784 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1785 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1786 } else if (afi == AFI_IP6) {
1787 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1788 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1789 }
1790 resolved_hop->ifindex = newhop->ifindex;
1791 break;
1792 case NEXTHOP_TYPE_BLACKHOLE:
1793 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
1794 resolved_hop->bh_type = newhop->bh_type;
1795 break;
1796 }
1797
1798 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1799 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1800
1801 /* Copy labels of the resolved route and the parent resolving to it */
1802 if (policy) {
1803 int i = 0;
1804
1805 /*
1806 * Don't push the first SID if the corresponding action in the
1807 * LFIB is POP.
1808 */
1809 if (!newhop->nh_label || !newhop->nh_label->num_labels
1810 || newhop->nh_label->label[0] == MPLS_LABEL_IMPLICIT_NULL)
1811 i = 1;
1812
1813 for (; i < policy->segment_list.label_num; i++)
1814 labels[num_labels++] = policy->segment_list.labels[i];
1815 label_type = policy->segment_list.type;
1816 } else if (newhop->nh_label) {
1817 for (i = 0; i < newhop->nh_label->num_labels; i++) {
1818 /* Be a bit picky about overrunning the local array */
1819 if (num_labels >= MPLS_MAX_LABELS) {
1820 if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1821 zlog_debug("%s: too many labels in newhop %pNHv",
1822 __func__, newhop);
1823 break;
1824 }
1825 labels[num_labels++] = newhop->nh_label->label[i];
1826 }
1827 /* Use the "outer" type */
1828 label_type = newhop->nh_label_type;
1829 }
1830
1831 if (nexthop->nh_label) {
1832 for (i = 0; i < nexthop->nh_label->num_labels; i++) {
1833 /* Be a bit picky about overrunning the local array */
1834 if (num_labels >= MPLS_MAX_LABELS) {
1835 if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
1836 zlog_debug("%s: too many labels in nexthop %pNHv",
1837 __func__, nexthop);
1838 break;
1839 }
1840 labels[num_labels++] = nexthop->nh_label->label[i];
1841 }
1842
1843 /* If the parent has labels, use its type if
1844 * we don't already have one.
1845 */
1846 if (label_type == ZEBRA_LSP_NONE)
1847 label_type = nexthop->nh_label_type;
1848 }
1849
1850 if (num_labels)
1851 nexthop_add_labels(resolved_hop, label_type, num_labels,
1852 labels);
1853
1854 if (nexthop->nh_srv6) {
1855 nexthop_add_srv6_seg6local(resolved_hop,
1856 nexthop->nh_srv6->seg6local_action,
1857 &nexthop->nh_srv6->seg6local_ctx);
1858 nexthop_add_srv6_seg6(resolved_hop,
1859 &nexthop->nh_srv6->seg6_segs);
1860 }
1861
1862 resolved_hop->rparent = nexthop;
1863 _nexthop_add(&nexthop->resolved, resolved_hop);
1864
1865 return resolved_hop;
1866 }
1867
1868 /* Checks if nexthop we are trying to resolve to is valid */
1869 static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1870 const struct nexthop *resolved)
1871 {
1872 /* Can't resolve to a recursive nexthop */
1873 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1874 return false;
1875
1876 /* Must be ACTIVE */
1877 if (!CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_ACTIVE))
1878 return false;
1879
1880 /* Must not be duplicate */
1881 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_DUPLICATE))
1882 return false;
1883
1884 switch (nexthop->type) {
1885 case NEXTHOP_TYPE_IPV4_IFINDEX:
1886 case NEXTHOP_TYPE_IPV6_IFINDEX:
1887 /* If the nexthop we are resolving to does not match the
1888 * ifindex for the nexthop the route wanted, its not valid.
1889 */
1890 if (nexthop->ifindex != resolved->ifindex)
1891 return false;
1892 break;
1893 case NEXTHOP_TYPE_IPV4:
1894 case NEXTHOP_TYPE_IPV6:
1895 case NEXTHOP_TYPE_IFINDEX:
1896 case NEXTHOP_TYPE_BLACKHOLE:
1897 break;
1898 }
1899
1900 return true;
1901 }
1902
1903 /*
1904 * When resolving a recursive nexthop, capture backup nexthop(s) also
1905 * so they can be conveyed through the dataplane to the FIB. We'll look
1906 * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
1907 * into the route's resolved nh 'resolved' and its nhe 'nhe'.
1908 */
1909 static int resolve_backup_nexthops(const struct nexthop *nexthop,
1910 const struct nhg_hash_entry *nhe,
1911 struct nexthop *resolved,
1912 struct nhg_hash_entry *resolve_nhe,
1913 struct backup_nh_map_s *map)
1914 {
1915 int i, j, idx;
1916 const struct nexthop *bnh;
1917 struct nexthop *nh, *newnh;
1918 mpls_label_t labels[MPLS_MAX_LABELS];
1919 uint8_t num_labels;
1920
1921 assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
1922
1923 /* Locate backups from the original nexthop's backup index and nhe */
1924 for (i = 0; i < nexthop->backup_num; i++) {
1925 idx = nexthop->backup_idx[i];
1926
1927 /* Do we already know about this particular backup? */
1928 for (j = 0; j < map->map_count; j++) {
1929 if (map->map[j].orig_idx == idx)
1930 break;
1931 }
1932
1933 if (j < map->map_count) {
1934 resolved->backup_idx[resolved->backup_num] =
1935 map->map[j].new_idx;
1936 resolved->backup_num++;
1937
1938 SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
1939
1940 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1941 zlog_debug("%s: found map idx orig %d, new %d",
1942 __func__, map->map[j].orig_idx,
1943 map->map[j].new_idx);
1944
1945 continue;
1946 }
1947
1948 /* We can't handle any new map entries at this point. */
1949 if (map->map_count == MULTIPATH_NUM)
1950 break;
1951
1952 /* Need to create/copy a new backup */
1953 bnh = nhe->backup_info->nhe->nhg.nexthop;
1954 for (j = 0; j < idx; j++) {
1955 if (bnh == NULL)
1956 break;
1957 bnh = bnh->next;
1958 }
1959
1960 /* Whoops - bad index in the nexthop? */
1961 if (bnh == NULL)
1962 continue;
1963
1964 if (resolve_nhe->backup_info == NULL)
1965 resolve_nhe->backup_info = zebra_nhg_backup_alloc();
1966
1967 /* Update backup info in the resolving nexthop and its nhe */
1968 newnh = nexthop_dup_no_recurse(bnh, NULL);
1969
1970 /* We may need some special handling for mpls labels: the new
1971 * backup needs to carry the recursive nexthop's labels,
1972 * if any: they may be vrf labels e.g.
1973 * The original/inner labels are in the stack of 'resolve_nhe',
1974 * if that is longer than the stack in 'nexthop'.
1975 */
1976 if (newnh->nh_label && resolved->nh_label &&
1977 nexthop->nh_label) {
1978 if (resolved->nh_label->num_labels >
1979 nexthop->nh_label->num_labels) {
1980 /* Prepare new label stack */
1981 num_labels = 0;
1982 for (j = 0; j < newnh->nh_label->num_labels;
1983 j++) {
1984 labels[j] = newnh->nh_label->label[j];
1985 num_labels++;
1986 }
1987
1988 /* Include inner labels */
1989 for (j = nexthop->nh_label->num_labels;
1990 j < resolved->nh_label->num_labels;
1991 j++) {
1992 labels[num_labels] =
1993 resolved->nh_label->label[j];
1994 num_labels++;
1995 }
1996
1997 /* Replace existing label stack in the backup */
1998 nexthop_del_labels(newnh);
1999 nexthop_add_labels(newnh, bnh->nh_label_type,
2000 num_labels, labels);
2001 }
2002 }
2003
2004 /* Need to compute the new backup index in the new
2005 * backup list, and add to map struct.
2006 */
2007 j = 0;
2008 nh = resolve_nhe->backup_info->nhe->nhg.nexthop;
2009 if (nh) {
2010 while (nh->next) {
2011 nh = nh->next;
2012 j++;
2013 }
2014
2015 nh->next = newnh;
2016 j++;
2017
2018 } else /* First one */
2019 resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
2020
2021 /* Capture index */
2022 resolved->backup_idx[resolved->backup_num] = j;
2023 resolved->backup_num++;
2024
2025 SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
2026
2027 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2028 zlog_debug("%s: added idx orig %d, new %d",
2029 __func__, idx, j);
2030
2031 /* Update map/cache */
2032 map->map[map->map_count].orig_idx = idx;
2033 map->map[map->map_count].new_idx = j;
2034 map->map_count++;
2035 }
2036
2037 return 0;
2038 }
2039
2040 /*
2041 * So this nexthop resolution has decided that a connected route
2042 * is the correct choice. At this point in time if FRR has multiple
2043 * connected routes that all point to the same prefix one will be
2044 * selected, *but* the particular interface may not be the one
2045 * that the nexthop points at. Let's look at all the available
2046 * connected routes on this node and if any of them auto match
2047 * the routes nexthops ifindex that is good enough for a match
2048 *
2049 * This code is depending on the fact that a nexthop->ifindex is 0
2050 * if it is not known, if this assumption changes, yummy!
2051 * Additionally a ifindx of 0 means figure it out for us.
2052 */
2053 static struct route_entry *
2054 zebra_nhg_connected_ifindex(struct route_node *rn, struct route_entry *match,
2055 int32_t curr_ifindex)
2056 {
2057 struct nexthop *newhop = match->nhe->nhg.nexthop;
2058 struct route_entry *re;
2059
2060 assert(newhop); /* What a kick in the patooey */
2061
2062 if (curr_ifindex == 0)
2063 return match;
2064
2065 if (curr_ifindex == newhop->ifindex)
2066 return match;
2067
2068 /*
2069 * At this point we know that this route is matching a connected
2070 * but there are possibly a bunch of connected routes that are
2071 * alive that should be considered as well. So let's iterate over
2072 * all the re's and see if they are connected as well and maybe one
2073 * of those ifindexes match as well.
2074 */
2075 RNODE_FOREACH_RE (rn, re) {
2076 if (re->type != ZEBRA_ROUTE_CONNECT)
2077 continue;
2078
2079 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
2080 continue;
2081
2082 /*
2083 * zebra has a connected route that is not removed
2084 * let's test if it is good
2085 */
2086 newhop = re->nhe->nhg.nexthop;
2087 assert(newhop);
2088 if (curr_ifindex == newhop->ifindex)
2089 return re;
2090 }
2091
2092 return match;
2093 }
2094
2095 /*
2096 * Given a nexthop we need to properly recursively resolve,
2097 * do a table lookup to find and match if at all possible.
2098 * Set the nexthop->ifindex and resolution info as appropriate.
2099 */
2100 static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
2101 const struct prefix *top, int type, uint32_t flags,
2102 uint32_t *pmtu, vrf_id_t vrf_id)
2103 {
2104 struct prefix p;
2105 struct route_table *table;
2106 struct route_node *rn;
2107 struct route_entry *match = NULL;
2108 int resolved;
2109 struct zebra_nhlfe *nhlfe;
2110 struct nexthop *newhop;
2111 struct interface *ifp;
2112 rib_dest_t *dest;
2113 struct zebra_vrf *zvrf;
2114 struct in_addr local_ipv4;
2115 struct in_addr *ipv4;
2116 afi_t afi = AFI_IP;
2117
2118 /* Reset some nexthop attributes that we'll recompute if necessary */
2119 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
2120 || (nexthop->type == NEXTHOP_TYPE_IPV6))
2121 nexthop->ifindex = 0;
2122
2123 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
2124 nexthops_free(nexthop->resolved);
2125 nexthop->resolved = NULL;
2126
2127 /*
2128 * Set afi based on nexthop type.
2129 * Some nexthop types get special handling, possibly skipping
2130 * the normal processing.
2131 */
2132 switch (nexthop->type) {
2133 case NEXTHOP_TYPE_IFINDEX:
2134
2135 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2136 /*
2137 * If the interface exists and its operative or its a kernel
2138 * route and interface is up, its active. We trust kernel routes
2139 * to be good.
2140 */
2141 if (ifp && (if_is_operative(ifp)))
2142 return 1;
2143 else
2144 return 0;
2145 break;
2146
2147 case NEXTHOP_TYPE_IPV6_IFINDEX:
2148 afi = AFI_IP6;
2149
2150 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
2151 ifp = if_lookup_by_index(nexthop->ifindex,
2152 nexthop->vrf_id);
2153 if (ifp && if_is_operative(ifp))
2154 return 1;
2155 else
2156 return 0;
2157 }
2158 break;
2159
2160 case NEXTHOP_TYPE_IPV4:
2161 case NEXTHOP_TYPE_IPV4_IFINDEX:
2162 afi = AFI_IP;
2163 break;
2164 case NEXTHOP_TYPE_IPV6:
2165 afi = AFI_IP6;
2166 break;
2167
2168 case NEXTHOP_TYPE_BLACKHOLE:
2169 return 1;
2170 }
2171
2172 /*
2173 * If the nexthop has been marked as 'onlink' we just need to make
2174 * sure the nexthop's interface is known and is operational.
2175 */
2176 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
2177 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2178 if (!ifp) {
2179 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2180 zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
2181 nexthop, nexthop->ifindex);
2182 return 0;
2183 }
2184 if (!if_is_operative(ifp)) {
2185 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2186 zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
2187 nexthop, ifp->name);
2188 return 0;
2189 }
2190 return 1;
2191 }
2192
2193 if (top &&
2194 ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN &&
2195 nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) ||
2196 (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN &&
2197 memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) ==
2198 0)) &&
2199 nexthop->vrf_id == vrf_id) {
2200 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2201 zlog_debug(
2202 " :%s: Attempting to install a max prefixlength route through itself",
2203 __func__);
2204 return 0;
2205 }
2206
2207 /* Validation for ipv4 mapped ipv6 nexthop. */
2208 if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
2209 afi = AFI_IP;
2210 ipv4 = &local_ipv4;
2211 ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, ipv4);
2212 } else {
2213 ipv4 = &nexthop->gate.ipv4;
2214 }
2215
2216 /* Processing for nexthops with SR 'color' attribute, using
2217 * the corresponding SR policy object.
2218 */
2219 if (nexthop->srte_color) {
2220 struct ipaddr endpoint = {0};
2221 struct zebra_sr_policy *policy;
2222
2223 switch (afi) {
2224 case AFI_IP:
2225 endpoint.ipa_type = IPADDR_V4;
2226 endpoint.ipaddr_v4 = *ipv4;
2227 break;
2228 case AFI_IP6:
2229 endpoint.ipa_type = IPADDR_V6;
2230 endpoint.ipaddr_v6 = nexthop->gate.ipv6;
2231 break;
2232 default:
2233 flog_err(EC_LIB_DEVELOPMENT,
2234 "%s: unknown address-family: %u", __func__,
2235 afi);
2236 exit(1);
2237 }
2238
2239 policy = zebra_sr_policy_find(nexthop->srte_color, &endpoint);
2240 if (policy && policy->status == ZEBRA_SR_POLICY_UP) {
2241 resolved = 0;
2242 frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list,
2243 nhlfe) {
2244 if (!CHECK_FLAG(nhlfe->flags,
2245 NHLFE_FLAG_SELECTED)
2246 || CHECK_FLAG(nhlfe->flags,
2247 NHLFE_FLAG_DELETED))
2248 continue;
2249 SET_FLAG(nexthop->flags,
2250 NEXTHOP_FLAG_RECURSIVE);
2251 nexthop_set_resolved(afi, nhlfe->nexthop,
2252 nexthop, policy);
2253 resolved = 1;
2254 }
2255 if (resolved)
2256 return 1;
2257 }
2258 }
2259
2260 /* Make lookup prefix. */
2261 memset(&p, 0, sizeof(struct prefix));
2262 switch (afi) {
2263 case AFI_IP:
2264 p.family = AF_INET;
2265 p.prefixlen = IPV4_MAX_BITLEN;
2266 p.u.prefix4 = *ipv4;
2267 break;
2268 case AFI_IP6:
2269 p.family = AF_INET6;
2270 p.prefixlen = IPV6_MAX_BITLEN;
2271 p.u.prefix6 = nexthop->gate.ipv6;
2272 break;
2273 default:
2274 assert(afi != AFI_IP && afi != AFI_IP6);
2275 break;
2276 }
2277 /* Lookup table. */
2278 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
2279 /* get zvrf */
2280 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
2281 if (!table || !zvrf) {
2282 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2283 zlog_debug(" %s: Table not found", __func__);
2284 return 0;
2285 }
2286
2287 rn = route_node_match(table, (struct prefix *)&p);
2288 while (rn) {
2289 route_unlock_node(rn);
2290
2291 /* Lookup should halt if we've matched against ourselves ('top',
2292 * if specified) - i.e., we cannot have a nexthop NH1 is
2293 * resolved by a route NH1. The exception is if the route is a
2294 * host route.
2295 */
2296 if (prefix_same(&rn->p, top))
2297 if (((afi == AFI_IP)
2298 && (rn->p.prefixlen != IPV4_MAX_BITLEN))
2299 || ((afi == AFI_IP6)
2300 && (rn->p.prefixlen != IPV6_MAX_BITLEN))) {
2301 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2302 zlog_debug(
2303 " %s: Matched against ourself and prefix length is not max bit length",
2304 __func__);
2305 return 0;
2306 }
2307
2308 /* Pick up selected route. */
2309 /* However, do not resolve over default route unless explicitly
2310 * allowed.
2311 */
2312 if (is_default_prefix(&rn->p)
2313 && !rnh_resolve_via_default(zvrf, p.family)) {
2314 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2315 zlog_debug(
2316 " :%s: Resolved against default route",
2317 __func__);
2318 return 0;
2319 }
2320
2321 dest = rib_dest_from_rnode(rn);
2322 if (dest && dest->selected_fib
2323 && !CHECK_FLAG(dest->selected_fib->status,
2324 ROUTE_ENTRY_REMOVED)
2325 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
2326 match = dest->selected_fib;
2327
2328 /* If there is no selected route or matched route is EGP, go up
2329 * tree.
2330 */
2331 if (!match) {
2332 do {
2333 rn = rn->parent;
2334 } while (rn && rn->info == NULL);
2335 if (rn)
2336 route_lock_node(rn);
2337
2338 continue;
2339 }
2340
2341 if ((match->type == ZEBRA_ROUTE_CONNECT) ||
2342 (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) {
2343 match = zebra_nhg_connected_ifindex(rn, match,
2344 nexthop->ifindex);
2345
2346 newhop = match->nhe->nhg.nexthop;
2347 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
2348 nexthop->type == NEXTHOP_TYPE_IPV6)
2349 nexthop->ifindex = newhop->ifindex;
2350 else if (nexthop->ifindex != newhop->ifindex) {
2351 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2352 zlog_debug(
2353 "%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
2354 __func__, nexthop, newhop);
2355 /*
2356 * NEXTHOP_TYPE_*_IFINDEX but ifindex
2357 * doesn't match what we found.
2358 */
2359 return 0;
2360 }
2361
2362 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2363 zlog_debug(
2364 "%s: CONNECT match %p (%pNG), newhop %pNHv",
2365 __func__, match, match->nhe, newhop);
2366
2367 return 1;
2368 } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
2369 struct nexthop_group *nhg;
2370 struct nexthop *resolver;
2371 struct backup_nh_map_s map = {};
2372
2373 resolved = 0;
2374
2375 /* Only useful if installed */
2376 if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
2377 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2378 zlog_debug(
2379 "%s: match %p (%pNG) not installed",
2380 __func__, match, match->nhe);
2381
2382 goto done_with_match;
2383 }
2384
2385 /* Examine installed nexthops; note that there
2386 * may not be any installed primary nexthops if
2387 * only backups are installed.
2388 */
2389 nhg = rib_get_fib_nhg(match);
2390 for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
2391 if (!nexthop_valid_resolve(nexthop, newhop))
2392 continue;
2393
2394 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2395 zlog_debug(
2396 "%s: RECURSIVE match %p (%pNG), newhop %pNHv",
2397 __func__, match, match->nhe,
2398 newhop);
2399
2400 SET_FLAG(nexthop->flags,
2401 NEXTHOP_FLAG_RECURSIVE);
2402 resolver = nexthop_set_resolved(afi, newhop,
2403 nexthop, NULL);
2404 resolved = 1;
2405
2406 /* If there are backup nexthops, capture
2407 * that info with the resolving nexthop.
2408 */
2409 if (resolver && newhop->backup_num > 0) {
2410 resolve_backup_nexthops(newhop,
2411 match->nhe,
2412 resolver, nhe,
2413 &map);
2414 }
2415 }
2416
2417 /* Examine installed backup nexthops, if any. There
2418 * are only installed backups *if* there is a
2419 * dedicated fib list. The UI can also control use
2420 * of backups for resolution.
2421 */
2422 nhg = rib_get_fib_backup_nhg(match);
2423 if (!use_recursive_backups ||
2424 nhg == NULL || nhg->nexthop == NULL)
2425 goto done_with_match;
2426
2427 for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
2428 if (!nexthop_valid_resolve(nexthop, newhop))
2429 continue;
2430
2431 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2432 zlog_debug(
2433 "%s: RECURSIVE match backup %p (%pNG), newhop %pNHv",
2434 __func__, match, match->nhe,
2435 newhop);
2436
2437 SET_FLAG(nexthop->flags,
2438 NEXTHOP_FLAG_RECURSIVE);
2439 nexthop_set_resolved(afi, newhop, nexthop,
2440 NULL);
2441 resolved = 1;
2442 }
2443
2444 done_with_match:
2445 /* Capture resolving mtu */
2446 if (resolved) {
2447 if (pmtu)
2448 *pmtu = match->mtu;
2449
2450 } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2451 zlog_debug(
2452 " %s: Recursion failed to find",
2453 __func__);
2454
2455 return resolved;
2456 } else {
2457 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
2458 zlog_debug(
2459 " %s: Route Type %s has not turned on recursion",
2460 __func__, zebra_route_string(type));
2461 if (type == ZEBRA_ROUTE_BGP
2462 && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
2463 zlog_debug(
2464 " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
2465 }
2466 return 0;
2467 }
2468 }
2469 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2470 zlog_debug(" %s: Nexthop did not lookup in table",
2471 __func__);
2472 return 0;
2473 }
2474
2475 /* This function verifies reachability of one given nexthop, which can be
2476 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
2477 * in nexthop->flags field. The nexthop->ifindex will be updated
2478 * appropriately as well.
2479 *
2480 * An existing route map can turn an otherwise active nexthop into inactive,
2481 * but not vice versa.
2482 *
2483 * The return value is the final value of 'ACTIVE' flag.
2484 */
2485 static unsigned nexthop_active_check(struct route_node *rn,
2486 struct route_entry *re,
2487 struct nexthop *nexthop,
2488 struct nhg_hash_entry *nhe)
2489 {
2490 route_map_result_t ret = RMAP_PERMITMATCH;
2491 afi_t family;
2492 const struct prefix *p, *src_p;
2493 struct zebra_vrf *zvrf;
2494 uint32_t mtu = 0;
2495 vrf_id_t vrf_id;
2496
2497 srcdest_rnode_prefixes(rn, &p, &src_p);
2498
2499 if (rn->p.family == AF_INET)
2500 family = AFI_IP;
2501 else if (rn->p.family == AF_INET6)
2502 family = AFI_IP6;
2503 else
2504 family = AF_UNSPEC;
2505
2506 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2507 zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
2508
2509 /*
2510 * If this is a kernel route, then if the interface is *up* then
2511 * by golly gee whiz it's a good route.
2512 */
2513 if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM) {
2514 struct interface *ifp;
2515
2516 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
2517
2518 if (ifp && (if_is_operative(ifp) || if_is_up(ifp))) {
2519 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2520 goto skip_check;
2521 }
2522 }
2523
2524 vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
2525 switch (nexthop->type) {
2526 case NEXTHOP_TYPE_IFINDEX:
2527 if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2528 &mtu, vrf_id))
2529 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2530 else
2531 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2532 break;
2533 case NEXTHOP_TYPE_IPV4:
2534 case NEXTHOP_TYPE_IPV4_IFINDEX:
2535 family = AFI_IP;
2536 if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2537 &mtu, vrf_id))
2538 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2539 else
2540 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2541 break;
2542 case NEXTHOP_TYPE_IPV6:
2543 family = AFI_IP6;
2544 if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2545 &mtu, vrf_id))
2546 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2547 else
2548 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2549 break;
2550 case NEXTHOP_TYPE_IPV6_IFINDEX:
2551 /* RFC 5549, v4 prefix with v6 NH */
2552 if (rn->p.family != AF_INET)
2553 family = AFI_IP6;
2554
2555 if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
2556 &mtu, vrf_id))
2557 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2558 else
2559 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2560 break;
2561 case NEXTHOP_TYPE_BLACKHOLE:
2562 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2563 break;
2564 default:
2565 break;
2566 }
2567
2568 skip_check:
2569
2570 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
2571 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2572 zlog_debug(" %s: Unable to find active nexthop",
2573 __func__);
2574 return 0;
2575 }
2576
2577 /* Capture recursive nexthop mtu.
2578 * TODO -- the code used to just reset the re's value to zero
2579 * for each nexthop, and then jam any resolving route's mtu value in,
2580 * whether or not that was zero, or lt/gt any existing value? The
2581 * way this is used appears to be as a floor value, so let's try
2582 * using it that way here.
2583 */
2584 if (mtu > 0) {
2585 if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu)
2586 re->nexthop_mtu = mtu;
2587 }
2588
2589 /* XXX: What exactly do those checks do? Do we support
2590 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
2591 */
2592 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
2593 || (family == AFI_IP6 && p->family != AF_INET6))
2594 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2595
2596 /* The original code didn't determine the family correctly
2597 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
2598 * from the rib_table_info in those cases.
2599 * Possibly it may be better to use only the rib_table_info
2600 * in every case.
2601 */
2602 if (family == 0) {
2603 struct rib_table_info *info;
2604
2605 info = srcdest_rnode_table_info(rn);
2606 family = info->afi;
2607 }
2608
2609 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
2610
2611 zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
2612 if (!zvrf) {
2613 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
2614 zlog_debug(" %s: zvrf is NULL", __func__);
2615 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2616 }
2617
2618 /* It'll get set if required inside */
2619 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
2620 zvrf, re->tag);
2621 if (ret == RMAP_DENYMATCH) {
2622 if (IS_ZEBRA_DEBUG_RIB) {
2623 zlog_debug(
2624 "%u:%pRN: Filtering out with NH out %s due to route map",
2625 re->vrf_id, rn,
2626 ifindex2ifname(nexthop->ifindex,
2627 nexthop->vrf_id));
2628 }
2629 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2630 }
2631 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2632 }
2633
2634 /* Helper function called after resolution to walk nhg rb trees
2635 * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop
2636 * is active on singleton NHEs.
2637 */
2638 static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe)
2639 {
2640 struct nhg_connected *rb_node_dep = NULL;
2641 bool valid = false;
2642
2643 if (!zebra_nhg_depends_is_empty(nhe)) {
2644 /* Is at least one depend valid? */
2645 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2646 if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe))
2647 valid = true;
2648 }
2649
2650 goto done;
2651 }
2652
2653 /* should be fully resolved singleton at this point */
2654 if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE))
2655 valid = true;
2656
2657 done:
2658 if (valid)
2659 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
2660
2661 return valid;
2662 }
2663
2664 /*
2665 * Process a list of nexthops, given an nhe, determining
2666 * whether each one is ACTIVE/installable at this time.
2667 */
2668 static uint32_t nexthop_list_active_update(struct route_node *rn,
2669 struct route_entry *re,
2670 struct nhg_hash_entry *nhe,
2671 bool is_backup)
2672 {
2673 union g_addr prev_src;
2674 unsigned int prev_active, new_active;
2675 ifindex_t prev_index;
2676 uint32_t counter = 0;
2677 struct nexthop *nexthop;
2678 struct nexthop_group *nhg = &nhe->nhg;
2679
2680 nexthop = nhg->nexthop;
2681
2682 /* Init recursive nh mtu */
2683 re->nexthop_mtu = 0;
2684
2685 /* Process nexthops one-by-one */
2686 for ( ; nexthop; nexthop = nexthop->next) {
2687
2688 /* No protocol daemon provides src and so we're skipping
2689 * tracking it
2690 */
2691 prev_src = nexthop->rmap_src;
2692 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
2693 prev_index = nexthop->ifindex;
2694
2695 /* Include the containing nhe for primary nexthops: if there's
2696 * recursive resolution, we capture the backup info also.
2697 */
2698 new_active =
2699 nexthop_active_check(rn, re, nexthop,
2700 (is_backup ? NULL : nhe));
2701
2702 /*
2703 * We need to respect the multipath_num here
2704 * as that what we should be able to install from
2705 * a multipath perspective should not be a data plane
2706 * decision point.
2707 */
2708 if (new_active && counter >= zrouter.multipath_num) {
2709 struct nexthop *nh;
2710
2711 /* Set it and its resolved nexthop as inactive. */
2712 for (nh = nexthop; nh; nh = nh->resolved)
2713 UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2714
2715 new_active = 0;
2716 }
2717
2718 if (new_active)
2719 counter++;
2720
2721 /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
2722 if (prev_active != new_active || prev_index != nexthop->ifindex
2723 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
2724 && nexthop->type < NEXTHOP_TYPE_IPV6)
2725 && prev_src.ipv4.s_addr
2726 != nexthop->rmap_src.ipv4.s_addr)
2727 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
2728 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
2729 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
2730 &nexthop->rmap_src.ipv6)))
2731 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
2732 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2733 }
2734
2735 return counter;
2736 }
2737
2738
2739 static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)
2740 {
2741 struct nexthop *nh;
2742 uint32_t curr_active = 0;
2743
2744 /* Assume all active for now */
2745
2746 for (nh = nhg->nexthop; nh; nh = nh->next) {
2747 SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
2748 curr_active++;
2749 }
2750
2751 return curr_active;
2752 }
2753
2754 /*
2755 * Iterate over all nexthops of the given RIB entry and refresh their
2756 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
2757 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
2758 *
2759 * Return value is the new number of active nexthops.
2760 */
2761 int nexthop_active_update(struct route_node *rn, struct route_entry *re)
2762 {
2763 struct nhg_hash_entry *curr_nhe;
2764 uint32_t curr_active = 0, backup_active = 0;
2765
2766 if (PROTO_OWNED(re->nhe))
2767 return proto_nhg_nexthop_active_update(&re->nhe->nhg);
2768
2769 afi_t rt_afi = family2afi(rn->p.family);
2770
2771 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
2772
2773 /* Make a local copy of the existing nhe, so we don't work on/modify
2774 * the shared nhe.
2775 */
2776 curr_nhe = zebra_nhe_copy(re->nhe, re->nhe->id);
2777
2778 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2779 zlog_debug("%s: re %p nhe %p (%pNG), curr_nhe %p", __func__, re,
2780 re->nhe, re->nhe, curr_nhe);
2781
2782 /* Clear the existing id, if any: this will avoid any confusion
2783 * if the id exists, and will also force the creation
2784 * of a new nhe reflecting the changes we may make in this local copy.
2785 */
2786 curr_nhe->id = 0;
2787
2788 /* Process nexthops */
2789 curr_active = nexthop_list_active_update(rn, re, curr_nhe, false);
2790
2791 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2792 zlog_debug("%s: re %p curr_active %u", __func__, re,
2793 curr_active);
2794
2795 /* If there are no backup nexthops, we are done */
2796 if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL)
2797 goto backups_done;
2798
2799 backup_active = nexthop_list_active_update(
2800 rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/);
2801
2802 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2803 zlog_debug("%s: re %p backup_active %u", __func__, re,
2804 backup_active);
2805
2806 backups_done:
2807
2808 /*
2809 * Ref or create an nhe that matches the current state of the
2810 * nexthop(s).
2811 */
2812 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
2813 struct nhg_hash_entry *new_nhe = NULL;
2814
2815 new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
2816
2817 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2818 zlog_debug(
2819 "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",
2820 __func__, re, re->nhe, re->nhe, new_nhe,
2821 new_nhe);
2822
2823 route_entry_update_nhe(re, new_nhe);
2824 }
2825
2826
2827 /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID
2828 * flag where appropriate.
2829 */
2830 if (curr_active)
2831 zebra_nhg_set_valid_if_active(re->nhe);
2832
2833 /*
2834 * Do not need the old / copied nhe anymore since it
2835 * was either copied over into a new nhe or not
2836 * used at all.
2837 */
2838 zebra_nhg_free(curr_nhe);
2839 return curr_active;
2840 }
2841
2842 /* Recursively construct a grp array of fully resolved IDs.
2843 *
2844 * This function allows us to account for groups within groups,
2845 * by converting them into a flat array of IDs.
2846 *
2847 * nh_grp is modified at every level of recursion to append
2848 * to it the next unique, fully resolved ID from the entire tree.
2849 *
2850 *
2851 * Note:
2852 * I'm pretty sure we only allow ONE level of group within group currently.
2853 * But making this recursive just in case that ever changes.
2854 */
2855 static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp,
2856 uint8_t curr_index,
2857 struct nhg_hash_entry *nhe,
2858 int max_num)
2859 {
2860 struct nhg_connected *rb_node_dep = NULL;
2861 struct nhg_hash_entry *depend = NULL;
2862 uint8_t i = curr_index;
2863
2864 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2865 bool duplicate = false;
2866
2867 if (i >= max_num)
2868 goto done;
2869
2870 depend = rb_node_dep->nhe;
2871
2872 /*
2873 * If its recursive, use its resolved nhe in the group
2874 */
2875 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
2876 depend = zebra_nhg_resolve(depend);
2877 if (!depend) {
2878 flog_err(
2879 EC_ZEBRA_NHG_FIB_UPDATE,
2880 "Failed to recursively resolve Nexthop Hash Entry in the group id=%pNG",
2881 nhe);
2882 continue;
2883 }
2884 }
2885
2886 if (!zebra_nhg_depends_is_empty(depend)) {
2887 /* This is a group within a group */
2888 i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num);
2889 } else {
2890 if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) {
2891 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2892 || IS_ZEBRA_DEBUG_NHG)
2893 zlog_debug(
2894 "%s: Nexthop ID (%u) not valid, not appending to dataplane install group",
2895 __func__, depend->id);
2896 continue;
2897 }
2898
2899 /* If the nexthop not installed/queued for install don't
2900 * put in the ID array.
2901 */
2902 if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED)
2903 || CHECK_FLAG(depend->flags,
2904 NEXTHOP_GROUP_QUEUED))) {
2905 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2906 || IS_ZEBRA_DEBUG_NHG)
2907 zlog_debug(
2908 "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group",
2909 __func__, depend->id);
2910 continue;
2911 }
2912
2913 /* Check for duplicate IDs, ignore if found. */
2914 for (int j = 0; j < i; j++) {
2915 if (depend->id == grp[j].id) {
2916 duplicate = true;
2917 break;
2918 }
2919 }
2920
2921 if (duplicate) {
2922 if (IS_ZEBRA_DEBUG_RIB_DETAILED
2923 || IS_ZEBRA_DEBUG_NHG)
2924 zlog_debug(
2925 "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group",
2926 __func__, depend->id);
2927 continue;
2928 }
2929
2930 grp[i].id = depend->id;
2931 grp[i].weight = depend->nhg.nexthop->weight;
2932 i++;
2933 }
2934 }
2935
2936 if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL)
2937 goto done;
2938
2939 /* TODO -- For now, we are not trying to use or install any
2940 * backup info in this nexthop-id path: we aren't prepared
2941 * to use the backups here yet. We're just debugging what we find.
2942 */
2943 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
2944 zlog_debug("%s: skipping backup nhe", __func__);
2945
2946 done:
2947 return i;
2948 }
2949
2950 /* Convert a nhe into a group array */
2951 uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
2952 int max_num)
2953 {
2954 /* Call into the recursive function */
2955 return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num);
2956 }
2957
2958 void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
2959 {
2960 struct nhg_connected *rb_node_dep = NULL;
2961
2962 /* Resolve it first */
2963 nhe = zebra_nhg_resolve(nhe);
2964
2965 /* Make sure all depends are installed/queued */
2966 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
2967 zebra_nhg_install_kernel(rb_node_dep->nhe);
2968 }
2969
2970 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)
2971 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
2972 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
2973 /* Change its type to us since we are installing it */
2974 if (!ZEBRA_NHG_CREATED(nhe))
2975 nhe->type = ZEBRA_ROUTE_NHG;
2976
2977 int ret = dplane_nexthop_add(nhe);
2978
2979 switch (ret) {
2980 case ZEBRA_DPLANE_REQUEST_QUEUED:
2981 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
2982 break;
2983 case ZEBRA_DPLANE_REQUEST_FAILURE:
2984 flog_err(
2985 EC_ZEBRA_DP_INSTALL_FAIL,
2986 "Failed to install Nexthop ID (%pNG) into the kernel",
2987 nhe);
2988 break;
2989 case ZEBRA_DPLANE_REQUEST_SUCCESS:
2990 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
2991 zebra_nhg_handle_install(nhe);
2992 break;
2993 }
2994 }
2995 }
2996
2997 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
2998 {
2999 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
3000 int ret = dplane_nexthop_delete(nhe);
3001
3002 switch (ret) {
3003 case ZEBRA_DPLANE_REQUEST_QUEUED:
3004 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
3005 break;
3006 case ZEBRA_DPLANE_REQUEST_FAILURE:
3007 flog_err(
3008 EC_ZEBRA_DP_DELETE_FAIL,
3009 "Failed to uninstall Nexthop ID (%pNG) from the kernel",
3010 nhe);
3011 break;
3012 case ZEBRA_DPLANE_REQUEST_SUCCESS:
3013 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3014 break;
3015 }
3016 }
3017
3018 zebra_nhg_handle_uninstall(nhe);
3019 }
3020
3021 void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
3022 {
3023 enum dplane_op_e op;
3024 enum zebra_dplane_result status;
3025 uint32_t id = 0;
3026 struct nhg_hash_entry *nhe = NULL;
3027
3028 op = dplane_ctx_get_op(ctx);
3029 status = dplane_ctx_get_status(ctx);
3030
3031 id = dplane_ctx_get_nhe_id(ctx);
3032
3033 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL)
3034 zlog_debug(
3035 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
3036 ctx, dplane_op2str(op), id, dplane_res2str(status));
3037
3038 switch (op) {
3039 case DPLANE_OP_NH_DELETE:
3040 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
3041 flog_err(
3042 EC_ZEBRA_DP_DELETE_FAIL,
3043 "Failed to uninstall Nexthop ID (%u) from the kernel",
3044 id);
3045
3046 /* We already free'd the data, nothing to do */
3047 break;
3048 case DPLANE_OP_NH_INSTALL:
3049 case DPLANE_OP_NH_UPDATE:
3050 nhe = zebra_nhg_lookup_id(id);
3051
3052 if (!nhe) {
3053 if (IS_ZEBRA_DEBUG_NHG)
3054 zlog_debug(
3055 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
3056 dplane_op2str(op), id);
3057
3058 break;
3059 }
3060
3061 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
3062 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
3063 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
3064 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3065 zebra_nhg_handle_install(nhe);
3066
3067 /* If daemon nhg, send it an update */
3068 if (PROTO_OWNED(nhe))
3069 zsend_nhg_notify(nhe->type, nhe->zapi_instance,
3070 nhe->zapi_session, nhe->id,
3071 ZAPI_NHG_INSTALLED);
3072 } else {
3073 /* If daemon nhg, send it an update */
3074 if (PROTO_OWNED(nhe))
3075 zsend_nhg_notify(nhe->type, nhe->zapi_instance,
3076 nhe->zapi_session, nhe->id,
3077 ZAPI_NHG_FAIL_INSTALL);
3078
3079 if (!(zebra_nhg_proto_nexthops_only() &&
3080 !PROTO_OWNED(nhe)))
3081 flog_err(
3082 EC_ZEBRA_DP_INSTALL_FAIL,
3083 "Failed to install Nexthop (%pNG) into the kernel",
3084 nhe);
3085 }
3086 break;
3087
3088 case DPLANE_OP_ROUTE_INSTALL:
3089 case DPLANE_OP_ROUTE_UPDATE:
3090 case DPLANE_OP_ROUTE_DELETE:
3091 case DPLANE_OP_ROUTE_NOTIFY:
3092 case DPLANE_OP_LSP_INSTALL:
3093 case DPLANE_OP_LSP_UPDATE:
3094 case DPLANE_OP_LSP_DELETE:
3095 case DPLANE_OP_LSP_NOTIFY:
3096 case DPLANE_OP_PW_INSTALL:
3097 case DPLANE_OP_PW_UNINSTALL:
3098 case DPLANE_OP_SYS_ROUTE_ADD:
3099 case DPLANE_OP_SYS_ROUTE_DELETE:
3100 case DPLANE_OP_ADDR_INSTALL:
3101 case DPLANE_OP_ADDR_UNINSTALL:
3102 case DPLANE_OP_MAC_INSTALL:
3103 case DPLANE_OP_MAC_DELETE:
3104 case DPLANE_OP_NEIGH_INSTALL:
3105 case DPLANE_OP_NEIGH_UPDATE:
3106 case DPLANE_OP_NEIGH_DELETE:
3107 case DPLANE_OP_NEIGH_IP_INSTALL:
3108 case DPLANE_OP_NEIGH_IP_DELETE:
3109 case DPLANE_OP_VTEP_ADD:
3110 case DPLANE_OP_VTEP_DELETE:
3111 case DPLANE_OP_RULE_ADD:
3112 case DPLANE_OP_RULE_DELETE:
3113 case DPLANE_OP_RULE_UPDATE:
3114 case DPLANE_OP_NEIGH_DISCOVER:
3115 case DPLANE_OP_BR_PORT_UPDATE:
3116 case DPLANE_OP_NONE:
3117 case DPLANE_OP_IPTABLE_ADD:
3118 case DPLANE_OP_IPTABLE_DELETE:
3119 case DPLANE_OP_IPSET_ADD:
3120 case DPLANE_OP_IPSET_DELETE:
3121 case DPLANE_OP_IPSET_ENTRY_ADD:
3122 case DPLANE_OP_IPSET_ENTRY_DELETE:
3123 case DPLANE_OP_NEIGH_TABLE_UPDATE:
3124 case DPLANE_OP_GRE_SET:
3125 case DPLANE_OP_INTF_ADDR_ADD:
3126 case DPLANE_OP_INTF_ADDR_DEL:
3127 case DPLANE_OP_INTF_NETCONFIG:
3128 case DPLANE_OP_INTF_INSTALL:
3129 case DPLANE_OP_INTF_UPDATE:
3130 case DPLANE_OP_INTF_DELETE:
3131 break;
3132 }
3133 }
3134
3135 static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
3136 {
3137 struct nhg_hash_entry *nhe = NULL;
3138
3139 nhe = (struct nhg_hash_entry *)bucket->data;
3140
3141 /*
3142 * same logic as with routes.
3143 *
3144 * If older than startup time, we know we read them in from the
3145 * kernel and have not gotten and update for them since startup
3146 * from an upper level proto.
3147 */
3148 if (zrouter.startup_time < nhe->uptime)
3149 return HASHWALK_CONTINUE;
3150
3151 /*
3152 * If it's proto-owned and not being used by a route, remove it since
3153 * we haven't gotten an update about it from the proto since startup.
3154 * This means that either the config for it was removed or the daemon
3155 * didn't get started. This handles graceful restart & retain scenario.
3156 */
3157 if (PROTO_OWNED(nhe) && nhe->refcnt == 1) {
3158 zebra_nhg_decrement_ref(nhe);
3159 return HASHWALK_ABORT;
3160 }
3161
3162 /*
3163 * If its being ref'd by routes, just let it be uninstalled via a route
3164 * removal.
3165 */
3166 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) {
3167 zebra_nhg_uninstall_kernel(nhe);
3168 return HASHWALK_ABORT;
3169 }
3170
3171 return HASHWALK_CONTINUE;
3172 }
3173
3174 void zebra_nhg_sweep_table(struct hash *hash)
3175 {
3176 uint32_t count;
3177
3178 /*
3179 * Yes this is extremely odd. Effectively nhg's have
3180 * other nexthop groups that depend on them and when you
3181 * remove them, you can have other entries blown up.
3182 * our hash code does not work with deleting multiple
3183 * entries at a time and will possibly cause crashes
3184 * So what to do? Whenever zebra_nhg_sweep_entry
3185 * deletes an entry it will return HASHWALK_ABORT,
3186 * cause that deletion might have triggered more.
3187 * then we can just keep sweeping this table
3188 * until nothing more is found to do.
3189 */
3190 do {
3191 count = hashcount(hash);
3192 hash_walk(hash, zebra_nhg_sweep_entry, NULL);
3193 } while (count != hashcount(hash));
3194 }
3195
3196 static void zebra_nhg_mark_keep_entry(struct hash_bucket *bucket, void *arg)
3197 {
3198 struct nhg_hash_entry *nhe = bucket->data;
3199
3200 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
3201 }
3202
3203 /*
3204 * When we are shutting down and we have retain mode enabled
3205 * in zebra the process is to mark each vrf that it's
3206 * routes should not be deleted. The problem with that
3207 * is that shutdown actually free's up memory which
3208 * causes the nexthop group's ref counts to go to zero
3209 * we need a way to subtly tell the system to not remove
3210 * the nexthop groups from the kernel at the same time.
3211 * The easiest just looks like that we should not mark
3212 * the nhg's as installed any more and when the ref count
3213 * goes to zero we'll attempt to delete and do nothing
3214 */
3215 void zebra_nhg_mark_keep(void)
3216 {
3217 hash_iterate(zrouter.nhgs_id, zebra_nhg_mark_keep_entry, NULL);
3218 }
3219
3220 /* Global control to disable use of kernel nexthops, if available. We can't
3221 * force the kernel to support nexthop ids, of course, but we can disable
3222 * zebra's use of them, for testing e.g. By default, if the kernel supports
3223 * nexthop ids, zebra uses them.
3224 */
3225 void zebra_nhg_enable_kernel_nexthops(bool set)
3226 {
3227 g_nexthops_enabled = set;
3228 }
3229
3230 bool zebra_nhg_kernel_nexthops_enabled(void)
3231 {
3232 return g_nexthops_enabled;
3233 }
3234
3235 /* Global control for use of activated backups for recursive resolution. */
3236 void zebra_nhg_set_recursive_use_backups(bool set)
3237 {
3238 use_recursive_backups = set;
3239 }
3240
3241 bool zebra_nhg_recursive_use_backups(void)
3242 {
3243 return use_recursive_backups;
3244 }
3245
3246 /*
3247 * Global control to only use kernel nexthops for protocol created NHGs.
3248 * There are some use cases where you may not want zebra to implicitly
3249 * create kernel nexthops for all routes and only create them for NHGs
3250 * passed down by upper level protos.
3251 *
3252 * Default is off.
3253 */
3254 void zebra_nhg_set_proto_nexthops_only(bool set)
3255 {
3256 proto_nexthops_only = set;
3257 }
3258
3259 bool zebra_nhg_proto_nexthops_only(void)
3260 {
3261 return proto_nexthops_only;
3262 }
3263
3264 /* Add NHE from upper level proto */
3265 struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
3266 uint16_t instance, uint32_t session,
3267 struct nexthop_group *nhg, afi_t afi)
3268 {
3269 struct nhg_hash_entry lookup;
3270 struct nhg_hash_entry *new, *old;
3271 struct nhg_connected *rb_node_dep = NULL;
3272 struct nexthop *newhop;
3273 bool replace = false;
3274
3275 if (!nhg->nexthop) {
3276 if (IS_ZEBRA_DEBUG_NHG)
3277 zlog_debug("%s: id %u, no nexthops passed to add",
3278 __func__, id);
3279 return NULL;
3280 }
3281
3282
3283 /* Set nexthop list as active, since they wont go through rib
3284 * processing.
3285 *
3286 * Assuming valid/onlink for now.
3287 *
3288 * Once resolution is figured out, we won't need this!
3289 */
3290 for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
3291 if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
3292 if (IS_ZEBRA_DEBUG_NHG)
3293 zlog_debug(
3294 "%s: id %u, backup nexthops not supported",
3295 __func__, id);
3296 return NULL;
3297 }
3298
3299 if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) {
3300 if (IS_ZEBRA_DEBUG_NHG)
3301 zlog_debug(
3302 "%s: id %u, blackhole nexthop not supported",
3303 __func__, id);
3304 return NULL;
3305 }
3306
3307 if (newhop->type == NEXTHOP_TYPE_IFINDEX) {
3308 if (IS_ZEBRA_DEBUG_NHG)
3309 zlog_debug(
3310 "%s: id %u, nexthop without gateway not supported",
3311 __func__, id);
3312 return NULL;
3313 }
3314
3315 if (!newhop->ifindex) {
3316 if (IS_ZEBRA_DEBUG_NHG)
3317 zlog_debug(
3318 "%s: id %u, nexthop without ifindex is not supported",
3319 __func__, id);
3320 return NULL;
3321 }
3322 SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE);
3323 }
3324
3325 zebra_nhe_init(&lookup, afi, nhg->nexthop);
3326 lookup.nhg.nexthop = nhg->nexthop;
3327 lookup.id = id;
3328 lookup.type = type;
3329
3330 old = zebra_nhg_lookup_id(id);
3331
3332 if (old) {
3333 /*
3334 * This is a replace, just release NHE from ID for now, The
3335 * depends/dependents may still be used in the replacement so
3336 * we don't touch them other than to remove their refs to their
3337 * old parent.
3338 */
3339 replace = true;
3340 hash_release(zrouter.nhgs_id, old);
3341
3342 /* Free all the things */
3343 zebra_nhg_release_all_deps(old);
3344 }
3345
3346 new = zebra_nhg_rib_find_nhe(&lookup, afi);
3347
3348 zebra_nhg_increment_ref(new);
3349
3350 /* Capture zapi client info */
3351 new->zapi_instance = instance;
3352 new->zapi_session = session;
3353
3354 zebra_nhg_set_valid_if_active(new);
3355
3356 zebra_nhg_install_kernel(new);
3357
3358 if (old) {
3359 /*
3360 * Check to handle recving DEL while routes still in use then
3361 * a replace.
3362 *
3363 * In this case we would have decremented the refcnt already
3364 * but set the FLAG here. Go ahead and increment once to fix
3365 * the misordering we have been sent.
3366 */
3367 if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED))
3368 zebra_nhg_increment_ref(old);
3369
3370 rib_handle_nhg_replace(old, new);
3371
3372 /* We have to decrement its singletons
3373 * because some might not exist in NEW.
3374 */
3375 if (!zebra_nhg_depends_is_empty(old)) {
3376 frr_each (nhg_connected_tree, &old->nhg_depends,
3377 rb_node_dep)
3378 zebra_nhg_decrement_ref(rb_node_dep->nhe);
3379 }
3380
3381 /* Dont call the dec API, we dont want to uninstall the ID */
3382 old->refcnt = 0;
3383 THREAD_OFF(old->timer);
3384 zebra_nhg_free(old);
3385 old = NULL;
3386 }
3387
3388 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3389 zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__,
3390 (replace ? "replaced" : "added"), new, new->id,
3391 new->vrf_id, zebra_route_string(new->type));
3392
3393 return new;
3394 }
3395
3396 /* Delete NHE from upper level proto, caller must decrement ref */
3397 struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id, int type)
3398 {
3399 struct nhg_hash_entry *nhe;
3400
3401 nhe = zebra_nhg_lookup_id(id);
3402
3403 if (!nhe) {
3404 if (IS_ZEBRA_DEBUG_NHG)
3405 zlog_debug("%s: id %u, lookup failed", __func__, id);
3406
3407 return NULL;
3408 }
3409
3410 if (type != nhe->type) {
3411 if (IS_ZEBRA_DEBUG_NHG)
3412 zlog_debug(
3413 "%s: id %u, type %s mismatch, sent by %s, ignoring",
3414 __func__, id, zebra_route_string(nhe->type),
3415 zebra_route_string(type));
3416 return NULL;
3417 }
3418
3419 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED)) {
3420 if (IS_ZEBRA_DEBUG_NHG)
3421 zlog_debug("%s: id %u, already released", __func__, id);
3422
3423 return NULL;
3424 }
3425
3426 SET_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED);
3427
3428 if (nhe->refcnt > 1) {
3429 if (IS_ZEBRA_DEBUG_NHG)
3430 zlog_debug(
3431 "%s: %pNG, still being used by routes refcnt %u",
3432 __func__, nhe, nhe->refcnt);
3433 return nhe;
3434 }
3435
3436 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3437 zlog_debug("%s: deleted nhe %p (%pNG), vrf %d, type %s",
3438 __func__, nhe, nhe, nhe->vrf_id,
3439 zebra_route_string(nhe->type));
3440
3441 return nhe;
3442 }
3443
3444 struct nhg_score_proto_iter {
3445 int type;
3446 struct list *found;
3447 };
3448
3449 static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
3450 {
3451 struct nhg_hash_entry *nhe;
3452 struct nhg_score_proto_iter *iter;
3453
3454 nhe = (struct nhg_hash_entry *)bucket->data;
3455 iter = arg;
3456
3457 /* Needs to match type and outside zebra ID space */
3458 if (nhe->type == iter->type && PROTO_OWNED(nhe)) {
3459 if (IS_ZEBRA_DEBUG_NHG_DETAIL)
3460 zlog_debug(
3461 "%s: found nhe %p (%pNG), vrf %d, type %s after client disconnect",
3462 __func__, nhe, nhe, nhe->vrf_id,
3463 zebra_route_string(nhe->type));
3464
3465 /* Add to removal list */
3466 listnode_add(iter->found, nhe);
3467 }
3468 }
3469
3470 /* Remove specific by proto NHGs */
3471 unsigned long zebra_nhg_score_proto(int type)
3472 {
3473 struct nhg_hash_entry *nhe;
3474 struct nhg_score_proto_iter iter = {};
3475 struct listnode *ln;
3476 unsigned long count;
3477
3478 iter.type = type;
3479 iter.found = list_new();
3480
3481 /* Find matching entries to remove */
3482 hash_iterate(zrouter.nhgs_id, zebra_nhg_score_proto_entry, &iter);
3483
3484 /* Now remove them */
3485 for (ALL_LIST_ELEMENTS_RO(iter.found, ln, nhe)) {
3486 /*
3487 * This should be the last ref if we remove client routes too,
3488 * and thus should remove and free them.
3489 */
3490 zebra_nhg_decrement_ref(nhe);
3491 }
3492
3493 count = iter.found->count;
3494 list_delete(&iter.found);
3495
3496 return count;
3497 }
3498
3499 printfrr_ext_autoreg_p("NG", printfrr_nhghe);
3500 static ssize_t printfrr_nhghe(struct fbuf *buf, struct printfrr_eargs *ea,
3501 const void *ptr)
3502 {
3503 const struct nhg_hash_entry *nhe = ptr;
3504 const struct nhg_connected *dep;
3505 ssize_t ret = 0;
3506
3507 if (!nhe)
3508 return bputs(buf, "[NULL]");
3509
3510 ret += bprintfrr(buf, "%u[", nhe->id);
3511 if (nhe->ifp)
3512 ret += printfrr_nhs(buf, nhe->nhg.nexthop);
3513 else {
3514 int count = zebra_nhg_depends_count(nhe);
3515
3516 frr_each (nhg_connected_tree_const, &nhe->nhg_depends, dep) {
3517 ret += bprintfrr(buf, "%u", dep->nhe->id);
3518 if (count > 1)
3519 ret += bputs(buf, "/");
3520 count--;
3521 }
3522 }
3523
3524 ret += bputs(buf, "]");
3525 return ret;
3526 }