]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
zebra: Add interface down marking to NHE's
[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");
0c8215cb 47
fe593b78
SW
48static int nhg_connected_cmp(const struct nhg_connected *dep1,
49 const struct nhg_connected *dep2);
0c8215cb 50
fe593b78 51RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry, nhg_connected_cmp);
0c8215cb 52
fe593b78 53void nhg_connected_free(struct nhg_connected *dep)
0c8215cb 54{
a15d4c00 55 XFREE(MTYPE_NHG_CONNECTED, dep);
0c8215cb
SW
56}
57
fe593b78 58struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
0c8215cb 59{
a15d4c00 60 struct nhg_connected *new = NULL;
0c8215cb 61
a15d4c00 62 new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
0c8215cb
SW
63 new->nhe = nhe;
64
65 return new;
66}
67
fe593b78
SW
68void nhg_connected_head_init(struct nhg_connected_head *head)
69{
70 RB_INIT(nhg_connected_head, head);
71}
72
73void nhg_connected_head_free(struct nhg_connected_head *head)
0c8215cb 74{
a15d4c00 75 struct nhg_connected *rb_node_dep = NULL;
fe593b78 76 struct nhg_connected *tmp = NULL;
0c8215cb 77
fe593b78
SW
78 if (!nhg_connected_head_is_empty(head)) {
79 RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) {
80 RB_REMOVE(nhg_connected_head, head, rb_node_dep);
81 nhg_connected_free(rb_node_dep);
82 }
0c8215cb 83 }
0c8215cb
SW
84}
85
fe593b78 86unsigned int nhg_connected_head_count(const struct nhg_connected_head *head)
0c8215cb 87{
fe593b78
SW
88 struct nhg_connected *rb_node_dep = NULL;
89 unsigned int i = 0;
0c8215cb 90
fe593b78
SW
91 RB_FOREACH (rb_node_dep, nhg_connected_head, head) {
92 i++;
93 }
94 return i;
0c8215cb 95}
3119f6a1 96
fe593b78 97bool nhg_connected_head_is_empty(const struct nhg_connected_head *head)
3119f6a1 98{
fe593b78 99 return RB_EMPTY(nhg_connected_head, head);
0c8215cb
SW
100}
101
fe593b78
SW
102void nhg_connected_head_del(struct nhg_connected_head *head,
103 struct nhg_hash_entry *depend)
0c8215cb 104{
a15d4c00
SW
105 struct nhg_connected lookup = {};
106 struct nhg_connected *removed = NULL;
0c8215cb
SW
107
108 lookup.nhe = depend;
3119f6a1 109
a15d4c00 110 removed = RB_REMOVE(nhg_connected_head, head, &lookup);
3119f6a1 111
a15d4c00 112 nhg_connected_free(removed);
3119f6a1
SW
113}
114
fe593b78
SW
115void nhg_connected_head_add(struct nhg_connected_head *head,
116 struct nhg_hash_entry *depend)
3119f6a1 117{
a15d4c00 118 struct nhg_connected *new = NULL;
0c8215cb 119
a15d4c00 120 new = nhg_connected_new(depend);
0c8215cb 121
a15d4c00 122 RB_INSERT(nhg_connected_head, head, new);
3119f6a1
SW
123}
124
fe593b78 125unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
a15d4c00 126{
fe593b78 127 return nhg_connected_head_count(&nhe->nhg_depends);
a15d4c00
SW
128}
129
fe593b78 130bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
a15d4c00 131{
fe593b78 132 return nhg_connected_head_is_empty(&nhe->nhg_depends);
a15d4c00
SW
133}
134
135/**
136 * zebra_nhg_depends_del() - Delete a dependency from the nhg_hash_entry
0c8215cb
SW
137 *
138 * @from: Nexthop group hash entry we are deleting from
139 * @depend: Dependency we are deleting
3119f6a1 140 */
0c8215cb
SW
141void zebra_nhg_depends_del(struct nhg_hash_entry *from,
142 struct nhg_hash_entry *depend)
3119f6a1 143{
fe593b78 144 nhg_connected_head_del(&from->nhg_depends, depend);
a15d4c00
SW
145
146 /* Delete from the dependent tree */
147 zebra_nhg_dependents_del(depend, from);
3119f6a1
SW
148}
149
150/**
0c8215cb 151 * zebra_nhg_depends_add() - Add a new dependency to the nhg_hash_entry
3119f6a1 152 *
0c8215cb
SW
153 * @to: Nexthop group hash entry we are adding to
154 * @depend: Dependency we are adding
3119f6a1 155 */
0c8215cb
SW
156void zebra_nhg_depends_add(struct nhg_hash_entry *to,
157 struct nhg_hash_entry *depend)
3119f6a1 158{
fe593b78 159 nhg_connected_head_add(&to->nhg_depends, depend);
d6e0094f
SW
160}
161
148a0103 162/**
0c8215cb 163 * zebra_nhg_depends_init() - Initialize tree for nhg dependencies
148a0103 164 *
0c8215cb 165 * @nhe: Nexthop group hash entry
148a0103 166 */
0c8215cb 167void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
148a0103 168{
fe593b78 169 nhg_connected_head_init(&nhe->nhg_depends);
148a0103
SW
170}
171
20822f9d
SW
172/**
173 * zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal
174 *
175 * @nhe1: Nexthop group hash entry
176 * @nhe2: Nexthop group hash entry
177 *
178 * Return: True if equal
179 *
180 * We don't care about ordering of the dependencies. If they contain
181 * the same nhe ID's, they are equivalent.
182 */
183static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1,
184 const struct nhg_hash_entry *nhe2)
185{
a15d4c00 186 struct nhg_connected *rb_node_dep = NULL;
20822f9d 187
0c8215cb
SW
188 if (zebra_nhg_depends_is_empty(nhe1)
189 && zebra_nhg_depends_is_empty(nhe2))
20822f9d
SW
190 return true;
191
0c8215cb
SW
192 if ((zebra_nhg_depends_is_empty(nhe1)
193 && !zebra_nhg_depends_is_empty(nhe2))
194 || (zebra_nhg_depends_is_empty(nhe2)
195 && !zebra_nhg_depends_is_empty(nhe1)))
20822f9d
SW
196 return false;
197
a15d4c00
SW
198 RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe1->nhg_depends) {
199 if (!RB_FIND(nhg_connected_head, &nhe2->nhg_depends,
200 rb_node_dep))
20822f9d
SW
201 return false;
202 }
203
204 return true;
205}
206
fe593b78
SW
207unsigned int zebra_nhg_dependents_count(const struct nhg_hash_entry *nhe)
208{
209 return nhg_connected_head_count(&nhe->nhg_dependents);
210}
211
212bool zebra_nhg_dependents_is_empty(const struct nhg_hash_entry *nhe)
213{
214 return nhg_connected_head_is_empty(&nhe->nhg_dependents);
215}
216
217/**
218 * zebra_nhg_dependents_del() - Delete a dependent from the nhg_hash_entry
219 *
220 * @from: Nexthop group hash entry we are deleting from
221 * @dependent: Dependent we are deleting
222 */
223void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
224 struct nhg_hash_entry *dependent)
225{
226 nhg_connected_head_del(&from->nhg_dependents, dependent);
227}
228
229/**
230 * zebra_nhg_dependents_add() - Add a new dependent to the nhg_hash_entry
231 *
232 * @to: Nexthop group hash entry we are adding to
233 * @dependent: Dependent we are adding
234 */
235void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
236 struct nhg_hash_entry *dependent)
237{
238 nhg_connected_head_add(&to->nhg_dependents, dependent);
239}
240
241/**
242 * zebra_nhg_dependents_init() - Initialize tree for nhg dependents
243 *
244 * @nhe: Nexthop group hash entry
245 */
246void zebra_nhg_dependents_init(struct nhg_hash_entry *nhe)
247{
248 nhg_connected_head_init(&nhe->nhg_dependents);
249}
250
d9f5b2f5
SW
251/**
252 * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
253 *
254 * @id: ID to look for
255 *
256 * Return: Nexthop hash entry if found/NULL if not found
257 */
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
266/**
267 * zebra_nhg_insert_id() - Insert a nhe into the id hashed table
268 *
269 * @nhe: The entry directly from the other table
270 *
271 * Return: Result status
272 */
273int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
274{
275 if (hash_lookup(zrouter.nhgs_id, nhe)) {
276 flog_err(
277 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
278 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
279 nhe->id);
280 return -1;
281 }
282
283 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
284
285 return 0;
286}
ad28e79a 287
4e49c8b8
DS
288
289static void *zebra_nhg_alloc(void *arg)
290{
291 struct nhg_hash_entry *nhe;
292 struct nhg_hash_entry *copy = arg;
a15d4c00
SW
293 struct nhg_connected *rb_node_dep = NULL;
294
4e49c8b8 295
51d80884 296 nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
d9f5b2f5 297
5bd81e4c
SW
298
299 nhe->id = copy->id;
4e49c8b8 300
0c8215cb 301 nhe->nhg_depends = copy->nhg_depends;
8e401b25 302
2d6cd1f0
SW
303 nhe->nhg = nexthop_group_new();
304 nexthop_group_copy(nhe->nhg, copy->nhg);
3119f6a1 305
4e49c8b8 306 nhe->vrf_id = copy->vrf_id;
77b76fc9 307 nhe->afi = copy->afi;
4e49c8b8 308 nhe->refcnt = 0;
9ed6c34a 309 nhe->is_kernel_nh = copy->is_kernel_nh;
4e49c8b8 310 nhe->dplane_ref = zebra_router_get_next_sequence();
2614bf87 311 nhe->ifp = NULL;
4e49c8b8 312
a15d4c00 313 /* Attach backpointer to anything that it depends on */
fe593b78 314 zebra_nhg_dependents_init(nhe);
a15d4c00
SW
315 if (!zebra_nhg_depends_is_empty(nhe)) {
316 RB_FOREACH (rb_node_dep, nhg_connected_head,
317 &nhe->nhg_depends) {
318 zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
319 }
320 }
4e49c8b8 321
d9f5b2f5
SW
322 /* Add to id table as well */
323 zebra_nhg_insert_id(nhe);
324
4e49c8b8 325
fe593b78
SW
326 // TODO: This needs to be moved
327 // It should only install AFTER it gets
328 // the ifp right?
329 //
20822f9d
SW
330 /* Send it to the kernel */
331 if (!nhe->is_kernel_nh)
332 zebra_nhg_install_kernel(nhe);
333
4e49c8b8
DS
334 return nhe;
335}
336
4e49c8b8
DS
337uint32_t zebra_nhg_hash_key(const void *arg)
338{
339 const struct nhg_hash_entry *nhe = arg;
d9f5b2f5 340
7286ac02 341 uint32_t key = 0x5a351234;
4e49c8b8 342
77b76fc9 343 key = jhash_2words(nhe->vrf_id, nhe->afi, key);
4e49c8b8 344
0c8215cb 345 key = jhash_1word(nexthop_group_hash(nhe->nhg), key);
d9f5b2f5 346
d9f5b2f5 347 return key;
4e49c8b8
DS
348}
349
a95b8020
SW
350uint32_t zebra_nhg_id_key(const void *arg)
351{
352 const struct nhg_hash_entry *nhe = arg;
353
354 return nhe->id;
355}
356
4e49c8b8
DS
357bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
358{
359 const struct nhg_hash_entry *nhe1 = arg1;
360 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8
DS
361
362 if (nhe1->vrf_id != nhe2->vrf_id)
363 return false;
364
77b76fc9
SW
365 if (nhe1->afi != nhe2->afi)
366 return false;
367
20822f9d
SW
368 if (!zebra_nhg_depends_equal(nhe1, nhe2))
369 return false;
4e49c8b8
DS
370
371 return true;
372}
373
d9f5b2f5 374bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 375{
d9f5b2f5
SW
376 const struct nhg_hash_entry *nhe1 = arg1;
377 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 378
d9f5b2f5
SW
379 return nhe1->id == nhe2->id;
380}
4e49c8b8 381
0c8215cb
SW
382/**
383 * zebra_nhg_cmp() - Compare the ID's of two nhe's
384 *
385 * @nhe1: Nexthop group hash entry #1
386 * @nhe2: Nexthop group hash entry #2
387 *
388 * Return:
389 * - Negative: #1 < #2
390 * - Positive: #1 > #2
391 * - Zero: #1 = #2
392 *
393 * This is used in the nhg RB trees.
394 */
395static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1,
396 const struct nhg_hash_entry *nhe2)
397{
398 return nhe1->id - nhe2->id;
399}
400
fe593b78
SW
401static int nhg_connected_cmp(const struct nhg_connected *dep1,
402 const struct nhg_connected *dep2)
0c8215cb
SW
403{
404 return zebra_nhg_cmp(dep1->nhe, dep2->nhe);
405}
406
d9f5b2f5
SW
407/**
408 * zebra_nhg_find() - Find the zebra nhg in our table, or create it
409 *
8e401b25
SW
410 * @nhg: Nexthop group we lookup with
411 * @vrf_id: VRF id
412 * @afi: Address Family type
413 * @id: ID we lookup with, 0 means its from us and we
414 * need to give it an ID, otherwise its from the
415 * kernel as we use the ID it gave us.
0c8215cb 416 * @nhg_depends: Nexthop dependency tree head
9ed6c34a 417 * @is_kernel_nh: Was the nexthop created by the kernel
d9f5b2f5 418 *
8e401b25 419 * Return: Hash entry found or created
85f5e761
SW
420 *
421 * The nhg and n_grp are fundementally the same thing (a group of nexthops).
422 * We are just using the nhg representation with routes and the n_grp
423 * is what the kernel gives us (a list of IDs). Our nhg_hash_entry
424 * will contain both.
425 *
426 * nhg_hash_entry example:
427 *
428 * nhe:
429 * ->nhg:
430 * .nexthop->nexthop->nexthop
431 * ->nhg_depends:
432 * .nhe->nhe->nhe
433 *
434 * Routes will use the nhg directly, and any updating of nexthops
435 * we have to do or flag setting, we use the nhg_depends.
436 *
d9f5b2f5
SW
437 */
438struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
85f5e761 439 vrf_id_t vrf_id, afi_t afi, uint32_t id,
a15d4c00 440 struct nhg_connected_head *nhg_depends,
9ed6c34a 441 bool is_kernel_nh)
a95b8020 442{
5bd81e4c
SW
443 /* lock for getiing and setting the id */
444 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
445 /* id counter to keep in sync with kernel */
446 static uint32_t id_counter = 0;
447
0c8215cb 448 struct nhg_hash_entry lookup = {};
d9f5b2f5 449 struct nhg_hash_entry *nhe = NULL;
5bd81e4c
SW
450 uint32_t old_id_counter = 0;
451
452 pthread_mutex_lock(&lock); /* Lock, set the id counter */
453
454 old_id_counter = id_counter;
455
456 if (id) {
457 if (id > id_counter) {
458 /* Increase our counter so we don't try to create
459 * an ID that already exists
460 */
461 id_counter = id;
462 }
463 lookup.id = id;
464 } else {
465 lookup.id = ++id_counter;
466 }
a95b8020 467
d9f5b2f5 468 lookup.vrf_id = vrf_id;
77b76fc9 469 lookup.afi = afi;
b599cd2a 470 lookup.nhg = nhg;
0c8215cb 471 lookup.nhg_depends = *nhg_depends;
9ed6c34a 472 lookup.is_kernel_nh = is_kernel_nh;
a95b8020 473
b599cd2a
SW
474 if (id)
475 nhe = zebra_nhg_lookup_id(id);
476 else
477 nhe = hash_lookup(zrouter.nhgs, &lookup);
d9f5b2f5 478
5bd81e4c
SW
479 /* If it found an nhe in our tables, this new ID is unused */
480 if (nhe)
481 id_counter = old_id_counter;
482
483 pthread_mutex_unlock(&lock);
484
2d6cd1f0 485 if (!nhe)
d9f5b2f5 486 nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
d9f5b2f5
SW
487
488 return nhe;
a95b8020
SW
489}
490
3057df51
SW
491/**
492 * zebra_nhg_find_nexthop() - Create a group with a single nexthop, find it in
493 * our table, or create it
494 *
495 * @nh: Nexthop to lookup
496 * @afi: Address Family type
497 *
498 * Return: Hash entry found or created
499 */
500struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi)
501{
502 struct nhg_hash_entry *nhe = NULL;
503
504 struct nexthop_group *nhg = nexthop_group_new();
505
506 nexthop_group_add_sorted(nhg, nh);
507 nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false);
508
509 nexthop_group_delete(&nhg);
510
511 return nhe;
512}
513
b599cd2a
SW
514/**
515 * zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group
516 * struct and depends
517 *
0c8215cb
SW
518 * @nhg: Nexthop_group
519 * @nhg_depends: Nexthop group dependency tree head
b599cd2a 520 */
0c8215cb 521void zebra_nhg_free_group_depends(struct nexthop_group **nhg,
a15d4c00
SW
522 struct nhg_connected_head *head)
523{
524 // TODO
525 //
526 //
527 // FIX THIS NAMING
528 //
529 //
530 //
531 //
532 //
0c8215cb 533 if (head)
fe593b78 534 nhg_connected_head_free(head);
0c8215cb
SW
535
536 if (nhg)
537 nexthop_group_free_delete(nhg);
b599cd2a
SW
538}
539
540/**
541 * zebra_nhg_free_members() - Free all members in the hash entry struct
542 *
543 * @nhe: Nexthop group hash entry
544 *
545 * Just use this to free everything but the entry itself.
546 */
547void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
548{
0c8215cb 549 zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends);
a15d4c00
SW
550
551 // TODO: Fixup this function
fe593b78 552 nhg_connected_head_free(&nhe->nhg_dependents);
b599cd2a
SW
553}
554
d9f5b2f5
SW
555/**
556 * zebra_nhg_free() - Free the nexthop group hash entry
557 *
558 * arg: Nexthop group entry to free
559 */
560void zebra_nhg_free(void *arg)
a95b8020 561{
d9f5b2f5 562 struct nhg_hash_entry *nhe = NULL;
a95b8020 563
d9f5b2f5 564 nhe = (struct nhg_hash_entry *)arg;
a95b8020 565
8e401b25 566 zebra_nhg_free_members(nhe);
51d80884
SW
567
568 XFREE(MTYPE_NHG, nhe);
a95b8020
SW
569}
570
d9f5b2f5
SW
571/**
572 * zebra_nhg_release() - Release a nhe from the tables
573 *
574 * @nhe: Nexthop group hash entry
575 */
576void zebra_nhg_release(struct nhg_hash_entry *nhe)
4e49c8b8 577{
7512f617
SW
578 if (!nhe->refcnt) {
579 zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
580 hash_release(zrouter.nhgs, nhe);
581 hash_release(zrouter.nhgs_id, nhe);
582 zebra_nhg_free(nhe);
583 }
584}
4e49c8b8 585
d9f5b2f5
SW
586/**
587 * zebra_nhg_decrement_ref() - Decrement the reference count, release if unused
588 *
589 * @nhe: Nexthop group hash entry
590 *
591 * If the counter hits 0 and is not a nexthop group that was created by the
592 * kernel, we don't need to have it in our table anymore.
593 */
594void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
595{
0c8215cb 596 if (!zebra_nhg_depends_is_empty(nhe)) {
a15d4c00 597 struct nhg_connected *rb_node_dep = NULL;
f54ef6a5 598
a15d4c00
SW
599 RB_FOREACH (rb_node_dep, nhg_connected_head,
600 &nhe->nhg_depends) {
0c8215cb 601 zebra_nhg_decrement_ref(rb_node_dep->nhe);
f54ef6a5
SW
602 }
603 }
604
4e49c8b8
DS
605 nhe->refcnt--;
606
d9f5b2f5 607 if (!nhe->is_kernel_nh && nhe->refcnt <= 0) {
7512f617 608 zebra_nhg_uninstall_release(nhe);
d9f5b2f5 609 }
7fd392cc
SW
610}
611
612/**
613 * zebra_nhg_increment_ref() - Increment the reference count
614 *
615 * @nhe: Nexthop group hash entry
616 */
617void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
618{
0c8215cb 619 if (!zebra_nhg_depends_is_empty(nhe)) {
a15d4c00 620 struct nhg_connected *rb_node_dep = NULL;
7fd392cc 621
a15d4c00
SW
622 RB_FOREACH (rb_node_dep, nhg_connected_head,
623 &nhe->nhg_depends) {
0c8215cb 624 zebra_nhg_increment_ref(rb_node_dep->nhe);
7fd392cc
SW
625 }
626 }
d9f5b2f5 627
7fd392cc 628 nhe->refcnt++;
4e49c8b8
DS
629}
630
fe593b78
SW
631void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe)
632{
633
634 if (!zebra_nhg_dependents_is_empty(nhe)) {
635 struct nhg_connected *rb_node_dep = NULL;
636
637 RB_FOREACH (rb_node_dep, nhg_connected_head,
638 &nhe->nhg_dependents) {
639 zebra_nhg_set_invalid(rb_node_dep->nhe);
640 }
641 }
642
643 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
644 /* Assuming uninstalled as well here */
645 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
646}
647
648void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp)
649{
650 nhe->ifp = ifp;
651 if_nhg_dependents_add(ifp, nhe);
652}
653
ad28e79a
SW
654static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
655 struct nexthop *nexthop)
656{
657 struct nexthop *resolved_hop;
b43434ad
SW
658 uint8_t num_labels = 0;
659 mpls_label_t labels[MPLS_MAX_LABELS];
660 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
661 int i = 0;
ad28e79a
SW
662
663 resolved_hop = nexthop_new();
664 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
665
666 resolved_hop->vrf_id = nexthop->vrf_id;
667 switch (newhop->type) {
668 case NEXTHOP_TYPE_IPV4:
669 case NEXTHOP_TYPE_IPV4_IFINDEX:
670 /* If the resolving route specifies a gateway, use it */
671 resolved_hop->type = newhop->type;
672 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
673
674 if (newhop->ifindex) {
675 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
676 resolved_hop->ifindex = newhop->ifindex;
677 }
678 break;
679 case NEXTHOP_TYPE_IPV6:
680 case NEXTHOP_TYPE_IPV6_IFINDEX:
681 resolved_hop->type = newhop->type;
682 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
683
684 if (newhop->ifindex) {
685 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
686 resolved_hop->ifindex = newhop->ifindex;
687 }
688 break;
689 case NEXTHOP_TYPE_IFINDEX:
690 /* If the resolving route is an interface route,
691 * it means the gateway we are looking up is connected
692 * to that interface. (The actual network is _not_ onlink).
693 * Therefore, the resolved route should have the original
694 * gateway as nexthop as it is directly connected.
695 *
696 * On Linux, we have to set the onlink netlink flag because
697 * otherwise, the kernel won't accept the route.
698 */
699 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
700 if (afi == AFI_IP) {
701 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
702 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
703 } else if (afi == AFI_IP6) {
704 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
705 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
706 }
707 resolved_hop->ifindex = newhop->ifindex;
708 break;
709 case NEXTHOP_TYPE_BLACKHOLE:
710 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 711 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
712 break;
713 }
714
715 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
716 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
717
b43434ad
SW
718 /* Copy labels of the resolved route and the parent resolving to it */
719 if (newhop->nh_label) {
720 for (i = 0; i < newhop->nh_label->num_labels; i++)
721 labels[num_labels++] = newhop->nh_label->label[i];
722 label_type = newhop->nh_label_type;
723 }
724
725 if (nexthop->nh_label) {
726 for (i = 0; i < nexthop->nh_label->num_labels; i++)
727 labels[num_labels++] = nexthop->nh_label->label[i];
728
729 /* If the parent has labels, use its type */
730 label_type = nexthop->nh_label_type;
731 }
732
733 if (num_labels)
734 nexthop_add_labels(resolved_hop, label_type, num_labels,
735 labels);
ad28e79a
SW
736
737 resolved_hop->rparent = nexthop;
50d89650 738 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
739}
740
6913cb1b
SW
741/* Checks if nexthop we are trying to resolve to is valid */
742static bool nexthop_valid_resolve(const struct nexthop *nexthop,
743 const struct nexthop *resolved)
744{
745 /* Can't resolve to a recursive nexthop */
746 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
747 return false;
748
749 switch (nexthop->type) {
750 case NEXTHOP_TYPE_IPV4_IFINDEX:
751 case NEXTHOP_TYPE_IPV6_IFINDEX:
752 /* If the nexthop we are resolving to does not match the
753 * ifindex for the nexthop the route wanted, its not valid.
754 */
755 if (nexthop->ifindex != resolved->ifindex)
756 return false;
757 break;
758 case NEXTHOP_TYPE_IPV4:
759 case NEXTHOP_TYPE_IPV6:
760 case NEXTHOP_TYPE_IFINDEX:
761 case NEXTHOP_TYPE_BLACKHOLE:
762 break;
763 }
764
765 return true;
766}
767
ad28e79a
SW
768/*
769 * Given a nexthop we need to properly recursively resolve
770 * the route. As such, do a table lookup to find and match
771 * if at all possible. Set the nexthop->ifindex as appropriate
772 */
773static int nexthop_active(afi_t afi, struct route_entry *re,
774 struct nexthop *nexthop, struct route_node *top)
775{
776 struct prefix p;
777 struct route_table *table;
778 struct route_node *rn;
779 struct route_entry *match = NULL;
780 int resolved;
781 struct nexthop *newhop;
782 struct interface *ifp;
783 rib_dest_t *dest;
5a0bdc78 784 struct zebra_vrf *zvrf;
ad28e79a
SW
785
786 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
787 || nexthop->type == NEXTHOP_TYPE_IPV6)
788 nexthop->ifindex = 0;
789
790 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
791 nexthops_free(nexthop->resolved);
792 nexthop->resolved = NULL;
793 re->nexthop_mtu = 0;
794
795 /*
a8c427ee 796 * If the kernel has sent us a NEW route, then
ad28e79a 797 * by golly gee whiz it's a good route.
a8c427ee
SW
798 *
799 * If its an already INSTALLED route we have already handled, then the
800 * kernel route's nexthop might have became unreachable
801 * and we have to handle that.
ad28e79a 802 */
a8c427ee
SW
803 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
804 && (re->type == ZEBRA_ROUTE_KERNEL
805 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
806 return 1;
807
808 /*
809 * Check to see if we should trust the passed in information
810 * for UNNUMBERED interfaces as that we won't find the GW
811 * address in the routing table.
812 * This check should suffice to handle IPv4 or IPv6 routes
813 * sourced from EVPN routes which are installed with the
814 * next hop as the remote VTEP IP.
815 */
816 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
817 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
818 if (!ifp) {
819 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
820 zlog_debug(
821 "\t%s: Onlink and interface: %u[%u] does not exist",
822 __PRETTY_FUNCTION__, nexthop->ifindex,
823 nexthop->vrf_id);
824 return 0;
825 }
826 if (connected_is_unnumbered(ifp)) {
827 if (if_is_operative(ifp))
828 return 1;
829 else {
830 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
831 zlog_debug(
832 "\t%s: Onlink and interface %s is not operative",
833 __PRETTY_FUNCTION__, ifp->name);
834 return 0;
835 }
836 }
837 if (!if_is_operative(ifp)) {
838 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
839 zlog_debug(
840 "\t%s: Interface %s is not unnumbered",
841 __PRETTY_FUNCTION__, ifp->name);
842 return 0;
843 }
844 }
845
846 /* Make lookup prefix. */
847 memset(&p, 0, sizeof(struct prefix));
848 switch (afi) {
849 case AFI_IP:
850 p.family = AF_INET;
851 p.prefixlen = IPV4_MAX_PREFIXLEN;
852 p.u.prefix4 = nexthop->gate.ipv4;
853 break;
854 case AFI_IP6:
855 p.family = AF_INET6;
856 p.prefixlen = IPV6_MAX_PREFIXLEN;
857 p.u.prefix6 = nexthop->gate.ipv6;
858 break;
859 default:
860 assert(afi != AFI_IP && afi != AFI_IP6);
861 break;
862 }
863 /* Lookup table. */
864 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
865 /* get zvrf */
866 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
867 if (!table || !zvrf) {
ad28e79a
SW
868 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
869 zlog_debug("\t%s: Table not found",
870 __PRETTY_FUNCTION__);
871 return 0;
872 }
873
874 rn = route_node_match(table, (struct prefix *)&p);
875 while (rn) {
876 route_unlock_node(rn);
877
878 /* Lookup should halt if we've matched against ourselves ('top',
879 * if specified) - i.e., we cannot have a nexthop NH1 is
880 * resolved by a route NH1. The exception is if the route is a
881 * host route.
882 */
883 if (top && rn == top)
884 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
885 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
886 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
887 zlog_debug(
888 "\t%s: Matched against ourself and prefix length is not max bit length",
889 __PRETTY_FUNCTION__);
890 return 0;
891 }
892
893 /* Pick up selected route. */
894 /* However, do not resolve over default route unless explicitly
895 * allowed. */
896 if (is_default_prefix(&rn->p)
5a0bdc78 897 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
898 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
899 zlog_debug(
900 "\t:%s: Resolved against default route",
901 __PRETTY_FUNCTION__);
902 return 0;
903 }
904
905 dest = rib_dest_from_rnode(rn);
906 if (dest && dest->selected_fib
907 && !CHECK_FLAG(dest->selected_fib->status,
908 ROUTE_ENTRY_REMOVED)
909 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
910 match = dest->selected_fib;
911
912 /* If there is no selected route or matched route is EGP, go up
913 tree. */
914 if (!match) {
915 do {
916 rn = rn->parent;
917 } while (rn && rn->info == NULL);
918 if (rn)
919 route_lock_node(rn);
920
921 continue;
922 }
923
924 if (match->type == ZEBRA_ROUTE_CONNECT) {
925 /* Directly point connected route. */
6b468511 926 newhop = match->ng->nexthop;
ad28e79a
SW
927 if (newhop) {
928 if (nexthop->type == NEXTHOP_TYPE_IPV4
929 || nexthop->type == NEXTHOP_TYPE_IPV6)
930 nexthop->ifindex = newhop->ifindex;
931 }
932 return 1;
933 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
934 resolved = 0;
6b468511 935 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
936 if (!CHECK_FLAG(match->status,
937 ROUTE_ENTRY_INSTALLED))
938 continue;
6913cb1b 939 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
940 continue;
941
942 SET_FLAG(nexthop->flags,
943 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
944 nexthop_set_resolved(afi, newhop, nexthop);
945 resolved = 1;
946 }
947 if (resolved)
948 re->nexthop_mtu = match->mtu;
949 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
950 zlog_debug("\t%s: Recursion failed to find",
951 __PRETTY_FUNCTION__);
952 return resolved;
953 } else if (re->type == ZEBRA_ROUTE_STATIC) {
954 resolved = 0;
6b468511 955 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
956 if (!CHECK_FLAG(match->status,
957 ROUTE_ENTRY_INSTALLED))
958 continue;
6913cb1b 959 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
960 continue;
961
962 SET_FLAG(nexthop->flags,
963 NEXTHOP_FLAG_RECURSIVE);
964 nexthop_set_resolved(afi, newhop, nexthop);
965 resolved = 1;
966 }
967 if (resolved)
968 re->nexthop_mtu = match->mtu;
969
970 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
971 zlog_debug(
972 "\t%s: Static route unable to resolve",
973 __PRETTY_FUNCTION__);
974 return resolved;
975 } else {
976 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
977 zlog_debug(
978 "\t%s: Route Type %s has not turned on recursion",
979 __PRETTY_FUNCTION__,
980 zebra_route_string(re->type));
981 if (re->type == ZEBRA_ROUTE_BGP
982 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
983 zlog_debug(
984 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
985 }
986 return 0;
987 }
988 }
989 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
990 zlog_debug("\t%s: Nexthop did not lookup in table",
991 __PRETTY_FUNCTION__);
992 return 0;
993}
994
995/* This function verifies reachability of one given nexthop, which can be
996 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
997 * in nexthop->flags field. The nexthop->ifindex will be updated
998 * appropriately as well. An existing route map can turn
999 * (otherwise active) nexthop into inactive, but not vice versa.
1000 *
1001 * The return value is the final value of 'ACTIVE' flag.
1002 */
1003static unsigned nexthop_active_check(struct route_node *rn,
1004 struct route_entry *re,
1005 struct nexthop *nexthop)
1006{
1007 struct interface *ifp;
b68885f9 1008 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
1009 int family;
1010 char buf[SRCDEST2STR_BUFFER];
1011 const struct prefix *p, *src_p;
1012 struct zebra_vrf *zvrf;
1013
1014 srcdest_rnode_prefixes(rn, &p, &src_p);
1015
1016 if (rn->p.family == AF_INET)
1017 family = AFI_IP;
1018 else if (rn->p.family == AF_INET6)
1019 family = AFI_IP6;
1020 else
1021 family = 0;
1022 switch (nexthop->type) {
1023 case NEXTHOP_TYPE_IFINDEX:
1024 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
1025 if (ifp && if_is_operative(ifp))
1026 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1027 else
1028 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1029 break;
1030 case NEXTHOP_TYPE_IPV4:
1031 case NEXTHOP_TYPE_IPV4_IFINDEX:
1032 family = AFI_IP;
1033 if (nexthop_active(AFI_IP, re, nexthop, rn))
1034 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1035 else
1036 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1037 break;
1038 case NEXTHOP_TYPE_IPV6:
1039 family = AFI_IP6;
1040 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1041 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1042 else
1043 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1044 break;
1045 case NEXTHOP_TYPE_IPV6_IFINDEX:
1046 /* RFC 5549, v4 prefix with v6 NH */
1047 if (rn->p.family != AF_INET)
1048 family = AFI_IP6;
1049 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
1050 ifp = if_lookup_by_index(nexthop->ifindex,
1051 nexthop->vrf_id);
1052 if (ifp && if_is_operative(ifp))
1053 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1054 else
1055 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1056 } else {
1057 if (nexthop_active(AFI_IP6, re, nexthop, rn))
1058 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1059 else
1060 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1061 }
1062 break;
1063 case NEXTHOP_TYPE_BLACKHOLE:
1064 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1065 break;
1066 default:
1067 break;
1068 }
1069 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
1070 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1071 zlog_debug("\t%s: Unable to find a active nexthop",
1072 __PRETTY_FUNCTION__);
1073 return 0;
1074 }
1075
1076 /* XXX: What exactly do those checks do? Do we support
1077 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
1078 */
1079 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
1080 || (family == AFI_IP6 && p->family != AF_INET6))
1081 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1082
1083 /* The original code didn't determine the family correctly
1084 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
1085 * from the rib_table_info in those cases.
1086 * Possibly it may be better to use only the rib_table_info
1087 * in every case.
1088 */
1089 if (!family) {
1090 rib_table_info_t *info;
1091
1092 info = srcdest_rnode_table_info(rn);
1093 family = info->afi;
1094 }
1095
1096 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
1097
1098 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
1099 if (!zvrf) {
1100 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
1101 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
1102 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1103 }
1104
1105 /* It'll get set if required inside */
1106 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
1107 zvrf, re->tag);
1108 if (ret == RMAP_DENYMATCH) {
1109 if (IS_ZEBRA_DEBUG_RIB) {
1110 srcdest_rnode2str(rn, buf, sizeof(buf));
1111 zlog_debug(
1112 "%u:%s: Filtering out with NH out %s due to route map",
1113 re->vrf_id, buf,
1114 ifindex2ifname(nexthop->ifindex,
1115 nexthop->vrf_id));
1116 }
1117 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1118 }
1119 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1120}
1121
1122/*
1123 * Iterate over all nexthops of the given RIB entry and refresh their
9a0d4dd3
DS
1124 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
1125 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
ad28e79a
SW
1126 *
1127 * Return value is the new number of active nexthops.
1128 */
1129int nexthop_active_update(struct route_node *rn, struct route_entry *re)
1130{
1131 struct nexthop *nexthop;
1132 union g_addr prev_src;
1133 unsigned int prev_active, new_active;
1134 ifindex_t prev_index;
9a0d4dd3 1135 uint8_t curr_active = 0;
ad28e79a 1136
ad28e79a
SW
1137 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
1138
6b468511 1139 for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
ad28e79a
SW
1140 /* No protocol daemon provides src and so we're skipping
1141 * tracking it */
1142 prev_src = nexthop->rmap_src;
1143 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1144 prev_index = nexthop->ifindex;
1145 /*
1146 * We need to respect the multipath_num here
1147 * as that what we should be able to install from
1148 * a multipath perpsective should not be a data plane
1149 * decision point.
1150 */
1151 new_active = nexthop_active_check(rn, re, nexthop);
1152 if (new_active
9a0d4dd3
DS
1153 && nexthop_group_active_nexthop_num(re->ng)
1154 >= zrouter.multipath_num) {
ad28e79a
SW
1155 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
1156 new_active = 0;
1157 }
9a0d4dd3 1158
ad28e79a 1159 if (new_active)
9a0d4dd3
DS
1160 curr_active++;
1161
ad28e79a
SW
1162 /* Don't allow src setting on IPv6 addr for now */
1163 if (prev_active != new_active || prev_index != nexthop->ifindex
1164 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
1165 && nexthop->type < NEXTHOP_TYPE_IPV6)
1166 && prev_src.ipv4.s_addr
1167 != nexthop->rmap_src.ipv4.s_addr)
1168 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
1169 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
1170 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
1171 &nexthop->rmap_src.ipv6)))
42fc558e 1172 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 1173 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
1174 }
1175
9a0d4dd3 1176 return curr_active;
ad28e79a 1177}
5be96a2d
SW
1178
1179/**
1180 * zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel
1181 *
1182 * @nhe: Nexthop Group hash entry to install
1183 */
1184void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
1185{
147bad16
SW
1186 if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1187 nhe->is_kernel_nh = false;
1188 int ret = dplane_nexthop_add(nhe);
1189 switch (ret) {
1190 case ZEBRA_DPLANE_REQUEST_QUEUED:
1191 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1192 break;
1193 case ZEBRA_DPLANE_REQUEST_FAILURE:
1194 flog_err(
1195 EC_ZEBRA_DP_INSTALL_FAIL,
1196 "Failed to install Nexthop ID (%u) into the kernel",
1197 nhe->id);
1198 break;
1199 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1200 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1201 break;
1202 }
1203 }
1204}
1205
1206/**
1207 * zebra_nhg_uninstall_kernel() - Uninstall Nexthop Group hash entry into kernel
1208 *
1209 * @nhe: Nexthop Group hash entry to uninstall
1210 */
1211void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
1212{
1213 if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
1214 int ret = dplane_nexthop_delete(nhe);
1215 switch (ret) {
1216 case ZEBRA_DPLANE_REQUEST_QUEUED:
1217 SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
1218 break;
1219 case ZEBRA_DPLANE_REQUEST_FAILURE:
1220 flog_err(
1221 EC_ZEBRA_DP_DELETE_FAIL,
1222 "Failed to uninstall Nexthop ID (%u) from the kernel",
1223 nhe->id);
1224 break;
1225 case ZEBRA_DPLANE_REQUEST_SUCCESS:
1226 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1227 break;
1228 }
1229 }
1230}
1231
3e0372d2
SW
1232/**
1233 * zebra_nhg_uninstall_created() - Uninstall nexthops we created in the kernel
1234 *
1235 * @nhe: Nexthop group hash entry
1236 */
1237static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
1238{
1239 struct nhg_hash_entry *nhe = NULL;
1240
1241 nhe = (struct nhg_hash_entry *)bucket->data;
1242
1243 if (nhe && !nhe->is_kernel_nh)
1244 zebra_nhg_uninstall_kernel(nhe);
1245}
1246
1247/**
1248 * zebra_nhg_cleanup_tables() - Iterate over our tables to uninstall nh's
1249 * we created
1250 */
1251void zebra_nhg_cleanup_tables(void)
1252{
1253 hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL);
1254}
1255
5f3c9e52
SW
1256/**
1257 * zebra_nhg_dplane_result() - Process dplane result
1258 *
1259 * @ctx: Dataplane context
1260 */
1261void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
1262{
1263 enum dplane_op_e op;
1264 enum zebra_dplane_result status;
1265 uint32_t id = 0;
1266 struct nhg_hash_entry *nhe = NULL;
1267
1268 op = dplane_ctx_get_op(ctx);
1269 status = dplane_ctx_get_status(ctx);
1270
0c8215cb 1271 id = dplane_ctx_get_nhe_id(ctx);
5f3c9e52
SW
1272 nhe = zebra_nhg_lookup_id(id);
1273
1274 if (nhe) {
7512f617 1275 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
5f3c9e52
SW
1276 if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
1277 zlog_debug(
1278 "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
1279 ctx, dplane_op2str(op), nhe->id,
1280 dplane_res2str(status));
1281
1282 switch (op) {
1283 case DPLANE_OP_NH_DELETE:
1284 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1285 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
5f3c9e52
SW
1286 } else {
1287 flog_err(
1288 EC_ZEBRA_DP_DELETE_FAIL,
1289 "Failed to uninstall Nexthop ID (%u) from the kernel",
1290 nhe->id);
1291 }
1292 break;
1293 case DPLANE_OP_NH_INSTALL:
1294 case DPLANE_OP_NH_UPDATE:
1295 if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
1296 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1297 } else {
1298 flog_err(
1299 EC_ZEBRA_DP_INSTALL_FAIL,
1300 "Failed to install Nexthop ID (%u) into the kernel",
1301 nhe->id);
1302 UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
1303 }
5f3c9e52
SW
1304 break;
1305 case DPLANE_OP_ROUTE_INSTALL:
1306 case DPLANE_OP_ROUTE_UPDATE:
1307 case DPLANE_OP_ROUTE_DELETE:
1308 case DPLANE_OP_ROUTE_NOTIFY:
1309 case DPLANE_OP_LSP_INSTALL:
1310 case DPLANE_OP_LSP_UPDATE:
1311 case DPLANE_OP_LSP_DELETE:
1312 case DPLANE_OP_LSP_NOTIFY:
1313 case DPLANE_OP_PW_INSTALL:
1314 case DPLANE_OP_PW_UNINSTALL:
1315 case DPLANE_OP_SYS_ROUTE_ADD:
1316 case DPLANE_OP_SYS_ROUTE_DELETE:
1317 case DPLANE_OP_ADDR_INSTALL:
1318 case DPLANE_OP_ADDR_UNINSTALL:
1319 case DPLANE_OP_MAC_INSTALL:
1320 case DPLANE_OP_MAC_DELETE:
1321 case DPLANE_OP_NONE:
1322 break;
1323 }
1324 dplane_ctx_fini(&ctx);
1325
1326 } else {
1327 flog_err(
1328 EC_ZEBRA_NHG_SYNC,
1329 "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
1330 dplane_op2str(op), id);
5be96a2d
SW
1331 }
1332}
1333