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"
41 #include "isis_misc.h"
42 #include "isis_adjacency.h"
43 #include "isis_circuit.h"
47 #include "isis_dynhn.h"
49 #include "isis_route.h"
52 extern struct isis
*isis
;
53 extern struct thread_master
*master
;
54 extern struct host host
;
56 int isis_run_spf_l1 (struct thread
*thread
);
57 int isis_run_spf_l2 (struct thread
*thread
);
61 remove_excess_adjs (struct list
*adjs
)
63 struct listnode
*node
, *excess
= NULL
;
64 struct isis_adjacency
*adj
, *candidate
= NULL
;
67 for (ALL_LIST_ELEMENTS_RO (adjs
, node
, adj
))
71 candidate
= listgetdata (excess
);
73 if (candidate
->sys_type
< adj
->sys_type
)
79 if (candidate
->sys_type
> adj
->sys_type
)
82 comp
= memcmp (candidate
->sysid
, adj
->sysid
, ISIS_SYS_ID_LEN
);
92 if (candidate
->circuit
->circuit_id
> adj
->circuit
->circuit_id
)
99 if (candidate
->circuit
->circuit_id
< adj
->circuit
->circuit_id
)
102 comp
= memcmp (candidate
->snpa
, adj
->snpa
, ETH_ALEN
);
111 list_delete_node (adjs
, excess
);
118 vtype2string (enum vertextype vtype
)
122 case VTYPE_PSEUDO_IS
:
125 case VTYPE_PSEUDO_TE_IS
:
126 return "pseudo_TE-IS";
128 case VTYPE_NONPSEUDO_IS
:
131 case VTYPE_NONPSEUDO_TE_IS
:
137 case VTYPE_IPREACH_INTERNAL
:
138 return "IP internal";
140 case VTYPE_IPREACH_EXTERNAL
:
141 return "IP external";
143 case VTYPE_IPREACH_TE
:
147 case VTYPE_IP6REACH_INTERNAL
:
148 return "IP6 internal";
150 case VTYPE_IP6REACH_EXTERNAL
:
151 return "IP6 external";
153 #endif /* HAVE_IPV6 */
157 return NULL
; /* Not reached */
161 vid2string (struct isis_vertex
*vertex
, u_char
* buff
)
163 switch (vertex
->type
)
165 case VTYPE_PSEUDO_IS
:
166 case VTYPE_PSEUDO_TE_IS
:
167 return rawlspid_print (vertex
->N
.id
);
169 case VTYPE_NONPSEUDO_IS
:
170 case VTYPE_NONPSEUDO_TE_IS
:
172 return sysid_print (vertex
->N
.id
);
174 case VTYPE_IPREACH_INTERNAL
:
175 case VTYPE_IPREACH_EXTERNAL
:
176 case VTYPE_IPREACH_TE
:
178 case VTYPE_IP6REACH_INTERNAL
:
179 case VTYPE_IP6REACH_EXTERNAL
:
180 #endif /* HAVE_IPV6 */
181 prefix2str ((struct prefix
*) &vertex
->N
.prefix
, (char *) buff
, BUFSIZ
);
187 return (char *) buff
;
189 #endif /* EXTREME_DEBUG */
191 static struct isis_spftree
*
194 struct isis_spftree
*tree
;
196 tree
= XCALLOC (MTYPE_ISIS_SPFTREE
, sizeof (struct isis_spftree
));
199 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
203 tree
->tents
= list_new ();
204 tree
->paths
= list_new ();
209 isis_vertex_del (struct isis_vertex
*vertex
)
211 list_delete (vertex
->Adj_N
);
213 XFREE (MTYPE_ISIS_VERTEX
, vertex
);
218 #if 0 /* HT: Not used yet. */
220 isis_spftree_del (struct isis_spftree
*spftree
)
222 spftree
->tents
->del
= (void (*)(void *)) isis_vertex_del
;
223 list_delete (spftree
->tents
);
225 spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
226 list_delete (spftree
->paths
);
228 XFREE (MTYPE_ISIS_SPFTREE
, spftree
);
235 spftree_area_init (struct isis_area
*area
)
237 if ((area
->is_type
& IS_LEVEL_1
) && area
->spftree
[0] == NULL
)
239 area
->spftree
[0] = isis_spftree_new ();
241 area
->spftree6
[0] = isis_spftree_new ();
244 /* thread_add_timer (master, isis_run_spf_l1, area,
245 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
248 if ((area
->is_type
& IS_LEVEL_2
) && area
->spftree
[1] == NULL
)
250 area
->spftree
[1] = isis_spftree_new ();
252 area
->spftree6
[1] = isis_spftree_new ();
254 /* thread_add_timer (master, isis_run_spf_l2, area,
255 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
261 static struct isis_vertex
*
262 isis_vertex_new (void *id
, enum vertextype vtype
)
264 struct isis_vertex
*vertex
;
266 vertex
= XCALLOC (MTYPE_ISIS_VERTEX
, sizeof (struct isis_vertex
));
269 zlog_err ("isis_vertex_new Out of memory!");
273 vertex
->type
= vtype
;
277 case VTYPE_NONPSEUDO_IS
:
278 case VTYPE_NONPSEUDO_TE_IS
:
279 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
);
281 case VTYPE_PSEUDO_IS
:
282 case VTYPE_PSEUDO_TE_IS
:
283 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
+ 1);
285 case VTYPE_IPREACH_INTERNAL
:
286 case VTYPE_IPREACH_EXTERNAL
:
287 case VTYPE_IPREACH_TE
:
289 case VTYPE_IP6REACH_INTERNAL
:
290 case VTYPE_IP6REACH_EXTERNAL
:
291 #endif /* HAVE_IPV6 */
292 memcpy (&vertex
->N
.prefix
, (struct prefix
*) id
,
293 sizeof (struct prefix
));
299 vertex
->Adj_N
= list_new ();
305 * Add this IS to the root of SPT
308 isis_spf_add_self (struct isis_spftree
*spftree
, struct isis_area
*area
,
311 struct isis_vertex
*vertex
;
312 struct isis_lsp
*lsp
;
313 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
316 #endif /* EXTREME_DEBUG */
317 memcpy (lspid
, isis
->sysid
, ISIS_SYS_ID_LEN
);
318 LSP_PSEUDO_ID (lspid
) = 0;
319 LSP_FRAGMENT (lspid
) = 0;
321 lsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
324 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level
);
326 if (!area
->oldmetric
)
327 vertex
= isis_vertex_new (isis
->sysid
, VTYPE_NONPSEUDO_TE_IS
);
329 vertex
= isis_vertex_new (isis
->sysid
, VTYPE_NONPSEUDO_IS
);
333 listnode_add (spftree
->paths
, vertex
);
336 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
337 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
338 vertex
->depth
, vertex
->d_N
);
339 #endif /* EXTREME_DEBUG */
344 static struct isis_vertex
*
345 isis_find_vertex (struct list
*list
, void *id
, enum vertextype vtype
)
347 struct listnode
*node
;
348 struct isis_vertex
*vertex
;
349 struct prefix
*p1
, *p2
;
351 for (ALL_LIST_ELEMENTS_RO (list
, node
, vertex
))
353 if (vertex
->type
!= vtype
)
358 case VTYPE_NONPSEUDO_IS
:
359 case VTYPE_NONPSEUDO_TE_IS
:
360 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
) == 0)
363 case VTYPE_PSEUDO_IS
:
364 case VTYPE_PSEUDO_TE_IS
:
365 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1) == 0)
368 case VTYPE_IPREACH_INTERNAL
:
369 case VTYPE_IPREACH_EXTERNAL
:
370 case VTYPE_IPREACH_TE
:
372 case VTYPE_IP6REACH_INTERNAL
:
373 case VTYPE_IP6REACH_EXTERNAL
:
374 #endif /* HAVE_IPV6 */
375 p1
= (struct prefix
*) id
;
376 p2
= (struct prefix
*) &vertex
->N
.id
;
377 if (p1
->family
== p2
->family
&& p1
->prefixlen
== p2
->prefixlen
&&
378 memcmp (&p1
->u
.prefix
, &p2
->u
.prefix
,
379 PSIZE (p1
->prefixlen
)) == 0)
389 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
391 static struct isis_vertex
*
392 isis_spf_add2tent (struct isis_spftree
*spftree
, enum vertextype vtype
,
393 void *id
, struct isis_adjacency
*adj
, u_int32_t cost
,
394 int depth
, int family
)
396 struct isis_vertex
*vertex
, *v
;
397 struct listnode
*node
;
402 vertex
= isis_vertex_new (id
, vtype
);
404 vertex
->depth
= depth
;
407 listnode_add (vertex
->Adj_N
, adj
);
409 zlog_debug ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
410 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
411 vertex
->depth
, vertex
->d_N
);
412 #endif /* EXTREME_DEBUG */
413 listnode_add (spftree
->tents
, vertex
);
414 if (list_isempty (spftree
->tents
))
416 listnode_add (spftree
->tents
, vertex
);
420 /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */
421 for (node
= listhead (spftree
->tents
); node
; node
= listnextnode (node
))
423 v
= listgetdata (node
);
424 if (v
->d_N
> vertex
->d_N
)
426 list_add_node_prev (spftree
->tents
, node
, vertex
);
429 else if (v
->d_N
== vertex
->d_N
)
431 /* Tie break, add according to type */
432 while (v
&& v
->d_N
== vertex
->d_N
&& v
->type
> vertex
->type
)
434 if (v
->type
> vertex
->type
)
438 /* XXX: this seems dubious, node is the loop iterator */
439 node
= listnextnode (node
);
440 (node
) ? (v
= listgetdata (node
)) : (v
= NULL
);
442 list_add_node_prev (spftree
->tents
, node
, vertex
);
445 else if (node
->next
== NULL
)
447 list_add_node_next (spftree
->tents
, node
, vertex
);
454 static struct isis_vertex
*
455 isis_spf_add_local (struct isis_spftree
*spftree
, enum vertextype vtype
,
456 void *id
, struct isis_adjacency
*adj
, u_int32_t cost
,
459 struct isis_vertex
*vertex
;
461 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
466 if (vertex
->d_N
== cost
)
469 listnode_add (vertex
->Adj_N
, adj
);
471 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
472 remove_excess_adjs (vertex
->Adj_N
);
475 else if (vertex
->d_N
> cost
)
477 listnode_delete (spftree
->tents
, vertex
);
485 return isis_spf_add2tent (spftree
, vtype
, id
, adj
, cost
, 1, family
);
489 process_N (struct isis_spftree
*spftree
, enum vertextype vtype
, void *id
,
490 u_int16_t dist
, u_int16_t depth
, struct isis_adjacency
*adj
,
493 struct isis_vertex
*vertex
;
499 if (dist
> MAX_PATH_METRIC
)
502 vertex
= isis_find_vertex (spftree
->paths
, id
, vtype
);
506 zlog_debug ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
507 vtype2string (vtype
), vid2string (vertex
, buff
), dist
);
508 #endif /* EXTREME_DEBUG */
509 assert (dist
>= vertex
->d_N
);
513 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
519 zlog_debug ("ISIS-Spf: process_N %s %s dist %d",
520 vtype2string (vtype
), vid2string (vertex
, buff
), dist
);
521 #endif /* EXTREME_DEBUG */
522 if (vertex
->d_N
== dist
)
525 listnode_add (vertex
->Adj_N
, adj
);
527 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
528 remove_excess_adjs (vertex
->Adj_N
);
532 else if (vertex
->d_N
< dist
)
539 listnode_delete (spftree
->tents
, vertex
);
543 isis_spf_add2tent (spftree
, vtype
, id
, adj
, dist
, depth
, family
);
551 isis_spf_process_lsp (struct isis_spftree
*spftree
, struct isis_lsp
*lsp
,
552 uint32_t cost
, uint16_t depth
, int family
)
554 struct listnode
*node
, *fragnode
= NULL
;
556 struct is_neigh
*is_neigh
;
557 struct te_is_neigh
*te_is_neigh
;
558 struct ipv4_reachability
*ipreach
;
559 struct te_ipv4_reachability
*te_ipv4_reach
;
560 enum vertextype vtype
;
561 struct prefix prefix
;
563 struct ipv6_reachability
*ip6reach
;
564 #endif /* HAVE_IPV6 */
569 if (lsp
->tlv_data
.nlpids
== NULL
|| !speaks (lsp
->tlv_data
.nlpids
, family
))
573 if (lsp
->lsp_header
->seq_num
== 0)
575 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
576 " - do not process");
580 if (!ISIS_MASK_LSP_OL_BIT (lsp
->lsp_header
->lsp_bits
))
582 if (lsp
->tlv_data
.is_neighs
)
584 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, node
, is_neigh
))
587 /* Two way connectivity */
588 if (!memcmp (is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
590 dist
= cost
+ is_neigh
->metrics
.metric_default
;
591 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
592 : VTYPE_NONPSEUDO_IS
;
593 process_N (spftree
, vtype
, (void *) is_neigh
->neigh_id
, dist
,
594 depth
+ 1, lsp
->adj
, family
);
597 if (lsp
->tlv_data
.te_is_neighs
)
599 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_is_neighs
, node
,
603 if (!memcmp (te_is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
605 memcpy (&metric
, te_is_neigh
->te_metric
, 3);
606 dist
= cost
+ ntohl (metric
<< 8);
607 vtype
= LSP_PSEUDO_ID (te_is_neigh
->neigh_id
) ? VTYPE_PSEUDO_TE_IS
608 : VTYPE_NONPSEUDO_TE_IS
;
609 process_N (spftree
, vtype
, (void *) te_is_neigh
->neigh_id
, dist
,
610 depth
+ 1, lsp
->adj
, family
);
613 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_int_reachs
)
615 prefix
.family
= AF_INET
;
616 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_int_reachs
,
619 dist
= cost
+ ipreach
->metrics
.metric_default
;
620 vtype
= VTYPE_IPREACH_INTERNAL
;
621 prefix
.u
.prefix4
= ipreach
->prefix
;
622 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
623 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
628 if (family
== AF_INET
&& lsp
->tlv_data
.ipv4_ext_reachs
)
630 prefix
.family
= AF_INET
;
631 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv4_ext_reachs
,
634 dist
= cost
+ ipreach
->metrics
.metric_default
;
635 vtype
= VTYPE_IPREACH_EXTERNAL
;
636 prefix
.u
.prefix4
= ipreach
->prefix
;
637 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
638 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
642 if (family
== AF_INET
&& lsp
->tlv_data
.te_ipv4_reachs
)
644 prefix
.family
= AF_INET
;
645 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_ipv4_reachs
,
646 node
, te_ipv4_reach
))
648 dist
= cost
+ ntohl (te_ipv4_reach
->te_metric
);
649 vtype
= VTYPE_IPREACH_TE
;
650 prefix
.u
.prefix4
= newprefix2inaddr (&te_ipv4_reach
->prefix_start
,
651 te_ipv4_reach
->control
);
652 prefix
.prefixlen
= (te_ipv4_reach
->control
& 0x3F);
653 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
658 if (family
== AF_INET6
&& lsp
->tlv_data
.ipv6_reachs
)
660 prefix
.family
= AF_INET6
;
661 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.ipv6_reachs
,
664 dist
= cost
+ ip6reach
->metric
;
665 vtype
= (ip6reach
->control_info
& CTRL_INFO_DISTRIBUTION
) ?
666 VTYPE_IP6REACH_EXTERNAL
: VTYPE_IP6REACH_INTERNAL
;
667 prefix
.prefixlen
= ip6reach
->prefix_len
;
668 memcpy (&prefix
.u
.prefix6
.s6_addr
, ip6reach
->prefix
,
669 PSIZE (ip6reach
->prefix_len
));
670 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
674 #endif /* HAVE_IPV6 */
677 if (fragnode
== NULL
)
678 fragnode
= listhead (lsp
->lspu
.frags
);
680 fragnode
= listnextnode (fragnode
);
684 lsp
= listgetdata (fragnode
);
692 isis_spf_process_pseudo_lsp (struct isis_spftree
*spftree
,
693 struct isis_lsp
*lsp
, uint16_t cost
,
694 uint16_t depth
, int family
)
696 struct listnode
*node
, *fragnode
= NULL
;
697 struct is_neigh
*is_neigh
;
698 struct te_is_neigh
*te_is_neigh
;
699 enum vertextype vtype
;
703 if (lsp
->lsp_header
->seq_num
== 0)
705 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
706 " - do not process");
710 if (lsp
->tlv_data
.is_neighs
)
711 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, node
, is_neigh
))
713 vtype
= LSP_PSEUDO_ID (is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
714 : VTYPE_NONPSEUDO_IS
;
715 /* Two way connectivity */
716 if (!memcmp (is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
719 (spftree
->tents
, (void *) is_neigh
->neigh_id
, vtype
) == NULL
720 && isis_find_vertex (spftree
->paths
, (void *) is_neigh
->neigh_id
,
724 isis_spf_add2tent (spftree
, vtype
, is_neigh
->neigh_id
, lsp
->adj
,
725 cost
, depth
, family
);
728 if (lsp
->tlv_data
.te_is_neighs
)
729 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.te_is_neighs
, node
, te_is_neigh
))
731 vtype
= LSP_PSEUDO_ID (te_is_neigh
->neigh_id
) ? VTYPE_PSEUDO_TE_IS
732 : VTYPE_NONPSEUDO_TE_IS
;
733 /* Two way connectivity */
734 if (!memcmp (te_is_neigh
->neigh_id
, isis
->sysid
, ISIS_SYS_ID_LEN
))
737 (spftree
->tents
, (void *) te_is_neigh
->neigh_id
, vtype
) == NULL
738 && isis_find_vertex (spftree
->paths
, (void *) te_is_neigh
->neigh_id
,
742 isis_spf_add2tent (spftree
, vtype
, te_is_neigh
->neigh_id
, lsp
->adj
,
743 cost
, depth
, family
);
747 if (fragnode
== NULL
)
748 fragnode
= listhead (lsp
->lspu
.frags
);
750 fragnode
= listnextnode (fragnode
);
754 lsp
= listgetdata (fragnode
);
762 isis_spf_preload_tent (struct isis_spftree
*spftree
,
763 struct isis_area
*area
, int level
, int family
)
765 struct isis_vertex
*vertex
;
766 struct isis_circuit
*circuit
;
767 struct listnode
*cnode
, *anode
, *ipnode
;
768 struct isis_adjacency
*adj
;
769 struct isis_lsp
*lsp
;
770 struct list
*adj_list
;
772 struct prefix_ipv4
*ipv4
;
773 struct prefix prefix
;
774 int retval
= ISIS_OK
;
775 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
777 struct prefix_ipv6
*ipv6
;
778 #endif /* HAVE_IPV6 */
780 for (ALL_LIST_ELEMENTS_RO (area
->circuit_list
, cnode
, circuit
))
782 if (circuit
->state
!= C_STATE_UP
)
784 if (!(circuit
->circuit_is_type
& level
))
786 if (family
== AF_INET
&& !circuit
->ip_router
)
789 if (family
== AF_INET6
&& !circuit
->ipv6_router
)
791 #endif /* HAVE_IPV6 */
793 * Add IP(v6) addresses of this circuit
795 if (family
== AF_INET
)
797 prefix
.family
= AF_INET
;
798 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
800 prefix
.u
.prefix4
= ipv4
->prefix
;
801 prefix
.prefixlen
= ipv4
->prefixlen
;
802 isis_spf_add_local (spftree
, VTYPE_IPREACH_INTERNAL
, &prefix
,
807 if (family
== AF_INET6
)
809 prefix
.family
= AF_INET6
;
810 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
812 prefix
.prefixlen
= ipv6
->prefixlen
;
813 prefix
.u
.prefix6
= ipv6
->prefix
;
814 isis_spf_add_local (spftree
, VTYPE_IP6REACH_INTERNAL
,
815 &prefix
, NULL
, 0, family
);
818 #endif /* HAVE_IPV6 */
819 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
822 * Add the adjacencies
824 adj_list
= list_new ();
825 adjdb
= circuit
->u
.bc
.adjdb
[level
- 1];
826 isis_adj_build_up_list (adjdb
, adj_list
);
827 if (listcount (adj_list
) == 0)
829 list_delete (adj_list
);
830 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
831 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
832 level
, circuit
->interface
->name
);
835 anode
= listhead (adj_list
);
838 adj
= listgetdata (anode
);
839 if (!speaks (&adj
->nlpids
, family
))
841 anode
= listnextnode (anode
);
844 switch (adj
->sys_type
)
846 case ISIS_SYSTYPE_ES
:
847 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
848 circuit
->te_metric
[level
- 1], family
);
850 case ISIS_SYSTYPE_IS
:
851 case ISIS_SYSTYPE_L1_IS
:
852 case ISIS_SYSTYPE_L2_IS
:
854 isis_spf_add_local (spftree
, VTYPE_NONPSEUDO_IS
,
856 circuit
->te_metric
[level
- 1], family
);
857 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
858 LSP_PSEUDO_ID (lsp_id
) = 0;
859 LSP_FRAGMENT (lsp_id
) = 0;
860 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
862 zlog_warn ("No lsp found for IS adjacency");
864 isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
867 case ISIS_SYSTYPE_UNKNOWN
:
869 zlog_warn ("isis_spf_preload_tent unknow adj type");
871 anode
= listnextnode (anode
);
873 list_delete (adj_list
);
878 memcpy (lsp_id
, circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
880 memcpy (lsp_id
, circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
881 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
882 adj
= isis_adj_lookup (lsp_id
, adjdb
);
883 /* if no adj, we are the dis or error */
884 if (!adj
&& !circuit
->u
.bc
.is_dr
[level
- 1])
886 zlog_warn ("ISIS-Spf: No adjacency found for DR");
888 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
890 zlog_warn ("ISIS-Spf: No lsp found for DR");
894 isis_spf_process_pseudo_lsp (spftree
, lsp
,
895 circuit
->te_metric
[level
- 1], 0, family
);
899 else if (circuit
->circ_type
== CIRCUIT_T_P2P
)
901 adj
= circuit
->u
.p2p
.neighbor
;
904 switch (adj
->sys_type
)
906 case ISIS_SYSTYPE_ES
:
907 isis_spf_add_local (spftree
, VTYPE_ES
, adj
->sysid
, adj
,
908 circuit
->te_metric
[level
- 1], family
);
910 case ISIS_SYSTYPE_IS
:
911 case ISIS_SYSTYPE_L1_IS
:
912 case ISIS_SYSTYPE_L2_IS
:
913 if (speaks (&adj
->nlpids
, family
))
914 isis_spf_add_local (spftree
, VTYPE_NONPSEUDO_IS
, adj
->sysid
,
915 adj
, circuit
->te_metric
[level
- 1],
918 case ISIS_SYSTYPE_UNKNOWN
:
920 zlog_warn ("isis_spf_preload_tent unknow adj type");
926 zlog_warn ("isis_spf_preload_tent unsupported media");
927 retval
= ISIS_WARNING
;
936 * The parent(s) for vertex is set when added to TENT list
937 * now we just put the child pointer(s) in place
940 add_to_paths (struct isis_spftree
*spftree
, struct isis_vertex
*vertex
,
941 struct isis_area
*area
, int level
)
945 #endif /* EXTREME_DEBUG */
946 listnode_add (spftree
->paths
, vertex
);
949 zlog_debug ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
950 vtype2string (vertex
->type
), vid2string (vertex
, buff
),
951 vertex
->depth
, vertex
->d_N
);
952 #endif /* EXTREME_DEBUG */
953 if (vertex
->type
> VTYPE_ES
)
955 if (listcount (vertex
->Adj_N
) > 0)
956 isis_route_create ((struct prefix
*) &vertex
->N
.prefix
, vertex
->d_N
,
957 vertex
->depth
, vertex
->Adj_N
, area
, level
);
958 else if (isis
->debugs
& DEBUG_SPF_EVENTS
)
959 zlog_debug ("ISIS-Spf: no adjacencies do not install route");
966 init_spt (struct isis_spftree
*spftree
)
968 spftree
->tents
->del
= spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
969 list_delete_all_node (spftree
->tents
);
970 list_delete_all_node (spftree
->paths
);
971 spftree
->tents
->del
= spftree
->paths
->del
= NULL
;
977 isis_run_spf (struct isis_area
*area
, int level
, int family
)
979 int retval
= ISIS_OK
;
980 struct listnode
*node
;
981 struct isis_vertex
*vertex
;
982 struct isis_spftree
*spftree
= NULL
;
983 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
984 struct isis_lsp
*lsp
;
985 struct route_table
*table
= NULL
;
986 struct route_node
*rode
;
987 struct isis_route_info
*rinfo
;
989 if (family
== AF_INET
)
990 spftree
= area
->spftree
[level
- 1];
992 else if (family
== AF_INET6
)
993 spftree
= area
->spftree6
[level
- 1];
998 /* Make all routes in current route table inactive. */
999 if (family
== AF_INET
)
1000 table
= area
->route_table
[level
- 1];
1002 else if (family
== AF_INET6
)
1003 table
= area
->route_table6
[level
- 1];
1006 for (rode
= route_top (table
); rode
; rode
= route_next (rode
))
1008 if (rode
->info
== NULL
)
1012 UNSET_FLAG (rinfo
->flag
, ISIS_ROUTE_FLAG_ACTIVE
);
1020 isis_spf_add_self (spftree
, area
, level
);
1022 retval
= isis_spf_preload_tent (spftree
, area
, level
, family
);
1027 if (listcount (spftree
->tents
) == 0)
1029 zlog_warn ("ISIS-Spf: TENT is empty");
1033 while (listcount (spftree
->tents
) > 0)
1035 node
= listhead (spftree
->tents
);
1036 vertex
= listgetdata (node
);
1037 /* Remove from tent list */
1038 list_delete_node (spftree
->tents
, node
);
1039 if (isis_find_vertex (spftree
->paths
, vertex
->N
.id
, vertex
->type
))
1041 add_to_paths (spftree
, vertex
, area
, level
);
1042 if (vertex
->type
== VTYPE_PSEUDO_IS
||
1043 vertex
->type
== VTYPE_NONPSEUDO_IS
)
1045 memcpy (lsp_id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1);
1046 LSP_FRAGMENT (lsp_id
) = 0;
1047 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
1050 if (LSP_PSEUDO_ID (lsp_id
))
1052 isis_spf_process_pseudo_lsp (spftree
, lsp
, vertex
->d_N
,
1053 vertex
->depth
, family
);
1058 isis_spf_process_lsp (spftree
, lsp
, vertex
->d_N
,
1059 vertex
->depth
, family
);
1064 zlog_warn ("ISIS-Spf: No LSP found for %s",
1065 rawlspid_print (lsp_id
));
1071 thread_add_event (master
, isis_route_validate
, area
, 0);
1072 spftree
->lastrun
= time (NULL
);
1073 spftree
->pending
= 0;
1079 isis_run_spf_l1 (struct thread
*thread
)
1081 struct isis_area
*area
;
1082 int retval
= ISIS_OK
;
1084 area
= THREAD_ARG (thread
);
1087 area
->spftree
[0]->t_spf
= NULL
;
1089 if (!(area
->is_type
& IS_LEVEL_1
))
1091 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1092 zlog_warn ("ISIS-SPF (%s) area does not share level",
1094 return ISIS_WARNING
;
1097 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1098 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1100 if (area
->ip_circuits
)
1101 retval
= isis_run_spf (area
, 1, AF_INET
);
1103 THREAD_TIMER_ON (master
, area
->spftree
[0]->t_spf
, isis_run_spf_l1
, area
,
1104 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1110 isis_run_spf_l2 (struct thread
*thread
)
1112 struct isis_area
*area
;
1113 int retval
= ISIS_OK
;
1115 area
= THREAD_ARG (thread
);
1118 area
->spftree
[1]->t_spf
= NULL
;
1120 if (!(area
->is_type
& IS_LEVEL_2
))
1122 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1123 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1124 return ISIS_WARNING
;
1127 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1128 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area
->area_tag
);
1130 if (area
->ip_circuits
)
1131 retval
= isis_run_spf (area
, 2, AF_INET
);
1133 THREAD_TIMER_ON (master
, area
->spftree
[1]->t_spf
, isis_run_spf_l2
, area
,
1134 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1140 isis_spf_schedule (struct isis_area
*area
, int level
)
1142 int retval
= ISIS_OK
;
1143 struct isis_spftree
*spftree
= area
->spftree
[level
- 1];
1144 time_t diff
, now
= time (NULL
);
1146 if (spftree
->pending
)
1149 diff
= now
- spftree
->lastrun
;
1151 /* FIXME: let's wait a minute before doing the SPF */
1152 if (now
- isis
->uptime
< 60 || isis
->uptime
== 0)
1155 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
, 60);
1157 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
, 60);
1159 spftree
->pending
= 1;
1163 THREAD_TIMER_OFF (spftree
->t_spf
);
1165 if (diff
< MINIMUM_SPF_INTERVAL
)
1168 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
,
1169 MINIMUM_SPF_INTERVAL
- diff
);
1171 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
,
1172 MINIMUM_SPF_INTERVAL
- diff
);
1174 spftree
->pending
= 1;
1178 spftree
->pending
= 0;
1179 retval
= isis_run_spf (area
, level
, AF_INET
);
1181 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l1
, area
,
1182 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1184 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf_l2
, area
,
1185 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1193 isis_run_spf6_l1 (struct thread
*thread
)
1195 struct isis_area
*area
;
1196 int retval
= ISIS_OK
;
1198 area
= THREAD_ARG (thread
);
1201 area
->spftree6
[0]->t_spf
= NULL
;
1203 if (!(area
->is_type
& IS_LEVEL_1
))
1205 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1206 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1207 return ISIS_WARNING
;
1210 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1211 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area
->area_tag
);
1213 if (area
->ipv6_circuits
)
1214 retval
= isis_run_spf (area
, 1, AF_INET6
);
1216 THREAD_TIMER_ON (master
, area
->spftree6
[0]->t_spf
, isis_run_spf6_l1
, area
,
1217 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1223 isis_run_spf6_l2 (struct thread
*thread
)
1225 struct isis_area
*area
;
1226 int retval
= ISIS_OK
;
1228 area
= THREAD_ARG (thread
);
1231 area
->spftree6
[1]->t_spf
= NULL
;
1233 if (!(area
->is_type
& IS_LEVEL_2
))
1235 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1236 zlog_warn ("ISIS-SPF (%s) area does not share level", area
->area_tag
);
1237 return ISIS_WARNING
;
1240 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1241 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area
->area_tag
);
1243 if (area
->ipv6_circuits
)
1244 retval
= isis_run_spf (area
, 2, AF_INET6
);
1246 THREAD_TIMER_ON (master
, area
->spftree6
[1]->t_spf
, isis_run_spf6_l2
, area
,
1247 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1253 isis_spf_schedule6 (struct isis_area
*area
, int level
)
1255 int retval
= ISIS_OK
;
1256 struct isis_spftree
*spftree
= area
->spftree6
[level
- 1];
1257 time_t diff
, now
= time (NULL
);
1259 if (spftree
->pending
)
1262 diff
= now
- spftree
->lastrun
;
1264 /* FIXME: let's wait a minute before doing the SPF */
1265 if (now
- isis
->uptime
< 60 || isis
->uptime
== 0)
1268 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
, 60);
1270 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
, 60);
1272 spftree
->pending
= 1;
1276 THREAD_TIMER_OFF (spftree
->t_spf
);
1278 if (diff
< MINIMUM_SPF_INTERVAL
)
1281 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
,
1282 MINIMUM_SPF_INTERVAL
- diff
);
1284 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
,
1285 MINIMUM_SPF_INTERVAL
- diff
);
1287 spftree
->pending
= 1;
1291 spftree
->pending
= 0;
1292 retval
= isis_run_spf (area
, level
, AF_INET6
);
1295 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l1
, area
,
1296 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1298 THREAD_TIMER_ON (master
, spftree
->t_spf
, isis_run_spf6_l2
, area
,
1299 isis_jitter (PERIODIC_SPF_INTERVAL
, 10));
1307 isis_print_paths (struct vty
*vty
, struct list
*paths
)
1309 struct listnode
*node
;
1310 struct isis_vertex
*vertex
;
1311 struct isis_dynhn
*dyn
, *nh_dyn
= NULL
;
1312 struct isis_adjacency
*adj
;
1317 vty_out (vty
, "System Id Metric Next-Hop"
1318 " Interface SNPA%s", VTY_NEWLINE
);
1320 for (ALL_LIST_ELEMENTS_RO (paths
, node
, vertex
))
1322 if (vertex
->type
!= VTYPE_NONPSEUDO_IS
)
1324 if (memcmp (vertex
->N
.id
, isis
->sysid
, ISIS_SYS_ID_LEN
) == 0)
1326 vty_out (vty
, "%s --%s", host
.name
?host
.name
:"",
1331 dyn
= dynhn_find_by_id ((u_char
*) vertex
->N
.id
);
1332 adj
= listgetdata (listhead (vertex
->Adj_N
));
1335 nh_dyn
= dynhn_find_by_id (adj
->sysid
);
1336 vty_out (vty
, "%-20s %-10u %-20s %-11s %-5s%s",
1337 (dyn
!= NULL
) ? dyn
->name
.name
:
1338 (const u_char
*)rawlspid_print ((u_char
*) vertex
->N
.id
),
1339 vertex
->d_N
, (nh_dyn
!= NULL
) ? nh_dyn
->name
.name
:
1340 (const u_char
*)rawlspid_print (adj
->sysid
),
1341 adj
->circuit
->interface
->name
,
1342 snpa_print (adj
->snpa
), VTY_NEWLINE
);
1346 vty_out (vty
, "%s %u %s", dyn
? dyn
->name
.name
:
1347 (const u_char
*) rawlspid_print (vertex
->N
.id
),
1348 vertex
->d_N
, VTY_NEWLINE
);
1352 vty_out (vty
, "%s %s %u %s", vtype2string (vertex
->type
),
1353 vid2string (vertex
, buff
), vertex
->d_N
, VTY_NEWLINE
);
1358 DEFUN (show_isis_topology
,
1359 show_isis_topology_cmd
,
1360 "show isis topology",
1362 "IS-IS information\n"
1363 "IS-IS paths to Intermediate Systems\n")
1365 struct listnode
*node
;
1366 struct isis_area
*area
;
1369 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1372 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1374 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1377 for (level
= 0; level
< ISIS_LEVELS
; level
++)
1379 if (area
->ip_circuits
> 0 && area
->spftree
[level
]
1380 && area
->spftree
[level
]->paths
->count
> 0)
1382 vty_out (vty
, "IS-IS paths to level-%d routers that speak IP%s",
1383 level
+ 1, VTY_NEWLINE
);
1384 isis_print_paths (vty
, area
->spftree
[level
]->paths
);
1387 if (area
->ipv6_circuits
> 0 && area
->spftree6
[level
]
1388 && area
->spftree6
[level
]->paths
->count
> 0)
1391 "IS-IS paths to level-%d routers that speak IPv6%s",
1392 level
+ 1, VTY_NEWLINE
);
1393 isis_print_paths (vty
, area
->spftree6
[level
]->paths
);
1395 #endif /* HAVE_IPV6 */
1402 DEFUN (show_isis_topology_l1
,
1403 show_isis_topology_l1_cmd
,
1404 "show isis topology level-1",
1406 "IS-IS information\n"
1407 "IS-IS paths to Intermediate Systems\n"
1408 "Paths to all level-1 routers in the area\n")
1410 struct listnode
*node
;
1411 struct isis_area
*area
;
1413 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1416 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1418 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1421 if (area
->ip_circuits
> 0 && area
->spftree
[0]
1422 && area
->spftree
[0]->paths
->count
> 0)
1424 vty_out (vty
, "IS-IS paths to level-1 routers that speak IP%s",
1426 isis_print_paths (vty
, area
->spftree
[0]->paths
);
1429 if (area
->ipv6_circuits
> 0 && area
->spftree6
[0]
1430 && area
->spftree6
[0]->paths
->count
> 0)
1432 vty_out (vty
, "IS-IS paths to level-1 routers that speak IPv6%s",
1434 isis_print_paths (vty
, area
->spftree6
[0]->paths
);
1436 #endif /* HAVE_IPV6 */
1442 DEFUN (show_isis_topology_l2
,
1443 show_isis_topology_l2_cmd
,
1444 "show isis topology level-2",
1446 "IS-IS information\n"
1447 "IS-IS paths to Intermediate Systems\n"
1448 "Paths to all level-2 routers in the domain\n")
1450 struct listnode
*node
;
1451 struct isis_area
*area
;
1453 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1456 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1458 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1461 if (area
->ip_circuits
> 0 && area
->spftree
[1]
1462 && area
->spftree
[1]->paths
->count
> 0)
1464 vty_out (vty
, "IS-IS paths to level-2 routers that speak IP%s",
1466 isis_print_paths (vty
, area
->spftree
[1]->paths
);
1469 if (area
->ipv6_circuits
> 0 && area
->spftree6
[1]
1470 && area
->spftree6
[1]->paths
->count
> 0)
1472 vty_out (vty
, "IS-IS paths to level-2 routers that speak IPv6%s",
1474 isis_print_paths (vty
, area
->spftree6
[1]->paths
);
1476 #endif /* HAVE_IPV6 */
1483 isis_spf_cmds_init ()
1485 install_element (VIEW_NODE
, &show_isis_topology_cmd
);
1486 install_element (VIEW_NODE
, &show_isis_topology_l1_cmd
);
1487 install_element (VIEW_NODE
, &show_isis_topology_l2_cmd
);
1489 install_element (ENABLE_NODE
, &show_isis_topology_cmd
);
1490 install_element (ENABLE_NODE
, &show_isis_topology_l1_cmd
);
1491 install_element (ENABLE_NODE
, &show_isis_topology_l2_cmd
);