]>
git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_spf.c
ca268cec7e3843fa1fa8202f47767824b9a37435
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
8 * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public Licenseas published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37 #include "spf_backoff.h"
39 #include "isis_constants.h"
40 #include "isis_common.h"
41 #include "isis_flags.h"
44 #include "isis_misc.h"
45 #include "isis_adjacency.h"
46 #include "isis_circuit.h"
50 #include "isis_dynhn.h"
52 #include "isis_route.h"
56 DEFINE_MTYPE_STATIC(ISISD
, ISIS_SPF_RUN
, "ISIS SPF Run Info");
59 struct isis_area
*area
;
65 remove_excess_adjs (struct list
*adjs
)
67 struct listnode
*node
, *excess
= NULL
;
68 struct isis_adjacency
*adj
, *candidate
= NULL
;
71 for (ALL_LIST_ELEMENTS_RO (adjs
, node
, adj
))
75 candidate
= listgetdata (excess
);
77 if (candidate
->sys_type
< adj
->sys_type
)
82 if (candidate
->sys_type
> adj
->sys_type
)
85 comp
= memcmp (candidate
->sysid
, adj
->sysid
, ISIS_SYS_ID_LEN
);
94 if (candidate
->circuit
->circuit_id
> adj
->circuit
->circuit_id
)
100 if (candidate
->circuit
->circuit_id
< adj
->circuit
->circuit_id
)
103 comp
= memcmp (candidate
->snpa
, adj
->snpa
, ETH_ALEN
);
111 list_delete_node (adjs
, excess
);
117 vtype2string (enum vertextype vtype
)
121 case VTYPE_PSEUDO_IS
:
124 case VTYPE_PSEUDO_TE_IS
:
125 return "pseudo_TE-IS";
127 case VTYPE_NONPSEUDO_IS
:
130 case VTYPE_NONPSEUDO_TE_IS
:
136 case VTYPE_IPREACH_INTERNAL
:
137 return "IP internal";
139 case VTYPE_IPREACH_EXTERNAL
:
140 return "IP external";
142 case VTYPE_IPREACH_TE
:
145 case VTYPE_IP6REACH_INTERNAL
:
146 return "IP6 internal";
148 case VTYPE_IP6REACH_EXTERNAL
:
149 return "IP6 external";
154 return NULL
; /* Not reached */
158 vid2string (struct isis_vertex
*vertex
, char * buff
, int size
)
160 if (VTYPE_IS(vertex
->type
) || VTYPE_ES(vertex
->type
))
162 return print_sys_hostname (vertex
->N
.id
);
165 if (VTYPE_IP(vertex
->type
))
167 prefix2str ((struct prefix
*) &vertex
->N
.prefix
, buff
, size
);
174 static struct isis_vertex
*
175 isis_vertex_new (void *id
, enum vertextype vtype
)
177 struct isis_vertex
*vertex
;
179 vertex
= XCALLOC (MTYPE_ISIS_VERTEX
, sizeof (struct isis_vertex
));
181 vertex
->type
= vtype
;
183 if (VTYPE_IS(vtype
) || VTYPE_ES(vtype
))
185 memcpy (vertex
->N
.id
, (u_char
*) id
, ISIS_SYS_ID_LEN
+ 1);
187 else if (VTYPE_IP(vtype
))
189 memcpy (&vertex
->N
.prefix
, (struct prefix
*) id
, sizeof (struct prefix
));
196 vertex
->Adj_N
= list_new ();
197 vertex
->parents
= list_new ();
198 vertex
->children
= list_new ();
204 isis_vertex_del (struct isis_vertex
*vertex
)
206 list_delete (vertex
->Adj_N
);
207 vertex
->Adj_N
= NULL
;
208 list_delete (vertex
->parents
);
209 vertex
->parents
= NULL
;
210 list_delete (vertex
->children
);
211 vertex
->children
= NULL
;
213 memset(vertex
, 0, sizeof(struct isis_vertex
));
214 XFREE (MTYPE_ISIS_VERTEX
, vertex
);
220 isis_vertex_adj_del (struct isis_vertex
*vertex
, struct isis_adjacency
*adj
)
222 struct listnode
*node
, *nextnode
;
225 for (node
= listhead (vertex
->Adj_N
); node
; node
= nextnode
)
227 nextnode
= listnextnode(node
);
228 if (listgetdata(node
) == adj
)
229 list_delete_node(vertex
->Adj_N
, node
);
234 struct isis_spftree
*
235 isis_spftree_new (struct isis_area
*area
)
237 struct isis_spftree
*tree
;
239 tree
= XCALLOC (MTYPE_ISIS_SPFTREE
, sizeof (struct isis_spftree
));
242 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
246 tree
->tents
= list_new ();
247 tree
->paths
= list_new ();
249 tree
->last_run_timestamp
= 0;
250 tree
->last_run_duration
= 0;
256 isis_spftree_del (struct isis_spftree
*spftree
)
259 spftree
->tents
->del
= (void (*)(void *)) isis_vertex_del
;
260 list_delete (spftree
->tents
);
261 spftree
->tents
= NULL
;
263 spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
264 list_delete (spftree
->paths
);
265 spftree
->paths
= NULL
;
267 XFREE (MTYPE_ISIS_SPFTREE
, spftree
);
273 isis_spftree_adj_del (struct isis_spftree
*spftree
, struct isis_adjacency
*adj
)
275 struct listnode
*node
;
278 for (node
= listhead (spftree
->tents
); node
; node
= listnextnode (node
))
279 isis_vertex_adj_del (listgetdata (node
), adj
);
280 for (node
= listhead (spftree
->paths
); node
; node
= listnextnode (node
))
281 isis_vertex_adj_del (listgetdata (node
), adj
);
286 spftree_area_init (struct isis_area
*area
)
288 if (area
->is_type
& IS_LEVEL_1
)
290 if (area
->spftree
[0] == NULL
)
291 area
->spftree
[0] = isis_spftree_new (area
);
292 if (area
->spftree6
[0] == NULL
)
293 area
->spftree6
[0] = isis_spftree_new (area
);
296 if (area
->is_type
& IS_LEVEL_2
)
298 if (area
->spftree
[1] == NULL
)
299 area
->spftree
[1] = isis_spftree_new (area
);
300 if (area
->spftree6
[1] == NULL
)
301 area
->spftree6
[1] = isis_spftree_new (area
);
308 spftree_area_del (struct isis_area
*area
)
310 if (area
->is_type
& IS_LEVEL_1
)
312 if (area
->spftree
[0] != NULL
)
314 isis_spftree_del (area
->spftree
[0]);
315 area
->spftree
[0] = NULL
;
317 if (area
->spftree6
[0])
319 isis_spftree_del (area
->spftree6
[0]);
320 area
->spftree6
[0] = NULL
;
324 if (area
->is_type
& IS_LEVEL_2
)
326 if (area
->spftree
[1] != NULL
)
328 isis_spftree_del (area
->spftree
[1]);
329 area
->spftree
[1] = NULL
;
331 if (area
->spftree6
[1] != NULL
)
333 isis_spftree_del (area
->spftree6
[1]);
334 area
->spftree6
[1] = NULL
;
342 spftree_area_adj_del (struct isis_area
*area
, struct isis_adjacency
*adj
)
344 if (area
->is_type
& IS_LEVEL_1
)
346 if (area
->spftree
[0] != NULL
)
347 isis_spftree_adj_del (area
->spftree
[0], adj
);
348 if (area
->spftree6
[0] != NULL
)
349 isis_spftree_adj_del (area
->spftree6
[0], adj
);
352 if (area
->is_type
& IS_LEVEL_2
)
354 if (area
->spftree
[1] != NULL
)
355 isis_spftree_adj_del (area
->spftree
[1], adj
);
356 if (area
->spftree6
[1] != NULL
)
357 isis_spftree_adj_del (area
->spftree6
[1], adj
);
364 * Find the system LSP: returns the LSP in our LSP database
365 * associated with the given system ID.
367 static struct isis_lsp
*
368 isis_root_system_lsp (struct isis_area
*area
, int level
, u_char
*sysid
)
370 struct isis_lsp
*lsp
;
371 u_char lspid
[ISIS_SYS_ID_LEN
+ 2];
373 memcpy (lspid
, sysid
, ISIS_SYS_ID_LEN
);
374 LSP_PSEUDO_ID (lspid
) = 0;
375 LSP_FRAGMENT (lspid
) = 0;
376 lsp
= lsp_search (lspid
, area
->lspdb
[level
- 1]);
377 if (lsp
&& lsp
->lsp_header
->rem_lifetime
!= 0)
383 * Add this IS to the root of SPT
385 static struct isis_vertex
*
386 isis_spf_add_root (struct isis_spftree
*spftree
, u_char
*sysid
)
388 struct isis_vertex
*vertex
;
389 struct isis_lsp
*lsp
;
391 char buff
[PREFIX2STR_BUFFER
];
392 #endif /* EXTREME_DEBUG */
393 u_char id
[ISIS_SYS_ID_LEN
+ 1];
395 memcpy(id
, sysid
, ISIS_SYS_ID_LEN
);
396 LSP_PSEUDO_ID(id
) = 0;
398 lsp
= isis_root_system_lsp (spftree
->area
, spftree
->level
, sysid
);
400 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", spftree
->level
);
402 vertex
= isis_vertex_new (id
, spftree
->area
->oldmetric
? VTYPE_NONPSEUDO_IS
403 : VTYPE_NONPSEUDO_TE_IS
);
404 listnode_add (spftree
->paths
, vertex
);
407 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
408 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
409 vertex
->depth
, vertex
->d_N
);
410 #endif /* EXTREME_DEBUG */
415 static struct isis_vertex
*
416 isis_find_vertex (struct list
*list
, void *id
, enum vertextype vtype
)
418 struct listnode
*node
;
419 struct isis_vertex
*vertex
;
420 struct prefix
*p1
, *p2
;
422 for (ALL_LIST_ELEMENTS_RO (list
, node
, vertex
))
424 if (vertex
->type
!= vtype
)
426 if (VTYPE_IS(vertex
->type
) || VTYPE_ES(vertex
->type
))
428 if (memcmp ((u_char
*) id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1) == 0)
431 if (VTYPE_IP(vertex
->type
))
433 p1
= (struct prefix
*) id
;
434 p2
= (struct prefix
*) &vertex
->N
.id
;
435 if (p1
->family
== p2
->family
436 && p1
->prefixlen
== p2
->prefixlen
437 && !memcmp(&p1
->u
.prefix
, &p2
->u
.prefix
, PSIZE (p1
->prefixlen
)))
448 * Compares vertizes for sorting in the TENT list. Returns true
449 * if candidate should be considered before current, false otherwise.
452 tent_cmp (struct isis_vertex
*current
, struct isis_vertex
*candidate
)
454 if (current
->d_N
> candidate
->d_N
)
457 if (current
->d_N
== candidate
->d_N
458 && current
->type
> candidate
->type
)
465 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
467 static struct isis_vertex
*
468 isis_spf_add2tent (struct isis_spftree
*spftree
, enum vertextype vtype
,
469 void *id
, uint32_t cost
, int depth
,
470 struct isis_adjacency
*adj
, struct isis_vertex
*parent
)
472 struct isis_vertex
*vertex
, *v
;
473 struct listnode
*node
;
474 struct isis_adjacency
*parent_adj
;
476 char buff
[PREFIX2STR_BUFFER
];
479 assert (isis_find_vertex (spftree
->paths
, id
, vtype
) == NULL
);
480 assert (isis_find_vertex (spftree
->tents
, id
, vtype
) == NULL
);
481 vertex
= isis_vertex_new (id
, vtype
);
483 vertex
->depth
= depth
;
486 listnode_add (vertex
->parents
, parent
);
487 if (listnode_lookup (parent
->children
, vertex
) == NULL
)
488 listnode_add (parent
->children
, vertex
);
491 if (parent
&& parent
->Adj_N
&& listcount(parent
->Adj_N
) > 0) {
492 for (ALL_LIST_ELEMENTS_RO (parent
->Adj_N
, node
, parent_adj
))
493 listnode_add (vertex
->Adj_N
, parent_adj
);
495 listnode_add (vertex
->Adj_N
, adj
);
499 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
500 print_sys_hostname (vertex
->N
.id
),
501 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
502 vertex
->depth
, vertex
->d_N
, listcount(vertex
->Adj_N
));
503 #endif /* EXTREME_DEBUG */
505 if (list_isempty (spftree
->tents
))
507 listnode_add (spftree
->tents
, vertex
);
511 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
512 for (node
= listhead (spftree
->tents
); node
; node
= listnextnode (node
))
514 v
= listgetdata (node
);
515 if (tent_cmp(v
, vertex
))
517 listnode_add_before (spftree
->tents
, node
, vertex
);
523 listnode_add (spftree
->tents
, vertex
);
529 isis_spf_add_local (struct isis_spftree
*spftree
, enum vertextype vtype
,
530 void *id
, struct isis_adjacency
*adj
, uint32_t cost
,
531 struct isis_vertex
*parent
)
533 struct isis_vertex
*vertex
;
535 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
540 if (vertex
->d_N
== cost
)
543 listnode_add (vertex
->Adj_N
, adj
);
545 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
546 remove_excess_adjs (vertex
->Adj_N
);
547 if (parent
&& (listnode_lookup (vertex
->parents
, parent
) == NULL
))
548 listnode_add (vertex
->parents
, parent
);
549 if (parent
&& (listnode_lookup (parent
->children
, vertex
) == NULL
))
550 listnode_add (parent
->children
, vertex
);
553 else if (vertex
->d_N
< cost
)
558 else { /* vertex->d_N > cost */
560 struct listnode
*pnode
, *pnextnode
;
561 struct isis_vertex
*pvertex
;
562 listnode_delete (spftree
->tents
, vertex
);
563 assert (listcount (vertex
->children
) == 0);
564 for (ALL_LIST_ELEMENTS (vertex
->parents
, pnode
, pnextnode
, pvertex
))
565 listnode_delete(pvertex
->children
, vertex
);
566 isis_vertex_del (vertex
);
570 isis_spf_add2tent (spftree
, vtype
, id
, cost
, 1, adj
, parent
);
575 process_N (struct isis_spftree
*spftree
, enum vertextype vtype
, void *id
,
576 uint32_t dist
, uint16_t depth
,
577 struct isis_vertex
*parent
)
579 struct isis_vertex
*vertex
;
581 char buff
[PREFIX2STR_BUFFER
];
584 assert (spftree
&& parent
);
586 /* RFC3787 section 5.1 */
587 if (spftree
->area
->newmetric
== 1)
589 if (dist
> MAX_WIDE_PATH_METRIC
)
593 else if (spftree
->area
->oldmetric
== 1)
595 if (dist
> MAX_NARROW_PATH_METRIC
)
600 vertex
= isis_find_vertex (spftree
->paths
, id
, vtype
);
604 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
605 print_sys_hostname (vertex
->N
.id
),
606 vtype2string (vtype
), vid2string (vertex
, buff
, sizeof (buff
)), dist
);
607 #endif /* EXTREME_DEBUG */
608 assert (dist
>= vertex
->d_N
);
612 vertex
= isis_find_vertex (spftree
->tents
, id
, vtype
);
618 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
619 print_sys_hostname (vertex
->N
.id
),
620 vtype2string (vtype
), vid2string (vertex
, buff
, sizeof (buff
)), dist
,
621 (parent
? print_sys_hostname (parent
->N
.id
) : "null"),
622 (parent
? listcount (parent
->Adj_N
) : 0));
623 #endif /* EXTREME_DEBUG */
624 if (vertex
->d_N
== dist
)
626 struct listnode
*node
;
627 struct isis_adjacency
*parent_adj
;
628 for (ALL_LIST_ELEMENTS_RO (parent
->Adj_N
, node
, parent_adj
))
629 if (listnode_lookup(vertex
->Adj_N
, parent_adj
) == NULL
)
630 listnode_add (vertex
->Adj_N
, parent_adj
);
632 if (listcount (vertex
->Adj_N
) > ISIS_MAX_PATH_SPLITS
)
633 remove_excess_adjs (vertex
->Adj_N
);
634 if (listnode_lookup (vertex
->parents
, parent
) == NULL
)
635 listnode_add (vertex
->parents
, parent
);
636 if (listnode_lookup (parent
->children
, vertex
) == NULL
)
637 listnode_add (parent
->children
, vertex
);
641 else if (vertex
->d_N
< dist
)
648 struct listnode
*pnode
, *pnextnode
;
649 struct isis_vertex
*pvertex
;
650 listnode_delete (spftree
->tents
, vertex
);
651 assert (listcount (vertex
->children
) == 0);
652 for (ALL_LIST_ELEMENTS (vertex
->parents
, pnode
, pnextnode
, pvertex
))
653 listnode_delete(pvertex
->children
, vertex
);
654 isis_vertex_del (vertex
);
659 zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
660 print_sys_hostname(id
), vtype2string (vtype
), dist
,
661 (parent
? print_sys_hostname (parent
->N
.id
) : "null"));
662 #endif /* EXTREME_DEBUG */
664 isis_spf_add2tent (spftree
, vtype
, id
, dist
, depth
, NULL
, parent
);
672 isis_spf_process_lsp (struct isis_spftree
*spftree
, struct isis_lsp
*lsp
,
673 uint32_t cost
, uint16_t depth
,
674 u_char
*root_sysid
, struct isis_vertex
*parent
)
676 bool pseudo_lsp
= LSP_PSEUDO_ID(lsp
->lsp_header
->lsp_id
);
677 struct listnode
*node
, *fragnode
= NULL
;
679 struct is_neigh
*is_neigh
;
680 struct te_is_neigh
*te_is_neigh
;
681 struct ipv4_reachability
*ipreach
;
682 struct te_ipv4_reachability
*te_ipv4_reach
;
683 enum vertextype vtype
;
684 struct prefix prefix
;
685 struct ipv6_reachability
*ip6reach
;
686 static const u_char null_sysid
[ISIS_SYS_ID_LEN
];
687 struct mt_router_info
*mt_router_info
= NULL
;
689 if (spftree
->mtid
!= ISIS_MT_IPV4_UNICAST
)
690 mt_router_info
= tlvs_lookup_mt_router_info(&lsp
->tlv_data
, spftree
->mtid
);
693 && (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
&& !speaks(lsp
->tlv_data
.nlpids
, spftree
->family
))
698 if (lsp
->lsp_header
->seq_num
== 0)
700 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
705 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp
->lsp_header
->lsp_id
));
706 #endif /* EXTREME_DEBUG */
708 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
710 || (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
&& !ISIS_MASK_LSP_OL_BIT (lsp
->lsp_header
->lsp_bits
))
711 || (mt_router_info
&& !mt_router_info
->overload
))
714 if (pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
716 for (ALL_LIST_ELEMENTS_RO (lsp
->tlv_data
.is_neighs
, node
, is_neigh
))
719 /* Two way connectivity */
720 if (!memcmp (is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
722 if (!pseudo_lsp
&& !memcmp (is_neigh
->neigh_id
, null_sysid
, ISIS_SYS_ID_LEN
))
724 dist
= cost
+ is_neigh
->metrics
.metric_default
;
725 process_N (spftree
, LSP_PSEUDO_ID(is_neigh
->neigh_id
) ? VTYPE_PSEUDO_IS
726 : VTYPE_NONPSEUDO_IS
,
727 (void *) is_neigh
->neigh_id
, dist
, depth
+ 1, parent
);
731 struct list
*te_is_neighs
= NULL
;
732 if (pseudo_lsp
|| spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
734 te_is_neighs
= lsp
->tlv_data
.te_is_neighs
;
738 struct tlv_mt_neighbors
*mt_neighbors
;
739 mt_neighbors
= tlvs_lookup_mt_neighbors(&lsp
->tlv_data
, spftree
->mtid
);
741 te_is_neighs
= mt_neighbors
->list
;
743 for (ALL_LIST_ELEMENTS_RO (te_is_neighs
, node
, te_is_neigh
))
745 if (!memcmp (te_is_neigh
->neigh_id
, root_sysid
, ISIS_SYS_ID_LEN
))
747 if (!pseudo_lsp
&& !memcmp (te_is_neigh
->neigh_id
, null_sysid
, ISIS_SYS_ID_LEN
))
749 dist
= cost
+ GET_TE_METRIC(te_is_neigh
);
750 process_N (spftree
, LSP_PSEUDO_ID(te_is_neigh
->neigh_id
) ? VTYPE_PSEUDO_TE_IS
751 : VTYPE_NONPSEUDO_TE_IS
,
752 (void *) te_is_neigh
->neigh_id
, dist
, depth
+ 1, parent
);
757 && spftree
->family
== AF_INET
758 && spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
760 struct list
*reachs
[] = {lsp
->tlv_data
.ipv4_int_reachs
,
761 lsp
->tlv_data
.ipv4_ext_reachs
};
763 prefix
.family
= AF_INET
;
764 for (unsigned int i
= 0; i
< array_size(reachs
); i
++)
766 vtype
= (reachs
[i
] == lsp
->tlv_data
.ipv4_int_reachs
) ? VTYPE_IPREACH_INTERNAL
767 : VTYPE_IPREACH_EXTERNAL
;
768 for (ALL_LIST_ELEMENTS_RO (reachs
[i
], node
, ipreach
))
770 dist
= cost
+ ipreach
->metrics
.metric_default
;
771 prefix
.u
.prefix4
= ipreach
->prefix
;
772 prefix
.prefixlen
= ip_masklen (ipreach
->mask
);
773 apply_mask (&prefix
);
774 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
780 if (!pseudo_lsp
&& spftree
->family
== AF_INET
)
782 struct list
*ipv4reachs
= NULL
;
784 if (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
786 ipv4reachs
= lsp
->tlv_data
.te_ipv4_reachs
;
790 struct tlv_mt_ipv4_reachs
*mt_reachs
;
791 mt_reachs
= tlvs_lookup_mt_ipv4_reachs(&lsp
->tlv_data
, spftree
->mtid
);
793 ipv4reachs
= mt_reachs
->list
;
796 prefix
.family
= AF_INET
;
797 for (ALL_LIST_ELEMENTS_RO (ipv4reachs
, node
, te_ipv4_reach
))
799 assert ((te_ipv4_reach
->control
& 0x3F) <= IPV4_MAX_BITLEN
);
801 dist
= cost
+ ntohl (te_ipv4_reach
->te_metric
);
802 prefix
.u
.prefix4
= newprefix2inaddr (&te_ipv4_reach
->prefix_start
,
803 te_ipv4_reach
->control
);
804 prefix
.prefixlen
= (te_ipv4_reach
->control
& 0x3F);
805 apply_mask (&prefix
);
806 process_N (spftree
, VTYPE_IPREACH_TE
, (void *) &prefix
, dist
, depth
+ 1,
812 && spftree
->family
== AF_INET6
)
814 struct list
*ipv6reachs
= NULL
;
816 if (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
)
818 ipv6reachs
= lsp
->tlv_data
.ipv6_reachs
;
822 struct tlv_mt_ipv6_reachs
*mt_reachs
;
823 mt_reachs
= tlvs_lookup_mt_ipv6_reachs(&lsp
->tlv_data
, spftree
->mtid
);
825 ipv6reachs
= mt_reachs
->list
;
828 prefix
.family
= AF_INET6
;
829 for (ALL_LIST_ELEMENTS_RO (ipv6reachs
, node
, ip6reach
))
831 assert (ip6reach
->prefix_len
<= IPV6_MAX_BITLEN
);
833 dist
= cost
+ ntohl(ip6reach
->metric
);
834 vtype
= (ip6reach
->control_info
& CTRL_INFO_DISTRIBUTION
) ?
835 VTYPE_IP6REACH_EXTERNAL
: VTYPE_IP6REACH_INTERNAL
;
836 prefix
.prefixlen
= ip6reach
->prefix_len
;
837 memcpy (&prefix
.u
.prefix6
.s6_addr
, ip6reach
->prefix
,
838 PSIZE (ip6reach
->prefix_len
));
839 apply_mask (&prefix
);
840 process_N (spftree
, vtype
, (void *) &prefix
, dist
, depth
+ 1,
845 if (fragnode
== NULL
)
846 fragnode
= listhead (lsp
->lspu
.frags
);
848 fragnode
= listnextnode (fragnode
);
852 lsp
= listgetdata (fragnode
);
860 isis_spf_preload_tent (struct isis_spftree
*spftree
,
862 struct isis_vertex
*parent
)
864 struct isis_circuit
*circuit
;
865 struct listnode
*cnode
, *anode
, *ipnode
;
866 struct isis_adjacency
*adj
;
867 struct isis_lsp
*lsp
;
868 struct list
*adj_list
;
870 struct prefix_ipv4
*ipv4
;
871 struct prefix prefix
;
872 int retval
= ISIS_OK
;
873 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
874 static u_char null_lsp_id
[ISIS_SYS_ID_LEN
+ 2];
875 struct prefix_ipv6
*ipv6
;
876 struct isis_circuit_mt_setting
*circuit_mt
;
878 for (ALL_LIST_ELEMENTS_RO (spftree
->area
->circuit_list
, cnode
, circuit
))
880 circuit_mt
= circuit_lookup_mt_setting(circuit
, spftree
->mtid
);
881 if (circuit_mt
&& !circuit_mt
->enabled
)
883 if (circuit
->state
!= C_STATE_UP
)
885 if (!(circuit
->is_type
& spftree
->level
))
887 if (spftree
->family
== AF_INET
&& !circuit
->ip_router
)
889 if (spftree
->family
== AF_INET6
&& !circuit
->ipv6_router
)
892 * Add IP(v6) addresses of this circuit
894 if (spftree
->family
== AF_INET
)
896 prefix
.family
= AF_INET
;
897 for (ALL_LIST_ELEMENTS_RO (circuit
->ip_addrs
, ipnode
, ipv4
))
899 prefix
.u
.prefix4
= ipv4
->prefix
;
900 prefix
.prefixlen
= ipv4
->prefixlen
;
901 apply_mask (&prefix
);
902 isis_spf_add_local (spftree
, VTYPE_IPREACH_INTERNAL
, &prefix
,
906 if (spftree
->family
== AF_INET6
)
908 prefix
.family
= AF_INET6
;
909 for (ALL_LIST_ELEMENTS_RO (circuit
->ipv6_non_link
, ipnode
, ipv6
))
911 prefix
.prefixlen
= ipv6
->prefixlen
;
912 prefix
.u
.prefix6
= ipv6
->prefix
;
913 apply_mask (&prefix
);
914 isis_spf_add_local (spftree
, VTYPE_IP6REACH_INTERNAL
,
915 &prefix
, NULL
, 0, parent
);
918 if (circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
921 * Add the adjacencies
923 adj_list
= list_new ();
924 adjdb
= circuit
->u
.bc
.adjdb
[spftree
->level
- 1];
925 isis_adj_build_up_list (adjdb
, adj_list
);
926 if (listcount (adj_list
) == 0)
928 list_delete (adj_list
);
929 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
930 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
931 spftree
->level
, circuit
->interface
->name
);
934 for (ALL_LIST_ELEMENTS_RO (adj_list
, anode
, adj
))
936 if (!adj_has_mt(adj
, spftree
->mtid
))
938 if (spftree
->mtid
== ISIS_MT_IPV4_UNICAST
&& !speaks (&adj
->nlpids
, spftree
->family
))
940 switch (adj
->sys_type
)
942 case ISIS_SYSTYPE_ES
:
943 memcpy(lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
944 LSP_PSEUDO_ID (lsp_id
) = 0;
945 isis_spf_add_local (spftree
, VTYPE_ES
, lsp_id
, adj
,
946 circuit
->te_metric
[spftree
->level
- 1],
949 case ISIS_SYSTYPE_IS
:
950 case ISIS_SYSTYPE_L1_IS
:
951 case ISIS_SYSTYPE_L2_IS
:
952 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
953 LSP_PSEUDO_ID (lsp_id
) = 0;
954 LSP_FRAGMENT (lsp_id
) = 0;
955 isis_spf_add_local (spftree
,
956 spftree
->area
->oldmetric
? VTYPE_NONPSEUDO_IS
957 : VTYPE_NONPSEUDO_TE_IS
,
959 circuit
->te_metric
[spftree
->level
- 1],
961 lsp
= lsp_search (lsp_id
, spftree
->area
->lspdb
[spftree
->level
- 1]);
962 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
963 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
965 rawlspid_print (lsp_id
), spftree
->level
,
966 circuit
->interface
->name
, circuit
->circuit_id
);
968 case ISIS_SYSTYPE_UNKNOWN
:
970 zlog_warn ("isis_spf_preload_tent unknow adj type");
973 list_delete (adj_list
);
977 if (spftree
->level
== 1)
978 memcpy (lsp_id
, circuit
->u
.bc
.l1_desig_is
, ISIS_SYS_ID_LEN
+ 1);
980 memcpy (lsp_id
, circuit
->u
.bc
.l2_desig_is
, ISIS_SYS_ID_LEN
+ 1);
981 /* can happen during DR reboot */
982 if (memcmp (lsp_id
, null_lsp_id
, ISIS_SYS_ID_LEN
+ 1) == 0)
984 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
985 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
986 spftree
->level
, circuit
->interface
->name
, circuit
->circuit_id
);
989 adj
= isis_adj_lookup (lsp_id
, adjdb
);
990 /* if no adj, we are the dis or error */
991 if (!adj
&& !circuit
->u
.bc
.is_dr
[spftree
->level
- 1])
993 zlog_warn ("ISIS-Spf: No adjacency found from root "
994 "to L%d DR %s on %s (ID %d)",
995 spftree
->level
, rawlspid_print (lsp_id
),
996 circuit
->interface
->name
, circuit
->circuit_id
);
999 lsp
= lsp_search (lsp_id
, spftree
->area
->lspdb
[spftree
->level
- 1]);
1000 if (lsp
== NULL
|| lsp
->lsp_header
->rem_lifetime
== 0)
1002 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1003 "to L%d DR %s on %s (ID %d)",
1004 (void *)lsp
, spftree
->level
, rawlspid_print (lsp_id
),
1005 circuit
->interface
->name
, circuit
->circuit_id
);
1008 isis_spf_process_lsp (spftree
, lsp
,
1009 circuit
->te_metric
[spftree
->level
- 1], 0,
1010 root_sysid
, parent
);
1012 else if (circuit
->circ_type
== CIRCUIT_T_P2P
)
1014 adj
= circuit
->u
.p2p
.neighbor
;
1017 if (!adj_has_mt(adj
, spftree
->mtid
))
1019 switch (adj
->sys_type
)
1021 case ISIS_SYSTYPE_ES
:
1022 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1023 LSP_PSEUDO_ID (lsp_id
) = 0;
1024 isis_spf_add_local (spftree
, VTYPE_ES
, lsp_id
, adj
,
1025 circuit
->te_metric
[spftree
->level
- 1],
1028 case ISIS_SYSTYPE_IS
:
1029 case ISIS_SYSTYPE_L1_IS
:
1030 case ISIS_SYSTYPE_L2_IS
:
1031 memcpy (lsp_id
, adj
->sysid
, ISIS_SYS_ID_LEN
);
1032 LSP_PSEUDO_ID (lsp_id
) = 0;
1033 LSP_FRAGMENT (lsp_id
) = 0;
1034 if (spftree
->mtid
!= ISIS_MT_IPV4_UNICAST
|| speaks (&adj
->nlpids
, spftree
->family
))
1035 isis_spf_add_local (spftree
,
1036 spftree
->area
->oldmetric
? VTYPE_NONPSEUDO_IS
1037 : VTYPE_NONPSEUDO_TE_IS
,
1039 adj
, circuit
->te_metric
[spftree
->level
- 1],
1042 case ISIS_SYSTYPE_UNKNOWN
:
1044 zlog_warn ("isis_spf_preload_tent unknown adj type");
1048 else if (circuit
->circ_type
== CIRCUIT_T_LOOPBACK
)
1054 zlog_warn ("isis_spf_preload_tent unsupported media");
1055 retval
= ISIS_WARNING
;
1063 * The parent(s) for vertex is set when added to TENT list
1064 * now we just put the child pointer(s) in place
1067 add_to_paths (struct isis_spftree
*spftree
, struct isis_vertex
*vertex
)
1069 char buff
[PREFIX2STR_BUFFER
];
1071 if (isis_find_vertex (spftree
->paths
, vertex
->N
.id
, vertex
->type
))
1073 listnode_add (spftree
->paths
, vertex
);
1075 #ifdef EXTREME_DEBUG
1076 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1077 print_sys_hostname (vertex
->N
.id
),
1078 vtype2string (vertex
->type
), vid2string (vertex
, buff
, sizeof (buff
)),
1079 vertex
->depth
, vertex
->d_N
);
1080 #endif /* EXTREME_DEBUG */
1082 if (VTYPE_IP(vertex
->type
))
1084 if (listcount (vertex
->Adj_N
) > 0)
1085 isis_route_create ((struct prefix
*) &vertex
->N
.prefix
, vertex
->d_N
,
1086 vertex
->depth
, vertex
->Adj_N
, spftree
->area
, spftree
->level
);
1087 else if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1088 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1089 "%s depth %d dist %d", vid2string (vertex
, buff
, sizeof (buff
)),
1090 vertex
->depth
, vertex
->d_N
);
1097 init_spt (struct isis_spftree
*spftree
, int mtid
, int level
, int family
)
1099 spftree
->tents
->del
= spftree
->paths
->del
= (void (*)(void *)) isis_vertex_del
;
1100 list_delete_all_node (spftree
->tents
);
1101 list_delete_all_node (spftree
->paths
);
1102 spftree
->tents
->del
= spftree
->paths
->del
= NULL
;
1104 spftree
->mtid
= mtid
;
1105 spftree
->level
= level
;
1106 spftree
->family
= family
;
1111 isis_run_spf (struct isis_area
*area
, int level
, int family
, u_char
*sysid
)
1113 int retval
= ISIS_OK
;
1114 struct listnode
*node
;
1115 struct isis_vertex
*vertex
;
1116 struct isis_vertex
*root_vertex
;
1117 struct isis_spftree
*spftree
= NULL
;
1118 u_char lsp_id
[ISIS_SYS_ID_LEN
+ 2];
1119 struct isis_lsp
*lsp
;
1120 struct route_table
*table
= NULL
;
1121 struct timeval time_now
;
1122 unsigned long long start_time
, end_time
;
1125 /* Get time that can't roll backwards. */
1126 monotime(&time_now
);
1127 start_time
= time_now
.tv_sec
;
1128 start_time
= (start_time
* 1000000) + time_now
.tv_usec
;
1130 if (family
== AF_INET
)
1131 spftree
= area
->spftree
[level
- 1];
1132 else if (family
== AF_INET6
)
1133 spftree
= area
->spftree6
[level
- 1];
1137 /* Make all routes in current route table inactive. */
1138 if (family
== AF_INET
)
1139 table
= area
->route_table
[level
- 1];
1140 else if (family
== AF_INET6
)
1141 table
= area
->route_table6
[level
- 1];
1143 isis_route_invalidate_table (area
, table
);
1145 /* We only support ipv4-unicast and ipv6-unicast as topologies for now */
1146 if (family
== AF_INET6
)
1147 mtid
= isis_area_ipv6_topology(area
);
1149 mtid
= ISIS_MT_IPV4_UNICAST
;
1154 init_spt (spftree
, mtid
, level
, family
);
1156 root_vertex
= isis_spf_add_root (spftree
, sysid
);
1158 retval
= isis_spf_preload_tent (spftree
, sysid
, root_vertex
);
1159 if (retval
!= ISIS_OK
)
1161 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid
));
1168 if (listcount (spftree
->tents
) == 0)
1170 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid
));
1174 while (listcount (spftree
->tents
) > 0)
1176 node
= listhead (spftree
->tents
);
1177 vertex
= listgetdata (node
);
1179 #ifdef EXTREME_DEBUG
1180 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1181 print_sys_hostname (vertex
->N
.id
),
1182 vtype2string (vertex
->type
), vertex
->depth
, vertex
->d_N
);
1183 #endif /* EXTREME_DEBUG */
1185 /* Remove from tent list and add to paths list */
1186 list_delete_node (spftree
->tents
, node
);
1187 add_to_paths (spftree
, vertex
);
1188 if (VTYPE_IS(vertex
->type
))
1190 memcpy (lsp_id
, vertex
->N
.id
, ISIS_SYS_ID_LEN
+ 1);
1191 LSP_FRAGMENT (lsp_id
) = 0;
1192 lsp
= lsp_search (lsp_id
, area
->lspdb
[level
- 1]);
1193 if (lsp
&& lsp
->lsp_header
->rem_lifetime
!= 0)
1195 isis_spf_process_lsp (spftree
, lsp
, vertex
->d_N
,
1196 vertex
->depth
, sysid
, vertex
);
1200 zlog_warn ("ISIS-Spf: No LSP found for %s",
1201 rawlspid_print (lsp_id
));
1207 isis_route_validate (area
);
1208 spftree
->runcount
++;
1209 spftree
->last_run_timestamp
= time (NULL
);
1210 monotime(&time_now
);
1211 end_time
= time_now
.tv_sec
;
1212 end_time
= (end_time
* 1000000) + time_now
.tv_usec
;
1213 spftree
->last_run_duration
= end_time
- start_time
;
1219 isis_run_spf_cb (struct thread
*thread
)
1221 struct isis_spf_run
*run
= THREAD_ARG (thread
);
1222 struct isis_area
*area
= run
->area
;
1223 int level
= run
->level
;
1224 int retval
= ISIS_OK
;
1226 XFREE(MTYPE_ISIS_SPF_RUN
, run
);
1227 area
->spf_timer
[level
- 1] = NULL
;
1229 if (!(area
->is_type
& level
))
1231 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1232 zlog_warn ("ISIS-SPF (%s) area does not share level",
1234 return ISIS_WARNING
;
1237 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1238 zlog_debug ("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
1239 area
->area_tag
, level
);
1241 if (area
->ip_circuits
)
1242 retval
= isis_run_spf (area
, level
, AF_INET
, isis
->sysid
);
1243 if (area
->ipv6_circuits
)
1244 retval
= isis_run_spf (area
, level
, AF_INET6
, isis
->sysid
);
1249 static struct isis_spf_run
*
1250 isis_run_spf_arg(struct isis_area
*area
, int level
)
1252 struct isis_spf_run
*run
= XMALLOC(MTYPE_ISIS_SPF_RUN
, sizeof(*run
));
1261 isis_spf_schedule (struct isis_area
*area
, int level
)
1263 struct isis_spftree
*spftree
= area
->spftree
[level
- 1];
1264 time_t now
= time (NULL
);
1265 int diff
= now
- spftree
->last_run_timestamp
;
1268 assert (area
->is_type
& level
);
1270 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1271 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1272 area
->area_tag
, level
, diff
);
1274 if (area
->spf_delay_ietf
[level
- 1])
1276 /* Need to call schedule function also if spf delay is running to
1277 * restart holdoff timer - compare draft-ietf-rtgwg-backoff-algo-04 */
1278 long delay
= spf_backoff_schedule(area
->spf_delay_ietf
[level
-1]);
1279 if (area
->spf_timer
[level
- 1])
1282 thread_add_timer_msec (master
, isis_run_spf_cb
,
1283 isis_run_spf_arg(area
, level
),
1284 delay
, &area
->spf_timer
[level
-1]);
1288 if (area
->spf_timer
[level
-1])
1291 /* wait configured min_spf_interval before doing the SPF */
1292 if (diff
>= area
->min_spf_interval
[level
-1])
1294 int retval
= ISIS_OK
;
1296 if (area
->ip_circuits
)
1297 retval
= isis_run_spf (area
, level
, AF_INET
, isis
->sysid
);
1298 if (area
->ipv6_circuits
)
1299 retval
= isis_run_spf (area
, level
, AF_INET6
, isis
->sysid
);
1304 thread_add_timer (master
, isis_run_spf_cb
, isis_run_spf_arg(area
, level
),
1305 area
->min_spf_interval
[level
-1] - diff
,
1306 &area
->spf_timer
[level
-1]);
1308 if (isis
->debugs
& DEBUG_SPF_EVENTS
)
1309 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
1310 area
->area_tag
, level
, area
->min_spf_interval
[level
-1] - diff
);
1316 isis_print_paths (struct vty
*vty
, struct list
*paths
, u_char
*root_sysid
)
1318 struct listnode
*node
;
1319 struct listnode
*anode
;
1320 struct isis_vertex
*vertex
;
1321 struct isis_adjacency
*adj
;
1322 char buff
[PREFIX2STR_BUFFER
];
1324 vty_out (vty
, "Vertex Type Metric "
1325 "Next-Hop Interface Parent%s", VTY_NEWLINE
);
1327 for (ALL_LIST_ELEMENTS_RO (paths
, node
, vertex
)) {
1328 if (memcmp (vertex
->N
.id
, root_sysid
, ISIS_SYS_ID_LEN
) == 0) {
1329 vty_out (vty
, "%-20s %-12s %-6s", print_sys_hostname (root_sysid
),
1331 vty_out (vty
, "%-30s", "");
1334 vty_out (vty
, "%-20s %-12s %-6u ", vid2string (vertex
, buff
, sizeof (buff
)),
1335 vtype2string (vertex
->type
), vertex
->d_N
);
1336 for (ALL_LIST_ELEMENTS_RO (vertex
->Adj_N
, anode
, adj
)) {
1339 vty_out (vty
, "%s", VTY_NEWLINE
);
1340 vty_out (vty
, "%-20s %-12s %-6s ", "", "", "");
1342 vty_out (vty
, "%-20s %-9s ",
1343 print_sys_hostname (adj
->sysid
),
1344 adj
->circuit
->interface
->name
);
1349 vty_out (vty
, "%-30s ", "");
1352 /* Print list of parents for the ECMP DAG */
1353 if (listcount (vertex
->parents
) > 0) {
1354 struct listnode
*pnode
;
1355 struct isis_vertex
*pvertex
;
1357 for (ALL_LIST_ELEMENTS_RO (vertex
->parents
, pnode
, pvertex
)) {
1359 vty_out (vty
, "%s", VTY_NEWLINE
);
1360 vty_out (vty
, "%-72s", "");
1362 vty_out (vty
, "%s(%d)",
1363 vid2string (pvertex
, buff
, sizeof (buff
)), pvertex
->type
);
1367 vty_out (vty
, " NULL ");
1370 vty_out (vty
, "%s", VTY_NEWLINE
);
1374 DEFUN (show_isis_topology
,
1375 show_isis_topology_cmd
,
1376 "show isis topology [<level-1|level-2>]",
1378 "IS-IS information\n"
1379 "IS-IS paths to Intermediate Systems\n"
1380 "Paths to all level-1 routers in the area\n"
1381 "Paths to all level-2 routers in the domain\n")
1384 struct listnode
*node
;
1385 struct isis_area
*area
;
1388 levels
= ISIS_LEVEL1
|ISIS_LEVEL2
;
1389 else if (!strcmp(argv
[3]->arg
, "level-1"))
1390 levels
= ISIS_LEVEL1
;
1392 levels
= ISIS_LEVEL2
;
1394 if (!isis
->area_list
|| isis
->area_list
->count
== 0)
1397 for (ALL_LIST_ELEMENTS_RO (isis
->area_list
, node
, area
))
1399 vty_out (vty
, "Area %s:%s", area
->area_tag
? area
->area_tag
: "null",
1402 for (int level
= ISIS_LEVEL1
; level
<= ISIS_LEVELS
; level
++)
1404 if ((level
& levels
) == 0)
1407 if (area
->ip_circuits
> 0 && area
->spftree
[level
-1]
1408 && area
->spftree
[level
-1]->paths
->count
> 0)
1410 vty_out (vty
, "IS-IS paths to level-%d routers that speak IP%s",
1411 level
, VTY_NEWLINE
);
1412 isis_print_paths (vty
, area
->spftree
[level
-1]->paths
, isis
->sysid
);
1413 vty_out (vty
, "%s", VTY_NEWLINE
);
1415 if (area
->ipv6_circuits
> 0 && area
->spftree6
[level
-1]
1416 && area
->spftree6
[level
-1]->paths
->count
> 0)
1419 "IS-IS paths to level-%d routers that speak IPv6%s",
1420 level
, VTY_NEWLINE
);
1421 isis_print_paths (vty
, area
->spftree6
[level
-1]->paths
, isis
->sysid
);
1422 vty_out (vty
, "%s", VTY_NEWLINE
);
1426 vty_out (vty
, "%s", VTY_NEWLINE
);
1433 isis_spf_cmds_init ()
1435 install_element (VIEW_NODE
, &show_isis_topology_cmd
);