]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_nhg.c
zebra: Add a queued flag to nhg_hash_entry
[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"
ad28e79a
SW
30
31#include "zebra/connected.h"
32#include "zebra/debug.h"
33#include "zebra/zebra_router.h"
34#include "zebra/zebra_nhg.h"
35#include "zebra/zebra_rnh.h"
36#include "zebra/zebra_routemap.h"
37#include "zebra/rt.h"
d9f5b2f5
SW
38#include "zebra_errors.h"
39
40/**
41 * zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
42 *
43 * @id: ID to look for
44 *
45 * Return: Nexthop hash entry if found/NULL if not found
46 */
47struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
48{
49 struct nhg_hash_entry lookup = {0};
50
51 lookup.id = id;
52 return hash_lookup(zrouter.nhgs_id, &lookup);
53}
54
55/**
56 * zebra_nhg_insert_id() - Insert a nhe into the id hashed table
57 *
58 * @nhe: The entry directly from the other table
59 *
60 * Return: Result status
61 */
62int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
63{
64 if (hash_lookup(zrouter.nhgs_id, nhe)) {
65 flog_err(
66 EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
67 "Failed inserting NHG id=%u into the ID hash table, entry already exists",
68 nhe->id);
69 return -1;
70 }
71
72 hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
73
74 return 0;
75}
ad28e79a 76
4e49c8b8
DS
77
78static void *zebra_nhg_alloc(void *arg)
79{
d9f5b2f5
SW
80 /* lock for getiing and setting the id */
81 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
82 /* id counter to keep in sync with kernel */
83 static uint32_t id_counter = 0;
4e49c8b8
DS
84 struct nhg_hash_entry *nhe;
85 struct nhg_hash_entry *copy = arg;
86
d9f5b2f5
SW
87 nhe = XCALLOC(MTYPE_TMP, sizeof(struct nhg_hash_entry));
88
89 pthread_mutex_lock(&lock); /* Lock, set the id counter from kernel */
90 if (copy->id) {
91 /* This is from the kernel if it has an id */
92 if (copy->id > id_counter) {
93 /* Increase our counter so we don't try to create
94 * an ID that already exists
95 */
96 id_counter = copy->id;
97 }
98 nhe->id = copy->id;
99 /* Mark as valid since from the kernel */
100 SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
101 SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
102 } else {
103 nhe->id = ++id_counter;
104 }
105 pthread_mutex_unlock(&lock);
4e49c8b8
DS
106
107 nhe->vrf_id = copy->vrf_id;
4e49c8b8 108 nhe->refcnt = 0;
d9f5b2f5 109 nhe->is_kernel_nh = false;
4e49c8b8
DS
110 nhe->dplane_ref = zebra_router_get_next_sequence();
111 nhe->nhg.nexthop = NULL;
112
113 nexthop_group_copy(&nhe->nhg, &copy->nhg);
114
d9f5b2f5
SW
115 /* Add to id table as well */
116 zebra_nhg_insert_id(nhe);
117
4e49c8b8
DS
118
119 return nhe;
120}
121
122static uint32_t zebra_nhg_hash_key_nexthop_group(struct nexthop_group *nhg)
123{
124 struct nexthop *nh;
125 uint32_t i;
126 uint32_t key = 0;
127
128 /*
129 * We are not interested in hashing over any recursively
130 * resolved nexthops
131 */
132 for (nh = nhg->nexthop; nh; nh = nh->next) {
8b5bdc8b 133 key = jhash_1word(nh->type, key);
4e49c8b8
DS
134 key = jhash_2words(nh->vrf_id, nh->nh_label_type, key);
135 /* gate and blackhole are together in a union */
136 key = jhash(&nh->gate, sizeof(nh->gate), key);
137 key = jhash(&nh->src, sizeof(nh->src), key);
138 key = jhash(&nh->rmap_src, sizeof(nh->rmap_src), key);
139 if (nh->nh_label) {
140 for (i = 0; i < nh->nh_label->num_labels; i++)
141 key = jhash_1word(nh->nh_label->label[i], key);
142 }
143 switch (nh->type) {
144 case NEXTHOP_TYPE_IPV4_IFINDEX:
145 case NEXTHOP_TYPE_IPV6_IFINDEX:
146 case NEXTHOP_TYPE_IFINDEX:
147 key = jhash_1word(nh->ifindex, key);
148 break;
149 case NEXTHOP_TYPE_BLACKHOLE:
150 case NEXTHOP_TYPE_IPV4:
151 case NEXTHOP_TYPE_IPV6:
152 break;
153 }
154 }
155 return key;
156}
157
158uint32_t zebra_nhg_hash_key(const void *arg)
159{
160 const struct nhg_hash_entry *nhe = arg;
d9f5b2f5 161
4e49c8b8
DS
162 int key = 0x5a351234;
163
8b5bdc8b 164 key = jhash_1word(nhe->vrf_id, key);
4e49c8b8 165
d9f5b2f5
SW
166 key = jhash_1word(zebra_nhg_hash_key_nexthop_group(&nhe->nhg), key);
167
168
169 return key;
4e49c8b8
DS
170}
171
a95b8020
SW
172uint32_t zebra_nhg_id_key(const void *arg)
173{
174 const struct nhg_hash_entry *nhe = arg;
175
176 return nhe->id;
177}
178
4e49c8b8
DS
179bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
180{
181 const struct nhg_hash_entry *nhe1 = arg1;
182 const struct nhg_hash_entry *nhe2 = arg2;
183 struct nexthop *nh1, *nh2;
184 uint32_t nh_count = 0;
185
186 if (nhe1->vrf_id != nhe2->vrf_id)
187 return false;
188
4e49c8b8
DS
189 /*
190 * Again we are not interested in looking at any recursively
191 * resolved nexthops. Top level only
192 */
193 for (nh1 = nhe1->nhg.nexthop; nh1; nh1 = nh1->next) {
194 uint32_t inner_nh_count = 0;
195 for (nh2 = nhe2->nhg.nexthop; nh2; nh2 = nh2->next) {
196 if (inner_nh_count == nh_count) {
197 break;
198 }
199 inner_nh_count++;
200 }
201
202 if (!nexthop_same(nh1, nh2))
203 return false;
204
205 nh_count++;
206 }
207
208 return true;
209}
210
d9f5b2f5 211bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
4e49c8b8 212{
d9f5b2f5
SW
213 const struct nhg_hash_entry *nhe1 = arg1;
214 const struct nhg_hash_entry *nhe2 = arg2;
4e49c8b8 215
d9f5b2f5
SW
216 return nhe1->id == nhe2->id;
217}
4e49c8b8 218
d9f5b2f5
SW
219struct nhg_hash_entry *zebra_nhg_find_id(uint32_t id, struct nexthop_group *nhg)
220{
221 // TODO: How this will work is yet to be determined
222 return NULL;
4e49c8b8
DS
223}
224
d9f5b2f5
SW
225/**
226 * zebra_nhg_find() - Find the zebra nhg in our table, or create it
227 *
228 * @nhg: Nexthop group we lookup with
229 * @vrf_id: VRF id
230 * @id: ID we lookup with, 0 means its from us and we need to give it
231 * an ID, otherwise its from the kernel as we use the ID it gave
232 * us.
233 *
234 * Return: Hash entry found or created
235 */
236struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
237 vrf_id_t vrf_id, uint32_t id)
a95b8020
SW
238{
239 struct nhg_hash_entry lookup = {0};
d9f5b2f5 240 struct nhg_hash_entry *nhe = NULL;
a95b8020 241
d9f5b2f5
SW
242 lookup.id = id;
243 lookup.vrf_id = vrf_id;
a95b8020
SW
244 lookup.nhg = *nhg;
245
d9f5b2f5
SW
246
247 nhe = hash_lookup(zrouter.nhgs, &lookup);
248
249 if (!nhe) {
250 nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
251 } else {
252 if (id) {
253 /* Duplicate but with different ID from the kernel */
254
255 /* The kernel allows duplicate nexthops as long as they
256 * have different IDs. We are ignoring those to prevent
257 * syncing problems with the kernel changes.
258 */
259 flog_warn(
260 EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
261 "Nexthop Group from kernel with ID (%d) is a duplicate, ignoring",
262 id);
263 return NULL;
264 }
265 }
266
267 return nhe;
a95b8020
SW
268}
269
d9f5b2f5
SW
270/**
271 * zebra_nhg_free() - Free the nexthop group hash entry
272 *
273 * arg: Nexthop group entry to free
274 */
275void zebra_nhg_free(void *arg)
a95b8020 276{
d9f5b2f5 277 struct nhg_hash_entry *nhe = NULL;
a95b8020 278
d9f5b2f5 279 nhe = (struct nhg_hash_entry *)arg;
a95b8020 280
d9f5b2f5
SW
281 nexthops_free(nhe->nhg.nexthop);
282 XFREE(MTYPE_TMP, nhe);
a95b8020
SW
283}
284
d9f5b2f5
SW
285/**
286 * zebra_nhg_release() - Release a nhe from the tables
287 *
288 * @nhe: Nexthop group hash entry
289 */
290void zebra_nhg_release(struct nhg_hash_entry *nhe)
4e49c8b8 291{
d9f5b2f5
SW
292 if (nhe->refcnt) {
293 flog_err(
294 EC_ZEBRA_NHG_SYNC,
295 "Kernel deleted a nexthop group with ID (%u) that we are still using for a route",
296 nhe->id);
297 // TODO: Re-send to kernel
298 }
4e49c8b8 299
d9f5b2f5
SW
300 hash_release(zrouter.nhgs, nhe);
301 hash_release(zrouter.nhgs_id, nhe);
302 zebra_nhg_free(nhe);
303}
4e49c8b8 304
d9f5b2f5
SW
305/**
306 * zebra_nhg_decrement_ref() - Decrement the reference count, release if unused
307 *
308 * @nhe: Nexthop group hash entry
309 *
310 * If the counter hits 0 and is not a nexthop group that was created by the
311 * kernel, we don't need to have it in our table anymore.
312 */
313void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
314{
4e49c8b8
DS
315 nhe->refcnt--;
316
d9f5b2f5
SW
317 if (!nhe->is_kernel_nh && nhe->refcnt <= 0) {
318 zebra_nhg_release(nhe);
319 }
320
4e49c8b8
DS
321 // re->ng = NULL;
322}
323
ad28e79a
SW
324static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
325 struct nexthop *nexthop)
326{
327 struct nexthop *resolved_hop;
b43434ad
SW
328 uint8_t num_labels = 0;
329 mpls_label_t labels[MPLS_MAX_LABELS];
330 enum lsp_types_t label_type = ZEBRA_LSP_NONE;
331 int i = 0;
ad28e79a
SW
332
333 resolved_hop = nexthop_new();
334 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
335
336 resolved_hop->vrf_id = nexthop->vrf_id;
337 switch (newhop->type) {
338 case NEXTHOP_TYPE_IPV4:
339 case NEXTHOP_TYPE_IPV4_IFINDEX:
340 /* If the resolving route specifies a gateway, use it */
341 resolved_hop->type = newhop->type;
342 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
343
344 if (newhop->ifindex) {
345 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
346 resolved_hop->ifindex = newhop->ifindex;
347 }
348 break;
349 case NEXTHOP_TYPE_IPV6:
350 case NEXTHOP_TYPE_IPV6_IFINDEX:
351 resolved_hop->type = newhop->type;
352 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
353
354 if (newhop->ifindex) {
355 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
356 resolved_hop->ifindex = newhop->ifindex;
357 }
358 break;
359 case NEXTHOP_TYPE_IFINDEX:
360 /* If the resolving route is an interface route,
361 * it means the gateway we are looking up is connected
362 * to that interface. (The actual network is _not_ onlink).
363 * Therefore, the resolved route should have the original
364 * gateway as nexthop as it is directly connected.
365 *
366 * On Linux, we have to set the onlink netlink flag because
367 * otherwise, the kernel won't accept the route.
368 */
369 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
370 if (afi == AFI_IP) {
371 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
372 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
373 } else if (afi == AFI_IP6) {
374 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
375 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
376 }
377 resolved_hop->ifindex = newhop->ifindex;
378 break;
379 case NEXTHOP_TYPE_BLACKHOLE:
380 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
2dc359a6 381 resolved_hop->bh_type = newhop->bh_type;
ad28e79a
SW
382 break;
383 }
384
385 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
386 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
387
b43434ad
SW
388 /* Copy labels of the resolved route and the parent resolving to it */
389 if (newhop->nh_label) {
390 for (i = 0; i < newhop->nh_label->num_labels; i++)
391 labels[num_labels++] = newhop->nh_label->label[i];
392 label_type = newhop->nh_label_type;
393 }
394
395 if (nexthop->nh_label) {
396 for (i = 0; i < nexthop->nh_label->num_labels; i++)
397 labels[num_labels++] = nexthop->nh_label->label[i];
398
399 /* If the parent has labels, use its type */
400 label_type = nexthop->nh_label_type;
401 }
402
403 if (num_labels)
404 nexthop_add_labels(resolved_hop, label_type, num_labels,
405 labels);
ad28e79a
SW
406
407 resolved_hop->rparent = nexthop;
50d89650 408 _nexthop_add(&nexthop->resolved, resolved_hop);
ad28e79a
SW
409}
410
6913cb1b
SW
411/* Checks if nexthop we are trying to resolve to is valid */
412static bool nexthop_valid_resolve(const struct nexthop *nexthop,
413 const struct nexthop *resolved)
414{
415 /* Can't resolve to a recursive nexthop */
416 if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
417 return false;
418
419 switch (nexthop->type) {
420 case NEXTHOP_TYPE_IPV4_IFINDEX:
421 case NEXTHOP_TYPE_IPV6_IFINDEX:
422 /* If the nexthop we are resolving to does not match the
423 * ifindex for the nexthop the route wanted, its not valid.
424 */
425 if (nexthop->ifindex != resolved->ifindex)
426 return false;
427 break;
428 case NEXTHOP_TYPE_IPV4:
429 case NEXTHOP_TYPE_IPV6:
430 case NEXTHOP_TYPE_IFINDEX:
431 case NEXTHOP_TYPE_BLACKHOLE:
432 break;
433 }
434
435 return true;
436}
437
ad28e79a
SW
438/*
439 * Given a nexthop we need to properly recursively resolve
440 * the route. As such, do a table lookup to find and match
441 * if at all possible. Set the nexthop->ifindex as appropriate
442 */
443static int nexthop_active(afi_t afi, struct route_entry *re,
444 struct nexthop *nexthop, struct route_node *top)
445{
446 struct prefix p;
447 struct route_table *table;
448 struct route_node *rn;
449 struct route_entry *match = NULL;
450 int resolved;
451 struct nexthop *newhop;
452 struct interface *ifp;
453 rib_dest_t *dest;
5a0bdc78 454 struct zebra_vrf *zvrf;
ad28e79a
SW
455
456 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
457 || nexthop->type == NEXTHOP_TYPE_IPV6)
458 nexthop->ifindex = 0;
459
460 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
461 nexthops_free(nexthop->resolved);
462 nexthop->resolved = NULL;
463 re->nexthop_mtu = 0;
464
465 /*
a8c427ee 466 * If the kernel has sent us a NEW route, then
ad28e79a 467 * by golly gee whiz it's a good route.
a8c427ee
SW
468 *
469 * If its an already INSTALLED route we have already handled, then the
470 * kernel route's nexthop might have became unreachable
471 * and we have to handle that.
ad28e79a 472 */
a8c427ee
SW
473 if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
474 && (re->type == ZEBRA_ROUTE_KERNEL
475 || re->type == ZEBRA_ROUTE_SYSTEM))
ad28e79a
SW
476 return 1;
477
478 /*
479 * Check to see if we should trust the passed in information
480 * for UNNUMBERED interfaces as that we won't find the GW
481 * address in the routing table.
482 * This check should suffice to handle IPv4 or IPv6 routes
483 * sourced from EVPN routes which are installed with the
484 * next hop as the remote VTEP IP.
485 */
486 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
487 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
488 if (!ifp) {
489 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
490 zlog_debug(
491 "\t%s: Onlink and interface: %u[%u] does not exist",
492 __PRETTY_FUNCTION__, nexthop->ifindex,
493 nexthop->vrf_id);
494 return 0;
495 }
496 if (connected_is_unnumbered(ifp)) {
497 if (if_is_operative(ifp))
498 return 1;
499 else {
500 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
501 zlog_debug(
502 "\t%s: Onlink and interface %s is not operative",
503 __PRETTY_FUNCTION__, ifp->name);
504 return 0;
505 }
506 }
507 if (!if_is_operative(ifp)) {
508 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
509 zlog_debug(
510 "\t%s: Interface %s is not unnumbered",
511 __PRETTY_FUNCTION__, ifp->name);
512 return 0;
513 }
514 }
515
516 /* Make lookup prefix. */
517 memset(&p, 0, sizeof(struct prefix));
518 switch (afi) {
519 case AFI_IP:
520 p.family = AF_INET;
521 p.prefixlen = IPV4_MAX_PREFIXLEN;
522 p.u.prefix4 = nexthop->gate.ipv4;
523 break;
524 case AFI_IP6:
525 p.family = AF_INET6;
526 p.prefixlen = IPV6_MAX_PREFIXLEN;
527 p.u.prefix6 = nexthop->gate.ipv6;
528 break;
529 default:
530 assert(afi != AFI_IP && afi != AFI_IP6);
531 break;
532 }
533 /* Lookup table. */
534 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
5a0bdc78
PG
535 /* get zvrf */
536 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
537 if (!table || !zvrf) {
ad28e79a
SW
538 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
539 zlog_debug("\t%s: Table not found",
540 __PRETTY_FUNCTION__);
541 return 0;
542 }
543
544 rn = route_node_match(table, (struct prefix *)&p);
545 while (rn) {
546 route_unlock_node(rn);
547
548 /* Lookup should halt if we've matched against ourselves ('top',
549 * if specified) - i.e., we cannot have a nexthop NH1 is
550 * resolved by a route NH1. The exception is if the route is a
551 * host route.
552 */
553 if (top && rn == top)
554 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
555 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
556 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
557 zlog_debug(
558 "\t%s: Matched against ourself and prefix length is not max bit length",
559 __PRETTY_FUNCTION__);
560 return 0;
561 }
562
563 /* Pick up selected route. */
564 /* However, do not resolve over default route unless explicitly
565 * allowed. */
566 if (is_default_prefix(&rn->p)
5a0bdc78 567 && !rnh_resolve_via_default(zvrf, p.family)) {
ad28e79a
SW
568 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
569 zlog_debug(
570 "\t:%s: Resolved against default route",
571 __PRETTY_FUNCTION__);
572 return 0;
573 }
574
575 dest = rib_dest_from_rnode(rn);
576 if (dest && dest->selected_fib
577 && !CHECK_FLAG(dest->selected_fib->status,
578 ROUTE_ENTRY_REMOVED)
579 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
580 match = dest->selected_fib;
581
582 /* If there is no selected route or matched route is EGP, go up
583 tree. */
584 if (!match) {
585 do {
586 rn = rn->parent;
587 } while (rn && rn->info == NULL);
588 if (rn)
589 route_lock_node(rn);
590
591 continue;
592 }
593
594 if (match->type == ZEBRA_ROUTE_CONNECT) {
595 /* Directly point connected route. */
6b468511 596 newhop = match->ng->nexthop;
ad28e79a
SW
597 if (newhop) {
598 if (nexthop->type == NEXTHOP_TYPE_IPV4
599 || nexthop->type == NEXTHOP_TYPE_IPV6)
600 nexthop->ifindex = newhop->ifindex;
601 }
602 return 1;
603 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
604 resolved = 0;
6b468511 605 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
606 if (!CHECK_FLAG(match->status,
607 ROUTE_ENTRY_INSTALLED))
608 continue;
6913cb1b 609 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
610 continue;
611
612 SET_FLAG(nexthop->flags,
613 NEXTHOP_FLAG_RECURSIVE);
ad28e79a
SW
614 nexthop_set_resolved(afi, newhop, nexthop);
615 resolved = 1;
616 }
617 if (resolved)
618 re->nexthop_mtu = match->mtu;
619 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
620 zlog_debug("\t%s: Recursion failed to find",
621 __PRETTY_FUNCTION__);
622 return resolved;
623 } else if (re->type == ZEBRA_ROUTE_STATIC) {
624 resolved = 0;
6b468511 625 for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
ad28e79a
SW
626 if (!CHECK_FLAG(match->status,
627 ROUTE_ENTRY_INSTALLED))
628 continue;
6913cb1b 629 if (!nexthop_valid_resolve(nexthop, newhop))
ad28e79a
SW
630 continue;
631
632 SET_FLAG(nexthop->flags,
633 NEXTHOP_FLAG_RECURSIVE);
634 nexthop_set_resolved(afi, newhop, nexthop);
635 resolved = 1;
636 }
637 if (resolved)
638 re->nexthop_mtu = match->mtu;
639
640 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
641 zlog_debug(
642 "\t%s: Static route unable to resolve",
643 __PRETTY_FUNCTION__);
644 return resolved;
645 } else {
646 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
647 zlog_debug(
648 "\t%s: Route Type %s has not turned on recursion",
649 __PRETTY_FUNCTION__,
650 zebra_route_string(re->type));
651 if (re->type == ZEBRA_ROUTE_BGP
652 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
653 zlog_debug(
654 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
655 }
656 return 0;
657 }
658 }
659 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
660 zlog_debug("\t%s: Nexthop did not lookup in table",
661 __PRETTY_FUNCTION__);
662 return 0;
663}
664
665/* This function verifies reachability of one given nexthop, which can be
666 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
667 * in nexthop->flags field. The nexthop->ifindex will be updated
668 * appropriately as well. An existing route map can turn
669 * (otherwise active) nexthop into inactive, but not vice versa.
670 *
671 * The return value is the final value of 'ACTIVE' flag.
672 */
673static unsigned nexthop_active_check(struct route_node *rn,
674 struct route_entry *re,
675 struct nexthop *nexthop)
676{
677 struct interface *ifp;
b68885f9 678 route_map_result_t ret = RMAP_PERMITMATCH;
ad28e79a
SW
679 int family;
680 char buf[SRCDEST2STR_BUFFER];
681 const struct prefix *p, *src_p;
682 struct zebra_vrf *zvrf;
683
684 srcdest_rnode_prefixes(rn, &p, &src_p);
685
686 if (rn->p.family == AF_INET)
687 family = AFI_IP;
688 else if (rn->p.family == AF_INET6)
689 family = AFI_IP6;
690 else
691 family = 0;
692 switch (nexthop->type) {
693 case NEXTHOP_TYPE_IFINDEX:
694 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
695 if (ifp && if_is_operative(ifp))
696 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
697 else
698 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
699 break;
700 case NEXTHOP_TYPE_IPV4:
701 case NEXTHOP_TYPE_IPV4_IFINDEX:
702 family = AFI_IP;
703 if (nexthop_active(AFI_IP, re, nexthop, rn))
704 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
705 else
706 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
707 break;
708 case NEXTHOP_TYPE_IPV6:
709 family = AFI_IP6;
710 if (nexthop_active(AFI_IP6, re, nexthop, rn))
711 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
712 else
713 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
714 break;
715 case NEXTHOP_TYPE_IPV6_IFINDEX:
716 /* RFC 5549, v4 prefix with v6 NH */
717 if (rn->p.family != AF_INET)
718 family = AFI_IP6;
719 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
720 ifp = if_lookup_by_index(nexthop->ifindex,
721 nexthop->vrf_id);
722 if (ifp && if_is_operative(ifp))
723 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
724 else
725 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
726 } else {
727 if (nexthop_active(AFI_IP6, re, nexthop, rn))
728 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
729 else
730 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
731 }
732 break;
733 case NEXTHOP_TYPE_BLACKHOLE:
734 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
735 break;
736 default:
737 break;
738 }
739 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
740 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
741 zlog_debug("\t%s: Unable to find a active nexthop",
742 __PRETTY_FUNCTION__);
743 return 0;
744 }
745
746 /* XXX: What exactly do those checks do? Do we support
747 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
748 */
749 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
750 || (family == AFI_IP6 && p->family != AF_INET6))
751 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
752
753 /* The original code didn't determine the family correctly
754 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
755 * from the rib_table_info in those cases.
756 * Possibly it may be better to use only the rib_table_info
757 * in every case.
758 */
759 if (!family) {
760 rib_table_info_t *info;
761
762 info = srcdest_rnode_table_info(rn);
763 family = info->afi;
764 }
765
766 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
767
768 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
769 if (!zvrf) {
770 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
771 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
772 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
773 }
774
775 /* It'll get set if required inside */
776 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
777 zvrf, re->tag);
778 if (ret == RMAP_DENYMATCH) {
779 if (IS_ZEBRA_DEBUG_RIB) {
780 srcdest_rnode2str(rn, buf, sizeof(buf));
781 zlog_debug(
782 "%u:%s: Filtering out with NH out %s due to route map",
783 re->vrf_id, buf,
784 ifindex2ifname(nexthop->ifindex,
785 nexthop->vrf_id));
786 }
787 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
788 }
789 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
790}
791
792/*
793 * Iterate over all nexthops of the given RIB entry and refresh their
9a0d4dd3
DS
794 * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
795 * the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
ad28e79a
SW
796 *
797 * Return value is the new number of active nexthops.
798 */
799int nexthop_active_update(struct route_node *rn, struct route_entry *re)
800{
801 struct nexthop *nexthop;
802 union g_addr prev_src;
803 unsigned int prev_active, new_active;
804 ifindex_t prev_index;
9a0d4dd3 805 uint8_t curr_active = 0;
ad28e79a 806
ad28e79a
SW
807 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
808
6b468511 809 for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
ad28e79a
SW
810 /* No protocol daemon provides src and so we're skipping
811 * tracking it */
812 prev_src = nexthop->rmap_src;
813 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
814 prev_index = nexthop->ifindex;
815 /*
816 * We need to respect the multipath_num here
817 * as that what we should be able to install from
818 * a multipath perpsective should not be a data plane
819 * decision point.
820 */
821 new_active = nexthop_active_check(rn, re, nexthop);
822 if (new_active
9a0d4dd3
DS
823 && nexthop_group_active_nexthop_num(re->ng)
824 >= zrouter.multipath_num) {
ad28e79a
SW
825 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
826 new_active = 0;
827 }
9a0d4dd3 828
ad28e79a 829 if (new_active)
9a0d4dd3
DS
830 curr_active++;
831
ad28e79a
SW
832 /* Don't allow src setting on IPv6 addr for now */
833 if (prev_active != new_active || prev_index != nexthop->ifindex
834 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
835 && nexthop->type < NEXTHOP_TYPE_IPV6)
836 && prev_src.ipv4.s_addr
837 != nexthop->rmap_src.ipv4.s_addr)
838 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
839 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
840 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
841 &nexthop->rmap_src.ipv6)))
42fc558e 842 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
ad28e79a 843 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
ad28e79a
SW
844 }
845
9a0d4dd3 846 return curr_active;
ad28e79a 847}