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