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