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