]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_route.c
Merge pull request #10398 from patrasar/pim_debug_fix
[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->family != family)
95 continue;
96 if (nh->ifindex != ifindex)
97 continue;
98
99 switch (family) {
100 case AF_INET:
101 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
102 continue;
103 break;
104 case AF_INET6:
105 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
106 continue;
107 break;
108 default:
109 flog_err(EC_LIB_DEVELOPMENT,
110 "%s: unknown address family [%d]", __func__,
111 family);
112 exit(1);
113 }
114
115 return nh;
116 }
117
118 return NULL;
119 }
120
121 void adjinfo2nexthop(int family, struct list *nexthops,
122 struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
123 struct mpls_label_stack *label_stack)
124 {
125 struct isis_nexthop *nh;
126 union g_addr ip = {};
127
128 switch (family) {
129 case AF_INET:
130 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
131 ip.ipv4 = adj->ipv4_addresses[i];
132
133 if (!nexthoplookup(nexthops, AF_INET, &ip,
134 adj->circuit->interface->ifindex)) {
135 nh = isis_nexthop_create(
136 AF_INET, &ip,
137 adj->circuit->interface->ifindex);
138 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
139 if (sr)
140 nh->sr = *sr;
141 nh->label_stack = label_stack;
142 listnode_add(nexthops, nh);
143 break;
144 }
145 }
146 break;
147 case AF_INET6:
148 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
149 ip.ipv6 = adj->ll_ipv6_addrs[i];
150
151 if (!nexthoplookup(nexthops, AF_INET6, &ip,
152 adj->circuit->interface->ifindex)) {
153 nh = isis_nexthop_create(
154 AF_INET6, &ip,
155 adj->circuit->interface->ifindex);
156 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
157 if (sr)
158 nh->sr = *sr;
159 nh->label_stack = label_stack;
160 listnode_add(nexthops, nh);
161 break;
162 }
163 }
164 break;
165 default:
166 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
167 __func__, family);
168 exit(1);
169 }
170 }
171
172 static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
173 const uint8_t *sysid,
174 struct isis_sr_psid_info *sr,
175 struct mpls_label_stack *label_stack)
176 {
177 struct isis_nexthop *nh;
178
179 nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
180 memcpy(nh->sysid, sysid, sizeof(nh->sysid));
181 nh->sr = *sr;
182 nh->label_stack = label_stack;
183 listnode_add(rinfo->nexthops, nh);
184 }
185
186 static struct isis_route_info *
187 isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
188 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
189 struct list *adjacencies, bool allow_ecmp)
190 {
191 struct isis_route_info *rinfo;
192 struct isis_vertex_adj *vadj;
193 struct listnode *node;
194
195 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
196
197 rinfo->nexthops = list_new();
198 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
199 struct isis_spf_adj *sadj = vadj->sadj;
200 struct isis_adjacency *adj = sadj->adj;
201 struct isis_sr_psid_info *sr = &vadj->sr;
202 struct mpls_label_stack *label_stack = vadj->label_stack;
203
204 /*
205 * Create dummy nexthops when running SPF on a testing
206 * environment.
207 */
208 if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
209 isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
210 label_stack);
211 if (!allow_ecmp)
212 break;
213 continue;
214 }
215
216 /* check for force resync this route */
217 if (CHECK_FLAG(adj->circuit->flags,
218 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
219 SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
220
221 /* update neighbor router address */
222 switch (prefix->family) {
223 case AF_INET:
224 if (depth == 2 && prefix->prefixlen == IPV4_MAX_BITLEN)
225 adj->router_address = prefix->u.prefix4;
226 break;
227 case AF_INET6:
228 if (depth == 2 && prefix->prefixlen == IPV6_MAX_BITLEN
229 && (!src_p || !src_p->prefixlen)) {
230 adj->router_address6 = prefix->u.prefix6;
231 }
232 break;
233 default:
234 flog_err(EC_LIB_DEVELOPMENT,
235 "%s: unknown address family [%d]", __func__,
236 prefix->family);
237 exit(1);
238 }
239 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
240 label_stack);
241 if (!allow_ecmp)
242 break;
243 }
244
245 rinfo->cost = cost;
246 rinfo->depth = depth;
247 rinfo->sr = *sr;
248
249 return rinfo;
250 }
251
252 static void isis_route_info_delete(struct isis_route_info *route_info)
253 {
254 if (route_info->nexthops) {
255 route_info->nexthops->del =
256 (void (*)(void *))isis_nexthop_delete;
257 list_delete(&route_info->nexthops);
258 }
259
260 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
261 }
262
263 void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
264 {
265 if (node->info)
266 isis_route_info_delete(node->info);
267 }
268
269 static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
270 struct isis_sr_psid_info *old)
271 {
272 if (new->present != old->present)
273 return false;
274
275 if (new->label != old->label)
276 return false;
277
278 if (new->sid.flags != old->sid.flags
279 || new->sid.value != old->sid.value)
280 return false;
281
282 return true;
283 }
284
285 static bool isis_label_stack_same(struct mpls_label_stack *new,
286 struct mpls_label_stack *old)
287 {
288 if (!new && !old)
289 return true;
290 if (!new || !old)
291 return false;
292 if (new->num_labels != old->num_labels)
293 return false;
294 if (memcmp(&new->label, &old->label,
295 sizeof(mpls_label_t) * new->num_labels))
296 return false;
297
298 return true;
299 }
300
301 static int isis_route_info_same(struct isis_route_info *new,
302 struct isis_route_info *old, char *buf,
303 size_t buf_size)
304 {
305 struct listnode *node;
306 struct isis_nexthop *new_nh, *old_nh;
307
308 if (new->cost != old->cost) {
309 if (buf)
310 snprintf(buf, buf_size, "cost (old: %u, new: %u)",
311 old->cost, new->cost);
312 return 0;
313 }
314
315 if (new->depth != old->depth) {
316 if (buf)
317 snprintf(buf, buf_size, "depth (old: %u, new: %u)",
318 old->depth, new->depth);
319 return 0;
320 }
321
322 if (!isis_sr_psid_info_same(&new->sr, &old->sr)) {
323 if (buf)
324 snprintf(buf, buf_size, "SR input label");
325 return 0;
326 }
327
328 if (new->nexthops->count != old->nexthops->count) {
329 if (buf)
330 snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
331 old->nexthops->count, new->nexthops->count);
332 return 0;
333 }
334
335 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
336 old_nh = nexthoplookup(old->nexthops, new_nh->family,
337 &new_nh->ip, new_nh->ifindex);
338 if (!old_nh) {
339 if (buf)
340 snprintf(buf, buf_size,
341 "new nhop"); /* TODO: print nhop */
342 return 0;
343 }
344 if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
345 if (buf)
346 snprintf(buf, buf_size, "nhop SR label");
347 return 0;
348 }
349 if (!isis_label_stack_same(new_nh->label_stack,
350 old_nh->label_stack)) {
351 if (buf)
352 snprintf(buf, buf_size, "nhop label stack");
353 return 0;
354 }
355 }
356
357 /* only the resync flag needs to be checked */
358 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
359 != CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) {
360 if (buf)
361 snprintf(buf, buf_size, "resync flag");
362 return 0;
363 }
364
365 return 1;
366 }
367
368 struct isis_route_info *
369 isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
370 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
371 struct list *adjacencies, bool allow_ecmp,
372 struct isis_area *area, struct route_table *table)
373 {
374 struct route_node *route_node;
375 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
376 char change_buf[64];
377
378 if (!table)
379 return NULL;
380
381 rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
382 adjacencies, allow_ecmp);
383 route_node = srcdest_rnode_get(table, prefix, src_p);
384
385 rinfo_old = route_node->info;
386 if (!rinfo_old) {
387 if (IS_DEBUG_RTE_EVENTS)
388 zlog_debug("ISIS-Rte (%s) route created: %pFX",
389 area->area_tag, prefix);
390 route_info = rinfo_new;
391 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
392 } else {
393 route_unlock_node(route_node);
394 #ifdef EXTREME_DEBUG
395 if (IS_DEBUG_RTE_EVENTS)
396 zlog_debug("ISIS-Rte (%s) route already exists: %pFX",
397 area->area_tag, prefix);
398 #endif /* EXTREME_DEBUG */
399 if (isis_route_info_same(rinfo_new, rinfo_old, change_buf,
400 sizeof(change_buf))) {
401 #ifdef EXTREME_DEBUG
402 if (IS_DEBUG_RTE_EVENTS)
403 zlog_debug(
404 "ISIS-Rte (%s) route unchanged: %pFX",
405 area->area_tag, prefix);
406 #endif /* EXTREME_DEBUG */
407 isis_route_info_delete(rinfo_new);
408 route_info = rinfo_old;
409 } else {
410 if (IS_DEBUG_RTE_EVENTS)
411 zlog_debug(
412 "ISIS-Rte (%s): route changed: %pFX, change: %s",
413 area->area_tag, prefix, change_buf);
414 rinfo_new->sr_previous = rinfo_old->sr;
415 isis_route_info_delete(rinfo_old);
416 route_info = rinfo_new;
417 UNSET_FLAG(route_info->flag,
418 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
419 }
420 }
421
422 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
423 route_node->info = route_info;
424
425 return route_info;
426 }
427
428 void isis_route_delete(struct isis_area *area, struct route_node *rode,
429 struct route_table *table)
430 {
431 struct isis_route_info *rinfo;
432 char buff[SRCDEST2STR_BUFFER];
433 struct prefix *prefix;
434 struct prefix_ipv6 *src_p;
435
436 /* for log */
437 srcdest_rnode2str(rode, buff, sizeof(buff));
438
439 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
440 (const struct prefix **)&src_p);
441
442 rinfo = rode->info;
443 if (rinfo == NULL) {
444 if (IS_DEBUG_RTE_EVENTS)
445 zlog_debug(
446 "ISIS-Rte: tried to delete non-existant route %s",
447 buff);
448 return;
449 }
450
451 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
452 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
453 if (IS_DEBUG_RTE_EVENTS)
454 zlog_debug("ISIS-Rte: route delete %s", buff);
455 isis_route_update(area, prefix, src_p, rinfo);
456 }
457 isis_route_info_delete(rinfo);
458 rode->info = NULL;
459 route_unlock_node(rode);
460 }
461
462 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
463 struct prefix_ipv6 *src_p,
464 struct isis_route_info *route_info)
465 {
466 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
467 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
468 return;
469
470 /*
471 * Explicitly uninstall previous Prefix-SID label if it has
472 * changed or was removed.
473 */
474 if (route_info->sr_previous.present
475 && (!route_info->sr.present
476 || route_info->sr_previous.label
477 != route_info->sr.label))
478 isis_zebra_prefix_sid_uninstall(
479 area, prefix, route_info,
480 &route_info->sr_previous);
481
482 /* Install route. */
483 isis_zebra_route_add_route(area->isis, prefix, src_p,
484 route_info);
485 /* Install/reinstall Prefix-SID label. */
486 if (route_info->sr.present)
487 isis_zebra_prefix_sid_install(area, prefix, route_info,
488 &route_info->sr);
489 hook_call(isis_route_update_hook, area, prefix, route_info);
490
491 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
492 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
493 } else {
494 /* Uninstall Prefix-SID label. */
495 if (route_info->sr.present)
496 isis_zebra_prefix_sid_uninstall(
497 area, prefix, route_info, &route_info->sr);
498 /* Uninstall route. */
499 isis_zebra_route_del_route(area->isis, prefix, src_p,
500 route_info);
501 hook_call(isis_route_update_hook, area, prefix, route_info);
502
503 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
504 }
505 }
506
507 static void _isis_route_verify_table(struct isis_area *area,
508 struct route_table *table,
509 struct route_table *table_backup,
510 struct route_table **tables)
511 {
512 struct route_node *rnode, *drnode;
513 struct isis_route_info *rinfo;
514 #ifdef EXTREME_DEBUG
515 char buff[SRCDEST2STR_BUFFER];
516 #endif /* EXTREME_DEBUG */
517
518 for (rnode = route_top(table); rnode;
519 rnode = srcdest_route_next(rnode)) {
520 if (rnode->info == NULL)
521 continue;
522 rinfo = rnode->info;
523
524 struct prefix *dst_p;
525 struct prefix_ipv6 *src_p;
526
527 srcdest_rnode_prefixes(rnode,
528 (const struct prefix **)&dst_p,
529 (const struct prefix **)&src_p);
530
531 /* Link primary route to backup route. */
532 if (table_backup) {
533 struct route_node *rnode_bck;
534
535 rnode_bck = srcdest_rnode_lookup(table_backup, dst_p,
536 src_p);
537 if (rnode_bck) {
538 rinfo->backup = rnode_bck->info;
539 UNSET_FLAG(rinfo->flag,
540 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
541 } else if (rinfo->backup) {
542 rinfo->backup = NULL;
543 UNSET_FLAG(rinfo->flag,
544 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
545 }
546 }
547
548 #ifdef EXTREME_DEBUG
549 if (IS_DEBUG_RTE_EVENTS) {
550 srcdest2str(dst_p, src_p, buff, sizeof(buff));
551 zlog_debug(
552 "ISIS-Rte (%s): route validate: %s %s %s %s",
553 area->area_tag,
554 (CHECK_FLAG(rinfo->flag,
555 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
556 ? "synced"
557 : "not-synced"),
558 (CHECK_FLAG(rinfo->flag,
559 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
560 ? "resync"
561 : "not-resync"),
562 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
563 ? "active"
564 : "inactive"),
565 buff);
566 }
567 #endif /* EXTREME_DEBUG */
568
569 isis_route_update(area, dst_p, src_p, rinfo);
570
571 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
572 continue;
573
574 /* Area is either L1 or L2 => we use level route tables
575 * directly for
576 * validating => no problems with deleting routes. */
577 if (!tables) {
578 isis_route_delete(area, rnode, table);
579 continue;
580 }
581
582 /* If area is L1L2, we work with merge table and
583 * therefore must
584 * delete node from level tables as well before deleting
585 * route info. */
586 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
587 drnode = srcdest_rnode_lookup(tables[level - 1],
588 dst_p, src_p);
589 if (!drnode)
590 continue;
591
592 route_unlock_node(drnode);
593
594 if (drnode->info != rnode->info)
595 continue;
596
597 drnode->info = NULL;
598 route_unlock_node(drnode);
599 }
600
601 isis_route_delete(area, rnode, table);
602 }
603 }
604
605 void isis_route_verify_table(struct isis_area *area, struct route_table *table,
606 struct route_table *table_backup)
607 {
608 _isis_route_verify_table(area, table, table_backup, NULL);
609 }
610
611 /* Function to validate route tables for L1L2 areas. In this case we can't use
612 * level route tables directly, we have to merge them at first. L1 routes are
613 * preferred over the L2 ones.
614 *
615 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
616 * merge table at first, then L2 paths are added if L1 path for same prefix
617 * doesn't already exists there.
618 *
619 * FIXME: Is it right place to do it at all? Maybe we should push both levels
620 * to the RIB with different zebra route types and let RIB handle this? */
621 void isis_route_verify_merge(struct isis_area *area,
622 struct route_table *level1_table,
623 struct route_table *level1_table_backup,
624 struct route_table *level2_table,
625 struct route_table *level2_table_backup)
626 {
627 struct route_table *tables[] = {level1_table, level2_table};
628 struct route_table *tables_backup[] = {level1_table_backup,
629 level2_table_backup};
630 struct route_table *merge;
631 struct route_node *rnode, *mrnode;
632
633 merge = srcdest_table_init();
634
635 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
636 for (rnode = route_top(tables[level - 1]); rnode;
637 rnode = srcdest_route_next(rnode)) {
638 struct isis_route_info *rinfo = rnode->info;
639 struct route_node *rnode_bck;
640
641 if (!rinfo)
642 continue;
643
644 struct prefix *prefix;
645 struct prefix_ipv6 *src_p;
646
647 srcdest_rnode_prefixes(rnode,
648 (const struct prefix **)&prefix,
649 (const struct prefix **)&src_p);
650
651 /* Link primary route to backup route. */
652 rnode_bck = srcdest_rnode_lookup(
653 tables_backup[level - 1], prefix, src_p);
654 if (rnode_bck) {
655 rinfo->backup = rnode_bck->info;
656 UNSET_FLAG(rinfo->flag,
657 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
658 } else if (rinfo->backup) {
659 rinfo->backup = NULL;
660 UNSET_FLAG(rinfo->flag,
661 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
662 }
663
664 mrnode = srcdest_rnode_get(merge, prefix, src_p);
665 struct isis_route_info *mrinfo = mrnode->info;
666 if (mrinfo) {
667 route_unlock_node(mrnode);
668 if (CHECK_FLAG(mrinfo->flag,
669 ISIS_ROUTE_FLAG_ACTIVE)) {
670 /* Clear the ZEBRA_SYNCED flag on the
671 * L2 route when L1 wins, otherwise L2
672 * won't get reinstalled when L1
673 * disappears.
674 */
675 UNSET_FLAG(
676 rinfo->flag,
677 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
678 );
679 continue;
680 } else if (CHECK_FLAG(rinfo->flag,
681 ISIS_ROUTE_FLAG_ACTIVE)) {
682 /* Clear the ZEBRA_SYNCED flag on the L1
683 * route when L2 wins, otherwise L1
684 * won't get reinstalled when it
685 * reappears.
686 */
687 UNSET_FLAG(
688 mrinfo->flag,
689 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
690 );
691 } else if (
692 CHECK_FLAG(
693 mrinfo->flag,
694 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
695 continue;
696 }
697 }
698 mrnode->info = rnode->info;
699 }
700 }
701
702 _isis_route_verify_table(area, merge, NULL, tables);
703 route_table_finish(merge);
704 }
705
706 void isis_route_invalidate_table(struct isis_area *area,
707 struct route_table *table)
708 {
709 struct route_node *rode;
710 struct isis_route_info *rinfo;
711 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
712 if (rode->info == NULL)
713 continue;
714 rinfo = rode->info;
715
716 if (rinfo->backup) {
717 rinfo->backup = NULL;
718 /*
719 * For now, always force routes that have backup
720 * nexthops to be reinstalled.
721 */
722 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
723 }
724 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
725 }
726 }