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