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