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