]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
zebra: Add nhg refcnt connected helper functions
[mirror_frr.git] / zebra / zebra_nhg.c
CommitLineData
ad28e79a
SW
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"
50d89650 26#include "lib/nexthop_group_private.h"
ad28e79a 27#include "lib/routemap.h"
b43434ad 28#include "lib/mpls.h"
69171da2 29#include "lib/jhash.h"
51d80884 30#include "lib/debug.h"
ad28e79a
SW
31
32#include "zebra/connected.h"
33#include "zebra/debug.h"
34#include "zebra/zebra_router.h"
35#include "zebra/zebra_nhg.h"
36#include "zebra/zebra_rnh.h"
37#include "zebra/zebra_routemap.h"
51d80884
SW
38#include "zebra/zebra_memory.h"
39#include "zebra/zserv.h"
ad28e79a 40#include "zebra/rt.h"
d9f5b2f5 41#include "zebra_errors.h"
0c8215cb 42#include "zebra_dplane.h"
fe593b78 43#include "zebra/interface.h"
d9f5b2f5 44
51d80884 45DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
a15d4c00 46DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
e22e8001 47DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
0c8215cb 48
fe593b78
SW
49static int nhg_connected_cmp(const struct nhg_connected *dep1,
50 const struct nhg_connected *dep2);
8a507796 51static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi);
0c8215cb 52
fe593b78 53RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
0c8215cb 54
e22e8001 55
fe593b78 56void nhg_connected_free(struct nhg_connected *dep)
0c8215cb 57{
a15d4c00 58 XFREE(MTYPE_NHG_CONNECTED, dep);
0c8215cb
SW
59}
60
fe593b78 61struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
0c8215cb 62{
a15d4c00 63 struct nhg_connected *new = NULL;
0c8215cb 64
a15d4c00 65 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
0c8215cb
SW
66 new->nhe = nhe;
67
68 return new;
69}
70
fe593b78
SW
71void nhg_connected_head_init(struct nhg_connected_head *head)
72{
73 RB_INIT(nhg_connected_head, head);
74}
75
76void nhg_connected_head_free(struct nhg_connected_head *head)
0c8215cb 77{
a15d4c00 78 struct nhg_connected *rb_node_dep = NULL;
fe593b78 79 struct nhg_connected *tmp = NULL;
0c8215cb 80
fe593b78
SW
81 if (!nhg_connected_head_is_empty(head)) {
82 RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) {
83 RB_REMOVE(nhg_connected_head, head, rb_node_dep);
84 nhg_connected_free(rb_node_dep);
85 }
0c8215cb 86 }
0c8215cb
SW
87}
88
fe593b78 89unsigned int nhg_connected_head_count(const struct nhg_connected_head *head)
0c8215cb 90{
fe593b78
SW
91 struct nhg_connected *rb_node_dep = NULL;
92 unsigned int i = 0;
0c8215cb 93
fe593b78
SW
94 RB_FOREACH (rb_node_dep, nhg_connected_head, head) {
95 i++;
96 }
97 return i;
0c8215cb 98}
3119f6a1 99
fe593b78 100bool nhg_connected_head_is_empty(const struct nhg_connected_head *head)
3119f6a1 101{
fe593b78 102 return RB_EMPTY(nhg_connected_head, head);
0c8215cb
SW
103}
104
98cda54a
SW
105struct nhg_connected *
106nhg_connected_head_root(const struct nhg_connected_head *head)
107{
108 return RB_ROOT(nhg_connected_head, head);
109}
110
fe593b78
SW
111void nhg_connected_head_del(struct nhg_connected_head *head,
112 struct nhg_hash_entry *depend)
0c8215cb 113{
a15d4c00 114 struct nhg_connected lookup = {};
085304dc 115 struct nhg_connected *remove = NULL;
0c8215cb
SW
116
117 lookup.nhe = depend;
3119f6a1 118
085304dc
SW
119 /* Lookup to find the element, then remove it */
120 remove = RB_FIND(nhg_connected_head, head, &lookup);
121 remove = RB_REMOVE(nhg_connected_head, head, remove);
3119f6a1 122
085304dc
SW
123 if (remove)
124 nhg_connected_free(remove);
3119f6a1
SW
125}
126
fe593b78
SW
127void nhg_connected_head_add(struct nhg_connected_head *head,
128 struct nhg_hash_entry *depend)
3119f6a1 129{
a15d4c00 130 struct nhg_connected *new = NULL;
0c8215cb 131
a15d4c00 132 new = nhg_connected_new(depend);
0c8215cb 133
18cf7f15
SW
134 if (new)
135 RB_INSERT(nhg_connected_head, head, new);
3119f6a1
SW
136}
137
32e29e79
SW
138static void nhg_connected_head_decrement_ref(struct nhg_connected_head *head)
139{
140 struct nhg_connected *rb_node_dep = NULL;
141 struct nhg_connected *tmp = NULL;
142
143 RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) {
144 zebra_nhg_decrement_ref(rb_node_dep->nhe);
145 }
146}
147
148static void nhg_connected_head_increment_ref(struct nhg_connected_head *head)
149{
150 struct nhg_connected *rb_node_dep = NULL;
151
152 RB_FOREACH (rb_node_dep, nhg_connected_head, head) {
153 zebra_nhg_increment_ref(rb_node_dep->nhe);
154 }
155}
156
98cda54a
SW
157struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe)
158{
159 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)
160 && !zebra_nhg_depends_is_empty(nhe)) {
161 nhe = nhg_connected_head_root(&nhe->nhg_depends)->nhe;
162 return zebra_nhg_resolve(nhe);
163 }
164
165 return nhe;
166}
167
168uint32_t zebra_nhg_get_resolved_id(uint32_t id)
169{
170 struct nhg_hash_entry *nhe = NULL;
171
172 nhe = zebra_nhg_lookup_id(id);
173
174 if (!nhe) {
175 flog_err(
176 EC_ZEBRA_TABLE_LOOKUP_FAILED,
177 "Zebra failed to lookup a resolved nexthop hash entry id=%u",
178 id);
179 return id;
180 }
181
182 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
183 nhe = zebra_nhg_resolve(nhe);
184
185 return nhe->id;
186}
187
fe593b78 188unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
a15d4c00 189{
fe593b78 190 return nhg_connected_head_count(&nhe->nhg_depends);
a15d4c00
SW
191}
192
fe593b78 193bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
a15d4c00 194{
fe593b78 195 return nhg_connected_head_is_empty(&nhe->nhg_depends);
a15d4c00
SW
196}
197
0c8215cb
SW
198void zebra_nhg_depends_del(struct nhg_hash_entry *from,
199 struct nhg_hash_entry *depend)
3119f6a1 200{
fe593b78 201 nhg_connected_head_del(&from->nhg_depends, depend);
3119f6a1
SW
202}
203
0c8215cb
SW
204void zebra_nhg_depends_add(struct nhg_hash_entry *to,
205 struct nhg_hash_entry *depend)
3119f6a1 206{
fe593b78 207 nhg_connected_head_add(&to->nhg_depends, depend);
d6e0094f
SW
208}
209
0c8215cb 210void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
148a0103 211{
fe593b78 212 nhg_connected_head_init(&nhe->nhg_depends);
148a0103
SW
213}
214
21615102
SW
215/* Release this nhe from anything that it depends on */
216static void zebra_nhg_depends_release(struct nhg_hash_entry *nhe)
217{
218 if (!zebra_nhg_depends_is_empty(nhe)) {
219 struct nhg_connected *rb_node_dep = NULL;
220 struct nhg_connected *tmp = NULL;
221
222 RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head,
223 &nhe->nhg_depends, tmp) {
224 zebra_nhg_dependents_del(rb_node_dep->nhe, nhe);
225 }
226 }
227}
228
fe593b78
SW
229unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
230{
231 return nhg_connected_head_count(&nhe->nhg_dependents);
232}
233
234bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
235{
236 return nhg_connected_head_is_empty(&nhe->nhg_dependents);
237}
238
fe593b78
SW
239void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
240 struct nhg_hash_entry *dependent)
241{
242 nhg_connected_head_del(&from->nhg_dependents, dependent);
243}
244
fe593b78
SW
245void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
246 struct nhg_hash_entry *dependent)
247{
248 nhg_connected_head_add(&to->nhg_dependents, dependent);
249}
250
fe593b78
SW
251void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
252{
253 nhg_connected_head_init(&nhe->nhg_dependents);
254}
255
21615102
SW
256/* Release this nhe from anything depending on it */
257static void zebra_nhg_dependents_release(struct nhg_hash_entry *nhe)
258{
259 if (!zebra_nhg_dependents_is_empty(nhe)) {
260 struct nhg_connected *rb_node_dep = NULL;
261 struct nhg_connected *tmp = NULL;
262
263 RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head,
264 &nhe->nhg_dependents, tmp) {
265 zebra_nhg_depends_del(rb_node_dep->nhe, nhe);
266 }
267 }
268}
269
d9f5b2f5
SW
270struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
271{
0c8215cb 272 struct nhg_hash_entry lookup = {};
d9f5b2f5
SW
273
274 lookup.id = id;
275 return hash_lookup(zrouter.nhgs_id, &lookup);
276}
277
d9f5b2f5
SW
278int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
279{
280 if (hash_lookup(zrouter.nhgs_id, nhe)) {
281 flog_err(
282 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
283 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
284 nhe->id);
285 return -1;
286 }
287
288 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
289
290 return 0;
291}
ad28e79a 292
4e49c8b8
DS
293
294static void *zebra_nhg_alloc(void *arg)
295{
296 struct nhg_hash_entry *nhe;
297 struct nhg_hash_entry *copy = arg;
a15d4c00
SW
298 struct nhg_connected *rb_node_dep = NULL;
299
51d80884 300 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
d9f5b2f5 301
5bd81e4c 302 nhe->id = copy->id;
0c8215cb 303 nhe->nhg_depends = copy->nhg_depends;
8e401b25 304
2d6cd1f0
SW
305 nhe->nhg = nexthop_group_new();
306 nexthop_group_copy(nhe->nhg, copy->nhg);
3119f6a1 307
4e49c8b8 308 nhe->vrf_id = copy->vrf_id;
77b76fc9 309 nhe->afi = copy->afi;
4e49c8b8 310 nhe->refcnt = 0;
9ed6c34a 311 nhe->is_kernel_nh = copy->is_kernel_nh;
4e49c8b8 312 nhe->dplane_ref = zebra_router_get_next_sequence();
4e49c8b8 313
a15d4c00 314 /* Attach backpointer to anything that it depends on */
fe593b78 315 zebra_nhg_dependents_init(nhe);
a15d4c00
SW
316 if (!zebra_nhg_depends_is_empty(nhe)) {
317 RB_FOREACH (rb_node_dep, nhg_connected_head,
318 &nhe->nhg_depends) {
319 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
320 }
321 }
4e49c8b8 322
7b683a96 323 /* Add the ifp now if its not a group or recursive and has ifindex */
a6e6a6d8
SW
324 if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop
325 && nhe->nhg->nexthop->ifindex) {
7b683a96
SW
326 struct interface *ifp = NULL;
327
a6e6a6d8
SW
328 ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
329 nhe->vrf_id);
7f1abf79
SW
330 if (ifp)
331 zebra_nhg_set_if(nhe, ifp);
332 else
333 flog_err(
334 EC_ZEBRA_IF_LOOKUP_FAILED,
335 "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
336 nhe->nhg->nexthop->ifindex, nhe->vrf_id,
337 nhe->id);
7b683a96
SW
338 }
339
d9f5b2f5
SW
340 /* Add to id table as well */
341 zebra_nhg_insert_id(nhe);
342
4e49c8b8
DS
343 return nhe;
344}
345
4e49c8b8
DS
346uint32_t zebra_nhg_hash_key(const void *arg)
347{
348 const struct nhg_hash_entry *nhe = arg;
d9f5b2f5 349
7286ac02 350 uint32_t key = 0x5a351234;
4e49c8b8 351
77b76fc9 352 key = jhash_2words(nhe->vrf_id, nhe->afi, key);
4e49c8b8 353
0c8215cb 354 key = jhash_1word(nexthop_group_hash(nhe->nhg), key);
d9f5b2f5 355
d9f5b2f5 356 return key;
4e49c8b8
DS
357}
358
a95b8020
SW
359uint32_t zebra_nhg_id_key(const void *arg)
360{
361 const struct nhg_hash_entry *nhe = arg;
362
363 return nhe->id;
364}
365
4e49c8b8
DS
366bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
367{
368 const struct nhg_hash_entry *nhe1 = arg1;
369 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 370
98cda54a
SW
371 /* No matter what if they equal IDs, assume equal */
372 if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
373 return true;
374
4e49c8b8
DS
375 if (nhe1->vrf_id != nhe2->vrf_id)
376 return false;
377
77b76fc9
SW
378 if (nhe1->afi != nhe2->afi)
379 return false;
380
7192bb23 381 if (!nexthop_group_equal(nhe1->nhg, nhe2->nhg))
20822f9d 382 return false;
4e49c8b8 383
98cda54a
SW
384 if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
385 != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
386 return false;
387
4e49c8b8
DS
388 return true;
389}
390
d9f5b2f5 391bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 392{
d9f5b2f5
SW
393 const struct nhg_hash_entry *nhe1 = arg1;
394 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 395
d9f5b2f5
SW
396 return nhe1->id == nhe2->id;
397}
4e49c8b8 398
3082f99c
SW
399static int nhg_connected_cmp(const struct nhg_connected *con1,
400 const struct nhg_connected *con2)
0c8215cb 401{
3082f99c 402 return (con1->nhe->id - con2->nhe->id);
0c8215cb
SW
403}
404
e22e8001
SW
405static void zebra_nhg_process_grp(struct nexthop_group *nhg,
406 struct nhg_connected_head *depends,
407 struct nh_grp *grp, uint8_t count)
408{
409 nhg_connected_head_init(depends);
410
411 for (int i = 0; i < count; i++) {
412 struct nhg_hash_entry *depend = NULL;
413 /* We do not care about nexthop_grp.weight at
414 * this time. But we should figure out
415 * how to adapt this to our code in
416 * the future.
417 */
418 depend = zebra_nhg_lookup_id(grp[i].id);
419 if (depend) {
420 nhg_connected_head_add(depends, depend);
421 /*
422 * If this is a nexthop with its own group
423 * dependencies, add them as well. Not sure its
424 * even possible to have a group within a group
425 * in the kernel.
426 */
427
428 copy_nexthops(&nhg->nexthop, depend->nhg->nexthop,
429 NULL);
430 } else {
431 flog_err(
432 EC_ZEBRA_NHG_SYNC,
433 "Received Nexthop Group from the kernel with a dependent Nexthop ID (%u) which we do not have in our table",
434 grp[i].id);
435 }
436 }
437}
438
439
4505578b
SW
440static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
441 struct nexthop_group *nhg,
442 struct nhg_connected_head *nhg_depends,
443 vrf_id_t vrf_id, afi_t afi, bool is_kernel_nh)
a95b8020 444{
5bd81e4c
SW
445 /* id counter to keep in sync with kernel */
446 static uint32_t id_counter = 0;
447
0c8215cb 448 struct nhg_hash_entry lookup = {};
5bd81e4c 449
e22e8001 450 uint32_t old_id_counter = id_counter;
5bd81e4c 451
4505578b
SW
452 bool created = false;
453
e22e8001
SW
454 if (id > id_counter) {
455 /* Increase our counter so we don't try to create
456 * an ID that already exists
457 */
458 id_counter = id;
5bd81e4c 459 lookup.id = id;
e22e8001 460 } else
5bd81e4c 461 lookup.id = ++id_counter;
a95b8020 462
77b76fc9 463 lookup.afi = afi;
e22e8001 464 lookup.vrf_id = vrf_id;
9ed6c34a 465 lookup.is_kernel_nh = is_kernel_nh;
e22e8001
SW
466 lookup.nhg = nhg;
467
468 if (nhg_depends)
469 lookup.nhg_depends = *nhg_depends;
a95b8020 470
b599cd2a 471 if (id)
4505578b 472 (*nhe) = zebra_nhg_lookup_id(id);
b599cd2a 473 else
4505578b 474 (*nhe) = hash_lookup(zrouter.nhgs, &lookup);
d9f5b2f5 475
5bd81e4c 476 /* If it found an nhe in our tables, this new ID is unused */
4505578b 477 if (*nhe)
5bd81e4c
SW
478 id_counter = old_id_counter;
479
4505578b
SW
480 if (!(*nhe)) {
481 (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
482 created = true;
483 }
d9f5b2f5 484
4505578b 485 return created;
a95b8020
SW
486}
487
e22e8001 488/* Find/create a single nexthop */
4505578b
SW
489static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id,
490 struct nexthop *nh, afi_t afi,
491 bool is_kernel_nh)
3057df51 492{
e22e8001 493 struct nexthop_group nhg = {};
8a507796
SW
494 struct nhg_connected_head nhg_depends = {};
495 bool created = true;
e22e8001
SW
496
497 _nexthop_group_add_sorted(&nhg, nh);
498
8a507796
SW
499 if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
500 struct nhg_hash_entry *depend = NULL;
501
502 nhg_connected_head_init(&nhg_depends);
503
504 depend = depends_find(nh->resolved, afi);
505 nhg_connected_head_add(&nhg_depends, depend);
506 }
507
508 if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi,
509 is_kernel_nh)) {
510 created = false;
511 nhg_connected_head_free(&nhg_depends);
512 } else {
513 if (zebra_nhg_depends_count(*nhe))
514 SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
515 }
516
517 return created;
e22e8001
SW
518}
519
520static struct nhg_ctx *nhg_ctx_new()
521{
522 struct nhg_ctx *new = NULL;
523
524 new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx));
525
526 return new;
527}
528
529static void nhg_ctx_free(struct nhg_ctx *ctx)
530{
531 XFREE(MTYPE_NHG_CTX, ctx);
532}
533
534static void nhg_ctx_set_status(struct nhg_ctx *ctx, enum nhg_ctx_result status)
535{
536 ctx->status = status;
537}
538
539static enum nhg_ctx_result nhg_ctx_get_status(const struct nhg_ctx *ctx)
540{
541 return ctx->status;
542}
543
544static void nhg_ctx_set_op(struct nhg_ctx *ctx, enum nhg_ctx_op_e op)
545{
546 ctx->op = op;
547}
548
549static enum nhg_ctx_op_e nhg_ctx_get_op(const struct nhg_ctx *ctx)
550{
551 return ctx->op;
552}
553
554static int nhg_ctx_process_new(struct nhg_ctx *ctx)
555{
556 struct nexthop_group *nhg = NULL;
557 struct nhg_connected_head nhg_depends = {};
3057df51
SW
558 struct nhg_hash_entry *nhe = NULL;
559
e22e8001
SW
560 if (ctx->count) {
561 nhg = nexthop_group_new();
562 zebra_nhg_process_grp(nhg, &nhg_depends, ctx->u.grp,
563 ctx->count);
4505578b
SW
564 if (!zebra_nhg_find(&nhe, ctx->id, nhg, &nhg_depends,
565 ctx->vrf_id, ctx->afi, true))
566 nhg_connected_head_free(&nhg_depends);
567
e22e8001
SW
568 /* These got copied over in zebra_nhg_alloc() */
569 nexthop_group_free_delete(&nhg);
4505578b
SW
570 } else if (!zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi,
571 ctx->is_kernel_nh))
572 nhg_connected_head_free(&nhg_depends);
e22e8001
SW
573
574 if (nhe) {
575 if (ctx->id != nhe->id)
576 /* Duplicate but with different ID from
2d3c57e6
SW
577 * the kernel
578 */
e22e8001
SW
579
580 /* The kernel allows duplicate nexthops
581 * as long as they have different IDs.
582 * We are ignoring those to prevent
583 * syncing problems with the kernel
584 * changes.
585 */
586 flog_warn(
587 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
588 "Nexthop Group with ID (%d) is a duplicate, ignoring",
589 ctx->id);
590 else {
591 /* It actually created a new nhe */
592 if (nhe->is_kernel_nh) {
593 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
594 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
595 }
596 }
597 } else {
598 flog_err(
599 EC_ZEBRA_TABLE_LOOKUP_FAILED,
600 "Zebra failed to find or create a nexthop hash entry for ID (%u)",
601 ctx->id);
602 return -1;
603 }
604
605 return 0;
606}
607
608static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
609{
610 /*
611 * Just freeing for now, maybe do something more in the future
612 * based on flag.
613 */
614
615 if (ctx)
616 nhg_ctx_free(ctx);
617}
618
619int nhg_ctx_process(struct nhg_ctx *ctx)
620{
621 int ret = 0;
622
623 switch (nhg_ctx_get_op(ctx)) {
624 case NHG_CTX_OP_NEW:
625 ret = nhg_ctx_process_new(ctx);
626 break;
627 case NHG_CTX_OP_DEL:
628 case NHG_CTX_OP_NONE:
629 break;
630 }
631
632 nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS));
633
634 nhg_ctx_process_finish(ctx);
635
636 return ret;
637}
3057df51 638
e22e8001
SW
639static int queue_add(struct nhg_ctx *ctx)
640{
641 /* If its queued or already processed do nothing */
642 if (nhg_ctx_get_status(ctx))
643 return 0;
644
645 if (rib_queue_nhg_add(ctx)) {
646 nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
647 return -1;
648 }
649
650 nhg_ctx_set_status(ctx, NHG_CTX_QUEUED);
651
652 return 0;
653}
654
655/* Kernel-side, you either get a single new nexthop or a array of ID's */
656int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
657 uint8_t count, vrf_id_t vrf_id, afi_t afi)
658{
659 // TODO: Can probably put table lookup
660 // here before queueing? And if deleted, re-send to kernel?
661 // ... Well, if changing the flags it probably needs to be queued
662 // still...
3057df51 663
e22e8001
SW
664 struct nhg_ctx *ctx = NULL;
665
666 ctx = nhg_ctx_new();
667
668 ctx->id = id;
669 ctx->vrf_id = vrf_id;
670 ctx->afi = afi;
671 ctx->is_kernel_nh = true;
672 ctx->count = count;
673
674 if (count)
675 /* Copy over the array */
676 memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
677 else
678 ctx->u.nh = *nh;
679
680 nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
681
682 if (queue_add(ctx)) {
683 nhg_ctx_process_finish(ctx);
684 return -1;
685 }
686
687 return 0;
688}
689
98cda54a
SW
690static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi)
691{
8a507796 692 struct nexthop *lookup = NULL;
4505578b 693 struct nhg_hash_entry *nhe = NULL;
98cda54a 694
8a507796
SW
695 copy_nexthops(&lookup, nh, NULL);
696
98cda54a 697 /* Clear it, in case its a group */
8a507796
SW
698 nexthops_free(lookup->next);
699 nexthops_free(lookup->prev);
700 lookup->next = NULL;
701 lookup->prev = NULL;
702
703 zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, false);
704
705 nexthops_free(lookup);
4505578b
SW
706
707 return nhe;
98cda54a
SW
708}
709
e22e8001 710/* Rib-side, you get a nexthop group struct */
7f997721
SW
711struct nhg_hash_entry *
712zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
e22e8001
SW
713{
714 struct nhg_hash_entry *nhe = NULL;
98cda54a 715 struct nhg_hash_entry *depend = NULL;
e22e8001 716 struct nhg_connected_head nhg_depends = {};
98cda54a 717
2d3c57e6 718 /* Defualt the nhe to the afi and vrf of the route */
e22e8001 719 afi_t nhg_afi = rt_afi;
7f997721 720 vrf_id_t nhg_vrf_id = nhg->nexthop->vrf_id;
e22e8001 721
98cda54a
SW
722 if (!nhg) {
723 flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
2d3c57e6 724 "No nexthop passed to %s", __func__);
98cda54a
SW
725 return NULL;
726 }
e22e8001 727
98cda54a 728 if (nhg->nexthop->next) {
e22e8001
SW
729 nhg_connected_head_init(&nhg_depends);
730
98cda54a
SW
731 /* If its a group, create a dependency tree */
732 struct nexthop *nh = NULL;
733
734 for (nh = nhg->nexthop; nh; nh = nh->next) {
735 depend = depends_find(nh, rt_afi);
e22e8001
SW
736 nhg_connected_head_add(&nhg_depends, depend);
737 }
738
739 /* change the afi/vrf_id since its a group */
740 nhg_afi = AFI_UNSPEC;
741 nhg_vrf_id = 0;
742 }
743
4505578b
SW
744 if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi,
745 false))
746 nhg_connected_head_free(&nhg_depends);
747
3057df51
SW
748 return nhe;
749}
750
b599cd2a
SW
751void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
752{
ddaee0c7
SW
753 nexthop_group_free_delete(&nhe->nhg);
754 nhg_connected_head_free(&nhe->nhg_depends);
fe593b78 755 nhg_connected_head_free(&nhe->nhg_dependents);
b599cd2a
SW
756}
757
d9f5b2f5 758void zebra_nhg_free(void *arg)
a95b8020 759{
d9f5b2f5 760 struct nhg_hash_entry *nhe = NULL;
a95b8020 761
d9f5b2f5 762 nhe = (struct nhg_hash_entry *)arg;
a95b8020 763
8e401b25 764 zebra_nhg_free_members(nhe);
51d80884
SW
765
766 XFREE(MTYPE_NHG, nhe);
a95b8020
SW
767}
768
e22e8001 769static void zebra_nhg_release(struct nhg_hash_entry *nhe)
4e49c8b8 770{
6ccc2b28
SW
771 zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
772
773 /* Remove it from any lists it may be on */
774 zebra_nhg_depends_release(nhe);
775 zebra_nhg_dependents_release(nhe);
776 if (nhe->ifp)
777 if_nhg_dependents_del(nhe->ifp, nhe);
778
8a507796
SW
779 if(!hash_release(zrouter.nhgs, nhe))
780 zlog_debug("Failed release");
6ccc2b28 781 hash_release(zrouter.nhgs_id, nhe);
e22e8001 782
6ccc2b28 783 zebra_nhg_free(nhe);
7512f617 784}
4e49c8b8 785
d9f5b2f5
SW
786void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
787{
e22e8001
SW
788 nhe->refcnt--;
789
32e29e79
SW
790 if (!zebra_nhg_depends_is_empty(nhe))
791 nhg_connected_head_decrement_ref(&nhe->nhg_depends);
f54ef6a5 792
e22e8001 793 if (!nhe->is_kernel_nh && nhe->refcnt <= 0)
cb50cbc9 794 zebra_nhg_uninstall_kernel(nhe);
7fd392cc
SW
795}
796
7fd392cc
SW
797void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
798{
e22e8001
SW
799 nhe->refcnt++;
800
32e29e79
SW
801 if (!zebra_nhg_depends_is_empty(nhe))
802 nhg_connected_head_increment_ref(&nhe->nhg_depends);
e22e8001 803}
d9f5b2f5 804
fe593b78
SW
805void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
806{
055a3fa6
SW
807 if (!zebra_nhg_depends_is_empty(nhe)
808 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) {
809 struct nhg_connected *rb_node_dep = NULL;
810
811 /* If anthing else in the group is valid, the group is valid */
812 RB_FOREACH (rb_node_dep, nhg_connected_head,
813 &nhe->nhg_dependents) {
814 if (CHECK_FLAG(rb_node_dep->nhe->flags,
815 NEXTHOP_GROUP_VALID))
816 return;
817 }
818 }
819
e22e8001
SW
820 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
821 /* Assuming uninstalled as well here */
822 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
fe593b78
SW
823
824 if (!zebra_nhg_dependents_is_empty(nhe)) {
825 struct nhg_connected *rb_node_dep = NULL;
826
827 RB_FOREACH (rb_node_dep, nhg_connected_head,
828 &nhe->nhg_dependents) {
829 zebra_nhg_set_invalid(rb_node_dep->nhe);
830 }
831 }
fe593b78
SW
832}
833
834void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
835{
836 nhe->ifp = ifp;
837 if_nhg_dependents_add(ifp, nhe);
838}
839
ad28e79a
SW
840static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
841 struct nexthop *nexthop)
842{
843 struct nexthop *resolved_hop;
b43434ad
SW
844 uint8_t num_labels = 0;
845 mpls_label_t labels[MPLS_MAX_LABELS];
846 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
847 int i = 0;
ad28e79a
SW
848
849 resolved_hop = nexthop_new();
850 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
851
852 resolved_hop->vrf_id = nexthop->vrf_id;
853 switch (newhop->type) {
854 case NEXTHOP_TYPE_IPV4:
855 case NEXTHOP_TYPE_IPV4_IFINDEX:
856 /* If the resolving route specifies a gateway, use it */
857 resolved_hop->type = newhop->type;
858 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
859
860 if (newhop->ifindex) {
861 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
862 resolved_hop->ifindex = newhop->ifindex;
863 }
864 break;
865 case NEXTHOP_TYPE_IPV6:
866 case NEXTHOP_TYPE_IPV6_IFINDEX:
867 resolved_hop->type = newhop->type;
868 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
869
870 if (newhop->ifindex) {
871 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
872 resolved_hop->ifindex = newhop->ifindex;
873 }
874 break;
875 case NEXTHOP_TYPE_IFINDEX:
876 /* If the resolving route is an interface route,
877 * it means the gateway we are looking up is connected
878 * to that interface. (The actual network is _not_ onlink).
879 * Therefore, the resolved route should have the original
880 * gateway as nexthop as it is directly connected.
881 *
882 * On Linux, we have to set the onlink netlink flag because
883 * otherwise, the kernel won't accept the route.
884 */
885 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
886 if (afi == AFI_IP) {
887 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
888 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
889 } else if (afi == AFI_IP6) {
890 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
891 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
892 }
893 resolved_hop->ifindex = newhop->ifindex;
894 break;
895 case NEXTHOP_TYPE_BLACKHOLE:
896 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 897 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
898 break;
899 }
900
901 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
902 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
903
b43434ad
SW
904 /* Copy labels of the resolved route and the parent resolving to it */
905 if (newhop->nh_label) {
906 for (i = 0; i < newhop->nh_label->num_labels; i++)
907 labels[num_labels++] = newhop->nh_label->label[i];
908 label_type = newhop->nh_label_type;
909 }
910
911 if (nexthop->nh_label) {
912 for (i = 0; i < nexthop->nh_label->num_labels; i++)
913 labels[num_labels++] = nexthop->nh_label->label[i];
914
915 /* If the parent has labels, use its type */
916 label_type = nexthop->nh_label_type;
917 }
918
919 if (num_labels)
920 nexthop_add_labels(resolved_hop, label_type, num_labels,
921 labels);
ad28e79a
SW
922
923 resolved_hop->rparent = nexthop;
50d89650 924 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
925}
926
6913cb1b
SW
927/* Checks if nexthop we are trying to resolve to is valid */
928static bool nexthop_valid_resolve(const struct nexthop *nexthop,
929 const struct nexthop *resolved)
930{
931 /* Can't resolve to a recursive nexthop */
932 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
933 return false;
934
935 switch (nexthop->type) {
936 case NEXTHOP_TYPE_IPV4_IFINDEX:
937 case NEXTHOP_TYPE_IPV6_IFINDEX:
938 /* If the nexthop we are resolving to does not match the
939 * ifindex for the nexthop the route wanted, its not valid.
940 */
941 if (nexthop->ifindex != resolved->ifindex)
942 return false;
943 break;
944 case NEXTHOP_TYPE_IPV4:
945 case NEXTHOP_TYPE_IPV6:
946 case NEXTHOP_TYPE_IFINDEX:
947 case NEXTHOP_TYPE_BLACKHOLE:
948 break;
949 }
950
951 return true;
952}
953
ad28e79a
SW
954/*
955 * Given a nexthop we need to properly recursively resolve
956 * the route. As such, do a table lookup to find and match
98cda54a
SW
957 * if at all possible. Set the nexthop->ifindex and resolved_id
958 * as appropriate
ad28e79a
SW
959 */
960static int nexthop_active(afi_t afi, struct route_entry *re,
8a507796 961 struct nexthop *nexthop, struct route_node *top)
ad28e79a
SW
962{
963 struct prefix p;
964 struct route_table *table;
965 struct route_node *rn;
966 struct route_entry *match = NULL;
967 int resolved;
968 struct nexthop *newhop;
969 struct interface *ifp;
970 rib_dest_t *dest;
5a0bdc78 971 struct zebra_vrf *zvrf;
ad28e79a
SW
972
973 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
974 || nexthop->type == NEXTHOP_TYPE_IPV6)
975 nexthop->ifindex = 0;
976
8a507796 977
ad28e79a
SW
978 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
979 nexthops_free(nexthop->resolved);
980 nexthop->resolved = NULL;
981 re->nexthop_mtu = 0;
982
983 /*
a8c427ee 984 * If the kernel has sent us a NEW route, then
ad28e79a 985 * by golly gee whiz it's a good route.
a8c427ee
SW
986 *
987 * If its an already INSTALLED route we have already handled, then the
988 * kernel route's nexthop might have became unreachable
989 * and we have to handle that.
ad28e79a 990 */
a8c427ee
SW
991 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
992 && (re->type == ZEBRA_ROUTE_KERNEL
993 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
994 return 1;
995
996 /*
997 * Check to see if we should trust the passed in information
998 * for UNNUMBERED interfaces as that we won't find the GW
999 * address in the routing table.
1000 * This check should suffice to handle IPv4 or IPv6 routes
1001 * sourced from EVPN routes which are installed with the
1002 * next hop as the remote VTEP IP.
1003 */
1004 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
1005 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1006 if (!ifp) {
1007 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1008 zlog_debug(
1009 "\t%s: Onlink and interface: %u[%u] does not exist",
1010 __PRETTY_FUNCTION__, nexthop->ifindex,
1011 nexthop->vrf_id);
1012 return 0;
1013 }
1014 if (connected_is_unnumbered(ifp)) {
1015 if (if_is_operative(ifp))
1016 return 1;
2d3c57e6
SW
1017
1018 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1019 zlog_debug(
1020 "\t%s: Onlink and interface %s is not operative",
1021 __PRETTY_FUNCTION__, ifp->name);
1022 return 0;
ad28e79a
SW
1023 }
1024 if (!if_is_operative(ifp)) {
1025 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1026 zlog_debug(
1027 "\t%s: Interface %s is not unnumbered",
1028 __PRETTY_FUNCTION__, ifp->name);
1029 return 0;
1030 }
1031 }
1032
1033 /* Make lookup prefix. */
1034 memset(&p, 0, sizeof(struct prefix));
1035 switch (afi) {
1036 case AFI_IP:
1037 p.family = AF_INET;
1038 p.prefixlen = IPV4_MAX_PREFIXLEN;
1039 p.u.prefix4 = nexthop->gate.ipv4;
1040 break;
1041 case AFI_IP6:
1042 p.family = AF_INET6;
1043 p.prefixlen = IPV6_MAX_PREFIXLEN;
1044 p.u.prefix6 = nexthop->gate.ipv6;
1045 break;
1046 default:
1047 assert(afi != AFI_IP && afi != AFI_IP6);
1048 break;
1049 }
1050 /* Lookup table. */
1051 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
1052 /* get zvrf */
1053 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1054 if (!table || !zvrf) {
ad28e79a
SW
1055 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1056 zlog_debug("\t%s: Table not found",
1057 __PRETTY_FUNCTION__);
1058 return 0;
1059 }
1060
1061 rn = route_node_match(table, (struct prefix *)&p);
1062 while (rn) {
1063 route_unlock_node(rn);
1064
1065 /* Lookup should halt if we've matched against ourselves ('top',
1066 * if specified) - i.e., we cannot have a nexthop NH1 is
1067 * resolved by a route NH1. The exception is if the route is a
1068 * host route.
1069 */
1070 if (top && rn == top)
1071 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
1072 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
1073 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1074 zlog_debug(
1075 "\t%s: Matched against ourself and prefix length is not max bit length",
1076 __PRETTY_FUNCTION__);
1077 return 0;
1078 }
1079
1080 /* Pick up selected route. */
1081 /* However, do not resolve over default route unless explicitly
2d3c57e6
SW
1082 * allowed.
1083 */
ad28e79a 1084 if (is_default_prefix(&rn->p)
5a0bdc78 1085 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
1086 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1087 zlog_debug(
1088 "\t:%s: Resolved against default route",
1089 __PRETTY_FUNCTION__);
1090 return 0;
1091 }
1092
1093 dest = rib_dest_from_rnode(rn);
1094 if (dest && dest->selected_fib
1095 && !CHECK_FLAG(dest->selected_fib->status,
1096 ROUTE_ENTRY_REMOVED)
1097 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
1098 match = dest->selected_fib;
1099
1100 /* If there is no selected route or matched route is EGP, go up
2d3c57e6
SW
1101 * tree.
1102 */
ad28e79a
SW
1103 if (!match) {
1104 do {
1105 rn = rn->parent;
1106 } while (rn && rn->info == NULL);
1107 if (rn)
1108 route_lock_node(rn);
1109
1110 continue;
1111 }
1112
1113 if (match->type == ZEBRA_ROUTE_CONNECT) {
1114 /* Directly point connected route. */
6b468511 1115 newhop = match->ng->nexthop;
ad28e79a
SW
1116 if (newhop) {
1117 if (nexthop->type == NEXTHOP_TYPE_IPV4
1118 || nexthop->type == NEXTHOP_TYPE_IPV6)
1119 nexthop->ifindex = newhop->ifindex;
1120 }
1121 return 1;
1122 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
1123 resolved = 0;
6b468511 1124 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
1125 if (!CHECK_FLAG(match->status,
1126 ROUTE_ENTRY_INSTALLED))
1127 continue;
6913cb1b 1128 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
1129 continue;
1130
1131 SET_FLAG(nexthop->flags,
1132 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
1133 nexthop_set_resolved(afi, newhop, nexthop);
1134 resolved = 1;
1135 }
8a507796 1136 if (resolved)
ad28e79a 1137 re->nexthop_mtu = match->mtu;
8a507796 1138
ad28e79a
SW
1139 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1140 zlog_debug("\t%s: Recursion failed to find",
1141 __PRETTY_FUNCTION__);
1142 return resolved;
1143 } else if (re->type == ZEBRA_ROUTE_STATIC) {
1144 resolved = 0;
6b468511 1145 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
1146 if (!CHECK_FLAG(match->status,
1147 ROUTE_ENTRY_INSTALLED))
1148 continue;
6913cb1b 1149 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
1150 continue;
1151
1152 SET_FLAG(nexthop->flags,
1153 NEXTHOP_FLAG_RECURSIVE);
1154 nexthop_set_resolved(afi, newhop, nexthop);
1155 resolved = 1;
1156 }
8a507796 1157 if (resolved)
ad28e79a 1158 re->nexthop_mtu = match->mtu;
8a507796 1159
ad28e79a
SW
1160 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
1161 zlog_debug(
1162 "\t%s: Static route unable to resolve",
1163 __PRETTY_FUNCTION__);
1164 return resolved;
1165 } else {
1166 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
1167 zlog_debug(
1168 "\t%s: Route Type %s has not turned on recursion",
1169 __PRETTY_FUNCTION__,
1170 zebra_route_string(re->type));
1171 if (re->type == ZEBRA_ROUTE_BGP
1172 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
1173 zlog_debug(
1174 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
1175 }
1176 return 0;
1177 }
1178 }
1179 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1180 zlog_debug("\t%s: Nexthop did not lookup in table",
1181 __PRETTY_FUNCTION__);
1182 return 0;
1183}
1184
1185/* This function verifies reachability of one given nexthop, which can be
1186 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
1187 * in nexthop->flags field. The nexthop->ifindex will be updated
1188 * appropriately as well. An existing route map can turn
1189 * (otherwise active) nexthop into inactive, but not vice versa.
1190 *
98cda54a
SW
1191 * If it finds a nexthop recursivedly, set the resolved_id
1192 * to match that nexthop's nhg_hash_entry ID;
1193 *
ad28e79a
SW
1194 * The return value is the final value of 'ACTIVE' flag.
1195 */
1196static unsigned nexthop_active_check(struct route_node *rn,
1197 struct route_entry *re,
8a507796 1198 struct nexthop *nexthop)
ad28e79a
SW
1199{
1200 struct interface *ifp;
b68885f9 1201 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
1202 int family;
1203 char buf[SRCDEST2STR_BUFFER];
1204 const struct prefix *p, *src_p;
1205 struct zebra_vrf *zvrf;
1206
1207 srcdest_rnode_prefixes(rn, &p, &src_p);
1208
1209 if (rn->p.family == AF_INET)
1210 family = AFI_IP;
1211 else if (rn->p.family == AF_INET6)
1212 family = AFI_IP6;
1213 else
1214 family = 0;
1215 switch (nexthop->type) {
1216 case NEXTHOP_TYPE_IFINDEX:
1217 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1218 if (ifp && if_is_operative(ifp))
1219 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1220 else
1221 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1222 break;
1223 case NEXTHOP_TYPE_IPV4:
1224 case NEXTHOP_TYPE_IPV4_IFINDEX:
1225 family = AFI_IP;
8a507796 1226 if (nexthop_active(AFI_IP, re, nexthop, rn))
ad28e79a
SW
1227 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1228 else
1229 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1230 break;
1231 case NEXTHOP_TYPE_IPV6:
1232 family = AFI_IP6;
8a507796 1233 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
1234 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1235 else
1236 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1237 break;
1238 case NEXTHOP_TYPE_IPV6_IFINDEX:
1239 /* RFC 5549, v4 prefix with v6 NH */
1240 if (rn->p.family != AF_INET)
1241 family = AFI_IP6;
1242 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
1243 ifp = if_lookup_by_index(nexthop->ifindex,
1244 nexthop->vrf_id);
1245 if (ifp && if_is_operative(ifp))
1246 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1247 else
1248 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1249 } else {
8a507796 1250 if (nexthop_active(AFI_IP6, re, nexthop, rn))
ad28e79a
SW
1251 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1252 else
1253 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1254 }
1255 break;
1256 case NEXTHOP_TYPE_BLACKHOLE:
1257 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1258 break;
1259 default:
1260 break;
1261 }
1262 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1263 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1264 zlog_debug("\t%s: Unable to find a active nexthop",
1265 __PRETTY_FUNCTION__);
1266 return 0;
1267 }
1268
1269 /* XXX: What exactly do those checks do? Do we support
1270 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1271 */
1272 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
1273 || (family == AFI_IP6 && p->family != AF_INET6))
1274 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1275
1276 /* The original code didn't determine the family correctly
1277 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1278 * from the rib_table_info in those cases.
1279 * Possibly it may be better to use only the rib_table_info
1280 * in every case.
1281 */
1282 if (!family) {
1283 rib_table_info_t *info;
1284
1285 info = srcdest_rnode_table_info(rn);
1286 family = info->afi;
1287 }
1288
1289 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
1290
1291 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1292 if (!zvrf) {
1293 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1294 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
1295 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1296 }
1297
1298 /* It'll get set if required inside */
1299 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
1300 zvrf, re->tag);
1301 if (ret == RMAP_DENYMATCH) {
1302 if (IS_ZEBRA_DEBUG_RIB) {
1303 srcdest_rnode2str(rn, buf, sizeof(buf));
1304 zlog_debug(
1305 "%u:%s: Filtering out with NH out %s due to route map",
1306 re->vrf_id, buf,
1307 ifindex2ifname(nexthop->ifindex,
1308 nexthop->vrf_id));
1309 }
1310 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1311 }
1312 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1313}
1314
1315/*
1316 * Iterate over all nexthops of the given RIB entry and refresh their
9a0d4dd3
DS
1317 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1318 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
ad28e79a
SW
1319 *
1320 * Return value is the new number of active nexthops.
1321 */
1322int nexthop_active_update(struct route_node *rn, struct route_entry *re)
1323{
98cda54a 1324 struct nexthop_group new_grp = {};
ad28e79a
SW
1325 struct nexthop *nexthop;
1326 union g_addr prev_src;
1327 unsigned int prev_active, new_active;
1328 ifindex_t prev_index;
9a0d4dd3 1329 uint8_t curr_active = 0;
e22e8001 1330
98cda54a 1331 afi_t rt_afi = family2afi(rn->p.family);
e22e8001 1332
98cda54a 1333 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
e22e8001 1334
98cda54a
SW
1335 /* Copy over the nexthops in current state */
1336 nexthop_group_copy(&new_grp, re->ng);
ad28e79a 1337
98cda54a 1338 for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) {
ad28e79a 1339
ad28e79a
SW
1340 /* No protocol daemon provides src and so we're skipping
1341 * tracking it */
1342 prev_src = nexthop->rmap_src;
1343 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1344 prev_index = nexthop->ifindex;
1345 /*
1346 * We need to respect the multipath_num here
1347 * as that what we should be able to install from
1348 * a multipath perpsective should not be a data plane
1349 * decision point.
1350 */
98cda54a 1351 new_active =
8a507796 1352 nexthop_active_check(rn, re, nexthop);
98cda54a 1353
ad28e79a 1354 if (new_active
98cda54a 1355 && nexthop_group_active_nexthop_num(&new_grp)
9a0d4dd3 1356 >= zrouter.multipath_num) {
ad28e79a
SW
1357 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1358 new_active = 0;
1359 }
9a0d4dd3 1360
df31a989 1361 if (new_active)
9a0d4dd3
DS
1362 curr_active++;
1363
ad28e79a
SW
1364 /* Don't allow src setting on IPv6 addr for now */
1365 if (prev_active != new_active || prev_index != nexthop->ifindex
1366 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
1367 && nexthop->type < NEXTHOP_TYPE_IPV6)
1368 && prev_src.ipv4.s_addr
1369 != nexthop->rmap_src.ipv4.s_addr)
1370 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
1371 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
1372 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
1373 &nexthop->rmap_src.ipv6)))
8a507796 1374 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 1375 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
1376 }
1377
8a507796 1378 if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
98cda54a
SW
1379 struct nhg_hash_entry *new_nhe = NULL;
1380 // TODO: Add proto type here
1381
7f997721 1382 new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi);
98cda54a 1383
144a1b34 1384 zebra_nhg_re_update_ref(re, new_nhe);
e22e8001
SW
1385 }
1386
98cda54a
SW
1387 if (curr_active) {
1388 struct nhg_hash_entry *nhe = NULL;
1389
1390 nhe = zebra_nhg_lookup_id(re->nhe_id);
1391
1392 if (nhe) {
1393 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
1394 if (!nhe->is_kernel_nh
1395 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
1396 zebra_nhg_install_kernel(nhe);
1397 } else
1398 flog_err(
1399 EC_ZEBRA_TABLE_LOOKUP_FAILED,
1400 "Active update on NHE id=%u that we do not have in our tables",
1401 re->nhe_id);
1402 }
1403
1404 /*
1405 * Do not need these nexthops anymore since they
1406 * were either copied over into an nhe or not
1407 * used at all.
1408 */
1409 nexthops_free(new_grp.nexthop);
9a0d4dd3 1410 return curr_active;
ad28e79a 1411}
5be96a2d 1412
144a1b34
SW
1413int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new)
1414{
1415 struct nhg_hash_entry *old = NULL;
139ddad8 1416 int ret = 0;
144a1b34 1417
139ddad8
SW
1418 if (new == NULL) {
1419 re->ng = NULL;
1420 goto done;
1421 }
144a1b34
SW
1422
1423 if (re->nhe_id != new->id) {
1424 old = zebra_nhg_lookup_id(re->nhe_id);
1425
1426 re->ng = new->nhg;
1427 re->nhe_id = new->id;
1428
1429 zebra_nhg_increment_ref(new);
1430 if (old)
1431 zebra_nhg_decrement_ref(old);
1432 }
1433
139ddad8
SW
1434done:
1435 return ret;
144a1b34
SW
1436}
1437
98cda54a
SW
1438/* Convert a nhe into a group array */
1439uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe)
1440{
1441 struct nhg_connected *rb_node_dep = NULL;
1442 struct nhg_hash_entry *depend = NULL;
1443 uint8_t i = 0;
1444
1445 RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe->nhg_depends) {
1446 depend = rb_node_dep->nhe;
1447
1448 /*
1449 * If its recursive, use its resolved nhe in the group
1450 */
1451 if (CHECK_FLAG(depend->flags, NEXTHOP_GROUP_RECURSIVE)) {
1452 depend = zebra_nhg_resolve(depend);
1453 if (!depend) {
1454 flog_err(
1455 EC_ZEBRA_NHG_FIB_UPDATE,
df31a989
SW
1456 "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
1457 nhe->id);
98cda54a
SW
1458 continue;
1459 }
1460 }
1461
1462 grp[i].id = depend->id;
1463 /* We aren't using weights for anything right now */
1464 grp[i].weight = 0;
1465 i++;
1466 }
1467 return i;
1468}
1469
5be96a2d
SW
1470void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
1471{
e22e8001
SW
1472 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
1473 && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
147bad16
SW
1474 nhe->is_kernel_nh = false;
1475 int ret = dplane_nexthop_add(nhe);
2d3c57e6 1476
147bad16
SW
1477 switch (ret) {
1478 case ZEBRA_DPLANE_REQUEST_QUEUED:
1479 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1480 break;
1481 case ZEBRA_DPLANE_REQUEST_FAILURE:
1482 flog_err(
1483 EC_ZEBRA_DP_INSTALL_FAIL,
1484 "Failed to install Nexthop ID (%u) into the kernel",
1485 nhe->id);
1486 break;
1487 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1488 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1489 break;
1490 }
1491 }
1492}
1493
147bad16
SW
1494void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
1495{
8a507796 1496 zlog_debug("Uninstalling NHE ID: %u", nhe->id);
147bad16
SW
1497 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1498 int ret = dplane_nexthop_delete(nhe);
2d3c57e6 1499
147bad16
SW
1500 switch (ret) {
1501 case ZEBRA_DPLANE_REQUEST_QUEUED:
1502 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1503 break;
1504 case ZEBRA_DPLANE_REQUEST_FAILURE:
1505 flog_err(
1506 EC_ZEBRA_DP_DELETE_FAIL,
1507 "Failed to uninstall Nexthop ID (%u) from the kernel",
1508 nhe->id);
1509 break;
1510 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1511 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
e22e8001 1512 zebra_nhg_release(nhe);
147bad16
SW
1513 break;
1514 }
e22e8001
SW
1515 } else
1516 zebra_nhg_release(nhe);
147bad16
SW
1517}
1518
3e0372d2
SW
1519static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
1520{
1521 struct nhg_hash_entry *nhe = NULL;
1522
1523 nhe = (struct nhg_hash_entry *)bucket->data;
1524
1525 if (nhe && !nhe->is_kernel_nh)
1526 zebra_nhg_uninstall_kernel(nhe);
1527}
1528
3e0372d2
SW
1529void zebra_nhg_cleanup_tables(void)
1530{
5155d86c
SW
1531 // TODO: These should only be uninstalled via route cleanup
1532 // path?
1533 return;
3e0372d2
SW
1534 hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL);
1535}
1536
5f3c9e52
SW
1537void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
1538{
1539 enum dplane_op_e op;
1540 enum zebra_dplane_result status;
1541 uint32_t id = 0;
1542 struct nhg_hash_entry *nhe = NULL;
1543
1544 op = dplane_ctx_get_op(ctx);
1545 status = dplane_ctx_get_status(ctx);
1546
0c8215cb 1547 id = dplane_ctx_get_nhe_id(ctx);
e22e8001 1548
5f3c9e52
SW
1549 nhe = zebra_nhg_lookup_id(id);
1550
1551 if (nhe) {
7512f617 1552 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
5f3c9e52
SW
1553 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1554 zlog_debug(
1555 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1556 ctx, dplane_op2str(op), nhe->id,
1557 dplane_res2str(status));
1558
1559 switch (op) {
1560 case DPLANE_OP_NH_DELETE:
1561 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1562 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
e22e8001 1563 zebra_nhg_release(nhe);
5f3c9e52
SW
1564 } else {
1565 flog_err(
1566 EC_ZEBRA_DP_DELETE_FAIL,
1567 "Failed to uninstall Nexthop ID (%u) from the kernel",
1568 nhe->id);
1569 }
1570 break;
1571 case DPLANE_OP_NH_INSTALL:
1572 case DPLANE_OP_NH_UPDATE:
1573 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1574 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1575 } else {
1576 flog_err(
1577 EC_ZEBRA_DP_INSTALL_FAIL,
1578 "Failed to install Nexthop ID (%u) into the kernel",
1579 nhe->id);
1580 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1581 }
5f3c9e52
SW
1582 break;
1583 case DPLANE_OP_ROUTE_INSTALL:
1584 case DPLANE_OP_ROUTE_UPDATE:
1585 case DPLANE_OP_ROUTE_DELETE:
1586 case DPLANE_OP_ROUTE_NOTIFY:
1587 case DPLANE_OP_LSP_INSTALL:
1588 case DPLANE_OP_LSP_UPDATE:
1589 case DPLANE_OP_LSP_DELETE:
1590 case DPLANE_OP_LSP_NOTIFY:
1591 case DPLANE_OP_PW_INSTALL:
1592 case DPLANE_OP_PW_UNINSTALL:
1593 case DPLANE_OP_SYS_ROUTE_ADD:
1594 case DPLANE_OP_SYS_ROUTE_DELETE:
1595 case DPLANE_OP_ADDR_INSTALL:
1596 case DPLANE_OP_ADDR_UNINSTALL:
1597 case DPLANE_OP_MAC_INSTALL:
1598 case DPLANE_OP_MAC_DELETE:
1599 case DPLANE_OP_NONE:
1600 break;
1601 }
71593b3f 1602 } else
5f3c9e52
SW
1603 flog_err(
1604 EC_ZEBRA_NHG_SYNC,
1605 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1606 dplane_op2str(op), id);
71593b3f
SW
1607
1608 dplane_ctx_fini(&ctx);
5be96a2d
SW
1609}
1610