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