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