blob: 66d4ca7e3ac44296d6e42b6068edf6759e400951 [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
hasso92365882005-01-18 13:53:33 +000061#if 0
62/* performace issue ???? HT: Old or new code? */
63static void
hassof390d2c2004-09-10 20:48:21 +000064union_adjlist (struct list *target, struct list *source)
jardineb5d44e2003-12-23 08:09:43 +000065{
66 struct isis_adjacency *adj, *adj2;
67 struct listnode *node, *node2;
hassof390d2c2004-09-10 20:48:21 +000068
hasso529d65b2004-12-24 00:14:50 +000069 zlog_debug ("Union adjlist!");
hassof390d2c2004-09-10 20:48:21 +000070 for (node = listhead (source); node; nextnode (node))
71 {
72 adj = getdata (node);
73
74 /* lookup adjacency in the source list */
75 for (node2 = listhead (target); node2; nextnode (node2))
76 {
77 adj2 = getdata (node2);
78 if (adj == adj2)
79 break;
80 }
81
82 if (!node2)
83 listnode_add (target, adj);
jardineb5d44e2003-12-23 08:09:43 +000084 }
jardineb5d44e2003-12-23 08:09:43 +000085}
hasso92365882005-01-18 13:53:33 +000086#endif
jardineb5d44e2003-12-23 08:09:43 +000087
jardineb5d44e2003-12-23 08:09:43 +000088/* 7.2.7 */
hasso92365882005-01-18 13:53:33 +000089static void
jardineb5d44e2003-12-23 08:09:43 +000090remove_excess_adjs (struct list *adjs)
91{
92 struct listnode *node, *excess = NULL;
93 struct isis_adjacency *adj, *candidate = NULL;
94 int comp;
95
hassof390d2c2004-09-10 20:48:21 +000096 for (node = listhead (adjs); node; nextnode (node))
97 {
98 if (excess == NULL)
99 excess = node;
100 candidate = getdata (excess);
101 adj = getdata (node);
102 if (candidate->sys_type < adj->sys_type)
103 {
104 excess = node;
105 candidate = adj;
106 continue;
107 }
108 if (candidate->sys_type > adj->sys_type)
109 continue;
110
111 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
112 if (comp > 0)
113 {
114 excess = node;
115 candidate = adj;
116 continue;
117 }
118 if (comp < 0)
119 continue;
120
121 if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
122 {
123 excess = node;
124 candidate = adj;
125 continue;
126 }
127
128 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
129 continue;
130
131 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
132 if (comp > 0)
133 {
134 excess = node;
135 candidate = adj;
136 continue;
137 }
jardineb5d44e2003-12-23 08:09:43 +0000138 }
139
jardineb5d44e2003-12-23 08:09:43 +0000140 list_delete_node (adjs, excess);
141
142 return;
143}
144
hasso92365882005-01-18 13:53:33 +0000145#ifdef EXTREME_DEBUG
146static const char *
jardineb5d44e2003-12-23 08:09:43 +0000147vtype2string (enum vertextype vtype)
148{
hassof390d2c2004-09-10 20:48:21 +0000149 switch (vtype)
150 {
151 case VTYPE_PSEUDO_IS:
152 return "pseudo_IS";
153 break;
154 case VTYPE_NONPSEUDO_IS:
155 return "IS";
156 break;
157 case VTYPE_ES:
158 return "ES";
159 break;
160 case VTYPE_IPREACH_INTERNAL:
161 return "IP internal";
162 break;
163 case VTYPE_IPREACH_EXTERNAL:
164 return "IP external";
165 break;
jardineb5d44e2003-12-23 08:09:43 +0000166#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000167 case VTYPE_IP6REACH_INTERNAL:
168 return "IP6 internal";
169 break;
170 case VTYPE_IP6REACH_EXTERNAL:
171 return "IP6 external";
172 break;
173#endif /* HAVE_IPV6 */
174 default:
175 return "UNKNOWN";
176 }
177 return NULL; /* Not reached */
jardineb5d44e2003-12-23 08:09:43 +0000178}
179
hasso92365882005-01-18 13:53:33 +0000180static const char *
hassof390d2c2004-09-10 20:48:21 +0000181vid2string (struct isis_vertex *vertex, u_char * buff)
jardineb5d44e2003-12-23 08:09:43 +0000182{
hassof390d2c2004-09-10 20:48:21 +0000183 switch (vertex->type)
184 {
185 case VTYPE_PSEUDO_IS:
186 return rawlspid_print (vertex->N.id);
187 break;
188 case VTYPE_NONPSEUDO_IS:
189 case VTYPE_ES:
190 return sysid_print (vertex->N.id);
191 break;
192 case VTYPE_IPREACH_INTERNAL:
193 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000194#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000195 case VTYPE_IP6REACH_INTERNAL:
196 case VTYPE_IP6REACH_EXTERNAL:
197#endif /* HAVE_IPV6 */
hassof7c43dc2004-09-26 16:24:14 +0000198 prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000199 break;
200 default:
201 return "UNKNOWN";
202 }
203
hassof7c43dc2004-09-26 16:24:14 +0000204 return (char *) buff;
jardineb5d44e2003-12-23 08:09:43 +0000205}
hasso92365882005-01-18 13:53:33 +0000206#endif /* EXTREME_DEBUG */
jardineb5d44e2003-12-23 08:09:43 +0000207
hasso92365882005-01-18 13:53:33 +0000208static struct isis_spftree *
jardineb5d44e2003-12-23 08:09:43 +0000209isis_spftree_new ()
210{
211 struct isis_spftree *tree;
212
213 tree = XMALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
hassof390d2c2004-09-10 20:48:21 +0000214 if (tree == NULL)
215 {
216 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
217 return NULL;
218 }
jardineb5d44e2003-12-23 08:09:43 +0000219 memset (tree, 0, sizeof (struct isis_spftree));
220
221 tree->tents = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000222 tree->paths = list_new ();
jardineb5d44e2003-12-23 08:09:43 +0000223 return tree;
224}
225
hasso92365882005-01-18 13:53:33 +0000226static void
jardineb5d44e2003-12-23 08:09:43 +0000227isis_vertex_del (struct isis_vertex *vertex)
228{
jardineb5d44e2003-12-23 08:09:43 +0000229 list_delete (vertex->Adj_N);
230
231 XFREE (MTYPE_ISIS_VERTEX, vertex);
hassof390d2c2004-09-10 20:48:21 +0000232
jardineb5d44e2003-12-23 08:09:43 +0000233 return;
234}
235
hasso92365882005-01-18 13:53:33 +0000236#if 0 /* HT: Not used yet. */
237static void
jardineb5d44e2003-12-23 08:09:43 +0000238isis_spftree_del (struct isis_spftree *spftree)
239{
hassof7c43dc2004-09-26 16:24:14 +0000240 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000241 list_delete (spftree->tents);
hassof390d2c2004-09-10 20:48:21 +0000242
hassof7c43dc2004-09-26 16:24:14 +0000243 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000244 list_delete (spftree->paths);
245
246 XFREE (MTYPE_ISIS_SPFTREE, spftree);
247
248 return;
249}
hasso92365882005-01-18 13:53:33 +0000250#endif
jardineb5d44e2003-12-23 08:09:43 +0000251
hassof390d2c2004-09-10 20:48:21 +0000252void
jardineb5d44e2003-12-23 08:09:43 +0000253spftree_area_init (struct isis_area *area)
254{
hassof390d2c2004-09-10 20:48:21 +0000255 if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL)
256 {
257 area->spftree[0] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000258#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000259 area->spftree6[0] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000260#endif
261
hassof390d2c2004-09-10 20:48:21 +0000262 /* thread_add_timer (master, isis_run_spf_l1, area,
263 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
264 }
265
266 if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL)
267 {
268 area->spftree[1] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000269#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000270 area->spftree6[1] = isis_spftree_new ();
jardineb5d44e2003-12-23 08:09:43 +0000271#endif
hassof390d2c2004-09-10 20:48:21 +0000272 /* thread_add_timer (master, isis_run_spf_l2, area,
273 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
274 }
jardineb5d44e2003-12-23 08:09:43 +0000275
276 return;
277}
278
hasso92365882005-01-18 13:53:33 +0000279static struct isis_vertex *
jardineb5d44e2003-12-23 08:09:43 +0000280isis_vertex_new (void *id, enum vertextype vtype)
281{
282 struct isis_vertex *vertex;
283
284 vertex = XMALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
hassof390d2c2004-09-10 20:48:21 +0000285 if (vertex == NULL)
286 {
287 zlog_err ("isis_vertex_new Out of memory!");
288 return NULL;
289 }
290
jardineb5d44e2003-12-23 08:09:43 +0000291 memset (vertex, 0, sizeof (struct isis_vertex));
292 vertex->type = vtype;
hassof390d2c2004-09-10 20:48:21 +0000293 switch (vtype)
294 {
295 case VTYPE_ES:
296 case VTYPE_NONPSEUDO_IS:
297 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
298 break;
299 case VTYPE_PSEUDO_IS:
300 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
301 break;
302 case VTYPE_IPREACH_INTERNAL:
303 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000304#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000305 case VTYPE_IP6REACH_INTERNAL:
306 case VTYPE_IP6REACH_EXTERNAL:
307#endif /* HAVE_IPV6 */
308 memcpy (&vertex->N.prefix, (struct prefix *) id,
309 sizeof (struct prefix));
310 break;
311 default:
312 zlog_err ("WTF!");
313 }
jardineb5d44e2003-12-23 08:09:43 +0000314
315 vertex->Adj_N = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000316
jardineb5d44e2003-12-23 08:09:43 +0000317 return vertex;
318}
319
320/*
321 * Add this IS to the root of SPT
322 */
hasso92365882005-01-18 13:53:33 +0000323static void
jardineb5d44e2003-12-23 08:09:43 +0000324isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
hassof390d2c2004-09-10 20:48:21 +0000325 int level)
jardineb5d44e2003-12-23 08:09:43 +0000326{
327 struct isis_vertex *vertex;
328 struct isis_lsp *lsp;
329 u_char lspid[ISIS_SYS_ID_LEN + 2];
330#ifdef EXTREME_DEBUG
331 u_char buff[BUFSIZ];
332#endif /* EXTREME_DEBUG */
333 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +0000334 LSP_PSEUDO_ID (lspid) = 0;
335 LSP_FRAGMENT (lspid) = 0;
336
jardineb5d44e2003-12-23 08:09:43 +0000337 lsp = lsp_search (lspid, area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +0000338
jardineb5d44e2003-12-23 08:09:43 +0000339 if (lsp == NULL)
340 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
hassof390d2c2004-09-10 20:48:21 +0000341
jardineb5d44e2003-12-23 08:09:43 +0000342 vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
343 vertex->lsp = lsp;
344
345 listnode_add (spftree->paths, vertex);
346
347#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000348 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
349 vtype2string (vertex->type), vid2string (vertex, buff),
350 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000351#endif /* EXTREME_DEBUG */
352
353 return;
354}
355
hasso92365882005-01-18 13:53:33 +0000356static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000357isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
jardineb5d44e2003-12-23 08:09:43 +0000358{
359 struct listnode *node;
360 struct isis_vertex *vertex;
361 struct prefix *p1, *p2;
362
hassof390d2c2004-09-10 20:48:21 +0000363 for (node = listhead (list); node; nextnode (node))
364 {
365 vertex = getdata (node);
366 if (vertex->type != vtype)
367 continue;
368 switch (vtype)
369 {
370 case VTYPE_ES:
371 case VTYPE_NONPSEUDO_IS:
372 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
373 return vertex;
374 break;
375 case VTYPE_PSEUDO_IS:
376 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
377 return vertex;
378 break;
379 case VTYPE_IPREACH_INTERNAL:
380 case VTYPE_IPREACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000381#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000382 case VTYPE_IP6REACH_INTERNAL:
383 case VTYPE_IP6REACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000384#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000385 p1 = (struct prefix *) id;
386 p2 = (struct prefix *) &vertex->N.id;
387 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
388 memcmp (&p1->u.prefix, &p2->u.prefix,
389 PSIZE (p1->prefixlen)) == 0)
390 return vertex;
391 break;
392 }
jardineb5d44e2003-12-23 08:09:43 +0000393 }
jardineb5d44e2003-12-23 08:09:43 +0000394
395 return NULL;
396}
397
jardineb5d44e2003-12-23 08:09:43 +0000398/*
399 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
400 */
hasso92365882005-01-18 13:53:33 +0000401static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000402isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
403 void *id, struct isis_adjacency *adj, u_int16_t cost,
404 int depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000405{
406 struct isis_vertex *vertex, *v;
407 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000408#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000409 u_char buff[BUFSIZ];
410#endif
411
412 vertex = isis_vertex_new (id, vtype);
413 vertex->d_N = cost;
414 vertex->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000415
jardineb5d44e2003-12-23 08:09:43 +0000416 if (adj)
417 listnode_add (vertex->Adj_N, adj);
hassof390d2c2004-09-10 20:48:21 +0000418#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000419 zlog_debug ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
420 vtype2string (vertex->type), vid2string (vertex, buff),
421 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000422#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000423 listnode_add (spftree->tents, vertex);
424 if (list_isempty (spftree->tents))
425 {
426 listnode_add (spftree->tents, vertex);
427 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000428 }
hassof390d2c2004-09-10 20:48:21 +0000429 for (node = listhead (spftree->tents); node; nextnode (node))
430 {
431 v = getdata (node);
432 if (v->d_N > vertex->d_N)
433 {
434 list_add_node_prev (spftree->tents, node, vertex);
435 break;
436 }
437 else if (v->d_N == vertex->d_N)
438 {
439 /* Tie break, add according to type */
440 while (v && v->d_N == vertex->d_N && v->type > vertex->type)
441 {
442 if (v->type > vertex->type)
443 {
444 break;
445 }
446 nextnode (node);
447 (node) ? (v = getdata (node)) : (v = NULL);
448 }
449 list_add_node_prev (spftree->tents, node, vertex);
450 break;
451 }
452 else if (node->next == NULL)
453 {
454 list_add_node_next (spftree->tents, node, vertex);
455 break;
456 }
457 }
jardineb5d44e2003-12-23 08:09:43 +0000458 return vertex;
459}
460
hasso92365882005-01-18 13:53:33 +0000461static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000462isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
463 void *id, struct isis_adjacency *adj, u_int16_t cost,
464 int family)
jardineb5d44e2003-12-23 08:09:43 +0000465{
466 struct isis_vertex *vertex;
jardineb5d44e2003-12-23 08:09:43 +0000467
hassof390d2c2004-09-10 20:48:21 +0000468 vertex = isis_find_vertex (spftree->tents, id, vtype);
469
470 if (vertex)
471 {
472 /* C.2.5 c) */
473 if (vertex->d_N == cost)
474 {
475 if (adj)
476 listnode_add (vertex->Adj_N, adj);
477 /* d) */
478 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
479 remove_excess_adjs (vertex->Adj_N);
480 }
481 /* f) */
482 else if (vertex->d_N > cost)
483 {
484 listnode_delete (spftree->tents, vertex);
485 goto add2tent;
486 }
487 /* e) do nothing */
488 return vertex;
489 }
490
491add2tent:
jardineb5d44e2003-12-23 08:09:43 +0000492 return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
493}
494
hasso92365882005-01-18 13:53:33 +0000495static void
hassof390d2c2004-09-10 20:48:21 +0000496process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
497 u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
498 int family)
jardineb5d44e2003-12-23 08:09:43 +0000499{
500 struct isis_vertex *vertex;
501#ifdef EXTREME_DEBUG
502 u_char buff[255];
503#endif
504
505 /* C.2.6 b) */
506 if (dist > MAX_PATH_METRIC)
507 return;
508 /* c) */
509 vertex = isis_find_vertex (spftree->paths, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000510 if (vertex)
511 {
jardineb5d44e2003-12-23 08:09:43 +0000512#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000513 zlog_debug ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
514 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000515#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000516 assert (dist >= vertex->d_N);
517 return;
518 }
jardineb5d44e2003-12-23 08:09:43 +0000519
520 vertex = isis_find_vertex (spftree->tents, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000521 /* d) */
522 if (vertex)
523 {
524 /* 1) */
jardineb5d44e2003-12-23 08:09:43 +0000525#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000526 zlog_debug ("ISIS-Spf: process_N %s %s dist %d",
527 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000528#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000529 if (vertex->d_N == dist)
530 {
531 if (adj)
532 listnode_add (vertex->Adj_N, adj);
533 /* 2) */
534 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
535 remove_excess_adjs (vertex->Adj_N);
536 /* 3) */
537 return;
538 }
539 else if (vertex->d_N < dist)
540 {
541 return;
542 /* 4) */
543 }
544 else
545 {
546 listnode_delete (spftree->tents, vertex);
547 }
jardineb5d44e2003-12-23 08:09:43 +0000548 }
hassof390d2c2004-09-10 20:48:21 +0000549
jardineb5d44e2003-12-23 08:09:43 +0000550 isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
551 return;
552}
553
554/*
555 * C.2.6 Step 1
556 */
hasso92365882005-01-18 13:53:33 +0000557static int
hassof390d2c2004-09-10 20:48:21 +0000558isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
559 uint16_t cost, uint16_t depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000560{
561 struct listnode *node, *fragnode = NULL;
562 u_int16_t dist;
563 struct is_neigh *is_neigh;
564 struct ipv4_reachability *ipreach;
565 enum vertextype vtype;
566 struct prefix prefix;
567#ifdef HAVE_IPV6
568 struct ipv6_reachability *ip6reach;
569#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000570
jardineb5d44e2003-12-23 08:09:43 +0000571
572 if (!lsp->adj)
573 return ISIS_WARNING;
hassof390d2c2004-09-10 20:48:21 +0000574 if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
jardineb5d44e2003-12-23 08:09:43 +0000575 return ISIS_OK;
576
hassof390d2c2004-09-10 20:48:21 +0000577lspfragloop:
578 if (lsp->lsp_header->seq_num == 0)
579 {
580 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
581 " - do not process");
582 return ISIS_WARNING;
583 }
jardineb5d44e2003-12-23 08:09:43 +0000584
hassof390d2c2004-09-10 20:48:21 +0000585 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
586 {
587 if (lsp->tlv_data.is_neighs)
588 {
589 for (node = listhead (lsp->tlv_data.is_neighs); node;
590 nextnode (node))
591 {
592 is_neigh = getdata (node);
593 /* C.2.6 a) */
594 /* Two way connectivity */
595 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
596 continue;
597 dist = cost + is_neigh->metrics.metric_default;
598 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
599 : VTYPE_NONPSEUDO_IS;
600 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
601 depth + 1, lsp->adj, family);
602 }
603 }
604 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
605 {
606 prefix.family = AF_INET;
607 for (node = listhead (lsp->tlv_data.ipv4_int_reachs); node;
608 nextnode (node))
609 {
610 ipreach = getdata (node);
611 dist = cost + ipreach->metrics.metric_default;
612 vtype = VTYPE_IPREACH_INTERNAL;
613 prefix.u.prefix4 = ipreach->prefix;
614 prefix.prefixlen = ip_masklen (ipreach->mask);
615 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
616 lsp->adj, family);
617 }
618 }
619
620 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
621 {
622 prefix.family = AF_INET;
623 for (node = listhead (lsp->tlv_data.ipv4_ext_reachs); node;
624 nextnode (node))
625 {
626 ipreach = getdata (node);
627 dist = cost + ipreach->metrics.metric_default;
628 vtype = VTYPE_IPREACH_EXTERNAL;
629 prefix.u.prefix4 = ipreach->prefix;
630 prefix.prefixlen = ip_masklen (ipreach->mask);
631 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
632 lsp->adj, family);
633 }
634 }
jardineb5d44e2003-12-23 08:09:43 +0000635#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000636 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
637 {
638 prefix.family = AF_INET6;
639 for (node = listhead (lsp->tlv_data.ipv6_reachs); node;
640 nextnode (node))
641 {
642 ip6reach = getdata (node);
643 dist = cost + ip6reach->metric;
644 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
645 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
646 prefix.prefixlen = ip6reach->prefix_len;
647 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
648 PSIZE (ip6reach->prefix_len));
649 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
650 lsp->adj, family);
651 }
652 }
jardineb5d44e2003-12-23 08:09:43 +0000653#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000654 }
655
jardineb5d44e2003-12-23 08:09:43 +0000656 if (fragnode == NULL)
657 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000658 else
hasso1cd80842004-10-07 20:07:40 +0000659 nextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000660
hassof390d2c2004-09-10 20:48:21 +0000661 if (fragnode)
662 {
663 lsp = getdata (fragnode);
664 goto lspfragloop;
665 }
666
jardineb5d44e2003-12-23 08:09:43 +0000667 return ISIS_OK;
668}
669
hasso92365882005-01-18 13:53:33 +0000670static int
hassof390d2c2004-09-10 20:48:21 +0000671isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
672 struct isis_lsp *lsp, uint16_t cost,
673 uint16_t depth, int family)
jardineb5d44e2003-12-23 08:09:43 +0000674{
675 struct listnode *node, *fragnode = NULL;
676 struct is_neigh *is_neigh;
677 enum vertextype vtype;
hassof390d2c2004-09-10 20:48:21 +0000678
679pseudofragloop:
680
681 if (lsp->lsp_header->seq_num == 0)
682 {
683 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
684 " - do not process");
685 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000686 }
hassof390d2c2004-09-10 20:48:21 +0000687
688 for (node = (lsp->tlv_data.is_neighs ?
689 listhead (lsp->tlv_data.is_neighs) : NULL);
690 node; nextnode (node))
691 {
692 is_neigh = getdata (node);
693 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
694 : VTYPE_NONPSEUDO_IS;
695 /* Two way connectivity */
696 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
697 continue;
698 if (isis_find_vertex
699 (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL
700 && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id,
701 vtype) == NULL)
702 {
703 /* C.2.5 i) */
704 isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
705 cost, depth, family);
706 }
707 }
708
jardineb5d44e2003-12-23 08:09:43 +0000709 if (fragnode == NULL)
710 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000711 else
hasso1cd80842004-10-07 20:07:40 +0000712 nextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000713
hassof390d2c2004-09-10 20:48:21 +0000714 if (fragnode)
715 {
716 lsp = getdata (fragnode);
717 goto pseudofragloop;
718 }
jardineb5d44e2003-12-23 08:09:43 +0000719
jardineb5d44e2003-12-23 08:09:43 +0000720 return ISIS_OK;
721}
hassof390d2c2004-09-10 20:48:21 +0000722
hasso92365882005-01-18 13:53:33 +0000723static int
hassof390d2c2004-09-10 20:48:21 +0000724isis_spf_preload_tent (struct isis_spftree *spftree,
725 struct isis_area *area, int level, int family)
jardineb5d44e2003-12-23 08:09:43 +0000726{
727 struct isis_vertex *vertex;
728 struct isis_circuit *circuit;
729 struct listnode *cnode, *anode, *ipnode;
730 struct isis_adjacency *adj;
731 struct isis_lsp *lsp;
732 struct list *adj_list;
733 struct list *adjdb;
734 struct prefix_ipv4 *ipv4;
735 struct prefix prefix;
736 int retval = ISIS_OK;
737 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
738#ifdef HAVE_IPV6
739 struct prefix_ipv6 *ipv6;
740#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000741
742 for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode))
743 {
744 circuit = getdata (cnode);
745 if (circuit->state != C_STATE_UP)
jardineb5d44e2003-12-23 08:09:43 +0000746 continue;
hassof390d2c2004-09-10 20:48:21 +0000747 if (!(circuit->circuit_is_type & level))
748 continue;
749 if (family == AF_INET && !circuit->ip_router)
750 continue;
751#ifdef HAVE_IPV6
752 if (family == AF_INET6 && !circuit->ipv6_router)
753 continue;
754#endif /* HAVE_IPV6 */
755 /*
756 * Add IP(v6) addresses of this circuit
jardineb5d44e2003-12-23 08:09:43 +0000757 */
hassof390d2c2004-09-10 20:48:21 +0000758 if (family == AF_INET)
759 {
760 prefix.family = AF_INET;
761 for (ipnode =
762 (circuit->ip_addrs ? listhead (circuit->ip_addrs) : NULL);
763 ipnode; nextnode (ipnode))
764 {
765 ipv4 = getdata (ipnode);
766 prefix.u.prefix4 = ipv4->prefix;
767 prefix.prefixlen = ipv4->prefixlen;
768 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
769 NULL, 0, family);
770 }
771 }
772#ifdef HAVE_IPV6
773 if (family == AF_INET6)
774 {
775 prefix.family = AF_INET6;
776 for (ipnode = (circuit->ipv6_non_link ? listhead
777 (circuit->ipv6_non_link) : NULL); ipnode;
778 nextnode (ipnode))
779 {
780 ipv6 = getdata (ipnode);
781 prefix.prefixlen = ipv6->prefixlen;
782 prefix.u.prefix6 = ipv6->prefix;
783 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
784 &prefix, NULL, 0, family);
785 }
786 }
787#endif /* HAVE_IPV6 */
788 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
789 {
790 /*
791 * Add the adjacencies
792 */
793 adj_list = list_new ();
794 adjdb = circuit->u.bc.adjdb[level - 1];
795 isis_adj_build_up_list (adjdb, adj_list);
796 if (listcount (adj_list) == 0)
797 {
798 list_delete (adj_list);
799 zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s",
800 level, circuit->interface->name);
801 continue;
802 }
803 anode = listhead (adj_list);
804 while (anode)
805 {
806 adj = getdata (anode);
807 if (!speaks (&adj->nlpids, family))
808 {
hasso1cd80842004-10-07 20:07:40 +0000809 nextnode (anode);
hassof390d2c2004-09-10 20:48:21 +0000810 continue;
811 }
812 switch (adj->sys_type)
813 {
814 case ISIS_SYSTYPE_ES:
815 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
816 circuit->metrics[level -
817 1].metric_default,
818 family);
819 break;
820 case ISIS_SYSTYPE_IS:
821 case ISIS_SYSTYPE_L1_IS:
822 case ISIS_SYSTYPE_L2_IS:
823 vertex =
824 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
825 adj->sysid, adj,
826 circuit->metrics[level -
827 1].metric_default,
828 family);
829 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
830 LSP_PSEUDO_ID (lsp_id) = 0;
831 LSP_FRAGMENT (lsp_id) = 0;
832 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
833 if (!lsp)
834 zlog_warn ("No lsp found for IS adjacency");
835 /* else {
836 isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
837 } */
838 break;
839 case ISIS_SYSTYPE_UNKNOWN:
840 default:
841 zlog_warn ("isis_spf_preload_tent unknow adj type");
842 }
hasso1cd80842004-10-07 20:07:40 +0000843 nextnode (anode);
hassof390d2c2004-09-10 20:48:21 +0000844 }
845 list_delete (adj_list);
846 /*
847 * Add the pseudonode
848 */
849 if (level == 1)
850 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
851 else
852 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
853 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
854 adj = isis_adj_lookup (lsp_id, adjdb);
855 /* if no adj, we are the dis or error */
856 if (!adj && !circuit->u.bc.is_dr[level - 1])
857 {
858 zlog_warn ("ISIS-Spf: No adjacency found for DR");
859 }
860 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
861 {
862 zlog_warn ("ISIS-Spf: No lsp found for DR");
863 }
864 else
865 {
866 isis_spf_process_pseudo_lsp
867 (spftree, lsp, circuit->metrics[level - 1].metric_default, 0,
868 family);
869
870 }
871 }
872 else if (circuit->circ_type == CIRCUIT_T_P2P)
873 {
874 adj = circuit->u.p2p.neighbor;
875 if (!adj)
876 continue;
877 switch (adj->sys_type)
878 {
879 case ISIS_SYSTYPE_ES:
880 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
881 circuit->metrics[level - 1].metric_default,
882 family);
883 break;
884 case ISIS_SYSTYPE_IS:
885 case ISIS_SYSTYPE_L1_IS:
886 case ISIS_SYSTYPE_L2_IS:
887 if (speaks (&adj->nlpids, family))
888 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
889 adj,
890 circuit->metrics[level -
891 1].metric_default,
892 family);
893 break;
894 case ISIS_SYSTYPE_UNKNOWN:
895 default:
896 zlog_warn ("isis_spf_preload_tent unknow adj type");
897 break;
898 }
899 }
jardineb5d44e2003-12-23 08:09:43 +0000900 else
hassof390d2c2004-09-10 20:48:21 +0000901 {
902 zlog_warn ("isis_spf_preload_tent unsupported media");
903 retval = ISIS_WARNING;
904 }
905
jardineb5d44e2003-12-23 08:09:43 +0000906 }
jardineb5d44e2003-12-23 08:09:43 +0000907
908 return retval;
909}
910
911/*
912 * The parent(s) for vertex is set when added to TENT list
913 * now we just put the child pointer(s) in place
914 */
hasso92365882005-01-18 13:53:33 +0000915static void
jardineb5d44e2003-12-23 08:09:43 +0000916add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
hassof390d2c2004-09-10 20:48:21 +0000917 struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +0000918{
jardineb5d44e2003-12-23 08:09:43 +0000919#ifdef EXTREME_DEBUG
920 u_char buff[BUFSIZ];
921#endif /* EXTREME_DEBUG */
922 listnode_add (spftree->paths, vertex);
923
hassof390d2c2004-09-10 20:48:21 +0000924#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000925 zlog_debug ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
926 vtype2string (vertex->type), vid2string (vertex, buff),
927 vertex->depth, vertex->d_N);
hassof390d2c2004-09-10 20:48:21 +0000928#endif /* EXTREME_DEBUG */
929 if (vertex->type > VTYPE_ES)
930 {
931 if (listcount (vertex->Adj_N) > 0)
932 isis_route_create ((struct prefix *) &vertex->N.prefix,
933 vertex->d_N, vertex->depth, vertex->Adj_N, area);
934 else if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +0000935 zlog_debug ("ISIS-Spf: no adjacencies do not install route");
hassof390d2c2004-09-10 20:48:21 +0000936 }
937
jardineb5d44e2003-12-23 08:09:43 +0000938 return;
939}
940
hasso92365882005-01-18 13:53:33 +0000941static void
jardineb5d44e2003-12-23 08:09:43 +0000942init_spt (struct isis_spftree *spftree)
943{
hassof7c43dc2004-09-26 16:24:14 +0000944 spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +0000945 list_delete_all_node (spftree->tents);
946 list_delete_all_node (spftree->paths);
947 spftree->tents->del = spftree->paths->del = NULL;
hassof390d2c2004-09-10 20:48:21 +0000948
jardineb5d44e2003-12-23 08:09:43 +0000949 return;
950}
951
hasso92365882005-01-18 13:53:33 +0000952static int
jardineb5d44e2003-12-23 08:09:43 +0000953isis_run_spf (struct isis_area *area, int level, int family)
954{
955 int retval = ISIS_OK;
956 struct listnode *node;
957 struct isis_vertex *vertex;
hassof390d2c2004-09-10 20:48:21 +0000958 struct isis_spftree *spftree = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000959 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
960 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000961
jardineb5d44e2003-12-23 08:09:43 +0000962 if (family == AF_INET)
963 spftree = area->spftree[level - 1];
964#ifdef HAVE_IPV6
965 else if (family == AF_INET6)
966 spftree = area->spftree6[level - 1];
967#endif
hassof390d2c2004-09-10 20:48:21 +0000968
jardineb5d44e2003-12-23 08:09:43 +0000969 assert (spftree);
970
971 /*
972 * C.2.5 Step 0
973 */
974 init_spt (spftree);
975 /* a) */
976 isis_spf_add_self (spftree, area, level);
977 /* b) */
978 retval = isis_spf_preload_tent (spftree, area, level, family);
hassof390d2c2004-09-10 20:48:21 +0000979
jardineb5d44e2003-12-23 08:09:43 +0000980 /*
981 * C.2.7 Step 2
982 */
hassof390d2c2004-09-10 20:48:21 +0000983 if (listcount (spftree->tents) == 0)
984 {
985 zlog_warn ("ISIS-Spf: TENT is empty");
986 spftree->lastrun = time (NULL);
987 return retval;
jardineb5d44e2003-12-23 08:09:43 +0000988 }
hassof390d2c2004-09-10 20:48:21 +0000989
990 while (listcount (spftree->tents) > 0)
991 {
992 node = listhead (spftree->tents);
993 vertex = getdata (node);
994 /* Remove from tent list */
995 list_delete_node (spftree->tents, node);
996 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
997 continue;
998 add_to_paths (spftree, vertex, area);
999 if (vertex->type == VTYPE_PSEUDO_IS ||
1000 vertex->type == VTYPE_NONPSEUDO_IS)
1001 {
1002 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1003 LSP_FRAGMENT (lsp_id) = 0;
1004 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
1005 if (lsp)
1006 {
1007 if (LSP_PSEUDO_ID (lsp_id))
1008 {
1009 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
1010 vertex->depth, family);
1011
1012 }
1013 else
1014 {
1015 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
1016 vertex->depth, family);
1017 }
1018 }
1019 else
1020 {
1021 zlog_warn ("ISIS-Spf: No LSP found for %s",
1022 rawlspid_print (lsp_id));
1023 }
1024 }
1025 }
1026
jardineb5d44e2003-12-23 08:09:43 +00001027 thread_add_event (master, isis_route_validate, area, 0);
1028 spftree->lastrun = time (NULL);
1029 spftree->pending = 0;
hassof390d2c2004-09-10 20:48:21 +00001030
jardineb5d44e2003-12-23 08:09:43 +00001031 return retval;
1032}
1033
1034int
1035isis_run_spf_l1 (struct thread *thread)
1036{
1037 struct isis_area *area;
1038 int retval = ISIS_OK;
1039
hassof390d2c2004-09-10 20:48:21 +00001040 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001041 assert (area);
1042
hasso12a5cae2004-09-19 19:39:26 +00001043 area->spftree[0]->t_spf = NULL;
1044
hassof390d2c2004-09-10 20:48:21 +00001045 if (!(area->is_type & IS_LEVEL_1))
1046 {
1047 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001048 zlog_warn ("ISIS-SPF (%s) area does not share level",
1049 area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001050 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001051 }
jardineb5d44e2003-12-23 08:09:43 +00001052
hassof390d2c2004-09-10 20:48:21 +00001053 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001054 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001055
jardineb5d44e2003-12-23 08:09:43 +00001056 if (area->ip_circuits)
1057 retval = isis_run_spf (area, 1, AF_INET);
hasso12a5cae2004-09-19 19:39:26 +00001058
1059 THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
1060 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1061
jardineb5d44e2003-12-23 08:09:43 +00001062 return retval;
1063}
1064
1065int
1066isis_run_spf_l2 (struct thread *thread)
1067{
1068 struct isis_area *area;
1069 int retval = ISIS_OK;
1070
hassof390d2c2004-09-10 20:48:21 +00001071 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001072 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001073
hasso12a5cae2004-09-19 19:39:26 +00001074 area->spftree[1]->t_spf = NULL;
1075
hassof390d2c2004-09-10 20:48:21 +00001076 if (!(area->is_type & IS_LEVEL_2))
1077 {
1078 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001079 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001080 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001081 }
hassof390d2c2004-09-10 20:48:21 +00001082
1083 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001084 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
jardineb5d44e2003-12-23 08:09:43 +00001085
1086 if (area->ip_circuits)
1087 retval = isis_run_spf (area, 2, AF_INET);
hasso12a5cae2004-09-19 19:39:26 +00001088
1089 THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
1090 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
jardineb5d44e2003-12-23 08:09:43 +00001091
1092 return retval;
1093}
1094
hassof390d2c2004-09-10 20:48:21 +00001095int
jardineb5d44e2003-12-23 08:09:43 +00001096isis_spf_schedule (struct isis_area *area, int level)
1097{
1098 int retval = ISIS_OK;
1099 struct isis_spftree *spftree = area->spftree[level - 1];
1100 time_t diff, now = time (NULL);
1101
1102 if (spftree->pending)
1103 return retval;
1104
hassof390d2c2004-09-10 20:48:21 +00001105 diff = now - spftree->lastrun;
jardineb5d44e2003-12-23 08:09:43 +00001106
1107 /* FIXME: let's wait a minute before doing the SPF */
hassof390d2c2004-09-10 20:48:21 +00001108 if (now - isis->uptime < 60 || isis->uptime == 0)
1109 {
1110 if (level == 1)
hasso12a5cae2004-09-19 19:39:26 +00001111 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
hassof390d2c2004-09-10 20:48:21 +00001112 else
hasso12a5cae2004-09-19 19:39:26 +00001113 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
jardineb5d44e2003-12-23 08:09:43 +00001114
hassof390d2c2004-09-10 20:48:21 +00001115 spftree->pending = 1;
1116 return retval;
1117 }
hasso12a5cae2004-09-19 19:39:26 +00001118
1119 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001120
hassof390d2c2004-09-10 20:48:21 +00001121 if (diff < MINIMUM_SPF_INTERVAL)
1122 {
1123 if (level == 1)
hasso12a5cae2004-09-19 19:39:26 +00001124 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
1125 MINIMUM_SPF_INTERVAL - diff);
hassof390d2c2004-09-10 20:48:21 +00001126 else
hasso12a5cae2004-09-19 19:39:26 +00001127 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
1128 MINIMUM_SPF_INTERVAL - diff);
jardineb5d44e2003-12-23 08:09:43 +00001129
hassof390d2c2004-09-10 20:48:21 +00001130 spftree->pending = 1;
1131 }
1132 else
1133 {
1134 spftree->pending = 0;
1135 retval = isis_run_spf (area, level, AF_INET);
hasso12a5cae2004-09-19 19:39:26 +00001136 if (level == 1)
1137 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
1138 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1139 else
1140 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
1141 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
hassof390d2c2004-09-10 20:48:21 +00001142 }
jardineb5d44e2003-12-23 08:09:43 +00001143
1144 return retval;
1145}
1146
1147#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +00001148static int
hasso12a5cae2004-09-19 19:39:26 +00001149isis_run_spf6_l1 (struct thread *thread)
1150{
1151 struct isis_area *area;
1152 int retval = ISIS_OK;
1153
1154 area = THREAD_ARG (thread);
1155 assert (area);
1156
1157 area->spftree6[0]->t_spf = NULL;
1158
1159 if (!(area->is_type & IS_LEVEL_1))
1160 {
1161 if (isis->debugs & DEBUG_SPF_EVENTS)
1162 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1163 return ISIS_WARNING;
1164 }
1165
1166 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001167 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001168
1169 if (area->ipv6_circuits)
1170 retval = isis_run_spf (area, 1, AF_INET6);
1171
1172 THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
1173 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1174
1175 return retval;
1176}
1177
hasso92365882005-01-18 13:53:33 +00001178static int
hasso12a5cae2004-09-19 19:39:26 +00001179isis_run_spf6_l2 (struct thread *thread)
1180{
1181 struct isis_area *area;
1182 int retval = ISIS_OK;
1183
1184 area = THREAD_ARG (thread);
1185 assert (area);
1186
1187 area->spftree6[1]->t_spf = NULL;
1188
1189 if (!(area->is_type & IS_LEVEL_2))
1190 {
1191 if (isis->debugs & DEBUG_SPF_EVENTS)
1192 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1193 return ISIS_WARNING;
1194 }
1195
1196 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001197 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001198
1199 if (area->ipv6_circuits)
1200 retval = isis_run_spf (area, 2, AF_INET6);
1201
1202 THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
1203 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1204
1205 return retval;
1206}
1207
1208int
jardineb5d44e2003-12-23 08:09:43 +00001209isis_spf_schedule6 (struct isis_area *area, int level)
1210{
1211 int retval = ISIS_OK;
1212 struct isis_spftree *spftree = area->spftree6[level - 1];
1213 time_t diff, now = time (NULL);
1214
1215 if (spftree->pending)
1216 return retval;
1217
hassof390d2c2004-09-10 20:48:21 +00001218 diff = now - spftree->lastrun;
1219
jardineb5d44e2003-12-23 08:09:43 +00001220 /* FIXME: let's wait a minute before doing the SPF */
hassof390d2c2004-09-10 20:48:21 +00001221 if (now - isis->uptime < 60 || isis->uptime == 0)
1222 {
1223 if (level == 1)
hasso12a5cae2004-09-19 19:39:26 +00001224 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60);
hassof390d2c2004-09-10 20:48:21 +00001225 else
hasso12a5cae2004-09-19 19:39:26 +00001226 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60);
jardineb5d44e2003-12-23 08:09:43 +00001227
hassof390d2c2004-09-10 20:48:21 +00001228 spftree->pending = 1;
1229 return retval;
1230 }
hasso12a5cae2004-09-19 19:39:26 +00001231
1232 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001233
hassof390d2c2004-09-10 20:48:21 +00001234 if (diff < MINIMUM_SPF_INTERVAL)
1235 {
1236 if (level == 1)
hasso12a5cae2004-09-19 19:39:26 +00001237 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1238 MINIMUM_SPF_INTERVAL - diff);
hassof390d2c2004-09-10 20:48:21 +00001239 else
hasso12a5cae2004-09-19 19:39:26 +00001240 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1241 MINIMUM_SPF_INTERVAL - diff);
jardineb5d44e2003-12-23 08:09:43 +00001242
hassof390d2c2004-09-10 20:48:21 +00001243 spftree->pending = 1;
1244 }
1245 else
1246 {
1247 spftree->pending = 0;
1248 retval = isis_run_spf (area, level, AF_INET6);
hasso12a5cae2004-09-19 19:39:26 +00001249
1250 if (level == 1)
1251 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1252 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
1253 else
1254 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1255 isis_jitter (PERIODIC_SPF_INTERVAL, 10));
hassof390d2c2004-09-10 20:48:21 +00001256 }
jardineb5d44e2003-12-23 08:09:43 +00001257
1258 return retval;
1259}
jardineb5d44e2003-12-23 08:09:43 +00001260#endif
1261
hasso92365882005-01-18 13:53:33 +00001262static void
jardineb5d44e2003-12-23 08:09:43 +00001263isis_print_paths (struct vty *vty, struct list *paths)
1264{
1265 struct listnode *node, *anode;
1266 struct isis_vertex *vertex;
1267 struct isis_dynhn *dyn, *nh_dyn = NULL;
1268 struct isis_adjacency *adj;
hasso92365882005-01-18 13:53:33 +00001269#if 0
jardineb5d44e2003-12-23 08:09:43 +00001270 u_char buff[255];
hasso92365882005-01-18 13:53:33 +00001271#endif /* 0 */
jardineb5d44e2003-12-23 08:09:43 +00001272
1273 vty_out (vty, "System Id Metric Next-Hop"
hassof390d2c2004-09-10 20:48:21 +00001274 " Interface SNPA%s", VTY_NEWLINE);
1275 for (node = listhead (paths); node; nextnode (node))
1276 {
1277 vertex = getdata (node);
1278 if (vertex->type != VTYPE_NONPSEUDO_IS)
1279 continue;
1280 if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
1281 {
1282 vty_out (vty, "%s --%s", host.name, VTY_NEWLINE);
1283 }
1284 else
1285 {
1286 dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
1287 anode = listhead (vertex->Adj_N);
1288 adj = getdata (anode);
1289 if (adj)
1290 {
1291 nh_dyn = dynhn_find_by_id (adj->sysid);
1292 vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
1293 (dyn != NULL) ? dyn->name.name :
1294 (u_char *) rawlspid_print ((u_char *) vertex->N.id),
1295 vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
1296 (u_char *) rawlspid_print (adj->sysid),
1297 adj->circuit->interface->name,
1298 snpa_print (adj->snpa), VTY_NEWLINE);
1299 }
1300 else
1301 {
1302 vty_out (vty, "%s %u %s", dyn ? dyn->name.name :
1303 (u_char *) rawlspid_print (vertex->N.id),
1304 vertex->d_N, VTY_NEWLINE);
1305 }
1306 }
jardineb5d44e2003-12-23 08:09:43 +00001307#if 0
hassof390d2c2004-09-10 20:48:21 +00001308 vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
1309 vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001310#endif
hassof390d2c2004-09-10 20:48:21 +00001311 }
jardineb5d44e2003-12-23 08:09:43 +00001312}
1313
1314DEFUN (show_isis_topology,
1315 show_isis_topology_cmd,
1316 "show isis topology",
1317 SHOW_STR
1318 "IS-IS information\n"
1319 "IS-IS paths to Intermediate Systems\n")
1320{
1321 struct listnode *node;
1322 struct isis_area *area;
1323 int level;
hassof390d2c2004-09-10 20:48:21 +00001324
jardineb5d44e2003-12-23 08:09:43 +00001325 if (!isis->area_list || isis->area_list->count == 0)
1326 return CMD_SUCCESS;
1327
hassof390d2c2004-09-10 20:48:21 +00001328 for (node = listhead (isis->area_list); node; nextnode (node))
1329 {
1330 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001331
hassof390d2c2004-09-10 20:48:21 +00001332 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1333 VTY_NEWLINE);
1334
1335 for (level = 0; level < ISIS_LEVELS; level++)
1336 {
1337 if (area->ip_circuits > 0 && area->spftree[level]
1338 && area->spftree[level]->paths->count > 0)
1339 {
1340 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1341 level + 1, VTY_NEWLINE);
1342 isis_print_paths (vty, area->spftree[level]->paths);
1343 }
jardineb5d44e2003-12-23 08:09:43 +00001344#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001345 if (area->ipv6_circuits > 0 && area->spftree6[level]
1346 && area->spftree6[level]->paths->count > 0)
1347 {
1348 vty_out (vty,
1349 "IS-IS paths to level-%d routers that speak IPv6%s",
1350 level + 1, VTY_NEWLINE);
1351 isis_print_paths (vty, area->spftree6[level]->paths);
1352 }
jardineb5d44e2003-12-23 08:09:43 +00001353#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001354 }
jardineb5d44e2003-12-23 08:09:43 +00001355 }
jardineb5d44e2003-12-23 08:09:43 +00001356
1357 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001358}
jardineb5d44e2003-12-23 08:09:43 +00001359
1360DEFUN (show_isis_topology_l1,
1361 show_isis_topology_l1_cmd,
1362 "show isis topology level-1",
1363 SHOW_STR
1364 "IS-IS information\n"
1365 "IS-IS paths to Intermediate Systems\n"
1366 "Paths to all level-1 routers in the area\n")
1367{
1368 struct listnode *node;
1369 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001370
jardineb5d44e2003-12-23 08:09:43 +00001371 if (!isis->area_list || isis->area_list->count == 0)
1372 return CMD_SUCCESS;
1373
hassof390d2c2004-09-10 20:48:21 +00001374 for (node = listhead (isis->area_list); node; nextnode (node))
1375 {
1376 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001377
hassof390d2c2004-09-10 20:48:21 +00001378 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1379 VTY_NEWLINE);
1380
1381 if (area->ip_circuits > 0 && area->spftree[0]
1382 && area->spftree[0]->paths->count > 0)
1383 {
1384 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1385 VTY_NEWLINE);
1386 isis_print_paths (vty, area->spftree[0]->paths);
1387 }
jardineb5d44e2003-12-23 08:09:43 +00001388#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001389 if (area->ipv6_circuits > 0 && area->spftree6[0]
1390 && area->spftree6[0]->paths->count > 0)
1391 {
1392 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1393 VTY_NEWLINE);
1394 isis_print_paths (vty, area->spftree6[0]->paths);
1395 }
jardineb5d44e2003-12-23 08:09:43 +00001396#endif /* HAVE_IPV6 */
1397 }
1398
jardineb5d44e2003-12-23 08:09:43 +00001399 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001400}
jardineb5d44e2003-12-23 08:09:43 +00001401
1402DEFUN (show_isis_topology_l2,
1403 show_isis_topology_l2_cmd,
1404 "show isis topology level-2",
1405 SHOW_STR
1406 "IS-IS information\n"
1407 "IS-IS paths to Intermediate Systems\n"
1408 "Paths to all level-2 routers in the domain\n")
1409{
1410 struct listnode *node;
1411 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001412
jardineb5d44e2003-12-23 08:09:43 +00001413 if (!isis->area_list || isis->area_list->count == 0)
1414 return CMD_SUCCESS;
1415
hassof390d2c2004-09-10 20:48:21 +00001416 for (node = listhead (isis->area_list); node; nextnode (node))
1417 {
1418 area = getdata (node);
jardineb5d44e2003-12-23 08:09:43 +00001419
hassof390d2c2004-09-10 20:48:21 +00001420 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1421 VTY_NEWLINE);
1422
1423 if (area->ip_circuits > 0 && area->spftree[1]
1424 && area->spftree[1]->paths->count > 0)
1425 {
1426 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1427 VTY_NEWLINE);
1428 isis_print_paths (vty, area->spftree[1]->paths);
1429 }
jardineb5d44e2003-12-23 08:09:43 +00001430#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001431 if (area->ipv6_circuits > 0 && area->spftree6[1]
1432 && area->spftree6[1]->paths->count > 0)
1433 {
1434 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1435 VTY_NEWLINE);
1436 isis_print_paths (vty, area->spftree6[1]->paths);
1437 }
jardineb5d44e2003-12-23 08:09:43 +00001438#endif /* HAVE_IPV6 */
1439 }
1440
jardineb5d44e2003-12-23 08:09:43 +00001441 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001442}
jardineb5d44e2003-12-23 08:09:43 +00001443
1444void
1445isis_spf_cmds_init ()
1446{
1447 install_element (VIEW_NODE, &show_isis_topology_cmd);
1448 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1449 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1450
1451 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1452 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1453 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1454}