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.
39 #include "isis_constants.h"
40 #include "isis_common.h"
43 #include "isis_misc.h"
44 #include "isis_adjacency.h"
45 #include "isis_circuit.h"
49 #include "isis_dynhn.h"
51 #include "isis_route.h"
54 extern struct isis
*isis
;
55 extern struct thread_master
*master
;
56 extern struct host host
;
58 int isis_run_spf_l1 (struct thread
*thread
);
59 int isis_run_spf_l2 (struct thread
*thread
);
61 /* performace issue ???? */
63 union_adjlist (struct list
*target
, struct list
*source
)
65 struct isis_adjacency
*adj
, *adj2
;
66 struct listnode
*node
, *node2
;
68 zlog_info ("Union adjlist!");
69 for (node
= listhead (source
); node
; nextnode (node
))
73 /* lookup adjacency in the source list */
74 for (node2
= listhead (target
); node2
; nextnode (node2
))
76 adj2
= getdata (node2
);
82 listnode_add (target
, adj
);
88 remove_excess_adjs (struct list
*adjs
)
90 struct listnode
*node
, *excess
= NULL
;
91 struct isis_adjacency
*adj
, *candidate
= NULL
;
94 for (node
= listhead (adjs
); node
; nextnode (node
))
98 candidate
= getdata (excess
);
100 if (candidate
->sys_type
< adj
->sys_type
)
106 if (candidate
->sys_type
> adj
->sys_type
)
109 comp
= memcmp (candidate
->sysid
, adj
->sysid
, ISIS_SYS_ID_LEN
);
119 if (candidate
->circuit
->circuit_id
> adj
->circuit
->circuit_id
)
126 if (candidate
->circuit
->circuit_id
< adj
->circuit
->circuit_id
)
129 comp
= memcmp (candidate
->snpa
, adj
->snpa
, ETH_ALEN
);
138 list_delete_node (adjs
, excess
);
144 vtype2string (enum vertextype vtype
)
148 case VTYPE_PSEUDO_IS
:
151 case VTYPE_NONPSEUDO_IS
:
157 case VTYPE_IPREACH_INTERNAL
:
158 return "IP internal";
160 case VTYPE_IPREACH_EXTERNAL
:
161 return "IP external";
164 case VTYPE_IP6REACH_INTERNAL
:
165 return "IP6 internal";
167 case VTYPE_IP6REACH_EXTERNAL
:
168 return "IP6 external";
170 #endif /* HAVE_IPV6 */
174 return NULL
; /* Not reached */
178 vid2string (struct isis_vertex
*vertex
, u_char
* buff
)
180 switch (vertex
->type
)
182 case VTYPE_PSEUDO_IS
:
183 return rawlspid_print (vertex
->N
.id
);
185 case VTYPE_NONPSEUDO_IS
:
187 return sysid_print (vertex
->N
.id
);
189 case VTYPE_IPREACH_INTERNAL
:
190 case VTYPE_IPREACH_EXTERNAL
:
192 case VTYPE_IP6REACH_INTERNAL
:
193 case VTYPE_IP6REACH_EXTERNAL
:
194 #endif /* HAVE_IPV6 */
195 prefix2str ((struct prefix
*) &vertex
->N
.prefix
, (char *) buff
, BUFSIZ
);
201 return (char *) buff
;
204 struct isis_spftree
*
207 struct isis_spftree
*tree
;
209 tree
= XMALLOC (MTYPE_ISIS_SPFTREE
, sizeof (struct isis_spftree
));
212 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
215 memset (tree
, 0, sizeof (struct isis_spftree
));
217 tree
->tents
= list_new ();
218 tree
->paths
= list_new ();
223 isis_vertex_del (struct isis_vertex
*vertex
)
225 list_delete (vertex
->Adj_N
);
227 XFREE (MTYPE_ISIS_VERTEX
, vertex
);
233 isis_spftree_del (struct isis_spftree
*spftree
)
235 spftree
->tents
->del
= (void (*)(void *)) isis_vertex_del
;
236 list_delete (spftree
->tents
);
238 spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
239 list_delete (spftree
->paths
);
241 XFREE (MTYPE_ISIS_SPFTREE
, spftree
);
247 spftree_area_init (struct isis_area
*area
)
249 if ((area
->is_type
& IS_LEVEL_1
) && area
->spftree
[0] == NULL
)
251 area
->spftree
[0] = isis_spftree_new ();
253 area
->spftree6
[0] = isis_spftree_new ();
256 /* thread_add_timer (master, isis_run_spf_l1, area,
257 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
260 if ((area
->is_type
& IS_LEVEL_2
) && area
->spftree
[1] == NULL
)
262 area
->spftree
[1] = isis_spftree_new ();
264 area
->spftree6
[1] = isis_spftree_new ();
266 /* thread_add_timer (master, isis_run_spf_l2, area,
267 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
274 isis_vertex_new (void *id
, enum vertextype vtype
)
276 struct isis_vertex
*vertex
;
278 vertex
= XMALLOC (MTYPE_ISIS_VERTEX
, sizeof (struct isis_vertex
));
281 zlog_err ("isis_vertex_new Out of memory!");
285 memset (vertex
, 0, sizeof (struct isis_vertex
));
286 vertex
->type
= vtype
;
290 case VTYPE_NONPSEUDO_IS
:
291 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
);
293 case VTYPE_PSEUDO_IS
:
294 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
+ 1);
296 case VTYPE_IPREACH_INTERNAL
:
297 case VTYPE_IPREACH_EXTERNAL
:
299 case VTYPE_IP6REACH_INTERNAL
:
300 case VTYPE_IP6REACH_EXTERNAL
:
301 #endif /* HAVE_IPV6 */
302 memcpy (&vertex
->N
.prefix
, (struct prefix
*) id
,
303 sizeof (struct prefix
));
309 vertex
->Adj_N
= list_new ();
315 * Add this IS to the root of SPT
318 isis_spf_add_self (struct isis_spftree
*spftree
, struct isis_area
*area
,
321 struct isis_vertex
*vertex
;
322 struct isis_lsp
*lsp
;
323 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
326 #endif /* EXTREME_DEBUG */
327 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
328 LSP_PSEUDO_ID (lspid
) = 0;
329 LSP_FRAGMENT (lspid
) = 0;
331 lsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
334 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level
);
336 vertex
= isis_vertex_new (isis
->sysid
, VTYPE_NONPSEUDO_IS
);
339 listnode_add (spftree
->paths
, vertex
);
342 zlog_info ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
343 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
344 vertex
->depth
, vertex
->d_N
);
345 #endif /* EXTREME_DEBUG */
351 isis_find_vertex (struct list
*list
, void *id
, enum vertextype vtype
)
353 struct listnode
*node
;
354 struct isis_vertex
*vertex
;
355 struct prefix
*p1
, *p2
;
357 for (node
= listhead (list
); node
; nextnode (node
))
359 vertex
= getdata (node
);
360 if (vertex
->type
!= vtype
)
365 case VTYPE_NONPSEUDO_IS
:
366 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
) == 0)
369 case VTYPE_PSEUDO_IS
:
370 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1) == 0)
373 case VTYPE_IPREACH_INTERNAL
:
374 case VTYPE_IPREACH_EXTERNAL
:
376 case VTYPE_IP6REACH_INTERNAL
:
377 case VTYPE_IP6REACH_EXTERNAL
:
378 #endif /* HAVE_IPV6 */
379 p1
= (struct prefix
*) id
;
380 p2
= (struct prefix
*) &vertex
->N
.id
;
381 if (p1
->family
== p2
->family
&& p1
->prefixlen
== p2
->prefixlen
&&
382 memcmp (&p1
->u
.prefix
, &p2
->u
.prefix
,
383 PSIZE (p1
->prefixlen
)) == 0)
393 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
396 isis_spf_add2tent (struct isis_spftree
*spftree
, enum vertextype vtype
,
397 void *id
, struct isis_adjacency
*adj
, u_int16_t cost
,
398 int depth
, int family
)
400 struct isis_vertex
*vertex
, *v
;
401 struct listnode
*node
;
406 vertex
= isis_vertex_new (id
, vtype
);
408 vertex
->depth
= depth
;
411 listnode_add (vertex
->Adj_N
, adj
);
413 zlog_info ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
414 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
415 vertex
->depth
, vertex
->d_N
);
416 #endif /* EXTREME_DEBUG */
417 listnode_add (spftree
->tents
, vertex
);
418 if (list_isempty (spftree
->tents
))
420 listnode_add (spftree
->tents
, vertex
);
423 for (node
= listhead (spftree
->tents
); node
; nextnode (node
))
426 if (v
->d_N
> vertex
->d_N
)
428 list_add_node_prev (spftree
->tents
, node
, vertex
);
431 else if (v
->d_N
== vertex
->d_N
)
433 /* Tie break, add according to type */
434 while (v
&& v
->d_N
== vertex
->d_N
&& v
->type
> vertex
->type
)
436 if (v
->type
> vertex
->type
)
441 (node
) ? (v
= getdata (node
)) : (v
= NULL
);
443 list_add_node_prev (spftree
->tents
, node
, vertex
);
446 else if (node
->next
== NULL
)
448 list_add_node_next (spftree
->tents
, node
, vertex
);
456 isis_spf_add_local (struct isis_spftree
*spftree
, enum vertextype vtype
,
457 void *id
, struct isis_adjacency
*adj
, u_int16_t cost
,
460 struct isis_vertex
*vertex
;
462 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
467 if (vertex
->d_N
== cost
)
470 listnode_add (vertex
->Adj_N
, adj
);
472 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
473 remove_excess_adjs (vertex
->Adj_N
);
476 else if (vertex
->d_N
> cost
)
478 listnode_delete (spftree
->tents
, vertex
);
486 return isis_spf_add2tent (spftree
, vtype
, id
, adj
, cost
, 1, family
);
490 process_N (struct isis_spftree
*spftree
, enum vertextype vtype
, void *id
,
491 u_int16_t dist
, u_int16_t depth
, struct isis_adjacency
*adj
,
494 struct isis_vertex
*vertex
;
500 if (dist
> MAX_PATH_METRIC
)
503 vertex
= isis_find_vertex (spftree
->paths
, id
, vtype
);
507 zlog_info ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
508 vtype2string (vtype
), vid2string (vertex
, buff
), dist
);
509 #endif /* EXTREME_DEBUG */
510 assert (dist
>= vertex
->d_N
);
514 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
520 zlog_info ("ISIS-Spf: process_N %s %s dist %d",
521 vtype2string (vtype
), vid2string (vertex
, buff
), dist
);
522 #endif /* EXTREME_DEBUG */
523 if (vertex
->d_N
== dist
)
526 listnode_add (vertex
->Adj_N
, adj
);
528 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
529 remove_excess_adjs (vertex
->Adj_N
);
533 else if (vertex
->d_N
< dist
)
540 listnode_delete (spftree
->tents
, vertex
);
544 isis_spf_add2tent (spftree
, vtype
, id
, adj
, dist
, depth
, family
);
552 isis_spf_process_lsp (struct isis_spftree
*spftree
, struct isis_lsp
*lsp
,
553 uint16_t cost
, uint16_t depth
, int family
)
555 struct listnode
*node
, *fragnode
= NULL
;
557 struct is_neigh
*is_neigh
;
558 struct ipv4_reachability
*ipreach
;
559 enum vertextype vtype
;
560 struct prefix prefix
;
562 struct ipv6_reachability
*ip6reach
;
563 #endif /* HAVE_IPV6 */
568 if (lsp
->tlv_data
.nlpids
== NULL
|| !speaks (lsp
->tlv_data
.nlpids
, family
))
572 if (lsp
->lsp_header
->seq_num
== 0)
574 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
575 " - do not process");
579 if (!ISIS_MASK_LSP_OL_BIT (lsp
->lsp_header
->lsp_bits
))
581 if (lsp
->tlv_data
.is_neighs
)
583 for (node
= listhead (lsp
->tlv_data
.is_neighs
); node
;
586 is_neigh
= getdata (node
);
588 /* Two way connectivity */
589 if (!memcmp (is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
591 dist
= cost
+ is_neigh
->metrics
.metric_default
;
592 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
593 : VTYPE_NONPSEUDO_IS
;
594 process_N (spftree
, vtype
, (void *) is_neigh
->neigh_id
, dist
,
595 depth
+ 1, lsp
->adj
, family
);
598 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_int_reachs
)
600 prefix
.family
= AF_INET
;
601 for (node
= listhead (lsp
->tlv_data
.ipv4_int_reachs
); node
;
604 ipreach
= getdata (node
);
605 dist
= cost
+ ipreach
->metrics
.metric_default
;
606 vtype
= VTYPE_IPREACH_INTERNAL
;
607 prefix
.u
.prefix4
= ipreach
->prefix
;
608 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
609 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
614 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_ext_reachs
)
616 prefix
.family
= AF_INET
;
617 for (node
= listhead (lsp
->tlv_data
.ipv4_ext_reachs
); node
;
620 ipreach
= getdata (node
);
621 dist
= cost
+ ipreach
->metrics
.metric_default
;
622 vtype
= VTYPE_IPREACH_EXTERNAL
;
623 prefix
.u
.prefix4
= ipreach
->prefix
;
624 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
625 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
630 if (family
== AF_INET6
&& lsp
->tlv_data
.ipv6_reachs
)
632 prefix
.family
= AF_INET6
;
633 for (node
= listhead (lsp
->tlv_data
.ipv6_reachs
); node
;
636 ip6reach
= getdata (node
);
637 dist
= cost
+ ip6reach
->metric
;
638 vtype
= (ip6reach
->control_info
& CTRL_INFO_DISTRIBUTION
) ?
639 VTYPE_IP6REACH_EXTERNAL
: VTYPE_IP6REACH_INTERNAL
;
640 prefix
.prefixlen
= ip6reach
->prefix_len
;
641 memcpy (&prefix
.u
.prefix6
.s6_addr
, ip6reach
->prefix
,
642 PSIZE (ip6reach
->prefix_len
));
643 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
647 #endif /* HAVE_IPV6 */
650 if (fragnode
== NULL
)
651 fragnode
= listhead (lsp
->lspu
.frags
);
657 lsp
= getdata (fragnode
);
665 isis_spf_process_pseudo_lsp (struct isis_spftree
*spftree
,
666 struct isis_lsp
*lsp
, uint16_t cost
,
667 uint16_t depth
, int family
)
669 struct listnode
*node
, *fragnode
= NULL
;
670 struct is_neigh
*is_neigh
;
671 enum vertextype vtype
;
675 if (lsp
->lsp_header
->seq_num
== 0)
677 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
678 " - do not process");
682 for (node
= (lsp
->tlv_data
.is_neighs
?
683 listhead (lsp
->tlv_data
.is_neighs
) : NULL
);
684 node
; nextnode (node
))
686 is_neigh
= getdata (node
);
687 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
688 : VTYPE_NONPSEUDO_IS
;
689 /* Two way connectivity */
690 if (!memcmp (is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
693 (spftree
->tents
, (void *) is_neigh
->neigh_id
, vtype
) == NULL
694 && isis_find_vertex (spftree
->paths
, (void *) is_neigh
->neigh_id
,
698 isis_spf_add2tent (spftree
, vtype
, is_neigh
->neigh_id
, lsp
->adj
,
699 cost
, depth
, family
);
703 if (fragnode
== NULL
)
704 fragnode
= listhead (lsp
->lspu
.frags
);
710 lsp
= getdata (fragnode
);
718 isis_spf_preload_tent (struct isis_spftree
*spftree
,
719 struct isis_area
*area
, int level
, int family
)
721 struct isis_vertex
*vertex
;
722 struct isis_circuit
*circuit
;
723 struct listnode
*cnode
, *anode
, *ipnode
;
724 struct isis_adjacency
*adj
;
725 struct isis_lsp
*lsp
;
726 struct list
*adj_list
;
728 struct prefix_ipv4
*ipv4
;
729 struct prefix prefix
;
730 int retval
= ISIS_OK
;
731 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
733 struct prefix_ipv6
*ipv6
;
734 #endif /* HAVE_IPV6 */
736 for (cnode
= listhead (area
->circuit_list
); cnode
; nextnode (cnode
))
738 circuit
= getdata (cnode
);
739 if (circuit
->state
!= C_STATE_UP
)
741 if (!(circuit
->circuit_is_type
& level
))
743 if (family
== AF_INET
&& !circuit
->ip_router
)
746 if (family
== AF_INET6
&& !circuit
->ipv6_router
)
748 #endif /* HAVE_IPV6 */
750 * Add IP(v6) addresses of this circuit
752 if (family
== AF_INET
)
754 prefix
.family
= AF_INET
;
756 (circuit
->ip_addrs
? listhead (circuit
->ip_addrs
) : NULL
);
757 ipnode
; nextnode (ipnode
))
759 ipv4
= getdata (ipnode
);
760 prefix
.u
.prefix4
= ipv4
->prefix
;
761 prefix
.prefixlen
= ipv4
->prefixlen
;
762 isis_spf_add_local (spftree
, VTYPE_IPREACH_INTERNAL
, &prefix
,
767 if (family
== AF_INET6
)
769 prefix
.family
= AF_INET6
;
770 for (ipnode
= (circuit
->ipv6_non_link
? listhead
771 (circuit
->ipv6_non_link
) : NULL
); ipnode
;
774 ipv6
= getdata (ipnode
);
775 prefix
.prefixlen
= ipv6
->prefixlen
;
776 prefix
.u
.prefix6
= ipv6
->prefix
;
777 isis_spf_add_local (spftree
, VTYPE_IP6REACH_INTERNAL
,
778 &prefix
, NULL
, 0, family
);
781 #endif /* HAVE_IPV6 */
782 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
785 * Add the adjacencies
787 adj_list
= list_new ();
788 adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
789 isis_adj_build_up_list (adjdb
, adj_list
);
790 if (listcount (adj_list
) == 0)
792 list_delete (adj_list
);
793 zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s",
794 level
, circuit
->interface
->name
);
797 anode
= listhead (adj_list
);
800 adj
= getdata (anode
);
801 if (!speaks (&adj
->nlpids
, family
))
806 switch (adj
->sys_type
)
808 case ISIS_SYSTYPE_ES
:
809 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
810 circuit
->metrics
[level
-
814 case ISIS_SYSTYPE_IS
:
815 case ISIS_SYSTYPE_L1_IS
:
816 case ISIS_SYSTYPE_L2_IS
:
818 isis_spf_add_local (spftree
, VTYPE_NONPSEUDO_IS
,
820 circuit
->metrics
[level
-
823 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
824 LSP_PSEUDO_ID (lsp_id
) = 0;
825 LSP_FRAGMENT (lsp_id
) = 0;
826 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
828 zlog_warn ("No lsp found for IS adjacency");
830 isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
833 case ISIS_SYSTYPE_UNKNOWN
:
835 zlog_warn ("isis_spf_preload_tent unknow adj type");
839 list_delete (adj_list
);
844 memcpy (lsp_id
, circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
846 memcpy (lsp_id
, circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
847 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
848 adj
= isis_adj_lookup (lsp_id
, adjdb
);
849 /* if no adj, we are the dis or error */
850 if (!adj
&& !circuit
->u
.bc
.is_dr
[level
- 1])
852 zlog_warn ("ISIS-Spf: No adjacency found for DR");
854 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
856 zlog_warn ("ISIS-Spf: No lsp found for DR");
860 isis_spf_process_pseudo_lsp
861 (spftree
, lsp
, circuit
->metrics
[level
- 1].metric_default
, 0,
866 else if (circuit
->circ_type
== CIRCUIT_T_P2P
)
868 adj
= circuit
->u
.p2p
.neighbor
;
871 switch (adj
->sys_type
)
873 case ISIS_SYSTYPE_ES
:
874 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
875 circuit
->metrics
[level
- 1].metric_default
,
878 case ISIS_SYSTYPE_IS
:
879 case ISIS_SYSTYPE_L1_IS
:
880 case ISIS_SYSTYPE_L2_IS
:
881 if (speaks (&adj
->nlpids
, family
))
882 isis_spf_add_local (spftree
, VTYPE_NONPSEUDO_IS
, adj
->sysid
,
884 circuit
->metrics
[level
-
888 case ISIS_SYSTYPE_UNKNOWN
:
890 zlog_warn ("isis_spf_preload_tent unknow adj type");
896 zlog_warn ("isis_spf_preload_tent unsupported media");
897 retval
= ISIS_WARNING
;
906 * The parent(s) for vertex is set when added to TENT list
907 * now we just put the child pointer(s) in place
910 add_to_paths (struct isis_spftree
*spftree
, struct isis_vertex
*vertex
,
911 struct isis_area
*area
)
915 #endif /* EXTREME_DEBUG */
916 listnode_add (spftree
->paths
, vertex
);
919 zlog_info ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
920 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
921 vertex
->depth
, vertex
->d_N
);
922 #endif /* EXTREME_DEBUG */
923 if (vertex
->type
> VTYPE_ES
)
925 if (listcount (vertex
->Adj_N
) > 0)
926 isis_route_create ((struct prefix
*) &vertex
->N
.prefix
,
927 vertex
->d_N
, vertex
->depth
, vertex
->Adj_N
, area
);
928 else if (isis
->debugs
& DEBUG_SPF_EVENTS
)
929 zlog_info ("ISIS-Spf: no adjacencies do not install route");
936 init_spt (struct isis_spftree
*spftree
)
938 spftree
->tents
->del
= spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
939 list_delete_all_node (spftree
->tents
);
940 list_delete_all_node (spftree
->paths
);
941 spftree
->tents
->del
= spftree
->paths
->del
= NULL
;
947 isis_run_spf (struct isis_area
*area
, int level
, int family
)
949 int retval
= ISIS_OK
;
950 struct listnode
*node
;
951 struct isis_vertex
*vertex
;
952 struct isis_spftree
*spftree
= NULL
;
953 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
954 struct isis_lsp
*lsp
;
956 if (family
== AF_INET
)
957 spftree
= area
->spftree
[level
- 1];
959 else if (family
== AF_INET6
)
960 spftree
= area
->spftree6
[level
- 1];
970 isis_spf_add_self (spftree
, area
, level
);
972 retval
= isis_spf_preload_tent (spftree
, area
, level
, family
);
977 if (listcount (spftree
->tents
) == 0)
979 zlog_warn ("ISIS-Spf: TENT is empty");
980 spftree
->lastrun
= time (NULL
);
984 while (listcount (spftree
->tents
) > 0)
986 node
= listhead (spftree
->tents
);
987 vertex
= getdata (node
);
988 /* Remove from tent list */
989 list_delete_node (spftree
->tents
, node
);
990 if (isis_find_vertex (spftree
->paths
, vertex
->N
.id
, vertex
->type
))
992 add_to_paths (spftree
, vertex
, area
);
993 if (vertex
->type
== VTYPE_PSEUDO_IS
||
994 vertex
->type
== VTYPE_NONPSEUDO_IS
)
996 memcpy (lsp_id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1);
997 LSP_FRAGMENT (lsp_id
) = 0;
998 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
1001 if (LSP_PSEUDO_ID (lsp_id
))
1003 isis_spf_process_pseudo_lsp (spftree
, lsp
, vertex
->d_N
,
1004 vertex
->depth
, family
);
1009 isis_spf_process_lsp (spftree
, lsp
, vertex
->d_N
,
1010 vertex
->depth
, family
);
1015 zlog_warn ("ISIS-Spf: No LSP found for %s",
1016 rawlspid_print (lsp_id
));
1021 thread_add_event (master
, isis_route_validate
, area
, 0);
1022 spftree
->lastrun
= time (NULL
);
1023 spftree
->pending
= 0;
1029 isis_run_spf_l1 (struct thread
*thread
)
1031 struct isis_area
*area
;
1032 int retval
= ISIS_OK
;
1034 area
= THREAD_ARG (thread
);
1037 area
->spftree
[0]->t_spf
= NULL
;
1039 if (!(area
->is_type
& IS_LEVEL_1
))
1041 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1042 zlog_warn ("ISIS-SPF (%s) area does not share level",
1044 return ISIS_WARNING
;
1047 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1048 zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1050 if (area
->ip_circuits
)
1051 retval
= isis_run_spf (area
, 1, AF_INET
);
1053 THREAD_TIMER_ON (master
, area
->spftree
[0]->t_spf
, isis_run_spf_l1
, area
,
1054 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1060 isis_run_spf_l2 (struct thread
*thread
)
1062 struct isis_area
*area
;
1063 int retval
= ISIS_OK
;
1065 area
= THREAD_ARG (thread
);
1068 area
->spftree
[1]->t_spf
= NULL
;
1070 if (!(area
->is_type
& IS_LEVEL_2
))
1072 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1073 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1074 return ISIS_WARNING
;
1077 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1078 zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area
->area_tag
);
1080 if (area
->ip_circuits
)
1081 retval
= isis_run_spf (area
, 2, AF_INET
);
1083 THREAD_TIMER_ON (master
, area
->spftree
[1]->t_spf
, isis_run_spf_l2
, area
,
1084 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1090 isis_spf_schedule (struct isis_area
*area
, int level
)
1092 int retval
= ISIS_OK
;
1093 struct isis_spftree
*spftree
= area
->spftree
[level
- 1];
1094 time_t diff
, now
= time (NULL
);
1096 if (spftree
->pending
)
1099 diff
= now
- spftree
->lastrun
;
1101 /* FIXME: let's wait a minute before doing the SPF */
1102 if (now
- isis
->uptime
< 60 || isis
->uptime
== 0)
1105 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
, 60);
1107 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
, 60);
1109 spftree
->pending
= 1;
1113 THREAD_TIMER_OFF (spftree
->t_spf
);
1115 if (diff
< MINIMUM_SPF_INTERVAL
)
1118 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
,
1119 MINIMUM_SPF_INTERVAL
- diff
);
1121 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
,
1122 MINIMUM_SPF_INTERVAL
- diff
);
1124 spftree
->pending
= 1;
1128 spftree
->pending
= 0;
1129 retval
= isis_run_spf (area
, level
, AF_INET
);
1131 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
,
1132 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1134 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
,
1135 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1143 isis_run_spf6_l1 (struct thread
*thread
)
1145 struct isis_area
*area
;
1146 int retval
= ISIS_OK
;
1148 area
= THREAD_ARG (thread
);
1151 area
->spftree6
[0]->t_spf
= NULL
;
1153 if (!(area
->is_type
& IS_LEVEL_1
))
1155 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1156 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1157 return ISIS_WARNING
;
1160 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1161 zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1163 if (area
->ipv6_circuits
)
1164 retval
= isis_run_spf (area
, 1, AF_INET6
);
1166 THREAD_TIMER_ON (master
, area
->spftree6
[0]->t_spf
, isis_run_spf6_l1
, area
,
1167 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1173 isis_run_spf6_l2 (struct thread
*thread
)
1175 struct isis_area
*area
;
1176 int retval
= ISIS_OK
;
1178 area
= THREAD_ARG (thread
);
1181 area
->spftree6
[1]->t_spf
= NULL
;
1183 if (!(area
->is_type
& IS_LEVEL_2
))
1185 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1186 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1187 return ISIS_WARNING
;
1190 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1191 zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area
->area_tag
);
1193 if (area
->ipv6_circuits
)
1194 retval
= isis_run_spf (area
, 2, AF_INET6
);
1196 THREAD_TIMER_ON (master
, area
->spftree6
[1]->t_spf
, isis_run_spf6_l2
, area
,
1197 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1203 isis_spf_schedule6 (struct isis_area
*area
, int level
)
1205 int retval
= ISIS_OK
;
1206 struct isis_spftree
*spftree
= area
->spftree6
[level
- 1];
1207 time_t diff
, now
= time (NULL
);
1209 if (spftree
->pending
)
1212 diff
= now
- spftree
->lastrun
;
1214 /* FIXME: let's wait a minute before doing the SPF */
1215 if (now
- isis
->uptime
< 60 || isis
->uptime
== 0)
1218 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
, 60);
1220 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
, 60);
1222 spftree
->pending
= 1;
1226 THREAD_TIMER_OFF (spftree
->t_spf
);
1228 if (diff
< MINIMUM_SPF_INTERVAL
)
1231 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
,
1232 MINIMUM_SPF_INTERVAL
- diff
);
1234 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
,
1235 MINIMUM_SPF_INTERVAL
- diff
);
1237 spftree
->pending
= 1;
1241 spftree
->pending
= 0;
1242 retval
= isis_run_spf (area
, level
, AF_INET6
);
1245 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
,
1246 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1248 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
,
1249 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1257 isis_print_paths (struct vty
*vty
, struct list
*paths
)
1259 struct listnode
*node
, *anode
;
1260 struct isis_vertex
*vertex
;
1261 struct isis_dynhn
*dyn
, *nh_dyn
= NULL
;
1262 struct isis_adjacency
*adj
;
1263 #ifdef EXTREME_DEBUG
1267 vty_out (vty
, "System Id Metric Next-Hop"
1268 " Interface SNPA%s", VTY_NEWLINE
);
1269 for (node
= listhead (paths
); node
; nextnode (node
))
1271 vertex
= getdata (node
);
1272 if (vertex
->type
!= VTYPE_NONPSEUDO_IS
)
1274 if (memcmp (vertex
->N
.id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1276 vty_out (vty
, "%s --%s", host
.name
, VTY_NEWLINE
);
1280 dyn
= dynhn_find_by_id ((u_char
*) vertex
->N
.id
);
1281 anode
= listhead (vertex
->Adj_N
);
1282 adj
= getdata (anode
);
1285 nh_dyn
= dynhn_find_by_id (adj
->sysid
);
1286 vty_out (vty
, "%-20s %-10u %-20s %-11s %-5s%s",
1287 (dyn
!= NULL
) ? dyn
->name
.name
:
1288 (u_char
*) rawlspid_print ((u_char
*) vertex
->N
.id
),
1289 vertex
->d_N
, (nh_dyn
!= NULL
) ? nh_dyn
->name
.name
:
1290 (u_char
*) rawlspid_print (adj
->sysid
),
1291 adj
->circuit
->interface
->name
,
1292 snpa_print (adj
->snpa
), VTY_NEWLINE
);
1296 vty_out (vty
, "%s %u %s", dyn
? dyn
->name
.name
:
1297 (u_char
*) rawlspid_print (vertex
->N
.id
),
1298 vertex
->d_N
, VTY_NEWLINE
);
1302 vty_out (vty
, "%s %s %u %s", vtype2string (vertex
->type
),
1303 vid2string (vertex
, buff
), vertex
->d_N
, VTY_NEWLINE
);
1308 DEFUN (show_isis_topology
,
1309 show_isis_topology_cmd
,
1310 "show isis topology",
1312 "IS-IS information\n"
1313 "IS-IS paths to Intermediate Systems\n")
1315 struct listnode
*node
;
1316 struct isis_area
*area
;
1319 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1322 for (node
= listhead (isis
->area_list
); node
; nextnode (node
))
1324 area
= getdata (node
);
1326 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1329 for (level
= 0; level
< ISIS_LEVELS
; level
++)
1331 if (area
->ip_circuits
> 0 && area
->spftree
[level
]
1332 && area
->spftree
[level
]->paths
->count
> 0)
1334 vty_out (vty
, "IS-IS paths to level-%d routers that speak IP%s",
1335 level
+ 1, VTY_NEWLINE
);
1336 isis_print_paths (vty
, area
->spftree
[level
]->paths
);
1339 if (area
->ipv6_circuits
> 0 && area
->spftree6
[level
]
1340 && area
->spftree6
[level
]->paths
->count
> 0)
1343 "IS-IS paths to level-%d routers that speak IPv6%s",
1344 level
+ 1, VTY_NEWLINE
);
1345 isis_print_paths (vty
, area
->spftree6
[level
]->paths
);
1347 #endif /* HAVE_IPV6 */
1354 DEFUN (show_isis_topology_l1
,
1355 show_isis_topology_l1_cmd
,
1356 "show isis topology level-1",
1358 "IS-IS information\n"
1359 "IS-IS paths to Intermediate Systems\n"
1360 "Paths to all level-1 routers in the area\n")
1362 struct listnode
*node
;
1363 struct isis_area
*area
;
1365 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1368 for (node
= listhead (isis
->area_list
); node
; nextnode (node
))
1370 area
= getdata (node
);
1372 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1375 if (area
->ip_circuits
> 0 && area
->spftree
[0]
1376 && area
->spftree
[0]->paths
->count
> 0)
1378 vty_out (vty
, "IS-IS paths to level-1 routers that speak IP%s",
1380 isis_print_paths (vty
, area
->spftree
[0]->paths
);
1383 if (area
->ipv6_circuits
> 0 && area
->spftree6
[0]
1384 && area
->spftree6
[0]->paths
->count
> 0)
1386 vty_out (vty
, "IS-IS paths to level-1 routers that speak IPv6%s",
1388 isis_print_paths (vty
, area
->spftree6
[0]->paths
);
1390 #endif /* HAVE_IPV6 */
1396 DEFUN (show_isis_topology_l2
,
1397 show_isis_topology_l2_cmd
,
1398 "show isis topology level-2",
1400 "IS-IS information\n"
1401 "IS-IS paths to Intermediate Systems\n"
1402 "Paths to all level-2 routers in the domain\n")
1404 struct listnode
*node
;
1405 struct isis_area
*area
;
1407 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1410 for (node
= listhead (isis
->area_list
); node
; nextnode (node
))
1412 area
= getdata (node
);
1414 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1417 if (area
->ip_circuits
> 0 && area
->spftree
[1]
1418 && area
->spftree
[1]->paths
->count
> 0)
1420 vty_out (vty
, "IS-IS paths to level-2 routers that speak IP%s",
1422 isis_print_paths (vty
, area
->spftree
[1]->paths
);
1425 if (area
->ipv6_circuits
> 0 && area
->spftree6
[1]
1426 && area
->spftree6
[1]->paths
->count
> 0)
1428 vty_out (vty
, "IS-IS paths to level-2 routers that speak IPv6%s",
1430 isis_print_paths (vty
, area
->spftree6
[1]->paths
);
1432 #endif /* HAVE_IPV6 */
1439 isis_spf_cmds_init ()
1441 install_element (VIEW_NODE
, &show_isis_topology_cmd
);
1442 install_element (VIEW_NODE
, &show_isis_topology_l1_cmd
);
1443 install_element (VIEW_NODE
, &show_isis_topology_l2_cmd
);
1445 install_element (ENABLE_NODE
, &show_isis_topology_cmd
);
1446 install_element (ENABLE_NODE
, &show_isis_topology_l1_cmd
);
1447 install_element (ENABLE_NODE
, &show_isis_topology_l2_cmd
);