1 // SPDX-License-Identifier: GPL-2.0-or-later
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
8 * based on ../ospf6d/ospf6_route.[ch]
18 #include "lib_errors.h"
24 #include "srcdest_table.h"
26 #include "isis_constants.h"
27 #include "isis_common.h"
28 #include "isis_flags.h"
30 #include "isis_misc.h"
31 #include "isis_adjacency.h"
32 #include "isis_circuit.h"
36 #include "isis_spf_private.h"
37 #include "isis_route.h"
38 #include "isis_zebra.h"
39 #include "isis_flex_algo.h"
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");
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
));
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
);
57 static struct mpls_label_stack
*
58 label_stack_dup(const struct mpls_label_stack
*const orig
)
60 struct mpls_label_stack
*copy
;
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
);
74 static struct isis_nexthop
*
75 isis_nexthop_create(int family
, const union g_addr
*const ip
, ifindex_t ifindex
)
77 struct isis_nexthop
*nexthop
;
79 nexthop
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
81 nexthop
->family
= family
;
82 nexthop
->ifindex
= ifindex
;
88 static struct isis_nexthop
*
89 isis_nexthop_dup(const struct isis_nexthop
*const orig
)
91 struct isis_nexthop
*nexthop
;
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
);
101 void isis_nexthop_delete(struct isis_nexthop
*nexthop
)
103 XFREE(MTYPE_ISIS_NEXTHOP_LABELS
, nexthop
->label_stack
);
104 XFREE(MTYPE_ISIS_NEXTHOP
, nexthop
);
107 static struct list
*isis_nexthop_list_dup(const struct list
*orig
)
110 struct listnode
*node
;
111 struct isis_nexthop
*nh
;
112 struct isis_nexthop
*nhcopy
;
115 for (ALL_LIST_ELEMENTS_RO(orig
, node
, nh
)) {
116 nhcopy
= isis_nexthop_dup(nh
);
117 listnode_add(copy
, nhcopy
);
122 static struct isis_nexthop
*nexthoplookup(struct list
*nexthops
, int family
,
123 union g_addr
*ip
, ifindex_t ifindex
)
125 struct listnode
*node
;
126 struct isis_nexthop
*nh
;
128 for (ALL_LIST_ELEMENTS_RO(nexthops
, node
, nh
)) {
129 if (nh
->ifindex
!= ifindex
)
132 /* if the IP is unspecified, return the first nexthop found on
138 if (nh
->family
!= family
)
143 if (IPV4_ADDR_CMP(&nh
->ip
.ipv4
, &ip
->ipv4
))
147 if (IPV6_ADDR_CMP(&nh
->ip
.ipv6
, &ip
->ipv6
))
151 flog_err(EC_LIB_DEVELOPMENT
,
152 "%s: unknown address family [%d]", __func__
,
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
)
167 struct isis_nexthop
*nh
;
168 union g_addr ip
= {};
172 for (unsigned int i
= 0; i
< adj
->ipv4_address_count
; i
++) {
173 ip
.ipv4
= adj
->ipv4_addresses
[i
];
175 if (!nexthoplookup(nexthops
, AF_INET
, &ip
,
176 adj
->circuit
->interface
->ifindex
)) {
177 nh
= isis_nexthop_create(
179 adj
->circuit
->interface
->ifindex
);
180 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
183 nh
->label_stack
= label_stack
;
184 listnode_add(nexthops
, nh
);
190 for (unsigned int i
= 0; i
< adj
->ll_ipv6_count
; i
++) {
191 ip
.ipv6
= adj
->ll_ipv6_addrs
[i
];
193 if (!nexthoplookup(nexthops
, AF_INET6
, &ip
,
194 adj
->circuit
->interface
->ifindex
)) {
195 nh
= isis_nexthop_create(
197 adj
->circuit
->interface
->ifindex
);
198 memcpy(nh
->sysid
, adj
->sysid
, sizeof(nh
->sysid
));
201 nh
->label_stack
= label_stack
;
202 listnode_add(nexthops
, nh
);
208 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown address family [%d]",
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
)
219 struct isis_nexthop
*nh
;
221 nh
= XCALLOC(MTYPE_ISIS_NEXTHOP
, sizeof(struct isis_nexthop
));
222 memcpy(nh
->sysid
, sysid
, sizeof(nh
->sysid
));
224 nh
->label_stack
= label_stack
;
225 listnode_add(rinfo
->nexthops
, nh
);
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
)
233 struct isis_route_info
*rinfo
;
234 struct isis_vertex_adj
*vadj
;
235 struct listnode
*node
;
237 rinfo
= XCALLOC(MTYPE_ISIS_ROUTE_INFO
, sizeof(struct isis_route_info
));
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
;
247 * Create dummy nexthops when running SPF on a testing
250 if (CHECK_FLAG(im
->options
, F_ISIS_UNIT_TEST
)) {
251 isis_route_add_dummy_nexthops(rinfo
, sadj
->id
, sr
,
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
);
263 /* update neighbor router address */
264 switch (prefix
->family
) {
266 if (depth
== 2 && prefix
->prefixlen
== IPV4_MAX_BITLEN
)
267 adj
->router_address
= prefix
->u
.prefix4
;
270 if (depth
== 2 && prefix
->prefixlen
== IPV6_MAX_BITLEN
271 && (!src_p
|| !src_p
->prefixlen
)) {
272 adj
->router_address6
= prefix
->u
.prefix6
;
276 flog_err(EC_LIB_DEVELOPMENT
,
277 "%s: unknown address family [%d]", __func__
,
281 adjinfo2nexthop(prefix
->family
, rinfo
->nexthops
, adj
, sr
,
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
;
297 static void isis_route_info_delete(struct isis_route_info
*route_info
)
299 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
300 if (!route_info
->sr_algo
[i
].present
)
303 if (route_info
->sr_algo
[i
].nexthops
== route_info
->nexthops
)
306 route_info
->sr_algo
[i
].nexthops
->del
=
307 (void (*)(void *))isis_nexthop_delete
;
308 list_delete(&route_info
->sr_algo
[i
].nexthops
);
311 if (route_info
->nexthops
) {
312 route_info
->nexthops
->del
=
313 (void (*)(void *))isis_nexthop_delete
;
314 list_delete(&route_info
->nexthops
);
317 XFREE(MTYPE_ISIS_ROUTE_INFO
, route_info
);
320 void isis_route_node_cleanup(struct route_table
*table
, struct route_node
*node
)
323 isis_route_info_delete(node
->info
);
326 struct isis_route_table_info
*isis_route_table_info_alloc(uint8_t algorithm
)
328 struct isis_route_table_info
*info
;
330 info
= XCALLOC(MTYPE_ISIS_ROUTE_TABLE_INFO
, sizeof(*info
));
331 info
->algorithm
= algorithm
;
335 void isis_route_table_info_free(void *info
)
337 XFREE(MTYPE_ISIS_ROUTE_TABLE_INFO
, info
);
340 uint8_t isis_route_table_algorithm(const struct route_table
*table
)
342 const struct isis_route_table_info
*info
= table
->info
;
344 return info
? info
->algorithm
: 0;
347 static bool isis_sr_psid_info_same(struct isis_sr_psid_info
*new,
348 struct isis_sr_psid_info
*old
)
350 if (new->present
!= old
->present
)
353 if (new->label
!= old
->label
)
356 if (new->sid
.flags
!= old
->sid
.flags
357 || new->sid
.value
!= old
->sid
.value
)
360 if (new->sid
.algorithm
!= old
->sid
.algorithm
)
366 static bool isis_label_stack_same(struct mpls_label_stack
*new,
367 struct mpls_label_stack
*old
)
373 if (new->num_labels
!= old
->num_labels
)
375 if (memcmp(&new->label
, &old
->label
,
376 sizeof(mpls_label_t
) * new->num_labels
))
382 static int isis_route_info_same(struct isis_route_info
*new,
383 struct isis_route_info
*old
, char *buf
,
386 struct listnode
*node
;
387 struct isis_nexthop
*new_nh
, *old_nh
;
389 if (new->cost
!= old
->cost
) {
391 snprintf(buf
, buf_size
, "cost (old: %u, new: %u)",
392 old
->cost
, new->cost
);
396 if (new->depth
!= old
->depth
) {
398 snprintf(buf
, buf_size
, "depth (old: %u, new: %u)",
399 old
->depth
, new->depth
);
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
;
407 new_sr_algo
= new->sr_algo
[i
];
408 old_sr_algo
= old
->sr_algo
[i
];
410 if (!isis_sr_psid_info_same(&new_sr_algo
, &old_sr_algo
)) {
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");
421 if (new->nexthops
->count
!= old
->nexthops
->count
) {
423 snprintf(buf
, buf_size
, "nhops num (old: %u, new: %u)",
424 old
->nexthops
->count
, new->nexthops
->count
);
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
);
433 snprintf(buf
, buf_size
,
434 "new nhop"); /* TODO: print nhop */
437 if (!isis_sr_psid_info_same(&new_nh
->sr
, &old_nh
->sr
)) {
439 snprintf(buf
, buf_size
, "nhop SR label");
442 if (!isis_label_stack_same(new_nh
->label_stack
,
443 old_nh
->label_stack
)) {
445 snprintf(buf
, buf_size
, "nhop label stack");
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
)) {
454 snprintf(buf
, buf_size
, "resync flag");
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
)
467 struct route_node
*route_node
;
468 struct isis_route_info
*rinfo_new
, *rinfo_old
, *route_info
= NULL
;
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
);
478 rinfo_old
= route_node
->info
;
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
);
486 route_unlock_node(route_node
);
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
))) {
495 if (IS_DEBUG_RTE_EVENTS
)
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
;
503 if (IS_DEBUG_RTE_EVENTS
)
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
);
517 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
518 route_node
->info
= route_info
;
523 void isis_route_delete(struct isis_area
*area
, struct route_node
*rode
,
524 struct route_table
*table
)
526 struct isis_route_info
*rinfo
;
527 char buff
[SRCDEST2STR_BUFFER
];
528 struct prefix
*prefix
;
529 struct prefix_ipv6
*src_p
;
532 srcdest_rnode2str(rode
, buff
, sizeof(buff
));
534 srcdest_rnode_prefixes(rode
, (const struct prefix
**)&prefix
,
535 (const struct prefix
**)&src_p
);
539 if (IS_DEBUG_RTE_EVENTS
)
541 "ISIS-Rte: tried to delete non-existent route %s",
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
);
552 isis_route_info_delete(rinfo
);
554 route_unlock_node(rode
);
557 static void isis_route_remove_previous_sid(struct isis_area
*area
,
558 struct prefix
*prefix
,
559 struct isis_route_info
*route_info
)
562 * Explicitly uninstall previous Prefix-SID label if it has
563 * changed or was removed.
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
]);
576 static void set_merge_route_info_sr_algo(struct isis_route_info
*mrinfo
,
577 struct isis_route_info
*rinfo
)
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
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
);
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
);
599 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
600 UNSET_FLAG(mrinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
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
)
610 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)) {
611 if (CHECK_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
))
614 isis_route_remove_previous_sid(area
, prefix
, route_info
);
617 isis_zebra_route_add_route(area
->isis
, prefix
, src_p
,
620 for (int i
= 0; i
< SR_ALGORITHM_COUNT
; i
++) {
621 struct isis_sr_psid_info sr_algo
;
623 sr_algo
= route_info
->sr_algo
[i
];
626 * Install/reinstall Prefix-SID label.
629 isis_zebra_prefix_sid_install(area
, prefix
,
632 hook_call(isis_route_update_hook
, area
, prefix
,
636 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
638 SET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
639 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_RESYNC
);
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
]);
648 /* Uninstall route. */
649 isis_zebra_route_del_route(area
->isis
, prefix
, src_p
,
651 hook_call(isis_route_update_hook
, area
, prefix
, route_info
);
653 UNSET_FLAG(route_info
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
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
)
662 struct route_node
*rnode
, *drnode
;
663 struct isis_route_info
*rinfo
;
665 char buff
[SRCDEST2STR_BUFFER
];
666 #endif /* EXTREME_DEBUG */
667 uint8_t algorithm
= isis_route_table_algorithm(table
);
669 for (rnode
= route_top(table
); rnode
;
670 rnode
= srcdest_route_next(rnode
)) {
671 if (rnode
->info
== NULL
)
675 struct prefix
*dst_p
;
676 struct prefix_ipv6
*src_p
;
678 srcdest_rnode_prefixes(rnode
,
679 (const struct prefix
**)&dst_p
,
680 (const struct prefix
**)&src_p
);
682 /* Link primary route to backup route. */
684 struct route_node
*rnode_bck
;
686 rnode_bck
= srcdest_rnode_lookup(table_backup
, dst_p
,
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
=
698 UNSET_FLAG(rinfo
->flag
,
699 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
704 if (IS_DEBUG_RTE_EVENTS
) {
705 srcdest2str(dst_p
, src_p
, buff
, sizeof(buff
));
707 "ISIS-Rte (%s): route validate: %s %s %s %s",
709 (CHECK_FLAG(rinfo
->flag
,
710 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)
713 (CHECK_FLAG(rinfo
->flag
,
714 ISIS_ROUTE_FLAG_ZEBRA_RESYNC
)
717 (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
)
722 #endif /* EXTREME_DEBUG */
724 isis_route_update(area
, dst_p
, src_p
, rinfo
);
726 if (CHECK_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
))
729 /* In case the verify is not for a merge, we use a single table
731 * validating => no problems with deleting routes. */
733 isis_route_delete(area
, rnode
, table
);
737 /* If we work on a merged table,
739 * delete node from each table as well before deleting
741 for (int i
= 0; tables
[i
]; i
++) {
742 drnode
= srcdest_rnode_lookup(tables
[i
], dst_p
, src_p
);
746 route_unlock_node(drnode
);
748 if (drnode
->info
!= rnode
->info
)
752 route_unlock_node(drnode
);
755 isis_route_delete(area
, rnode
, table
);
759 static void _isis_route_verify_merge(struct isis_area
*area
,
760 struct route_table
**tables
,
761 struct route_table
**tables_backup
,
764 void isis_route_verify_table(struct isis_area
*area
, struct route_table
*table
,
765 struct route_table
*table_backup
, int tree
)
767 struct route_table
*tables
[SR_ALGORITHM_COUNT
] = {table
};
768 struct route_table
*tables_backup
[SR_ALGORITHM_COUNT
] = {table_backup
};
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
;
776 for (ALL_LIST_ELEMENTS_RO(area
->flex_algos
->flex_algos
, node
, fa
)) {
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
);
786 #endif /* ifndef FABRICD */
788 _isis_route_verify_merge(area
, tables
, tables_backup
, tree
);
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.
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.
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
)
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
);
813 static void _isis_route_verify_merge(struct isis_area
*area
,
814 struct route_table
**tables
,
815 struct route_table
**tables_backup
,
818 struct route_table
*merge
;
819 struct route_node
*rnode
, *mrnode
;
821 merge
= srcdest_table_init();
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
;
833 struct prefix
*prefix
;
834 struct prefix_ipv6
*src_p
;
836 srcdest_rnode_prefixes(rnode
,
837 (const struct prefix
**)&prefix
,
838 (const struct prefix
**)&src_p
);
840 /* Link primary route to backup route. */
841 rnode_bck
= srcdest_rnode_lookup(tables_backup
[i
],
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
=
853 UNSET_FLAG(rinfo
->flag
,
854 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
857 mrnode
= srcdest_rnode_get(merge
, prefix
, src_p
);
858 struct isis_route_info
*mrinfo
= mrnode
->info
;
860 route_unlock_node(mrnode
);
861 set_merge_route_info_sr_algo(mrinfo
, rinfo
);
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
872 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
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
884 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
889 ISIS_ROUTE_FLAG_ZEBRA_SYNCED
)) {
893 mrnode
->info
= rnode
->info
;
898 _isis_route_verify_table(area
, merge
, NULL
, tables
);
899 route_table_finish(merge
);
902 void isis_route_invalidate_table(struct isis_area
*area
,
903 struct route_table
*table
)
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
)
914 rinfo
->backup
= NULL
;
915 rinfo
->sr_algo
[algorithm
].nexthops_backup
= NULL
;
917 * For now, always force routes that have backup
918 * nexthops to be reinstalled.
920 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ZEBRA_SYNCED
);
922 UNSET_FLAG(rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
926 void isis_route_switchover_nexthop(struct isis_area
*area
,
927 struct route_table
*table
, int family
,
928 union g_addr
*nexthop_addr
,
931 const char *ifname
= NULL
, *vrfname
= NULL
;
932 struct isis_route_info
*rinfo
;
933 struct prefix_ipv6
*src_p
;
934 struct route_node
*rnode
;
936 struct prefix
*prefix
;
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
);
944 zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
945 __func__
, family2str(family
), vrfname
? vrfname
: "",
946 ifname
? ifname
: "");
949 for (rnode
= route_top(table
); rnode
;
950 rnode
= srcdest_route_next(rnode
)) {
958 if (!nexthoplookup(rinfo
->nexthops
, family
, nexthop_addr
,
962 srcdest_rnode_prefixes(rnode
, (const struct prefix
**)&prefix
,
963 (const struct prefix
**)&src_p
);
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
);
970 isis_route_info_delete(rinfo
);
973 route_unlock_node(rnode
);