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