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