blob: bd79659cb5759eddb81ad0a5b40b51f18da4278f [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
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
24#include <stdlib.h>
25#include <stdio.h>
26#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000027
28#include "thread.h"
29#include "linklist.h"
30#include "vty.h"
31#include "log.h"
32#include "command.h"
33#include "memory.h"
34#include "prefix.h"
35#include "hash.h"
36#include "if.h"
37#include "table.h"
38
39#include "isis_constants.h"
40#include "isis_common.h"
41#include "dict.h"
42#include "isisd.h"
43#include "isis_misc.h"
44#include "isis_adjacency.h"
45#include "isis_circuit.h"
46#include "isis_tlv.h"
47#include "isis_pdu.h"
48#include "isis_lsp.h"
49#include "isis_dynhn.h"
50#include "isis_spf.h"
51#include "isis_route.h"
52#include "isis_csm.h"
53
54extern struct isis *isis;
55extern struct thread_master *master;
56extern struct host host;
57
58int isis_run_spf_l1 (struct thread *thread);
59int isis_run_spf_l2 (struct thread *thread);
60
61/* performace issue ???? */
62void
hassof390d2c2004-09-10 20:48:21 +000063union_adjlist (struct list *target, struct list *source)
jardineb5d44e2003-12-23 08:09:43 +000064{
65 struct isis_adjacency *adj, *adj2;
66 struct listnode *node, *node2;
hassof390d2c2004-09-10 20:48:21 +000067
jardineb5d44e2003-12-23 08:09:43 +000068 zlog_info ("Union adjlist!");
hassof390d2c2004-09-10 20:48:21 +000069 for (node = listhead (source); node; nextnode (node))
70 {
71 adj = getdata (node);
72
73 /* lookup adjacency in the source list */
74 for (node2 = listhead (target); node2; nextnode (node2))
75 {
76 adj2 = getdata (node2);
77 if (adj == adj2)
78 break;
79 }
80
81 if (!node2)
82 listnode_add (target, adj);
jardineb5d44e2003-12-23 08:09:43 +000083 }
jardineb5d44e2003-12-23 08:09:43 +000084}
85
jardineb5d44e2003-12-23 08:09:43 +000086/* 7.2.7 */
hassof390d2c2004-09-10 20:48:21 +000087void
jardineb5d44e2003-12-23 08:09:43 +000088remove_excess_adjs (struct list *adjs)
89{
90 struct listnode *node, *excess = NULL;
91 struct isis_adjacency *adj, *candidate = NULL;
92 int comp;
93
hassof390d2c2004-09-10 20:48:21 +000094 for (node = listhead (adjs); node; nextnode (node))
95 {
96 if (excess == NULL)
97 excess = node;
98 candidate = getdata (excess);
99 adj = getdata (node);
100 if (candidate->sys_type < adj->sys_type)
101 {
102 excess = node;
103 candidate = adj;
104 continue;
105 }
106 if (candidate->sys_type > adj->sys_type)
107 continue;
108
109 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
110 if (comp > 0)
111 {
112 excess = node;
113 candidate = adj;
114 continue;
115 }
116 if (comp < 0)
117 continue;
118
119 if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
120 {
121 excess = node;
122 candidate = adj;
123 continue;
124 }
125
126 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
127 continue;
128
129 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
130 if (comp > 0)
131 {
132 excess = node;
133 candidate = adj;
134 continue;
135 }
jardineb5d44e2003-12-23 08:09:43 +0000136 }
137
jardineb5d44e2003-12-23 08:09:43 +0000138 list_delete_node (adjs, excess);
139
140 return;
141}
142
143const char *
144vtype2string (enum vertextype vtype)
145{
hassof390d2c2004-09-10 20:48:21 +0000146 switch (vtype)
147 {
148 case VTYPE_PSEUDO_IS:
149 return "pseudo_IS";
150 break;
151 case VTYPE_NONPSEUDO_IS:
152 return "IS";
153 break;
154 case VTYPE_ES:
155 return "ES";
156 break;
157 case VTYPE_IPREACH_INTERNAL:
158 return "IP internal";
159 break;
160 case VTYPE_IPREACH_EXTERNAL:
161 return "IP external";
162 break;
jardineb5d44e2003-12-23 08:09:43 +0000163#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000164 case VTYPE_IP6REACH_INTERNAL:
165 return "IP6 internal";
166 break;
167 case VTYPE_IP6REACH_EXTERNAL:
168 return "IP6 external";
169 break;
170#endif /* HAVE_IPV6 */
171 default:
172 return "UNKNOWN";
173 }
174 return NULL; /* Not reached */
jardineb5d44e2003-12-23 08:09:43 +0000175}
176
177char *
hassof390d2c2004-09-10 20:48:21 +0000178vid2string (struct isis_vertex *vertex, u_char * buff)
jardineb5d44e2003-12-23 08:09:43 +0000179{
hassof390d2c2004-09-10 20:48:21 +0000180 switch (vertex->type)
181 {
182 case VTYPE_PSEUDO_IS:
183 return rawlspid_print (vertex->N.id);
184 break;
185 case VTYPE_NONPSEUDO_IS:
186 case VTYPE_ES:
187 return sysid_print (vertex->N.id);
188 break;
189 case VTYPE_IPREACH_INTERNAL:
190 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000191#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000192 case VTYPE_IP6REACH_INTERNAL:
193 case VTYPE_IP6REACH_EXTERNAL:
194#endif /* HAVE_IPV6 */
195 prefix2str ((struct prefix *) &vertex->N.prefix, buff, BUFSIZ);
196 break;
197 default:
198 return "UNKNOWN";
199 }
200
jardineb5d44e2003-12-23 08:09:43 +0000201 return buff;
202}
203
204struct isis_spftree *
205isis_spftree_new ()
206{
207 struct isis_spftree *tree;
208
209 tree = XMALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
hassof390d2c2004-09-10 20:48:21 +0000210 if (tree == NULL)
211 {
212 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
213 return NULL;
214 }
jardineb5d44e2003-12-23 08:09:43 +0000215 memset (tree, 0, sizeof (struct isis_spftree));
216
217 tree->tents = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000218 tree->paths = list_new ();
jardineb5d44e2003-12-23 08:09:43 +0000219 return tree;
220}
221
222void
223isis_vertex_del (struct isis_vertex *vertex)
224{
jardineb5d44e2003-12-23 08:09:43 +0000225 list_delete (vertex->Adj_N);
226
227 XFREE (MTYPE_ISIS_VERTEX, vertex);
hassof390d2c2004-09-10 20:48:21 +0000228
jardineb5d44e2003-12-23 08:09:43 +0000229 return;
230}
231
232void
233isis_spftree_del (struct isis_spftree *spftree)
234{
hassof390d2c2004-09-10 20:48:21 +0000235 spftree->tents->del = (void *) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000236 list_delete (spftree->tents);
hassof390d2c2004-09-10 20:48:21 +0000237
238 spftree->paths->del = (void *) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000239 list_delete (spftree->paths);
240
241 XFREE (MTYPE_ISIS_SPFTREE, spftree);
242
243 return;
244}
245
hassof390d2c2004-09-10 20:48:21 +0000246void
jardineb5d44e2003-12-23 08:09:43 +0000247spftree_area_init (struct isis_area *area)
248{
hassof390d2c2004-09-10 20:48:21 +0000249 if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL)
250 {
251 area->spftree[0] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000252#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000253 area->spftree6[0] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000254#endif
255
hassof390d2c2004-09-10 20:48:21 +0000256 /* thread_add_timer (master, isis_run_spf_l1, area,
257 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
258 }
259
260 if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL)
261 {
262 area->spftree[1] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000263#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000264 area->spftree6[1] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000265#endif
hassof390d2c2004-09-10 20:48:21 +0000266 /* thread_add_timer (master, isis_run_spf_l2, area,
267 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
268 }
jardineb5d44e2003-12-23 08:09:43 +0000269
270 return;
271}
272
273struct isis_vertex *
274isis_vertex_new (void *id, enum vertextype vtype)
275{
276 struct isis_vertex *vertex;
277
278 vertex = XMALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
hassof390d2c2004-09-10 20:48:21 +0000279 if (vertex == NULL)
280 {
281 zlog_err ("isis_vertex_new Out of memory!");
282 return NULL;
283 }
284
jardineb5d44e2003-12-23 08:09:43 +0000285 memset (vertex, 0, sizeof (struct isis_vertex));
286 vertex->type = vtype;
hassof390d2c2004-09-10 20:48:21 +0000287 switch (vtype)
288 {
289 case VTYPE_ES:
290 case VTYPE_NONPSEUDO_IS:
291 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
292 break;
293 case VTYPE_PSEUDO_IS:
294 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
295 break;
296 case VTYPE_IPREACH_INTERNAL:
297 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000298#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000299 case VTYPE_IP6REACH_INTERNAL:
300 case VTYPE_IP6REACH_EXTERNAL:
301#endif /* HAVE_IPV6 */
302 memcpy (&vertex->N.prefix, (struct prefix *) id,
303 sizeof (struct prefix));
304 break;
305 default:
306 zlog_err ("WTF!");
307 }
jardineb5d44e2003-12-23 08:09:43 +0000308
309 vertex->Adj_N = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000310
jardineb5d44e2003-12-23 08:09:43 +0000311 return vertex;
312}
313
314/*
315 * Add this IS to the root of SPT
316 */
317void
318isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
hassof390d2c2004-09-10 20:48:21 +0000319 int level)
jardineb5d44e2003-12-23 08:09:43 +0000320{
321 struct isis_vertex *vertex;
322 struct isis_lsp *lsp;
323 u_char lspid[ISIS_SYS_ID_LEN + 2];
324#ifdef EXTREME_DEBUG
325 u_char buff[BUFSIZ];
326#endif /* EXTREME_DEBUG */
327 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +0000328 LSP_PSEUDO_ID (lspid) = 0;
329 LSP_FRAGMENT (lspid) = 0;
330
jardineb5d44e2003-12-23 08:09:43 +0000331 lsp = lsp_search (lspid, area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +0000332
jardineb5d44e2003-12-23 08:09:43 +0000333 if (lsp == NULL)
334 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
hassof390d2c2004-09-10 20:48:21 +0000335
jardineb5d44e2003-12-23 08:09:43 +0000336 vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
337 vertex->lsp = lsp;
338
339 listnode_add (spftree->paths, vertex);
340
341#ifdef EXTREME_DEBUG
342 zlog_info ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
hassof390d2c2004-09-10 20:48:21 +0000343 vtype2string (vertex->type), vid2string (vertex, buff),
344 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000345#endif /* EXTREME_DEBUG */
346
347 return;
348}
349
350struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000351isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
jardineb5d44e2003-12-23 08:09:43 +0000352{
353 struct listnode *node;
354 struct isis_vertex *vertex;
355 struct prefix *p1, *p2;
356
hassof390d2c2004-09-10 20:48:21 +0000357 for (node = listhead (list); node; nextnode (node))
358 {
359 vertex = getdata (node);
360 if (vertex->type != vtype)
361 continue;
362 switch (vtype)
363 {
364 case VTYPE_ES:
365 case VTYPE_NONPSEUDO_IS:
366 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
367 return vertex;
368 break;
369 case VTYPE_PSEUDO_IS:
370 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
371 return vertex;
372 break;
373 case VTYPE_IPREACH_INTERNAL:
374 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000375#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000376 case VTYPE_IP6REACH_INTERNAL:
377 case VTYPE_IP6REACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000378#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000379 p1 = (struct prefix *) id;
380 p2 = (struct prefix *) &vertex->N.id;
381 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
382 memcmp (&p1->u.prefix, &p2->u.prefix,
383 PSIZE (p1->prefixlen)) == 0)
384 return vertex;
385 break;
386 }
jardineb5d44e2003-12-23 08:09:43 +0000387 }
jardineb5d44e2003-12-23 08:09:43 +0000388
389 return NULL;
390}
391
jardineb5d44e2003-12-23 08:09:43 +0000392/*
393 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
394 */
395struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000396isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
397 void *id, struct isis_adjacency *adj, u_int16_t cost,
398 int depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000399{
400 struct isis_vertex *vertex, *v;
401 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000402#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000403 u_char buff[BUFSIZ];
404#endif
405
406 vertex = isis_vertex_new (id, vtype);
407 vertex->d_N = cost;
408 vertex->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000409
jardineb5d44e2003-12-23 08:09:43 +0000410 if (adj)
411 listnode_add (vertex->Adj_N, adj);
hassof390d2c2004-09-10 20:48:21 +0000412#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000413 zlog_info ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
hassof390d2c2004-09-10 20:48:21 +0000414 vtype2string (vertex->type), vid2string (vertex, buff),
415 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000416#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000417 listnode_add (spftree->tents, vertex);
418 if (list_isempty (spftree->tents))
419 {
420 listnode_add (spftree->tents, vertex);
421 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000422 }
hassof390d2c2004-09-10 20:48:21 +0000423 for (node = listhead (spftree->tents); node; nextnode (node))
424 {
425 v = getdata (node);
426 if (v->d_N > vertex->d_N)
427 {
428 list_add_node_prev (spftree->tents, node, vertex);
429 break;
430 }
431 else if (v->d_N == vertex->d_N)
432 {
433 /* Tie break, add according to type */
434 while (v && v->d_N == vertex->d_N && v->type > vertex->type)
435 {
436 if (v->type > vertex->type)
437 {
438 break;
439 }
440 nextnode (node);
441 (node) ? (v = getdata (node)) : (v = NULL);
442 }
443 list_add_node_prev (spftree->tents, node, vertex);
444 break;
445 }
446 else if (node->next == NULL)
447 {
448 list_add_node_next (spftree->tents, node, vertex);
449 break;
450 }
451 }
jardineb5d44e2003-12-23 08:09:43 +0000452 return vertex;
453}
454
455struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000456isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
457 void *id, struct isis_adjacency *adj, u_int16_t cost,
458 int family)
jardineb5d44e2003-12-23 08:09:43 +0000459{
460 struct isis_vertex *vertex;
jardineb5d44e2003-12-23 08:09:43 +0000461
hassof390d2c2004-09-10 20:48:21 +0000462 vertex = isis_find_vertex (spftree->tents, id, vtype);
463
464 if (vertex)
465 {
466 /* C.2.5 c) */
467 if (vertex->d_N == cost)
468 {
469 if (adj)
470 listnode_add (vertex->Adj_N, adj);
471 /* d) */
472 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
473 remove_excess_adjs (vertex->Adj_N);
474 }
475 /* f) */
476 else if (vertex->d_N > cost)
477 {
478 listnode_delete (spftree->tents, vertex);
479 goto add2tent;
480 }
481 /* e) do nothing */
482 return vertex;
483 }
484
485add2tent:
jardineb5d44e2003-12-23 08:09:43 +0000486 return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
487}
488
489void
hassof390d2c2004-09-10 20:48:21 +0000490process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
491 u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
492 int family)
jardineb5d44e2003-12-23 08:09:43 +0000493{
494 struct isis_vertex *vertex;
495#ifdef EXTREME_DEBUG
496 u_char buff[255];
497#endif
498
499 /* C.2.6 b) */
500 if (dist > MAX_PATH_METRIC)
501 return;
502 /* c) */
503 vertex = isis_find_vertex (spftree->paths, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000504 if (vertex)
505 {
jardineb5d44e2003-12-23 08:09:43 +0000506#ifdef EXTREME_DEBUG
hassof390d2c2004-09-10 20:48:21 +0000507 zlog_info ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
508 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000509#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000510 assert (dist >= vertex->d_N);
511 return;
512 }
jardineb5d44e2003-12-23 08:09:43 +0000513
514 vertex = isis_find_vertex (spftree->tents, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000515 /* d) */
516 if (vertex)
517 {
518 /* 1) */
jardineb5d44e2003-12-23 08:09:43 +0000519#ifdef EXTREME_DEBUG
hassof390d2c2004-09-10 20:48:21 +0000520 zlog_info ("ISIS-Spf: process_N %s %s dist %d",
521 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000522#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000523 if (vertex->d_N == dist)
524 {
525 if (adj)
526 listnode_add (vertex->Adj_N, adj);
527 /* 2) */
528 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
529 remove_excess_adjs (vertex->Adj_N);
530 /* 3) */
531 return;
532 }
533 else if (vertex->d_N < dist)
534 {
535 return;
536 /* 4) */
537 }
538 else
539 {
540 listnode_delete (spftree->tents, vertex);
541 }
jardineb5d44e2003-12-23 08:09:43 +0000542 }
hassof390d2c2004-09-10 20:48:21 +0000543
jardineb5d44e2003-12-23 08:09:43 +0000544 isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
545 return;
546}
547
548/*
549 * C.2.6 Step 1
550 */
551int
hassof390d2c2004-09-10 20:48:21 +0000552isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
553 uint16_t cost, uint16_t depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000554{
555 struct listnode *node, *fragnode = NULL;
556 u_int16_t dist;
557 struct is_neigh *is_neigh;
558 struct ipv4_reachability *ipreach;
559 enum vertextype vtype;
560 struct prefix prefix;
561#ifdef HAVE_IPV6
562 struct ipv6_reachability *ip6reach;
563#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000564
jardineb5d44e2003-12-23 08:09:43 +0000565
566 if (!lsp->adj)
567 return ISIS_WARNING;
hassof390d2c2004-09-10 20:48:21 +0000568 if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
jardineb5d44e2003-12-23 08:09:43 +0000569 return ISIS_OK;
570
hassof390d2c2004-09-10 20:48:21 +0000571lspfragloop:
572 if (lsp->lsp_header->seq_num == 0)
573 {
574 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
575 " - do not process");
576 return ISIS_WARNING;
577 }
jardineb5d44e2003-12-23 08:09:43 +0000578
hassof390d2c2004-09-10 20:48:21 +0000579 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
580 {
581 if (lsp->tlv_data.is_neighs)
582 {
583 for (node = listhead (lsp->tlv_data.is_neighs); node;
584 nextnode (node))
585 {
586 is_neigh = getdata (node);
587 /* C.2.6 a) */
588 /* Two way connectivity */
589 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
590 continue;
591 dist = cost + is_neigh->metrics.metric_default;
592 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
593 : VTYPE_NONPSEUDO_IS;
594 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
595 depth + 1, lsp->adj, family);
596 }
597 }
598 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
599 {
600 prefix.family = AF_INET;
601 for (node = listhead (lsp->tlv_data.ipv4_int_reachs); node;
602 nextnode (node))
603 {
604 ipreach = getdata (node);
605 dist = cost + ipreach->metrics.metric_default;
606 vtype = VTYPE_IPREACH_INTERNAL;
607 prefix.u.prefix4 = ipreach->prefix;
608 prefix.prefixlen = ip_masklen (ipreach->mask);
609 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
610 lsp->adj, family);
611 }
612 }
613
614 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
615 {
616 prefix.family = AF_INET;
617 for (node = listhead (lsp->tlv_data.ipv4_ext_reachs); node;
618 nextnode (node))
619 {
620 ipreach = getdata (node);
621 dist = cost + ipreach->metrics.metric_default;
622 vtype = VTYPE_IPREACH_EXTERNAL;
623 prefix.u.prefix4 = ipreach->prefix;
624 prefix.prefixlen = ip_masklen (ipreach->mask);
625 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
626 lsp->adj, family);
627 }
628 }
jardineb5d44e2003-12-23 08:09:43 +0000629#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000630 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
631 {
632 prefix.family = AF_INET6;
633 for (node = listhead (lsp->tlv_data.ipv6_reachs); node;
634 nextnode (node))
635 {
636 ip6reach = getdata (node);
637 dist = cost + ip6reach->metric;
638 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
639 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
640 prefix.prefixlen = ip6reach->prefix_len;
641 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
642 PSIZE (ip6reach->prefix_len));
643 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
644 lsp->adj, family);
645 }
646 }
jardineb5d44e2003-12-23 08:09:43 +0000647#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000648 }
649
jardineb5d44e2003-12-23 08:09:43 +0000650 if (fragnode == NULL)
651 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000652 else
jardineb5d44e2003-12-23 08:09:43 +0000653 fragnode = nextnode (fragnode);
654
hassof390d2c2004-09-10 20:48:21 +0000655 if (fragnode)
656 {
657 lsp = getdata (fragnode);
658 goto lspfragloop;
659 }
660
jardineb5d44e2003-12-23 08:09:43 +0000661 return ISIS_OK;
662}
663
664int
hassof390d2c2004-09-10 20:48:21 +0000665isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
666 struct isis_lsp *lsp, uint16_t cost,
667 uint16_t depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000668{
669 struct listnode *node, *fragnode = NULL;
670 struct is_neigh *is_neigh;
671 enum vertextype vtype;
hassof390d2c2004-09-10 20:48:21 +0000672
673pseudofragloop:
674
675 if (lsp->lsp_header->seq_num == 0)
676 {
677 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
678 " - do not process");
679 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000680 }
hassof390d2c2004-09-10 20:48:21 +0000681
682 for (node = (lsp->tlv_data.is_neighs ?
683 listhead (lsp->tlv_data.is_neighs) : NULL);
684 node; nextnode (node))
685 {
686 is_neigh = getdata (node);
687 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
688 : VTYPE_NONPSEUDO_IS;
689 /* Two way connectivity */
690 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
691 continue;
692 if (isis_find_vertex
693 (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL
694 && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id,
695 vtype) == NULL)
696 {
697 /* C.2.5 i) */
698 isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
699 cost, depth, family);
700 }
701 }
702
jardineb5d44e2003-12-23 08:09:43 +0000703 if (fragnode == NULL)
704 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000705 else
jardineb5d44e2003-12-23 08:09:43 +0000706 fragnode = nextnode (fragnode);
707
hassof390d2c2004-09-10 20:48:21 +0000708 if (fragnode)
709 {
710 lsp = getdata (fragnode);
711 goto pseudofragloop;
712 }
jardineb5d44e2003-12-23 08:09:43 +0000713
jardineb5d44e2003-12-23 08:09:43 +0000714 return ISIS_OK;
715}
hassof390d2c2004-09-10 20:48:21 +0000716
jardineb5d44e2003-12-23 08:09:43 +0000717int
hassof390d2c2004-09-10 20:48:21 +0000718isis_spf_preload_tent (struct isis_spftree *spftree,
719 struct isis_area *area, int level, int family)
jardineb5d44e2003-12-23 08:09:43 +0000720{
721 struct isis_vertex *vertex;
722 struct isis_circuit *circuit;
723 struct listnode *cnode, *anode, *ipnode;
724 struct isis_adjacency *adj;
725 struct isis_lsp *lsp;
726 struct list *adj_list;
727 struct list *adjdb;
728 struct prefix_ipv4 *ipv4;
729 struct prefix prefix;
730 int retval = ISIS_OK;
731 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
732#ifdef HAVE_IPV6
733 struct prefix_ipv6 *ipv6;
734#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000735
736 for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode))
737 {
738 circuit = getdata (cnode);
739 if (circuit->state != C_STATE_UP)
jardineb5d44e2003-12-23 08:09:43 +0000740 continue;
hassof390d2c2004-09-10 20:48:21 +0000741 if (!(circuit->circuit_is_type & level))
742 continue;
743 if (family == AF_INET && !circuit->ip_router)
744 continue;
745#ifdef HAVE_IPV6
746 if (family == AF_INET6 && !circuit->ipv6_router)
747 continue;
748#endif /* HAVE_IPV6 */
749 /*
750 * Add IP(v6) addresses of this circuit
jardineb5d44e2003-12-23 08:09:43 +0000751 */
hassof390d2c2004-09-10 20:48:21 +0000752 if (family == AF_INET)
753 {
754 prefix.family = AF_INET;
755 for (ipnode =
756 (circuit->ip_addrs ? listhead (circuit->ip_addrs) : NULL);
757 ipnode; nextnode (ipnode))
758 {
759 ipv4 = getdata (ipnode);
760 prefix.u.prefix4 = ipv4->prefix;
761 prefix.prefixlen = ipv4->prefixlen;
762 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
763 NULL, 0, family);
764 }
765 }
766#ifdef HAVE_IPV6
767 if (family == AF_INET6)
768 {
769 prefix.family = AF_INET6;
770 for (ipnode = (circuit->ipv6_non_link ? listhead
771 (circuit->ipv6_non_link) : NULL); ipnode;
772 nextnode (ipnode))
773 {
774 ipv6 = getdata (ipnode);
775 prefix.prefixlen = ipv6->prefixlen;
776 prefix.u.prefix6 = ipv6->prefix;
777 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
778 &prefix, NULL, 0, family);
779 }
780 }
781#endif /* HAVE_IPV6 */
782 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
783 {
784 /*
785 * Add the adjacencies
786 */
787 adj_list = list_new ();
788 adjdb = circuit->u.bc.adjdb[level - 1];
789 isis_adj_build_up_list (adjdb, adj_list);
790 if (listcount (adj_list) == 0)
791 {
792 list_delete (adj_list);
793 zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s",
794 level, circuit->interface->name);
795 continue;
796 }
797 anode = listhead (adj_list);
798 while (anode)
799 {
800 adj = getdata (anode);
801 if (!speaks (&adj->nlpids, family))
802 {
803 anode = nextnode (anode);
804 continue;
805 }
806 switch (adj->sys_type)
807 {
808 case ISIS_SYSTYPE_ES:
809 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
810 circuit->metrics[level -
811 1].metric_default,
812 family);
813 break;
814 case ISIS_SYSTYPE_IS:
815 case ISIS_SYSTYPE_L1_IS:
816 case ISIS_SYSTYPE_L2_IS:
817 vertex =
818 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
819 adj->sysid, adj,
820 circuit->metrics[level -
821 1].metric_default,
822 family);
823 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
824 LSP_PSEUDO_ID (lsp_id) = 0;
825 LSP_FRAGMENT (lsp_id) = 0;
826 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
827 if (!lsp)
828 zlog_warn ("No lsp found for IS adjacency");
829 /* else {
830 isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
831 } */
832 break;
833 case ISIS_SYSTYPE_UNKNOWN:
834 default:
835 zlog_warn ("isis_spf_preload_tent unknow adj type");
836 }
837 anode = nextnode (anode);
838 }
839 list_delete (adj_list);
840 /*
841 * Add the pseudonode
842 */
843 if (level == 1)
844 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
845 else
846 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
847 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
848 adj = isis_adj_lookup (lsp_id, adjdb);
849 /* if no adj, we are the dis or error */
850 if (!adj && !circuit->u.bc.is_dr[level - 1])
851 {
852 zlog_warn ("ISIS-Spf: No adjacency found for DR");
853 }
854 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
855 {
856 zlog_warn ("ISIS-Spf: No lsp found for DR");
857 }
858 else
859 {
860 isis_spf_process_pseudo_lsp
861 (spftree, lsp, circuit->metrics[level - 1].metric_default, 0,
862 family);
863
864 }
865 }
866 else if (circuit->circ_type == CIRCUIT_T_P2P)
867 {
868 adj = circuit->u.p2p.neighbor;
869 if (!adj)
870 continue;
871 switch (adj->sys_type)
872 {
873 case ISIS_SYSTYPE_ES:
874 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
875 circuit->metrics[level - 1].metric_default,
876 family);
877 break;
878 case ISIS_SYSTYPE_IS:
879 case ISIS_SYSTYPE_L1_IS:
880 case ISIS_SYSTYPE_L2_IS:
881 if (speaks (&adj->nlpids, family))
882 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
883 adj,
884 circuit->metrics[level -
885 1].metric_default,
886 family);
887 break;
888 case ISIS_SYSTYPE_UNKNOWN:
889 default:
890 zlog_warn ("isis_spf_preload_tent unknow adj type");
891 break;
892 }
893 }
jardineb5d44e2003-12-23 08:09:43 +0000894 else
hassof390d2c2004-09-10 20:48:21 +0000895 {
896 zlog_warn ("isis_spf_preload_tent unsupported media");
897 retval = ISIS_WARNING;
898 }
899
jardineb5d44e2003-12-23 08:09:43 +0000900 }
jardineb5d44e2003-12-23 08:09:43 +0000901
902 return retval;
903}
904
905/*
906 * The parent(s) for vertex is set when added to TENT list
907 * now we just put the child pointer(s) in place
908 */
909void
910add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
hassof390d2c2004-09-10 20:48:21 +0000911 struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +0000912{
jardineb5d44e2003-12-23 08:09:43 +0000913#ifdef EXTREME_DEBUG
914 u_char buff[BUFSIZ];
915#endif /* EXTREME_DEBUG */
916 listnode_add (spftree->paths, vertex);
917
hassof390d2c2004-09-10 20:48:21 +0000918#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000919 zlog_info ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
hassof390d2c2004-09-10 20:48:21 +0000920 vtype2string (vertex->type), vid2string (vertex, buff),
921 vertex->depth, vertex->d_N);
922#endif /* EXTREME_DEBUG */
923 if (vertex->type > VTYPE_ES)
924 {
925 if (listcount (vertex->Adj_N) > 0)
926 isis_route_create ((struct prefix *) &vertex->N.prefix,
927 vertex->d_N, vertex->depth, vertex->Adj_N, area);
928 else if (isis->debugs & DEBUG_SPF_EVENTS)
929 zlog_info ("ISIS-Spf: no adjacencies do not install route");
930 }
931
jardineb5d44e2003-12-23 08:09:43 +0000932 return;
933}
934
jardineb5d44e2003-12-23 08:09:43 +0000935void
936init_spt (struct isis_spftree *spftree)
937{
hassof390d2c2004-09-10 20:48:21 +0000938 spftree->tents->del = spftree->paths->del = (void *) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000939 list_delete_all_node (spftree->tents);
940 list_delete_all_node (spftree->paths);
941 spftree->tents->del = spftree->paths->del = NULL;
hassof390d2c2004-09-10 20:48:21 +0000942
jardineb5d44e2003-12-23 08:09:43 +0000943 return;
944}
945
946int
947isis_run_spf (struct isis_area *area, int level, int family)
948{
949 int retval = ISIS_OK;
950 struct listnode *node;
951 struct isis_vertex *vertex;
hassof390d2c2004-09-10 20:48:21 +0000952 struct isis_spftree *spftree = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000953 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
954 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000955
jardineb5d44e2003-12-23 08:09:43 +0000956 if (family == AF_INET)
957 spftree = area->spftree[level - 1];
958#ifdef HAVE_IPV6
959 else if (family == AF_INET6)
960 spftree = area->spftree6[level - 1];
961#endif
hassof390d2c2004-09-10 20:48:21 +0000962
jardineb5d44e2003-12-23 08:09:43 +0000963 assert (spftree);
964
965 /*
966 * C.2.5 Step 0
967 */
968 init_spt (spftree);
969 /* a) */
970 isis_spf_add_self (spftree, area, level);
971 /* b) */
972 retval = isis_spf_preload_tent (spftree, area, level, family);
hassof390d2c2004-09-10 20:48:21 +0000973
jardineb5d44e2003-12-23 08:09:43 +0000974 /*
975 * C.2.7 Step 2
976 */
hassof390d2c2004-09-10 20:48:21 +0000977 if (listcount (spftree->tents) == 0)
978 {
979 zlog_warn ("ISIS-Spf: TENT is empty");
980 spftree->lastrun = time (NULL);
981 return retval;
jardineb5d44e2003-12-23 08:09:43 +0000982 }
hassof390d2c2004-09-10 20:48:21 +0000983
984 while (listcount (spftree->tents) > 0)
985 {
986 node = listhead (spftree->tents);
987 vertex = getdata (node);
988 /* Remove from tent list */
989 list_delete_node (spftree->tents, node);
990 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
991 continue;
992 add_to_paths (spftree, vertex, area);
993 if (vertex->type == VTYPE_PSEUDO_IS ||
994 vertex->type == VTYPE_NONPSEUDO_IS)
995 {
996 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
997 LSP_FRAGMENT (lsp_id) = 0;
998 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
999 if (lsp)
1000 {
1001 if (LSP_PSEUDO_ID (lsp_id))
1002 {
1003 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
1004 vertex->depth, family);
1005
1006 }
1007 else
1008 {
1009 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
1010 vertex->depth, family);
1011 }
1012 }
1013 else
1014 {
1015 zlog_warn ("ISIS-Spf: No LSP found for %s",
1016 rawlspid_print (lsp_id));
1017 }
1018 }
1019 }
1020
jardineb5d44e2003-12-23 08:09:43 +00001021 thread_add_event (master, isis_route_validate, area, 0);
1022 spftree->lastrun = time (NULL);
1023 spftree->pending = 0;
hassof390d2c2004-09-10 20:48:21 +00001024
1025 if (level == 1)
1026 {
1027 /* FIXME: Should do it earlier. */
1028 spftree->t_spf_periodic = NULL;
1029 THREAD_TIMER_ON (master, spftree->t_spf_periodic, isis_run_spf_l1, area,
1030 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1031 }
1032 else
1033 {
1034 /* FIXME: Should do it earlier. */
1035 spftree->t_spf_periodic = NULL;
1036 THREAD_TIMER_ON (master, spftree->t_spf_periodic, isis_run_spf_l2, area,
1037 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1038 }
jardineb5d44e2003-12-23 08:09:43 +00001039
1040 return retval;
1041}
1042
1043int
1044isis_run_spf_l1 (struct thread *thread)
1045{
1046 struct isis_area *area;
1047 int retval = ISIS_OK;
1048
hassof390d2c2004-09-10 20:48:21 +00001049 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001050 assert (area);
1051
hassof390d2c2004-09-10 20:48:21 +00001052 if (!(area->is_type & IS_LEVEL_1))
1053 {
1054 if (isis->debugs & DEBUG_SPF_EVENTS)
1055 {
1056 zlog_warn ("ISIS-SPF (%s) area does not share level",
1057 area->area_tag);
1058 }
1059 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001060 }
jardineb5d44e2003-12-23 08:09:43 +00001061
hassof390d2c2004-09-10 20:48:21 +00001062 if (isis->debugs & DEBUG_SPF_EVENTS)
1063 {
1064 zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
1065 }
1066
jardineb5d44e2003-12-23 08:09:43 +00001067 if (area->ip_circuits)
1068 retval = isis_run_spf (area, 1, AF_INET);
1069#ifdef HAVE_IPV6
1070 if (area->ipv6_circuits)
1071 retval = isis_run_spf (area, 1, AF_INET6);
1072#endif
1073 return retval;
1074}
1075
1076int
1077isis_run_spf_l2 (struct thread *thread)
1078{
1079 struct isis_area *area;
1080 int retval = ISIS_OK;
1081
hassof390d2c2004-09-10 20:48:21 +00001082 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001083 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001084
1085 if (!(area->is_type & IS_LEVEL_2))
1086 {
1087 if (isis->debugs & DEBUG_SPF_EVENTS)
1088 {
1089 zlog_warn ("ISIS-SPF (%s) area does not share level",
1090 area->area_tag);
1091 }
1092 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001093 }
hassof390d2c2004-09-10 20:48:21 +00001094
1095 if (isis->debugs & DEBUG_SPF_EVENTS)
1096 {
1097 zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
1098 }
jardineb5d44e2003-12-23 08:09:43 +00001099
1100 if (area->ip_circuits)
1101 retval = isis_run_spf (area, 2, AF_INET);
1102#ifdef HAVE_IPV6
1103 if (area->ipv6_circuits)
1104 retval = isis_run_spf (area, 2, AF_INET6);
1105#endif
1106
1107 return retval;
1108}
1109
hassof390d2c2004-09-10 20:48:21 +00001110int
jardineb5d44e2003-12-23 08:09:43 +00001111isis_spf_schedule (struct isis_area *area, int level)
1112{
1113 int retval = ISIS_OK;
1114 struct isis_spftree *spftree = area->spftree[level - 1];
1115 time_t diff, now = time (NULL);
1116
1117 if (spftree->pending)
1118 return retval;
1119
hassof390d2c2004-09-10 20:48:21 +00001120 diff = now - spftree->lastrun;
jardineb5d44e2003-12-23 08:09:43 +00001121
1122 /* FIXME: let's wait a minute before doing the SPF */
hassof390d2c2004-09-10 20:48:21 +00001123 if (now - isis->uptime < 60 || isis->uptime == 0)
1124 {
1125 if (level == 1)
1126 thread_add_timer (master, isis_run_spf_l1, area, 60);
1127 else
1128 thread_add_timer (master, isis_run_spf_l2, area, 60);
jardineb5d44e2003-12-23 08:09:43 +00001129
hassof390d2c2004-09-10 20:48:21 +00001130 spftree->pending = 1;
1131 return retval;
1132 }
hasso00995cf2004-05-19 13:43:50 +00001133 /* FIXME: This stuff is just mess. All spf thread add/cancel
1134 logic should be reviewed. */
hassof390d2c2004-09-10 20:48:21 +00001135 THREAD_TIMER_OFF (spftree->t_spf_periodic);
jardineb5d44e2003-12-23 08:09:43 +00001136
hassof390d2c2004-09-10 20:48:21 +00001137 if (diff < MINIMUM_SPF_INTERVAL)
1138 {
1139 if (level == 1)
1140 thread_add_timer (master, isis_run_spf_l1, area,
1141 MINIMUM_SPF_INTERVAL - diff);
1142 else
1143 thread_add_timer (master, isis_run_spf_l2, area,
1144 MINIMUM_SPF_INTERVAL - diff);
jardineb5d44e2003-12-23 08:09:43 +00001145
hassof390d2c2004-09-10 20:48:21 +00001146 spftree->pending = 1;
1147 }
1148 else
1149 {
1150 spftree->pending = 0;
1151 retval = isis_run_spf (area, level, AF_INET);
1152 }
jardineb5d44e2003-12-23 08:09:43 +00001153
1154 return retval;
1155}
1156
1157#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001158int
jardineb5d44e2003-12-23 08:09:43 +00001159isis_spf_schedule6 (struct isis_area *area, int level)
1160{
1161 int retval = ISIS_OK;
1162 struct isis_spftree *spftree = area->spftree6[level - 1];
1163 time_t diff, now = time (NULL);
1164
1165 if (spftree->pending)
1166 return retval;
1167
hassof390d2c2004-09-10 20:48:21 +00001168 diff = now - spftree->lastrun;
1169
1170 THREAD_TIMER_OFF (spftree->t_spf_periodic);
1171
jardineb5d44e2003-12-23 08:09:43 +00001172 /* FIXME: let's wait a minute before doing the SPF */
hassof390d2c2004-09-10 20:48:21 +00001173 if (now - isis->uptime < 60 || isis->uptime == 0)
1174 {
1175 if (level == 1)
1176 thread_add_timer (master, isis_run_spf_l1, area, 60);
1177 else
1178 thread_add_timer (master, isis_run_spf_l2, area, 60);
jardineb5d44e2003-12-23 08:09:43 +00001179
hassof390d2c2004-09-10 20:48:21 +00001180 spftree->pending = 1;
1181 return retval;
1182 }
jardineb5d44e2003-12-23 08:09:43 +00001183
1184
hassof390d2c2004-09-10 20:48:21 +00001185 if (diff < MINIMUM_SPF_INTERVAL)
1186 {
1187 if (level == 1)
1188 thread_add_timer (master, isis_run_spf_l1, area,
1189 MINIMUM_SPF_INTERVAL - diff);
1190 else
1191 thread_add_timer (master, isis_run_spf_l2, area,
1192 MINIMUM_SPF_INTERVAL - diff);
jardineb5d44e2003-12-23 08:09:43 +00001193
hassof390d2c2004-09-10 20:48:21 +00001194 spftree->pending = 1;
1195 }
1196 else
1197 {
1198 spftree->pending = 0;
1199 retval = isis_run_spf (area, level, AF_INET6);
1200 }
jardineb5d44e2003-12-23 08:09:43 +00001201
1202 return retval;
1203}
1204
1205#endif
1206
1207void
1208isis_print_paths (struct vty *vty, struct list *paths)
1209{
1210 struct listnode *node, *anode;
1211 struct isis_vertex *vertex;
1212 struct isis_dynhn *dyn, *nh_dyn = NULL;
1213 struct isis_adjacency *adj;
1214#ifdef EXTREME_DEBUG
1215 u_char buff[255];
hassof390d2c2004-09-10 20:48:21 +00001216#endif
jardineb5d44e2003-12-23 08:09:43 +00001217
1218 vty_out (vty, "System Id Metric Next-Hop"
hassof390d2c2004-09-10 20:48:21 +00001219 " Interface SNPA%s", VTY_NEWLINE);
1220 for (node = listhead (paths); node; nextnode (node))
1221 {
1222 vertex = getdata (node);
1223 if (vertex->type != VTYPE_NONPSEUDO_IS)
1224 continue;
1225 if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
1226 {
1227 vty_out (vty, "%s --%s", host.name, VTY_NEWLINE);
1228 }
1229 else
1230 {
1231 dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
1232 anode = listhead (vertex->Adj_N);
1233 adj = getdata (anode);
1234 if (adj)
1235 {
1236 nh_dyn = dynhn_find_by_id (adj->sysid);
1237 vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
1238 (dyn != NULL) ? dyn->name.name :
1239 (u_char *) rawlspid_print ((u_char *) vertex->N.id),
1240 vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
1241 (u_char *) rawlspid_print (adj->sysid),
1242 adj->circuit->interface->name,
1243 snpa_print (adj->snpa), VTY_NEWLINE);
1244 }
1245 else
1246 {
1247 vty_out (vty, "%s %u %s", dyn ? dyn->name.name :
1248 (u_char *) rawlspid_print (vertex->N.id),
1249 vertex->d_N, VTY_NEWLINE);
1250 }
1251 }
jardineb5d44e2003-12-23 08:09:43 +00001252#if 0
hassof390d2c2004-09-10 20:48:21 +00001253 vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
1254 vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001255#endif
hassof390d2c2004-09-10 20:48:21 +00001256 }
jardineb5d44e2003-12-23 08:09:43 +00001257}
1258
1259DEFUN (show_isis_topology,
1260 show_isis_topology_cmd,
1261 "show isis topology",
1262 SHOW_STR
1263 "IS-IS information\n"
1264 "IS-IS paths to Intermediate Systems\n")
1265{
1266 struct listnode *node;
1267 struct isis_area *area;
1268 int level;
hassof390d2c2004-09-10 20:48:21 +00001269
jardineb5d44e2003-12-23 08:09:43 +00001270 if (!isis->area_list || isis->area_list->count == 0)
1271 return CMD_SUCCESS;
1272
hassof390d2c2004-09-10 20:48:21 +00001273 for (node = listhead (isis->area_list); node; nextnode (node))
1274 {
1275 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001276
hassof390d2c2004-09-10 20:48:21 +00001277 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1278 VTY_NEWLINE);
1279
1280 for (level = 0; level < ISIS_LEVELS; level++)
1281 {
1282 if (area->ip_circuits > 0 && area->spftree[level]
1283 && area->spftree[level]->paths->count > 0)
1284 {
1285 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1286 level + 1, VTY_NEWLINE);
1287 isis_print_paths (vty, area->spftree[level]->paths);
1288 }
jardineb5d44e2003-12-23 08:09:43 +00001289#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001290 if (area->ipv6_circuits > 0 && area->spftree6[level]
1291 && area->spftree6[level]->paths->count > 0)
1292 {
1293 vty_out (vty,
1294 "IS-IS paths to level-%d routers that speak IPv6%s",
1295 level + 1, VTY_NEWLINE);
1296 isis_print_paths (vty, area->spftree6[level]->paths);
1297 }
jardineb5d44e2003-12-23 08:09:43 +00001298#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001299 }
jardineb5d44e2003-12-23 08:09:43 +00001300 }
jardineb5d44e2003-12-23 08:09:43 +00001301
1302 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001303}
jardineb5d44e2003-12-23 08:09:43 +00001304
1305DEFUN (show_isis_topology_l1,
1306 show_isis_topology_l1_cmd,
1307 "show isis topology level-1",
1308 SHOW_STR
1309 "IS-IS information\n"
1310 "IS-IS paths to Intermediate Systems\n"
1311 "Paths to all level-1 routers in the area\n")
1312{
1313 struct listnode *node;
1314 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001315
jardineb5d44e2003-12-23 08:09:43 +00001316 if (!isis->area_list || isis->area_list->count == 0)
1317 return CMD_SUCCESS;
1318
hassof390d2c2004-09-10 20:48:21 +00001319 for (node = listhead (isis->area_list); node; nextnode (node))
1320 {
1321 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001322
hassof390d2c2004-09-10 20:48:21 +00001323 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1324 VTY_NEWLINE);
1325
1326 if (area->ip_circuits > 0 && area->spftree[0]
1327 && area->spftree[0]->paths->count > 0)
1328 {
1329 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1330 VTY_NEWLINE);
1331 isis_print_paths (vty, area->spftree[0]->paths);
1332 }
jardineb5d44e2003-12-23 08:09:43 +00001333#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001334 if (area->ipv6_circuits > 0 && area->spftree6[0]
1335 && area->spftree6[0]->paths->count > 0)
1336 {
1337 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1338 VTY_NEWLINE);
1339 isis_print_paths (vty, area->spftree6[0]->paths);
1340 }
jardineb5d44e2003-12-23 08:09:43 +00001341#endif /* HAVE_IPV6 */
1342 }
1343
jardineb5d44e2003-12-23 08:09:43 +00001344 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001345}
jardineb5d44e2003-12-23 08:09:43 +00001346
1347DEFUN (show_isis_topology_l2,
1348 show_isis_topology_l2_cmd,
1349 "show isis topology level-2",
1350 SHOW_STR
1351 "IS-IS information\n"
1352 "IS-IS paths to Intermediate Systems\n"
1353 "Paths to all level-2 routers in the domain\n")
1354{
1355 struct listnode *node;
1356 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001357
jardineb5d44e2003-12-23 08:09:43 +00001358 if (!isis->area_list || isis->area_list->count == 0)
1359 return CMD_SUCCESS;
1360
hassof390d2c2004-09-10 20:48:21 +00001361 for (node = listhead (isis->area_list); node; nextnode (node))
1362 {
1363 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001364
hassof390d2c2004-09-10 20:48:21 +00001365 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1366 VTY_NEWLINE);
1367
1368 if (area->ip_circuits > 0 && area->spftree[1]
1369 && area->spftree[1]->paths->count > 0)
1370 {
1371 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1372 VTY_NEWLINE);
1373 isis_print_paths (vty, area->spftree[1]->paths);
1374 }
jardineb5d44e2003-12-23 08:09:43 +00001375#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001376 if (area->ipv6_circuits > 0 && area->spftree6[1]
1377 && area->spftree6[1]->paths->count > 0)
1378 {
1379 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1380 VTY_NEWLINE);
1381 isis_print_paths (vty, area->spftree6[1]->paths);
1382 }
jardineb5d44e2003-12-23 08:09:43 +00001383#endif /* HAVE_IPV6 */
1384 }
1385
jardineb5d44e2003-12-23 08:09:43 +00001386 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001387}
jardineb5d44e2003-12-23 08:09:43 +00001388
1389void
1390isis_spf_cmds_init ()
1391{
1392 install_element (VIEW_NODE, &show_isis_topology_cmd);
1393 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1394 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1395
1396 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1397 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1398 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1399}