2 * IS-IS Rout(e)ing protocol - isis_spf.c
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #include "isis_constants.h"
38 #include "isis_common.h"
39 #include "isis_flags.h"
42 #include "isis_misc.h"
43 #include "isis_adjacency.h"
44 #include "isis_circuit.h"
48 #include "isis_dynhn.h"
50 #include "isis_route.h"
53 int isis_run_spf_l1 (struct thread
*thread
);
54 int isis_run_spf_l2 (struct thread
*thread
);
58 remove_excess_adjs (struct list
*adjs
)
60 struct listnode
*node
, *excess
= NULL
;
61 struct isis_adjacency
*adj
, *candidate
= NULL
;
64 for (ALL_LIST_ELEMENTS_RO (adjs
, node
, adj
))
68 candidate
= listgetdata (excess
);
70 if (candidate
->sys_type
< adj
->sys_type
)
76 if (candidate
->sys_type
> adj
->sys_type
)
79 comp
= memcmp (candidate
->sysid
, adj
->sysid
, ISIS_SYS_ID_LEN
);
89 if (candidate
->circuit
->circuit_id
> adj
->circuit
->circuit_id
)
96 if (candidate
->circuit
->circuit_id
< adj
->circuit
->circuit_id
)
99 comp
= memcmp (candidate
->snpa
, adj
->snpa
, ETH_ALEN
);
108 list_delete_node (adjs
, excess
);
114 vtype2string (enum vertextype vtype
)
118 case VTYPE_PSEUDO_IS
:
121 case VTYPE_PSEUDO_TE_IS
:
122 return "pseudo_TE-IS";
124 case VTYPE_NONPSEUDO_IS
:
127 case VTYPE_NONPSEUDO_TE_IS
:
133 case VTYPE_IPREACH_INTERNAL
:
134 return "IP internal";
136 case VTYPE_IPREACH_EXTERNAL
:
137 return "IP external";
139 case VTYPE_IPREACH_TE
:
143 case VTYPE_IP6REACH_INTERNAL
:
144 return "IP6 internal";
146 case VTYPE_IP6REACH_EXTERNAL
:
147 return "IP6 external";
149 #endif /* HAVE_IPV6 */
153 return NULL
; /* Not reached */
157 vid2string (struct isis_vertex
*vertex
, char * buff
, int size
)
159 switch (vertex
->type
)
161 case VTYPE_PSEUDO_IS
:
162 case VTYPE_PSEUDO_TE_IS
:
163 return print_sys_hostname (vertex
->N
.id
);
165 case VTYPE_NONPSEUDO_IS
:
166 case VTYPE_NONPSEUDO_TE_IS
:
168 return print_sys_hostname (vertex
->N
.id
);
170 case VTYPE_IPREACH_INTERNAL
:
171 case VTYPE_IPREACH_EXTERNAL
:
172 case VTYPE_IPREACH_TE
:
174 case VTYPE_IP6REACH_INTERNAL
:
175 case VTYPE_IP6REACH_EXTERNAL
:
176 #endif /* HAVE_IPV6 */
177 prefix2str ((struct prefix
*) &vertex
->N
.prefix
, buff
, size
);
183 return (char *) buff
;
186 static struct isis_vertex
*
187 isis_vertex_new (void *id
, enum vertextype vtype
)
189 struct isis_vertex
*vertex
;
191 vertex
= XCALLOC (MTYPE_ISIS_VERTEX
, sizeof (struct isis_vertex
));
194 zlog_err ("isis_vertex_new Out of memory!");
198 vertex
->type
= vtype
;
202 case VTYPE_NONPSEUDO_IS
:
203 case VTYPE_NONPSEUDO_TE_IS
:
204 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
);
206 case VTYPE_PSEUDO_IS
:
207 case VTYPE_PSEUDO_TE_IS
:
208 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
+ 1);
210 case VTYPE_IPREACH_INTERNAL
:
211 case VTYPE_IPREACH_EXTERNAL
:
212 case VTYPE_IPREACH_TE
:
214 case VTYPE_IP6REACH_INTERNAL
:
215 case VTYPE_IP6REACH_EXTERNAL
:
216 #endif /* HAVE_IPV6 */
217 memcpy (&vertex
->N
.prefix
, (struct prefix
*) id
,
218 sizeof (struct prefix
));
224 vertex
->Adj_N
= list_new ();
225 vertex
->parents
= list_new ();
226 vertex
->children
= list_new ();
232 isis_vertex_del (struct isis_vertex
*vertex
)
234 list_delete (vertex
->Adj_N
);
235 vertex
->Adj_N
= NULL
;
236 list_delete (vertex
->parents
);
237 vertex
->parents
= NULL
;
238 list_delete (vertex
->children
);
239 vertex
->children
= NULL
;
241 memset(vertex
, 0, sizeof(struct isis_vertex
));
242 XFREE (MTYPE_ISIS_VERTEX
, vertex
);
248 isis_vertex_adj_del (struct isis_vertex
*vertex
, struct isis_adjacency
*adj
)
250 struct listnode
*node
, *nextnode
;
253 for (node
= listhead (vertex
->Adj_N
); node
; node
= nextnode
)
255 nextnode
= listnextnode(node
);
256 if (listgetdata(node
) == adj
)
257 list_delete_node(vertex
->Adj_N
, node
);
262 struct isis_spftree
*
263 isis_spftree_new (struct isis_area
*area
)
265 struct isis_spftree
*tree
;
267 tree
= XCALLOC (MTYPE_ISIS_SPFTREE
, sizeof (struct isis_spftree
));
270 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
274 tree
->tents
= list_new ();
275 tree
->paths
= list_new ();
277 tree
->last_run_timestamp
= 0;
278 tree
->last_run_duration
= 0;
285 isis_spftree_del (struct isis_spftree
*spftree
)
287 THREAD_TIMER_OFF (spftree
->t_spf
);
289 spftree
->tents
->del
= (void (*)(void *)) isis_vertex_del
;
290 list_delete (spftree
->tents
);
291 spftree
->tents
= NULL
;
293 spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
294 list_delete (spftree
->paths
);
295 spftree
->paths
= NULL
;
297 XFREE (MTYPE_ISIS_SPFTREE
, spftree
);
303 isis_spftree_adj_del (struct isis_spftree
*spftree
, struct isis_adjacency
*adj
)
305 struct listnode
*node
;
308 for (node
= listhead (spftree
->tents
); node
; node
= listnextnode (node
))
309 isis_vertex_adj_del (listgetdata (node
), adj
);
310 for (node
= listhead (spftree
->paths
); node
; node
= listnextnode (node
))
311 isis_vertex_adj_del (listgetdata (node
), adj
);
316 spftree_area_init (struct isis_area
*area
)
318 if (area
->is_type
& IS_LEVEL_1
)
320 if (area
->spftree
[0] == NULL
)
321 area
->spftree
[0] = isis_spftree_new (area
);
323 if (area
->spftree6
[0] == NULL
)
324 area
->spftree6
[0] = isis_spftree_new (area
);
328 if (area
->is_type
& IS_LEVEL_2
)
330 if (area
->spftree
[1] == NULL
)
331 area
->spftree
[1] = isis_spftree_new (area
);
333 if (area
->spftree6
[1] == NULL
)
334 area
->spftree6
[1] = isis_spftree_new (area
);
342 spftree_area_del (struct isis_area
*area
)
344 if (area
->is_type
& IS_LEVEL_1
)
346 if (area
->spftree
[0] != NULL
)
348 isis_spftree_del (area
->spftree
[0]);
349 area
->spftree
[0] = NULL
;
352 if (area
->spftree6
[0])
354 isis_spftree_del (area
->spftree6
[0]);
355 area
->spftree6
[0] = NULL
;
360 if (area
->is_type
& IS_LEVEL_2
)
362 if (area
->spftree
[1] != NULL
)
364 isis_spftree_del (area
->spftree
[1]);
365 area
->spftree
[1] = NULL
;
368 if (area
->spftree6
[1] != NULL
)
370 isis_spftree_del (area
->spftree6
[1]);
371 area
->spftree6
[1] = NULL
;
380 spftree_area_adj_del (struct isis_area
*area
, struct isis_adjacency
*adj
)
382 if (area
->is_type
& IS_LEVEL_1
)
384 if (area
->spftree
[0] != NULL
)
385 isis_spftree_adj_del (area
->spftree
[0], adj
);
387 if (area
->spftree6
[0] != NULL
)
388 isis_spftree_adj_del (area
->spftree6
[0], adj
);
392 if (area
->is_type
& IS_LEVEL_2
)
394 if (area
->spftree
[1] != NULL
)
395 isis_spftree_adj_del (area
->spftree
[1], adj
);
397 if (area
->spftree6
[1] != NULL
)
398 isis_spftree_adj_del (area
->spftree6
[1], adj
);
406 * Find the system LSP: returns the LSP in our LSP database
407 * associated with the given system ID.
409 static struct isis_lsp
*
410 isis_root_system_lsp (struct isis_area
*area
, int level
, u_char
*sysid
)
412 struct isis_lsp
*lsp
;
413 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
415 memcpy (lspid
, sysid
, ISIS_SYS_ID_LEN
);
416 LSP_PSEUDO_ID (lspid
) = 0;
417 LSP_FRAGMENT (lspid
) = 0;
418 lsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
419 if (lsp
&& lsp
->lsp_header
->rem_lifetime
!= 0)
425 * Add this IS to the root of SPT
427 static struct isis_vertex
*
428 isis_spf_add_root (struct isis_spftree
*spftree
, int level
, u_char
*sysid
)
430 struct isis_vertex
*vertex
;
431 struct isis_lsp
*lsp
;
433 char buff
[PREFIX2STR_BUFFER
];
434 #endif /* EXTREME_DEBUG */
436 lsp
= isis_root_system_lsp (spftree
->area
, level
, sysid
);
438 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level
);
440 if (!spftree
->area
->oldmetric
)
441 vertex
= isis_vertex_new (sysid
, VTYPE_NONPSEUDO_TE_IS
);
443 vertex
= isis_vertex_new (sysid
, VTYPE_NONPSEUDO_IS
);
445 listnode_add (spftree
->paths
, vertex
);
448 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
449 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
450 vertex
->depth
, vertex
->d_N
);
451 #endif /* EXTREME_DEBUG */
456 static struct isis_vertex
*
457 isis_find_vertex (struct list
*list
, void *id
, enum vertextype vtype
)
459 struct listnode
*node
;
460 struct isis_vertex
*vertex
;
461 struct prefix
*p1
, *p2
;
463 for (ALL_LIST_ELEMENTS_RO (list
, node
, vertex
))
465 if (vertex
->type
!= vtype
)
470 case VTYPE_NONPSEUDO_IS
:
471 case VTYPE_NONPSEUDO_TE_IS
:
472 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
) == 0)
475 case VTYPE_PSEUDO_IS
:
476 case VTYPE_PSEUDO_TE_IS
:
477 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1) == 0)
480 case VTYPE_IPREACH_INTERNAL
:
481 case VTYPE_IPREACH_EXTERNAL
:
482 case VTYPE_IPREACH_TE
:
484 case VTYPE_IP6REACH_INTERNAL
:
485 case VTYPE_IP6REACH_EXTERNAL
:
486 #endif /* HAVE_IPV6 */
487 p1
= (struct prefix
*) id
;
488 p2
= (struct prefix
*) &vertex
->N
.id
;
489 if (p1
->family
== p2
->family
&& p1
->prefixlen
== p2
->prefixlen
&&
490 memcmp (&p1
->u
.prefix
, &p2
->u
.prefix
,
491 PSIZE (p1
->prefixlen
)) == 0)
501 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
503 static struct isis_vertex
*
504 isis_spf_add2tent (struct isis_spftree
*spftree
, enum vertextype vtype
,
505 void *id
, uint32_t cost
, int depth
, int family
,
506 struct isis_adjacency
*adj
, struct isis_vertex
*parent
)
508 struct isis_vertex
*vertex
, *v
;
509 struct listnode
*node
;
510 struct isis_adjacency
*parent_adj
;
512 char buff
[PREFIX2STR_BUFFER
];
515 assert (isis_find_vertex (spftree
->paths
, id
, vtype
) == NULL
);
516 assert (isis_find_vertex (spftree
->tents
, id
, vtype
) == NULL
);
517 vertex
= isis_vertex_new (id
, vtype
);
519 vertex
->depth
= depth
;
522 listnode_add (vertex
->parents
, parent
);
523 if (listnode_lookup (parent
->children
, vertex
) == NULL
)
524 listnode_add (parent
->children
, vertex
);
527 if (parent
&& parent
->Adj_N
&& listcount(parent
->Adj_N
) > 0) {
528 for (ALL_LIST_ELEMENTS_RO (parent
->Adj_N
, node
, parent_adj
))
529 listnode_add (vertex
->Adj_N
, parent_adj
);
531 listnode_add (vertex
->Adj_N
, adj
);
535 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
536 print_sys_hostname (vertex
->N
.id
),
537 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
538 vertex
->depth
, vertex
->d_N
, listcount(vertex
->Adj_N
));
539 #endif /* EXTREME_DEBUG */
541 if (list_isempty (spftree
->tents
))
543 listnode_add (spftree
->tents
, vertex
);
547 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
548 for (node
= listhead (spftree
->tents
); node
; node
= listnextnode (node
))
550 v
= listgetdata (node
);
551 if (v
->d_N
> vertex
->d_N
)
553 list_add_node_prev (spftree
->tents
, node
, vertex
);
556 else if (v
->d_N
== vertex
->d_N
&& v
->type
> vertex
->type
)
558 /* Tie break, add according to type */
559 list_add_node_prev (spftree
->tents
, node
, vertex
);
565 listnode_add (spftree
->tents
, vertex
);
571 isis_spf_add_local (struct isis_spftree
*spftree
, enum vertextype vtype
,
572 void *id
, struct isis_adjacency
*adj
, uint32_t cost
,
573 int family
, struct isis_vertex
*parent
)
575 struct isis_vertex
*vertex
;
577 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
582 if (vertex
->d_N
== cost
)
585 listnode_add (vertex
->Adj_N
, adj
);
587 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
588 remove_excess_adjs (vertex
->Adj_N
);
589 if (parent
&& (listnode_lookup (vertex
->parents
, parent
) == NULL
))
590 listnode_add (vertex
->parents
, parent
);
591 if (parent
&& (listnode_lookup (parent
->children
, vertex
) == NULL
))
592 listnode_add (parent
->children
, vertex
);
595 else if (vertex
->d_N
< cost
)
600 else { /* vertex->d_N > cost */
602 struct listnode
*pnode
, *pnextnode
;
603 struct isis_vertex
*pvertex
;
604 listnode_delete (spftree
->tents
, vertex
);
605 assert (listcount (vertex
->children
) == 0);
606 for (ALL_LIST_ELEMENTS (vertex
->parents
, pnode
, pnextnode
, pvertex
))
607 listnode_delete(pvertex
->children
, vertex
);
608 isis_vertex_del (vertex
);
612 isis_spf_add2tent (spftree
, vtype
, id
, cost
, 1, family
, adj
, parent
);
617 process_N (struct isis_spftree
*spftree
, enum vertextype vtype
, void *id
,
618 uint32_t dist
, uint16_t depth
, int family
,
619 struct isis_vertex
*parent
)
621 struct isis_vertex
*vertex
;
623 char buff
[PREFIX2STR_BUFFER
];
626 assert (spftree
&& parent
);
628 /* RFC3787 section 5.1 */
629 if (spftree
->area
->newmetric
== 1)
631 if (dist
> MAX_WIDE_PATH_METRIC
)
635 else if (spftree
->area
->oldmetric
== 1)
637 if (dist
> MAX_NARROW_PATH_METRIC
)
642 vertex
= isis_find_vertex (spftree
->paths
, id
, vtype
);
646 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
647 print_sys_hostname (vertex
->N
.id
),
648 vtype2string (vtype
), vid2string (vertex
, buff
, sizeof (buff
)), dist
);
649 #endif /* EXTREME_DEBUG */
650 assert (dist
>= vertex
->d_N
);
654 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
660 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
661 print_sys_hostname (vertex
->N
.id
),
662 vtype2string (vtype
), vid2string (vertex
, buff
, sizeof (buff
)), dist
,
663 (parent
? print_sys_hostname (parent
->N
.id
) : "null"),
664 (parent
? listcount (parent
->Adj_N
) : 0));
665 #endif /* EXTREME_DEBUG */
666 if (vertex
->d_N
== dist
)
668 struct listnode
*node
;
669 struct isis_adjacency
*parent_adj
;
670 for (ALL_LIST_ELEMENTS_RO (parent
->Adj_N
, node
, parent_adj
))
671 if (listnode_lookup(vertex
->Adj_N
, parent_adj
) == NULL
)
672 listnode_add (vertex
->Adj_N
, parent_adj
);
674 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
675 remove_excess_adjs (vertex
->Adj_N
);
676 if (listnode_lookup (vertex
->parents
, parent
) == NULL
)
677 listnode_add (vertex
->parents
, parent
);
678 if (listnode_lookup (parent
->children
, vertex
) == NULL
)
679 listnode_add (parent
->children
, vertex
);
683 else if (vertex
->d_N
< dist
)
690 struct listnode
*pnode
, *pnextnode
;
691 struct isis_vertex
*pvertex
;
692 listnode_delete (spftree
->tents
, vertex
);
693 assert (listcount (vertex
->children
) == 0);
694 for (ALL_LIST_ELEMENTS (vertex
->parents
, pnode
, pnextnode
, pvertex
))
695 listnode_delete(pvertex
->children
, vertex
);
696 isis_vertex_del (vertex
);
701 zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
702 print_sys_hostname(id
), vtype2string (vtype
), dist
,
703 (parent
? print_sys_hostname (parent
->N
.id
) : "null"));
704 #endif /* EXTREME_DEBUG */
706 isis_spf_add2tent (spftree
, vtype
, id
, dist
, depth
, family
, NULL
, parent
);
714 isis_spf_process_lsp (struct isis_spftree
*spftree
, struct isis_lsp
*lsp
,
715 uint32_t cost
, uint16_t depth
, int family
,
716 u_char
*root_sysid
, struct isis_vertex
*parent
)
718 struct listnode
*node
, *fragnode
= NULL
;
720 struct is_neigh
*is_neigh
;
721 struct te_is_neigh
*te_is_neigh
;
722 struct ipv4_reachability
*ipreach
;
723 struct te_ipv4_reachability
*te_ipv4_reach
;
724 enum vertextype vtype
;
725 struct prefix prefix
;
727 struct ipv6_reachability
*ip6reach
;
728 #endif /* HAVE_IPV6 */
729 static const u_char null_sysid
[ISIS_SYS_ID_LEN
];
731 if (!speaks (lsp
->tlv_data
.nlpids
, family
))
735 if (lsp
->lsp_header
->seq_num
== 0)
737 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
742 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp
->lsp_header
->lsp_id
));
743 #endif /* EXTREME_DEBUG */
745 if (!ISIS_MASK_LSP_OL_BIT (lsp
->lsp_header
->lsp_bits
))
747 if (lsp
->tlv_data
.is_neighs
)
749 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, node
, is_neigh
))
752 /* Two way connectivity */
753 if (!memcmp (is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
755 if (!memcmp (is_neigh
->neigh_id
, null_sysid
, ISIS_SYS_ID_LEN
))
757 dist
= cost
+ is_neigh
->metrics
.metric_default
;
758 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
759 : VTYPE_NONPSEUDO_IS
;
760 process_N (spftree
, vtype
, (void *) is_neigh
->neigh_id
, dist
,
761 depth
+ 1, family
, parent
);
764 if (lsp
->tlv_data
.te_is_neighs
)
766 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_is_neighs
, node
,
769 if (!memcmp (te_is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
771 if (!memcmp (te_is_neigh
->neigh_id
, null_sysid
, ISIS_SYS_ID_LEN
))
773 dist
= cost
+ GET_TE_METRIC(te_is_neigh
);
774 vtype
= LSP_PSEUDO_ID (te_is_neigh
->neigh_id
) ? VTYPE_PSEUDO_TE_IS
775 : VTYPE_NONPSEUDO_TE_IS
;
776 process_N (spftree
, vtype
, (void *) te_is_neigh
->neigh_id
, dist
,
777 depth
+ 1, family
, parent
);
782 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_int_reachs
)
784 prefix
.family
= AF_INET
;
785 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_int_reachs
, node
, ipreach
))
787 dist
= cost
+ ipreach
->metrics
.metric_default
;
788 vtype
= VTYPE_IPREACH_INTERNAL
;
789 prefix
.u
.prefix4
= ipreach
->prefix
;
790 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
791 apply_mask (&prefix
);
792 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
796 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_ext_reachs
)
798 prefix
.family
= AF_INET
;
799 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_ext_reachs
, node
, ipreach
))
801 dist
= cost
+ ipreach
->metrics
.metric_default
;
802 vtype
= VTYPE_IPREACH_EXTERNAL
;
803 prefix
.u
.prefix4
= ipreach
->prefix
;
804 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
805 apply_mask (&prefix
);
806 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
810 if (family
== AF_INET
&& lsp
->tlv_data
.te_ipv4_reachs
)
812 prefix
.family
= AF_INET
;
813 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_ipv4_reachs
,
814 node
, te_ipv4_reach
))
816 assert ((te_ipv4_reach
->control
& 0x3F) <= IPV4_MAX_BITLEN
);
818 dist
= cost
+ ntohl (te_ipv4_reach
->te_metric
);
819 vtype
= VTYPE_IPREACH_TE
;
820 prefix
.u
.prefix4
= newprefix2inaddr (&te_ipv4_reach
->prefix_start
,
821 te_ipv4_reach
->control
);
822 prefix
.prefixlen
= (te_ipv4_reach
->control
& 0x3F);
823 apply_mask (&prefix
);
824 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
829 if (family
== AF_INET6
&& lsp
->tlv_data
.ipv6_reachs
)
831 prefix
.family
= AF_INET6
;
832 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv6_reachs
, node
, ip6reach
))
834 assert (ip6reach
->prefix_len
<= IPV6_MAX_BITLEN
);
836 dist
= cost
+ ntohl(ip6reach
->metric
);
837 vtype
= (ip6reach
->control_info
& CTRL_INFO_DISTRIBUTION
) ?
838 VTYPE_IP6REACH_EXTERNAL
: VTYPE_IP6REACH_INTERNAL
;
839 prefix
.prefixlen
= ip6reach
->prefix_len
;
840 memcpy (&prefix
.u
.prefix6
.s6_addr
, ip6reach
->prefix
,
841 PSIZE (ip6reach
->prefix_len
));
842 apply_mask (&prefix
);
843 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
847 #endif /* HAVE_IPV6 */
849 if (fragnode
== NULL
)
850 fragnode
= listhead (lsp
->lspu
.frags
);
852 fragnode
= listnextnode (fragnode
);
856 lsp
= listgetdata (fragnode
);
864 isis_spf_process_pseudo_lsp (struct isis_spftree
*spftree
,
865 struct isis_lsp
*lsp
, uint32_t cost
,
866 uint16_t depth
, int family
,
868 struct isis_vertex
*parent
)
870 struct listnode
*node
, *fragnode
= NULL
;
871 struct is_neigh
*is_neigh
;
872 struct te_is_neigh
*te_is_neigh
;
873 enum vertextype vtype
;
878 if (lsp
->lsp_header
->seq_num
== 0)
880 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
881 " - do not process");
886 zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
887 print_sys_hostname(lsp
->lsp_header
->lsp_id
));
888 #endif /* EXTREME_DEBUG */
890 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
892 if (lsp
->tlv_data
.is_neighs
)
893 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, node
, is_neigh
))
895 /* Two way connectivity */
896 if (!memcmp (is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
898 dist
= cost
+ is_neigh
->metrics
.metric_default
;
899 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
900 : VTYPE_NONPSEUDO_IS
;
901 process_N (spftree
, vtype
, (void *) is_neigh
->neigh_id
, dist
,
902 depth
+ 1, family
, parent
);
904 if (lsp
->tlv_data
.te_is_neighs
)
905 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_is_neighs
, node
, te_is_neigh
))
907 /* Two way connectivity */
908 if (!memcmp (te_is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
910 dist
= cost
+ GET_TE_METRIC(te_is_neigh
);
911 vtype
= LSP_PSEUDO_ID (te_is_neigh
->neigh_id
) ? VTYPE_PSEUDO_TE_IS
912 : VTYPE_NONPSEUDO_TE_IS
;
913 process_N (spftree
, vtype
, (void *) te_is_neigh
->neigh_id
, dist
,
914 depth
+ 1, family
, parent
);
917 if (fragnode
== NULL
)
918 fragnode
= listhead (lsp
->lspu
.frags
);
920 fragnode
= listnextnode (fragnode
);
924 lsp
= listgetdata (fragnode
);
932 isis_spf_preload_tent (struct isis_spftree
*spftree
, int level
,
933 int family
, u_char
*root_sysid
,
934 struct isis_vertex
*parent
)
936 struct isis_circuit
*circuit
;
937 struct listnode
*cnode
, *anode
, *ipnode
;
938 struct isis_adjacency
*adj
;
939 struct isis_lsp
*lsp
;
940 struct list
*adj_list
;
942 struct prefix_ipv4
*ipv4
;
943 struct prefix prefix
;
944 int retval
= ISIS_OK
;
945 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
946 static u_char null_lsp_id
[ISIS_SYS_ID_LEN
+ 2];
948 struct prefix_ipv6
*ipv6
;
949 #endif /* HAVE_IPV6 */
951 for (ALL_LIST_ELEMENTS_RO (spftree
->area
->circuit_list
, cnode
, circuit
))
953 if (circuit
->state
!= C_STATE_UP
)
955 if (!(circuit
->is_type
& level
))
957 if (family
== AF_INET
&& !circuit
->ip_router
)
960 if (family
== AF_INET6
&& !circuit
->ipv6_router
)
962 #endif /* HAVE_IPV6 */
964 * Add IP(v6) addresses of this circuit
966 if (family
== AF_INET
)
968 prefix
.family
= AF_INET
;
969 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
971 prefix
.u
.prefix4
= ipv4
->prefix
;
972 prefix
.prefixlen
= ipv4
->prefixlen
;
973 apply_mask (&prefix
);
974 isis_spf_add_local (spftree
, VTYPE_IPREACH_INTERNAL
, &prefix
,
975 NULL
, 0, family
, parent
);
979 if (family
== AF_INET6
)
981 prefix
.family
= AF_INET6
;
982 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
984 prefix
.prefixlen
= ipv6
->prefixlen
;
985 prefix
.u
.prefix6
= ipv6
->prefix
;
986 apply_mask (&prefix
);
987 isis_spf_add_local (spftree
, VTYPE_IP6REACH_INTERNAL
,
988 &prefix
, NULL
, 0, family
, parent
);
991 #endif /* HAVE_IPV6 */
992 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
995 * Add the adjacencies
997 adj_list
= list_new ();
998 adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
999 isis_adj_build_up_list (adjdb
, adj_list
);
1000 if (listcount (adj_list
) == 0)
1002 list_delete (adj_list
);
1003 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1004 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
1005 level
, circuit
->interface
->name
);
1008 for (ALL_LIST_ELEMENTS_RO (adj_list
, anode
, adj
))
1010 if (!speaks (&adj
->nlpids
, family
))
1012 switch (adj
->sys_type
)
1014 case ISIS_SYSTYPE_ES
:
1015 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
1016 circuit
->te_metric
[level
- 1],
1019 case ISIS_SYSTYPE_IS
:
1020 case ISIS_SYSTYPE_L1_IS
:
1021 case ISIS_SYSTYPE_L2_IS
:
1022 isis_spf_add_local (spftree
,
1023 spftree
->area
->oldmetric
?
1024 VTYPE_NONPSEUDO_IS
:
1025 VTYPE_NONPSEUDO_TE_IS
,
1027 circuit
->te_metric
[level
- 1],
1029 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1030 LSP_PSEUDO_ID (lsp_id
) = 0;
1031 LSP_FRAGMENT (lsp_id
) = 0;
1032 lsp
= lsp_search (lsp_id
, spftree
->area
->lspdb
[level
- 1]);
1033 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
1034 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
1035 "L%d on %s (ID %u)",
1036 rawlspid_print (lsp_id
), level
,
1037 circuit
->interface
->name
, circuit
->circuit_id
);
1039 case ISIS_SYSTYPE_UNKNOWN
:
1041 zlog_warn ("isis_spf_preload_tent unknow adj type");
1044 list_delete (adj_list
);
1046 * Add the pseudonode
1049 memcpy (lsp_id
, circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1051 memcpy (lsp_id
, circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
1052 /* can happen during DR reboot */
1053 if (memcmp (lsp_id
, null_lsp_id
, ISIS_SYS_ID_LEN
+ 1) == 0)
1055 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1056 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
1057 level
, circuit
->interface
->name
, circuit
->circuit_id
);
1060 adj
= isis_adj_lookup (lsp_id
, adjdb
);
1061 /* if no adj, we are the dis or error */
1062 if (!adj
&& !circuit
->u
.bc
.is_dr
[level
- 1])
1064 zlog_warn ("ISIS-Spf: No adjacency found from root "
1065 "to L%d DR %s on %s (ID %d)",
1066 level
, rawlspid_print (lsp_id
),
1067 circuit
->interface
->name
, circuit
->circuit_id
);
1070 lsp
= lsp_search (lsp_id
, spftree
->area
->lspdb
[level
- 1]);
1071 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
1073 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1074 "to L%d DR %s on %s (ID %d)",
1075 lsp
, level
, rawlspid_print (lsp_id
),
1076 circuit
->interface
->name
, circuit
->circuit_id
);
1079 isis_spf_process_pseudo_lsp (spftree
, lsp
,
1080 circuit
->te_metric
[level
- 1], 0,
1081 family
, root_sysid
, parent
);
1083 else if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1085 adj
= circuit
->u
.p2p
.neighbor
;
1088 switch (adj
->sys_type
)
1090 case ISIS_SYSTYPE_ES
:
1091 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
1092 circuit
->te_metric
[level
- 1], family
,
1095 case ISIS_SYSTYPE_IS
:
1096 case ISIS_SYSTYPE_L1_IS
:
1097 case ISIS_SYSTYPE_L2_IS
:
1098 if (speaks (&adj
->nlpids
, family
))
1099 isis_spf_add_local (spftree
,
1100 spftree
->area
->oldmetric
?
1101 VTYPE_NONPSEUDO_IS
:
1102 VTYPE_NONPSEUDO_TE_IS
,
1104 adj
, circuit
->te_metric
[level
- 1],
1107 case ISIS_SYSTYPE_UNKNOWN
:
1109 zlog_warn ("isis_spf_preload_tent unknown adj type");
1113 else if (circuit
->circ_type
== CIRCUIT_T_LOOPBACK
)
1119 zlog_warn ("isis_spf_preload_tent unsupported media");
1120 retval
= ISIS_WARNING
;
1128 * The parent(s) for vertex is set when added to TENT list
1129 * now we just put the child pointer(s) in place
1132 add_to_paths (struct isis_spftree
*spftree
, struct isis_vertex
*vertex
,
1135 char buff
[PREFIX2STR_BUFFER
];
1137 if (isis_find_vertex (spftree
->paths
, vertex
->N
.id
, vertex
->type
))
1139 listnode_add (spftree
->paths
, vertex
);
1141 #ifdef EXTREME_DEBUG
1142 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1143 print_sys_hostname (vertex
->N
.id
),
1144 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
1145 vertex
->depth
, vertex
->d_N
);
1146 #endif /* EXTREME_DEBUG */
1148 if (vertex
->type
> VTYPE_ES
)
1150 if (listcount (vertex
->Adj_N
) > 0)
1151 isis_route_create ((struct prefix
*) &vertex
->N
.prefix
, vertex
->d_N
,
1152 vertex
->depth
, vertex
->Adj_N
, spftree
->area
, level
);
1153 else if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1154 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1155 "%s depth %d dist %d", vid2string (vertex
, buff
, sizeof (buff
)),
1156 vertex
->depth
, vertex
->d_N
);
1163 init_spt (struct isis_spftree
*spftree
)
1165 spftree
->tents
->del
= spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
1166 list_delete_all_node (spftree
->tents
);
1167 list_delete_all_node (spftree
->paths
);
1168 spftree
->tents
->del
= spftree
->paths
->del
= NULL
;
1173 isis_run_spf (struct isis_area
*area
, int level
, int family
, u_char
*sysid
)
1175 int retval
= ISIS_OK
;
1176 struct listnode
*node
;
1177 struct isis_vertex
*vertex
;
1178 struct isis_vertex
*root_vertex
;
1179 struct isis_spftree
*spftree
= NULL
;
1180 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1181 struct isis_lsp
*lsp
;
1182 struct route_table
*table
= NULL
;
1183 struct timeval time_now
;
1184 unsigned long long start_time
, end_time
;
1186 /* Get time that can't roll backwards. */
1187 quagga_gettime(QUAGGA_CLK_MONOTONIC
, &time_now
);
1188 start_time
= time_now
.tv_sec
;
1189 start_time
= (start_time
* 1000000) + time_now
.tv_usec
;
1191 if (family
== AF_INET
)
1192 spftree
= area
->spftree
[level
- 1];
1194 else if (family
== AF_INET6
)
1195 spftree
= area
->spftree6
[level
- 1];
1200 /* Make all routes in current route table inactive. */
1201 if (family
== AF_INET
)
1202 table
= area
->route_table
[level
- 1];
1204 else if (family
== AF_INET6
)
1205 table
= area
->route_table6
[level
- 1];
1208 isis_route_invalidate_table (area
, table
);
1215 root_vertex
= isis_spf_add_root (spftree
, level
, sysid
);
1217 retval
= isis_spf_preload_tent (spftree
, level
, family
, sysid
, root_vertex
);
1218 if (retval
!= ISIS_OK
)
1220 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid
));
1227 if (listcount (spftree
->tents
) == 0)
1229 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid
));
1233 while (listcount (spftree
->tents
) > 0)
1235 node
= listhead (spftree
->tents
);
1236 vertex
= listgetdata (node
);
1238 #ifdef EXTREME_DEBUG
1239 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1240 print_sys_hostname (vertex
->N
.id
),
1241 vtype2string (vertex
->type
), vertex
->depth
, vertex
->d_N
);
1242 #endif /* EXTREME_DEBUG */
1244 /* Remove from tent list and add to paths list */
1245 list_delete_node (spftree
->tents
, node
);
1246 add_to_paths (spftree
, vertex
, level
);
1247 switch (vertex
->type
)
1249 case VTYPE_PSEUDO_IS
:
1250 case VTYPE_NONPSEUDO_IS
:
1251 case VTYPE_PSEUDO_TE_IS
:
1252 case VTYPE_NONPSEUDO_TE_IS
:
1253 memcpy (lsp_id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1);
1254 LSP_FRAGMENT (lsp_id
) = 0;
1255 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
1256 if (lsp
&& lsp
->lsp_header
->rem_lifetime
!= 0)
1258 if (LSP_PSEUDO_ID (lsp_id
))
1260 isis_spf_process_pseudo_lsp (spftree
, lsp
, vertex
->d_N
,
1261 vertex
->depth
, family
, sysid
,
1266 isis_spf_process_lsp (spftree
, lsp
, vertex
->d_N
,
1267 vertex
->depth
, family
, sysid
, vertex
);
1272 zlog_warn ("ISIS-Spf: No LSP found for %s",
1273 rawlspid_print (lsp_id
));
1281 isis_route_validate (area
);
1282 spftree
->pending
= 0;
1283 spftree
->runcount
++;
1284 spftree
->last_run_timestamp
= time (NULL
);
1285 quagga_gettime(QUAGGA_CLK_MONOTONIC
, &time_now
);
1286 end_time
= time_now
.tv_sec
;
1287 end_time
= (end_time
* 1000000) + time_now
.tv_usec
;
1288 spftree
->last_run_duration
= end_time
- start_time
;
1295 isis_run_spf_l1 (struct thread
*thread
)
1297 struct isis_area
*area
;
1298 int retval
= ISIS_OK
;
1300 area
= THREAD_ARG (thread
);
1303 area
->spftree
[0]->t_spf
= NULL
;
1304 area
->spftree
[0]->pending
= 0;
1306 if (!(area
->is_type
& IS_LEVEL_1
))
1308 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1309 zlog_warn ("ISIS-SPF (%s) area does not share level",
1311 return ISIS_WARNING
;
1314 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1315 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1317 if (area
->ip_circuits
)
1318 retval
= isis_run_spf (area
, 1, AF_INET
, isis
->sysid
);
1324 isis_run_spf_l2 (struct thread
*thread
)
1326 struct isis_area
*area
;
1327 int retval
= ISIS_OK
;
1329 area
= THREAD_ARG (thread
);
1332 area
->spftree
[1]->t_spf
= NULL
;
1333 area
->spftree
[1]->pending
= 0;
1335 if (!(area
->is_type
& IS_LEVEL_2
))
1337 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1338 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1339 return ISIS_WARNING
;
1342 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1343 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area
->area_tag
);
1345 if (area
->ip_circuits
)
1346 retval
= isis_run_spf (area
, 2, AF_INET
, isis
->sysid
);
1352 isis_spf_schedule (struct isis_area
*area
, int level
)
1354 struct isis_spftree
*spftree
= area
->spftree
[level
- 1];
1355 time_t now
= time (NULL
);
1356 int diff
= now
- spftree
->last_run_timestamp
;
1359 assert (area
->is_type
& level
);
1361 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1362 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1363 area
->area_tag
, level
, diff
);
1365 if (spftree
->pending
)
1368 THREAD_TIMER_OFF (spftree
->t_spf
);
1370 /* wait configured min_spf_interval before doing the SPF */
1371 if (diff
>= area
->min_spf_interval
[level
-1])
1372 return isis_run_spf (area
, level
, AF_INET
, isis
->sysid
);
1375 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
,
1376 area
->min_spf_interval
[0] - diff
);
1378 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
,
1379 area
->min_spf_interval
[1] - diff
);
1381 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1382 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
1383 area
->area_tag
, level
, area
->min_spf_interval
[level
-1] - diff
);
1385 spftree
->pending
= 1;
1392 isis_run_spf6_l1 (struct thread
*thread
)
1394 struct isis_area
*area
;
1395 int retval
= ISIS_OK
;
1397 area
= THREAD_ARG (thread
);
1400 area
->spftree6
[0]->t_spf
= NULL
;
1401 area
->spftree6
[0]->pending
= 0;
1403 if (!(area
->is_type
& IS_LEVEL_1
))
1405 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1406 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1407 return ISIS_WARNING
;
1410 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1411 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1413 if (area
->ipv6_circuits
)
1414 retval
= isis_run_spf (area
, 1, AF_INET6
, isis
->sysid
);
1420 isis_run_spf6_l2 (struct thread
*thread
)
1422 struct isis_area
*area
;
1423 int retval
= ISIS_OK
;
1425 area
= THREAD_ARG (thread
);
1428 area
->spftree6
[1]->t_spf
= NULL
;
1429 area
->spftree6
[1]->pending
= 0;
1431 if (!(area
->is_type
& IS_LEVEL_2
))
1433 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1434 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1435 return ISIS_WARNING
;
1438 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1439 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area
->area_tag
);
1441 if (area
->ipv6_circuits
)
1442 retval
= isis_run_spf (area
, 2, AF_INET6
, isis
->sysid
);
1448 isis_spf_schedule6 (struct isis_area
*area
, int level
)
1450 int retval
= ISIS_OK
;
1451 struct isis_spftree
*spftree
= area
->spftree6
[level
- 1];
1452 time_t now
= time (NULL
);
1453 time_t diff
= now
- spftree
->last_run_timestamp
;
1456 assert (area
->is_type
& level
);
1458 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1459 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago",
1460 area
->area_tag
, level
, (long long)diff
);
1462 if (spftree
->pending
)
1465 THREAD_TIMER_OFF (spftree
->t_spf
);
1467 /* wait configured min_spf_interval before doing the SPF */
1468 if (diff
>= area
->min_spf_interval
[level
-1])
1469 return isis_run_spf (area
, level
, AF_INET6
, isis
->sysid
);
1472 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
,
1473 area
->min_spf_interval
[0] - diff
);
1475 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
,
1476 area
->min_spf_interval
[1] - diff
);
1478 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1479 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now",
1480 area
->area_tag
, level
, (long long)(area
->min_spf_interval
[level
-1] - diff
));
1482 spftree
->pending
= 1;
1489 isis_print_paths (struct vty
*vty
, struct list
*paths
, u_char
*root_sysid
)
1491 struct listnode
*node
;
1492 struct listnode
*anode
;
1493 struct isis_vertex
*vertex
;
1494 struct isis_adjacency
*adj
;
1495 char buff
[PREFIX2STR_BUFFER
];
1497 vty_out (vty
, "Vertex Type Metric "
1498 "Next-Hop Interface Parent%s", VTY_NEWLINE
);
1500 for (ALL_LIST_ELEMENTS_RO (paths
, node
, vertex
)) {
1501 if (memcmp (vertex
->N
.id
, root_sysid
, ISIS_SYS_ID_LEN
) == 0) {
1502 vty_out (vty
, "%-20s %-12s %-6s", print_sys_hostname (root_sysid
),
1504 vty_out (vty
, "%-30s", "");
1507 vty_out (vty
, "%-20s %-12s %-6u ", vid2string (vertex
, buff
, sizeof (buff
)),
1508 vtype2string (vertex
->type
), vertex
->d_N
);
1509 for (ALL_LIST_ELEMENTS_RO (vertex
->Adj_N
, anode
, adj
)) {
1512 vty_out (vty
, "%s", VTY_NEWLINE
);
1513 vty_out (vty
, "%-20s %-12s %-6s ", "", "", "");
1515 vty_out (vty
, "%-20s %-9s ",
1516 print_sys_hostname (adj
->sysid
),
1517 adj
->circuit
->interface
->name
);
1522 vty_out (vty
, "%-30s ", "");
1525 /* Print list of parents for the ECMP DAG */
1526 if (listcount (vertex
->parents
) > 0) {
1527 struct listnode
*pnode
;
1528 struct isis_vertex
*pvertex
;
1530 for (ALL_LIST_ELEMENTS_RO (vertex
->parents
, pnode
, pvertex
)) {
1532 vty_out (vty
, "%s", VTY_NEWLINE
);
1533 vty_out (vty
, "%-72s", "");
1535 vty_out (vty
, "%s(%d)",
1536 vid2string (pvertex
, buff
, sizeof (buff
)), pvertex
->type
);
1540 vty_out (vty
, " NULL ");
1543 vty_out (vty
, "%s", VTY_NEWLINE
);
1547 DEFUN (show_isis_topology
,
1548 show_isis_topology_cmd
,
1549 "show isis topology",
1551 "IS-IS information\n"
1552 "IS-IS paths to Intermediate Systems\n")
1554 struct listnode
*node
;
1555 struct isis_area
*area
;
1558 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1561 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1563 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1566 for (level
= 0; level
< ISIS_LEVELS
; level
++)
1568 if (area
->ip_circuits
> 0 && area
->spftree
[level
]
1569 && area
->spftree
[level
]->paths
->count
> 0)
1571 vty_out (vty
, "IS-IS paths to level-%d routers that speak IP%s",
1572 level
+ 1, VTY_NEWLINE
);
1573 isis_print_paths (vty
, area
->spftree
[level
]->paths
, isis
->sysid
);
1574 vty_out (vty
, "%s", VTY_NEWLINE
);
1577 if (area
->ipv6_circuits
> 0 && area
->spftree6
[level
]
1578 && area
->spftree6
[level
]->paths
->count
> 0)
1581 "IS-IS paths to level-%d routers that speak IPv6%s",
1582 level
+ 1, VTY_NEWLINE
);
1583 isis_print_paths (vty
, area
->spftree6
[level
]->paths
, isis
->sysid
);
1584 vty_out (vty
, "%s", VTY_NEWLINE
);
1586 #endif /* HAVE_IPV6 */
1589 vty_out (vty
, "%s", VTY_NEWLINE
);
1595 DEFUN (show_isis_topology_l1
,
1596 show_isis_topology_l1_cmd
,
1597 "show isis topology level-1",
1599 "IS-IS information\n"
1600 "IS-IS paths to Intermediate Systems\n"
1601 "Paths to all level-1 routers in the area\n")
1603 struct listnode
*node
;
1604 struct isis_area
*area
;
1606 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1609 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1611 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1614 if (area
->ip_circuits
> 0 && area
->spftree
[0]
1615 && area
->spftree
[0]->paths
->count
> 0)
1617 vty_out (vty
, "IS-IS paths to level-1 routers that speak IP%s",
1619 isis_print_paths (vty
, area
->spftree
[0]->paths
, isis
->sysid
);
1620 vty_out (vty
, "%s", VTY_NEWLINE
);
1623 if (area
->ipv6_circuits
> 0 && area
->spftree6
[0]
1624 && area
->spftree6
[0]->paths
->count
> 0)
1626 vty_out (vty
, "IS-IS paths to level-1 routers that speak IPv6%s",
1628 isis_print_paths (vty
, area
->spftree6
[0]->paths
, isis
->sysid
);
1629 vty_out (vty
, "%s", VTY_NEWLINE
);
1631 #endif /* HAVE_IPV6 */
1632 vty_out (vty
, "%s", VTY_NEWLINE
);
1638 DEFUN (show_isis_topology_l2
,
1639 show_isis_topology_l2_cmd
,
1640 "show isis topology level-2",
1642 "IS-IS information\n"
1643 "IS-IS paths to Intermediate Systems\n"
1644 "Paths to all level-2 routers in the domain\n")
1646 struct listnode
*node
;
1647 struct isis_area
*area
;
1649 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1652 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1654 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1657 if (area
->ip_circuits
> 0 && area
->spftree
[1]
1658 && area
->spftree
[1]->paths
->count
> 0)
1660 vty_out (vty
, "IS-IS paths to level-2 routers that speak IP%s",
1662 isis_print_paths (vty
, area
->spftree
[1]->paths
, isis
->sysid
);
1663 vty_out (vty
, "%s", VTY_NEWLINE
);
1666 if (area
->ipv6_circuits
> 0 && area
->spftree6
[1]
1667 && area
->spftree6
[1]->paths
->count
> 0)
1669 vty_out (vty
, "IS-IS paths to level-2 routers that speak IPv6%s",
1671 isis_print_paths (vty
, area
->spftree6
[1]->paths
, isis
->sysid
);
1672 vty_out (vty
, "%s", VTY_NEWLINE
);
1674 #endif /* HAVE_IPV6 */
1675 vty_out (vty
, "%s", VTY_NEWLINE
);
1682 isis_spf_cmds_init ()
1684 install_element (VIEW_NODE
, &show_isis_topology_cmd
);
1685 install_element (VIEW_NODE
, &show_isis_topology_l1_cmd
);
1686 install_element (VIEW_NODE
, &show_isis_topology_l2_cmd
);
1688 install_element (ENABLE_NODE
, &show_isis_topology_cmd
);
1689 install_element (ENABLE_NODE
, &show_isis_topology_l1_cmd
);
1690 install_element (ENABLE_NODE
, &show_isis_topology_l2_cmd
);