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