]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_route.c
Merge pull request #13366 from zmw12306/rte_tag
[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 "frrevent.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 #include "isis_flex_algo.h"
40
41 DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop");
42 DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
43 DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_TABLE_INFO, "ISIS route table info");
44
45
46 DEFINE_HOOK(isis_route_update_hook,
47 (struct isis_area * area, struct prefix *prefix,
48 struct isis_route_info *route_info),
49 (area, prefix, route_info));
50
51 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
52 union g_addr *ip, ifindex_t ifindex);
53 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
54 struct prefix_ipv6 *src_p,
55 struct isis_route_info *route_info);
56
57 static struct mpls_label_stack *
58 label_stack_dup(const struct mpls_label_stack *const orig)
59 {
60 struct mpls_label_stack *copy;
61 int array_size;
62
63 if (orig == NULL)
64 return NULL;
65
66 array_size = orig->num_labels * sizeof(mpls_label_t);
67 copy = XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
68 sizeof(struct mpls_label_stack) + array_size);
69 copy->num_labels = orig->num_labels;
70 memcpy(copy->label, orig->label, array_size);
71 return copy;
72 }
73
74 static struct isis_nexthop *
75 isis_nexthop_create(int family, const union g_addr *const ip, ifindex_t ifindex)
76 {
77 struct isis_nexthop *nexthop;
78
79 nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
80
81 nexthop->family = family;
82 nexthop->ifindex = ifindex;
83 nexthop->ip = *ip;
84
85 return nexthop;
86 }
87
88 static struct isis_nexthop *
89 isis_nexthop_dup(const struct isis_nexthop *const orig)
90 {
91 struct isis_nexthop *nexthop;
92
93 nexthop = isis_nexthop_create(orig->family, &orig->ip, orig->ifindex);
94 memcpy(nexthop->sysid, orig->sysid, ISIS_SYS_ID_LEN);
95 nexthop->sr = orig->sr;
96 nexthop->label_stack = label_stack_dup(orig->label_stack);
97
98 return nexthop;
99 }
100
101 void isis_nexthop_delete(struct isis_nexthop *nexthop)
102 {
103 XFREE(MTYPE_ISIS_NEXTHOP_LABELS, nexthop->label_stack);
104 XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
105 }
106
107 static struct list *isis_nexthop_list_dup(const struct list *orig)
108 {
109 struct list *copy;
110 struct listnode *node;
111 struct isis_nexthop *nh;
112 struct isis_nexthop *nhcopy;
113
114 copy = list_new();
115 for (ALL_LIST_ELEMENTS_RO(orig, node, nh)) {
116 nhcopy = isis_nexthop_dup(nh);
117 listnode_add(copy, nhcopy);
118 }
119 return copy;
120 }
121
122 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
123 union g_addr *ip, ifindex_t ifindex)
124 {
125 struct listnode *node;
126 struct isis_nexthop *nh;
127
128 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
129 if (nh->ifindex != ifindex)
130 continue;
131
132 /* if the IP is unspecified, return the first nexthop found on
133 * the interface
134 */
135 if (!ip)
136 return nh;
137
138 if (nh->family != family)
139 continue;
140
141 switch (family) {
142 case AF_INET:
143 if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
144 continue;
145 break;
146 case AF_INET6:
147 if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
148 continue;
149 break;
150 default:
151 flog_err(EC_LIB_DEVELOPMENT,
152 "%s: unknown address family [%d]", __func__,
153 family);
154 exit(1);
155 }
156
157 return nh;
158 }
159
160 return NULL;
161 }
162
163 void adjinfo2nexthop(int family, struct list *nexthops,
164 struct isis_adjacency *adj, struct isis_sr_psid_info *sr,
165 struct mpls_label_stack *label_stack)
166 {
167 struct isis_nexthop *nh;
168 union g_addr ip = {};
169
170 switch (family) {
171 case AF_INET:
172 for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
173 ip.ipv4 = adj->ipv4_addresses[i];
174
175 if (!nexthoplookup(nexthops, AF_INET, &ip,
176 adj->circuit->interface->ifindex)) {
177 nh = isis_nexthop_create(
178 AF_INET, &ip,
179 adj->circuit->interface->ifindex);
180 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
181 if (sr)
182 nh->sr = *sr;
183 nh->label_stack = label_stack;
184 listnode_add(nexthops, nh);
185 break;
186 }
187 }
188 break;
189 case AF_INET6:
190 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
191 ip.ipv6 = adj->ll_ipv6_addrs[i];
192
193 if (!nexthoplookup(nexthops, AF_INET6, &ip,
194 adj->circuit->interface->ifindex)) {
195 nh = isis_nexthop_create(
196 AF_INET6, &ip,
197 adj->circuit->interface->ifindex);
198 memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
199 if (sr)
200 nh->sr = *sr;
201 nh->label_stack = label_stack;
202 listnode_add(nexthops, nh);
203 break;
204 }
205 }
206 break;
207 default:
208 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
209 __func__, family);
210 exit(1);
211 }
212 }
213
214 static void isis_route_add_dummy_nexthops(struct isis_route_info *rinfo,
215 const uint8_t *sysid,
216 struct isis_sr_psid_info *sr,
217 struct mpls_label_stack *label_stack)
218 {
219 struct isis_nexthop *nh;
220
221 nh = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
222 memcpy(nh->sysid, sysid, sizeof(nh->sysid));
223 nh->sr = *sr;
224 nh->label_stack = label_stack;
225 listnode_add(rinfo->nexthops, nh);
226 }
227
228 static struct isis_route_info *
229 isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p,
230 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
231 struct list *adjacencies, bool allow_ecmp)
232 {
233 struct isis_route_info *rinfo;
234 struct isis_vertex_adj *vadj;
235 struct listnode *node;
236
237 rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
238
239 rinfo->nexthops = list_new();
240 for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) {
241 struct isis_spf_adj *sadj = vadj->sadj;
242 struct isis_adjacency *adj = sadj->adj;
243 struct isis_sr_psid_info *sr = &vadj->sr;
244 struct mpls_label_stack *label_stack = vadj->label_stack;
245
246 /*
247 * Create dummy nexthops when running SPF on a testing
248 * environment.
249 */
250 if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) {
251 isis_route_add_dummy_nexthops(rinfo, sadj->id, sr,
252 label_stack);
253 if (!allow_ecmp)
254 break;
255 continue;
256 }
257
258 /* check for force resync this route */
259 if (CHECK_FLAG(adj->circuit->flags,
260 ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
261 SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
262
263 /* update neighbor router address */
264 switch (prefix->family) {
265 case AF_INET:
266 if (depth == 2 && prefix->prefixlen == IPV4_MAX_BITLEN)
267 adj->router_address = prefix->u.prefix4;
268 break;
269 case AF_INET6:
270 if (depth == 2 && prefix->prefixlen == IPV6_MAX_BITLEN
271 && (!src_p || !src_p->prefixlen)) {
272 adj->router_address6 = prefix->u.prefix6;
273 }
274 break;
275 default:
276 flog_err(EC_LIB_DEVELOPMENT,
277 "%s: unknown address family [%d]", __func__,
278 prefix->family);
279 exit(1);
280 }
281 adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr,
282 label_stack);
283 if (!allow_ecmp)
284 break;
285 }
286
287 rinfo->cost = cost;
288 rinfo->depth = depth;
289 rinfo->sr_algo[sr->algorithm] = *sr;
290 rinfo->sr_algo[sr->algorithm].nexthops = rinfo->nexthops;
291 rinfo->sr_algo[sr->algorithm].nexthops_backup =
292 rinfo->backup ? rinfo->backup->nexthops : NULL;
293
294 return rinfo;
295 }
296
297 static void isis_route_info_delete(struct isis_route_info *route_info)
298 {
299 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
300 if (!route_info->sr_algo[i].present)
301 continue;
302
303 if (route_info->sr_algo[i].nexthops == route_info->nexthops)
304 continue;
305
306 route_info->sr_algo[i].nexthops->del =
307 (void (*)(void *))isis_nexthop_delete;
308 list_delete(&route_info->sr_algo[i].nexthops);
309 }
310
311 if (route_info->nexthops) {
312 route_info->nexthops->del =
313 (void (*)(void *))isis_nexthop_delete;
314 list_delete(&route_info->nexthops);
315 }
316
317 XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
318 }
319
320 void isis_route_node_cleanup(struct route_table *table, struct route_node *node)
321 {
322 if (node->info)
323 isis_route_info_delete(node->info);
324 }
325
326 struct isis_route_table_info *isis_route_table_info_alloc(uint8_t algorithm)
327 {
328 struct isis_route_table_info *info;
329
330 info = XCALLOC(MTYPE_ISIS_ROUTE_TABLE_INFO, sizeof(*info));
331 info->algorithm = algorithm;
332 return info;
333 }
334
335 void isis_route_table_info_free(void *info)
336 {
337 XFREE(MTYPE_ISIS_ROUTE_TABLE_INFO, info);
338 }
339
340 uint8_t isis_route_table_algorithm(const struct route_table *table)
341 {
342 const struct isis_route_table_info *info = table->info;
343
344 return info ? info->algorithm : 0;
345 }
346
347 static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
348 struct isis_sr_psid_info *old)
349 {
350 if (new->present != old->present)
351 return false;
352
353 if (new->label != old->label)
354 return false;
355
356 if (new->sid.flags != old->sid.flags
357 || new->sid.value != old->sid.value)
358 return false;
359
360 if (new->sid.algorithm != old->sid.algorithm)
361 return false;
362
363 return true;
364 }
365
366 static bool isis_label_stack_same(struct mpls_label_stack *new,
367 struct mpls_label_stack *old)
368 {
369 if (!new && !old)
370 return true;
371 if (!new || !old)
372 return false;
373 if (new->num_labels != old->num_labels)
374 return false;
375 if (memcmp(&new->label, &old->label,
376 sizeof(mpls_label_t) * new->num_labels))
377 return false;
378
379 return true;
380 }
381
382 static int isis_route_info_same(struct isis_route_info *new,
383 struct isis_route_info *old, char *buf,
384 size_t buf_size)
385 {
386 struct listnode *node;
387 struct isis_nexthop *new_nh, *old_nh;
388
389 if (new->cost != old->cost) {
390 if (buf)
391 snprintf(buf, buf_size, "cost (old: %u, new: %u)",
392 old->cost, new->cost);
393 return 0;
394 }
395
396 if (new->depth != old->depth) {
397 if (buf)
398 snprintf(buf, buf_size, "depth (old: %u, new: %u)",
399 old->depth, new->depth);
400 return 0;
401 }
402
403 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
404 struct isis_sr_psid_info new_sr_algo;
405 struct isis_sr_psid_info old_sr_algo;
406
407 new_sr_algo = new->sr_algo[i];
408 old_sr_algo = old->sr_algo[i];
409
410 if (!isis_sr_psid_info_same(&new_sr_algo, &old_sr_algo)) {
411 if (buf)
412 snprintf(
413 buf, buf_size,
414 "SR input label algo-%u (old: %s, new: %s)",
415 i, old_sr_algo.present ? "yes" : "no",
416 new_sr_algo.present ? "yes" : "no");
417 return 0;
418 }
419 }
420
421 if (new->nexthops->count != old->nexthops->count) {
422 if (buf)
423 snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
424 old->nexthops->count, new->nexthops->count);
425 return 0;
426 }
427
428 for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, new_nh)) {
429 old_nh = nexthoplookup(old->nexthops, new_nh->family,
430 &new_nh->ip, new_nh->ifindex);
431 if (!old_nh) {
432 if (buf)
433 snprintf(buf, buf_size,
434 "new nhop"); /* TODO: print nhop */
435 return 0;
436 }
437 if (!isis_sr_psid_info_same(&new_nh->sr, &old_nh->sr)) {
438 if (buf)
439 snprintf(buf, buf_size, "nhop SR label");
440 return 0;
441 }
442 if (!isis_label_stack_same(new_nh->label_stack,
443 old_nh->label_stack)) {
444 if (buf)
445 snprintf(buf, buf_size, "nhop label stack");
446 return 0;
447 }
448 }
449
450 /* only the resync flag needs to be checked */
451 if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
452 != CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) {
453 if (buf)
454 snprintf(buf, buf_size, "resync flag");
455 return 0;
456 }
457
458 return 1;
459 }
460
461 struct isis_route_info *
462 isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
463 uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
464 struct list *adjacencies, bool allow_ecmp,
465 struct isis_area *area, struct route_table *table)
466 {
467 struct route_node *route_node;
468 struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
469 char change_buf[64];
470
471 if (!table)
472 return NULL;
473
474 rinfo_new = isis_route_info_new(prefix, src_p, cost, depth, sr,
475 adjacencies, allow_ecmp);
476 route_node = srcdest_rnode_get(table, prefix, src_p);
477
478 rinfo_old = route_node->info;
479 if (!rinfo_old) {
480 if (IS_DEBUG_RTE_EVENTS)
481 zlog_debug("ISIS-Rte (%s) route created: %pFX",
482 area->area_tag, prefix);
483 route_info = rinfo_new;
484 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
485 } else {
486 route_unlock_node(route_node);
487 #ifdef EXTREME_DEBUG
488 if (IS_DEBUG_RTE_EVENTS)
489 zlog_debug("ISIS-Rte (%s) route already exists: %pFX",
490 area->area_tag, prefix);
491 #endif /* EXTREME_DEBUG */
492 if (isis_route_info_same(rinfo_new, rinfo_old, change_buf,
493 sizeof(change_buf))) {
494 #ifdef EXTREME_DEBUG
495 if (IS_DEBUG_RTE_EVENTS)
496 zlog_debug(
497 "ISIS-Rte (%s) route unchanged: %pFX",
498 area->area_tag, prefix);
499 #endif /* EXTREME_DEBUG */
500 isis_route_info_delete(rinfo_new);
501 route_info = rinfo_old;
502 } else {
503 if (IS_DEBUG_RTE_EVENTS)
504 zlog_debug(
505 "ISIS-Rte (%s): route changed: %pFX, change: %s",
506 area->area_tag, prefix, change_buf);
507 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
508 rinfo_new->sr_algo_previous[i] =
509 rinfo_old->sr_algo[i];
510 isis_route_info_delete(rinfo_old);
511 route_info = rinfo_new;
512 UNSET_FLAG(route_info->flag,
513 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
514 }
515 }
516
517 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
518 route_node->info = route_info;
519
520 return route_info;
521 }
522
523 void isis_route_delete(struct isis_area *area, struct route_node *rode,
524 struct route_table *table)
525 {
526 struct isis_route_info *rinfo;
527 char buff[SRCDEST2STR_BUFFER];
528 struct prefix *prefix;
529 struct prefix_ipv6 *src_p;
530
531 /* for log */
532 srcdest_rnode2str(rode, buff, sizeof(buff));
533
534 srcdest_rnode_prefixes(rode, (const struct prefix **)&prefix,
535 (const struct prefix **)&src_p);
536
537 rinfo = rode->info;
538 if (rinfo == NULL) {
539 if (IS_DEBUG_RTE_EVENTS)
540 zlog_debug(
541 "ISIS-Rte: tried to delete non-existent route %s",
542 buff);
543 return;
544 }
545
546 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
547 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
548 if (IS_DEBUG_RTE_EVENTS)
549 zlog_debug("ISIS-Rte: route delete %s", buff);
550 isis_route_update(area, prefix, src_p, rinfo);
551 }
552 isis_route_info_delete(rinfo);
553 rode->info = NULL;
554 route_unlock_node(rode);
555 }
556
557 static void isis_route_remove_previous_sid(struct isis_area *area,
558 struct prefix *prefix,
559 struct isis_route_info *route_info)
560 {
561 /*
562 * Explicitly uninstall previous Prefix-SID label if it has
563 * changed or was removed.
564 */
565 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
566 if (route_info->sr_algo_previous[i].present &&
567 (!route_info->sr_algo[i].present ||
568 route_info->sr_algo_previous[i].label !=
569 route_info->sr_algo[i].label))
570 isis_zebra_prefix_sid_uninstall(
571 area, prefix, route_info,
572 &route_info->sr_algo_previous[i]);
573 }
574 }
575
576 static void set_merge_route_info_sr_algo(struct isis_route_info *mrinfo,
577 struct isis_route_info *rinfo)
578 {
579 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
580 if (rinfo->sr_algo[i].present) {
581 assert(i == rinfo->sr_algo[i].algorithm);
582 assert(rinfo->nexthops);
583 assert(rinfo->backup ? rinfo->backup->nexthops != NULL
584 : true);
585
586 if (mrinfo->sr_algo[i].nexthops != NULL &&
587 mrinfo->sr_algo[i].nexthops != mrinfo->nexthops) {
588 mrinfo->sr_algo[i].nexthops->del =
589 (void (*)(void *))isis_nexthop_delete;
590 list_delete(&mrinfo->sr_algo[i].nexthops);
591 }
592
593 mrinfo->sr_algo[i] = rinfo->sr_algo[i];
594 mrinfo->sr_algo[i].nexthops = isis_nexthop_list_dup(
595 rinfo->sr_algo[i].nexthops);
596 }
597 }
598
599 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
600 UNSET_FLAG(mrinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
601 }
602
603 static void isis_route_update(struct isis_area *area, struct prefix *prefix,
604 struct prefix_ipv6 *src_p,
605 struct isis_route_info *route_info)
606 {
607 if (area == NULL)
608 return;
609
610 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
611 if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
612 return;
613
614 isis_route_remove_previous_sid(area, prefix, route_info);
615
616 /* Install route. */
617 isis_zebra_route_add_route(area->isis, prefix, src_p,
618 route_info);
619
620 for (int i = 0; i < SR_ALGORITHM_COUNT; i++) {
621 struct isis_sr_psid_info sr_algo;
622
623 sr_algo = route_info->sr_algo[i];
624
625 /*
626 * Install/reinstall Prefix-SID label.
627 */
628 if (sr_algo.present)
629 isis_zebra_prefix_sid_install(area, prefix,
630 &sr_algo);
631
632 hook_call(isis_route_update_hook, area, prefix,
633 route_info);
634 }
635
636 hook_call(isis_route_update_hook, area, prefix, route_info);
637
638 SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
639 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
640 } else {
641 /* Uninstall Prefix-SID label. */
642 for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
643 if (route_info->sr_algo[i].present)
644 isis_zebra_prefix_sid_uninstall(
645 area, prefix, route_info,
646 &route_info->sr_algo[i]);
647
648 /* Uninstall route. */
649 isis_zebra_route_del_route(area->isis, prefix, src_p,
650 route_info);
651 hook_call(isis_route_update_hook, area, prefix, route_info);
652
653 UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
654 }
655 }
656
657 static void _isis_route_verify_table(struct isis_area *area,
658 struct route_table *table,
659 struct route_table *table_backup,
660 struct route_table **tables)
661 {
662 struct route_node *rnode, *drnode;
663 struct isis_route_info *rinfo;
664 #ifdef EXTREME_DEBUG
665 char buff[SRCDEST2STR_BUFFER];
666 #endif /* EXTREME_DEBUG */
667 uint8_t algorithm = isis_route_table_algorithm(table);
668
669 for (rnode = route_top(table); rnode;
670 rnode = srcdest_route_next(rnode)) {
671 if (rnode->info == NULL)
672 continue;
673 rinfo = rnode->info;
674
675 struct prefix *dst_p;
676 struct prefix_ipv6 *src_p;
677
678 srcdest_rnode_prefixes(rnode,
679 (const struct prefix **)&dst_p,
680 (const struct prefix **)&src_p);
681
682 /* Link primary route to backup route. */
683 if (table_backup) {
684 struct route_node *rnode_bck;
685
686 rnode_bck = srcdest_rnode_lookup(table_backup, dst_p,
687 src_p);
688 if (rnode_bck) {
689 rinfo->backup = rnode_bck->info;
690 rinfo->sr_algo[algorithm].nexthops_backup =
691 rinfo->backup->nexthops;
692 UNSET_FLAG(rinfo->flag,
693 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
694 } else if (rinfo->backup) {
695 rinfo->backup = NULL;
696 rinfo->sr_algo[algorithm].nexthops_backup =
697 NULL;
698 UNSET_FLAG(rinfo->flag,
699 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
700 }
701 }
702
703 #ifdef EXTREME_DEBUG
704 if (IS_DEBUG_RTE_EVENTS) {
705 srcdest2str(dst_p, src_p, buff, sizeof(buff));
706 zlog_debug(
707 "ISIS-Rte (%s): route validate: %s %s %s %s",
708 area->area_tag,
709 (CHECK_FLAG(rinfo->flag,
710 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)
711 ? "synced"
712 : "not-synced"),
713 (CHECK_FLAG(rinfo->flag,
714 ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
715 ? "resync"
716 : "not-resync"),
717 (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)
718 ? "active"
719 : "inactive"),
720 buff);
721 }
722 #endif /* EXTREME_DEBUG */
723
724 isis_route_update(area, dst_p, src_p, rinfo);
725
726 if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
727 continue;
728
729 /* In case the verify is not for a merge, we use a single table
730 * directly for
731 * validating => no problems with deleting routes. */
732 if (!tables) {
733 isis_route_delete(area, rnode, table);
734 continue;
735 }
736
737 /* If we work on a merged table,
738 * therefore we must
739 * delete node from each table as well before deleting
740 * route info. */
741 for (int i = 0; tables[i]; i++) {
742 drnode = srcdest_rnode_lookup(tables[i], dst_p, src_p);
743 if (!drnode)
744 continue;
745
746 route_unlock_node(drnode);
747
748 if (drnode->info != rnode->info)
749 continue;
750
751 drnode->info = NULL;
752 route_unlock_node(drnode);
753 }
754
755 isis_route_delete(area, rnode, table);
756 }
757 }
758
759 static void _isis_route_verify_merge(struct isis_area *area,
760 struct route_table **tables,
761 struct route_table **tables_backup,
762 int tree);
763
764 void isis_route_verify_table(struct isis_area *area, struct route_table *table,
765 struct route_table *table_backup, int tree)
766 {
767 struct route_table *tables[SR_ALGORITHM_COUNT] = {table};
768 struct route_table *tables_backup[SR_ALGORITHM_COUNT] = {table_backup};
769 #ifndef FABRICD
770 int tables_next = 1;
771 int level = area->is_type == IS_LEVEL_1 ? ISIS_LEVEL1 : ISIS_LEVEL2;
772 struct listnode *node;
773 struct flex_algo *fa;
774 struct isis_flex_algo_data *data;
775
776 for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, node, fa)) {
777 data = fa->data;
778 tables[tables_next] =
779 data->spftree[tree][level - 1]->route_table;
780 tables_backup[tables_next] =
781 data->spftree[tree][level - 1]->route_table_backup;
782 _isis_route_verify_table(area, tables[tables_next],
783 tables_backup[tables_next], NULL);
784 tables_next++;
785 }
786 #endif /* ifndef FABRICD */
787
788 _isis_route_verify_merge(area, tables, tables_backup, tree);
789 }
790
791 /* Function to validate route tables for L1L2 areas. In this case we can't use
792 * level route tables directly, we have to merge them at first. L1 routes are
793 * preferred over the L2 ones.
794 *
795 * Merge algorithm is trivial (at least for now). All L1 paths are copied into
796 * merge table at first, then L2 paths are added if L1 path for same prefix
797 * doesn't already exists there.
798 *
799 * FIXME: Is it right place to do it at all? Maybe we should push both levels
800 * to the RIB with different zebra route types and let RIB handle this? */
801 void isis_route_verify_merge(struct isis_area *area,
802 struct route_table *level1_table,
803 struct route_table *level1_table_backup,
804 struct route_table *level2_table,
805 struct route_table *level2_table_backup, int tree)
806 {
807 struct route_table *tables[] = {level1_table, level2_table, NULL};
808 struct route_table *tables_backup[] = {level1_table_backup,
809 level2_table_backup, NULL};
810 _isis_route_verify_merge(area, tables, tables_backup, tree);
811 }
812
813 static void _isis_route_verify_merge(struct isis_area *area,
814 struct route_table **tables,
815 struct route_table **tables_backup,
816 int tree)
817 {
818 struct route_table *merge;
819 struct route_node *rnode, *mrnode;
820
821 merge = srcdest_table_init();
822
823 for (int i = 0; tables[i]; i++) {
824 uint8_t algorithm = isis_route_table_algorithm(tables[i]);
825 for (rnode = route_top(tables[i]); rnode;
826 rnode = srcdest_route_next(rnode)) {
827 struct isis_route_info *rinfo = rnode->info;
828 struct route_node *rnode_bck;
829
830 if (!rinfo)
831 continue;
832
833 struct prefix *prefix;
834 struct prefix_ipv6 *src_p;
835
836 srcdest_rnode_prefixes(rnode,
837 (const struct prefix **)&prefix,
838 (const struct prefix **)&src_p);
839
840 /* Link primary route to backup route. */
841 rnode_bck = srcdest_rnode_lookup(tables_backup[i],
842 prefix, src_p);
843 if (rnode_bck) {
844 rinfo->backup = rnode_bck->info;
845 rinfo->sr_algo[algorithm].nexthops_backup =
846 rinfo->backup->nexthops;
847 UNSET_FLAG(rinfo->flag,
848 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
849 } else if (rinfo->backup) {
850 rinfo->backup = NULL;
851 rinfo->sr_algo[algorithm].nexthops_backup =
852 NULL;
853 UNSET_FLAG(rinfo->flag,
854 ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
855 }
856
857 mrnode = srcdest_rnode_get(merge, prefix, src_p);
858 struct isis_route_info *mrinfo = mrnode->info;
859 if (mrinfo) {
860 route_unlock_node(mrnode);
861 set_merge_route_info_sr_algo(mrinfo, rinfo);
862
863 if (CHECK_FLAG(mrinfo->flag,
864 ISIS_ROUTE_FLAG_ACTIVE)) {
865 /* Clear the ZEBRA_SYNCED flag on the
866 * L2 route when L1 wins, otherwise L2
867 * won't get reinstalled when L1
868 * disappears.
869 */
870 UNSET_FLAG(
871 rinfo->flag,
872 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
873 );
874 continue;
875 } else if (CHECK_FLAG(rinfo->flag,
876 ISIS_ROUTE_FLAG_ACTIVE)) {
877 /* Clear the ZEBRA_SYNCED flag on the L1
878 * route when L2 wins, otherwise L1
879 * won't get reinstalled when it
880 * reappears.
881 */
882 UNSET_FLAG(
883 mrinfo->flag,
884 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
885 );
886 } else if (
887 CHECK_FLAG(
888 mrinfo->flag,
889 ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
890 continue;
891 }
892 } else {
893 mrnode->info = rnode->info;
894 }
895 }
896 }
897
898 _isis_route_verify_table(area, merge, NULL, tables);
899 route_table_finish(merge);
900 }
901
902 void isis_route_invalidate_table(struct isis_area *area,
903 struct route_table *table)
904 {
905 struct route_node *rode;
906 struct isis_route_info *rinfo;
907 uint8_t algorithm = isis_route_table_algorithm(table);
908 for (rode = route_top(table); rode; rode = srcdest_route_next(rode)) {
909 if (rode->info == NULL)
910 continue;
911 rinfo = rode->info;
912
913 if (rinfo->backup) {
914 rinfo->backup = NULL;
915 rinfo->sr_algo[algorithm].nexthops_backup = NULL;
916 /*
917 * For now, always force routes that have backup
918 * nexthops to be reinstalled.
919 */
920 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
921 }
922 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
923 }
924 }
925
926 void isis_route_switchover_nexthop(struct isis_area *area,
927 struct route_table *table, int family,
928 union g_addr *nexthop_addr,
929 ifindex_t ifindex)
930 {
931 const char *ifname = NULL, *vrfname = NULL;
932 struct isis_route_info *rinfo;
933 struct prefix_ipv6 *src_p;
934 struct route_node *rnode;
935 vrf_id_t vrf_id;
936 struct prefix *prefix;
937
938 if (IS_DEBUG_EVENTS) {
939 if (area && area->isis) {
940 vrf_id = area->isis->vrf_id;
941 vrfname = vrf_id_to_name(vrf_id);
942 ifname = ifindex2ifname(ifindex, vrf_id);
943 }
944 zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
945 __func__, family2str(family), vrfname ? vrfname : "",
946 ifname ? ifname : "");
947 }
948
949 for (rnode = route_top(table); rnode;
950 rnode = srcdest_route_next(rnode)) {
951 if (!rnode->info)
952 continue;
953 rinfo = rnode->info;
954
955 if (!rinfo->backup)
956 continue;
957
958 if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
959 ifindex))
960 continue;
961
962 srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
963 (const struct prefix **)&src_p);
964
965 /* Switchover route. */
966 isis_route_remove_previous_sid(area, prefix, rinfo);
967 UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
968 isis_route_update(area, prefix, src_p, rinfo->backup);
969
970 isis_route_info_delete(rinfo);
971
972 rnode->info = NULL;
973 route_unlock_node(rnode);
974 }
975 }