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