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