]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_nhg.c
Merge pull request #4897 from sworleys/zebra_nhg_add
[mirror_frr.git] / zebra / zebra_nhg.c
1 /* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 * Stephen Worley
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23 #include <zebra.h>
24
25 #include "lib/nexthop.h"
26 #include "lib/nexthop_group_private.h"
27 #include "lib/routemap.h"
28 #include "lib/mpls.h"
29 #include "lib/jhash.h"
30 #include "lib/debug.h"
31
32 #include "zebra/connected.h"
33 #include "zebra/debug.h"
34 #include "zebra/zebra_router.h"
35 #include "zebra/zebra_nhg_private.h"
36 #include "zebra/zebra_rnh.h"
37 #include "zebra/zebra_routemap.h"
38 #include "zebra/zebra_memory.h"
39 #include "zebra/zserv.h"
40 #include "zebra/rt.h"
41 #include "zebra_errors.h"
42 #include "zebra_dplane.h"
43 #include "zebra/interface.h"
44
45 DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
46 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
47 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
48
49 /* id counter to keep in sync with kernel */
50 uint32_t id_counter;
51
52 static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi);
53 static void depends_add(struct nhg_connected_tree_head *head,
54 struct nhg_hash_entry *depend);
55 static struct nhg_hash_entry *
56 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
57 afi_t afi);
58 static struct nhg_hash_entry *
59 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
60 static void depends_decrement_free(struct nhg_connected_tree_head *head);
61
62
63 static void nhg_connected_free(struct nhg_connected *dep)
64 {
65 XFREE(MTYPE_NHG_CONNECTED, dep);
66 }
67
68 static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
69 {
70 struct nhg_connected *new = NULL;
71
72 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
73 new->nhe = nhe;
74
75 return new;
76 }
77
78 void nhg_connected_tree_free(struct nhg_connected_tree_head *head)
79 {
80 struct nhg_connected *rb_node_dep = NULL;
81
82 if (!nhg_connected_tree_is_empty(head)) {
83 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
84 nhg_connected_tree_del(head, rb_node_dep);
85 nhg_connected_free(rb_node_dep);
86 }
87 }
88 }
89
90 bool nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head)
91 {
92 return nhg_connected_tree_count(head) ? false : true;
93 }
94
95 struct nhg_connected *
96 nhg_connected_tree_root(struct nhg_connected_tree_head *head)
97 {
98 return nhg_connected_tree_first(head);
99 }
100
101 void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
102 struct nhg_hash_entry *depend)
103 {
104 struct nhg_connected lookup = {};
105 struct nhg_connected *remove = NULL;
106
107 lookup.nhe = depend;
108
109 /* Lookup to find the element, then remove it */
110 remove = nhg_connected_tree_find(head, &lookup);
111 remove = nhg_connected_tree_del(head, remove);
112
113 if (remove)
114 nhg_connected_free(remove);
115 }
116
117 void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
118 struct nhg_hash_entry *depend)
119 {
120 struct nhg_connected *new = NULL;
121
122 new = nhg_connected_new(depend);
123
124 if (new)
125 nhg_connected_tree_add(head, new);
126 }
127
128 static void
129 nhg_connected_tree_decrement_ref(struct nhg_connected_tree_head *head)
130 {
131 struct nhg_connected *rb_node_dep = NULL;
132
133 frr_each_safe(nhg_connected_tree, head, rb_node_dep) {
134 zebra_nhg_decrement_ref(rb_node_dep->nhe);
135 }
136 }
137
138 static void
139 nhg_connected_tree_increment_ref(struct nhg_connected_tree_head *head)
140 {
141 struct nhg_connected *rb_node_dep = NULL;
142
143 frr_each(nhg_connected_tree, head, rb_node_dep) {
144 zebra_nhg_increment_ref(rb_node_dep->nhe);
145 }
146 }
147
148 struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
149 {
150 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
151 && !zebra_nhg_depends_is_empty(nhe)) {
152 nhe = nhg_connected_tree_root(&nhe->nhg_depends)->nhe;
153 return zebra_nhg_resolve(nhe);
154 }
155
156 return nhe;
157 }
158
159 unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
160 {
161 return nhg_connected_tree_count(&nhe->nhg_depends);
162 }
163
164 bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
165 {
166 return nhg_connected_tree_is_empty(&nhe->nhg_depends);
167 }
168
169 static void zebra_nhg_depends_del(struct nhg_hash_entry *from,
170 struct nhg_hash_entry *depend)
171 {
172 nhg_connected_tree_del_nhe(&from->nhg_depends, depend);
173 }
174
175 static void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
176 {
177 nhg_connected_tree_init(&nhe->nhg_depends);
178 }
179
180 unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
181 {
182 return nhg_connected_tree_count(&nhe->nhg_dependents);
183 }
184
185
186 bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
187 {
188 return nhg_connected_tree_is_empty(&nhe->nhg_dependents);
189 }
190
191 static void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
192 struct nhg_hash_entry *dependent)
193 {
194 nhg_connected_tree_del_nhe(&from->nhg_dependents, dependent);
195 }
196
197 static void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
198 struct nhg_hash_entry *dependent)
199 {
200 nhg_connected_tree_add_nhe(&to->nhg_dependents, dependent);
201 }
202
203 static void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
204 {
205 nhg_connected_tree_init(&nhe->nhg_dependents);
206 }
207
208 /* Release this nhe from anything depending on it */
209 static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
210 {
211 struct nhg_connected *rb_node_dep = NULL;
212
213 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) {
214 zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
215 /* recheck validity of the dependent */
216 zebra_nhg_check_valid(rb_node_dep->nhe);
217 }
218 }
219
220 /* Release this nhe from anything that it depends on */
221 static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
222 {
223 if (!zebra_nhg_depends_is_empty(nhe)) {
224 struct nhg_connected *rb_node_dep = NULL;
225
226 frr_each_safe(nhg_connected_tree, &nhe->nhg_depends,
227 rb_node_dep) {
228 zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
229 }
230 }
231 }
232
233
234 struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
235 {
236 struct nhg_hash_entry lookup = {};
237
238 lookup.id = id;
239 return hash_lookup(zrouter.nhgs_id, &lookup);
240 }
241
242 static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
243 {
244 if (hash_lookup(zrouter.nhgs_id, nhe)) {
245 flog_err(
246 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
247 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
248 nhe->id);
249 return -1;
250 }
251
252 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
253
254 return 0;
255 }
256
257 static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
258 {
259 nhe->ifp = ifp;
260 if_nhg_dependents_add(ifp, nhe);
261 }
262
263 static void
264 zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
265 struct nhg_connected_tree_head nhg_depends)
266 {
267 struct nhg_connected *rb_node_dep = NULL;
268
269 /* This has been allocated higher above in the stack. Could probably
270 * re-allocate and free the old stuff but just using the same memory
271 * for now. Otherwise, their might be a time trade-off for repeated
272 * alloc/frees as startup.
273 */
274 nhe->nhg_depends = nhg_depends;
275
276 /* Attach backpointer to anything that it depends on */
277 zebra_nhg_dependents_init(nhe);
278 if (!zebra_nhg_depends_is_empty(nhe)) {
279 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
280 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
281 }
282 }
283
284 /* Add the ifp now if its not a group or recursive and has ifindex */
285 if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop
286 && nhe->nhg->nexthop->ifindex) {
287 struct interface *ifp = NULL;
288
289 ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
290 nhe->vrf_id);
291 if (ifp)
292 zebra_nhg_set_if(nhe, ifp);
293 else
294 flog_err(
295 EC_ZEBRA_IF_LOOKUP_FAILED,
296 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
297 nhe->nhg->nexthop->ifindex, nhe->vrf_id,
298 nhe->id);
299 }
300 }
301
302 static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy,
303 uint32_t id)
304 {
305 struct nhg_hash_entry *nhe;
306
307 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
308
309 nhe->id = id;
310
311 nhe->nhg = nexthop_group_new();
312 nexthop_group_copy(nhe->nhg, copy->nhg);
313
314 nhe->vrf_id = copy->vrf_id;
315 nhe->afi = copy->afi;
316 nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG;
317 nhe->refcnt = 0;
318 nhe->dplane_ref = zebra_router_get_next_sequence();
319
320 return nhe;
321 }
322
323 /* Allocation via hash handler */
324 static void *zebra_nhg_hash_alloc(void *arg)
325 {
326 struct nhg_hash_entry *nhe = NULL;
327 struct nhg_hash_entry *copy = arg;
328
329 nhe = zebra_nhg_copy(copy, copy->id);
330
331 /* Mark duplicate nexthops in a group at creation time. */
332 nexthop_group_mark_duplicates(nhe->nhg);
333
334 zebra_nhg_connect_depends(nhe, copy->nhg_depends);
335 zebra_nhg_insert_id(nhe);
336
337 return nhe;
338 }
339
340 uint32_t zebra_nhg_hash_key(const void *arg)
341 {
342 const struct nhg_hash_entry *nhe = arg;
343
344 uint32_t key = 0x5a351234;
345
346 key = jhash_3words(nhe->vrf_id, nhe->afi, nexthop_group_hash(nhe->nhg),
347 key);
348
349 return key;
350 }
351
352 uint32_t zebra_nhg_id_key(const void *arg)
353 {
354 const struct nhg_hash_entry *nhe = arg;
355
356 return nhe->id;
357 }
358
359 bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
360 {
361 const struct nhg_hash_entry *nhe1 = arg1;
362 const struct nhg_hash_entry *nhe2 = arg2;
363
364 /* No matter what if they equal IDs, assume equal */
365 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
366 return true;
367
368 if (nhe1->vrf_id != nhe2->vrf_id)
369 return false;
370
371 if (nhe1->afi != nhe2->afi)
372 return false;
373
374 if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
375 != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
376 return false;
377
378 if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg))
379 return false;
380
381 return true;
382 }
383
384 bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
385 {
386 const struct nhg_hash_entry *nhe1 = arg1;
387 const struct nhg_hash_entry *nhe2 = arg2;
388
389 return nhe1->id == nhe2->id;
390 }
391
392 static int zebra_nhg_process_grp(struct nexthop_group *nhg,
393 struct nhg_connected_tree_head *depends,
394 struct nh_grp *grp, uint8_t count)
395 {
396 nhg_connected_tree_init(depends);
397
398 for (int i = 0; i < count; i++) {
399 struct nhg_hash_entry *depend = NULL;
400 /* We do not care about nexthop_grp.weight at
401 * this time. But we should figure out
402 * how to adapt this to our code in
403 * the future.
404 */
405 depend = depends_find_id_add(depends, grp[i].id);
406
407 if (!depend) {
408 flog_err(
409 EC_ZEBRA_NHG_SYNC,
410 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
411 grp[i].id);
412 return -1;
413 }
414
415 /*
416 * If this is a nexthop with its own group
417 * dependencies, add them as well. Not sure its
418 * even possible to have a group within a group
419 * in the kernel.
420 */
421
422 copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL);
423 }
424
425 return 0;
426 }
427
428 static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
429 struct nexthop *nh, afi_t afi)
430 {
431 struct nhg_hash_entry *depend = NULL;
432 struct nexthop_group resolved_ng = {};
433
434 _nexthop_group_add_sorted(&resolved_ng, nh);
435
436 depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
437 depends_add(nhg_depends, depend);
438 }
439
440 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
441 struct nexthop_group *nhg,
442 struct nhg_connected_tree_head *nhg_depends,
443 vrf_id_t vrf_id, afi_t afi, int type)
444 {
445 struct nhg_hash_entry lookup = {};
446
447 uint32_t old_id_counter = id_counter;
448
449 bool created = false;
450 bool recursive = false;
451
452 /*
453 * If it has an id at this point, we must have gotten it from the kernel
454 */
455 lookup.id = id ? id : ++id_counter;
456
457 lookup.type = type ? type : ZEBRA_ROUTE_NHG;
458 lookup.nhg = nhg;
459
460 if (lookup.nhg->nexthop->next) {
461 /* Groups can have all vrfs and AF's in them */
462 lookup.afi = AFI_UNSPEC;
463 lookup.vrf_id = 0;
464 } else {
465 switch (lookup.nhg->nexthop->type) {
466 case (NEXTHOP_TYPE_IFINDEX):
467 case (NEXTHOP_TYPE_BLACKHOLE):
468 /*
469 * This switch case handles setting the afi different
470 * for ipv4/v6 routes. Ifindex/blackhole nexthop
471 * objects cannot be ambiguous, they must be Address
472 * Family specific. If we get here, we will either use
473 * the AF of the route, or the one we got passed from
474 * here from the kernel.
475 */
476 lookup.afi = afi;
477 break;
478 case (NEXTHOP_TYPE_IPV4_IFINDEX):
479 case (NEXTHOP_TYPE_IPV4):
480 lookup.afi = AFI_IP;
481 break;
482 case (NEXTHOP_TYPE_IPV6_IFINDEX):
483 case (NEXTHOP_TYPE_IPV6):
484 lookup.afi = AFI_IP6;
485 break;
486 }
487
488 lookup.vrf_id = vrf_id;
489 }
490
491 if (id)
492 (*nhe) = zebra_nhg_lookup_id(id);
493 else
494 (*nhe) = hash_lookup(zrouter.nhgs, &lookup);
495
496 /* If it found an nhe in our tables, this new ID is unused */
497 if (*nhe)
498 id_counter = old_id_counter;
499
500 if (!(*nhe)) {
501 /* Only hash/lookup the depends if the first lookup
502 * fails to find something. This should hopefully save a
503 * lot of cycles for larger ecmp sizes.
504 */
505 if (nhg_depends)
506 /* If you don't want to hash on each nexthop in the
507 * nexthop group struct you can pass the depends
508 * directly. Kernel-side we do this since it just looks
509 * them up via IDs.
510 */
511 lookup.nhg_depends = *nhg_depends;
512 else {
513 if (nhg->nexthop->next) {
514 zebra_nhg_depends_init(&lookup);
515
516 /* If its a group, create a dependency tree */
517 struct nexthop *nh = NULL;
518
519 for (nh = nhg->nexthop; nh; nh = nh->next)
520 depends_find_add(&lookup.nhg_depends,
521 nh, afi);
522 } else if (CHECK_FLAG(nhg->nexthop->flags,
523 NEXTHOP_FLAG_RECURSIVE)) {
524 zebra_nhg_depends_init(&lookup);
525 handle_recursive_depend(&lookup.nhg_depends,
526 nhg->nexthop->resolved,
527 afi);
528 recursive = true;
529 }
530 }
531
532 (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
533 created = true;
534
535 if (recursive)
536 SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
537 }
538 return created;
539 }
540
541 /* Find/create a single nexthop */
542 static struct nhg_hash_entry *
543 zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
544 {
545 struct nhg_hash_entry *nhe = NULL;
546 struct nexthop_group nhg = {};
547
548 _nexthop_group_add_sorted(&nhg, nh);
549
550 zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0);
551
552 return nhe;
553 }
554
555 static struct nhg_ctx *nhg_ctx_new()
556 {
557 struct nhg_ctx *new = NULL;
558
559 new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
560
561 return new;
562 }
563
564 static void nhg_ctx_free(struct nhg_ctx *ctx)
565 {
566 XFREE(MTYPE_NHG_CTX, ctx);
567 }
568
569 static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx)
570 {
571 return ctx->id;
572 }
573
574 static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_status status)
575 {
576 ctx->status = status;
577 }
578
579 static enum nhg_ctx_status nhg_ctx_get_status(const struct nhg_ctx *ctx)
580 {
581 return ctx->status;
582 }
583
584 static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
585 {
586 ctx->op = op;
587 }
588
589 static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
590 {
591 return ctx->op;
592 }
593
594 static vrf_id_t nhg_ctx_get_vrf_id(const struct nhg_ctx *ctx)
595 {
596 return ctx->vrf_id;
597 }
598
599 static int nhg_ctx_get_type(const struct nhg_ctx *ctx)
600 {
601 return ctx->type;
602 }
603
604 static int nhg_ctx_get_afi(const struct nhg_ctx *ctx)
605 {
606 return ctx->afi;
607 }
608
609 static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx)
610 {
611 return &ctx->u.nh;
612 }
613
614 static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx)
615 {
616 return ctx->count;
617 }
618
619 static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
620 {
621 return ctx->u.grp;
622 }
623
624 static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
625 struct nh_grp *grp, vrf_id_t vrf_id,
626 afi_t afi, int type, uint8_t count)
627 {
628 struct nhg_ctx *ctx = NULL;
629
630 ctx = nhg_ctx_new();
631
632 ctx->id = id;
633 ctx->vrf_id = vrf_id;
634 ctx->afi = afi;
635 ctx->type = type;
636 ctx->count = count;
637
638 if (count)
639 /* Copy over the array */
640 memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
641 else if (nh)
642 ctx->u.nh = *nh;
643
644 return ctx;
645 }
646
647 static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
648 {
649 struct nhg_connected *rb_node_dep = NULL;
650
651 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
652 if (CHECK_FLAG(rb_node_dep->nhe->flags,
653 NEXTHOP_GROUP_UNHASHABLE))
654 return true;
655 }
656
657 return false;
658 }
659
660 static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
661 {
662 SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
663 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
664
665 flog_warn(
666 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
667 "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
668 nhe->id);
669 }
670
671 static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
672 {
673 struct nhg_connected *rb_node_dep;
674
675 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
676
677 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
678 zebra_nhg_set_valid(rb_node_dep->nhe);
679 }
680
681 static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
682 {
683 struct nhg_connected *rb_node_dep;
684
685 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
686
687 /* Update validity of nexthops depending on it */
688 frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
689 zebra_nhg_check_valid(rb_node_dep->nhe);
690 }
691
692 void zebra_nhg_check_valid(struct nhg_hash_entry *nhe)
693 {
694 struct nhg_connected *rb_node_dep = NULL;
695 bool valid = false;
696
697 /* If anthing else in the group is valid, the group is valid */
698 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
699 if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) {
700 valid = true;
701 goto done;
702 }
703 }
704
705 done:
706 if (valid)
707 zebra_nhg_set_valid(nhe);
708 else
709 zebra_nhg_set_invalid(nhe);
710 }
711
712
713 static void zebra_nhg_release(struct nhg_hash_entry *nhe)
714 {
715 /* Remove it from any lists it may be on */
716 zebra_nhg_depends_release(nhe);
717 zebra_nhg_dependents_release(nhe);
718 if (nhe->ifp)
719 if_nhg_dependents_del(nhe->ifp, nhe);
720
721 /*
722 * If its unhashable, we didn't store it here and have to be
723 * sure we don't clear one thats actually being used.
724 */
725 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
726 hash_release(zrouter.nhgs, nhe);
727
728 hash_release(zrouter.nhgs_id, nhe);
729 }
730
731 static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe)
732 {
733 zebra_nhg_release(nhe);
734 zebra_nhg_free(nhe);
735 }
736
737 static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe)
738 {
739 /* Update validity of groups depending on it */
740 struct nhg_connected *rb_node_dep;
741
742 frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
743 zebra_nhg_set_valid(rb_node_dep->nhe);
744 }
745
746 /*
747 * The kernel/other program has changed the state of a nexthop object we are
748 * using.
749 */
750 static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe,
751 bool is_delete)
752 {
753 if (nhe->refcnt) {
754 flog_err(
755 EC_ZEBRA_NHG_SYNC,
756 "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
757 (is_delete ? "deleted" : "updated"), nhe->id);
758
759 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
760 zebra_nhg_install_kernel(nhe);
761 } else
762 zebra_nhg_handle_uninstall(nhe);
763 }
764
765 static int nhg_ctx_process_new(struct nhg_ctx *ctx)
766 {
767 struct nexthop_group *nhg = NULL;
768 struct nhg_connected_tree_head nhg_depends = {};
769 struct nhg_hash_entry *lookup = NULL;
770 struct nhg_hash_entry *nhe = NULL;
771
772 uint32_t id = nhg_ctx_get_id(ctx);
773 uint8_t count = nhg_ctx_get_count(ctx);
774 vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx);
775 int type = nhg_ctx_get_type(ctx);
776 afi_t afi = nhg_ctx_get_afi(ctx);
777
778 lookup = zebra_nhg_lookup_id(id);
779
780 if (lookup) {
781 /* This is already present in our table, hence an update
782 * that we did not initate.
783 */
784 zebra_nhg_handle_kernel_state_change(lookup, false);
785 return 0;
786 }
787
788 if (nhg_ctx_get_count(ctx)) {
789 nhg = nexthop_group_new();
790 if (zebra_nhg_process_grp(nhg, &nhg_depends,
791 nhg_ctx_get_grp(ctx), count)) {
792 depends_decrement_free(&nhg_depends);
793 nexthop_group_delete(&nhg);
794 return -ENOENT;
795 }
796
797 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
798 afi))
799 depends_decrement_free(&nhg_depends);
800
801 /* These got copied over in zebra_nhg_alloc() */
802 nexthop_group_delete(&nhg);
803 } else
804 nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
805 type);
806
807 if (nhe) {
808 if (id != nhe->id) {
809 struct nhg_hash_entry *kernel_nhe = NULL;
810
811 /* Duplicate but with different ID from
812 * the kernel
813 */
814
815 /* The kernel allows duplicate nexthops
816 * as long as they have different IDs.
817 * We are ignoring those to prevent
818 * syncing problems with the kernel
819 * changes.
820 *
821 * We maintain them *ONLY* in the ID hash table to
822 * track them and set the flag to indicated
823 * their attributes are unhashable.
824 */
825
826 kernel_nhe = zebra_nhg_copy(nhe, id);
827 zebra_nhg_insert_id(kernel_nhe);
828 zebra_nhg_set_unhashable(kernel_nhe);
829 } else if (zebra_nhg_contains_unhashable(nhe)) {
830 /* The group we got contains an unhashable/duplicated
831 * depend, so lets mark this group as unhashable as well
832 * and release it from the non-ID hash.
833 */
834 hash_release(zrouter.nhgs, nhe);
835 zebra_nhg_set_unhashable(nhe);
836 } else {
837 /* It actually created a new nhe */
838 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
839 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
840 }
841 } else {
842 flog_err(
843 EC_ZEBRA_TABLE_LOOKUP_FAILED,
844 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
845 id);
846 return -1;
847 }
848
849 return 0;
850 }
851
852 static int nhg_ctx_process_del(struct nhg_ctx *ctx)
853 {
854 struct nhg_hash_entry *nhe = NULL;
855 uint32_t id = nhg_ctx_get_id(ctx);
856
857 nhe = zebra_nhg_lookup_id(id);
858
859 if (!nhe) {
860 flog_warn(
861 EC_ZEBRA_BAD_NHG_MESSAGE,
862 "Kernel delete message received for nexthop group ID (%u) that we do not have in our ID table",
863 id);
864 return -1;
865 }
866
867 zebra_nhg_handle_kernel_state_change(nhe, true);
868
869 return 0;
870 }
871
872 static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
873 {
874 struct nexthop *nh;
875
876 /*
877 * Just freeing for now, maybe do something more in the future
878 * based on flag.
879 */
880
881 if (nhg_ctx_get_count(ctx))
882 goto done;
883
884 nh = nhg_ctx_get_nh(ctx);
885
886 nexthop_del_labels(nh);
887
888 done:
889 if (ctx)
890 nhg_ctx_free(ctx);
891 }
892
893 static int queue_add(struct nhg_ctx *ctx)
894 {
895 /* If its queued or already processed do nothing */
896 if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
897 return 0;
898
899 if (rib_queue_nhg_add(ctx)) {
900 nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
901 return -1;
902 }
903
904 nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
905
906 return 0;
907 }
908
909 int nhg_ctx_process(struct nhg_ctx *ctx)
910 {
911 int ret = 0;
912
913 switch (nhg_ctx_get_op(ctx)) {
914 case NHG_CTX_OP_NEW:
915 ret = nhg_ctx_process_new(ctx);
916 if (nhg_ctx_get_count(ctx) && ret == -ENOENT
917 && nhg_ctx_get_status(ctx) != NHG_CTX_REQUEUED) {
918 /**
919 * We have entered a situation where we are
920 * processing a group from the kernel
921 * that has a contained nexthop which
922 * we have not yet processed.
923 *
924 * Re-enqueue this ctx to be handled exactly one
925 * more time (indicated by the flag).
926 *
927 * By the time we get back to it, we
928 * should have processed its depends.
929 */
930 nhg_ctx_set_status(ctx, NHG_CTX_NONE);
931 if (queue_add(ctx) == 0) {
932 nhg_ctx_set_status(ctx, NHG_CTX_REQUEUED);
933 return 0;
934 }
935 }
936 break;
937 case NHG_CTX_OP_DEL:
938 ret = nhg_ctx_process_del(ctx);
939 case NHG_CTX_OP_NONE:
940 break;
941 }
942
943 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
944
945 nhg_ctx_process_finish(ctx);
946
947 return ret;
948 }
949
950 /* Kernel-side, you either get a single new nexthop or a array of ID's */
951 int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
952 uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
953 int startup)
954 {
955 struct nhg_ctx *ctx = NULL;
956
957 if (id > id_counter)
958 /* Increase our counter so we don't try to create
959 * an ID that already exists
960 */
961 id_counter = id;
962
963 ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
964 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
965
966 /* Under statup conditions, we need to handle them immediately
967 * like we do for routes. Otherwise, we are going to get a route
968 * with a nhe_id that we have not handled.
969 */
970 if (startup)
971 return nhg_ctx_process(ctx);
972
973 if (queue_add(ctx)) {
974 nhg_ctx_process_finish(ctx);
975 return -1;
976 }
977
978 return 0;
979 }
980
981 /* Kernel-side, received delete message */
982 int zebra_nhg_kernel_del(uint32_t id)
983 {
984 struct nhg_ctx *ctx = NULL;
985
986 ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
987
988 nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
989
990 if (queue_add(ctx)) {
991 nhg_ctx_process_finish(ctx);
992 return -1;
993 }
994
995 return 0;
996 }
997
998 /* Some dependency helper functions */
999 static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
1000 {
1001 struct nexthop *lookup = NULL;
1002 struct nhg_hash_entry *nhe = NULL;
1003
1004 copy_nexthops(&lookup, nh, NULL);
1005
1006 /* Clear it, in case its a group */
1007 nexthops_free(lookup->next);
1008 nexthops_free(lookup->prev);
1009 lookup->next = NULL;
1010 lookup->prev = NULL;
1011
1012 nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
1013
1014 nexthops_free(lookup);
1015
1016 return nhe;
1017 }
1018
1019 static void depends_add(struct nhg_connected_tree_head *head,
1020 struct nhg_hash_entry *depend)
1021 {
1022 nhg_connected_tree_add_nhe(head, depend);
1023 zebra_nhg_increment_ref(depend);
1024 }
1025
1026 static struct nhg_hash_entry *
1027 depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
1028 afi_t afi)
1029 {
1030 struct nhg_hash_entry *depend = NULL;
1031
1032 depend = depends_find(nh, afi);
1033
1034 if (depend)
1035 depends_add(head, depend);
1036
1037 return depend;
1038 }
1039
1040 static struct nhg_hash_entry *
1041 depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id)
1042 {
1043 struct nhg_hash_entry *depend = NULL;
1044
1045 depend = zebra_nhg_lookup_id(id);
1046
1047 if (depend)
1048 depends_add(head, depend);
1049
1050 return depend;
1051 }
1052
1053 static void depends_decrement_free(struct nhg_connected_tree_head *head)
1054 {
1055 nhg_connected_tree_decrement_ref(head);
1056 nhg_connected_tree_free(head);
1057 }
1058
1059 /* Rib-side, you get a nexthop group struct */
1060 struct nhg_hash_entry *
1061 zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
1062 {
1063 struct nhg_hash_entry *nhe = NULL;
1064
1065 if (!(nhg && nhg->nexthop)) {
1066 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
1067 "No nexthop passed to %s", __func__);
1068 return NULL;
1069 }
1070
1071 zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
1072
1073 return nhe;
1074 }
1075
1076 static void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
1077 {
1078 nexthop_group_delete(&nhe->nhg);
1079 /* Decrement to remove connection ref */
1080 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1081 nhg_connected_tree_free(&nhe->nhg_depends);
1082 nhg_connected_tree_free(&nhe->nhg_dependents);
1083 }
1084
1085 void zebra_nhg_free(void *arg)
1086 {
1087 struct nhg_hash_entry *nhe = NULL;
1088
1089 nhe = (struct nhg_hash_entry *)arg;
1090
1091 if (nhe->refcnt)
1092 zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
1093
1094 zebra_nhg_free_members(nhe);
1095
1096 XFREE(MTYPE_NHG, nhe);
1097 }
1098
1099 void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
1100 {
1101 nhe->refcnt--;
1102
1103 if (!zebra_nhg_depends_is_empty(nhe))
1104 nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
1105
1106 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1107 zebra_nhg_uninstall_kernel(nhe);
1108 }
1109
1110 void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
1111 {
1112 nhe->refcnt++;
1113
1114 if (!zebra_nhg_depends_is_empty(nhe))
1115 nhg_connected_tree_increment_ref(&nhe->nhg_depends);
1116 }
1117
1118 static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
1119 struct nexthop *nexthop)
1120 {
1121 struct nexthop *resolved_hop;
1122 uint8_t num_labels = 0;
1123 mpls_label_t labels[MPLS_MAX_LABELS];
1124 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
1125 int i = 0;
1126
1127 resolved_hop = nexthop_new();
1128 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
1129
1130 resolved_hop->vrf_id = nexthop->vrf_id;
1131 switch (newhop->type) {
1132 case NEXTHOP_TYPE_IPV4:
1133 case NEXTHOP_TYPE_IPV4_IFINDEX:
1134 /* If the resolving route specifies a gateway, use it */
1135 resolved_hop->type = newhop->type;
1136 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
1137
1138 if (newhop->ifindex) {
1139 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1140 resolved_hop->ifindex = newhop->ifindex;
1141 }
1142 break;
1143 case NEXTHOP_TYPE_IPV6:
1144 case NEXTHOP_TYPE_IPV6_IFINDEX:
1145 resolved_hop->type = newhop->type;
1146 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
1147
1148 if (newhop->ifindex) {
1149 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1150 resolved_hop->ifindex = newhop->ifindex;
1151 }
1152 break;
1153 case NEXTHOP_TYPE_IFINDEX:
1154 /* If the resolving route is an interface route,
1155 * it means the gateway we are looking up is connected
1156 * to that interface. (The actual network is _not_ onlink).
1157 * Therefore, the resolved route should have the original
1158 * gateway as nexthop as it is directly connected.
1159 *
1160 * On Linux, we have to set the onlink netlink flag because
1161 * otherwise, the kernel won't accept the route.
1162 */
1163 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1164 if (afi == AFI_IP) {
1165 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
1166 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
1167 } else if (afi == AFI_IP6) {
1168 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
1169 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
1170 }
1171 resolved_hop->ifindex = newhop->ifindex;
1172 break;
1173 case NEXTHOP_TYPE_BLACKHOLE:
1174 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
1175 resolved_hop->bh_type = newhop->bh_type;
1176 break;
1177 }
1178
1179 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
1180 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
1181
1182 /* Copy labels of the resolved route and the parent resolving to it */
1183 if (newhop->nh_label) {
1184 for (i = 0; i < newhop->nh_label->num_labels; i++)
1185 labels[num_labels++] = newhop->nh_label->label[i];
1186 label_type = newhop->nh_label_type;
1187 }
1188
1189 if (nexthop->nh_label) {
1190 for (i = 0; i < nexthop->nh_label->num_labels; i++)
1191 labels[num_labels++] = nexthop->nh_label->label[i];
1192
1193 /* If the parent has labels, use its type */
1194 label_type = nexthop->nh_label_type;
1195 }
1196
1197 if (num_labels)
1198 nexthop_add_labels(resolved_hop, label_type, num_labels,
1199 labels);
1200
1201 resolved_hop->rparent = nexthop;
1202 _nexthop_add(&nexthop->resolved, resolved_hop);
1203 }
1204
1205 /* Checks if nexthop we are trying to resolve to is valid */
1206 static bool nexthop_valid_resolve(const struct nexthop *nexthop,
1207 const struct nexthop *resolved)
1208 {
1209 /* Can't resolve to a recursive nexthop */
1210 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
1211 return false;
1212
1213 switch (nexthop->type) {
1214 case NEXTHOP_TYPE_IPV4_IFINDEX:
1215 case NEXTHOP_TYPE_IPV6_IFINDEX:
1216 /* If the nexthop we are resolving to does not match the
1217 * ifindex for the nexthop the route wanted, its not valid.
1218 */
1219 if (nexthop->ifindex != resolved->ifindex)
1220 return false;
1221 break;
1222 case NEXTHOP_TYPE_IPV4:
1223 case NEXTHOP_TYPE_IPV6:
1224 case NEXTHOP_TYPE_IFINDEX:
1225 case NEXTHOP_TYPE_BLACKHOLE:
1226 break;
1227 }
1228
1229 return true;
1230 }
1231
1232 /*
1233 * Given a nexthop we need to properly recursively resolve
1234 * the route. As such, do a table lookup to find and match
1235 * if at all possible. Set the nexthop->ifindex and resolved_id
1236 * as appropriate
1237 */
1238 static int nexthop_active(afi_t afi, struct route_entry *re,
1239 struct nexthop *nexthop, struct route_node *top)
1240 {
1241 struct prefix p;
1242 struct route_table *table;
1243 struct route_node *rn;
1244 struct route_entry *match = NULL;
1245 int resolved;
1246 struct nexthop *newhop;
1247 struct interface *ifp;
1248 rib_dest_t *dest;
1249 struct zebra_vrf *zvrf;
1250
1251 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
1252 || nexthop->type == NEXTHOP_TYPE_IPV6)
1253 nexthop->ifindex = 0;
1254
1255
1256 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
1257 nexthops_free(nexthop->resolved);
1258 nexthop->resolved = NULL;
1259 re->nexthop_mtu = 0;
1260
1261 /*
1262 * If the kernel has sent us a NEW route, then
1263 * by golly gee whiz it's a good route.
1264 *
1265 * If its an already INSTALLED route we have already handled, then the
1266 * kernel route's nexthop might have became unreachable
1267 * and we have to handle that.
1268 */
1269 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
1270 && (re->type == ZEBRA_ROUTE_KERNEL
1271 || re->type == ZEBRA_ROUTE_SYSTEM))
1272 return 1;
1273
1274 /*
1275 * Check to see if we should trust the passed in information
1276 * for UNNUMBERED interfaces as that we won't find the GW
1277 * address in the routing table.
1278 * This check should suffice to handle IPv4 or IPv6 routes
1279 * sourced from EVPN routes which are installed with the
1280 * next hop as the remote VTEP IP.
1281 */
1282 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
1283 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1284 if (!ifp) {
1285 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1286 zlog_debug(
1287 "\t%s: Onlink and interface: %u[%u] does not exist",
1288 __PRETTY_FUNCTION__, nexthop->ifindex,
1289 nexthop->vrf_id);
1290 return 0;
1291 }
1292 if (connected_is_unnumbered(ifp)) {
1293 if (if_is_operative(ifp))
1294 return 1;
1295
1296 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1297 zlog_debug(
1298 "\t%s: Onlink and interface %s is not operative",
1299 __PRETTY_FUNCTION__, ifp->name);
1300 return 0;
1301 }
1302 if (!if_is_operative(ifp)) {
1303 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1304 zlog_debug(
1305 "\t%s: Interface %s is not unnumbered",
1306 __PRETTY_FUNCTION__, ifp->name);
1307 return 0;
1308 }
1309 }
1310
1311 /* Make lookup prefix. */
1312 memset(&p, 0, sizeof(struct prefix));
1313 switch (afi) {
1314 case AFI_IP:
1315 p.family = AF_INET;
1316 p.prefixlen = IPV4_MAX_PREFIXLEN;
1317 p.u.prefix4 = nexthop->gate.ipv4;
1318 break;
1319 case AFI_IP6:
1320 p.family = AF_INET6;
1321 p.prefixlen = IPV6_MAX_PREFIXLEN;
1322 p.u.prefix6 = nexthop->gate.ipv6;
1323 break;
1324 default:
1325 assert(afi != AFI_IP && afi != AFI_IP6);
1326 break;
1327 }
1328 /* Lookup table. */
1329 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
1330 /* get zvrf */
1331 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1332 if (!table || !zvrf) {
1333 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1334 zlog_debug("\t%s: Table not found",
1335 __PRETTY_FUNCTION__);
1336 return 0;
1337 }
1338
1339 rn = route_node_match(table, (struct prefix *)&p);
1340 while (rn) {
1341 route_unlock_node(rn);
1342
1343 /* Lookup should halt if we've matched against ourselves ('top',
1344 * if specified) - i.e., we cannot have a nexthop NH1 is
1345 * resolved by a route NH1. The exception is if the route is a
1346 * host route.
1347 */
1348 if (top && rn == top)
1349 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
1350 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
1351 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1352 zlog_debug(
1353 "\t%s: Matched against ourself and prefix length is not max bit length",
1354 __PRETTY_FUNCTION__);
1355 return 0;
1356 }
1357
1358 /* Pick up selected route. */
1359 /* However, do not resolve over default route unless explicitly
1360 * allowed.
1361 */
1362 if (is_default_prefix(&rn->p)
1363 && !rnh_resolve_via_default(zvrf, p.family)) {
1364 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1365 zlog_debug(
1366 "\t:%s: Resolved against default route",
1367 __PRETTY_FUNCTION__);
1368 return 0;
1369 }
1370
1371 dest = rib_dest_from_rnode(rn);
1372 if (dest && dest->selected_fib
1373 && !CHECK_FLAG(dest->selected_fib->status,
1374 ROUTE_ENTRY_REMOVED)
1375 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
1376 match = dest->selected_fib;
1377
1378 /* If there is no selected route or matched route is EGP, go up
1379 * tree.
1380 */
1381 if (!match) {
1382 do {
1383 rn = rn->parent;
1384 } while (rn && rn->info == NULL);
1385 if (rn)
1386 route_lock_node(rn);
1387
1388 continue;
1389 }
1390
1391 if (match->type == ZEBRA_ROUTE_CONNECT) {
1392 /* Directly point connected route. */
1393 newhop = match->ng->nexthop;
1394 if (newhop) {
1395 if (nexthop->type == NEXTHOP_TYPE_IPV4
1396 || nexthop->type == NEXTHOP_TYPE_IPV6)
1397 nexthop->ifindex = newhop->ifindex;
1398 }
1399 return 1;
1400 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
1401 resolved = 0;
1402 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
1403 if (!CHECK_FLAG(match->status,
1404 ROUTE_ENTRY_INSTALLED))
1405 continue;
1406 if (!nexthop_valid_resolve(nexthop, newhop))
1407 continue;
1408
1409 SET_FLAG(nexthop->flags,
1410 NEXTHOP_FLAG_RECURSIVE);
1411 nexthop_set_resolved(afi, newhop, nexthop);
1412 resolved = 1;
1413 }
1414 if (resolved)
1415 re->nexthop_mtu = match->mtu;
1416
1417 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1418 zlog_debug("\t%s: Recursion failed to find",
1419 __PRETTY_FUNCTION__);
1420 return resolved;
1421 } else if (re->type == ZEBRA_ROUTE_STATIC) {
1422 resolved = 0;
1423 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
1424 if (!CHECK_FLAG(match->status,
1425 ROUTE_ENTRY_INSTALLED))
1426 continue;
1427 if (!nexthop_valid_resolve(nexthop, newhop))
1428 continue;
1429
1430 SET_FLAG(nexthop->flags,
1431 NEXTHOP_FLAG_RECURSIVE);
1432 nexthop_set_resolved(afi, newhop, nexthop);
1433 resolved = 1;
1434 }
1435 if (resolved)
1436 re->nexthop_mtu = match->mtu;
1437
1438 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1439 zlog_debug(
1440 "\t%s: Static route unable to resolve",
1441 __PRETTY_FUNCTION__);
1442 return resolved;
1443 } else {
1444 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
1445 zlog_debug(
1446 "\t%s: Route Type %s has not turned on recursion",
1447 __PRETTY_FUNCTION__,
1448 zebra_route_string(re->type));
1449 if (re->type == ZEBRA_ROUTE_BGP
1450 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
1451 zlog_debug(
1452 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1453 }
1454 return 0;
1455 }
1456 }
1457 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1458 zlog_debug("\t%s: Nexthop did not lookup in table",
1459 __PRETTY_FUNCTION__);
1460 return 0;
1461 }
1462
1463 /* This function verifies reachability of one given nexthop, which can be
1464 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1465 * in nexthop->flags field. The nexthop->ifindex will be updated
1466 * appropriately as well. An existing route map can turn
1467 * (otherwise active) nexthop into inactive, but not vice versa.
1468 *
1469 * If it finds a nexthop recursivedly, set the resolved_id
1470 * to match that nexthop's nhg_hash_entry ID;
1471 *
1472 * The return value is the final value of 'ACTIVE' flag.
1473 */
1474 static unsigned nexthop_active_check(struct route_node *rn,
1475 struct route_entry *re,
1476 struct nexthop *nexthop)
1477 {
1478 struct interface *ifp;
1479 route_map_result_t ret = RMAP_PERMITMATCH;
1480 int family;
1481 char buf[SRCDEST2STR_BUFFER];
1482 const struct prefix *p, *src_p;
1483 struct zebra_vrf *zvrf;
1484
1485 srcdest_rnode_prefixes(rn, &p, &src_p);
1486
1487 if (rn->p.family == AF_INET)
1488 family = AFI_IP;
1489 else if (rn->p.family == AF_INET6)
1490 family = AFI_IP6;
1491 else
1492 family = 0;
1493 switch (nexthop->type) {
1494 case NEXTHOP_TYPE_IFINDEX:
1495 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1496 if (ifp && if_is_operative(ifp))
1497 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1498 else
1499 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1500 break;
1501 case NEXTHOP_TYPE_IPV4:
1502 case NEXTHOP_TYPE_IPV4_IFINDEX:
1503 family = AFI_IP;
1504 if (nexthop_active(AFI_IP, re, nexthop, rn))
1505 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1506 else
1507 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1508 break;
1509 case NEXTHOP_TYPE_IPV6:
1510 family = AFI_IP6;
1511 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1512 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1513 else
1514 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1515 break;
1516 case NEXTHOP_TYPE_IPV6_IFINDEX:
1517 /* RFC 5549, v4 prefix with v6 NH */
1518 if (rn->p.family != AF_INET)
1519 family = AFI_IP6;
1520 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
1521 ifp = if_lookup_by_index(nexthop->ifindex,
1522 nexthop->vrf_id);
1523 if (ifp && if_is_operative(ifp))
1524 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1525 else
1526 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1527 } else {
1528 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1529 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1530 else
1531 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1532 }
1533 break;
1534 case NEXTHOP_TYPE_BLACKHOLE:
1535 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1536 break;
1537 default:
1538 break;
1539 }
1540 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1541 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1542 zlog_debug("\t%s: Unable to find a active nexthop",
1543 __PRETTY_FUNCTION__);
1544 return 0;
1545 }
1546
1547 /* XXX: What exactly do those checks do? Do we support
1548 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1549 */
1550 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
1551 || (family == AFI_IP6 && p->family != AF_INET6))
1552 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1553
1554 /* The original code didn't determine the family correctly
1555 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1556 * from the rib_table_info in those cases.
1557 * Possibly it may be better to use only the rib_table_info
1558 * in every case.
1559 */
1560 if (!family) {
1561 rib_table_info_t *info;
1562
1563 info = srcdest_rnode_table_info(rn);
1564 family = info->afi;
1565 }
1566
1567 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
1568
1569 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1570 if (!zvrf) {
1571 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1572 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
1573 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1574 }
1575
1576 /* It'll get set if required inside */
1577 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
1578 zvrf, re->tag);
1579 if (ret == RMAP_DENYMATCH) {
1580 if (IS_ZEBRA_DEBUG_RIB) {
1581 srcdest_rnode2str(rn, buf, sizeof(buf));
1582 zlog_debug(
1583 "%u:%s: Filtering out with NH out %s due to route map",
1584 re->vrf_id, buf,
1585 ifindex2ifname(nexthop->ifindex,
1586 nexthop->vrf_id));
1587 }
1588 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1589 }
1590 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1591 }
1592
1593 /*
1594 * Iterate over all nexthops of the given RIB entry and refresh their
1595 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1596 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
1597 *
1598 * Return value is the new number of active nexthops.
1599 */
1600 int nexthop_active_update(struct route_node *rn, struct route_entry *re)
1601 {
1602 struct nexthop_group new_grp = {};
1603 struct nexthop *nexthop;
1604 union g_addr prev_src;
1605 unsigned int prev_active, new_active;
1606 ifindex_t prev_index;
1607 uint8_t curr_active = 0;
1608
1609 afi_t rt_afi = family2afi(rn->p.family);
1610
1611 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1612
1613 /* Copy over the nexthops in current state */
1614 nexthop_group_copy(&new_grp, re->ng);
1615
1616 for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
1617
1618 /* No protocol daemon provides src and so we're skipping
1619 * tracking it */
1620 prev_src = nexthop->rmap_src;
1621 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1622 prev_index = nexthop->ifindex;
1623 /*
1624 * We need to respect the multipath_num here
1625 * as that what we should be able to install from
1626 * a multipath perpsective should not be a data plane
1627 * decision point.
1628 */
1629 new_active =
1630 nexthop_active_check(rn, re, nexthop);
1631
1632 if (new_active
1633 && nexthop_group_active_nexthop_num(&new_grp)
1634 >= zrouter.multipath_num) {
1635 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1636 new_active = 0;
1637 }
1638
1639 if (new_active)
1640 curr_active++;
1641
1642 /* Don't allow src setting on IPv6 addr for now */
1643 if (prev_active != new_active || prev_index != nexthop->ifindex
1644 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
1645 && nexthop->type < NEXTHOP_TYPE_IPV6)
1646 && prev_src.ipv4.s_addr
1647 != nexthop->rmap_src.ipv4.s_addr)
1648 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
1649 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
1650 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
1651 &nexthop->rmap_src.ipv6)))
1652 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
1653 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1654 }
1655
1656 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
1657 struct nhg_hash_entry *new_nhe = NULL;
1658
1659 new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
1660
1661 zebra_nhg_re_update_ref(re, new_nhe);
1662 }
1663
1664 if (curr_active) {
1665 struct nhg_hash_entry *nhe = NULL;
1666
1667 nhe = zebra_nhg_lookup_id(re->nhe_id);
1668
1669 if (nhe)
1670 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1671 else
1672 flog_err(
1673 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1674 "Active update on NHE id=%u that we do not have in our tables",
1675 re->nhe_id);
1676 }
1677
1678 /*
1679 * Do not need these nexthops anymore since they
1680 * were either copied over into an nhe or not
1681 * used at all.
1682 */
1683 nexthops_free(new_grp.nexthop);
1684 return curr_active;
1685 }
1686
1687 static void zebra_nhg_re_attach_ref(struct route_entry *re,
1688 struct nhg_hash_entry *new)
1689 {
1690 re->ng = new->nhg;
1691 re->nhe_id = new->id;
1692
1693 zebra_nhg_increment_ref(new);
1694 }
1695
1696 int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new)
1697 {
1698 struct nhg_hash_entry *old = NULL;
1699 int ret = 0;
1700
1701 if (new == NULL) {
1702 re->ng = NULL;
1703 goto done;
1704 }
1705
1706 if (re->nhe_id != new->id) {
1707 old = zebra_nhg_lookup_id(re->nhe_id);
1708
1709 zebra_nhg_re_attach_ref(re, new);
1710
1711 if (old)
1712 zebra_nhg_decrement_ref(old);
1713 } else if (!re->ng)
1714 /* This is the first time it's being attached */
1715 zebra_nhg_re_attach_ref(re, new);
1716
1717 done:
1718 return ret;
1719 }
1720
1721 /* Convert a nhe into a group array */
1722 uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe,
1723 int max_num)
1724 {
1725 struct nhg_connected *rb_node_dep = NULL;
1726 struct nhg_hash_entry *depend = NULL;
1727 uint8_t i = 0;
1728
1729 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1730 bool duplicate = false;
1731
1732 depend = rb_node_dep->nhe;
1733
1734 /*
1735 * If its recursive, use its resolved nhe in the group
1736 */
1737 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
1738 depend = zebra_nhg_resolve(depend);
1739 if (!depend) {
1740 flog_err(
1741 EC_ZEBRA_NHG_FIB_UPDATE,
1742 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
1743 nhe->id);
1744 continue;
1745 }
1746 }
1747
1748 /* Check for duplicate IDs, kernel doesn't like that */
1749 for (int j = 0; j < i; j++) {
1750 if (depend->id == grp[j].id)
1751 duplicate = true;
1752 }
1753
1754 if (!duplicate) {
1755 grp[i].id = depend->id;
1756 /* We aren't using weights for anything right now */
1757 grp[i].weight = 0;
1758 i++;
1759 }
1760
1761 if (i >= max_num)
1762 goto done;
1763 }
1764
1765 done:
1766 return i;
1767 }
1768
1769 void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
1770 {
1771 struct nhg_connected *rb_node_dep = NULL;
1772
1773 /* Resolve it first */
1774 nhe = zebra_nhg_resolve(nhe);
1775
1776 /* Make sure all depends are installed/queued */
1777 frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
1778 zebra_nhg_install_kernel(rb_node_dep->nhe);
1779 }
1780
1781 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
1782 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
1783 /* Change its type to us since we are installing it */
1784 nhe->type = ZEBRA_ROUTE_NHG;
1785
1786 int ret = dplane_nexthop_add(nhe);
1787
1788 switch (ret) {
1789 case ZEBRA_DPLANE_REQUEST_QUEUED:
1790 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1791 break;
1792 case ZEBRA_DPLANE_REQUEST_FAILURE:
1793 flog_err(
1794 EC_ZEBRA_DP_INSTALL_FAIL,
1795 "Failed to install Nexthop ID (%u) into the kernel",
1796 nhe->id);
1797 break;
1798 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1799 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1800 zebra_nhg_handle_install(nhe);
1801 break;
1802 }
1803 }
1804 }
1805
1806 void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
1807 {
1808 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1809 int ret = dplane_nexthop_delete(nhe);
1810
1811 switch (ret) {
1812 case ZEBRA_DPLANE_REQUEST_QUEUED:
1813 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1814 break;
1815 case ZEBRA_DPLANE_REQUEST_FAILURE:
1816 flog_err(
1817 EC_ZEBRA_DP_DELETE_FAIL,
1818 "Failed to uninstall Nexthop ID (%u) from the kernel",
1819 nhe->id);
1820 break;
1821 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1822 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1823 break;
1824 }
1825 }
1826
1827 zebra_nhg_handle_uninstall(nhe);
1828 }
1829
1830 void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
1831 {
1832 enum dplane_op_e op;
1833 enum zebra_dplane_result status;
1834 uint32_t id = 0;
1835 struct nhg_hash_entry *nhe = NULL;
1836
1837 op = dplane_ctx_get_op(ctx);
1838 status = dplane_ctx_get_status(ctx);
1839
1840 id = dplane_ctx_get_nhe_id(ctx);
1841
1842 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1843 zlog_debug(
1844 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1845 ctx, dplane_op2str(op), id, dplane_res2str(status));
1846
1847 switch (op) {
1848 case DPLANE_OP_NH_DELETE:
1849 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
1850 flog_err(
1851 EC_ZEBRA_DP_DELETE_FAIL,
1852 "Failed to uninstall Nexthop ID (%u) from the kernel",
1853 id);
1854 /* We already free'd the data, nothing to do */
1855 break;
1856 case DPLANE_OP_NH_INSTALL:
1857 case DPLANE_OP_NH_UPDATE:
1858 nhe = zebra_nhg_lookup_id(id);
1859
1860 if (!nhe) {
1861 flog_err(
1862 EC_ZEBRA_NHG_SYNC,
1863 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1864 dplane_op2str(op), id);
1865 break;
1866 }
1867
1868 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1869 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1870 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1871 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1872 zebra_nhg_handle_install(nhe);
1873 } else
1874 flog_err(
1875 EC_ZEBRA_DP_INSTALL_FAIL,
1876 "Failed to install Nexthop ID (%u) into the kernel",
1877 nhe->id);
1878 break;
1879 case DPLANE_OP_ROUTE_INSTALL:
1880 case DPLANE_OP_ROUTE_UPDATE:
1881 case DPLANE_OP_ROUTE_DELETE:
1882 case DPLANE_OP_ROUTE_NOTIFY:
1883 case DPLANE_OP_LSP_INSTALL:
1884 case DPLANE_OP_LSP_UPDATE:
1885 case DPLANE_OP_LSP_DELETE:
1886 case DPLANE_OP_LSP_NOTIFY:
1887 case DPLANE_OP_PW_INSTALL:
1888 case DPLANE_OP_PW_UNINSTALL:
1889 case DPLANE_OP_SYS_ROUTE_ADD:
1890 case DPLANE_OP_SYS_ROUTE_DELETE:
1891 case DPLANE_OP_ADDR_INSTALL:
1892 case DPLANE_OP_ADDR_UNINSTALL:
1893 case DPLANE_OP_MAC_INSTALL:
1894 case DPLANE_OP_MAC_DELETE:
1895 case DPLANE_OP_NEIGH_INSTALL:
1896 case DPLANE_OP_NEIGH_UPDATE:
1897 case DPLANE_OP_NEIGH_DELETE:
1898 case DPLANE_OP_VTEP_ADD:
1899 case DPLANE_OP_VTEP_DELETE:
1900 case DPLANE_OP_NONE:
1901 break;
1902 }
1903
1904 dplane_ctx_fini(&ctx);
1905 }
1906
1907 static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
1908 {
1909 struct nhg_hash_entry *nhe = NULL;
1910
1911 nhe = (struct nhg_hash_entry *)bucket->data;
1912
1913 /* If its being ref'd, just let it be uninstalled via a route removal */
1914 if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
1915 zebra_nhg_uninstall_kernel(nhe);
1916 }
1917
1918 void zebra_nhg_sweep_table(struct hash *hash)
1919 {
1920 hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
1921 }