]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_spf.c
isisd: verify metrics on metric-style transition
[mirror_frr.git] / isisd / isis_spf.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_spf.c
3 * The SPT algorithm
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
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)
12 * any later version.
13 *
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
17 * more details.
18
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.
22 */
23
eb5d44eb 24#include <zebra.h>
eb5d44eb 25
26#include "thread.h"
27#include "linklist.h"
28#include "vty.h"
29#include "log.h"
30#include "command.h"
31#include "memory.h"
32#include "prefix.h"
33#include "hash.h"
34#include "if.h"
35#include "table.h"
36
37#include "isis_constants.h"
38#include "isis_common.h"
3f045a08 39#include "isis_flags.h"
eb5d44eb 40#include "dict.h"
41#include "isisd.h"
42#include "isis_misc.h"
43#include "isis_adjacency.h"
44#include "isis_circuit.h"
45#include "isis_tlv.h"
46#include "isis_pdu.h"
47#include "isis_lsp.h"
48#include "isis_dynhn.h"
49#include "isis_spf.h"
50#include "isis_route.h"
51#include "isis_csm.h"
52
eb5d44eb 53int isis_run_spf_l1 (struct thread *thread);
54int isis_run_spf_l2 (struct thread *thread);
55
eb5d44eb 56/* 7.2.7 */
92365889 57static void
eb5d44eb 58remove_excess_adjs (struct list *adjs)
59{
3fdb2dd9 60 struct listnode *node, *excess = NULL;
eb5d44eb 61 struct isis_adjacency *adj, *candidate = NULL;
62 int comp;
63
3fdb2dd9 64 for (ALL_LIST_ELEMENTS_RO (adjs, node, adj))
f390d2c7 65 {
66 if (excess == NULL)
67 excess = node;
1eb8ef25 68 candidate = listgetdata (excess);
69
f390d2c7 70 if (candidate->sys_type < adj->sys_type)
71 {
72 excess = node;
73 candidate = adj;
74 continue;
75 }
76 if (candidate->sys_type > adj->sys_type)
77 continue;
78
79 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
80 if (comp > 0)
81 {
82 excess = node;
83 candidate = adj;
84 continue;
85 }
86 if (comp < 0)
87 continue;
eb5d44eb 88
f390d2c7 89 if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
90 {
91 excess = node;
92 candidate = adj;
93 continue;
94 }
95
96 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
97 continue;
98
99 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
100 if (comp > 0)
101 {
102 excess = node;
103 candidate = adj;
104 continue;
105 }
eb5d44eb 106 }
f390d2c7 107
eb5d44eb 108 list_delete_node (adjs, excess);
109
110 return;
111}
112
92365889 113static const char *
eb5d44eb 114vtype2string (enum vertextype vtype)
115{
f390d2c7 116 switch (vtype)
117 {
118 case VTYPE_PSEUDO_IS:
119 return "pseudo_IS";
120 break;
82a8428c 121 case VTYPE_PSEUDO_TE_IS:
122 return "pseudo_TE-IS";
123 break;
f390d2c7 124 case VTYPE_NONPSEUDO_IS:
125 return "IS";
126 break;
82a8428c 127 case VTYPE_NONPSEUDO_TE_IS:
128 return "TE-IS";
129 break;
f390d2c7 130 case VTYPE_ES:
131 return "ES";
132 break;
133 case VTYPE_IPREACH_INTERNAL:
134 return "IP internal";
135 break;
136 case VTYPE_IPREACH_EXTERNAL:
137 return "IP external";
138 break;
82a8428c 139 case VTYPE_IPREACH_TE:
140 return "IP TE";
141 break;
eb5d44eb 142#ifdef HAVE_IPV6
f390d2c7 143 case VTYPE_IP6REACH_INTERNAL:
144 return "IP6 internal";
145 break;
146 case VTYPE_IP6REACH_EXTERNAL:
147 return "IP6 external";
148 break;
149#endif /* HAVE_IPV6 */
150 default:
151 return "UNKNOWN";
152 }
153 return NULL; /* Not reached */
eb5d44eb 154}
155
92365889 156static const char *
f390d2c7 157vid2string (struct isis_vertex *vertex, u_char * buff)
eb5d44eb 158{
f390d2c7 159 switch (vertex->type)
160 {
161 case VTYPE_PSEUDO_IS:
82a8428c 162 case VTYPE_PSEUDO_TE_IS:
3f045a08 163 return print_sys_hostname (vertex->N.id);
f390d2c7 164 break;
165 case VTYPE_NONPSEUDO_IS:
82a8428c 166 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 167 case VTYPE_ES:
3f045a08 168 return print_sys_hostname (vertex->N.id);
f390d2c7 169 break;
170 case VTYPE_IPREACH_INTERNAL:
171 case VTYPE_IPREACH_EXTERNAL:
82a8428c 172 case VTYPE_IPREACH_TE:
eb5d44eb 173#ifdef HAVE_IPV6
f390d2c7 174 case VTYPE_IP6REACH_INTERNAL:
175 case VTYPE_IP6REACH_EXTERNAL:
176#endif /* HAVE_IPV6 */
f7c43dcb 177 prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ);
f390d2c7 178 break;
179 default:
180 return "UNKNOWN";
181 }
182
f7c43dcb 183 return (char *) buff;
eb5d44eb 184}
185
3f045a08
JB
186static struct isis_vertex *
187isis_vertex_new (void *id, enum vertextype vtype)
eb5d44eb 188{
3f045a08 189 struct isis_vertex *vertex;
eb5d44eb 190
3f045a08
JB
191 vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
192 if (vertex == NULL)
f390d2c7 193 {
3f045a08 194 zlog_err ("isis_vertex_new Out of memory!");
f390d2c7 195 return NULL;
196 }
eb5d44eb 197
3f045a08
JB
198 vertex->type = vtype;
199 switch (vtype)
200 {
201 case VTYPE_ES:
202 case VTYPE_NONPSEUDO_IS:
203 case VTYPE_NONPSEUDO_TE_IS:
204 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
205 break;
206 case VTYPE_PSEUDO_IS:
207 case VTYPE_PSEUDO_TE_IS:
208 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
209 break;
210 case VTYPE_IPREACH_INTERNAL:
211 case VTYPE_IPREACH_EXTERNAL:
212 case VTYPE_IPREACH_TE:
213#ifdef HAVE_IPV6
214 case VTYPE_IP6REACH_INTERNAL:
215 case VTYPE_IP6REACH_EXTERNAL:
216#endif /* HAVE_IPV6 */
217 memcpy (&vertex->N.prefix, (struct prefix *) id,
218 sizeof (struct prefix));
219 break;
220 default:
221 zlog_err ("WTF!");
222 }
223
224 vertex->Adj_N = list_new ();
225 vertex->parents = list_new ();
226 vertex->children = list_new ();
227
228 return vertex;
eb5d44eb 229}
230
92365889 231static void
eb5d44eb 232isis_vertex_del (struct isis_vertex *vertex)
233{
eb5d44eb 234 list_delete (vertex->Adj_N);
3f045a08
JB
235 vertex->Adj_N = NULL;
236 list_delete (vertex->parents);
237 vertex->parents = NULL;
238 list_delete (vertex->children);
239 vertex->children = NULL;
eb5d44eb 240
3f045a08 241 memset(vertex, 0, sizeof(struct isis_vertex));
eb5d44eb 242 XFREE (MTYPE_ISIS_VERTEX, vertex);
f390d2c7 243
eb5d44eb 244 return;
245}
246
92365889 247static void
3f045a08
JB
248isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
249{
250 struct listnode *node, *nextnode;
251 if (!vertex)
252 return;
253 for (node = listhead (vertex->Adj_N); node; node = nextnode)
254 {
255 nextnode = listnextnode(node);
256 if (listgetdata(node) == adj)
257 list_delete_node(vertex->Adj_N, node);
258 }
259 return;
260}
261
262struct isis_spftree *
263isis_spftree_new (struct isis_area *area)
264{
265 struct isis_spftree *tree;
266
267 tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
268 if (tree == NULL)
269 {
270 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
271 return NULL;
272 }
273
274 tree->tents = list_new ();
275 tree->paths = list_new ();
276 tree->area = area;
e38e0df0
SV
277 tree->last_run_timestamp = 0;
278 tree->last_run_duration = 0;
3f045a08
JB
279 tree->runcount = 0;
280 tree->pending = 0;
281 return tree;
282}
283
284void
eb5d44eb 285isis_spftree_del (struct isis_spftree *spftree)
286{
3f045a08
JB
287 THREAD_TIMER_OFF (spftree->t_spf);
288
f7c43dcb 289 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 290 list_delete (spftree->tents);
3f045a08 291 spftree->tents = NULL;
f390d2c7 292
f7c43dcb 293 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 294 list_delete (spftree->paths);
3f045a08 295 spftree->paths = NULL;
eb5d44eb 296
297 XFREE (MTYPE_ISIS_SPFTREE, spftree);
298
299 return;
300}
3f045a08
JB
301
302void
303isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
304{
305 struct listnode *node;
306 if (!adj)
307 return;
308 for (node = listhead (spftree->tents); node; node = listnextnode (node))
309 isis_vertex_adj_del (listgetdata (node), adj);
310 for (node = listhead (spftree->paths); node; node = listnextnode (node))
311 isis_vertex_adj_del (listgetdata (node), adj);
312 return;
313}
eb5d44eb 314
f390d2c7 315void
eb5d44eb 316spftree_area_init (struct isis_area *area)
317{
3f045a08
JB
318 if (area->is_type & IS_LEVEL_1)
319 {
320 if (area->spftree[0] == NULL)
321 area->spftree[0] = isis_spftree_new (area);
eb5d44eb 322#ifdef HAVE_IPV6
3f045a08
JB
323 if (area->spftree6[0] == NULL)
324 area->spftree6[0] = isis_spftree_new (area);
eb5d44eb 325#endif
3f045a08 326 }
eb5d44eb 327
3f045a08
JB
328 if (area->is_type & IS_LEVEL_2)
329 {
330 if (area->spftree[1] == NULL)
331 area->spftree[1] = isis_spftree_new (area);
eb5d44eb 332#ifdef HAVE_IPV6
3f045a08
JB
333 if (area->spftree6[1] == NULL)
334 area->spftree6[1] = isis_spftree_new (area);
eb5d44eb 335#endif
3f045a08 336 }
eb5d44eb 337
338 return;
339}
340
3f045a08
JB
341void
342spftree_area_del (struct isis_area *area)
eb5d44eb 343{
3f045a08
JB
344 if (area->is_type & IS_LEVEL_1)
345 {
346 if (area->spftree[0] != NULL)
f390d2c7 347 {
3f045a08
JB
348 isis_spftree_del (area->spftree[0]);
349 area->spftree[0] = NULL;
350 }
351#ifdef HAVE_IPV6
352 if (area->spftree6[0])
353 {
354 isis_spftree_del (area->spftree6[0]);
355 area->spftree6[0] = NULL;
f390d2c7 356 }
3f045a08
JB
357#endif
358 }
f390d2c7 359
3f045a08
JB
360 if (area->is_type & IS_LEVEL_2)
361 {
362 if (area->spftree[1] != NULL)
f390d2c7 363 {
3f045a08
JB
364 isis_spftree_del (area->spftree[1]);
365 area->spftree[1] = NULL;
366 }
eb5d44eb 367#ifdef HAVE_IPV6
de543de3 368 if (area->spftree6[1] != NULL)
3f045a08
JB
369 {
370 isis_spftree_del (area->spftree6[1]);
371 area->spftree6[1] = NULL;
f390d2c7 372 }
3f045a08
JB
373#endif
374 }
eb5d44eb 375
3f045a08
JB
376 return;
377}
f390d2c7 378
3f045a08
JB
379void
380spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
381{
382 if (area->is_type & IS_LEVEL_1)
383 {
384 if (area->spftree[0] != NULL)
385 isis_spftree_adj_del (area->spftree[0], adj);
386#ifdef HAVE_IPV6
387 if (area->spftree6[0] != NULL)
388 isis_spftree_adj_del (area->spftree6[0], adj);
389#endif
390 }
391
392 if (area->is_type & IS_LEVEL_2)
393 {
394 if (area->spftree[1] != NULL)
395 isis_spftree_adj_del (area->spftree[1], adj);
396#ifdef HAVE_IPV6
397 if (area->spftree6[1] != NULL)
398 isis_spftree_adj_del (area->spftree6[1], adj);
399#endif
400 }
401
402 return;
403}
404
405/*
406 * Find the system LSP: returns the LSP in our LSP database
407 * associated with the given system ID.
408 */
409static struct isis_lsp *
410isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
411{
e38e0df0 412 struct isis_lsp *lsp;
3f045a08
JB
413 u_char lspid[ISIS_SYS_ID_LEN + 2];
414
415 memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
416 LSP_PSEUDO_ID (lspid) = 0;
417 LSP_FRAGMENT (lspid) = 0;
e38e0df0
SV
418 lsp = lsp_search (lspid, area->lspdb[level - 1]);
419 if (lsp && lsp->lsp_header->rem_lifetime != 0)
420 return lsp;
421 return NULL;
eb5d44eb 422}
423
424/*
425 * Add this IS to the root of SPT
426 */
3f045a08
JB
427static struct isis_vertex *
428isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
eb5d44eb 429{
430 struct isis_vertex *vertex;
431 struct isis_lsp *lsp;
eb5d44eb 432#ifdef EXTREME_DEBUG
433 u_char buff[BUFSIZ];
434#endif /* EXTREME_DEBUG */
f390d2c7 435
3f045a08 436 lsp = isis_root_system_lsp (spftree->area, level, sysid);
eb5d44eb 437 if (lsp == NULL)
438 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
f390d2c7 439
3f045a08
JB
440 if (!spftree->area->oldmetric)
441 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
82a8428c 442 else
3f045a08 443 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
eb5d44eb 444
445 listnode_add (spftree->paths, vertex);
446
447#ifdef EXTREME_DEBUG
529d65b3 448 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
449 vtype2string (vertex->type), vid2string (vertex, buff),
450 vertex->depth, vertex->d_N);
eb5d44eb 451#endif /* EXTREME_DEBUG */
452
3f045a08 453 return vertex;
eb5d44eb 454}
455
92365889 456static struct isis_vertex *
f390d2c7 457isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
eb5d44eb 458{
459 struct listnode *node;
460 struct isis_vertex *vertex;
461 struct prefix *p1, *p2;
462
1eb8ef25 463 for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
f390d2c7 464 {
f390d2c7 465 if (vertex->type != vtype)
466 continue;
467 switch (vtype)
468 {
469 case VTYPE_ES:
470 case VTYPE_NONPSEUDO_IS:
82a8428c 471 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 472 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
473 return vertex;
474 break;
475 case VTYPE_PSEUDO_IS:
82a8428c 476 case VTYPE_PSEUDO_TE_IS:
f390d2c7 477 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
478 return vertex;
479 break;
480 case VTYPE_IPREACH_INTERNAL:
481 case VTYPE_IPREACH_EXTERNAL:
82a8428c 482 case VTYPE_IPREACH_TE:
eb5d44eb 483#ifdef HAVE_IPV6
f390d2c7 484 case VTYPE_IP6REACH_INTERNAL:
485 case VTYPE_IP6REACH_EXTERNAL:
eb5d44eb 486#endif /* HAVE_IPV6 */
f390d2c7 487 p1 = (struct prefix *) id;
488 p2 = (struct prefix *) &vertex->N.id;
489 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
490 memcmp (&p1->u.prefix, &p2->u.prefix,
491 PSIZE (p1->prefixlen)) == 0)
492 return vertex;
493 break;
494 }
eb5d44eb 495 }
eb5d44eb 496
497 return NULL;
498}
499
eb5d44eb 500/*
501 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
502 */
92365889 503static struct isis_vertex *
f390d2c7 504isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
3f045a08
JB
505 void *id, uint32_t cost, int depth, int family,
506 struct isis_adjacency *adj, struct isis_vertex *parent)
eb5d44eb 507{
508 struct isis_vertex *vertex, *v;
509 struct listnode *node;
3f045a08 510 struct isis_adjacency *parent_adj;
f390d2c7 511#ifdef EXTREME_DEBUG
eb5d44eb 512 u_char buff[BUFSIZ];
513#endif
514
3f045a08
JB
515 assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
516 assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
eb5d44eb 517 vertex = isis_vertex_new (id, vtype);
518 vertex->d_N = cost;
519 vertex->depth = depth;
f390d2c7 520
3f045a08
JB
521 if (parent) {
522 listnode_add (vertex->parents, parent);
523 if (listnode_lookup (parent->children, vertex) == NULL)
524 listnode_add (parent->children, vertex);
525 }
526
527 if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
528 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
529 listnode_add (vertex->Adj_N, parent_adj);
530 } else if (adj) {
eb5d44eb 531 listnode_add (vertex->Adj_N, adj);
3f045a08
JB
532 }
533
f390d2c7 534#ifdef EXTREME_DEBUG
3f045a08
JB
535 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
536 print_sys_hostname (vertex->N.id),
529d65b3 537 vtype2string (vertex->type), vid2string (vertex, buff),
3f045a08 538 vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
eb5d44eb 539#endif /* EXTREME_DEBUG */
3f045a08 540
f390d2c7 541 if (list_isempty (spftree->tents))
542 {
543 listnode_add (spftree->tents, vertex);
544 return vertex;
545 }
3f045a08
JB
546
547 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
1eb8ef25 548 for (node = listhead (spftree->tents); node; node = listnextnode (node))
f390d2c7 549 {
1eb8ef25 550 v = listgetdata (node);
f390d2c7 551 if (v->d_N > vertex->d_N)
552 {
553 list_add_node_prev (spftree->tents, node, vertex);
554 break;
555 }
3f045a08 556 else if (v->d_N == vertex->d_N && v->type > vertex->type)
f390d2c7 557 {
558 /* Tie break, add according to type */
3f045a08 559 list_add_node_prev (spftree->tents, node, vertex);
f390d2c7 560 break;
561 }
eb5d44eb 562 }
3f045a08
JB
563
564 if (node == NULL)
565 listnode_add (spftree->tents, vertex);
566
eb5d44eb 567 return vertex;
568}
569
3f045a08 570static void
f390d2c7 571isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
3f045a08
JB
572 void *id, struct isis_adjacency *adj, uint32_t cost,
573 int family, struct isis_vertex *parent)
eb5d44eb 574{
575 struct isis_vertex *vertex;
f390d2c7 576
577 vertex = isis_find_vertex (spftree->tents, id, vtype);
578
579 if (vertex)
580 {
581 /* C.2.5 c) */
582 if (vertex->d_N == cost)
583 {
584 if (adj)
585 listnode_add (vertex->Adj_N, adj);
586 /* d) */
587 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
588 remove_excess_adjs (vertex->Adj_N);
3f045a08
JB
589 if (parent && (listnode_lookup (vertex->parents, parent) == NULL))
590 listnode_add (vertex->parents, parent);
591 if (parent && (listnode_lookup (parent->children, vertex) == NULL))
592 listnode_add (parent->children, vertex);
593 return;
f390d2c7 594 }
3f045a08 595 else if (vertex->d_N < cost)
f390d2c7 596 {
3f045a08
JB
597 /* e) do nothing */
598 return;
f390d2c7 599 }
3f045a08
JB
600 else { /* vertex->d_N > cost */
601 /* f) */
602 struct listnode *pnode, *pnextnode;
603 struct isis_vertex *pvertex;
604 listnode_delete (spftree->tents, vertex);
605 assert (listcount (vertex->children) == 0);
606 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
607 listnode_delete(pvertex->children, vertex);
608 isis_vertex_del (vertex);
609 }
eb5d44eb 610 }
eb5d44eb 611
3f045a08
JB
612 isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
613 return;
eb5d44eb 614}
615
92365889 616static void
f390d2c7 617process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
3f045a08
JB
618 uint32_t dist, uint16_t depth, int family,
619 struct isis_vertex *parent)
eb5d44eb 620{
621 struct isis_vertex *vertex;
622#ifdef EXTREME_DEBUG
623 u_char buff[255];
624#endif
625
3f045a08
JB
626 assert (spftree && parent);
627
628 /* RFC3787 section 5.1 */
629 if (spftree->area->newmetric == 1)
630 {
631 if (dist > MAX_WIDE_PATH_METRIC)
632 return;
633 }
eb5d44eb 634 /* C.2.6 b) */
3f045a08
JB
635 else if (spftree->area->oldmetric == 1)
636 {
637 if (dist > MAX_NARROW_PATH_METRIC)
638 return;
639 }
640
eb5d44eb 641 /* c) */
642 vertex = isis_find_vertex (spftree->paths, id, vtype);
f390d2c7 643 if (vertex)
644 {
eb5d44eb 645#ifdef EXTREME_DEBUG
3f045a08
JB
646 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
647 print_sys_hostname (vertex->N.id),
529d65b3 648 vtype2string (vtype), vid2string (vertex, buff), dist);
eb5d44eb 649#endif /* EXTREME_DEBUG */
f390d2c7 650 assert (dist >= vertex->d_N);
651 return;
652 }
eb5d44eb 653
654 vertex = isis_find_vertex (spftree->tents, id, vtype);
f390d2c7 655 /* d) */
656 if (vertex)
657 {
658 /* 1) */
eb5d44eb 659#ifdef EXTREME_DEBUG
3f045a08
JB
660 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
661 print_sys_hostname (vertex->N.id),
662 vtype2string (vtype), vid2string (vertex, buff), dist,
663 (parent ? print_sys_hostname (parent->N.id) : "null"),
664 (parent ? listcount (parent->Adj_N) : 0));
eb5d44eb 665#endif /* EXTREME_DEBUG */
f390d2c7 666 if (vertex->d_N == dist)
667 {
3f045a08
JB
668 struct listnode *node;
669 struct isis_adjacency *parent_adj;
670 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
671 if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL)
672 listnode_add (vertex->Adj_N, parent_adj);
f390d2c7 673 /* 2) */
674 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
675 remove_excess_adjs (vertex->Adj_N);
3f045a08
JB
676 if (listnode_lookup (vertex->parents, parent) == NULL)
677 listnode_add (vertex->parents, parent);
678 if (listnode_lookup (parent->children, vertex) == NULL)
679 listnode_add (parent->children, vertex);
f390d2c7 680 /* 3) */
681 return;
682 }
683 else if (vertex->d_N < dist)
684 {
685 return;
686 /* 4) */
687 }
688 else
689 {
3f045a08
JB
690 struct listnode *pnode, *pnextnode;
691 struct isis_vertex *pvertex;
f390d2c7 692 listnode_delete (spftree->tents, vertex);
3f045a08
JB
693 assert (listcount (vertex->children) == 0);
694 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
695 listnode_delete(pvertex->children, vertex);
696 isis_vertex_del (vertex);
f390d2c7 697 }
eb5d44eb 698 }
f390d2c7 699
3f045a08
JB
700#ifdef EXTREME_DEBUG
701 zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
702 print_sys_hostname(id), vtype2string (vtype), dist,
703 (parent ? print_sys_hostname (parent->N.id) : "null"));
704#endif /* EXTREME_DEBUG */
705
706 isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
eb5d44eb 707 return;
708}
709
710/*
711 * C.2.6 Step 1
712 */
92365889 713static int
f390d2c7 714isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
3f045a08
JB
715 uint32_t cost, uint16_t depth, int family,
716 u_char *root_sysid, struct isis_vertex *parent)
eb5d44eb 717{
718 struct listnode *node, *fragnode = NULL;
3f045a08 719 uint32_t dist;
eb5d44eb 720 struct is_neigh *is_neigh;
82a8428c 721 struct te_is_neigh *te_is_neigh;
eb5d44eb 722 struct ipv4_reachability *ipreach;
82a8428c 723 struct te_ipv4_reachability *te_ipv4_reach;
eb5d44eb 724 enum vertextype vtype;
725 struct prefix prefix;
726#ifdef HAVE_IPV6
727 struct ipv6_reachability *ip6reach;
728#endif /* HAVE_IPV6 */
3f045a08 729 static const u_char null_sysid[ISIS_SYS_ID_LEN];
f390d2c7 730
3f045a08 731 if (!speaks (lsp->tlv_data.nlpids, family))
eb5d44eb 732 return ISIS_OK;
733
f390d2c7 734lspfragloop:
735 if (lsp->lsp_header->seq_num == 0)
736 {
3f045a08 737 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
f390d2c7 738 return ISIS_WARNING;
eb5d44eb 739 }
f390d2c7 740
3f045a08
JB
741#ifdef EXTREME_DEBUG
742 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
743#endif /* EXTREME_DEBUG */
744
f390d2c7 745 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
3f045a08
JB
746 {
747 if (lsp->tlv_data.is_neighs)
f390d2c7 748 {
3f045a08
JB
749 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
750 {
751 /* C.2.6 a) */
752 /* Two way connectivity */
753 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
754 continue;
755 if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
756 continue;
757 dist = cost + is_neigh->metrics.metric_default;
758 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
759 : VTYPE_NONPSEUDO_IS;
760 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
761 depth + 1, family, parent);
762 }
763 }
764 if (lsp->tlv_data.te_is_neighs)
765 {
766 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
767 te_is_neigh))
768 {
769 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
770 continue;
771 if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
772 continue;
773 dist = cost + GET_TE_METRIC(te_is_neigh);
774 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
775 : VTYPE_NONPSEUDO_TE_IS;
776 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
777 depth + 1, family, parent);
778 }
779 }
780 }
f390d2c7 781
3f045a08
JB
782 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
783 {
784 prefix.family = AF_INET;
785 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
786 {
787 dist = cost + ipreach->metrics.metric_default;
788 vtype = VTYPE_IPREACH_INTERNAL;
789 prefix.u.prefix4 = ipreach->prefix;
790 prefix.prefixlen = ip_masklen (ipreach->mask);
791 apply_mask (&prefix);
792 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
793 family, parent);
794 }
795 }
796 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
797 {
798 prefix.family = AF_INET;
799 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
800 {
801 dist = cost + ipreach->metrics.metric_default;
802 vtype = VTYPE_IPREACH_EXTERNAL;
803 prefix.u.prefix4 = ipreach->prefix;
804 prefix.prefixlen = ip_masklen (ipreach->mask);
805 apply_mask (&prefix);
806 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
807 family, parent);
808 }
809 }
810 if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
811 {
812 prefix.family = AF_INET;
813 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
814 node, te_ipv4_reach))
815 {
948b6bef
DL
816 assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
817
3f045a08
JB
818 dist = cost + ntohl (te_ipv4_reach->te_metric);
819 vtype = VTYPE_IPREACH_TE;
820 prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
821 te_ipv4_reach->control);
822 prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
823 apply_mask (&prefix);
824 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
825 family, parent);
826 }
827 }
eb5d44eb 828#ifdef HAVE_IPV6
3f045a08
JB
829 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
830 {
831 prefix.family = AF_INET6;
832 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
833 {
948b6bef
DL
834 assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
835
3f045a08
JB
836 dist = cost + ip6reach->metric;
837 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
838 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
839 prefix.prefixlen = ip6reach->prefix_len;
840 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
841 PSIZE (ip6reach->prefix_len));
842 apply_mask (&prefix);
843 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
844 family, parent);
f390d2c7 845 }
3f045a08
JB
846 }
847#endif /* HAVE_IPV6 */
f390d2c7 848
eb5d44eb 849 if (fragnode == NULL)
850 fragnode = listhead (lsp->lspu.frags);
f390d2c7 851 else
1eb8ef25 852 fragnode = listnextnode (fragnode);
eb5d44eb 853
f390d2c7 854 if (fragnode)
855 {
1eb8ef25 856 lsp = listgetdata (fragnode);
f390d2c7 857 goto lspfragloop;
858 }
859
eb5d44eb 860 return ISIS_OK;
861}
862
92365889 863static int
f390d2c7 864isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
3f045a08
JB
865 struct isis_lsp *lsp, uint32_t cost,
866 uint16_t depth, int family,
867 u_char *root_sysid,
868 struct isis_vertex *parent)
eb5d44eb 869{
3fdb2dd9 870 struct listnode *node, *fragnode = NULL;
eb5d44eb 871 struct is_neigh *is_neigh;
82a8428c 872 struct te_is_neigh *te_is_neigh;
eb5d44eb 873 enum vertextype vtype;
3f045a08 874 uint32_t dist;
f390d2c7 875
876pseudofragloop:
877
878 if (lsp->lsp_header->seq_num == 0)
879 {
880 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
881 " - do not process");
882 return ISIS_WARNING;
eb5d44eb 883 }
f390d2c7 884
3f045a08
JB
885#ifdef EXTREME_DEBUG
886 zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
887 print_sys_hostname(lsp->lsp_header->lsp_id));
888#endif /* EXTREME_DEBUG */
889
890 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
891
82a8428c 892 if (lsp->tlv_data.is_neighs)
3fdb2dd9 893 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
82a8428c 894 {
82a8428c 895 /* Two way connectivity */
3f045a08 896 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
82a8428c 897 continue;
3f045a08
JB
898 dist = cost + is_neigh->metrics.metric_default;
899 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
900 : VTYPE_NONPSEUDO_IS;
901 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
902 depth + 1, family, parent);
82a8428c 903 }
904 if (lsp->tlv_data.te_is_neighs)
3fdb2dd9 905 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
82a8428c 906 {
82a8428c 907 /* Two way connectivity */
3f045a08 908 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
82a8428c 909 continue;
3f045a08
JB
910 dist = cost + GET_TE_METRIC(te_is_neigh);
911 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
912 : VTYPE_NONPSEUDO_TE_IS;
913 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
914 depth + 1, family, parent);
82a8428c 915 }
f390d2c7 916
eb5d44eb 917 if (fragnode == NULL)
918 fragnode = listhead (lsp->lspu.frags);
f390d2c7 919 else
1eb8ef25 920 fragnode = listnextnode (fragnode);
eb5d44eb 921
f390d2c7 922 if (fragnode)
923 {
1eb8ef25 924 lsp = listgetdata (fragnode);
f390d2c7 925 goto pseudofragloop;
926 }
eb5d44eb 927
eb5d44eb 928 return ISIS_OK;
929}
f390d2c7 930
92365889 931static int
3f045a08
JB
932isis_spf_preload_tent (struct isis_spftree *spftree, int level,
933 int family, u_char *root_sysid,
934 struct isis_vertex *parent)
eb5d44eb 935{
eb5d44eb 936 struct isis_circuit *circuit;
3fdb2dd9 937 struct listnode *cnode, *anode, *ipnode;
eb5d44eb 938 struct isis_adjacency *adj;
939 struct isis_lsp *lsp;
940 struct list *adj_list;
941 struct list *adjdb;
942 struct prefix_ipv4 *ipv4;
943 struct prefix prefix;
944 int retval = ISIS_OK;
945 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
3f045a08 946 static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
eb5d44eb 947#ifdef HAVE_IPV6
948 struct prefix_ipv6 *ipv6;
949#endif /* HAVE_IPV6 */
f390d2c7 950
3f045a08 951 for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
f390d2c7 952 {
f390d2c7 953 if (circuit->state != C_STATE_UP)
954 continue;
3f045a08 955 if (!(circuit->is_type & level))
f390d2c7 956 continue;
957 if (family == AF_INET && !circuit->ip_router)
958 continue;
eb5d44eb 959#ifdef HAVE_IPV6
f390d2c7 960 if (family == AF_INET6 && !circuit->ipv6_router)
961 continue;
eb5d44eb 962#endif /* HAVE_IPV6 */
f390d2c7 963 /*
964 * Add IP(v6) addresses of this circuit
965 */
966 if (family == AF_INET)
967 {
968 prefix.family = AF_INET;
3fdb2dd9 969 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
f390d2c7 970 {
f390d2c7 971 prefix.u.prefix4 = ipv4->prefix;
972 prefix.prefixlen = ipv4->prefixlen;
3f045a08 973 apply_mask (&prefix);
f390d2c7 974 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
3f045a08 975 NULL, 0, family, parent);
f390d2c7 976 }
977 }
eb5d44eb 978#ifdef HAVE_IPV6
f390d2c7 979 if (family == AF_INET6)
980 {
981 prefix.family = AF_INET6;
3fdb2dd9 982 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
f390d2c7 983 {
f390d2c7 984 prefix.prefixlen = ipv6->prefixlen;
985 prefix.u.prefix6 = ipv6->prefix;
3f045a08 986 apply_mask (&prefix);
f390d2c7 987 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
3f045a08 988 &prefix, NULL, 0, family, parent);
f390d2c7 989 }
990 }
eb5d44eb 991#endif /* HAVE_IPV6 */
f390d2c7 992 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
993 {
994 /*
995 * Add the adjacencies
996 */
997 adj_list = list_new ();
998 adjdb = circuit->u.bc.adjdb[level - 1];
999 isis_adj_build_up_list (adjdb, adj_list);
1000 if (listcount (adj_list) == 0)
1001 {
1002 list_delete (adj_list);
c89c05dd 1003 if (isis->debugs & DEBUG_SPF_EVENTS)
1004 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
1005 level, circuit->interface->name);
f390d2c7 1006 continue;
1007 }
3f045a08 1008 for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
f390d2c7 1009 {
f390d2c7 1010 if (!speaks (&adj->nlpids, family))
f390d2c7 1011 continue;
f390d2c7 1012 switch (adj->sys_type)
1013 {
1014 case ISIS_SYSTYPE_ES:
1015 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
3f045a08
JB
1016 circuit->te_metric[level - 1],
1017 family, parent);
f390d2c7 1018 break;
1019 case ISIS_SYSTYPE_IS:
1020 case ISIS_SYSTYPE_L1_IS:
1021 case ISIS_SYSTYPE_L2_IS:
3f045a08
JB
1022 isis_spf_add_local (spftree,
1023 spftree->area->oldmetric ?
1024 VTYPE_NONPSEUDO_IS :
1025 VTYPE_NONPSEUDO_TE_IS,
1026 adj->sysid, adj,
1027 circuit->te_metric[level - 1],
1028 family, parent);
f390d2c7 1029 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1030 LSP_PSEUDO_ID (lsp_id) = 0;
1031 LSP_FRAGMENT (lsp_id) = 0;
3f045a08 1032 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
e38e0df0 1033 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
3f045a08
JB
1034 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
1035 "L%d on %s (ID %u)",
1036 rawlspid_print (lsp_id), level,
1037 circuit->interface->name, circuit->circuit_id);
f390d2c7 1038 break;
1039 case ISIS_SYSTYPE_UNKNOWN:
1040 default:
1041 zlog_warn ("isis_spf_preload_tent unknow adj type");
1042 }
f390d2c7 1043 }
1044 list_delete (adj_list);
1045 /*
1046 * Add the pseudonode
1047 */
1048 if (level == 1)
1049 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1050 else
1051 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
3f045a08
JB
1052 /* can happen during DR reboot */
1053 if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
1054 {
1055 if (isis->debugs & DEBUG_SPF_EVENTS)
1056 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
1057 level, circuit->interface->name, circuit->circuit_id);
1058 continue;
1059 }
f390d2c7 1060 adj = isis_adj_lookup (lsp_id, adjdb);
1061 /* if no adj, we are the dis or error */
1062 if (!adj && !circuit->u.bc.is_dr[level - 1])
1063 {
3f045a08
JB
1064 zlog_warn ("ISIS-Spf: No adjacency found from root "
1065 "to L%d DR %s on %s (ID %d)",
1066 level, rawlspid_print (lsp_id),
1067 circuit->interface->name, circuit->circuit_id);
1068 continue;
f390d2c7 1069 }
3f045a08 1070 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
f390d2c7 1071 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
1072 {
3f045a08
JB
1073 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1074 "to L%d DR %s on %s (ID %d)",
1075 lsp, level, rawlspid_print (lsp_id),
1076 circuit->interface->name, circuit->circuit_id);
1077 continue;
f390d2c7 1078 }
3f045a08
JB
1079 isis_spf_process_pseudo_lsp (spftree, lsp,
1080 circuit->te_metric[level - 1], 0,
1081 family, root_sysid, parent);
f390d2c7 1082 }
1083 else if (circuit->circ_type == CIRCUIT_T_P2P)
1084 {
1085 adj = circuit->u.p2p.neighbor;
1086 if (!adj)
1087 continue;
1088 switch (adj->sys_type)
1089 {
1090 case ISIS_SYSTYPE_ES:
1091 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
3f045a08
JB
1092 circuit->te_metric[level - 1], family,
1093 parent);
f390d2c7 1094 break;
1095 case ISIS_SYSTYPE_IS:
1096 case ISIS_SYSTYPE_L1_IS:
1097 case ISIS_SYSTYPE_L2_IS:
1098 if (speaks (&adj->nlpids, family))
3f045a08
JB
1099 isis_spf_add_local (spftree,
1100 spftree->area->oldmetric ?
1101 VTYPE_NONPSEUDO_IS :
1102 VTYPE_NONPSEUDO_TE_IS,
1103 adj->sysid,
82a8428c 1104 adj, circuit->te_metric[level - 1],
3f045a08 1105 family, parent);
f390d2c7 1106 break;
1107 case ISIS_SYSTYPE_UNKNOWN:
1108 default:
3f045a08 1109 zlog_warn ("isis_spf_preload_tent unknown adj type");
f390d2c7 1110 break;
1111 }
1112 }
3f045a08
JB
1113 else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
1114 {
1115 continue;
1116 }
eb5d44eb 1117 else
f390d2c7 1118 {
1119 zlog_warn ("isis_spf_preload_tent unsupported media");
1120 retval = ISIS_WARNING;
1121 }
eb5d44eb 1122 }
eb5d44eb 1123
1124 return retval;
1125}
1126
1127/*
1128 * The parent(s) for vertex is set when added to TENT list
1129 * now we just put the child pointer(s) in place
1130 */
92365889 1131static void
eb5d44eb 1132add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
3f045a08 1133 int level)
eb5d44eb 1134{
eb5d44eb 1135 u_char buff[BUFSIZ];
3f045a08
JB
1136
1137 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
1138 return;
eb5d44eb 1139 listnode_add (spftree->paths, vertex);
1140
f390d2c7 1141#ifdef EXTREME_DEBUG
3f045a08
JB
1142 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1143 print_sys_hostname (vertex->N.id),
529d65b3 1144 vtype2string (vertex->type), vid2string (vertex, buff),
1145 vertex->depth, vertex->d_N);
f390d2c7 1146#endif /* EXTREME_DEBUG */
3f045a08 1147
f390d2c7 1148 if (vertex->type > VTYPE_ES)
1149 {
1150 if (listcount (vertex->Adj_N) > 0)
fac1f7cc 1151 isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
3f045a08 1152 vertex->depth, vertex->Adj_N, spftree->area, level);
f390d2c7 1153 else if (isis->debugs & DEBUG_SPF_EVENTS)
3f045a08
JB
1154 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1155 "%s depth %d dist %d", vid2string (vertex, buff),
1156 vertex->depth, vertex->d_N);
f390d2c7 1157 }
1158
eb5d44eb 1159 return;
1160}
1161
92365889 1162static void
eb5d44eb 1163init_spt (struct isis_spftree *spftree)
1164{
f7c43dcb 1165 spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 1166 list_delete_all_node (spftree->tents);
1167 list_delete_all_node (spftree->paths);
1168 spftree->tents->del = spftree->paths->del = NULL;
eb5d44eb 1169 return;
1170}
1171
92365889 1172static int
3f045a08 1173isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
eb5d44eb 1174{
1175 int retval = ISIS_OK;
1176 struct listnode *node;
1177 struct isis_vertex *vertex;
3f045a08 1178 struct isis_vertex *root_vertex;
f390d2c7 1179 struct isis_spftree *spftree = NULL;
eb5d44eb 1180 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1181 struct isis_lsp *lsp;
fac1f7cc 1182 struct route_table *table = NULL;
43057bf2 1183 struct timeval time_now;
e38e0df0
SV
1184 unsigned long long start_time, end_time;
1185
1186 /* Get time that can't roll backwards. */
43057bf2 1187 quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
e38e0df0 1188 start_time = time_now.tv_sec;
43057bf2 1189 start_time = (start_time * 1000000) + time_now.tv_usec;
f390d2c7 1190
eb5d44eb 1191 if (family == AF_INET)
1192 spftree = area->spftree[level - 1];
1193#ifdef HAVE_IPV6
1194 else if (family == AF_INET6)
1195 spftree = area->spftree6[level - 1];
1196#endif
eb5d44eb 1197 assert (spftree);
3f045a08 1198 assert (sysid);
eb5d44eb 1199
fac1f7cc 1200 /* Make all routes in current route table inactive. */
1201 if (family == AF_INET)
1202 table = area->route_table[level - 1];
41b36e90 1203#ifdef HAVE_IPV6
fac1f7cc 1204 else if (family == AF_INET6)
1205 table = area->route_table6[level - 1];
41b36e90 1206#endif
fac1f7cc 1207
3f045a08 1208 isis_route_invalidate_table (area, table);
fac1f7cc 1209
eb5d44eb 1210 /*
1211 * C.2.5 Step 0
1212 */
1213 init_spt (spftree);
1214 /* a) */
3f045a08 1215 root_vertex = isis_spf_add_root (spftree, level, sysid);
eb5d44eb 1216 /* b) */
3f045a08
JB
1217 retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
1218 if (retval != ISIS_OK)
1219 {
1220 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
1221 goto out;
1222 }
f390d2c7 1223
eb5d44eb 1224 /*
1225 * C.2.7 Step 2
1226 */
f390d2c7 1227 if (listcount (spftree->tents) == 0)
1228 {
3f045a08 1229 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
13fb40ac 1230 goto out;
f390d2c7 1231 }
1232
1233 while (listcount (spftree->tents) > 0)
1234 {
1235 node = listhead (spftree->tents);
1eb8ef25 1236 vertex = listgetdata (node);
3f045a08
JB
1237
1238#ifdef EXTREME_DEBUG
1239 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1240 print_sys_hostname (vertex->N.id),
1241 vtype2string (vertex->type), vertex->depth, vertex->d_N);
1242#endif /* EXTREME_DEBUG */
1243
1244 /* Remove from tent list and add to paths list */
f390d2c7 1245 list_delete_node (spftree->tents, node);
3f045a08
JB
1246 add_to_paths (spftree, vertex, level);
1247 switch (vertex->type)
1248 {
1249 case VTYPE_PSEUDO_IS:
1250 case VTYPE_NONPSEUDO_IS:
1251 case VTYPE_PSEUDO_TE_IS:
1252 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 1253 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1254 LSP_FRAGMENT (lsp_id) = 0;
1255 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
e38e0df0 1256 if (lsp && lsp->lsp_header->rem_lifetime != 0)
f390d2c7 1257 {
1258 if (LSP_PSEUDO_ID (lsp_id))
1259 {
1260 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
3f045a08
JB
1261 vertex->depth, family, sysid,
1262 vertex);
f390d2c7 1263 }
1264 else
1265 {
1266 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
3f045a08 1267 vertex->depth, family, sysid, vertex);
f390d2c7 1268 }
1269 }
1270 else
1271 {
1272 zlog_warn ("ISIS-Spf: No LSP found for %s",
1273 rawlspid_print (lsp_id));
1274 }
3f045a08
JB
1275 break;
1276 default:;
eb5d44eb 1277 }
eb5d44eb 1278 }
f390d2c7 1279
13fb40ac 1280out:
3f045a08 1281 isis_route_validate (area);
eb5d44eb 1282 spftree->pending = 0;
e38e0df0
SV
1283 spftree->runcount++;
1284 spftree->last_run_timestamp = time (NULL);
43057bf2 1285 quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
e38e0df0 1286 end_time = time_now.tv_sec;
43057bf2 1287 end_time = (end_time * 1000000) + time_now.tv_usec;
e38e0df0
SV
1288 spftree->last_run_duration = end_time - start_time;
1289
f390d2c7 1290
eb5d44eb 1291 return retval;
1292}
1293
1294int
1295isis_run_spf_l1 (struct thread *thread)
1296{
1297 struct isis_area *area;
1298 int retval = ISIS_OK;
1299
f390d2c7 1300 area = THREAD_ARG (thread);
eb5d44eb 1301 assert (area);
1302
12a5cae7 1303 area->spftree[0]->t_spf = NULL;
3f045a08 1304 area->spftree[0]->pending = 0;
12a5cae7 1305
f390d2c7 1306 if (!(area->is_type & IS_LEVEL_1))
1307 {
1308 if (isis->debugs & DEBUG_SPF_EVENTS)
12a5cae7 1309 zlog_warn ("ISIS-SPF (%s) area does not share level",
1310 area->area_tag);
f390d2c7 1311 return ISIS_WARNING;
1312 }
1313
1314 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1315 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
eb5d44eb 1316
eb5d44eb 1317 if (area->ip_circuits)
3f045a08 1318 retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
12a5cae7 1319
eb5d44eb 1320 return retval;
1321}
1322
1323int
1324isis_run_spf_l2 (struct thread *thread)
1325{
1326 struct isis_area *area;
1327 int retval = ISIS_OK;
1328
f390d2c7 1329 area = THREAD_ARG (thread);
eb5d44eb 1330 assert (area);
f390d2c7 1331
12a5cae7 1332 area->spftree[1]->t_spf = NULL;
3f045a08 1333 area->spftree[1]->pending = 0;
12a5cae7 1334
f390d2c7 1335 if (!(area->is_type & IS_LEVEL_2))
1336 {
1337 if (isis->debugs & DEBUG_SPF_EVENTS)
12a5cae7 1338 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
f390d2c7 1339 return ISIS_WARNING;
1340 }
1341
1342 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1343 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
eb5d44eb 1344
1345 if (area->ip_circuits)
3f045a08 1346 retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
eb5d44eb 1347
1348 return retval;
1349}
1350
f390d2c7 1351int
eb5d44eb 1352isis_spf_schedule (struct isis_area *area, int level)
1353{
eb5d44eb 1354 struct isis_spftree *spftree = area->spftree[level - 1];
3f045a08 1355 time_t now = time (NULL);
e38e0df0 1356 int diff = now - spftree->last_run_timestamp;
eb5d44eb 1357
3f045a08
JB
1358 assert (diff >= 0);
1359 assert (area->is_type & level);
eb5d44eb 1360
3f045a08
JB
1361 if (isis->debugs & DEBUG_SPF_EVENTS)
1362 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1363 area->area_tag, level, diff);
f390d2c7 1364
3f045a08
JB
1365 if (spftree->pending)
1366 return ISIS_OK;
12a5cae7 1367
1368 THREAD_TIMER_OFF (spftree->t_spf);
f390d2c7 1369
e38e0df0
SV
1370 /* wait configured min_spf_interval before doing the SPF */
1371 if (diff >= area->min_spf_interval[level-1])
3f045a08 1372 return isis_run_spf (area, level, AF_INET, isis->sysid);
f390d2c7 1373
3f045a08
JB
1374 if (level == 1)
1375 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
e38e0df0 1376 area->min_spf_interval[0] - diff);
f390d2c7 1377 else
3f045a08 1378 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
e38e0df0 1379 area->min_spf_interval[1] - diff);
eb5d44eb 1380
3f045a08
JB
1381 if (isis->debugs & DEBUG_SPF_EVENTS)
1382 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
e38e0df0 1383 area->area_tag, level, area->min_spf_interval[level-1] - diff);
3f045a08
JB
1384
1385 spftree->pending = 1;
1386
1387 return ISIS_OK;
eb5d44eb 1388}
1389
1390#ifdef HAVE_IPV6
92365889 1391static int
12a5cae7 1392isis_run_spf6_l1 (struct thread *thread)
1393{
1394 struct isis_area *area;
1395 int retval = ISIS_OK;
1396
1397 area = THREAD_ARG (thread);
1398 assert (area);
1399
1400 area->spftree6[0]->t_spf = NULL;
3f045a08 1401 area->spftree6[0]->pending = 0;
12a5cae7 1402
1403 if (!(area->is_type & IS_LEVEL_1))
1404 {
1405 if (isis->debugs & DEBUG_SPF_EVENTS)
3f045a08 1406 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
12a5cae7 1407 return ISIS_WARNING;
1408 }
1409
1410 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1411 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
12a5cae7 1412
1413 if (area->ipv6_circuits)
3f045a08 1414 retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
12a5cae7 1415
1416 return retval;
1417}
1418
92365889 1419static int
12a5cae7 1420isis_run_spf6_l2 (struct thread *thread)
1421{
1422 struct isis_area *area;
1423 int retval = ISIS_OK;
1424
1425 area = THREAD_ARG (thread);
1426 assert (area);
1427
1428 area->spftree6[1]->t_spf = NULL;
3f045a08 1429 area->spftree6[1]->pending = 0;
12a5cae7 1430
1431 if (!(area->is_type & IS_LEVEL_2))
1432 {
1433 if (isis->debugs & DEBUG_SPF_EVENTS)
1434 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1435 return ISIS_WARNING;
1436 }
1437
1438 if (isis->debugs & DEBUG_SPF_EVENTS)
fac1f7cc 1439 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
12a5cae7 1440
1441 if (area->ipv6_circuits)
3f045a08 1442 retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
12a5cae7 1443
1444 return retval;
1445}
1446
f390d2c7 1447int
eb5d44eb 1448isis_spf_schedule6 (struct isis_area *area, int level)
1449{
1450 int retval = ISIS_OK;
1451 struct isis_spftree *spftree = area->spftree6[level - 1];
e38e0df0
SV
1452 time_t now = time (NULL);
1453 time_t diff = now - spftree->last_run_timestamp;
1454
1455 assert (diff >= 0);
1456 assert (area->is_type & level);
1457
1458 if (isis->debugs & DEBUG_SPF_EVENTS)
1459 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1460 area->area_tag, level, diff);
eb5d44eb 1461
1462 if (spftree->pending)
e38e0df0 1463 return ISIS_OK;
eb5d44eb 1464
12a5cae7 1465 THREAD_TIMER_OFF (spftree->t_spf);
eb5d44eb 1466
e38e0df0
SV
1467 /* wait configured min_spf_interval before doing the SPF */
1468 if (diff >= area->min_spf_interval[level-1])
1469 return isis_run_spf (area, level, AF_INET6, isis->sysid);
1470
1471 if (level == 1)
1472 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1473 area->min_spf_interval[0] - diff);
3f045a08 1474 else
e38e0df0
SV
1475 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1476 area->min_spf_interval[1] - diff);
3f045a08 1477
e38e0df0
SV
1478 if (isis->debugs & DEBUG_SPF_EVENTS)
1479 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
1480 area->area_tag, level, area->min_spf_interval[level-1] - diff);
f390d2c7 1481
e38e0df0 1482 spftree->pending = 1;
eb5d44eb 1483
1484 return retval;
1485}
eb5d44eb 1486#endif
1487
92365889 1488static void
3f045a08 1489isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
eb5d44eb 1490{
1eb8ef25 1491 struct listnode *node;
3f045a08 1492 struct listnode *anode;
eb5d44eb 1493 struct isis_vertex *vertex;
eb5d44eb 1494 struct isis_adjacency *adj;
e8aca32f 1495 u_char buff[BUFSIZ];
eb5d44eb 1496
3f045a08
JB
1497 vty_out (vty, "Vertex Type Metric "
1498 "Next-Hop Interface Parent%s", VTY_NEWLINE);
1499
1500 for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) {
1501 if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
1502 vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid),
1503 "", "");
1504 vty_out (vty, "%-30s", "");
1505 } else {
1506 int rows = 0;
1507 vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff),
1508 vtype2string (vertex->type), vertex->d_N);
1509 for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) {
1510 if (adj) {
1511 if (rows) {
1512 vty_out (vty, "%s", VTY_NEWLINE);
1513 vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
1514 }
1515 vty_out (vty, "%-20s %-9s ",
1516 print_sys_hostname (adj->sysid),
1517 adj->circuit->interface->name);
1518 ++rows;
1519 }
1520 }
1521 if (rows == 0)
1522 vty_out (vty, "%-30s ", "");
1523 }
1eb8ef25 1524
3f045a08
JB
1525 /* Print list of parents for the ECMP DAG */
1526 if (listcount (vertex->parents) > 0) {
1527 struct listnode *pnode;
1528 struct isis_vertex *pvertex;
1529 int rows = 0;
1530 for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
1531 if (rows) {
1532 vty_out (vty, "%s", VTY_NEWLINE);
1533 vty_out (vty, "%-72s", "");
1534 }
1535 vty_out (vty, "%s(%d)",
1536 vid2string (pvertex, buff), pvertex->type);
1537 ++rows;
f390d2c7 1538 }
3f045a08
JB
1539 } else {
1540 vty_out (vty, " NULL ");
1541 }
1542
1543#if 0
1544 if (listcount (vertex->children) > 0) {
1545 struct listnode *cnode;
1546 struct isis_vertex *cvertex;
1547 for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) {
1548 vty_out (vty, "%s", VTY_NEWLINE);
1549 vty_out (vty, "%-72s", "");
1550 vty_out (vty, "%s(%d) ",
1551 vid2string (cvertex, buff), cvertex->type);
f390d2c7 1552 }
1553 }
eb5d44eb 1554#endif
3f045a08 1555 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1556 }
eb5d44eb 1557}
1558
1559DEFUN (show_isis_topology,
1560 show_isis_topology_cmd,
1561 "show isis topology",
1562 SHOW_STR
1563 "IS-IS information\n"
1564 "IS-IS paths to Intermediate Systems\n")
1565{
1566 struct listnode *node;
1567 struct isis_area *area;
1568 int level;
f390d2c7 1569
eb5d44eb 1570 if (!isis->area_list || isis->area_list->count == 0)
1571 return CMD_SUCCESS;
1572
1eb8ef25 1573 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1574 {
f390d2c7 1575 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1576 VTY_NEWLINE);
1577
1578 for (level = 0; level < ISIS_LEVELS; level++)
1579 {
1580 if (area->ip_circuits > 0 && area->spftree[level]
1581 && area->spftree[level]->paths->count > 0)
1582 {
1583 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1584 level + 1, VTY_NEWLINE);
3f045a08
JB
1585 isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
1586 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1587 }
eb5d44eb 1588#ifdef HAVE_IPV6
f390d2c7 1589 if (area->ipv6_circuits > 0 && area->spftree6[level]
1590 && area->spftree6[level]->paths->count > 0)
1591 {
1592 vty_out (vty,
1593 "IS-IS paths to level-%d routers that speak IPv6%s",
1594 level + 1, VTY_NEWLINE);
3f045a08
JB
1595 isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
1596 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1597 }
eb5d44eb 1598#endif /* HAVE_IPV6 */
f390d2c7 1599 }
3f045a08
JB
1600
1601 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1602 }
eb5d44eb 1603
1604 return CMD_SUCCESS;
f390d2c7 1605}
eb5d44eb 1606
1607DEFUN (show_isis_topology_l1,
1608 show_isis_topology_l1_cmd,
1609 "show isis topology level-1",
1610 SHOW_STR
1611 "IS-IS information\n"
1612 "IS-IS paths to Intermediate Systems\n"
1613 "Paths to all level-1 routers in the area\n")
1614{
1615 struct listnode *node;
1616 struct isis_area *area;
f390d2c7 1617
eb5d44eb 1618 if (!isis->area_list || isis->area_list->count == 0)
1619 return CMD_SUCCESS;
1620
1eb8ef25 1621 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1622 {
f390d2c7 1623 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1624 VTY_NEWLINE);
1625
1626 if (area->ip_circuits > 0 && area->spftree[0]
1627 && area->spftree[0]->paths->count > 0)
1628 {
1629 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1630 VTY_NEWLINE);
3f045a08
JB
1631 isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
1632 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1633 }
eb5d44eb 1634#ifdef HAVE_IPV6
f390d2c7 1635 if (area->ipv6_circuits > 0 && area->spftree6[0]
1636 && area->spftree6[0]->paths->count > 0)
1637 {
1638 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1639 VTY_NEWLINE);
3f045a08
JB
1640 isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
1641 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1642 }
eb5d44eb 1643#endif /* HAVE_IPV6 */
3f045a08 1644 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1645 }
1646
eb5d44eb 1647 return CMD_SUCCESS;
f390d2c7 1648}
eb5d44eb 1649
1650DEFUN (show_isis_topology_l2,
1651 show_isis_topology_l2_cmd,
1652 "show isis topology level-2",
1653 SHOW_STR
1654 "IS-IS information\n"
1655 "IS-IS paths to Intermediate Systems\n"
1656 "Paths to all level-2 routers in the domain\n")
1657{
1658 struct listnode *node;
1659 struct isis_area *area;
f390d2c7 1660
eb5d44eb 1661 if (!isis->area_list || isis->area_list->count == 0)
1662 return CMD_SUCCESS;
1663
1eb8ef25 1664 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1665 {
f390d2c7 1666 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1667 VTY_NEWLINE);
1668
1669 if (area->ip_circuits > 0 && area->spftree[1]
1670 && area->spftree[1]->paths->count > 0)
1671 {
1672 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1673 VTY_NEWLINE);
3f045a08
JB
1674 isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
1675 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1676 }
eb5d44eb 1677#ifdef HAVE_IPV6
f390d2c7 1678 if (area->ipv6_circuits > 0 && area->spftree6[1]
1679 && area->spftree6[1]->paths->count > 0)
1680 {
1681 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1682 VTY_NEWLINE);
3f045a08
JB
1683 isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
1684 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1685 }
eb5d44eb 1686#endif /* HAVE_IPV6 */
3f045a08 1687 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1688 }
1689
eb5d44eb 1690 return CMD_SUCCESS;
f390d2c7 1691}
eb5d44eb 1692
1693void
1694isis_spf_cmds_init ()
1695{
1696 install_element (VIEW_NODE, &show_isis_topology_cmd);
1697 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1698 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1699
1700 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1701 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1702 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1703}