]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_route.c
Merge pull request #11569 from opensourcerouting/gcc-plugin-shortcomings-220708
[mirror_frr.git] / isisd / isis_route.c
1 /*
2 * IS-IS Rout(e)ing protocol - isis_route.c
3 * Copyright (C) 2001,2002 Sampo Saaristo
4 * Tampere University of Technology
5 * Institute of Communications Engineering
6 *
7 * based on ../ospf6d/ospf6_route.[ch]
8 * by Yasuhiro Ohara
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public Licenseas published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <zebra.h>
26
27 #include "thread.h"
28 #include "linklist.h"
29 #include "vty.h"
30 #include "log.h"
31 #include "lib_errors.h"
32 #include "memory.h"
33 #include "prefix.h"
34 #include "hash.h"
35 #include "if.h"
36 #include "table.h"
37 #include "srcdest_table.h"
38
39 #include "isis_constants.h"
40 #include "isis_common.h"
41 #include "isis_flags.h"
42 #include "isisd.h"
43 #include "isis_misc.h"
44 #include "isis_adjacency.h"
45 #include "isis_circuit.h"
46 #include "isis_pdu.h"
47 #include "isis_lsp.h"
48 #include "isis_spf.h"
49 #include "isis_spf_private.h"
50 #include "isis_route.h"
51 #include "isis_zebra.h"
52
53 DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
54 DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
55
56 DEFINE_HOOK(isis_route_update_hook,
57 (struct isis_area * area, struct prefix *prefix,
58 struct isis_route_info *route_info),
59 (area, prefix, route_info));
60
61 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
62 union g_addr *ip, ifindex_t ifindex);
63 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
64 struct prefix_ipv6 *src_p,
65 struct isis_route_info *route_info);
66
67 static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
68 ifindex_t ifindex)
69 {
70 struct isis_nexthop *nexthop;
71
72 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
73
74 nexthop->family = family;
75 nexthop->ifindex = ifindex;
76 nexthop->ip = *ip;
77
78 return nexthop;
79 }
80
81 void isis_nexthop_delete(struct isis_nexthop *nexthop)
82 {
83 XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
84 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
85 }
86
87 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
88 union g_addr *ip, ifindex_t ifindex)
89 {
90 struct listnode *node;
91 struct isis_nexthop *nh;
92
93 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
94 if (nh->ifindex != ifindex)
95 continue;
96
97 /* if the IP is unspecified, return the first nexthop found on
98 * the interface */
99 if (!ip)
100 return nh;
101
102 if (nh->family != family)
103 continue;
104
105 switch (family) {
106 case AF_INET:
107 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
108 continue;
109 break;
110 case AF_INET6:
111 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
112 continue;
113 break;
114 default:
115 flog_err(EC_LIB_DEVELOPMENT,
116 "%s: unknown address family [%d]", __func__,
117 family);
118 exit(1);
119 }
120
121 return nh;
122 }
123
124 return NULL;
125 }
126
127 void adjinfo2nexthop(int family, struct list *nexthops,
128 struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
129 struct mpls_label_stack *label_stack)
130 {
131 struct isis_nexthop *nh;
132 union g_addr ip = {};
133
134 switch (family) {
135 case AF_INET:
136 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
137 ip.ipv4 = adj->ipv4_addresses[i];
138
139 if (!nexthoplookup(nexthops, AF_INET, &ip,
140 adj->circuit->interface->ifindex)) {
141 nh = isis_nexthop_create(
142 AF_INET, &ip,
143 adj->circuit->interface->ifindex);
144 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
145 if (sr)
146 nh->sr = *sr;
147 nh->label_stack = label_stack;
148 listnode_add(nexthops, nh);
149 break;
150 }
151 }
152 break;
153 case AF_INET6:
154 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
155 ip.ipv6 = adj->ll_ipv6_addrs[i];
156
157 if (!nexthoplookup(nexthops, AF_INET6, &ip,
158 adj->circuit->interface->ifindex)) {
159 nh = isis_nexthop_create(
160 AF_INET6, &ip,
161 adj->circuit->interface->ifindex);
162 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
163 if (sr)
164 nh->sr = *sr;
165 nh->label_stack = label_stack;
166 listnode_add(nexthops, nh);
167 break;
168 }
169 }
170 break;
171 default:
172 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
173 __func__, family);
174 exit(1);
175 }
176 }
177
178 static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
179 const uint8_t *sysid,
180 struct isis_sr_psid_info *sr,
181 struct mpls_label_stack *label_stack)
182 {
183 struct isis_nexthop *nh;
184
185 nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
186 memcpy(nh->sysid, sysid, sizeof(nh->sysid));
187 nh->sr = *sr;
188 nh->label_stack = label_stack;
189 listnode_add(rinfo->nexthops, nh);
190 }
191
192 static struct isis_route_info *
193 isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
194 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
195 struct list *adjacencies, bool allow_ecmp)
196 {
197 struct isis_route_info *rinfo;
198 struct isis_vertex_adj *vadj;
199 struct listnode *node;
200
201 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
202
203 rinfo->nexthops = list_new();
204 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
205 struct isis_spf_adj *sadj = vadj->sadj;
206 struct isis_adjacency *adj = sadj->adj;
207 struct isis_sr_psid_info *sr = &vadj->sr;
208 struct mpls_label_stack *label_stack = vadj->label_stack;
209
210 /*
211 * Create dummy nexthops when running SPF on a testing
212 * environment.
213 */
214 if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
215 isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
216 label_stack);
217 if (!allow_ecmp)
218 break;
219 continue;
220 }
221
222 /* check for force resync this route */
223 if (CHECK_FLAG(adj->circuit->flags,
224 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
225 SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
226
227 /* update neighbor router address */
228 switch (prefix->family) {
229 case AF_INET:
230 if (depth == 2 && prefix->prefixlen == IPV4_MAX_BITLEN)
231 adj->router_address = prefix->u.prefix4;
232 break;
233 case AF_INET6:
234 if (depth == 2 && prefix->prefixlen == IPV6_MAX_BITLEN
235 && (!src_p || !src_p->prefixlen)) {
236 adj->router_address6 = prefix->u.prefix6;
237 }
238 break;
239 default:
240 flog_err(EC_LIB_DEVELOPMENT,
241 "%s: unknown address family [%d]", __func__,
242 prefix->family);
243 exit(1);
244 }
245 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
246 label_stack);
247 if (!allow_ecmp)
248 break;
249 }
250
251 rinfo->cost = cost;
252 rinfo->depth = depth;
253 rinfo->sr = *sr;
254
255 return rinfo;
256 }
257
258 static void isis_route_info_delete(struct isis_route_info *route_info)
259 {
260 if (route_info->nexthops) {
261 route_info->nexthops->del =
262 (void (*)(void *))isis_nexthop_delete;
263 list_delete(&route_info->nexthops);
264 }
265
266 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
267 }
268
269 void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
270 {
271 if (node->info)
272 isis_route_info_delete(node->info);
273 }
274
275 static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
276 struct isis_sr_psid_info *old)
277 {
278 if (new->present != old->present)
279 return false;
280
281 if (new->label != old->label)
282 return false;
283
284 if (new->sid.flags != old->sid.flags
285 || new->sid.value != old->sid.value)
286 return false;
287
288 return true;
289 }
290
291 static bool isis_label_stack_same(struct mpls_label_stack *new,
292 struct mpls_label_stack *old)
293 {
294 if (!new && !old)
295 return true;
296 if (!new || !old)
297 return false;
298 if (new->num_labels != old->num_labels)
299 return false;
300 if (memcmp(&new->label, &old->label,
301 sizeof(mpls_label_t) * new->num_labels))
302 return false;
303
304 return true;
305 }
306
307 static int isis_route_info_same(struct isis_route_info *new,
308 struct isis_route_info *old, char *buf,
309 size_t buf_size)
310 {
311 struct listnode *node;
312 struct isis_nexthop *new_nh, *old_nh;
313
314 if (new->cost != old->cost) {
315 if (buf)
316 snprintf(buf, buf_size, "cost (old: %u, new: %u)",
317 old->cost, new->cost);
318 return 0;
319 }
320
321 if (new->depth != old->depth) {
322 if (buf)
323 snprintf(buf, buf_size, "depth (old: %u, new: %u)",
324 old->depth, new->depth);
325 return 0;
326 }
327
328 if (!isis_sr_psid_info_same(&new->sr, &old->sr)) {
329 if (buf)
330 snprintf(buf, buf_size, "SR input label");
331 return 0;
332 }
333
334 if (new->nexthops->count != old->nexthops->count) {
335 if (buf)
336 snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
337 old->nexthops->count, new->nexthops->count);
338 return 0;
339 }
340
341 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
342 old_nh = nexthoplookup(old->nexthops, new_nh->family,
343 &new_nh->ip, new_nh->ifindex);
344 if (!old_nh) {
345 if (buf)
346 snprintf(buf, buf_size,
347 "new nhop"); /* TODO: print nhop */
348 return 0;
349 }
350 if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
351 if (buf)
352 snprintf(buf, buf_size, "nhop SR label");
353 return 0;
354 }
355 if (!isis_label_stack_same(new_nh->label_stack,
356 old_nh->label_stack)) {
357 if (buf)
358 snprintf(buf, buf_size, "nhop label stack");
359 return 0;
360 }
361 }
362
363 /* only the resync flag needs to be checked */
364 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
365 != CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) {
366 if (buf)
367 snprintf(buf, buf_size, "resync flag");
368 return 0;
369 }
370
371 return 1;
372 }
373
374 struct isis_route_info *
375 isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
376 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
377 struct list *adjacencies, bool allow_ecmp,
378 struct isis_area *area, struct route_table *table)
379 {
380 struct route_node *route_node;
381 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
382 char change_buf[64];
383
384 if (!table)
385 return NULL;
386
387 rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
388 adjacencies, allow_ecmp);
389 route_node = srcdest_rnode_get(table, prefix, src_p);
390
391 rinfo_old = route_node->info;
392 if (!rinfo_old) {
393 if (IS_DEBUG_RTE_EVENTS)
394 zlog_debug("ISIS-Rte (%s) route created: %pFX",
395 area->area_tag, prefix);
396 route_info = rinfo_new;
397 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
398 } else {
399 route_unlock_node(route_node);
400 #ifdef EXTREME_DEBUG
401 if (IS_DEBUG_RTE_EVENTS)
402 zlog_debug("ISIS-Rte (%s) route already exists: %pFX",
403 area->area_tag, prefix);
404 #endif /* EXTREME_DEBUG */
405 if (isis_route_info_same(rinfo_new, rinfo_old, change_buf,
406 sizeof(change_buf))) {
407 #ifdef EXTREME_DEBUG
408 if (IS_DEBUG_RTE_EVENTS)
409 zlog_debug(
410 "ISIS-Rte (%s) route unchanged: %pFX",
411 area->area_tag, prefix);
412 #endif /* EXTREME_DEBUG */
413 isis_route_info_delete(rinfo_new);
414 route_info = rinfo_old;
415 } else {
416 if (IS_DEBUG_RTE_EVENTS)
417 zlog_debug(
418 "ISIS-Rte (%s): route changed: %pFX, change: %s",
419 area->area_tag, prefix, change_buf);
420 rinfo_new->sr_previous = rinfo_old->sr;
421 isis_route_info_delete(rinfo_old);
422 route_info = rinfo_new;
423 UNSET_FLAG(route_info->flag,
424 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
425 }
426 }
427
428 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
429 route_node->info = route_info;
430
431 return route_info;
432 }
433
434 void isis_route_delete(struct isis_area *area, struct route_node *rode,
435 struct route_table *table)
436 {
437 struct isis_route_info *rinfo;
438 char buff[SRCDEST2STR_BUFFER];
439 struct prefix *prefix;
440 struct prefix_ipv6 *src_p;
441
442 /* for log */
443 srcdest_rnode2str(rode, buff, sizeof(buff));
444
445 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
446 (const struct prefix **)&src_p);
447
448 rinfo = rode->info;
449 if (rinfo == NULL) {
450 if (IS_DEBUG_RTE_EVENTS)
451 zlog_debug(
452 "ISIS-Rte: tried to delete non-existent route %s",
453 buff);
454 return;
455 }
456
457 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
458 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
459 if (IS_DEBUG_RTE_EVENTS)
460 zlog_debug("ISIS-Rte: route delete %s", buff);
461 isis_route_update(area, prefix, src_p, rinfo);
462 }
463 isis_route_info_delete(rinfo);
464 rode->info = NULL;
465 route_unlock_node(rode);
466 }
467
468 static void isis_route_remove_previous_sid(struct isis_area *area,
469 struct prefix *prefix,
470 struct isis_route_info *route_info)
471 {
472 /*
473 * Explicitly uninstall previous Prefix-SID label if it has
474 * changed or was removed.
475 */
476 if (route_info->sr_previous.present &&
477 (!route_info->sr.present ||
478 route_info->sr_previous.label != route_info->sr.label))
479 isis_zebra_prefix_sid_uninstall(area, prefix, route_info,
480 &route_info->sr_previous);
481 }
482
483 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
484 struct prefix_ipv6 *src_p,
485 struct isis_route_info *route_info)
486 {
487 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
488 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
489 return;
490
491 isis_route_remove_previous_sid(area, prefix, route_info);
492
493 /* Install route. */
494 isis_zebra_route_add_route(area->isis, prefix, src_p,
495 route_info);
496 /* Install/reinstall Prefix-SID label. */
497 if (route_info->sr.present)
498 isis_zebra_prefix_sid_install(area, prefix, route_info,
499 &route_info->sr);
500 hook_call(isis_route_update_hook, area, prefix, route_info);
501
502 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
503 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
504 } else {
505 /* Uninstall Prefix-SID label. */
506 if (route_info->sr.present)
507 isis_zebra_prefix_sid_uninstall(
508 area, prefix, route_info, &route_info->sr);
509 /* Uninstall route. */
510 isis_zebra_route_del_route(area->isis, prefix, src_p,
511 route_info);
512 hook_call(isis_route_update_hook, area, prefix, route_info);
513
514 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
515 }
516 }
517
518 static void _isis_route_verify_table(struct isis_area *area,
519 struct route_table *table,
520 struct route_table *table_backup,
521 struct route_table **tables)
522 {
523 struct route_node *rnode, *drnode;
524 struct isis_route_info *rinfo;
525 #ifdef EXTREME_DEBUG
526 char buff[SRCDEST2STR_BUFFER];
527 #endif /* EXTREME_DEBUG */
528
529 for (rnode = route_top(table); rnode;
530 rnode = srcdest_route_next(rnode)) {
531 if (rnode->info == NULL)
532 continue;
533 rinfo = rnode->info;
534
535 struct prefix *dst_p;
536 struct prefix_ipv6 *src_p;
537
538 srcdest_rnode_prefixes(rnode,
539 (const struct prefix **)&dst_p,
540 (const struct prefix **)&src_p);
541
542 /* Link primary route to backup route. */
543 if (table_backup) {
544 struct route_node *rnode_bck;
545
546 rnode_bck = srcdest_rnode_lookup(table_backup, dst_p,
547 src_p);
548 if (rnode_bck) {
549 rinfo->backup = rnode_bck->info;
550 UNSET_FLAG(rinfo->flag,
551 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
552 } else if (rinfo->backup) {
553 rinfo->backup = NULL;
554 UNSET_FLAG(rinfo->flag,
555 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
556 }
557 }
558
559 #ifdef EXTREME_DEBUG
560 if (IS_DEBUG_RTE_EVENTS) {
561 srcdest2str(dst_p, src_p, buff, sizeof(buff));
562 zlog_debug(
563 "ISIS-Rte (%s): route validate: %s %s %s %s",
564 area->area_tag,
565 (CHECK_FLAG(rinfo->flag,
566 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
567 ? "synced"
568 : "not-synced"),
569 (CHECK_FLAG(rinfo->flag,
570 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
571 ? "resync"
572 : "not-resync"),
573 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
574 ? "active"
575 : "inactive"),
576 buff);
577 }
578 #endif /* EXTREME_DEBUG */
579
580 isis_route_update(area, dst_p, src_p, rinfo);
581
582 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
583 continue;
584
585 /* Area is either L1 or L2 => we use level route tables
586 * directly for
587 * validating => no problems with deleting routes. */
588 if (!tables) {
589 isis_route_delete(area, rnode, table);
590 continue;
591 }
592
593 /* If area is L1L2, we work with merge table and
594 * therefore must
595 * delete node from level tables as well before deleting
596 * route info. */
597 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
598 drnode = srcdest_rnode_lookup(tables[level - 1],
599 dst_p, src_p);
600 if (!drnode)
601 continue;
602
603 route_unlock_node(drnode);
604
605 if (drnode->info != rnode->info)
606 continue;
607
608 drnode->info = NULL;
609 route_unlock_node(drnode);
610 }
611
612 isis_route_delete(area, rnode, table);
613 }
614 }
615
616 void isis_route_verify_table(struct isis_area *area, struct route_table *table,
617 struct route_table *table_backup)
618 {
619 _isis_route_verify_table(area, table, table_backup, NULL);
620 }
621
622 /* Function to validate route tables for L1L2 areas. In this case we can't use
623 * level route tables directly, we have to merge them at first. L1 routes are
624 * preferred over the L2 ones.
625 *
626 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
627 * merge table at first, then L2 paths are added if L1 path for same prefix
628 * doesn't already exists there.
629 *
630 * FIXME: Is it right place to do it at all? Maybe we should push both levels
631 * to the RIB with different zebra route types and let RIB handle this? */
632 void isis_route_verify_merge(struct isis_area *area,
633 struct route_table *level1_table,
634 struct route_table *level1_table_backup,
635 struct route_table *level2_table,
636 struct route_table *level2_table_backup)
637 {
638 struct route_table *tables[] = {level1_table, level2_table};
639 struct route_table *tables_backup[] = {level1_table_backup,
640 level2_table_backup};
641 struct route_table *merge;
642 struct route_node *rnode, *mrnode;
643
644 merge = srcdest_table_init();
645
646 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
647 for (rnode = route_top(tables[level - 1]); rnode;
648 rnode = srcdest_route_next(rnode)) {
649 struct isis_route_info *rinfo = rnode->info;
650 struct route_node *rnode_bck;
651
652 if (!rinfo)
653 continue;
654
655 struct prefix *prefix;
656 struct prefix_ipv6 *src_p;
657
658 srcdest_rnode_prefixes(rnode,
659 (const struct prefix **)&prefix,
660 (const struct prefix **)&src_p);
661
662 /* Link primary route to backup route. */
663 rnode_bck = srcdest_rnode_lookup(
664 tables_backup[level - 1], prefix, src_p);
665 if (rnode_bck) {
666 rinfo->backup = rnode_bck->info;
667 UNSET_FLAG(rinfo->flag,
668 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
669 } else if (rinfo->backup) {
670 rinfo->backup = NULL;
671 UNSET_FLAG(rinfo->flag,
672 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
673 }
674
675 mrnode = srcdest_rnode_get(merge, prefix, src_p);
676 struct isis_route_info *mrinfo = mrnode->info;
677 if (mrinfo) {
678 route_unlock_node(mrnode);
679 if (CHECK_FLAG(mrinfo->flag,
680 ISIS_ROUTE_FLAG_ACTIVE)) {
681 /* Clear the ZEBRA_SYNCED flag on the
682 * L2 route when L1 wins, otherwise L2
683 * won't get reinstalled when L1
684 * disappears.
685 */
686 UNSET_FLAG(
687 rinfo->flag,
688 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
689 );
690 continue;
691 } else if (CHECK_FLAG(rinfo->flag,
692 ISIS_ROUTE_FLAG_ACTIVE)) {
693 /* Clear the ZEBRA_SYNCED flag on the L1
694 * route when L2 wins, otherwise L1
695 * won't get reinstalled when it
696 * reappears.
697 */
698 UNSET_FLAG(
699 mrinfo->flag,
700 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
701 );
702 } else if (
703 CHECK_FLAG(
704 mrinfo->flag,
705 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
706 continue;
707 }
708 }
709 mrnode->info = rnode->info;
710 }
711 }
712
713 _isis_route_verify_table(area, merge, NULL, tables);
714 route_table_finish(merge);
715 }
716
717 void isis_route_invalidate_table(struct isis_area *area,
718 struct route_table *table)
719 {
720 struct route_node *rode;
721 struct isis_route_info *rinfo;
722 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
723 if (rode->info == NULL)
724 continue;
725 rinfo = rode->info;
726
727 if (rinfo->backup) {
728 rinfo->backup = NULL;
729 /*
730 * For now, always force routes that have backup
731 * nexthops to be reinstalled.
732 */
733 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
734 }
735 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
736 }
737 }
738
739 void isis_route_switchover_nexthop(struct isis_area *area,
740 struct route_table *table, int family,
741 union g_addr *nexthop_addr,
742 ifindex_t ifindex)
743 {
744 const char *ifname = NULL, *vrfname = NULL;
745 struct isis_route_info *rinfo;
746 struct prefix_ipv6 *src_p;
747 struct route_node *rnode;
748 vrf_id_t vrf_id;
749 struct prefix *prefix;
750
751 if (IS_DEBUG_EVENTS) {
752 if (area && area->isis) {
753 vrf_id = area->isis->vrf_id;
754 vrfname = vrf_id_to_name(vrf_id);
755 ifname = ifindex2ifname(ifindex, vrf_id);
756 }
757 zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
758 __func__, family2str(family), vrfname ? vrfname : "",
759 ifname ? ifname : "");
760 }
761
762 for (rnode = route_top(table); rnode;
763 rnode = srcdest_route_next(rnode)) {
764 if (!rnode->info)
765 continue;
766 rinfo = rnode->info;
767
768 if (!rinfo->backup)
769 continue;
770
771 if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
772 ifindex))
773 continue;
774
775 srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
776 (const struct prefix **)&src_p);
777
778 /* Switchover route. */
779 isis_route_remove_previous_sid(area, prefix, rinfo);
780 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
781 isis_route_update(area, prefix, src_p, rinfo->backup);
782
783 isis_route_info_delete(rinfo);
784
785 rnode->info = NULL;
786 route_unlock_node(rnode);
787 }
788 }