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