1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_spf.c
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
9 * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
19 #include "termtable.h"
26 #include "spf_backoff.h"
27 #include "srcdest_table.h"
31 #include "isis_errors.h"
32 #include "isis_constants.h"
33 #include "isis_common.h"
34 #include "isis_flags.h"
36 #include "isis_misc.h"
37 #include "isis_adjacency.h"
38 #include "isis_circuit.h"
41 #include "isis_dynhn.h"
43 #include "isis_route.h"
46 #include "isis_tlvs.h"
47 #include "isis_flex_algo.h"
48 #include "isis_zebra.h"
50 #include "isis_spf_private.h"
52 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SPFTREE
, "ISIS SPFtree");
53 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SPF_RUN
, "ISIS SPF Run Info");
54 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SPF_ADJ
, "ISIS SPF Adjacency");
55 DEFINE_MTYPE_STATIC(ISISD
, ISIS_VERTEX
, "ISIS vertex");
56 DEFINE_MTYPE_STATIC(ISISD
, ISIS_VERTEX_ADJ
, "ISIS SPF Vertex Adjacency");
58 static void spf_adj_list_parse_lsp(struct isis_spftree
*spftree
,
59 struct list
*adj_list
, struct isis_lsp
*lsp
,
60 const uint8_t *pseudo_nodeid
,
61 uint32_t pseudo_metric
);
64 * supports the given af ?
66 static bool speaks(uint8_t *protocols
, uint8_t count
, int family
)
68 for (uint8_t i
= 0; i
< count
; i
++) {
69 if (family
== AF_INET
&& protocols
[i
] == NLPID_IP
)
71 if (family
== AF_INET6
&& protocols
[i
] == NLPID_IPV6
)
78 struct isis_area
*area
;
83 static void remove_excess_adjs(struct list
*adjs
)
85 struct listnode
*node
, *excess
= NULL
;
86 struct isis_vertex_adj
*vadj
, *candidate
= NULL
;
89 for (ALL_LIST_ELEMENTS_RO(adjs
, node
, vadj
)) {
90 struct isis_adjacency
*adj
, *candidate_adj
;
92 adj
= vadj
->sadj
->adj
;
97 candidate
= listgetdata(excess
);
98 candidate_adj
= candidate
->sadj
->adj
;
100 if (candidate_adj
->sys_type
< adj
->sys_type
) {
104 if (candidate_adj
->sys_type
> adj
->sys_type
)
107 comp
= memcmp(candidate_adj
->sysid
, adj
->sysid
,
116 if (candidate_adj
->circuit
->idx
> adj
->circuit
->idx
) {
121 if (candidate_adj
->circuit
->idx
< adj
->circuit
->idx
)
124 comp
= memcmp(candidate_adj
->snpa
, adj
->snpa
, ETH_ALEN
);
131 list_delete_node(adjs
, excess
);
136 const char *vtype2string(enum vertextype vtype
)
139 case VTYPE_PSEUDO_IS
:
141 case VTYPE_PSEUDO_TE_IS
:
142 return "pseudo_TE-IS";
143 case VTYPE_NONPSEUDO_IS
:
145 case VTYPE_NONPSEUDO_TE_IS
:
149 case VTYPE_IPREACH_INTERNAL
:
150 return "IP internal";
151 case VTYPE_IPREACH_EXTERNAL
:
152 return "IP external";
153 case VTYPE_IPREACH_TE
:
155 case VTYPE_IP6REACH_INTERNAL
:
156 return "IP6 internal";
157 case VTYPE_IP6REACH_EXTERNAL
:
158 return "IP6 external";
162 return NULL
; /* Not reached */
165 const char *vid2string(const struct isis_vertex
*vertex
, char *buff
, int size
)
167 if (VTYPE_IS(vertex
->type
) || VTYPE_ES(vertex
->type
)) {
168 const char *hostname
= print_sys_hostname(vertex
->N
.id
);
169 strlcpy(buff
, hostname
, size
);
173 if (VTYPE_IP(vertex
->type
)) {
174 srcdest2str(&vertex
->N
.ip
.p
.dest
, &vertex
->N
.ip
.p
.src
, buff
,
182 static bool prefix_sid_cmp(const void *value1
, const void *value2
)
184 const struct isis_vertex
*c1
= value1
;
185 const struct isis_vertex
*c2
= value2
;
187 if (CHECK_FLAG(c1
->N
.ip
.sr
.sid
.flags
,
188 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
)
189 != CHECK_FLAG(c2
->N
.ip
.sr
.sid
.flags
,
190 ISIS_PREFIX_SID_VALUE
| ISIS_PREFIX_SID_LOCAL
))
193 return c1
->N
.ip
.sr
.sid
.value
== c2
->N
.ip
.sr
.sid
.value
;
196 static unsigned int prefix_sid_key_make(const void *value
)
198 const struct isis_vertex
*vertex
= value
;
200 return jhash_1word(vertex
->N
.ip
.sr
.sid
.value
, 0);
203 struct isis_vertex
*isis_spf_prefix_sid_lookup(struct isis_spftree
*spftree
,
204 struct isis_prefix_sid
*psid
)
206 struct isis_vertex lookup
= {};
208 lookup
.N
.ip
.sr
.sid
= *psid
;
209 return hash_lookup(spftree
->prefix_sids
, &lookup
);
212 void isis_vertex_adj_free(void *arg
)
214 struct isis_vertex_adj
*vadj
= arg
;
216 XFREE(MTYPE_ISIS_VERTEX_ADJ
, vadj
);
219 static struct isis_vertex
*isis_vertex_new(struct isis_spftree
*spftree
,
221 enum vertextype vtype
)
223 struct isis_vertex
*vertex
;
225 vertex
= XCALLOC(MTYPE_ISIS_VERTEX
, sizeof(struct isis_vertex
));
227 isis_vertex_id_init(vertex
, id
, vtype
);
229 vertex
->Adj_N
= list_new();
230 vertex
->Adj_N
->del
= isis_vertex_adj_free
;
231 vertex
->parents
= list_new();
233 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_HOPCOUNT_METRIC
)) {
234 vertex
->firsthops
= hash_create(isis_vertex_queue_hash_key
,
235 isis_vertex_queue_hash_cmp
,
242 void isis_vertex_del(struct isis_vertex
*vertex
)
244 list_delete(&vertex
->Adj_N
);
245 list_delete(&vertex
->parents
);
246 hash_clean_and_free(&vertex
->firsthops
, NULL
);
248 memset(vertex
, 0, sizeof(struct isis_vertex
));
249 XFREE(MTYPE_ISIS_VERTEX
, vertex
);
252 struct isis_vertex_adj
*
253 isis_vertex_adj_add(struct isis_spftree
*spftree
, struct isis_vertex
*vertex
,
254 struct list
*vadj_list
, struct isis_spf_adj
*sadj
,
255 struct isis_prefix_sid
*psid
, bool last_hop
)
257 struct isis_vertex_adj
*vadj
;
259 vadj
= XCALLOC(MTYPE_ISIS_VERTEX_ADJ
, sizeof(*vadj
));
261 if (spftree
->area
->srdb
.enabled
&& psid
) {
262 if (vertex
->N
.ip
.sr
.present
263 && vertex
->N
.ip
.sr
.sid
.value
!= psid
->value
)
265 "ISIS-SPF: ignoring different Prefix-SID for route %pFX",
266 &vertex
->N
.ip
.p
.dest
);
268 vadj
->sr
.sid
= *psid
;
269 vadj
->sr
.label
= sr_prefix_out_label(
270 spftree
->lspdb
, vertex
->N
.ip
.p
.dest
.family
,
271 psid
, sadj
->id
, last_hop
);
272 if (vadj
->sr
.label
!= MPLS_INVALID_LABEL
)
273 vadj
->sr
.present
= true;
276 listnode_add(vadj_list
, vadj
);
281 static void isis_vertex_adj_del(struct isis_vertex
*vertex
,
282 struct isis_adjacency
*adj
)
284 struct isis_vertex_adj
*vadj
;
285 struct listnode
*node
, *nextnode
;
290 for (ALL_LIST_ELEMENTS(vertex
->Adj_N
, node
, nextnode
, vadj
)) {
291 if (vadj
->sadj
->adj
== adj
) {
292 listnode_delete(vertex
->Adj_N
, vadj
);
293 isis_vertex_adj_free(vadj
);
299 bool isis_vertex_adj_exists(const struct isis_spftree
*spftree
,
300 const struct isis_vertex
*vertex
,
301 const struct isis_spf_adj
*sadj
)
303 struct isis_vertex_adj
*tmp
;
304 struct listnode
*node
;
306 for (ALL_LIST_ELEMENTS_RO(vertex
->Adj_N
, node
, tmp
)) {
307 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
)) {
308 if (memcmp(sadj
->id
, tmp
->sadj
->id
, sizeof(sadj
->id
))
312 if (sadj
->adj
== tmp
->sadj
->adj
)
320 static void isis_spf_adj_free(void *arg
)
322 struct isis_spf_adj
*sadj
= arg
;
324 XFREE(MTYPE_ISIS_SPF_ADJ
, sadj
);
327 static void _isis_spftree_init(struct isis_spftree
*tree
)
329 isis_vertex_queue_init(&tree
->tents
, "IS-IS SPF tents", true);
330 isis_vertex_queue_init(&tree
->paths
, "IS-IS SPF paths", false);
331 tree
->route_table
= srcdest_table_init();
332 tree
->route_table
->cleanup
= isis_route_node_cleanup
;
333 tree
->route_table
->info
= isis_route_table_info_alloc(tree
->algorithm
);
334 tree
->route_table_backup
= srcdest_table_init();
335 tree
->route_table_backup
->info
=
336 isis_route_table_info_alloc(tree
->algorithm
);
337 tree
->route_table_backup
->cleanup
= isis_route_node_cleanup
;
338 tree
->prefix_sids
= hash_create(prefix_sid_key_make
, prefix_sid_cmp
,
339 "SR Prefix-SID Entries");
340 tree
->sadj_list
= list_new();
341 tree
->sadj_list
->del
= isis_spf_adj_free
;
342 isis_rlfa_list_init(tree
);
343 tree
->lfa
.remote
.pc_spftrees
= list_new();
344 tree
->lfa
.remote
.pc_spftrees
->del
= (void (*)(void *))isis_spftree_del
;
345 if (tree
->type
== SPF_TYPE_RLFA
|| tree
->type
== SPF_TYPE_TI_LFA
) {
346 isis_spf_node_list_init(&tree
->lfa
.p_space
);
347 isis_spf_node_list_init(&tree
->lfa
.q_space
);
351 struct isis_spftree
*
352 isis_spftree_new(struct isis_area
*area
, struct lspdb_head
*lspdb
,
353 const uint8_t *sysid
, int level
, enum spf_tree_id tree_id
,
354 enum spf_type type
, uint8_t flags
, uint8_t algorithm
)
356 struct isis_spftree
*tree
;
358 tree
= XCALLOC(MTYPE_ISIS_SPFTREE
, sizeof(struct isis_spftree
));
362 tree
->last_run_timestamp
= 0;
363 tree
->last_run_monotime
= 0;
364 tree
->last_run_duration
= 0;
367 memcpy(tree
->sysid
, sysid
, ISIS_SYS_ID_LEN
);
369 tree
->tree_id
= tree_id
;
370 tree
->family
= (tree
->tree_id
== SPFTREE_IPV4
) ? AF_INET
: AF_INET6
;
372 tree
->algorithm
= algorithm
;
374 _isis_spftree_init(tree
);
379 static void _isis_spftree_del(struct isis_spftree
*spftree
)
381 hash_clean_and_free(&spftree
->prefix_sids
, NULL
);
382 isis_zebra_rlfa_unregister_all(spftree
);
383 isis_rlfa_list_clear(spftree
);
384 list_delete(&spftree
->lfa
.remote
.pc_spftrees
);
385 if (spftree
->type
== SPF_TYPE_RLFA
386 || spftree
->type
== SPF_TYPE_TI_LFA
) {
387 isis_spf_node_list_clear(&spftree
->lfa
.q_space
);
388 isis_spf_node_list_clear(&spftree
->lfa
.p_space
);
390 isis_spf_node_list_clear(&spftree
->adj_nodes
);
391 list_delete(&spftree
->sadj_list
);
392 isis_vertex_queue_free(&spftree
->tents
);
393 isis_vertex_queue_free(&spftree
->paths
);
394 isis_route_table_info_free(spftree
->route_table
->info
);
395 isis_route_table_info_free(spftree
->route_table_backup
->info
);
396 route_table_finish(spftree
->route_table
);
397 route_table_finish(spftree
->route_table_backup
);
400 void isis_spftree_del(struct isis_spftree
*spftree
)
402 _isis_spftree_del(spftree
);
404 spftree
->route_table
= NULL
;
406 XFREE(MTYPE_ISIS_SPFTREE
, spftree
);
411 static void isis_spftree_clear(struct isis_spftree
*spftree
)
413 _isis_spftree_del(spftree
);
414 _isis_spftree_init(spftree
);
416 #endif /* ifndef FABRICD */
418 static void isis_spftree_adj_del(struct isis_spftree
*spftree
,
419 struct isis_adjacency
*adj
)
421 struct listnode
*node
;
422 struct isis_vertex
*v
;
425 assert(!isis_vertex_queue_count(&spftree
->tents
));
426 for (ALL_QUEUE_ELEMENTS_RO(&spftree
->paths
, node
, v
))
427 isis_vertex_adj_del(v
, adj
);
431 void spftree_area_init(struct isis_area
*area
)
433 for (int tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++) {
434 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
435 if (!(area
->is_type
& level
))
437 if (area
->spftree
[tree
][level
- 1])
440 area
->spftree
[tree
][level
- 1] = isis_spftree_new(
441 area
, &area
->lspdb
[level
- 1],
442 area
->isis
->sysid
, level
, tree
,
443 SPF_TYPE_FORWARD
, 0, SR_ALGORITHM_SPF
);
448 void spftree_area_del(struct isis_area
*area
)
450 for (int tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++) {
451 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
452 if (!(area
->is_type
& level
))
454 if (!area
->spftree
[tree
][level
- 1])
457 isis_spftree_del(area
->spftree
[tree
][level
- 1]);
462 static int spf_adj_state_change(struct isis_adjacency
*adj
)
464 struct isis_area
*area
= adj
->circuit
->area
;
466 if (adj
->adj_state
== ISIS_ADJ_UP
)
469 /* Remove adjacency from all SPF trees. */
470 for (int tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++) {
471 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVEL2
; level
++) {
472 if (!(area
->is_type
& level
))
474 if (!area
->spftree
[tree
][level
- 1])
476 isis_spftree_adj_del(area
->spftree
[tree
][level
- 1],
481 if (fabricd_spftree(area
) != NULL
)
482 isis_spftree_adj_del(fabricd_spftree(area
), adj
);
488 * Find the system LSP: returns the LSP in our LSP database
489 * associated with the given system ID.
491 struct isis_lsp
*isis_root_system_lsp(struct lspdb_head
*lspdb
,
492 const uint8_t *sysid
)
494 struct isis_lsp
*lsp
;
495 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
497 memcpy(lspid
, sysid
, ISIS_SYS_ID_LEN
);
498 LSP_PSEUDO_ID(lspid
) = 0;
499 LSP_FRAGMENT(lspid
) = 0;
500 lsp
= lsp_search(lspdb
, lspid
);
501 if (lsp
&& lsp
->hdr
.rem_lifetime
!= 0)
507 * Add this IS to the root of SPT
509 static struct isis_vertex
*isis_spf_add_root(struct isis_spftree
*spftree
)
511 struct isis_vertex
*vertex
;
513 char buff
[VID2STR_BUFFER
];
514 #endif /* EXTREME_DEBUG */
516 vertex
= isis_vertex_new(spftree
, spftree
->sysid
,
517 spftree
->area
->oldmetric
519 : VTYPE_NONPSEUDO_TE_IS
);
520 isis_vertex_queue_append(&spftree
->paths
, vertex
);
523 if (IS_DEBUG_SPF_EVENTS
)
525 "ISIS-SPF: A:%hhu added this IS %s %s depth %d dist %d to PATHS",
526 spftree
->algorithm
, vtype2string(vertex
->type
),
527 vid2string(vertex
, buff
, sizeof(buff
)), vertex
->depth
,
529 #endif /* EXTREME_DEBUG */
534 static void vertex_add_parent_firsthop(struct hash_bucket
*bucket
, void *arg
)
536 struct isis_vertex
*vertex
= arg
;
537 struct isis_vertex
*hop
= bucket
->data
;
539 (void)hash_get(vertex
->firsthops
, hop
, hash_alloc_intern
);
542 static void vertex_update_firsthops(struct isis_vertex
*vertex
,
543 struct isis_vertex
*parent
)
545 if (vertex
->d_N
<= 2)
546 (void)hash_get(vertex
->firsthops
, vertex
, hash_alloc_intern
);
548 if (vertex
->d_N
< 2 || !parent
)
551 hash_iterate(parent
->firsthops
, vertex_add_parent_firsthop
, vertex
);
555 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
557 static struct isis_vertex
*
558 isis_spf_add2tent(struct isis_spftree
*spftree
, enum vertextype vtype
, void *id
,
559 uint32_t cost
, int depth
, struct isis_spf_adj
*sadj
,
560 struct isis_prefix_sid
*psid
, struct isis_vertex
*parent
)
562 struct isis_vertex
*vertex
;
563 struct listnode
*node
;
565 char buff
[VID2STR_BUFFER
];
567 vertex
= isis_find_vertex(&spftree
->paths
, id
, vtype
);
568 if (vertex
!= NULL
) {
570 "%s: vertex %s of type %s already in PATH; check for sysId collisions with established neighbors",
571 __func__
, vid2string(vertex
, buff
, sizeof(buff
)),
572 vtype2string(vertex
->type
));
575 vertex
= isis_find_vertex(&spftree
->tents
, id
, vtype
);
576 if (vertex
!= NULL
) {
578 "%s: vertex %s of type %s already in TENT; check for sysId collisions with established neighbors",
579 __func__
, vid2string(vertex
, buff
, sizeof(buff
)),
580 vtype2string(vertex
->type
));
584 vertex
= isis_vertex_new(spftree
, id
, vtype
);
586 vertex
->depth
= depth
;
587 if (VTYPE_IP(vtype
) && spftree
->area
->srdb
.enabled
&& psid
) {
588 struct isis_area
*area
= spftree
->area
;
589 struct isis_vertex
*vertex_psid
;
592 * Check if the Prefix-SID is already in use by another prefix.
594 vertex_psid
= isis_spf_prefix_sid_lookup(spftree
, psid
);
596 && !prefix_same(&vertex_psid
->N
.ip
.p
.dest
,
597 &vertex
->N
.ip
.p
.dest
)) {
599 EC_ISIS_SID_COLLISION
,
600 "ISIS-Sr (%s): collision detected, prefixes %pFX and %pFX share the same SID %s (%u)",
601 area
->area_tag
, &vertex
->N
.ip
.p
.dest
,
602 &vertex_psid
->N
.ip
.p
.dest
,
603 CHECK_FLAG(psid
->flags
, ISIS_PREFIX_SID_VALUE
)
611 local
= (vertex
->depth
== 1);
612 vertex
->N
.ip
.sr
.sid
= *psid
;
613 vertex
->N
.ip
.sr
.label
=
614 sr_prefix_in_label(area
, psid
, local
);
615 vertex
->N
.ip
.sr
.algorithm
= psid
->algorithm
;
617 if (vertex
->N
.ip
.sr
.label
!= MPLS_INVALID_LABEL
)
618 vertex
->N
.ip
.sr
.present
= true;
621 if (flex_algo_id_valid(spftree
->algorithm
) &&
622 !isis_flex_algo_elected_supported(
623 spftree
->algorithm
, spftree
->area
)) {
624 vertex
->N
.ip
.sr
.present
= false;
625 vertex
->N
.ip
.sr
.label
= MPLS_INVALID_LABEL
;
627 #endif /* ifndef FABRICD */
629 (void)hash_get(spftree
->prefix_sids
, vertex
,
635 listnode_add(vertex
->parents
, parent
);
638 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_HOPCOUNT_METRIC
))
639 vertex_update_firsthops(vertex
, parent
);
641 last_hop
= (vertex
->depth
== 2);
642 if (parent
&& parent
->Adj_N
&& listcount(parent
->Adj_N
) > 0) {
643 struct isis_vertex_adj
*parent_vadj
;
645 for (ALL_LIST_ELEMENTS_RO(parent
->Adj_N
, node
, parent_vadj
))
646 isis_vertex_adj_add(spftree
, vertex
, vertex
->Adj_N
,
647 parent_vadj
->sadj
, psid
, last_hop
);
649 isis_vertex_adj_add(spftree
, vertex
, vertex
->Adj_N
, sadj
, psid
,
654 if (IS_DEBUG_SPF_EVENTS
)
656 "ISIS-SPF: A:%hhu add to TENT %s %s %s depth %d dist %d adjcount %d",
657 spftree
->algorithm
, print_sys_hostname(vertex
->N
.id
),
658 vtype2string(vertex
->type
),
659 vid2string(vertex
, buff
, sizeof(buff
)), vertex
->depth
,
660 vertex
->d_N
, listcount(vertex
->Adj_N
));
661 #endif /* EXTREME_DEBUG */
663 isis_vertex_queue_insert(&spftree
->tents
, vertex
);
667 static void isis_spf_add_local(struct isis_spftree
*spftree
,
668 enum vertextype vtype
, void *id
,
669 struct isis_spf_adj
*sadj
, uint32_t cost
,
670 struct isis_prefix_sid
*psid
,
671 struct isis_vertex
*parent
)
673 struct isis_vertex
*vertex
;
675 vertex
= isis_find_vertex(&spftree
->tents
, id
, vtype
);
679 if (vertex
->d_N
== cost
) {
681 bool last_hop
= (vertex
->depth
== 2);
683 isis_vertex_adj_add(spftree
, vertex
,
684 vertex
->Adj_N
, sadj
, psid
,
688 if (!CHECK_FLAG(spftree
->flags
,
689 F_SPFTREE_NO_ADJACENCIES
)
690 && listcount(vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
691 remove_excess_adjs(vertex
->Adj_N
);
692 if (parent
&& (listnode_lookup(vertex
->parents
, parent
)
694 listnode_add(vertex
->parents
, parent
);
696 } else if (vertex
->d_N
< cost
) {
699 } else { /* vertex->d_N > cost */
701 isis_vertex_queue_delete(&spftree
->tents
, vertex
);
702 isis_vertex_del(vertex
);
706 isis_spf_add2tent(spftree
, vtype
, id
, cost
, 1, sadj
, psid
, parent
);
710 static void process_N(struct isis_spftree
*spftree
, enum vertextype vtype
,
711 void *id
, uint32_t dist
, uint16_t depth
,
712 struct isis_prefix_sid
*psid
, struct isis_vertex
*parent
)
714 struct isis_vertex
*vertex
;
716 char buff
[VID2STR_BUFFER
];
719 assert(spftree
&& parent
);
721 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_HOPCOUNT_METRIC
)
725 struct prefix_pair p
;
726 if (vtype
>= VTYPE_IPREACH_INTERNAL
) {
727 memcpy(&p
, id
, sizeof(p
));
733 /* RFC3787 section 5.1 */
734 if (spftree
->area
->newmetric
== 1) {
735 if (dist
> MAX_WIDE_PATH_METRIC
)
739 else if (spftree
->area
->oldmetric
== 1) {
740 if (dist
> MAX_NARROW_PATH_METRIC
)
745 vertex
= isis_find_vertex(&spftree
->paths
, id
, vtype
);
748 if (IS_DEBUG_SPF_EVENTS
)
750 "ISIS-SPF: A:%hhu process_N %s %s %s dist %d already found from PATH",
752 print_sys_hostname(vertex
->N
.id
),
754 vid2string(vertex
, buff
, sizeof(buff
)), dist
);
755 #endif /* EXTREME_DEBUG */
756 assert(dist
>= vertex
->d_N
);
760 vertex
= isis_find_vertex(&spftree
->tents
, id
, vtype
);
765 if (IS_DEBUG_SPF_EVENTS
)
767 "ISIS-SPF: A:%hhu process_N %s %s %s dist %d parent %s adjcount %d",
769 print_sys_hostname(vertex
->N
.id
),
771 vid2string(vertex
, buff
, sizeof(buff
)), dist
,
772 (parent
? print_sys_hostname(parent
->N
.id
)
774 (parent
? listcount(parent
->Adj_N
) : 0));
775 #endif /* EXTREME_DEBUG */
776 if (vertex
->d_N
== dist
) {
777 struct listnode
*node
;
778 struct isis_vertex_adj
*parent_vadj
;
779 for (ALL_LIST_ELEMENTS_RO(parent
->Adj_N
, node
,
781 if (!isis_vertex_adj_exists(
783 parent_vadj
->sadj
)) {
784 bool last_hop
= (vertex
->depth
== 2);
786 isis_vertex_adj_add(spftree
, vertex
,
791 if (CHECK_FLAG(spftree
->flags
,
792 F_SPFTREE_HOPCOUNT_METRIC
))
793 vertex_update_firsthops(vertex
, parent
);
795 if (!CHECK_FLAG(spftree
->flags
,
796 F_SPFTREE_NO_ADJACENCIES
)
797 && listcount(vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
798 remove_excess_adjs(vertex
->Adj_N
);
799 if (listnode_lookup(vertex
->parents
, parent
) == NULL
)
800 listnode_add(vertex
->parents
, parent
);
802 } else if (vertex
->d_N
< dist
) {
806 isis_vertex_queue_delete(&spftree
->tents
, vertex
);
807 isis_vertex_del(vertex
);
812 if (IS_DEBUG_SPF_EVENTS
)
814 "ISIS-SPF: A:%hhu process_N add2tent %s %s dist %d parent %s",
815 spftree
->algorithm
, print_sys_hostname(id
),
816 vtype2string(vtype
), dist
,
817 (parent
? print_sys_hostname(parent
->N
.id
) : "null"));
818 #endif /* EXTREME_DEBUG */
820 isis_spf_add2tent(spftree
, vtype
, id
, dist
, depth
, NULL
, psid
, parent
);
827 static int isis_spf_process_lsp(struct isis_spftree
*spftree
,
828 struct isis_lsp
*lsp
, uint32_t cost
,
829 uint16_t depth
, uint8_t *root_sysid
,
830 struct isis_vertex
*parent
)
832 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
833 struct listnode
*fragnode
= NULL
;
835 enum vertextype vtype
;
836 static const uint8_t null_sysid
[ISIS_SYS_ID_LEN
];
837 struct isis_mt_router_info
*mt_router_info
= NULL
;
838 struct prefix_pair ip_info
;
841 if (isis_lfa_excise_node_check(spftree
, lsp
->hdr
.lsp_id
)) {
843 zlog_debug("ISIS-LFA: excising node %s",
844 print_sys_hostname(lsp
->hdr
.lsp_id
));
851 if (spftree
->mtid
!= ISIS_MT_IPV4_UNICAST
)
852 mt_router_info
= isis_tlvs_lookup_mt_router_info(lsp
->tlvs
,
855 if (!pseudo_lsp
&& (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
856 && !speaks(lsp
->tlvs
->protocols_supported
.protocols
,
857 lsp
->tlvs
->protocols_supported
.count
,
862 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
863 bool no_overload
= (pseudo_lsp
864 || (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
865 && !ISIS_MASK_LSP_OL_BIT(lsp
->hdr
.lsp_bits
))
866 || (mt_router_info
&& !mt_router_info
->overload
));
869 if (lsp
->hdr
.seqno
== 0) {
870 zlog_warn("%s: lsp with 0 seq_num - ignore", __func__
);
875 if (IS_DEBUG_SPF_EVENTS
)
876 zlog_debug("ISIS-SPF: A:%hhu process_lsp %s",
878 print_sys_hostname(lsp
->hdr
.lsp_id
));
879 #endif /* EXTREME_DEBUG */
882 if ((pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
883 && spftree
->area
->oldmetric
) {
884 struct isis_oldstyle_reach
*r
;
885 for (r
= (struct isis_oldstyle_reach
*)
886 lsp
->tlvs
->oldstyle_reach
.head
;
892 /* Two way connectivity */
893 if (!LSP_PSEUDO_ID(r
->id
)
894 && !memcmp(r
->id
, root_sysid
,
898 && !memcmp(r
->id
, null_sysid
,
901 dist
= cost
+ r
->metric
;
905 : VTYPE_NONPSEUDO_IS
,
906 (void *)r
->id
, dist
, depth
+ 1, NULL
,
911 if (spftree
->area
->newmetric
) {
912 struct isis_item_list
*te_neighs
= NULL
;
913 if (pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
914 te_neighs
= &lsp
->tlvs
->extended_reach
;
916 te_neighs
= isis_lookup_mt_items(
917 &lsp
->tlvs
->mt_reach
, spftree
->mtid
);
919 struct isis_extended_reach
*er
;
920 for (er
= te_neighs
? (struct isis_extended_reach
*)
925 /* Two way connectivity */
926 if (!LSP_PSEUDO_ID(er
->id
)
927 && !memcmp(er
->id
, root_sysid
,
931 && !memcmp(er
->id
, null_sysid
,
936 if (flex_algo_id_valid(spftree
->algorithm
) &&
937 (!sr_algorithm_participated(
938 lsp
, spftree
->algorithm
) ||
939 isis_flex_algo_constraint_drop(spftree
,
942 #endif /* ifndef FABRICD */
945 + (CHECK_FLAG(spftree
->flags
,
946 F_SPFTREE_HOPCOUNT_METRIC
)
950 LSP_PSEUDO_ID(er
->id
)
952 : VTYPE_NONPSEUDO_TE_IS
,
953 (void *)er
->id
, dist
, depth
+ 1, NULL
,
959 if (!fabricd
&& !pseudo_lsp
&& spftree
->family
== AF_INET
960 && spftree
->mtid
== ISIS_MT_IPV4_UNICAST
961 && spftree
->area
->oldmetric
) {
962 struct isis_item_list
*reachs
[] = {
963 &lsp
->tlvs
->oldstyle_ip_reach
,
964 &lsp
->tlvs
->oldstyle_ip_reach_ext
};
966 for (unsigned int i
= 0; i
< array_size(reachs
); i
++) {
967 vtype
= i
? VTYPE_IPREACH_EXTERNAL
968 : VTYPE_IPREACH_INTERNAL
;
970 memset(&ip_info
, 0, sizeof(ip_info
));
971 ip_info
.dest
.family
= AF_INET
;
973 struct isis_oldstyle_ip_reach
*r
;
974 for (r
= (struct isis_oldstyle_ip_reach
*)reachs
[i
]
977 dist
= cost
+ r
->metric
;
978 ip_info
.dest
.u
.prefix4
= r
->prefix
.prefix
;
979 ip_info
.dest
.prefixlen
= r
->prefix
.prefixlen
;
980 process_N(spftree
, vtype
, &ip_info
,
981 dist
, depth
+ 1, NULL
, parent
);
986 /* we can skip all the rest if we're using metric style narrow */
987 if (!spftree
->area
->newmetric
)
990 if (!pseudo_lsp
&& spftree
->family
== AF_INET
) {
991 struct isis_item_list
*ipv4_reachs
;
992 if (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
993 ipv4_reachs
= &lsp
->tlvs
->extended_ip_reach
;
995 ipv4_reachs
= isis_lookup_mt_items(
996 &lsp
->tlvs
->mt_ip_reach
, spftree
->mtid
);
998 memset(&ip_info
, 0, sizeof(ip_info
));
999 ip_info
.dest
.family
= AF_INET
;
1001 struct isis_extended_ip_reach
*r
;
1002 for (r
= ipv4_reachs
1003 ? (struct isis_extended_ip_reach
*)
1007 dist
= cost
+ r
->metric
;
1008 ip_info
.dest
.u
.prefix4
= r
->prefix
.prefix
;
1009 ip_info
.dest
.prefixlen
= r
->prefix
.prefixlen
;
1011 /* Parse list of Prefix-SID subTLVs if SR is enabled */
1012 has_valid_psid
= false;
1013 if (spftree
->area
->srdb
.enabled
&& r
->subtlvs
) {
1014 for (struct isis_item
*i
=
1015 r
->subtlvs
->prefix_sids
.head
;
1017 struct isis_prefix_sid
*psid
=
1018 (struct isis_prefix_sid
*)i
;
1020 if (psid
->algorithm
!=
1025 if (flex_algo_id_valid(
1026 spftree
->algorithm
) &&
1027 (!sr_algorithm_participated(
1028 lsp
, spftree
->algorithm
) ||
1029 !isis_flex_algo_elected_supported(
1033 #endif /* ifndef FABRICD */
1035 has_valid_psid
= true;
1036 process_N(spftree
, VTYPE_IPREACH_TE
,
1037 &ip_info
, dist
, depth
+ 1,
1040 * Stop the Prefix-SID iteration since
1041 * we only support the SPF algorithm for
1047 if (!has_valid_psid
)
1048 process_N(spftree
, VTYPE_IPREACH_TE
, &ip_info
,
1049 dist
, depth
+ 1, NULL
, parent
);
1053 if (!pseudo_lsp
&& spftree
->family
== AF_INET6
) {
1054 struct isis_item_list
*ipv6_reachs
;
1055 if (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
1056 ipv6_reachs
= &lsp
->tlvs
->ipv6_reach
;
1058 ipv6_reachs
= isis_lookup_mt_items(
1059 &lsp
->tlvs
->mt_ipv6_reach
, spftree
->mtid
);
1061 struct isis_ipv6_reach
*r
;
1062 for (r
= ipv6_reachs
1063 ? (struct isis_ipv6_reach
*)ipv6_reachs
->head
1066 dist
= cost
+ r
->metric
;
1067 vtype
= r
->external
? VTYPE_IP6REACH_EXTERNAL
1068 : VTYPE_IP6REACH_INTERNAL
;
1069 memset(&ip_info
, 0, sizeof(ip_info
));
1070 ip_info
.dest
.family
= AF_INET6
;
1071 ip_info
.dest
.u
.prefix6
= r
->prefix
.prefix
;
1072 ip_info
.dest
.prefixlen
= r
->prefix
.prefixlen
;
1074 if (spftree
->area
->srdb
.enabled
&& r
->subtlvs
&&
1075 r
->subtlvs
->source_prefix
&&
1076 r
->subtlvs
->source_prefix
->prefixlen
) {
1077 if (spftree
->tree_id
!= SPFTREE_DSTSRC
) {
1078 char buff
[VID2STR_BUFFER
];
1079 zlog_warn("Ignoring dest-src route %s in non dest-src topology",
1082 r
->subtlvs
->source_prefix
,
1088 ip_info
.src
= *r
->subtlvs
->source_prefix
;
1091 /* Parse list of Prefix-SID subTLVs */
1092 has_valid_psid
= false;
1094 for (struct isis_item
*i
=
1095 r
->subtlvs
->prefix_sids
.head
;
1097 struct isis_prefix_sid
*psid
=
1098 (struct isis_prefix_sid
*)i
;
1100 if (psid
->algorithm
!=
1105 if (flex_algo_id_valid(
1106 spftree
->algorithm
) &&
1107 (!sr_algorithm_participated(
1108 lsp
, spftree
->algorithm
) ||
1109 !isis_flex_algo_elected_supported(
1113 #endif /* ifndef FABRICD */
1115 has_valid_psid
= true;
1116 process_N(spftree
, vtype
, &ip_info
,
1117 dist
, depth
+ 1, psid
,
1120 * Stop the Prefix-SID iteration since
1121 * we only support the SPF algorithm for
1127 if (!has_valid_psid
)
1128 process_N(spftree
, vtype
, &ip_info
, dist
,
1129 depth
+ 1, NULL
, parent
);
1135 /* if attach bit set in LSP, attached-bit receive ignore is
1136 * not configured, we are a level-1 area and we have no other
1137 * level-2 | level1-2 areas then add a default route toward
1140 if ((lsp
->hdr
.lsp_bits
& LSPBIT_ATT
) == LSPBIT_ATT
1141 && !spftree
->area
->attached_bit_rcv_ignore
1142 && (spftree
->area
->is_type
& IS_LEVEL_1
)
1143 && !isis_level2_adj_up(spftree
->area
)) {
1144 struct prefix_pair ip_info
= { {0} };
1145 if (IS_DEBUG_RTE_EVENTS
)
1146 zlog_debug("ISIS-Spf (%pLS): add default %s route",
1148 spftree
->family
== AF_INET
? "ipv4"
1151 if (spftree
->family
== AF_INET
) {
1152 ip_info
.dest
.family
= AF_INET
;
1153 vtype
= VTYPE_IPREACH_INTERNAL
;
1155 ip_info
.dest
.family
= AF_INET6
;
1156 vtype
= VTYPE_IP6REACH_INTERNAL
;
1158 process_N(spftree
, vtype
, &ip_info
, cost
, depth
+ 1, NULL
,
1162 if (fragnode
== NULL
)
1163 fragnode
= listhead(lsp
->lspu
.frags
);
1165 fragnode
= listnextnode(fragnode
);
1168 lsp
= listgetdata(fragnode
);
1175 static struct isis_adjacency
*adj_find(struct list
*adj_list
, const uint8_t *id
,
1176 int level
, uint16_t mtid
, int family
)
1178 struct isis_adjacency
*adj
;
1179 struct listnode
*node
;
1181 for (ALL_LIST_ELEMENTS_RO(adj_list
, node
, adj
)) {
1182 if (!(adj
->level
& level
))
1184 if (memcmp(adj
->sysid
, id
, ISIS_SYS_ID_LEN
) != 0)
1186 if (adj
->adj_state
!= ISIS_ADJ_UP
)
1188 if (!adj_has_mt(adj
, mtid
))
1190 if (mtid
== ISIS_MT_IPV4_UNICAST
1191 && !speaks(adj
->nlpids
.nlpids
, adj
->nlpids
.count
, family
))
1199 struct spf_preload_tent_ip_reach_args
{
1200 struct isis_spftree
*spftree
;
1201 struct isis_vertex
*parent
;
1204 static int isis_spf_preload_tent_ip_reach_cb(const struct prefix
*prefix
,
1205 uint32_t metric
, bool external
,
1206 struct isis_subtlvs
*subtlvs
,
1209 struct spf_preload_tent_ip_reach_args
*args
= arg
;
1210 struct isis_spftree
*spftree
= args
->spftree
;
1211 struct isis_vertex
*parent
= args
->parent
;
1212 struct prefix_pair ip_info
;
1213 enum vertextype vtype
;
1214 bool has_valid_psid
= false;
1217 return LSP_ITER_CONTINUE
;
1219 assert(spftree
->family
== prefix
->family
);
1220 memset(&ip_info
, 0, sizeof(ip_info
));
1221 prefix_copy(&ip_info
.dest
, prefix
);
1222 apply_mask(&ip_info
.dest
);
1224 if (prefix
->family
== AF_INET
)
1225 vtype
= VTYPE_IPREACH_INTERNAL
;
1227 vtype
= VTYPE_IP6REACH_INTERNAL
;
1229 /* Parse list of Prefix-SID subTLVs if SR is enabled */
1230 if (spftree
->area
->srdb
.enabled
&& subtlvs
) {
1231 for (struct isis_item
*i
= subtlvs
->prefix_sids
.head
; i
;
1233 struct isis_prefix_sid
*psid
=
1234 (struct isis_prefix_sid
*)i
;
1236 if (psid
->algorithm
!= spftree
->algorithm
)
1239 has_valid_psid
= true;
1240 isis_spf_add_local(spftree
, vtype
, &ip_info
, NULL
, 0,
1244 * Stop the Prefix-SID iteration since we only support
1245 * the SPF algorithm for now.
1250 if (!has_valid_psid
)
1251 isis_spf_add_local(spftree
, vtype
, &ip_info
, NULL
, 0, NULL
,
1254 return LSP_ITER_CONTINUE
;
1257 static void isis_spf_preload_tent(struct isis_spftree
*spftree
,
1258 uint8_t *root_sysid
,
1259 struct isis_lsp
*root_lsp
,
1260 struct isis_vertex
*parent
)
1262 struct spf_preload_tent_ip_reach_args ip_reach_args
;
1263 struct isis_spf_adj
*sadj
;
1264 struct listnode
*node
;
1266 if (!CHECK_FLAG(spftree
->flags
, F_SPFTREE_HOPCOUNT_METRIC
)) {
1267 ip_reach_args
.spftree
= spftree
;
1268 ip_reach_args
.parent
= parent
;
1269 isis_lsp_iterate_ip_reach(
1270 root_lsp
, spftree
->family
, spftree
->mtid
,
1271 isis_spf_preload_tent_ip_reach_cb
, &ip_reach_args
);
1274 /* Iterate over adjacencies. */
1275 for (ALL_LIST_ELEMENTS_RO(spftree
->sadj_list
, node
, sadj
)) {
1276 const uint8_t *adj_id
;
1279 if (CHECK_FLAG(sadj
->flags
, F_ISIS_SPF_ADJ_BROADCAST
))
1280 adj_id
= sadj
->lan
.desig_is_id
;
1284 if (isis_lfa_excise_adj_check(spftree
, adj_id
)) {
1286 zlog_debug("ISIS-SPF: excising adjacency %pPN",
1291 metric
= CHECK_FLAG(spftree
->flags
, F_SPFTREE_HOPCOUNT_METRIC
)
1294 if (!LSP_PSEUDO_ID(sadj
->id
)) {
1295 isis_spf_add_local(spftree
,
1296 CHECK_FLAG(sadj
->flags
,
1297 F_ISIS_SPF_ADJ_OLDMETRIC
)
1298 ? VTYPE_NONPSEUDO_IS
1299 : VTYPE_NONPSEUDO_TE_IS
,
1300 sadj
->id
, sadj
, metric
, NULL
,
1302 } else if (sadj
->lsp
) {
1303 isis_spf_process_lsp(spftree
, sadj
->lsp
, metric
, 0,
1304 spftree
->sysid
, parent
);
1309 struct spf_adj_find_reverse_metric_args
{
1310 const uint8_t *id_self
;
1311 uint32_t reverse_metric
;
1314 static int spf_adj_find_reverse_metric_cb(const uint8_t *id
, uint32_t metric
,
1316 struct isis_ext_subtlvs
*subtlvs
,
1319 struct spf_adj_find_reverse_metric_args
*args
= arg
;
1321 if (memcmp(id
, args
->id_self
, ISIS_SYS_ID_LEN
))
1322 return LSP_ITER_CONTINUE
;
1324 args
->reverse_metric
= metric
;
1326 return LSP_ITER_STOP
;
1330 * Change all SPF adjacencies to use the link cost in the direction from the
1331 * next hop back towards root in place of the link cost in the direction away
1332 * from root towards the next hop.
1334 static void spf_adj_get_reverse_metrics(struct isis_spftree
*spftree
)
1336 struct isis_spf_adj
*sadj
;
1337 struct listnode
*node
, *nnode
;
1339 for (ALL_LIST_ELEMENTS(spftree
->sadj_list
, node
, nnode
, sadj
)) {
1340 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1341 struct isis_lsp
*lsp_adj
;
1342 const uint8_t *id_self
;
1343 struct spf_adj_find_reverse_metric_args args
;
1345 /* Skip pseudonodes. */
1346 if (LSP_PSEUDO_ID(sadj
->id
))
1349 /* Find LSP of the corresponding adjacency. */
1350 memcpy(lspid
, sadj
->id
, ISIS_SYS_ID_LEN
);
1351 LSP_PSEUDO_ID(lspid
) = 0;
1352 LSP_FRAGMENT(lspid
) = 0;
1353 lsp_adj
= lsp_search(spftree
->lspdb
, lspid
);
1354 if (lsp_adj
== NULL
|| lsp_adj
->hdr
.rem_lifetime
== 0) {
1355 /* Delete one-way adjacency. */
1356 listnode_delete(spftree
->sadj_list
, sadj
);
1357 isis_spf_adj_free(sadj
);
1361 /* Find root node in the LSP of the adjacent router. */
1362 if (CHECK_FLAG(sadj
->flags
, F_ISIS_SPF_ADJ_BROADCAST
))
1363 id_self
= sadj
->lan
.desig_is_id
;
1365 id_self
= spftree
->sysid
;
1366 args
.id_self
= id_self
;
1367 args
.reverse_metric
= UINT32_MAX
;
1368 isis_lsp_iterate_is_reach(lsp_adj
, spftree
->mtid
,
1369 spf_adj_find_reverse_metric_cb
,
1371 if (args
.reverse_metric
== UINT32_MAX
) {
1372 /* Delete one-way adjacency. */
1373 listnode_delete(spftree
->sadj_list
, sadj
);
1374 isis_spf_adj_free(sadj
);
1377 sadj
->metric
= args
.reverse_metric
;
1381 static void spf_adj_list_parse_tlv(struct isis_spftree
*spftree
,
1382 struct list
*adj_list
, const uint8_t *id
,
1383 const uint8_t *desig_is_id
,
1384 uint32_t pseudo_metric
, uint32_t metric
,
1386 struct isis_ext_subtlvs
*subtlvs
)
1388 struct isis_spf_adj
*sadj
;
1389 uint8_t lspid
[ISIS_SYS_ID_LEN
+ 2];
1390 struct isis_lsp
*lsp
;
1393 /* Skip self in the pseudonode. */
1394 if (desig_is_id
&& !memcmp(id
, spftree
->sysid
, ISIS_SYS_ID_LEN
))
1397 /* Find LSP from the adjacency. */
1398 memcpy(lspid
, id
, ISIS_SYS_ID_LEN
+ 1);
1399 LSP_FRAGMENT(lspid
) = 0;
1400 lsp
= lsp_search(spftree
->lspdb
, lspid
);
1401 if (lsp
== NULL
|| lsp
->hdr
.rem_lifetime
== 0) {
1402 zlog_warn("ISIS-SPF: No LSP found from root to L%d %pLS",
1403 spftree
->level
, lspid
);
1407 sadj
= XCALLOC(MTYPE_ISIS_SPF_ADJ
, sizeof(*sadj
));
1408 memcpy(sadj
->id
, id
, sizeof(sadj
->id
));
1410 memcpy(sadj
->lan
.desig_is_id
, desig_is_id
,
1411 sizeof(sadj
->lan
.desig_is_id
));
1412 SET_FLAG(flags
, F_ISIS_SPF_ADJ_BROADCAST
);
1413 sadj
->metric
= pseudo_metric
;
1415 sadj
->metric
= metric
;
1417 SET_FLAG(flags
, F_ISIS_SPF_ADJ_OLDMETRIC
);
1419 sadj
->subtlvs
= subtlvs
;
1420 sadj
->flags
= flags
;
1422 if ((oldmetric
&& metric
== ISIS_NARROW_METRIC_INFINITY
)
1423 || (!oldmetric
&& metric
== ISIS_WIDE_METRIC_INFINITY
))
1424 SET_FLAG(flags
, F_ISIS_SPF_ADJ_METRIC_INFINITY
);
1426 /* Set real adjacency. */
1427 if (!CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
)
1428 && !LSP_PSEUDO_ID(id
)) {
1429 struct isis_adjacency
*adj
;
1431 adj
= adj_find(adj_list
, id
, spftree
->level
, spftree
->mtid
,
1434 XFREE(MTYPE_ISIS_SPF_ADJ
, sadj
);
1438 listnode_delete(adj_list
, adj
);
1442 /* Add adjacency to the list. */
1443 listnode_add(spftree
->sadj_list
, sadj
);
1445 if (!LSP_PSEUDO_ID(id
)) {
1446 struct isis_spf_node
*node
;
1448 node
= isis_spf_node_find(&spftree
->adj_nodes
, id
);
1450 node
= isis_spf_node_new(&spftree
->adj_nodes
, id
);
1451 if (node
->best_metric
== 0 || sadj
->metric
< node
->best_metric
)
1452 node
->best_metric
= sadj
->metric
;
1453 listnode_add(node
->adjacencies
, sadj
);
1456 /* Parse pseudonode LSP too. */
1457 if (LSP_PSEUDO_ID(id
))
1458 spf_adj_list_parse_lsp(spftree
, adj_list
, lsp
, id
, metric
);
1461 static void spf_adj_list_parse_lsp(struct isis_spftree
*spftree
,
1462 struct list
*adj_list
, struct isis_lsp
*lsp
,
1463 const uint8_t *pseudo_nodeid
,
1464 uint32_t pseudo_metric
)
1466 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->hdr
.lsp_id
);
1467 struct isis_lsp
*frag
;
1468 struct listnode
*node
;
1469 struct isis_item
*head
;
1470 struct isis_item_list
*te_neighs
;
1472 if (lsp
->hdr
.seqno
== 0 || lsp
->hdr
.rem_lifetime
== 0)
1477 if (pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
) {
1478 head
= lsp
->tlvs
->oldstyle_reach
.head
;
1479 for (struct isis_oldstyle_reach
*reach
=
1480 (struct isis_oldstyle_reach
*)head
;
1481 reach
; reach
= reach
->next
) {
1482 spf_adj_list_parse_tlv(
1483 spftree
, adj_list
, reach
->id
,
1484 pseudo_nodeid
, pseudo_metric
,
1485 reach
->metric
, true, NULL
);
1489 if (pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
1490 te_neighs
= &lsp
->tlvs
->extended_reach
;
1492 te_neighs
= isis_get_mt_items(&lsp
->tlvs
->mt_reach
,
1495 head
= te_neighs
->head
;
1496 for (struct isis_extended_reach
*reach
=
1497 (struct isis_extended_reach
*)head
;
1498 reach
; reach
= reach
->next
) {
1501 * cutting out adjacency by flex-algo link
1502 * affinity attribute
1504 if (flex_algo_id_valid(spftree
->algorithm
) &&
1505 (!sr_algorithm_participated(
1506 lsp
, spftree
->algorithm
) ||
1507 isis_flex_algo_constraint_drop(
1508 spftree
, lsp
, reach
)))
1510 #endif /* ifndef FABRICD */
1512 spf_adj_list_parse_tlv(
1513 spftree
, adj_list
, reach
->id
,
1514 pseudo_nodeid
, pseudo_metric
,
1515 reach
->metric
, false, reach
->subtlvs
);
1520 if (LSP_FRAGMENT(lsp
->hdr
.lsp_id
))
1523 /* Parse LSP fragments. */
1524 for (ALL_LIST_ELEMENTS_RO(lsp
->lspu
.frags
, node
, frag
)) {
1528 spf_adj_list_parse_lsp(spftree
, adj_list
, frag
, pseudo_nodeid
,
1533 static void isis_spf_build_adj_list(struct isis_spftree
*spftree
,
1534 struct isis_lsp
*lsp
)
1536 struct list
*adj_list
= NULL
;
1538 if (!CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
))
1539 adj_list
= list_dup(spftree
->area
->adjacency_list
);
1541 spf_adj_list_parse_lsp(spftree
, adj_list
, lsp
, NULL
, 0);
1543 if (!CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
))
1544 list_delete(&adj_list
);
1546 if (spftree
->type
== SPF_TYPE_REVERSE
)
1547 spf_adj_get_reverse_metrics(spftree
);
1551 * The parent(s) for vertex is set when added to TENT list
1552 * now we just put the child pointer(s) in place
1554 static void add_to_paths(struct isis_spftree
*spftree
,
1555 struct isis_vertex
*vertex
)
1557 #ifdef EXTREME_DEBUG
1558 char buff
[VID2STR_BUFFER
];
1559 #endif /* EXTREME_DEBUG */
1561 if (isis_find_vertex(&spftree
->paths
, &vertex
->N
, vertex
->type
))
1563 isis_vertex_queue_append(&spftree
->paths
, vertex
);
1565 #ifdef EXTREME_DEBUG
1566 if (IS_DEBUG_SPF_EVENTS
)
1568 "ISIS-SPF: A:%hhu S:%p added %s %s %s depth %d dist %d to PATHS",
1569 spftree
->algorithm
, spftree
,
1570 print_sys_hostname(vertex
->N
.id
),
1571 vtype2string(vertex
->type
),
1572 vid2string(vertex
, buff
, sizeof(buff
)), vertex
->depth
,
1574 #endif /* EXTREME_DEBUG */
1577 static void init_spt(struct isis_spftree
*spftree
, int mtid
)
1579 /* Clear data from previous run. */
1580 hash_clean(spftree
->prefix_sids
, NULL
);
1581 isis_spf_node_list_clear(&spftree
->adj_nodes
);
1582 list_delete_all_node(spftree
->sadj_list
);
1583 isis_vertex_queue_clear(&spftree
->tents
);
1584 isis_vertex_queue_clear(&spftree
->paths
);
1585 isis_zebra_rlfa_unregister_all(spftree
);
1586 isis_rlfa_list_clear(spftree
);
1587 list_delete_all_node(spftree
->lfa
.remote
.pc_spftrees
);
1588 memset(&spftree
->lfa
.protection_counters
, 0,
1589 sizeof(spftree
->lfa
.protection_counters
));
1591 spftree
->mtid
= mtid
;
1594 static enum spf_prefix_priority
1595 spf_prefix_priority(struct isis_spftree
*spftree
, struct isis_vertex
*vertex
)
1597 struct isis_area
*area
= spftree
->area
;
1598 struct prefix
*prefix
= &vertex
->N
.ip
.p
.dest
;
1600 for (int priority
= SPF_PREFIX_PRIO_CRITICAL
;
1601 priority
<= SPF_PREFIX_PRIO_MEDIUM
; priority
++) {
1602 struct spf_prefix_priority_acl
*ppa
;
1603 enum filter_type ret
= FILTER_PERMIT
;
1605 ppa
= &area
->spf_prefix_priorities
[priority
];
1606 switch (spftree
->family
) {
1608 ret
= access_list_apply(ppa
->list_v4
, prefix
);
1611 ret
= access_list_apply(ppa
->list_v6
, prefix
);
1617 if (ret
== FILTER_PERMIT
)
1621 /* Assign medium priority to loopback prefixes by default. */
1622 if (is_host_route(prefix
))
1623 return SPF_PREFIX_PRIO_MEDIUM
;
1625 return SPF_PREFIX_PRIO_LOW
;
1628 static void spf_path_process(struct isis_spftree
*spftree
,
1629 struct isis_vertex
*vertex
)
1631 struct isis_area
*area
= spftree
->area
;
1632 int level
= spftree
->level
;
1633 char buff
[VID2STR_BUFFER
];
1635 if (spftree
->type
== SPF_TYPE_TI_LFA
&& VTYPE_IS(vertex
->type
)
1636 && !CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
)) {
1637 if (listcount(vertex
->Adj_N
) > 0) {
1638 struct isis_adjacency
*adj
;
1640 if (isis_tilfa_check(spftree
, vertex
) != 0)
1643 adj
= isis_adj_find(area
, level
, vertex
->N
.id
);
1645 sr_adj_sid_add_single(adj
, spftree
->family
,
1646 true, vertex
->Adj_N
);
1647 } else if (IS_DEBUG_SPF_EVENTS
)
1649 "ISIS-SPF: no adjacencies, do not install backup Adj-SID for %s depth %d dist %d",
1650 vid2string(vertex
, buff
, sizeof(buff
)),
1651 vertex
->depth
, vertex
->d_N
);
1654 if (VTYPE_IP(vertex
->type
)
1655 && !CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ROUTES
)) {
1656 enum spf_prefix_priority priority
;
1658 priority
= spf_prefix_priority(spftree
, vertex
);
1659 vertex
->N
.ip
.priority
= priority
;
1660 if (vertex
->depth
== 1 || listcount(vertex
->Adj_N
) > 0) {
1661 struct isis_spftree
*pre_spftree
;
1662 struct route_table
*route_table
= NULL
;
1663 bool allow_ecmp
= false;
1665 switch (spftree
->type
) {
1667 case SPF_TYPE_TI_LFA
:
1669 > area
->lfa_priority_limit
[level
- 1]) {
1672 "ISIS-LFA: skipping %s %s (low prefix priority)",
1681 case SPF_TYPE_FORWARD
:
1682 case SPF_TYPE_REVERSE
:
1686 switch (spftree
->type
) {
1688 isis_rlfa_check(spftree
, vertex
);
1690 case SPF_TYPE_TI_LFA
:
1691 if (isis_tilfa_check(spftree
, vertex
) != 0)
1694 pre_spftree
= spftree
->lfa
.old
.spftree
;
1695 route_table
= pre_spftree
->route_table_backup
;
1696 allow_ecmp
= area
->lfa_load_sharing
[level
- 1];
1697 pre_spftree
->lfa
.protection_counters
1698 .tilfa
[vertex
->N
.ip
.priority
] += 1;
1700 case SPF_TYPE_FORWARD
:
1701 case SPF_TYPE_REVERSE
:
1702 route_table
= spftree
->route_table
;
1706 * Update LFA protection counters (ignore local
1709 if (vertex
->depth
> 1) {
1710 spftree
->lfa
.protection_counters
1711 .total
[priority
] += 1;
1712 if (listcount(vertex
->Adj_N
) > 1)
1713 spftree
->lfa
.protection_counters
1714 .ecmp
[priority
] += 1;
1719 #ifdef EXTREME_DEBUG
1720 struct isis_route_info
*ri
=
1721 #endif /* EXTREME_DEBUG */
1722 isis_route_create(&vertex
->N
.ip
.p
.dest
,
1723 &vertex
->N
.ip
.p
.src
,
1724 vertex
->d_N
, vertex
->depth
,
1726 vertex
->Adj_N
, allow_ecmp
,
1729 #ifdef EXTREME_DEBUG
1731 "ISIS-SPF: A:%hhu create route pfx %pFX dist %d, sr.algo %d, table %p, rv %p",
1732 spftree
->algorithm
, &vertex
->N
.ip
.p
.dest
,
1733 vertex
->d_N
, vertex
->N
.ip
.sr
.algorithm
,
1735 #endif /* EXTREME_DEBUG */
1736 } else if (IS_DEBUG_SPF_EVENTS
)
1738 "ISIS-SPF: no adjacencies, do not install route for %s depth %d dist %d",
1739 vid2string(vertex
, buff
, sizeof(buff
)),
1740 vertex
->depth
, vertex
->d_N
);
1744 static void isis_spf_loop(struct isis_spftree
*spftree
,
1745 uint8_t *root_sysid
)
1747 struct isis_vertex
*vertex
;
1748 struct isis_lsp
*lsp
;
1749 struct listnode
*node
;
1751 while (isis_vertex_queue_count(&spftree
->tents
)) {
1752 vertex
= isis_vertex_queue_pop(&spftree
->tents
);
1754 #ifdef EXTREME_DEBUG
1756 "ISIS-SPF: A:%hhu get TENT node %s %s depth %d dist %d to PATHS",
1757 spftree
->algorithm
, print_sys_hostname(vertex
->N
.id
),
1758 vtype2string(vertex
->type
), vertex
->depth
, vertex
->d_N
);
1759 #endif /* EXTREME_DEBUG */
1761 add_to_paths(spftree
, vertex
);
1762 if (!VTYPE_IS(vertex
->type
))
1765 lsp
= lsp_for_vertex(spftree
, vertex
);
1767 zlog_warn("ISIS-SPF: No LSP found for %pPN",
1772 isis_spf_process_lsp(spftree
, lsp
, vertex
->d_N
, vertex
->depth
,
1773 root_sysid
, vertex
);
1776 /* Generate routes once the SPT is formed. */
1777 for (ALL_QUEUE_ELEMENTS_RO(&spftree
->paths
, node
, vertex
)) {
1778 /* New-style TLVs take precedence over the old-style TLVs. */
1779 switch (vertex
->type
) {
1780 case VTYPE_IPREACH_INTERNAL
:
1781 case VTYPE_IPREACH_EXTERNAL
:
1782 if (isis_find_vertex(&spftree
->paths
, &vertex
->N
,
1786 case VTYPE_PSEUDO_IS
:
1787 case VTYPE_PSEUDO_TE_IS
:
1788 case VTYPE_NONPSEUDO_IS
:
1789 case VTYPE_NONPSEUDO_TE_IS
:
1791 case VTYPE_IPREACH_TE
:
1792 case VTYPE_IP6REACH_INTERNAL
:
1793 case VTYPE_IP6REACH_EXTERNAL
:
1797 spf_path_process(spftree
, vertex
);
1801 struct isis_spftree
*isis_run_hopcount_spf(struct isis_area
*area
,
1803 struct isis_spftree
*spftree
)
1806 spftree
= isis_spftree_new(
1807 area
, &area
->lspdb
[IS_LEVEL_2
- 1], sysid
, ISIS_LEVEL2
,
1808 SPFTREE_IPV4
, SPF_TYPE_FORWARD
,
1809 F_SPFTREE_HOPCOUNT_METRIC
, SR_ALGORITHM_SPF
);
1811 init_spt(spftree
, ISIS_MT_IPV4_UNICAST
);
1812 if (!memcmp(sysid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
)) {
1813 struct isis_lsp
*root_lsp
;
1814 struct isis_vertex
*root_vertex
;
1816 root_lsp
= isis_root_system_lsp(spftree
->lspdb
, spftree
->sysid
);
1819 * If we are running locally, initialize with
1820 * information from adjacencies
1822 root_vertex
= isis_spf_add_root(spftree
);
1824 isis_spf_preload_tent(spftree
, sysid
, root_lsp
,
1828 isis_vertex_queue_insert(
1830 isis_vertex_new(spftree
, sysid
, VTYPE_NONPSEUDO_TE_IS
));
1833 isis_spf_loop(spftree
, sysid
);
1838 void isis_run_spf(struct isis_spftree
*spftree
)
1840 struct isis_lsp
*root_lsp
;
1841 struct isis_vertex
*root_vertex
;
1842 struct timeval time_start
;
1843 struct timeval time_end
;
1844 struct isis_mt_router_info
*mt_router_info
;
1847 /* Get time that can't roll backwards. */
1848 monotime(&time_start
);
1850 root_lsp
= isis_root_system_lsp(spftree
->lspdb
, spftree
->sysid
);
1851 if (root_lsp
== NULL
) {
1852 zlog_err("ISIS-SPF: could not find own l%d LSP!",
1857 /* Get Multi-Topology ID. */
1858 switch (spftree
->tree_id
) {
1860 mtid
= ISIS_MT_IPV4_UNICAST
;
1863 mt_router_info
= isis_tlvs_lookup_mt_router_info(
1864 root_lsp
->tlvs
, ISIS_MT_IPV6_UNICAST
);
1866 mtid
= ISIS_MT_IPV6_UNICAST
;
1868 mtid
= ISIS_MT_IPV4_UNICAST
;
1870 case SPFTREE_DSTSRC
:
1871 mtid
= ISIS_MT_IPV6_DSTSRC
;
1875 "%s should never be called with SPFTREE_COUNT as argument!",
1881 /* If a node is configured to participate in a particular Flexible-
1882 * Algorithm, but there is no valid Flex-Algorithm definition available
1883 * for it, or the selected Flex-Algorithm definition includes
1884 * calculation-type, metric-type, constraint, flag, or Sub-TLV that is
1885 * not supported by the node, it MUST stop participating in such
1886 * Flexible-Algorithm.
1888 if (flex_algo_id_valid(spftree
->algorithm
) &&
1889 !flex_algo_get_state(spftree
->area
->flex_algos
,
1890 spftree
->algorithm
)) {
1891 if (!CHECK_FLAG(spftree
->flags
, F_SPFTREE_DISABLED
)) {
1892 isis_spftree_clear(spftree
);
1893 SET_FLAG(spftree
->flags
, F_SPFTREE_DISABLED
);
1894 lsp_regenerate_schedule(spftree
->area
,
1895 spftree
->area
->is_type
, 0);
1899 #endif /* ifndef FABRICD */
1904 init_spt(spftree
, mtid
);
1906 root_vertex
= isis_spf_add_root(spftree
);
1908 isis_spf_build_adj_list(spftree
, root_lsp
);
1909 isis_spf_preload_tent(spftree
, spftree
->sysid
, root_lsp
, root_vertex
);
1914 if (!isis_vertex_queue_count(&spftree
->tents
)
1915 && (IS_DEBUG_SPF_EVENTS
)) {
1916 zlog_warn("ISIS-SPF: TENT is empty SPF-root:%s",
1917 print_sys_hostname(spftree
->sysid
));
1920 isis_spf_loop(spftree
, spftree
->sysid
);
1925 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_DISABLED
)) {
1926 UNSET_FLAG(spftree
->flags
, F_SPFTREE_DISABLED
);
1927 lsp_regenerate_schedule(spftree
->area
, spftree
->area
->is_type
,
1932 #endif /* ifndef FABRICD */
1933 spftree
->runcount
++;
1934 spftree
->last_run_timestamp
= time(NULL
);
1935 spftree
->last_run_monotime
= monotime(&time_end
);
1936 spftree
->last_run_duration
=
1937 ((time_end
.tv_sec
- time_start
.tv_sec
) * 1000000)
1938 + (time_end
.tv_usec
- time_start
.tv_usec
);
1941 static void isis_run_spf_with_protection(struct isis_area
*area
,
1942 struct isis_spftree
*spftree
)
1944 /* Run forward SPF locally. */
1945 memcpy(spftree
->sysid
, area
->isis
->sysid
, ISIS_SYS_ID_LEN
);
1946 isis_run_spf(spftree
);
1948 /* Run LFA protection if configured. */
1949 if (area
->lfa_protected_links
[spftree
->level
- 1] > 0
1950 || area
->tilfa_protected_links
[spftree
->level
- 1] > 0)
1951 isis_spf_run_lfa(area
, spftree
);
1954 void isis_spf_verify_routes(struct isis_area
*area
, struct isis_spftree
**trees
,
1957 if (area
->is_type
== IS_LEVEL_1
) {
1958 isis_route_verify_table(area
, trees
[0]->route_table
,
1959 trees
[0]->route_table_backup
, tree
);
1960 } else if (area
->is_type
== IS_LEVEL_2
) {
1961 isis_route_verify_table(area
, trees
[1]->route_table
,
1962 trees
[1]->route_table_backup
, tree
);
1964 isis_route_verify_merge(area
, trees
[0]->route_table
,
1965 trees
[0]->route_table_backup
,
1966 trees
[1]->route_table
,
1967 trees
[1]->route_table_backup
, tree
);
1971 void isis_spf_invalidate_routes(struct isis_spftree
*tree
)
1973 struct isis_route_table_info
*backup_info
;
1975 isis_route_invalidate_table(tree
->area
, tree
->route_table
);
1977 /* Delete backup routes. */
1979 backup_info
= tree
->route_table_backup
->info
;
1980 route_table_finish(tree
->route_table_backup
);
1981 isis_route_table_info_free(backup_info
);
1982 tree
->route_table_backup
= srcdest_table_init();
1983 tree
->route_table_backup
->info
=
1984 isis_route_table_info_alloc(tree
->algorithm
);
1985 tree
->route_table_backup
->cleanup
= isis_route_node_cleanup
;
1988 void isis_spf_switchover_routes(struct isis_area
*area
,
1989 struct isis_spftree
**trees
, int family
,
1990 union g_addr
*nexthop_ip
, ifindex_t ifindex
,
1993 isis_route_switchover_nexthop(area
, trees
[level
- 1]->route_table
,
1994 family
, nexthop_ip
, ifindex
);
1997 static void isis_run_spf_cb(struct event
*thread
)
1999 struct isis_spf_run
*run
= EVENT_ARG(thread
);
2000 struct isis_area
*area
= run
->area
;
2001 int level
= run
->level
;
2003 struct listnode
*node
;
2004 struct isis_circuit
*circuit
;
2006 struct flex_algo
*fa
;
2007 struct isis_flex_algo_data
*data
;
2008 #endif /* ifndef FABRICD */
2010 XFREE(MTYPE_ISIS_SPF_RUN
, run
);
2012 if (!(area
->is_type
& level
)) {
2013 if (IS_DEBUG_SPF_EVENTS
)
2014 zlog_warn("ISIS-SPF (%s) area does not share level",
2019 isis_area_delete_backup_adj_sids(area
, level
);
2020 isis_area_invalidate_routes(area
, level
);
2022 if (IS_DEBUG_SPF_EVENTS
)
2023 zlog_debug("ISIS-SPF (%s) L%d SPF needed, periodic SPF",
2024 area
->area_tag
, level
);
2026 if (area
->ip_circuits
) {
2027 isis_run_spf_with_protection(
2028 area
, area
->spftree
[SPFTREE_IPV4
][level
- 1]);
2030 for (ALL_LIST_ELEMENTS_RO(area
->flex_algos
->flex_algos
, node
,
2033 isis_run_spf_with_protection(
2034 area
, data
->spftree
[SPFTREE_IPV4
][level
- 1]);
2036 #endif /* ifndef FABRICD */
2039 if (area
->ipv6_circuits
) {
2040 isis_run_spf_with_protection(
2041 area
, area
->spftree
[SPFTREE_IPV6
][level
- 1]);
2043 for (ALL_LIST_ELEMENTS_RO(area
->flex_algos
->flex_algos
, node
,
2046 isis_run_spf_with_protection(
2047 area
, data
->spftree
[SPFTREE_IPV6
][level
- 1]);
2049 #endif /* ifndef FABRICD */
2052 if (area
->ipv6_circuits
&& isis_area_ipv6_dstsrc_enabled(area
)) {
2053 isis_run_spf_with_protection(
2054 area
, area
->spftree
[SPFTREE_DSTSRC
][level
- 1]);
2059 area
->spf_run_count
[level
]++;
2061 isis_area_verify_routes(area
);
2063 /* walk all circuits and reset any spf specific flags */
2064 for (ALL_LIST_ELEMENTS_RO(area
->circuit_list
, node
, circuit
))
2065 UNSET_FLAG(circuit
->flags
, ISIS_CIRCUIT_FLAPPED_AFTER_SPF
);
2067 fabricd_run_spf(area
);
2070 static struct isis_spf_run
*isis_run_spf_arg(struct isis_area
*area
, int level
)
2072 struct isis_spf_run
*run
= XMALLOC(MTYPE_ISIS_SPF_RUN
, sizeof(*run
));
2080 void isis_spf_timer_free(void *run
)
2082 XFREE(MTYPE_ISIS_SPF_RUN
, run
);
2085 int _isis_spf_schedule(struct isis_area
*area
, int level
,
2086 const char *func
, const char *file
, int line
)
2088 struct isis_spftree
*spftree
;
2090 long tree_diff
, diff
;
2093 now
= monotime(NULL
);
2095 for (tree
= SPFTREE_IPV4
; tree
< SPFTREE_COUNT
; tree
++) {
2096 spftree
= area
->spftree
[tree
][level
- 1];
2097 tree_diff
= difftime(now
- spftree
->last_run_monotime
, 0);
2098 if (tree_diff
!= now
&& (diff
== 0 || tree_diff
< diff
))
2102 if (CHECK_FLAG(im
->options
, F_ISIS_UNIT_TEST
))
2106 assert(area
->is_type
& level
);
2108 if (IS_DEBUG_SPF_EVENTS
) {
2110 "ISIS-SPF (%s) L%d SPF schedule called, lastrun %ld sec ago Caller: %s %s:%d",
2111 area
->area_tag
, level
, diff
, func
, file
, line
);
2114 EVENT_OFF(area
->t_rlfa_rib_update
);
2115 if (area
->spf_delay_ietf
[level
- 1]) {
2116 /* Need to call schedule function also if spf delay is running
2118 * restart holdoff timer - compare
2119 * draft-ietf-rtgwg-backoff-algo-04 */
2121 spf_backoff_schedule(area
->spf_delay_ietf
[level
- 1]);
2122 if (area
->spf_timer
[level
- 1])
2125 event_add_timer_msec(master
, isis_run_spf_cb
,
2126 isis_run_spf_arg(area
, level
), delay
,
2127 &area
->spf_timer
[level
- 1]);
2131 if (area
->spf_timer
[level
- 1])
2134 /* wait configured min_spf_interval before doing the SPF */
2136 if (diff
>= area
->min_spf_interval
[level
- 1]
2137 || area
->bfd_force_spf_refresh
) {
2139 * Last run is more than min interval ago or BFD signalled a
2140 * 'down' message, schedule immediate run
2144 if (area
->bfd_force_spf_refresh
) {
2146 "ISIS-SPF (%s) L%d SPF scheduled immediately due to BFD 'down' message",
2147 area
->area_tag
, level
);
2148 area
->bfd_force_spf_refresh
= false;
2151 timer
= area
->min_spf_interval
[level
- 1] - diff
;
2154 event_add_timer(master
, isis_run_spf_cb
, isis_run_spf_arg(area
, level
),
2155 timer
, &area
->spf_timer
[level
- 1]);
2157 if (IS_DEBUG_SPF_EVENTS
)
2158 zlog_debug("ISIS-SPF (%s) L%d SPF scheduled %ld sec from now",
2159 area
->area_tag
, level
, timer
);
2164 static void isis_print_paths(struct vty
*vty
, struct isis_vertex_queue
*queue
,
2165 uint8_t *root_sysid
)
2167 struct listnode
*node
;
2168 struct isis_vertex
*vertex
;
2169 char buff
[VID2STR_BUFFER
];
2172 "Vertex Type Metric Next-Hop Interface Parent\n");
2174 for (ALL_QUEUE_ELEMENTS_RO(queue
, node
, vertex
)) {
2175 if (VTYPE_IS(vertex
->type
)
2176 && memcmp(vertex
->N
.id
, root_sysid
, ISIS_SYS_ID_LEN
) == 0) {
2177 vty_out(vty
, "%-20s %-12s %-6s",
2178 print_sys_hostname(root_sysid
), "", "");
2179 vty_out(vty
, "%-30s\n", "");
2184 struct listnode
*anode
= listhead(vertex
->Adj_N
);
2185 struct listnode
*pnode
= listhead(vertex
->parents
);
2186 struct isis_vertex_adj
*vadj
;
2187 struct isis_vertex
*pvertex
;
2189 vty_out(vty
, "%-20s %-12s %-6u ",
2190 vid2string(vertex
, buff
, sizeof(buff
)),
2191 vtype2string(vertex
->type
), vertex
->d_N
);
2192 for (unsigned int i
= 0;
2193 i
< MAX(vertex
->Adj_N
? listcount(vertex
->Adj_N
) : 0,
2194 vertex
->parents
? listcount(vertex
->parents
) : 0);
2197 vadj
= listgetdata(anode
);
2198 anode
= anode
->next
;
2204 pvertex
= listgetdata(pnode
);
2205 pnode
= pnode
->next
;
2212 vty_out(vty
, "%-20s %-12s %-6s ", "", "", "");
2216 struct isis_spf_adj
*sadj
= vadj
->sadj
;
2218 vty_out(vty
, "%-20s %-9s ",
2219 print_sys_hostname(sadj
->id
),
2220 sadj
->adj
? sadj
->adj
->circuit
2227 vty_out(vty
, "%-20s %-9s ", "", "");
2229 vty_out(vty
, "%s(%d)",
2230 vid2string(pvertex
, buff
, sizeof(buff
)),
2240 void isis_print_spftree(struct vty
*vty
, struct isis_spftree
*spftree
)
2242 const char *tree_id_text
= NULL
;
2244 if (!spftree
|| !isis_vertex_queue_count(&spftree
->paths
))
2247 switch (spftree
->tree_id
) {
2249 tree_id_text
= "that speak IP";
2252 tree_id_text
= "that speak IPv6";
2254 case SPFTREE_DSTSRC
:
2255 tree_id_text
= "that support IPv6 dst-src routing";
2258 assert(!"isis_print_spftree shouldn't be called with SPFTREE_COUNT as type");
2262 vty_out(vty
, "IS-IS paths to level-%d routers %s\n", spftree
->level
,
2264 isis_print_paths(vty
, &spftree
->paths
, spftree
->sysid
);
2268 static void show_isis_topology_common(struct vty
*vty
, int levels
,
2269 struct isis
*isis
, uint8_t algo
)
2272 struct isis_flex_algo_data
*fa_data
;
2273 struct flex_algo
*fa
;
2274 #endif /* ifndef FABRICD */
2275 struct isis_spftree
*spftree
;
2276 struct listnode
*node
;
2277 struct isis_area
*area
;
2279 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
2282 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2284 "Area %s:", area
->area_tag
? area
->area_tag
: "null");
2288 * The shapes of the flex algo spftree 2-dimensional array
2289 * and the area spftree 2-dimensional array are not guaranteed
2293 if (flex_algo_id_valid(algo
)) {
2294 fa
= flex_algo_lookup(area
->flex_algos
, algo
);
2297 fa_data
= (struct isis_flex_algo_data
*)fa
->data
;
2301 if (algo
!= SR_ALGORITHM_SPF
)
2302 vty_out(vty
, " Algorithm %hhu\n", algo
);
2304 #endif /* ifndef FABRICD */
2307 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2308 if ((level
& levels
) == 0)
2311 if (area
->ip_circuits
> 0) {
2314 spftree
= fa_data
->spftree
[SPFTREE_IPV4
]
2317 #endif /* ifndef FABRICD */
2318 spftree
= area
->spftree
[SPFTREE_IPV4
]
2321 isis_print_spftree(vty
, spftree
);
2323 if (area
->ipv6_circuits
> 0) {
2326 spftree
= fa_data
->spftree
[SPFTREE_IPV6
]
2329 #endif /* ifndef FABRICD */
2330 spftree
= area
->spftree
[SPFTREE_IPV6
]
2332 isis_print_spftree(vty
, spftree
);
2334 if (isis_area_ipv6_dstsrc_enabled(area
)) {
2338 fa_data
->spftree
[SPFTREE_DSTSRC
]
2341 #endif /* ifndef FABRICD */
2342 spftree
= area
->spftree
[SPFTREE_DSTSRC
]
2344 isis_print_spftree(vty
, spftree
);
2348 if (fabricd_spftree(area
)) {
2350 "IS-IS paths to level-2 routers with hop-by-hop metric\n");
2351 isis_print_paths(vty
, &fabricd_spftree(area
)->paths
, isis
->sysid
);
2359 DEFUN(show_isis_topology
, show_isis_topology_cmd
,
2361 " [vrf <NAME|all>] topology"
2363 " [<level-1|level-2>]"
2364 " [algorithm (128-255)]"
2365 #endif /* ifndef FABRICD */
2367 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
2369 "IS-IS paths to Intermediate Systems\n"
2371 "Paths to all level-1 routers in the area\n"
2372 "Paths to all level-2 routers in the domain\n"
2373 "Show Flex-algo routes\n"
2374 "Algorithm number\n"
2375 #endif /* ifndef FABRICD */
2378 int levels
= ISIS_LEVELS
;
2379 struct listnode
*node
;
2380 struct isis
*isis
= NULL
;
2381 const char *vrf_name
= VRF_DEFAULT_NAME
;
2382 bool all_vrf
= false;
2384 uint8_t algorithm
= SR_ALGORITHM_SPF
;
2388 levels
= ISIS_LEVEL1
| ISIS_LEVEL2
;
2389 if (argv_find(argv
, argc
, "level-1", &idx
))
2390 levels
= ISIS_LEVEL1
;
2391 if (argv_find(argv
, argc
, "level-2", &idx
))
2392 levels
= ISIS_LEVEL2
;
2393 if (argv_find(argv
, argc
, "algorithm", &idx
))
2394 algorithm
= (uint8_t)strtoul(argv
[idx
+ 1]->arg
, NULL
, 10);
2395 #endif /* ifndef FABRICD */
2398 vty_out(vty
, "IS-IS Routing Process not enabled\n");
2401 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2405 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
))
2406 show_isis_topology_common(vty
, levels
, isis
,
2410 isis
= isis_lookup_by_vrfname(vrf_name
);
2412 show_isis_topology_common(vty
, levels
, isis
, algorithm
);
2419 static void show_isis_flex_algo_display_eag(struct vty
*vty
, char *buf
,
2421 struct admin_group
*admin_group
)
2423 if (admin_group_zero(admin_group
))
2424 vty_out(vty
, "not-set\n");
2426 vty_out(vty
, "%s\n",
2427 admin_group_string(buf
, ADMIN_GROUP_PRINT_MAX_SIZE
,
2428 indent
, admin_group
));
2429 admin_group_print(buf
, indent
, admin_group
);
2431 vty_out(vty
, " Bit positions: %s\n", buf
);
2435 static void show_isis_flex_algo_common(struct vty
*vty
, struct isis
*isis
,
2438 struct isis_router_cap_fad
*router_fad
;
2439 char buf
[ADMIN_GROUP_PRINT_MAX_SIZE
];
2440 struct admin_group
*admin_group
;
2441 struct isis_area
*area
;
2442 struct listnode
*node
;
2443 struct flex_algo
*fa
;
2445 bool fad_identical
, fad_supported
;
2447 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
2450 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2452 * The shapes of the flex algo spftree 2-dimensional array
2453 * and the area spftree 2-dimensional array are not guaranteed
2457 for (algo
= 0; algo
< SR_ALGORITHM_COUNT
; algo
++) {
2458 if (algorithm
!= SR_ALGORITHM_UNSET
&&
2462 fa
= flex_algo_lookup(area
->flex_algos
, algo
);
2466 vty_out(vty
, "Area %s:",
2467 area
->area_tag
? area
->area_tag
: "null");
2469 vty_out(vty
, " Algorithm %d\n", algo
);
2472 vty_out(vty
, " Enabled Data-Planes:");
2473 if (fa
->dataplanes
== 0) {
2474 vty_out(vty
, " None\n\n");
2477 if (CHECK_FLAG(fa
->dataplanes
, FLEX_ALGO_SR_MPLS
))
2478 vty_out(vty
, " SR-MPLS");
2479 if (CHECK_FLAG(fa
->dataplanes
, FLEX_ALGO_SRV6
))
2480 vty_out(vty
, " SRv6");
2481 if (CHECK_FLAG(fa
->dataplanes
, FLEX_ALGO_IP
))
2482 vty_out(vty
, " IP");
2483 vty_out(vty
, "\n\n");
2486 router_fad
= isis_flex_algo_elected(algo
, area
);
2488 " Elected and running Flexible-Algorithm Definition:\n");
2490 vty_out(vty
, " Source: %pSY\n",
2493 vty_out(vty
, " Source: Not found\n");
2501 flex_algo_definition_cmp(fa
, &router_fad
->fad
);
2503 isis_flex_algo_supported(&router_fad
->fad
);
2504 vty_out(vty
, " Priority: %d\n",
2505 router_fad
->fad
.priority
);
2506 vty_out(vty
, " Equal to local: %s\n",
2507 fad_identical
? "yes" : "no");
2508 vty_out(vty
, " Local state: %s\n",
2511 : "disabled (unsupported definition)");
2512 vty_out(vty
, " Calculation type: ");
2513 if (router_fad
->fad
.calc_type
== 0)
2514 vty_out(vty
, "spf\n");
2516 vty_out(vty
, "%d\n", router_fad
->fad
.calc_type
);
2517 vty_out(vty
, " Metric type: %s\n",
2518 flex_algo_metric_type_print(
2520 router_fad
->fad
.metric_type
));
2521 vty_out(vty
, " Prefix-metric: %s\n",
2522 CHECK_FLAG(router_fad
->fad
.flags
, FAD_FLAG_M
)
2525 if (router_fad
->fad
.flags
!= 0 &&
2526 router_fad
->fad
.flags
!= FAD_FLAG_M
)
2527 vty_out(vty
, " Flags: 0x%x\n",
2528 router_fad
->fad
.flags
);
2529 vty_out(vty
, " Exclude SRLG: %s\n",
2530 router_fad
->fad
.exclude_srlg
? "enabled"
2533 admin_group
= &router_fad
->fad
.admin_group_exclude_any
;
2534 indent
= vty_out(vty
, " Exclude-any admin-group: ");
2535 show_isis_flex_algo_display_eag(vty
, buf
, indent
,
2538 admin_group
= &router_fad
->fad
.admin_group_include_all
;
2539 indent
= vty_out(vty
, " Include-all admin-group: ");
2540 show_isis_flex_algo_display_eag(vty
, buf
, indent
,
2543 admin_group
= &router_fad
->fad
.admin_group_include_any
;
2544 indent
= vty_out(vty
, " Include-any admin-group: ");
2545 show_isis_flex_algo_display_eag(vty
, buf
, indent
,
2548 if (router_fad
->fad
.unsupported_subtlv
)
2550 " Unsupported sub-TLV: Present (see logs)");
2557 DEFUN(show_isis_flex_algo
, show_isis_flex_algo_cmd
,
2559 " [vrf <NAME|all>] flex-algo"
2561 SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
2563 "IS-IS Flex-algo information\n"
2564 "Algorithm number\n")
2567 struct listnode
*node
;
2568 const char *vrf_name
= VRF_DEFAULT_NAME
;
2569 bool all_vrf
= false;
2575 vty_out(vty
, "IS-IS Routing Process not enabled\n");
2579 if (argv_find(argv
, argc
, "flex-algo", &idx
) && (idx
+ 1) < argc
)
2580 flex_algo
= (uint8_t)strtoul(argv
[idx
+ 1]->arg
, NULL
, 10);
2582 flex_algo
= SR_ALGORITHM_UNSET
;
2584 ISIS_FIND_VRF_ARGS(argv
, argc
, idx_vrf
, vrf_name
, all_vrf
);
2588 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
))
2589 show_isis_flex_algo_common(vty
, isis
,
2593 isis
= isis_lookup_by_vrfname(vrf_name
);
2595 show_isis_flex_algo_common(vty
, isis
, flex_algo
);
2600 #endif /* ifndef FABRICD */
2602 static void isis_print_route(struct ttable
*tt
, const struct prefix
*prefix
,
2603 struct isis_route_info
*rinfo
, bool prefix_sid
,
2604 bool no_adjacencies
, bool json
)
2606 struct isis_nexthop
*nexthop
;
2607 struct listnode
*node
;
2609 char buf_prefix
[BUFSIZ
];
2611 (void)prefix2str(prefix
, buf_prefix
, sizeof(buf_prefix
));
2612 for (int alg
= 0; alg
< SR_ALGORITHM_COUNT
; alg
++) {
2613 for (ALL_LIST_ELEMENTS_RO(rinfo
->sr_algo
[alg
].nexthops
, node
,
2615 struct interface
*ifp
;
2616 char buf_iface
[BUFSIZ
];
2617 char buf_nhop
[BUFSIZ
];
2619 if (!no_adjacencies
) {
2620 inet_ntop(nexthop
->family
, &nexthop
->ip
,
2621 buf_nhop
, sizeof(buf_nhop
));
2622 ifp
= if_lookup_by_index(nexthop
->ifindex
,
2625 strlcpy(buf_iface
, ifp
->name
,
2628 snprintf(buf_iface
, sizeof(buf_iface
),
2633 print_sys_hostname(nexthop
->sysid
),
2635 strlcpy(buf_iface
, "-", sizeof(buf_iface
));
2639 char buf_sid
[BUFSIZ
] = {};
2640 char buf_lblop
[BUFSIZ
] = {};
2642 if (rinfo
->sr_algo
[alg
].present
) {
2643 snprintf(buf_sid
, sizeof(buf_sid
), "%u",
2644 rinfo
->sr_algo
[alg
].sid
.value
);
2645 sr_op2str(buf_lblop
, sizeof(buf_lblop
),
2646 rinfo
->sr_algo
[alg
].label
,
2648 } else if (alg
== SR_ALGORITHM_SPF
) {
2649 strlcpy(buf_sid
, "-", sizeof(buf_sid
));
2650 strlcpy(buf_lblop
, "-",
2656 if (first
|| json
) {
2658 "%s|%u|%s|%s|%s|%s|%d",
2659 buf_prefix
, rinfo
->cost
,
2660 buf_iface
, buf_nhop
,
2661 buf_sid
, buf_lblop
, alg
);
2664 ttable_add_row(tt
, "||%s|%s|%s|%s|%d",
2665 buf_iface
, buf_nhop
,
2666 buf_sid
, buf_lblop
, alg
);
2668 char buf_labels
[BUFSIZ
] = {};
2670 if (nexthop
->label_stack
) {
2673 nexthop
->label_stack
->num_labels
;
2675 char buf_label
[BUFSIZ
];
2677 label2str(nexthop
->label_stack
2682 strlcat(buf_labels
, "/",
2683 sizeof(buf_labels
));
2684 strlcat(buf_labels
, buf_label
,
2685 sizeof(buf_labels
));
2687 } else if (nexthop
->sr
.present
)
2688 label2str(nexthop
->sr
.label
, 0,
2690 sizeof(buf_labels
));
2692 strlcpy(buf_labels
, "-",
2693 sizeof(buf_labels
));
2695 if (first
|| json
) {
2696 ttable_add_row(tt
, "%s|%u|%s|%s|%s",
2697 buf_prefix
, rinfo
->cost
,
2698 buf_iface
, buf_nhop
,
2702 ttable_add_row(tt
, "||%s|%s|%s",
2703 buf_iface
, buf_nhop
,
2709 if (list_isempty(rinfo
->nexthops
)) {
2711 char buf_sid
[BUFSIZ
] = {};
2712 char buf_lblop
[BUFSIZ
] = {};
2714 if (rinfo
->sr_algo
[SR_ALGORITHM_SPF
].present
) {
2715 snprintf(buf_sid
, sizeof(buf_sid
), "%u",
2716 rinfo
->sr_algo
[SR_ALGORITHM_SPF
]
2719 buf_lblop
, sizeof(buf_lblop
),
2720 rinfo
->sr_algo
[SR_ALGORITHM_SPF
].label
,
2721 MPLS_LABEL_IMPLICIT_NULL
);
2723 strlcpy(buf_sid
, "-", sizeof(buf_sid
));
2724 strlcpy(buf_lblop
, "-", sizeof(buf_lblop
));
2727 ttable_add_row(tt
, "%s|%u|%s|%s|%s|%s", buf_prefix
,
2728 rinfo
->cost
, "-", "-", buf_sid
,
2731 ttable_add_row(tt
, "%s|%u|%s|%s|%s", buf_prefix
,
2732 rinfo
->cost
, "-", "-", "-");
2736 void isis_print_routes(struct vty
*vty
, struct isis_spftree
*spftree
,
2737 struct json_object
**json
, bool prefix_sid
, bool backup
)
2739 struct route_table
*route_table
;
2741 struct route_node
*rn
;
2742 bool no_adjacencies
= false;
2743 const char *tree_id_text
= NULL
;
2748 switch (spftree
->tree_id
) {
2750 tree_id_text
= "IPv4";
2753 tree_id_text
= "IPv6";
2755 case SPFTREE_DSTSRC
:
2756 tree_id_text
= "IPv6 (dst-src routing)";
2759 assert(!"isis_print_routes shouldn't be called with SPFTREE_COUNT as type");
2764 vty_out(vty
, "IS-IS %s %s routing table:\n\n",
2765 circuit_t2string(spftree
->level
), tree_id_text
);
2767 /* Prepare table. */
2768 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
2772 "Prefix|Metric|Interface|Nexthop|SID|Label Op.|Algo");
2774 ttable_add_row(tt
, "Prefix|Metric|Interface|Nexthop|Label(s)");
2775 tt
->style
.cell
.rpad
= 2;
2776 tt
->style
.corner
= '+';
2778 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
2780 if (CHECK_FLAG(spftree
->flags
, F_SPFTREE_NO_ADJACENCIES
))
2781 no_adjacencies
= true;
2784 (backup
) ? spftree
->route_table_backup
: spftree
->route_table
;
2785 for (rn
= route_top(route_table
); rn
; rn
= route_next(rn
)) {
2786 struct isis_route_info
*rinfo
;
2792 isis_print_route(tt
, &rn
->p
, rinfo
, prefix_sid
, no_adjacencies
,
2796 /* Dump the generated table. */
2797 if (json
== NULL
&& tt
->nrows
> 1) {
2800 table
= ttable_dump(tt
, "\n");
2801 vty_out(vty
, "%s\n", table
);
2802 XFREE(MTYPE_TMP
, table
);
2804 *json
= ttable_json(tt
, prefix_sid
? "sdssdsdd" : "sdsss");
2809 static void show_isis_route_common(struct vty
*vty
, int levels
,
2810 struct isis
*isis
, bool prefix_sid
,
2811 bool backup
, uint8_t algo
,
2814 json_object
*json_level
= NULL
, *jstr
= NULL
, *json_val
;
2816 struct isis_flex_algo_data
*fa_data
;
2817 struct flex_algo
*fa
;
2818 #endif /* ifndef FABRICD */
2819 struct isis_spftree
*spftree
;
2820 struct listnode
*node
;
2821 struct isis_area
*area
;
2824 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
2828 *json
= json_object_new_object();
2830 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
2833 * The shapes of the flex algo spftree 2-dimensional array
2834 * and the area spftree 2-dimensional array are not guaranteed
2838 if (flex_algo_id_valid(algo
)) {
2839 fa
= flex_algo_lookup(area
->flex_algos
, algo
);
2842 fa_data
= (struct isis_flex_algo_data
*)fa
->data
;
2846 #endif /* ifndef FABRICD */
2849 jstr
= json_object_new_string(
2850 area
->area_tag
? area
->area_tag
: "null");
2851 json_object_object_add(*json
, "area", jstr
);
2853 vty_out(vty
, "Area %s:",
2854 area
->area_tag
? area
->area_tag
: "null");
2856 if (algo
!= SR_ALGORITHM_SPF
)
2857 vty_out(vty
, " Algorithm %hhu\n", algo
);
2859 #endif /* ifndef FABRICD */
2863 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
2864 if ((level
& levels
) == 0)
2868 json_level
= json_object_new_object();
2869 jstr
= json_object_new_string(
2870 area
->area_tag
? area
->area_tag
2872 json_object_object_add(json_level
, "area",
2876 if (area
->ip_circuits
> 0) {
2880 spftree
= fa_data
->spftree
[SPFTREE_IPV4
]
2883 #endif /* ifndef FABRICD */
2884 spftree
= area
->spftree
[SPFTREE_IPV4
]
2888 isis_print_spftree(vty
, spftree
);
2890 isis_print_routes(vty
, spftree
,
2891 json
? &json_val
: NULL
,
2892 prefix_sid
, backup
);
2893 if (json
&& json_val
) {
2894 json_object_object_add(
2895 json_level
, "ipv4", json_val
);
2898 if (area
->ipv6_circuits
> 0) {
2902 spftree
= fa_data
->spftree
[SPFTREE_IPV6
]
2905 #endif /* ifndef FABRICD */
2906 spftree
= area
->spftree
[SPFTREE_IPV6
]
2910 isis_print_spftree(vty
, spftree
);
2912 isis_print_routes(vty
, spftree
,
2913 json
? &json_val
: NULL
,
2914 prefix_sid
, backup
);
2915 if (json
&& json_val
) {
2916 json_object_object_add(
2917 json_level
, "ipv6", json_val
);
2920 if (isis_area_ipv6_dstsrc_enabled(area
)) {
2925 fa_data
->spftree
[SPFTREE_DSTSRC
]
2928 #endif /* ifndef FABRICD */
2929 spftree
= area
->spftree
[SPFTREE_DSTSRC
]
2933 isis_print_spftree(vty
, spftree
);
2934 isis_print_routes(vty
, spftree
,
2935 json
? &json_val
: NULL
,
2936 prefix_sid
, backup
);
2937 if (json
&& json_val
) {
2938 json_object_object_add(json_level
,
2944 snprintf(key
, sizeof(key
), "level-%d", level
);
2945 json_object_object_add(*json
, key
, json_level
);
2951 DEFUN(show_isis_route
, show_isis_route_cmd
,
2953 " [vrf <NAME|all>] route"
2955 " [<level-1|level-2>]"
2956 #endif /* ifndef FABRICD */
2957 " [<prefix-sid|backup>]"
2959 " [algorithm (128-255)]"
2960 #endif /* ifndef FABRICD */
2962 SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
2963 "IS-IS routing table\n"
2967 #endif /* ifndef FABRICD */
2968 "Show Prefix-SID information\n"
2969 "Show backup routes\n"
2971 "Show Flex-algo routes\n"
2972 "Algorithm number\n"
2973 #endif /* ifndef FABRICD */
2978 struct listnode
*node
;
2979 const char *vrf_name
= VRF_DEFAULT_NAME
;
2980 bool all_vrf
= false;
2981 bool prefix_sid
= false;
2982 bool backup
= false;
2983 bool uj
= use_json(argc
, argv
);
2985 json_object
*json
= NULL
, *json_vrf
= NULL
;
2986 uint8_t algorithm
= SR_ALGORITHM_SPF
;
2988 if (argv_find(argv
, argc
, "level-1", &idx
))
2989 levels
= ISIS_LEVEL1
;
2990 else if (argv_find(argv
, argc
, "level-2", &idx
))
2991 levels
= ISIS_LEVEL2
;
2993 levels
= ISIS_LEVEL1
| ISIS_LEVEL2
;
2996 vty_out(vty
, "IS-IS Routing Process not enabled\n");
2999 ISIS_FIND_VRF_ARGS(argv
, argc
, idx
, vrf_name
, all_vrf
);
3001 if (argv_find(argv
, argc
, "prefix-sid", &idx
))
3003 if (argv_find(argv
, argc
, "backup", &idx
))
3007 if (argv_find(argv
, argc
, "algorithm", &idx
))
3008 algorithm
= (uint8_t)strtoul(argv
[idx
+ 1]->arg
, NULL
, 10);
3009 #endif /* ifndef FABRICD */
3012 json
= json_object_new_array();
3016 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
3017 show_isis_route_common(
3018 vty
, levels
, isis
, prefix_sid
, backup
,
3019 algorithm
, uj
? &json_vrf
: NULL
);
3021 json_object_object_add(
3023 json_object_new_int(
3025 json_object_array_add(json
, json_vrf
);
3030 isis
= isis_lookup_by_vrfname(vrf_name
);
3032 show_isis_route_common(vty
, levels
, isis
, prefix_sid
,
3034 uj
? &json_vrf
: NULL
);
3036 json_object_object_add(
3038 json_object_new_int(isis
->vrf_id
));
3039 json_object_array_add(json
, json_vrf
);
3046 vty_out(vty
, "%s\n",
3047 json_object_to_json_string_ext(
3048 json
, JSON_C_TO_STRING_PRETTY
));
3049 json_object_free(json
);
3055 static void isis_print_frr_summary_line(struct ttable
*tt
,
3056 const char *protection
,
3057 uint32_t counters
[SPF_PREFIX_PRIO_MAX
])
3059 uint32_t critical
, high
, medium
, low
, total
;
3061 critical
= counters
[SPF_PREFIX_PRIO_CRITICAL
];
3062 high
= counters
[SPF_PREFIX_PRIO_HIGH
];
3063 medium
= counters
[SPF_PREFIX_PRIO_MEDIUM
];
3064 low
= counters
[SPF_PREFIX_PRIO_LOW
];
3065 total
= critical
+ high
+ medium
+ low
;
3067 ttable_add_row(tt
, "%s|%u|%u|%u|%u|%u", protection
, critical
, high
,
3068 medium
, low
, total
);
3072 isis_print_frr_summary_line_coverage(struct ttable
*tt
, const char *protection
,
3073 double counters
[SPF_PREFIX_PRIO_MAX
],
3076 double critical
, high
, medium
, low
;
3078 critical
= counters
[SPF_PREFIX_PRIO_CRITICAL
] * 100;
3079 high
= counters
[SPF_PREFIX_PRIO_HIGH
] * 100;
3080 medium
= counters
[SPF_PREFIX_PRIO_MEDIUM
] * 100;
3081 low
= counters
[SPF_PREFIX_PRIO_LOW
] * 100;
3084 ttable_add_row(tt
, "%s|%.2f%%|%.2f%%|%.2f%%|%.2f%%|%.2f%%", protection
,
3085 critical
, high
, medium
, low
, total
);
3088 static void isis_print_frr_summary(struct vty
*vty
,
3089 struct isis_spftree
*spftree
)
3093 const char *tree_id_text
= NULL
;
3094 uint32_t protectd
[SPF_PREFIX_PRIO_MAX
] = {0};
3095 uint32_t unprotected
[SPF_PREFIX_PRIO_MAX
] = {0};
3096 double coverage
[SPF_PREFIX_PRIO_MAX
] = {0};
3097 uint32_t protected_total
= 0, grand_total
= 0;
3098 double coverage_total
;
3103 switch (spftree
->tree_id
) {
3105 tree_id_text
= "IPv4";
3108 tree_id_text
= "IPv6";
3110 case SPFTREE_DSTSRC
:
3111 tree_id_text
= "IPv6 (dst-src routing)";
3114 assert(!"isis_print_frr_summary shouldn't be called with SPFTREE_COUNT as type");
3118 vty_out(vty
, " IS-IS %s %s Fast ReRoute summary:\n\n",
3119 circuit_t2string(spftree
->level
), tree_id_text
);
3121 /* Prepare table. */
3122 tt
= ttable_new(&ttable_styles
[TTSTYLE_BLANK
]);
3125 "Protection \\ Priority|Critical|High |Medium |Low |Total");
3126 tt
->style
.cell
.rpad
= 2;
3127 tt
->style
.corner
= '+';
3129 ttable_rowseps(tt
, 0, BOTTOM
, true, '-');
3131 /* Compute unprotected and coverage totals. */
3132 for (int priority
= SPF_PREFIX_PRIO_CRITICAL
;
3133 priority
< SPF_PREFIX_PRIO_MAX
; priority
++) {
3134 uint32_t *lfa
= spftree
->lfa
.protection_counters
.lfa
;
3135 uint32_t *rlfa
= spftree
->lfa
.protection_counters
.rlfa
;
3136 uint32_t *tilfa
= spftree
->lfa
.protection_counters
.tilfa
;
3137 uint32_t *ecmp
= spftree
->lfa
.protection_counters
.ecmp
;
3138 uint32_t *total
= spftree
->lfa
.protection_counters
.total
;
3140 protectd
[priority
] = lfa
[priority
] + rlfa
[priority
]
3141 + tilfa
[priority
] + ecmp
[priority
];
3142 /* Safeguard to protect against possible inconsistencies. */
3143 if (protectd
[priority
] > total
[priority
])
3144 protectd
[priority
] = total
[priority
];
3145 unprotected
[priority
] = total
[priority
] - protectd
[priority
];
3146 protected_total
+= protectd
[priority
];
3147 grand_total
+= total
[priority
];
3149 if (!total
[priority
])
3150 coverage
[priority
] = 0;
3152 coverage
[priority
] =
3153 protectd
[priority
] / (double)total
[priority
];
3159 coverage_total
= protected_total
/ (double)grand_total
;
3162 isis_print_frr_summary_line(tt
, "Classic LFA",
3163 spftree
->lfa
.protection_counters
.lfa
);
3164 isis_print_frr_summary_line(tt
, "Remote LFA",
3165 spftree
->lfa
.protection_counters
.rlfa
);
3166 isis_print_frr_summary_line(tt
, "Topology Independent LFA",
3167 spftree
->lfa
.protection_counters
.tilfa
);
3168 isis_print_frr_summary_line(tt
, "ECMP",
3169 spftree
->lfa
.protection_counters
.ecmp
);
3170 isis_print_frr_summary_line(tt
, "Unprotected", unprotected
);
3171 isis_print_frr_summary_line_coverage(tt
, "Protection coverage",
3172 coverage
, coverage_total
);
3174 /* Dump the generated table. */
3175 table
= ttable_dump(tt
, "\n");
3176 vty_out(vty
, "%s\n", table
);
3177 XFREE(MTYPE_TMP
, table
);
3181 static void show_isis_frr_summary_common(struct vty
*vty
, int levels
,
3184 struct listnode
*node
;
3185 struct isis_area
*area
;
3187 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
3190 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
)) {
3191 vty_out(vty
, "Area %s:\n",
3192 area
->area_tag
? area
->area_tag
: "null");
3194 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++) {
3195 if ((level
& levels
) == 0)
3198 if (area
->ip_circuits
> 0) {
3199 isis_print_frr_summary(
3201 area
->spftree
[SPFTREE_IPV4
][level
- 1]);
3203 if (area
->ipv6_circuits
> 0) {
3204 isis_print_frr_summary(
3206 area
->spftree
[SPFTREE_IPV6
][level
- 1]);
3208 if (isis_area_ipv6_dstsrc_enabled(area
)) {
3209 isis_print_frr_summary(
3210 vty
, area
->spftree
[SPFTREE_DSTSRC
]
3217 DEFUN(show_isis_frr_summary
, show_isis_frr_summary_cmd
,
3219 " [vrf <NAME|all>] fast-reroute summary"
3221 " [<level-1|level-2>]"
3224 SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
3225 "IS-IS FRR information\n"
3235 struct listnode
*node
;
3236 const char *vrf_name
= VRF_DEFAULT_NAME
;
3237 bool all_vrf
= false;
3240 if (argv_find(argv
, argc
, "level-1", &idx
))
3241 levels
= ISIS_LEVEL1
;
3242 else if (argv_find(argv
, argc
, "level-2", &idx
))
3243 levels
= ISIS_LEVEL2
;
3245 levels
= ISIS_LEVEL1
| ISIS_LEVEL2
;
3248 vty_out(vty
, "IS-IS Routing Process not enabled\n");
3251 ISIS_FIND_VRF_ARGS(argv
, argc
, idx
, vrf_name
, all_vrf
);
3255 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
))
3256 show_isis_frr_summary_common(vty
, levels
, isis
);
3259 isis
= isis_lookup_by_vrfname(vrf_name
);
3261 show_isis_frr_summary_common(vty
, levels
, isis
);
3267 void isis_spf_init(void)
3270 install_element(VIEW_NODE
, &show_isis_flex_algo_cmd
);
3271 #endif /* ifndef FABRICD */
3272 install_element(VIEW_NODE
, &show_isis_topology_cmd
);
3273 install_element(VIEW_NODE
, &show_isis_route_cmd
);
3274 install_element(VIEW_NODE
, &show_isis_frr_summary_cmd
);
3276 /* Register hook(s). */
3277 hook_register(isis_adj_state_change_hook
, spf_adj_state_change
);
3280 void isis_spf_print(struct isis_spftree
*spftree
, struct vty
*vty
)
3282 uint64_t last_run_duration
= spftree
->last_run_duration
;
3284 vty_out(vty
, " last run elapsed : ");
3285 vty_out_timestr(vty
, spftree
->last_run_timestamp
);
3288 vty_out(vty
, " last run duration : %" PRIu64
" usec\n",
3291 vty_out(vty
, " run count : %u\n", spftree
->runcount
);
3293 void isis_spf_print_json(struct isis_spftree
*spftree
, struct json_object
*json
)
3295 char uptime
[MONOTIME_STRLEN
];
3298 cur
-= spftree
->last_run_timestamp
;
3299 frrtime_to_interval(cur
, uptime
, sizeof(uptime
));
3300 json_object_string_add(json
, "last-run-elapsed", uptime
);
3301 json_object_int_add(json
, "last-run-duration-usec",
3302 spftree
->last_run_duration
);
3303 json_object_int_add(json
, "last-run-count", spftree
->runcount
);