]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_spf.c
ca268cec7e3843fa1fa8202f47767824b9a37435
[mirror_frr.git] / isisd / isis_spf.c
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 * Copyright (C) 2017 Christian Franke <chris@opensourcerouting.org>
9 *
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)
13 * any later version.
14 *
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
18 * more details.
19 *
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
23 */
24
25 #include <zebra.h>
26
27 #include "thread.h"
28 #include "linklist.h"
29 #include "vty.h"
30 #include "log.h"
31 #include "command.h"
32 #include "memory.h"
33 #include "prefix.h"
34 #include "hash.h"
35 #include "if.h"
36 #include "table.h"
37 #include "spf_backoff.h"
38
39 #include "isis_constants.h"
40 #include "isis_common.h"
41 #include "isis_flags.h"
42 #include "dict.h"
43 #include "isisd.h"
44 #include "isis_misc.h"
45 #include "isis_adjacency.h"
46 #include "isis_circuit.h"
47 #include "isis_tlv.h"
48 #include "isis_pdu.h"
49 #include "isis_lsp.h"
50 #include "isis_dynhn.h"
51 #include "isis_spf.h"
52 #include "isis_route.h"
53 #include "isis_csm.h"
54 #include "isis_mt.h"
55
56 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
57
58 struct isis_spf_run {
59 struct isis_area *area;
60 int level;
61 };
62
63 /* 7.2.7 */
64 static void
65 remove_excess_adjs (struct list *adjs)
66 {
67 struct listnode *node, *excess = NULL;
68 struct isis_adjacency *adj, *candidate = NULL;
69 int comp;
70
71 for (ALL_LIST_ELEMENTS_RO (adjs, node, adj))
72 {
73 if (excess == NULL)
74 excess = node;
75 candidate = listgetdata (excess);
76
77 if (candidate->sys_type < adj->sys_type)
78 {
79 excess = node;
80 continue;
81 }
82 if (candidate->sys_type > adj->sys_type)
83 continue;
84
85 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
86 if (comp > 0)
87 {
88 excess = node;
89 continue;
90 }
91 if (comp < 0)
92 continue;
93
94 if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
95 {
96 excess = node;
97 continue;
98 }
99
100 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
101 continue;
102
103 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
104 if (comp > 0)
105 {
106 excess = node;
107 continue;
108 }
109 }
110
111 list_delete_node (adjs, excess);
112
113 return;
114 }
115
116 static const char *
117 vtype2string (enum vertextype vtype)
118 {
119 switch (vtype)
120 {
121 case VTYPE_PSEUDO_IS:
122 return "pseudo_IS";
123 break;
124 case VTYPE_PSEUDO_TE_IS:
125 return "pseudo_TE-IS";
126 break;
127 case VTYPE_NONPSEUDO_IS:
128 return "IS";
129 break;
130 case VTYPE_NONPSEUDO_TE_IS:
131 return "TE-IS";
132 break;
133 case VTYPE_ES:
134 return "ES";
135 break;
136 case VTYPE_IPREACH_INTERNAL:
137 return "IP internal";
138 break;
139 case VTYPE_IPREACH_EXTERNAL:
140 return "IP external";
141 break;
142 case VTYPE_IPREACH_TE:
143 return "IP TE";
144 break;
145 case VTYPE_IP6REACH_INTERNAL:
146 return "IP6 internal";
147 break;
148 case VTYPE_IP6REACH_EXTERNAL:
149 return "IP6 external";
150 break;
151 default:
152 return "UNKNOWN";
153 }
154 return NULL; /* Not reached */
155 }
156
157 static const char *
158 vid2string (struct isis_vertex *vertex, char * buff, int size)
159 {
160 if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
161 {
162 return print_sys_hostname (vertex->N.id);
163 }
164
165 if (VTYPE_IP(vertex->type))
166 {
167 prefix2str ((struct prefix *) &vertex->N.prefix, buff, size);
168 return buff;
169 }
170
171 return "UNKNOWN";
172 }
173
174 static struct isis_vertex *
175 isis_vertex_new (void *id, enum vertextype vtype)
176 {
177 struct isis_vertex *vertex;
178
179 vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
180
181 vertex->type = vtype;
182
183 if (VTYPE_IS(vtype) || VTYPE_ES(vtype))
184 {
185 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
186 }
187 else if (VTYPE_IP(vtype))
188 {
189 memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix));
190 }
191 else
192 {
193 zlog_err ("WTF!");
194 }
195
196 vertex->Adj_N = list_new ();
197 vertex->parents = list_new ();
198 vertex->children = list_new ();
199
200 return vertex;
201 }
202
203 static void
204 isis_vertex_del (struct isis_vertex *vertex)
205 {
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;
212
213 memset(vertex, 0, sizeof(struct isis_vertex));
214 XFREE (MTYPE_ISIS_VERTEX, vertex);
215
216 return;
217 }
218
219 static void
220 isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
221 {
222 struct listnode *node, *nextnode;
223 if (!vertex)
224 return;
225 for (node = listhead (vertex->Adj_N); node; node = nextnode)
226 {
227 nextnode = listnextnode(node);
228 if (listgetdata(node) == adj)
229 list_delete_node(vertex->Adj_N, node);
230 }
231 return;
232 }
233
234 struct isis_spftree *
235 isis_spftree_new (struct isis_area *area)
236 {
237 struct isis_spftree *tree;
238
239 tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
240 if (tree == NULL)
241 {
242 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
243 return NULL;
244 }
245
246 tree->tents = list_new ();
247 tree->paths = list_new ();
248 tree->area = area;
249 tree->last_run_timestamp = 0;
250 tree->last_run_duration = 0;
251 tree->runcount = 0;
252 return tree;
253 }
254
255 void
256 isis_spftree_del (struct isis_spftree *spftree)
257 {
258
259 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
260 list_delete (spftree->tents);
261 spftree->tents = NULL;
262
263 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
264 list_delete (spftree->paths);
265 spftree->paths = NULL;
266
267 XFREE (MTYPE_ISIS_SPFTREE, spftree);
268
269 return;
270 }
271
272 static void
273 isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
274 {
275 struct listnode *node;
276 if (!adj)
277 return;
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);
282 return;
283 }
284
285 void
286 spftree_area_init (struct isis_area *area)
287 {
288 if (area->is_type & IS_LEVEL_1)
289 {
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);
294 }
295
296 if (area->is_type & IS_LEVEL_2)
297 {
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);
302 }
303
304 return;
305 }
306
307 void
308 spftree_area_del (struct isis_area *area)
309 {
310 if (area->is_type & IS_LEVEL_1)
311 {
312 if (area->spftree[0] != NULL)
313 {
314 isis_spftree_del (area->spftree[0]);
315 area->spftree[0] = NULL;
316 }
317 if (area->spftree6[0])
318 {
319 isis_spftree_del (area->spftree6[0]);
320 area->spftree6[0] = NULL;
321 }
322 }
323
324 if (area->is_type & IS_LEVEL_2)
325 {
326 if (area->spftree[1] != NULL)
327 {
328 isis_spftree_del (area->spftree[1]);
329 area->spftree[1] = NULL;
330 }
331 if (area->spftree6[1] != NULL)
332 {
333 isis_spftree_del (area->spftree6[1]);
334 area->spftree6[1] = NULL;
335 }
336 }
337
338 return;
339 }
340
341 void
342 spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
343 {
344 if (area->is_type & IS_LEVEL_1)
345 {
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);
350 }
351
352 if (area->is_type & IS_LEVEL_2)
353 {
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);
358 }
359
360 return;
361 }
362
363 /*
364 * Find the system LSP: returns the LSP in our LSP database
365 * associated with the given system ID.
366 */
367 static struct isis_lsp *
368 isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
369 {
370 struct isis_lsp *lsp;
371 u_char lspid[ISIS_SYS_ID_LEN + 2];
372
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)
378 return lsp;
379 return NULL;
380 }
381
382 /*
383 * Add this IS to the root of SPT
384 */
385 static struct isis_vertex *
386 isis_spf_add_root (struct isis_spftree *spftree, u_char *sysid)
387 {
388 struct isis_vertex *vertex;
389 struct isis_lsp *lsp;
390 #ifdef EXTREME_DEBUG
391 char buff[PREFIX2STR_BUFFER];
392 #endif /* EXTREME_DEBUG */
393 u_char id[ISIS_SYS_ID_LEN + 1];
394
395 memcpy(id, sysid, ISIS_SYS_ID_LEN);
396 LSP_PSEUDO_ID(id) = 0;
397
398 lsp = isis_root_system_lsp (spftree->area, spftree->level, sysid);
399 if (lsp == NULL)
400 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", spftree->level);
401
402 vertex = isis_vertex_new (id, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS
403 : VTYPE_NONPSEUDO_TE_IS);
404 listnode_add (spftree->paths, vertex);
405
406 #ifdef EXTREME_DEBUG
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 */
411
412 return vertex;
413 }
414
415 static struct isis_vertex *
416 isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
417 {
418 struct listnode *node;
419 struct isis_vertex *vertex;
420 struct prefix *p1, *p2;
421
422 for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
423 {
424 if (vertex->type != vtype)
425 continue;
426 if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type))
427 {
428 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
429 return vertex;
430 }
431 if (VTYPE_IP(vertex->type))
432 {
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)))
438 {
439 return vertex;
440 }
441 }
442 }
443
444 return NULL;
445 }
446
447 /*
448 * Compares vertizes for sorting in the TENT list. Returns true
449 * if candidate should be considered before current, false otherwise.
450 */
451 static bool
452 tent_cmp (struct isis_vertex *current, struct isis_vertex *candidate)
453 {
454 if (current->d_N > candidate->d_N)
455 return true;
456
457 if (current->d_N == candidate->d_N
458 && current->type > candidate->type)
459 return true;
460
461 return false;
462 }
463
464 /*
465 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
466 */
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)
471 {
472 struct isis_vertex *vertex, *v;
473 struct listnode *node;
474 struct isis_adjacency *parent_adj;
475 #ifdef EXTREME_DEBUG
476 char buff[PREFIX2STR_BUFFER];
477 #endif
478
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);
482 vertex->d_N = cost;
483 vertex->depth = depth;
484
485 if (parent) {
486 listnode_add (vertex->parents, parent);
487 if (listnode_lookup (parent->children, vertex) == NULL)
488 listnode_add (parent->children, vertex);
489 }
490
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);
494 } else if (adj) {
495 listnode_add (vertex->Adj_N, adj);
496 }
497
498 #ifdef EXTREME_DEBUG
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 */
504
505 if (list_isempty (spftree->tents))
506 {
507 listnode_add (spftree->tents, vertex);
508 return vertex;
509 }
510
511 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
512 for (node = listhead (spftree->tents); node; node = listnextnode (node))
513 {
514 v = listgetdata (node);
515 if (tent_cmp(v, vertex))
516 {
517 listnode_add_before (spftree->tents, node, vertex);
518 break;
519 }
520 }
521
522 if (node == NULL)
523 listnode_add (spftree->tents, vertex);
524
525 return vertex;
526 }
527
528 static void
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)
532 {
533 struct isis_vertex *vertex;
534
535 vertex = isis_find_vertex (spftree->tents, id, vtype);
536
537 if (vertex)
538 {
539 /* C.2.5 c) */
540 if (vertex->d_N == cost)
541 {
542 if (adj)
543 listnode_add (vertex->Adj_N, adj);
544 /* d) */
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);
551 return;
552 }
553 else if (vertex->d_N < cost)
554 {
555 /* e) do nothing */
556 return;
557 }
558 else { /* vertex->d_N > cost */
559 /* f) */
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);
567 }
568 }
569
570 isis_spf_add2tent (spftree, vtype, id, cost, 1, adj, parent);
571 return;
572 }
573
574 static void
575 process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
576 uint32_t dist, uint16_t depth,
577 struct isis_vertex *parent)
578 {
579 struct isis_vertex *vertex;
580 #ifdef EXTREME_DEBUG
581 char buff[PREFIX2STR_BUFFER];
582 #endif
583
584 assert (spftree && parent);
585
586 /* RFC3787 section 5.1 */
587 if (spftree->area->newmetric == 1)
588 {
589 if (dist > MAX_WIDE_PATH_METRIC)
590 return;
591 }
592 /* C.2.6 b) */
593 else if (spftree->area->oldmetric == 1)
594 {
595 if (dist > MAX_NARROW_PATH_METRIC)
596 return;
597 }
598
599 /* c) */
600 vertex = isis_find_vertex (spftree->paths, id, vtype);
601 if (vertex)
602 {
603 #ifdef EXTREME_DEBUG
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);
609 return;
610 }
611
612 vertex = isis_find_vertex (spftree->tents, id, vtype);
613 /* d) */
614 if (vertex)
615 {
616 /* 1) */
617 #ifdef EXTREME_DEBUG
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)
625 {
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);
631 /* 2) */
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);
638 /* 3) */
639 return;
640 }
641 else if (vertex->d_N < dist)
642 {
643 return;
644 /* 4) */
645 }
646 else
647 {
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);
655 }
656 }
657
658 #ifdef EXTREME_DEBUG
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 */
663
664 isis_spf_add2tent (spftree, vtype, id, dist, depth, NULL, parent);
665 return;
666 }
667
668 /*
669 * C.2.6 Step 1
670 */
671 static int
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)
675 {
676 bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id);
677 struct listnode *node, *fragnode = NULL;
678 uint32_t dist;
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;
688
689 if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
690 mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, spftree->mtid);
691
692 if (!pseudo_lsp
693 && (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks(lsp->tlv_data.nlpids, spftree->family))
694 && !mt_router_info)
695 return ISIS_OK;
696
697 lspfragloop:
698 if (lsp->lsp_header->seq_num == 0)
699 {
700 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
701 return ISIS_WARNING;
702 }
703
704 #ifdef EXTREME_DEBUG
705 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
706 #endif /* EXTREME_DEBUG */
707
708 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
709 if (pseudo_lsp
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))
712
713 {
714 if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
715 {
716 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
717 {
718 /* C.2.6 a) */
719 /* Two way connectivity */
720 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
721 continue;
722 if (!pseudo_lsp && !memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
723 continue;
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);
728 }
729 }
730
731 struct list *te_is_neighs = NULL;
732 if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
733 {
734 te_is_neighs = lsp->tlv_data.te_is_neighs;
735 }
736 else
737 {
738 struct tlv_mt_neighbors *mt_neighbors;
739 mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, spftree->mtid);
740 if (mt_neighbors)
741 te_is_neighs = mt_neighbors->list;
742 }
743 for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
744 {
745 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
746 continue;
747 if (!pseudo_lsp && !memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
748 continue;
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);
753 }
754 }
755
756 if (!pseudo_lsp
757 && spftree->family == AF_INET
758 && spftree->mtid == ISIS_MT_IPV4_UNICAST)
759 {
760 struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
761 lsp->tlv_data.ipv4_ext_reachs};
762
763 prefix.family = AF_INET;
764 for (unsigned int i = 0; i < array_size(reachs); i++)
765 {
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))
769 {
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,
775 parent);
776 }
777 }
778 }
779
780 if (!pseudo_lsp && spftree->family == AF_INET)
781 {
782 struct list *ipv4reachs = NULL;
783
784 if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
785 {
786 ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
787 }
788 else
789 {
790 struct tlv_mt_ipv4_reachs *mt_reachs;
791 mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, spftree->mtid);
792 if (mt_reachs)
793 ipv4reachs = mt_reachs->list;
794 }
795
796 prefix.family = AF_INET;
797 for (ALL_LIST_ELEMENTS_RO (ipv4reachs, node, te_ipv4_reach))
798 {
799 assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
800
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,
807 parent);
808 }
809 }
810
811 if (!pseudo_lsp
812 && spftree->family == AF_INET6)
813 {
814 struct list *ipv6reachs = NULL;
815
816 if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
817 {
818 ipv6reachs = lsp->tlv_data.ipv6_reachs;
819 }
820 else
821 {
822 struct tlv_mt_ipv6_reachs *mt_reachs;
823 mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, spftree->mtid);
824 if (mt_reachs)
825 ipv6reachs = mt_reachs->list;
826 }
827
828 prefix.family = AF_INET6;
829 for (ALL_LIST_ELEMENTS_RO (ipv6reachs, node, ip6reach))
830 {
831 assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
832
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,
841 parent);
842 }
843 }
844
845 if (fragnode == NULL)
846 fragnode = listhead (lsp->lspu.frags);
847 else
848 fragnode = listnextnode (fragnode);
849
850 if (fragnode)
851 {
852 lsp = listgetdata (fragnode);
853 goto lspfragloop;
854 }
855
856 return ISIS_OK;
857 }
858
859 static int
860 isis_spf_preload_tent (struct isis_spftree *spftree,
861 u_char *root_sysid,
862 struct isis_vertex *parent)
863 {
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;
869 struct list *adjdb;
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;
877
878 for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
879 {
880 circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
881 if (circuit_mt && !circuit_mt->enabled)
882 continue;
883 if (circuit->state != C_STATE_UP)
884 continue;
885 if (!(circuit->is_type & spftree->level))
886 continue;
887 if (spftree->family == AF_INET && !circuit->ip_router)
888 continue;
889 if (spftree->family == AF_INET6 && !circuit->ipv6_router)
890 continue;
891 /*
892 * Add IP(v6) addresses of this circuit
893 */
894 if (spftree->family == AF_INET)
895 {
896 prefix.family = AF_INET;
897 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
898 {
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,
903 NULL, 0, parent);
904 }
905 }
906 if (spftree->family == AF_INET6)
907 {
908 prefix.family = AF_INET6;
909 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
910 {
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);
916 }
917 }
918 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
919 {
920 /*
921 * Add the adjacencies
922 */
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)
927 {
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);
932 continue;
933 }
934 for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
935 {
936 if (!adj_has_mt(adj, spftree->mtid))
937 continue;
938 if (spftree->mtid == ISIS_MT_IPV4_UNICAST && !speaks (&adj->nlpids, spftree->family))
939 continue;
940 switch (adj->sys_type)
941 {
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],
947 parent);
948 break;
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,
958 lsp_id, adj,
959 circuit->te_metric[spftree->level - 1],
960 parent);
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 "
964 "L%d on %s (ID %u)",
965 rawlspid_print (lsp_id), spftree->level,
966 circuit->interface->name, circuit->circuit_id);
967 break;
968 case ISIS_SYSTYPE_UNKNOWN:
969 default:
970 zlog_warn ("isis_spf_preload_tent unknow adj type");
971 }
972 }
973 list_delete (adj_list);
974 /*
975 * Add the pseudonode
976 */
977 if (spftree->level == 1)
978 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
979 else
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)
983 {
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);
987 continue;
988 }
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])
992 {
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);
997 continue;
998 }
999 lsp = lsp_search (lsp_id, spftree->area->lspdb[spftree->level - 1]);
1000 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
1001 {
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);
1006 continue;
1007 }
1008 isis_spf_process_lsp (spftree, lsp,
1009 circuit->te_metric[spftree->level - 1], 0,
1010 root_sysid, parent);
1011 }
1012 else if (circuit->circ_type == CIRCUIT_T_P2P)
1013 {
1014 adj = circuit->u.p2p.neighbor;
1015 if (!adj)
1016 continue;
1017 if (!adj_has_mt(adj, spftree->mtid))
1018 continue;
1019 switch (adj->sys_type)
1020 {
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],
1026 parent);
1027 break;
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,
1038 lsp_id,
1039 adj, circuit->te_metric[spftree->level - 1],
1040 parent);
1041 break;
1042 case ISIS_SYSTYPE_UNKNOWN:
1043 default:
1044 zlog_warn ("isis_spf_preload_tent unknown adj type");
1045 break;
1046 }
1047 }
1048 else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
1049 {
1050 continue;
1051 }
1052 else
1053 {
1054 zlog_warn ("isis_spf_preload_tent unsupported media");
1055 retval = ISIS_WARNING;
1056 }
1057 }
1058
1059 return retval;
1060 }
1061
1062 /*
1063 * The parent(s) for vertex is set when added to TENT list
1064 * now we just put the child pointer(s) in place
1065 */
1066 static void
1067 add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex)
1068 {
1069 char buff[PREFIX2STR_BUFFER];
1070
1071 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
1072 return;
1073 listnode_add (spftree->paths, vertex);
1074
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 */
1081
1082 if (VTYPE_IP(vertex->type))
1083 {
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);
1091 }
1092
1093 return;
1094 }
1095
1096 static void
1097 init_spt (struct isis_spftree *spftree, int mtid, int level, int family)
1098 {
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;
1103
1104 spftree->mtid = mtid;
1105 spftree->level = level;
1106 spftree->family = family;
1107 return;
1108 }
1109
1110 static int
1111 isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
1112 {
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;
1123 uint16_t mtid;
1124
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;
1129
1130 if (family == AF_INET)
1131 spftree = area->spftree[level - 1];
1132 else if (family == AF_INET6)
1133 spftree = area->spftree6[level - 1];
1134 assert (spftree);
1135 assert (sysid);
1136
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];
1142
1143 isis_route_invalidate_table (area, table);
1144
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);
1148 else
1149 mtid = ISIS_MT_IPV4_UNICAST;
1150
1151 /*
1152 * C.2.5 Step 0
1153 */
1154 init_spt (spftree, mtid, level, family);
1155 /* a) */
1156 root_vertex = isis_spf_add_root (spftree, sysid);
1157 /* b) */
1158 retval = isis_spf_preload_tent (spftree, sysid, root_vertex);
1159 if (retval != ISIS_OK)
1160 {
1161 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
1162 goto out;
1163 }
1164
1165 /*
1166 * C.2.7 Step 2
1167 */
1168 if (listcount (spftree->tents) == 0)
1169 {
1170 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
1171 goto out;
1172 }
1173
1174 while (listcount (spftree->tents) > 0)
1175 {
1176 node = listhead (spftree->tents);
1177 vertex = listgetdata (node);
1178
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 */
1184
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))
1189 {
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)
1194 {
1195 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
1196 vertex->depth, sysid, vertex);
1197 }
1198 else
1199 {
1200 zlog_warn ("ISIS-Spf: No LSP found for %s",
1201 rawlspid_print (lsp_id));
1202 }
1203 }
1204 }
1205
1206 out:
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;
1214
1215 return retval;
1216 }
1217
1218 static int
1219 isis_run_spf_cb (struct thread *thread)
1220 {
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;
1225
1226 XFREE(MTYPE_ISIS_SPF_RUN, run);
1227 area->spf_timer[level - 1] = NULL;
1228
1229 if (!(area->is_type & level))
1230 {
1231 if (isis->debugs & DEBUG_SPF_EVENTS)
1232 zlog_warn ("ISIS-SPF (%s) area does not share level",
1233 area->area_tag);
1234 return ISIS_WARNING;
1235 }
1236
1237 if (isis->debugs & DEBUG_SPF_EVENTS)
1238 zlog_debug ("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
1239 area->area_tag, level);
1240
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);
1245
1246 return retval;
1247 }
1248
1249 static struct isis_spf_run*
1250 isis_run_spf_arg(struct isis_area *area, int level)
1251 {
1252 struct isis_spf_run *run = XMALLOC(MTYPE_ISIS_SPF_RUN, sizeof(*run));
1253
1254 run->area = area;
1255 run->level = level;
1256
1257 return run;
1258 }
1259
1260 int
1261 isis_spf_schedule (struct isis_area *area, int level)
1262 {
1263 struct isis_spftree *spftree = area->spftree[level - 1];
1264 time_t now = time (NULL);
1265 int diff = now - spftree->last_run_timestamp;
1266
1267 assert (diff >= 0);
1268 assert (area->is_type & level);
1269
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);
1273
1274 if (area->spf_delay_ietf[level - 1])
1275 {
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])
1280 return ISIS_OK;
1281
1282 thread_add_timer_msec (master, isis_run_spf_cb,
1283 isis_run_spf_arg(area, level),
1284 delay, &area->spf_timer[level-1]);
1285 return ISIS_OK;
1286 }
1287
1288 if (area->spf_timer[level -1])
1289 return ISIS_OK;
1290
1291 /* wait configured min_spf_interval before doing the SPF */
1292 if (diff >= area->min_spf_interval[level-1])
1293 {
1294 int retval = ISIS_OK;
1295
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);
1300
1301 return retval;
1302 }
1303
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]);
1307
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);
1311
1312 return ISIS_OK;
1313 }
1314
1315 static void
1316 isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
1317 {
1318 struct listnode *node;
1319 struct listnode *anode;
1320 struct isis_vertex *vertex;
1321 struct isis_adjacency *adj;
1322 char buff[PREFIX2STR_BUFFER];
1323
1324 vty_out (vty, "Vertex Type Metric "
1325 "Next-Hop Interface Parent%s", VTY_NEWLINE);
1326
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),
1330 "", "");
1331 vty_out (vty, "%-30s", "");
1332 } else {
1333 int rows = 0;
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)) {
1337 if (adj) {
1338 if (rows) {
1339 vty_out (vty, "%s", VTY_NEWLINE);
1340 vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
1341 }
1342 vty_out (vty, "%-20s %-9s ",
1343 print_sys_hostname (adj->sysid),
1344 adj->circuit->interface->name);
1345 ++rows;
1346 }
1347 }
1348 if (rows == 0)
1349 vty_out (vty, "%-30s ", "");
1350 }
1351
1352 /* Print list of parents for the ECMP DAG */
1353 if (listcount (vertex->parents) > 0) {
1354 struct listnode *pnode;
1355 struct isis_vertex *pvertex;
1356 int rows = 0;
1357 for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
1358 if (rows) {
1359 vty_out (vty, "%s", VTY_NEWLINE);
1360 vty_out (vty, "%-72s", "");
1361 }
1362 vty_out (vty, "%s(%d)",
1363 vid2string (pvertex, buff, sizeof (buff)), pvertex->type);
1364 ++rows;
1365 }
1366 } else {
1367 vty_out (vty, " NULL ");
1368 }
1369
1370 vty_out (vty, "%s", VTY_NEWLINE);
1371 }
1372 }
1373
1374 DEFUN (show_isis_topology,
1375 show_isis_topology_cmd,
1376 "show isis topology [<level-1|level-2>]",
1377 SHOW_STR
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")
1382 {
1383 int levels;
1384 struct listnode *node;
1385 struct isis_area *area;
1386
1387 if (argc < 4)
1388 levels = ISIS_LEVEL1|ISIS_LEVEL2;
1389 else if (!strcmp(argv[3]->arg, "level-1"))
1390 levels = ISIS_LEVEL1;
1391 else
1392 levels = ISIS_LEVEL2;
1393
1394 if (!isis->area_list || isis->area_list->count == 0)
1395 return CMD_SUCCESS;
1396
1397 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
1398 {
1399 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1400 VTY_NEWLINE);
1401
1402 for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
1403 {
1404 if ((level & levels) == 0)
1405 continue;
1406
1407 if (area->ip_circuits > 0 && area->spftree[level-1]
1408 && area->spftree[level-1]->paths->count > 0)
1409 {
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);
1414 }
1415 if (area->ipv6_circuits > 0 && area->spftree6[level-1]
1416 && area->spftree6[level-1]->paths->count > 0)
1417 {
1418 vty_out (vty,
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);
1423 }
1424 }
1425
1426 vty_out (vty, "%s", VTY_NEWLINE);
1427 }
1428
1429 return CMD_SUCCESS;
1430 }
1431
1432 void
1433 isis_spf_cmds_init ()
1434 {
1435 install_element (VIEW_NODE, &show_isis_topology_cmd);
1436 }