]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
zebra,lib: Refactor depends to RB tree
[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"
d9f5b2f5 43
51d80884 44DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
0c8215cb
SW
45DEFINE_MTYPE_STATIC(ZEBRA, NHG_DEPEND, "Nexthop Group Dependency");
46
47static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1,
48 const struct nhg_depend *dep2);
49
50RB_GENERATE(nhg_depends_head, nhg_depend, depend, zebra_nhg_depend_cmp);
51
52static void nhg_depend_free(struct nhg_depend *dep)
53{
54 XFREE(MTYPE_NHG_DEPEND, dep);
55}
56
57static struct nhg_depend *nhg_depend_new(struct nhg_hash_entry *nhe)
58{
59 struct nhg_depend *new = NULL;
60
61 new = XCALLOC(MTYPE_NHG_DEPEND, sizeof(struct nhg_depend));
62 new->nhe = nhe;
63
64 return new;
65}
66
67static uint8_t zebra_nhg_depends_head_count(const struct nhg_depends_head *head)
68{
69 struct nhg_depend *rb_node_dep = NULL;
70 uint8_t i = 0;
71
72 RB_FOREACH (rb_node_dep, nhg_depends_head, head) {
73 i++;
74 }
75 return i;
76}
77
78uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
79{
80 return zebra_nhg_depends_head_count(&nhe->nhg_depends);
81}
82
83static bool zebra_nhg_depends_head_is_empty(const struct nhg_depends_head *head)
84{
85 return RB_EMPTY(nhg_depends_head, head);
86}
3119f6a1
SW
87
88/**
0c8215cb 89 * zebra_nhg_depends_is_empty() - Are there any dependencies
3119f6a1 90 *
0c8215cb 91 * @nhe: Nexthop group hash entry
3119f6a1 92 *
0c8215cb 93 * Return: True if empty, False otherwise
3119f6a1 94 */
0c8215cb 95bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
3119f6a1 96{
0c8215cb
SW
97 return zebra_nhg_depends_head_is_empty(&nhe->nhg_depends);
98}
99
100void zebra_nhg_depends_head_del(struct nhg_depends_head *head,
101 struct nhg_hash_entry *depend)
102{
103 struct nhg_depend lookup = {};
104 struct nhg_depend *removed = NULL;
105
106 lookup.nhe = depend;
3119f6a1 107
0c8215cb 108 removed = RB_REMOVE(nhg_depends_head, head, &lookup);
3119f6a1 109
0c8215cb 110 nhg_depend_free(removed);
3119f6a1
SW
111}
112
0c8215cb
SW
113// TODO: Refactor this for use with dependents as well
114void zebra_nhg_depends_head_add(struct nhg_depends_head *head,
115 struct nhg_hash_entry *depend)
3119f6a1 116{
0c8215cb
SW
117 struct nhg_depend *new = NULL;
118
119 new = nhg_depend_new(depend);
120
121 RB_INSERT(nhg_depends_head, head, new);
3119f6a1
SW
122}
123
124/**
0c8215cb
SW
125 * zebra_nhg_depend_del() - Delete a dependency from the nhg_hash_entry
126 *
127 * @from: Nexthop group hash entry we are deleting from
128 * @depend: Dependency we are deleting
3119f6a1 129 */
0c8215cb
SW
130void zebra_nhg_depends_del(struct nhg_hash_entry *from,
131 struct nhg_hash_entry *depend)
3119f6a1 132{
0c8215cb 133 zebra_nhg_depends_head_del(&from->nhg_depends, depend);
3119f6a1
SW
134}
135
136/**
0c8215cb 137 * zebra_nhg_depends_add() - Add a new dependency to the nhg_hash_entry
3119f6a1 138 *
0c8215cb
SW
139 * @to: Nexthop group hash entry we are adding to
140 * @depend: Dependency we are adding
3119f6a1 141 */
0c8215cb
SW
142void zebra_nhg_depends_add(struct nhg_hash_entry *to,
143 struct nhg_hash_entry *depend)
3119f6a1 144{
0c8215cb 145 zebra_nhg_depends_head_add(&to->nhg_depends, depend);
3119f6a1
SW
146}
147
d6e0094f 148/**
0c8215cb 149 * zebra_nhg_depends_head_init() - Helper to init the RB tree head directly
d6e0094f 150 *
0c8215cb 151 * @head: RB nhg_depends_head struct
d6e0094f 152 */
0c8215cb 153void zebra_nhg_depends_head_init(struct nhg_depends_head *head)
d6e0094f 154{
0c8215cb 155 RB_INIT(nhg_depends_head, head);
d6e0094f
SW
156}
157
148a0103 158/**
0c8215cb 159 * zebra_nhg_depends_init() - Initialize tree for nhg dependencies
148a0103 160 *
0c8215cb 161 * @nhe: Nexthop group hash entry
148a0103 162 */
0c8215cb 163void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
148a0103 164{
0c8215cb 165 zebra_nhg_depends_head_init(&nhe->nhg_depends);
148a0103
SW
166}
167
0c8215cb 168
20822f9d
SW
169/**
170 * zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal
171 *
172 * @nhe1: Nexthop group hash entry
173 * @nhe2: Nexthop group hash entry
174 *
175 * Return: True if equal
176 *
177 * We don't care about ordering of the dependencies. If they contain
178 * the same nhe ID's, they are equivalent.
179 */
180static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1,
181 const struct nhg_hash_entry *nhe2)
182{
0c8215cb 183 struct nhg_depend *rb_node_dep = NULL;
20822f9d 184
0c8215cb
SW
185 if (zebra_nhg_depends_is_empty(nhe1)
186 && zebra_nhg_depends_is_empty(nhe2))
20822f9d
SW
187 return true;
188
0c8215cb
SW
189 if ((zebra_nhg_depends_is_empty(nhe1)
190 && !zebra_nhg_depends_is_empty(nhe2))
191 || (zebra_nhg_depends_is_empty(nhe2)
192 && !zebra_nhg_depends_is_empty(nhe1)))
20822f9d
SW
193 return false;
194
0c8215cb
SW
195 RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe1->nhg_depends) {
196 if (!RB_FIND(nhg_depends_head, &nhe2->nhg_depends, rb_node_dep))
20822f9d
SW
197 return false;
198 }
199
200 return true;
201}
202
d9f5b2f5
SW
203/**
204 * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
205 *
206 * @id: ID to look for
207 *
208 * Return: Nexthop hash entry if found/NULL if not found
209 */
210struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
211{
0c8215cb 212 struct nhg_hash_entry lookup = {};
d9f5b2f5
SW
213
214 lookup.id = id;
215 return hash_lookup(zrouter.nhgs_id, &lookup);
216}
217
218/**
219 * zebra_nhg_insert_id() - Insert a nhe into the id hashed table
220 *
221 * @nhe: The entry directly from the other table
222 *
223 * Return: Result status
224 */
225int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
226{
227 if (hash_lookup(zrouter.nhgs_id, nhe)) {
228 flog_err(
229 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
230 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
231 nhe->id);
232 return -1;
233 }
234
235 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
236
237 return 0;
238}
ad28e79a 239
4e49c8b8
DS
240
241static void *zebra_nhg_alloc(void *arg)
242{
243 struct nhg_hash_entry *nhe;
244 struct nhg_hash_entry *copy = arg;
245
51d80884 246 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
d9f5b2f5 247
5bd81e4c
SW
248
249 nhe->id = copy->id;
4e49c8b8 250
0c8215cb 251 nhe->nhg_depends = copy->nhg_depends;
8e401b25 252
2d6cd1f0
SW
253 nhe->nhg = nexthop_group_new();
254 nexthop_group_copy(nhe->nhg, copy->nhg);
3119f6a1 255
4e49c8b8 256 nhe->vrf_id = copy->vrf_id;
77b76fc9 257 nhe->afi = copy->afi;
4e49c8b8 258 nhe->refcnt = 0;
9ed6c34a 259 nhe->is_kernel_nh = copy->is_kernel_nh;
4e49c8b8 260 nhe->dplane_ref = zebra_router_get_next_sequence();
2614bf87 261 nhe->ifp = NULL;
4e49c8b8 262
4e49c8b8 263
d9f5b2f5
SW
264 /* Add to id table as well */
265 zebra_nhg_insert_id(nhe);
266
4e49c8b8 267
20822f9d
SW
268 /* Send it to the kernel */
269 if (!nhe->is_kernel_nh)
270 zebra_nhg_install_kernel(nhe);
271
4e49c8b8
DS
272 return nhe;
273}
274
4e49c8b8
DS
275uint32_t zebra_nhg_hash_key(const void *arg)
276{
277 const struct nhg_hash_entry *nhe = arg;
d9f5b2f5 278
7286ac02 279 uint32_t key = 0x5a351234;
4e49c8b8 280
77b76fc9 281 key = jhash_2words(nhe->vrf_id, nhe->afi, key);
4e49c8b8 282
0c8215cb 283 key = jhash_1word(nexthop_group_hash(nhe->nhg), key);
d9f5b2f5 284
d9f5b2f5 285 return key;
4e49c8b8
DS
286}
287
a95b8020
SW
288uint32_t zebra_nhg_id_key(const void *arg)
289{
290 const struct nhg_hash_entry *nhe = arg;
291
292 return nhe->id;
293}
294
4e49c8b8
DS
295bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
296{
297 const struct nhg_hash_entry *nhe1 = arg1;
298 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8
DS
299
300 if (nhe1->vrf_id != nhe2->vrf_id)
301 return false;
302
77b76fc9
SW
303 if (nhe1->afi != nhe2->afi)
304 return false;
305
20822f9d
SW
306 if (!zebra_nhg_depends_equal(nhe1, nhe2))
307 return false;
4e49c8b8
DS
308
309 return true;
310}
311
d9f5b2f5 312bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 313{
d9f5b2f5
SW
314 const struct nhg_hash_entry *nhe1 = arg1;
315 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 316
d9f5b2f5
SW
317 return nhe1->id == nhe2->id;
318}
4e49c8b8 319
0c8215cb
SW
320/**
321 * zebra_nhg_cmp() - Compare the ID's of two nhe's
322 *
323 * @nhe1: Nexthop group hash entry #1
324 * @nhe2: Nexthop group hash entry #2
325 *
326 * Return:
327 * - Negative: #1 < #2
328 * - Positive: #1 > #2
329 * - Zero: #1 = #2
330 *
331 * This is used in the nhg RB trees.
332 */
333static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1,
334 const struct nhg_hash_entry *nhe2)
335{
336 return nhe1->id - nhe2->id;
337}
338
339static int zebra_nhg_depend_cmp(const struct nhg_depend *dep1,
340 const struct nhg_depend *dep2)
341{
342 return zebra_nhg_cmp(dep1->nhe, dep2->nhe);
343}
344
d9f5b2f5
SW
345/**
346 * zebra_nhg_find() - Find the zebra nhg in our table, or create it
347 *
8e401b25
SW
348 * @nhg: Nexthop group we lookup with
349 * @vrf_id: VRF id
350 * @afi: Address Family type
351 * @id: ID we lookup with, 0 means its from us and we
352 * need to give it an ID, otherwise its from the
353 * kernel as we use the ID it gave us.
0c8215cb 354 * @nhg_depends: Nexthop dependency tree head
9ed6c34a 355 * @is_kernel_nh: Was the nexthop created by the kernel
d9f5b2f5 356 *
8e401b25 357 * Return: Hash entry found or created
85f5e761
SW
358 *
359 * The nhg and n_grp are fundementally the same thing (a group of nexthops).
360 * We are just using the nhg representation with routes and the n_grp
361 * is what the kernel gives us (a list of IDs). Our nhg_hash_entry
362 * will contain both.
363 *
364 * nhg_hash_entry example:
365 *
366 * nhe:
367 * ->nhg:
368 * .nexthop->nexthop->nexthop
369 * ->nhg_depends:
370 * .nhe->nhe->nhe
371 *
372 * Routes will use the nhg directly, and any updating of nexthops
373 * we have to do or flag setting, we use the nhg_depends.
374 *
d9f5b2f5
SW
375 */
376struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
85f5e761 377 vrf_id_t vrf_id, afi_t afi, uint32_t id,
0c8215cb 378 struct nhg_depends_head *nhg_depends,
9ed6c34a 379 bool is_kernel_nh)
a95b8020 380{
5bd81e4c
SW
381 /* lock for getiing and setting the id */
382 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
383 /* id counter to keep in sync with kernel */
384 static uint32_t id_counter = 0;
385
0c8215cb 386 struct nhg_hash_entry lookup = {};
d9f5b2f5 387 struct nhg_hash_entry *nhe = NULL;
5bd81e4c
SW
388 uint32_t old_id_counter = 0;
389
390 pthread_mutex_lock(&lock); /* Lock, set the id counter */
391
392 old_id_counter = id_counter;
393
394 if (id) {
395 if (id > id_counter) {
396 /* Increase our counter so we don't try to create
397 * an ID that already exists
398 */
399 id_counter = id;
400 }
401 lookup.id = id;
402 } else {
403 lookup.id = ++id_counter;
404 }
a95b8020 405
d9f5b2f5 406 lookup.vrf_id = vrf_id;
77b76fc9 407 lookup.afi = afi;
b599cd2a 408 lookup.nhg = nhg;
0c8215cb 409 lookup.nhg_depends = *nhg_depends;
9ed6c34a 410 lookup.is_kernel_nh = is_kernel_nh;
a95b8020 411
b599cd2a
SW
412 if (id)
413 nhe = zebra_nhg_lookup_id(id);
414 else
415 nhe = hash_lookup(zrouter.nhgs, &lookup);
d9f5b2f5 416
5bd81e4c
SW
417 /* If it found an nhe in our tables, this new ID is unused */
418 if (nhe)
419 id_counter = old_id_counter;
420
421 pthread_mutex_unlock(&lock);
422
2d6cd1f0 423 if (!nhe)
d9f5b2f5 424 nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
d9f5b2f5
SW
425
426 return nhe;
a95b8020
SW
427}
428
3057df51
SW
429/**
430 * zebra_nhg_find_nexthop() - Create a group with a single nexthop, find it in
431 * our table, or create it
432 *
433 * @nh: Nexthop to lookup
434 * @afi: Address Family type
435 *
436 * Return: Hash entry found or created
437 */
438struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi)
439{
440 struct nhg_hash_entry *nhe = NULL;
441
442 struct nexthop_group *nhg = nexthop_group_new();
443
444 nexthop_group_add_sorted(nhg, nh);
445 nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false);
446
447 nexthop_group_delete(&nhg);
448
449 return nhe;
450}
451
0c8215cb
SW
452void zebra_nhg_depends_free(struct nhg_depends_head *head)
453{
454 struct nhg_depend *rb_node_dep = NULL;
455 struct nhg_depend *tmp = NULL;
456
457 if (!zebra_nhg_depends_head_is_empty(head)) {
458 RB_FOREACH_SAFE (rb_node_dep, nhg_depends_head, head, tmp) {
459 RB_REMOVE(nhg_depends_head, head, rb_node_dep);
460 nhg_depend_free(rb_node_dep);
461 }
462 }
463}
464
b599cd2a
SW
465/**
466 * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group
467 * struct and depends
468 *
0c8215cb
SW
469 * @nhg: Nexthop_group
470 * @nhg_depends: Nexthop group dependency tree head
b599cd2a 471 */
0c8215cb
SW
472void zebra_nhg_free_group_depends(struct nexthop_group **nhg,
473 struct nhg_depends_head *head)
b599cd2a 474{
0c8215cb
SW
475 if (head)
476 zebra_nhg_depends_free(head);
477
478 if (nhg)
479 nexthop_group_free_delete(nhg);
b599cd2a
SW
480}
481
482/**
483 * zebra_nhg_free_members() - Free all members in the hash entry struct
484 *
485 * @nhe: Nexthop group hash entry
486 *
487 * Just use this to free everything but the entry itself.
488 */
489void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
490{
0c8215cb 491 zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends);
b599cd2a
SW
492}
493
d9f5b2f5
SW
494/**
495 * zebra_nhg_free() - Free the nexthop group hash entry
496 *
497 * arg: Nexthop group entry to free
498 */
499void zebra_nhg_free(void *arg)
a95b8020 500{
d9f5b2f5 501 struct nhg_hash_entry *nhe = NULL;
a95b8020 502
d9f5b2f5 503 nhe = (struct nhg_hash_entry *)arg;
a95b8020 504
8e401b25 505 zebra_nhg_free_members(nhe);
51d80884
SW
506
507 XFREE(MTYPE_NHG, nhe);
a95b8020
SW
508}
509
d9f5b2f5
SW
510/**
511 * zebra_nhg_release() - Release a nhe from the tables
512 *
513 * @nhe: Nexthop group hash entry
514 */
515void zebra_nhg_release(struct nhg_hash_entry *nhe)
4e49c8b8 516{
7512f617
SW
517 if (!nhe->refcnt) {
518 zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
519 hash_release(zrouter.nhgs, nhe);
520 hash_release(zrouter.nhgs_id, nhe);
521 zebra_nhg_free(nhe);
522 }
523}
4e49c8b8 524
7512f617
SW
525/**
526 * zebra_nhg_uninstall_release() - Unistall and release a nhe
527 *
528 * @nhe: Nexthop group hash entry
529 */
530static void zebra_nhg_uninstall_release(struct nhg_hash_entry *nhe)
531{
532 zebra_nhg_uninstall_kernel(nhe);
533 // zebra_nhg_release(nhe);
d9f5b2f5 534}
4e49c8b8 535
d9f5b2f5
SW
536/**
537 * zebra_nhg_decrement_ref() - Decrement the reference count, release if unused
538 *
539 * @nhe: Nexthop group hash entry
540 *
541 * If the counter hits 0 and is not a nexthop group that was created by the
542 * kernel, we don't need to have it in our table anymore.
543 */
544void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
545{
0c8215cb
SW
546 if (!zebra_nhg_depends_is_empty(nhe)) {
547 struct nhg_depend *rb_node_dep = NULL;
f54ef6a5 548
0c8215cb
SW
549 RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) {
550 zebra_nhg_decrement_ref(rb_node_dep->nhe);
f54ef6a5
SW
551 }
552 }
553
4e49c8b8
DS
554 nhe->refcnt--;
555
d9f5b2f5 556 if (!nhe->is_kernel_nh && nhe->refcnt <= 0) {
7512f617 557 zebra_nhg_uninstall_release(nhe);
d9f5b2f5 558 }
7fd392cc
SW
559}
560
561/**
562 * zebra_nhg_increment_ref() - Increment the reference count
563 *
564 * @nhe: Nexthop group hash entry
565 */
566void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
567{
0c8215cb
SW
568 if (!zebra_nhg_depends_is_empty(nhe)) {
569 struct nhg_depend *rb_node_dep = NULL;
7fd392cc 570
0c8215cb
SW
571 RB_FOREACH (rb_node_dep, nhg_depends_head, &nhe->nhg_depends) {
572 zebra_nhg_increment_ref(rb_node_dep->nhe);
7fd392cc
SW
573 }
574 }
d9f5b2f5 575
7fd392cc 576 nhe->refcnt++;
4e49c8b8
DS
577}
578
ad28e79a
SW
579static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
580 struct nexthop *nexthop)
581{
582 struct nexthop *resolved_hop;
b43434ad
SW
583 uint8_t num_labels = 0;
584 mpls_label_t labels[MPLS_MAX_LABELS];
585 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
586 int i = 0;
ad28e79a
SW
587
588 resolved_hop = nexthop_new();
589 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
590
591 resolved_hop->vrf_id = nexthop->vrf_id;
592 switch (newhop->type) {
593 case NEXTHOP_TYPE_IPV4:
594 case NEXTHOP_TYPE_IPV4_IFINDEX:
595 /* If the resolving route specifies a gateway, use it */
596 resolved_hop->type = newhop->type;
597 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
598
599 if (newhop->ifindex) {
600 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
601 resolved_hop->ifindex = newhop->ifindex;
602 }
603 break;
604 case NEXTHOP_TYPE_IPV6:
605 case NEXTHOP_TYPE_IPV6_IFINDEX:
606 resolved_hop->type = newhop->type;
607 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
608
609 if (newhop->ifindex) {
610 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
611 resolved_hop->ifindex = newhop->ifindex;
612 }
613 break;
614 case NEXTHOP_TYPE_IFINDEX:
615 /* If the resolving route is an interface route,
616 * it means the gateway we are looking up is connected
617 * to that interface. (The actual network is _not_ onlink).
618 * Therefore, the resolved route should have the original
619 * gateway as nexthop as it is directly connected.
620 *
621 * On Linux, we have to set the onlink netlink flag because
622 * otherwise, the kernel won't accept the route.
623 */
624 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
625 if (afi == AFI_IP) {
626 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
627 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
628 } else if (afi == AFI_IP6) {
629 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
630 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
631 }
632 resolved_hop->ifindex = newhop->ifindex;
633 break;
634 case NEXTHOP_TYPE_BLACKHOLE:
635 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 636 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
637 break;
638 }
639
640 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
641 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
642
b43434ad
SW
643 /* Copy labels of the resolved route and the parent resolving to it */
644 if (newhop->nh_label) {
645 for (i = 0; i < newhop->nh_label->num_labels; i++)
646 labels[num_labels++] = newhop->nh_label->label[i];
647 label_type = newhop->nh_label_type;
648 }
649
650 if (nexthop->nh_label) {
651 for (i = 0; i < nexthop->nh_label->num_labels; i++)
652 labels[num_labels++] = nexthop->nh_label->label[i];
653
654 /* If the parent has labels, use its type */
655 label_type = nexthop->nh_label_type;
656 }
657
658 if (num_labels)
659 nexthop_add_labels(resolved_hop, label_type, num_labels,
660 labels);
ad28e79a
SW
661
662 resolved_hop->rparent = nexthop;
50d89650 663 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
664}
665
6913cb1b
SW
666/* Checks if nexthop we are trying to resolve to is valid */
667static bool nexthop_valid_resolve(const struct nexthop *nexthop,
668 const struct nexthop *resolved)
669{
670 /* Can't resolve to a recursive nexthop */
671 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
672 return false;
673
674 switch (nexthop->type) {
675 case NEXTHOP_TYPE_IPV4_IFINDEX:
676 case NEXTHOP_TYPE_IPV6_IFINDEX:
677 /* If the nexthop we are resolving to does not match the
678 * ifindex for the nexthop the route wanted, its not valid.
679 */
680 if (nexthop->ifindex != resolved->ifindex)
681 return false;
682 break;
683 case NEXTHOP_TYPE_IPV4:
684 case NEXTHOP_TYPE_IPV6:
685 case NEXTHOP_TYPE_IFINDEX:
686 case NEXTHOP_TYPE_BLACKHOLE:
687 break;
688 }
689
690 return true;
691}
692
ad28e79a
SW
693/*
694 * Given a nexthop we need to properly recursively resolve
695 * the route. As such, do a table lookup to find and match
696 * if at all possible. Set the nexthop->ifindex as appropriate
697 */
698static int nexthop_active(afi_t afi, struct route_entry *re,
699 struct nexthop *nexthop, struct route_node *top)
700{
701 struct prefix p;
702 struct route_table *table;
703 struct route_node *rn;
704 struct route_entry *match = NULL;
705 int resolved;
706 struct nexthop *newhop;
707 struct interface *ifp;
708 rib_dest_t *dest;
5a0bdc78 709 struct zebra_vrf *zvrf;
ad28e79a
SW
710
711 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
712 || nexthop->type == NEXTHOP_TYPE_IPV6)
713 nexthop->ifindex = 0;
714
715 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
716 nexthops_free(nexthop->resolved);
717 nexthop->resolved = NULL;
718 re->nexthop_mtu = 0;
719
720 /*
a8c427ee 721 * If the kernel has sent us a NEW route, then
ad28e79a 722 * by golly gee whiz it's a good route.
a8c427ee
SW
723 *
724 * If its an already INSTALLED route we have already handled, then the
725 * kernel route's nexthop might have became unreachable
726 * and we have to handle that.
ad28e79a 727 */
a8c427ee
SW
728 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
729 && (re->type == ZEBRA_ROUTE_KERNEL
730 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
731 return 1;
732
733 /*
734 * Check to see if we should trust the passed in information
735 * for UNNUMBERED interfaces as that we won't find the GW
736 * address in the routing table.
737 * This check should suffice to handle IPv4 or IPv6 routes
738 * sourced from EVPN routes which are installed with the
739 * next hop as the remote VTEP IP.
740 */
741 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
742 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
743 if (!ifp) {
744 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
745 zlog_debug(
746 "\t%s: Onlink and interface: %u[%u] does not exist",
747 __PRETTY_FUNCTION__, nexthop->ifindex,
748 nexthop->vrf_id);
749 return 0;
750 }
751 if (connected_is_unnumbered(ifp)) {
752 if (if_is_operative(ifp))
753 return 1;
754 else {
755 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
756 zlog_debug(
757 "\t%s: Onlink and interface %s is not operative",
758 __PRETTY_FUNCTION__, ifp->name);
759 return 0;
760 }
761 }
762 if (!if_is_operative(ifp)) {
763 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
764 zlog_debug(
765 "\t%s: Interface %s is not unnumbered",
766 __PRETTY_FUNCTION__, ifp->name);
767 return 0;
768 }
769 }
770
771 /* Make lookup prefix. */
772 memset(&p, 0, sizeof(struct prefix));
773 switch (afi) {
774 case AFI_IP:
775 p.family = AF_INET;
776 p.prefixlen = IPV4_MAX_PREFIXLEN;
777 p.u.prefix4 = nexthop->gate.ipv4;
778 break;
779 case AFI_IP6:
780 p.family = AF_INET6;
781 p.prefixlen = IPV6_MAX_PREFIXLEN;
782 p.u.prefix6 = nexthop->gate.ipv6;
783 break;
784 default:
785 assert(afi != AFI_IP && afi != AFI_IP6);
786 break;
787 }
788 /* Lookup table. */
789 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
790 /* get zvrf */
791 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
792 if (!table || !zvrf) {
ad28e79a
SW
793 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
794 zlog_debug("\t%s: Table not found",
795 __PRETTY_FUNCTION__);
796 return 0;
797 }
798
799 rn = route_node_match(table, (struct prefix *)&p);
800 while (rn) {
801 route_unlock_node(rn);
802
803 /* Lookup should halt if we've matched against ourselves ('top',
804 * if specified) - i.e., we cannot have a nexthop NH1 is
805 * resolved by a route NH1. The exception is if the route is a
806 * host route.
807 */
808 if (top && rn == top)
809 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
810 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
811 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
812 zlog_debug(
813 "\t%s: Matched against ourself and prefix length is not max bit length",
814 __PRETTY_FUNCTION__);
815 return 0;
816 }
817
818 /* Pick up selected route. */
819 /* However, do not resolve over default route unless explicitly
820 * allowed. */
821 if (is_default_prefix(&rn->p)
5a0bdc78 822 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
823 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
824 zlog_debug(
825 "\t:%s: Resolved against default route",
826 __PRETTY_FUNCTION__);
827 return 0;
828 }
829
830 dest = rib_dest_from_rnode(rn);
831 if (dest && dest->selected_fib
832 && !CHECK_FLAG(dest->selected_fib->status,
833 ROUTE_ENTRY_REMOVED)
834 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
835 match = dest->selected_fib;
836
837 /* If there is no selected route or matched route is EGP, go up
838 tree. */
839 if (!match) {
840 do {
841 rn = rn->parent;
842 } while (rn && rn->info == NULL);
843 if (rn)
844 route_lock_node(rn);
845
846 continue;
847 }
848
849 if (match->type == ZEBRA_ROUTE_CONNECT) {
850 /* Directly point connected route. */
6b468511 851 newhop = match->ng->nexthop;
ad28e79a
SW
852 if (newhop) {
853 if (nexthop->type == NEXTHOP_TYPE_IPV4
854 || nexthop->type == NEXTHOP_TYPE_IPV6)
855 nexthop->ifindex = newhop->ifindex;
856 }
857 return 1;
858 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
859 resolved = 0;
6b468511 860 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
861 if (!CHECK_FLAG(match->status,
862 ROUTE_ENTRY_INSTALLED))
863 continue;
6913cb1b 864 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
865 continue;
866
867 SET_FLAG(nexthop->flags,
868 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
869 nexthop_set_resolved(afi, newhop, nexthop);
870 resolved = 1;
871 }
872 if (resolved)
873 re->nexthop_mtu = match->mtu;
874 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
875 zlog_debug("\t%s: Recursion failed to find",
876 __PRETTY_FUNCTION__);
877 return resolved;
878 } else if (re->type == ZEBRA_ROUTE_STATIC) {
879 resolved = 0;
6b468511 880 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
881 if (!CHECK_FLAG(match->status,
882 ROUTE_ENTRY_INSTALLED))
883 continue;
6913cb1b 884 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
885 continue;
886
887 SET_FLAG(nexthop->flags,
888 NEXTHOP_FLAG_RECURSIVE);
889 nexthop_set_resolved(afi, newhop, nexthop);
890 resolved = 1;
891 }
892 if (resolved)
893 re->nexthop_mtu = match->mtu;
894
895 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
896 zlog_debug(
897 "\t%s: Static route unable to resolve",
898 __PRETTY_FUNCTION__);
899 return resolved;
900 } else {
901 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
902 zlog_debug(
903 "\t%s: Route Type %s has not turned on recursion",
904 __PRETTY_FUNCTION__,
905 zebra_route_string(re->type));
906 if (re->type == ZEBRA_ROUTE_BGP
907 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
908 zlog_debug(
909 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
910 }
911 return 0;
912 }
913 }
914 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
915 zlog_debug("\t%s: Nexthop did not lookup in table",
916 __PRETTY_FUNCTION__);
917 return 0;
918}
919
920/* This function verifies reachability of one given nexthop, which can be
921 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
922 * in nexthop->flags field. The nexthop->ifindex will be updated
923 * appropriately as well. An existing route map can turn
924 * (otherwise active) nexthop into inactive, but not vice versa.
925 *
926 * The return value is the final value of 'ACTIVE' flag.
927 */
928static unsigned nexthop_active_check(struct route_node *rn,
929 struct route_entry *re,
930 struct nexthop *nexthop)
931{
932 struct interface *ifp;
b68885f9 933 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
934 int family;
935 char buf[SRCDEST2STR_BUFFER];
936 const struct prefix *p, *src_p;
937 struct zebra_vrf *zvrf;
938
939 srcdest_rnode_prefixes(rn, &p, &src_p);
940
941 if (rn->p.family == AF_INET)
942 family = AFI_IP;
943 else if (rn->p.family == AF_INET6)
944 family = AFI_IP6;
945 else
946 family = 0;
947 switch (nexthop->type) {
948 case NEXTHOP_TYPE_IFINDEX:
949 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
950 if (ifp && if_is_operative(ifp))
951 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
952 else
953 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
954 break;
955 case NEXTHOP_TYPE_IPV4:
956 case NEXTHOP_TYPE_IPV4_IFINDEX:
957 family = AFI_IP;
958 if (nexthop_active(AFI_IP, re, nexthop, rn))
959 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
960 else
961 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
962 break;
963 case NEXTHOP_TYPE_IPV6:
964 family = AFI_IP6;
965 if (nexthop_active(AFI_IP6, re, nexthop, rn))
966 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
967 else
968 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
969 break;
970 case NEXTHOP_TYPE_IPV6_IFINDEX:
971 /* RFC 5549, v4 prefix with v6 NH */
972 if (rn->p.family != AF_INET)
973 family = AFI_IP6;
974 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
975 ifp = if_lookup_by_index(nexthop->ifindex,
976 nexthop->vrf_id);
977 if (ifp && if_is_operative(ifp))
978 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
979 else
980 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
981 } else {
982 if (nexthop_active(AFI_IP6, re, nexthop, rn))
983 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
984 else
985 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
986 }
987 break;
988 case NEXTHOP_TYPE_BLACKHOLE:
989 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
990 break;
991 default:
992 break;
993 }
994 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
995 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
996 zlog_debug("\t%s: Unable to find a active nexthop",
997 __PRETTY_FUNCTION__);
998 return 0;
999 }
1000
1001 /* XXX: What exactly do those checks do? Do we support
1002 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1003 */
1004 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
1005 || (family == AFI_IP6 && p->family != AF_INET6))
1006 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1007
1008 /* The original code didn't determine the family correctly
1009 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1010 * from the rib_table_info in those cases.
1011 * Possibly it may be better to use only the rib_table_info
1012 * in every case.
1013 */
1014 if (!family) {
1015 rib_table_info_t *info;
1016
1017 info = srcdest_rnode_table_info(rn);
1018 family = info->afi;
1019 }
1020
1021 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
1022
1023 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1024 if (!zvrf) {
1025 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1026 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
1027 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1028 }
1029
1030 /* It'll get set if required inside */
1031 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
1032 zvrf, re->tag);
1033 if (ret == RMAP_DENYMATCH) {
1034 if (IS_ZEBRA_DEBUG_RIB) {
1035 srcdest_rnode2str(rn, buf, sizeof(buf));
1036 zlog_debug(
1037 "%u:%s: Filtering out with NH out %s due to route map",
1038 re->vrf_id, buf,
1039 ifindex2ifname(nexthop->ifindex,
1040 nexthop->vrf_id));
1041 }
1042 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1043 }
1044 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1045}
1046
1047/*
1048 * Iterate over all nexthops of the given RIB entry and refresh their
9a0d4dd3
DS
1049 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1050 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
ad28e79a
SW
1051 *
1052 * Return value is the new number of active nexthops.
1053 */
1054int nexthop_active_update(struct route_node *rn, struct route_entry *re)
1055{
1056 struct nexthop *nexthop;
1057 union g_addr prev_src;
1058 unsigned int prev_active, new_active;
1059 ifindex_t prev_index;
9a0d4dd3 1060 uint8_t curr_active = 0;
ad28e79a 1061
ad28e79a
SW
1062 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1063
6b468511 1064 for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
ad28e79a
SW
1065 /* No protocol daemon provides src and so we're skipping
1066 * tracking it */
1067 prev_src = nexthop->rmap_src;
1068 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1069 prev_index = nexthop->ifindex;
1070 /*
1071 * We need to respect the multipath_num here
1072 * as that what we should be able to install from
1073 * a multipath perpsective should not be a data plane
1074 * decision point.
1075 */
1076 new_active = nexthop_active_check(rn, re, nexthop);
1077 if (new_active
9a0d4dd3
DS
1078 && nexthop_group_active_nexthop_num(re->ng)
1079 >= zrouter.multipath_num) {
ad28e79a
SW
1080 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1081 new_active = 0;
1082 }
9a0d4dd3 1083
ad28e79a 1084 if (new_active)
9a0d4dd3
DS
1085 curr_active++;
1086
ad28e79a
SW
1087 /* Don't allow src setting on IPv6 addr for now */
1088 if (prev_active != new_active || prev_index != nexthop->ifindex
1089 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
1090 && nexthop->type < NEXTHOP_TYPE_IPV6)
1091 && prev_src.ipv4.s_addr
1092 != nexthop->rmap_src.ipv4.s_addr)
1093 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
1094 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
1095 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
1096 &nexthop->rmap_src.ipv6)))
42fc558e 1097 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 1098 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
1099 }
1100
9a0d4dd3 1101 return curr_active;
ad28e79a 1102}
5be96a2d
SW
1103
1104/**
1105 * zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel
1106 *
1107 * @nhe: Nexthop Group hash entry to install
1108 */
1109void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
1110{
147bad16
SW
1111 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1112 nhe->is_kernel_nh = false;
1113 int ret = dplane_nexthop_add(nhe);
1114 switch (ret) {
1115 case ZEBRA_DPLANE_REQUEST_QUEUED:
1116 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1117 break;
1118 case ZEBRA_DPLANE_REQUEST_FAILURE:
1119 flog_err(
1120 EC_ZEBRA_DP_INSTALL_FAIL,
1121 "Failed to install Nexthop ID (%u) into the kernel",
1122 nhe->id);
1123 break;
1124 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1125 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1126 break;
1127 }
1128 }
1129}
1130
1131/**
1132 * zebra_nhg_uninstall_kernel() - Uninstall Nexthop Group hash entry into kernel
1133 *
1134 * @nhe: Nexthop Group hash entry to uninstall
1135 */
1136void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
1137{
1138 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1139 int ret = dplane_nexthop_delete(nhe);
1140 switch (ret) {
1141 case ZEBRA_DPLANE_REQUEST_QUEUED:
1142 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1143 break;
1144 case ZEBRA_DPLANE_REQUEST_FAILURE:
1145 flog_err(
1146 EC_ZEBRA_DP_DELETE_FAIL,
1147 "Failed to uninstall Nexthop ID (%u) from the kernel",
1148 nhe->id);
1149 break;
1150 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1151 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1152 break;
1153 }
1154 }
1155}
1156
3e0372d2
SW
1157/**
1158 * zebra_nhg_uninstall_created() - Uninstall nexthops we created in the kernel
1159 *
1160 * @nhe: Nexthop group hash entry
1161 */
1162static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
1163{
1164 struct nhg_hash_entry *nhe = NULL;
1165
1166 nhe = (struct nhg_hash_entry *)bucket->data;
1167
1168 if (nhe && !nhe->is_kernel_nh)
1169 zebra_nhg_uninstall_kernel(nhe);
1170}
1171
1172/**
1173 * zebra_nhg_cleanup_tables() - Iterate over our tables to uninstall nh's
1174 * we created
1175 */
1176void zebra_nhg_cleanup_tables(void)
1177{
1178 hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL);
1179}
1180
5f3c9e52
SW
1181/**
1182 * zebra_nhg_dplane_result() - Process dplane result
1183 *
1184 * @ctx: Dataplane context
1185 */
1186void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
1187{
1188 enum dplane_op_e op;
1189 enum zebra_dplane_result status;
1190 uint32_t id = 0;
1191 struct nhg_hash_entry *nhe = NULL;
1192
1193 op = dplane_ctx_get_op(ctx);
1194 status = dplane_ctx_get_status(ctx);
1195
0c8215cb 1196 id = dplane_ctx_get_nhe_id(ctx);
5f3c9e52
SW
1197 nhe = zebra_nhg_lookup_id(id);
1198
1199 if (nhe) {
7512f617 1200 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
5f3c9e52
SW
1201 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1202 zlog_debug(
1203 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1204 ctx, dplane_op2str(op), nhe->id,
1205 dplane_res2str(status));
1206
1207 switch (op) {
1208 case DPLANE_OP_NH_DELETE:
1209 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1210 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
5f3c9e52
SW
1211 } else {
1212 flog_err(
1213 EC_ZEBRA_DP_DELETE_FAIL,
1214 "Failed to uninstall Nexthop ID (%u) from the kernel",
1215 nhe->id);
1216 }
1217 break;
1218 case DPLANE_OP_NH_INSTALL:
1219 case DPLANE_OP_NH_UPDATE:
1220 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1221 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1222 } else {
1223 flog_err(
1224 EC_ZEBRA_DP_INSTALL_FAIL,
1225 "Failed to install Nexthop ID (%u) into the kernel",
1226 nhe->id);
1227 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1228 }
5f3c9e52
SW
1229 break;
1230 case DPLANE_OP_ROUTE_INSTALL:
1231 case DPLANE_OP_ROUTE_UPDATE:
1232 case DPLANE_OP_ROUTE_DELETE:
1233 case DPLANE_OP_ROUTE_NOTIFY:
1234 case DPLANE_OP_LSP_INSTALL:
1235 case DPLANE_OP_LSP_UPDATE:
1236 case DPLANE_OP_LSP_DELETE:
1237 case DPLANE_OP_LSP_NOTIFY:
1238 case DPLANE_OP_PW_INSTALL:
1239 case DPLANE_OP_PW_UNINSTALL:
1240 case DPLANE_OP_SYS_ROUTE_ADD:
1241 case DPLANE_OP_SYS_ROUTE_DELETE:
1242 case DPLANE_OP_ADDR_INSTALL:
1243 case DPLANE_OP_ADDR_UNINSTALL:
1244 case DPLANE_OP_MAC_INSTALL:
1245 case DPLANE_OP_MAC_DELETE:
1246 case DPLANE_OP_NONE:
1247 break;
1248 }
1249 dplane_ctx_fini(&ctx);
1250
1251 } else {
1252 flog_err(
1253 EC_ZEBRA_NHG_SYNC,
1254 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1255 dplane_op2str(op), id);
5be96a2d
SW
1256 }
1257}
1258