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