blob: 198104a98d22938c211ab27490f70875ea4f23f4 [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
jardineb5d44e2003-12-23 08:09:43 +000024#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000025
26#include "thread.h"
27#include "linklist.h"
28#include "vty.h"
29#include "log.h"
30#include "command.h"
31#include "memory.h"
32#include "prefix.h"
33#include "hash.h"
34#include "if.h"
35#include "table.h"
36
37#include "isis_constants.h"
38#include "isis_common.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070039#include "isis_flags.h"
jardineb5d44e2003-12-23 08:09:43 +000040#include "dict.h"
41#include "isisd.h"
42#include "isis_misc.h"
43#include "isis_adjacency.h"
44#include "isis_circuit.h"
45#include "isis_tlv.h"
46#include "isis_pdu.h"
47#include "isis_lsp.h"
48#include "isis_dynhn.h"
49#include "isis_spf.h"
50#include "isis_route.h"
51#include "isis_csm.h"
52
jardineb5d44e2003-12-23 08:09:43 +000053int isis_run_spf_l1 (struct thread *thread);
54int isis_run_spf_l2 (struct thread *thread);
55
jardineb5d44e2003-12-23 08:09:43 +000056/* 7.2.7 */
hasso92365882005-01-18 13:53:33 +000057static void
jardineb5d44e2003-12-23 08:09:43 +000058remove_excess_adjs (struct list *adjs)
59{
hasso3fdb2dd2005-09-28 18:45:54 +000060 struct listnode *node, *excess = NULL;
jardineb5d44e2003-12-23 08:09:43 +000061 struct isis_adjacency *adj, *candidate = NULL;
62 int comp;
63
hasso3fdb2dd2005-09-28 18:45:54 +000064 for (ALL_LIST_ELEMENTS_RO (adjs, node, adj))
hassof390d2c2004-09-10 20:48:21 +000065 {
66 if (excess == NULL)
67 excess = node;
paul1eb8ef22005-04-07 07:30:20 +000068 candidate = listgetdata (excess);
69
hassof390d2c2004-09-10 20:48:21 +000070 if (candidate->sys_type < adj->sys_type)
71 {
72 excess = node;
73 candidate = adj;
74 continue;
75 }
76 if (candidate->sys_type > adj->sys_type)
77 continue;
78
79 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
80 if (comp > 0)
81 {
82 excess = node;
83 candidate = adj;
84 continue;
85 }
86 if (comp < 0)
87 continue;
88
89 if (candidate->circuit->circuit_id > adj->circuit->circuit_id)
90 {
91 excess = node;
92 candidate = adj;
93 continue;
94 }
95
96 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
97 continue;
98
99 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
100 if (comp > 0)
101 {
102 excess = node;
103 candidate = adj;
104 continue;
105 }
jardineb5d44e2003-12-23 08:09:43 +0000106 }
107
jardineb5d44e2003-12-23 08:09:43 +0000108 list_delete_node (adjs, excess);
109
110 return;
111}
112
hasso92365882005-01-18 13:53:33 +0000113static const char *
jardineb5d44e2003-12-23 08:09:43 +0000114vtype2string (enum vertextype vtype)
115{
hassof390d2c2004-09-10 20:48:21 +0000116 switch (vtype)
117 {
118 case VTYPE_PSEUDO_IS:
119 return "pseudo_IS";
120 break;
hasso82a84282005-09-26 18:15:36 +0000121 case VTYPE_PSEUDO_TE_IS:
122 return "pseudo_TE-IS";
123 break;
hassof390d2c2004-09-10 20:48:21 +0000124 case VTYPE_NONPSEUDO_IS:
125 return "IS";
126 break;
hasso82a84282005-09-26 18:15:36 +0000127 case VTYPE_NONPSEUDO_TE_IS:
128 return "TE-IS";
129 break;
hassof390d2c2004-09-10 20:48:21 +0000130 case VTYPE_ES:
131 return "ES";
132 break;
133 case VTYPE_IPREACH_INTERNAL:
134 return "IP internal";
135 break;
136 case VTYPE_IPREACH_EXTERNAL:
137 return "IP external";
138 break;
hasso82a84282005-09-26 18:15:36 +0000139 case VTYPE_IPREACH_TE:
140 return "IP TE";
141 break;
jardineb5d44e2003-12-23 08:09:43 +0000142#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000143 case VTYPE_IP6REACH_INTERNAL:
144 return "IP6 internal";
145 break;
146 case VTYPE_IP6REACH_EXTERNAL:
147 return "IP6 external";
148 break;
149#endif /* HAVE_IPV6 */
150 default:
151 return "UNKNOWN";
152 }
153 return NULL; /* Not reached */
jardineb5d44e2003-12-23 08:09:43 +0000154}
155
hasso92365882005-01-18 13:53:33 +0000156static const char *
hassof390d2c2004-09-10 20:48:21 +0000157vid2string (struct isis_vertex *vertex, u_char * buff)
jardineb5d44e2003-12-23 08:09:43 +0000158{
hassof390d2c2004-09-10 20:48:21 +0000159 switch (vertex->type)
160 {
161 case VTYPE_PSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000162 case VTYPE_PSEUDO_TE_IS:
Josh Bailey3f045a02012-03-24 08:35:20 -0700163 return print_sys_hostname (vertex->N.id);
hassof390d2c2004-09-10 20:48:21 +0000164 break;
165 case VTYPE_NONPSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000166 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000167 case VTYPE_ES:
Josh Bailey3f045a02012-03-24 08:35:20 -0700168 return print_sys_hostname (vertex->N.id);
hassof390d2c2004-09-10 20:48:21 +0000169 break;
170 case VTYPE_IPREACH_INTERNAL:
171 case VTYPE_IPREACH_EXTERNAL:
hasso82a84282005-09-26 18:15:36 +0000172 case VTYPE_IPREACH_TE:
jardineb5d44e2003-12-23 08:09:43 +0000173#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000174 case VTYPE_IP6REACH_INTERNAL:
175 case VTYPE_IP6REACH_EXTERNAL:
176#endif /* HAVE_IPV6 */
hassof7c43dc2004-09-26 16:24:14 +0000177 prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ);
hassof390d2c2004-09-10 20:48:21 +0000178 break;
179 default:
180 return "UNKNOWN";
181 }
182
hassof7c43dc2004-09-26 16:24:14 +0000183 return (char *) buff;
jardineb5d44e2003-12-23 08:09:43 +0000184}
jardineb5d44e2003-12-23 08:09:43 +0000185
hasso92365882005-01-18 13:53:33 +0000186static struct isis_vertex *
jardineb5d44e2003-12-23 08:09:43 +0000187isis_vertex_new (void *id, enum vertextype vtype)
188{
189 struct isis_vertex *vertex;
190
hasso3fdb2dd2005-09-28 18:45:54 +0000191 vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
hassof390d2c2004-09-10 20:48:21 +0000192 if (vertex == NULL)
193 {
194 zlog_err ("isis_vertex_new Out of memory!");
195 return NULL;
196 }
197
jardineb5d44e2003-12-23 08:09:43 +0000198 vertex->type = vtype;
hassof390d2c2004-09-10 20:48:21 +0000199 switch (vtype)
200 {
201 case VTYPE_ES:
202 case VTYPE_NONPSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000203 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000204 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
205 break;
206 case VTYPE_PSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000207 case VTYPE_PSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000208 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
209 break;
210 case VTYPE_IPREACH_INTERNAL:
211 case VTYPE_IPREACH_EXTERNAL:
hasso82a84282005-09-26 18:15:36 +0000212 case VTYPE_IPREACH_TE:
jardineb5d44e2003-12-23 08:09:43 +0000213#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000214 case VTYPE_IP6REACH_INTERNAL:
215 case VTYPE_IP6REACH_EXTERNAL:
216#endif /* HAVE_IPV6 */
217 memcpy (&vertex->N.prefix, (struct prefix *) id,
218 sizeof (struct prefix));
219 break;
220 default:
221 zlog_err ("WTF!");
222 }
jardineb5d44e2003-12-23 08:09:43 +0000223
224 vertex->Adj_N = list_new ();
Josh Bailey3f045a02012-03-24 08:35:20 -0700225 vertex->parents = list_new ();
226 vertex->children = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000227
jardineb5d44e2003-12-23 08:09:43 +0000228 return vertex;
229}
230
Josh Bailey3f045a02012-03-24 08:35:20 -0700231static void
232isis_vertex_del (struct isis_vertex *vertex)
233{
234 list_delete (vertex->Adj_N);
235 vertex->Adj_N = NULL;
236 list_delete (vertex->parents);
237 vertex->parents = NULL;
238 list_delete (vertex->children);
239 vertex->children = NULL;
240
241 memset(vertex, 0, sizeof(struct isis_vertex));
242 XFREE (MTYPE_ISIS_VERTEX, vertex);
243
244 return;
245}
246
247static void
248isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
249{
250 struct listnode *node, *nextnode;
251 if (!vertex)
252 return;
253 for (node = listhead (vertex->Adj_N); node; node = nextnode)
254 {
255 nextnode = listnextnode(node);
256 if (listgetdata(node) == adj)
257 list_delete_node(vertex->Adj_N, node);
258 }
259 return;
260}
261
262struct isis_spftree *
263isis_spftree_new (struct isis_area *area)
264{
265 struct isis_spftree *tree;
266
267 tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
268 if (tree == NULL)
269 {
270 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
271 return NULL;
272 }
273
274 tree->tents = list_new ();
275 tree->paths = list_new ();
276 tree->area = area;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700277 tree->last_run_timestamp = 0;
278 tree->last_run_duration = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -0700279 tree->runcount = 0;
280 tree->pending = 0;
281 return tree;
282}
283
284void
285isis_spftree_del (struct isis_spftree *spftree)
286{
287 THREAD_TIMER_OFF (spftree->t_spf);
288
289 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
290 list_delete (spftree->tents);
291 spftree->tents = NULL;
292
293 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
294 list_delete (spftree->paths);
295 spftree->paths = NULL;
296
297 XFREE (MTYPE_ISIS_SPFTREE, spftree);
298
299 return;
300}
301
302void
303isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
304{
305 struct listnode *node;
306 if (!adj)
307 return;
308 for (node = listhead (spftree->tents); node; node = listnextnode (node))
309 isis_vertex_adj_del (listgetdata (node), adj);
310 for (node = listhead (spftree->paths); node; node = listnextnode (node))
311 isis_vertex_adj_del (listgetdata (node), adj);
312 return;
313}
314
315void
316spftree_area_init (struct isis_area *area)
317{
318 if (area->is_type & IS_LEVEL_1)
319 {
320 if (area->spftree[0] == NULL)
321 area->spftree[0] = isis_spftree_new (area);
322#ifdef HAVE_IPV6
323 if (area->spftree6[0] == NULL)
324 area->spftree6[0] = isis_spftree_new (area);
325#endif
326 }
327
328 if (area->is_type & IS_LEVEL_2)
329 {
330 if (area->spftree[1] == NULL)
331 area->spftree[1] = isis_spftree_new (area);
332#ifdef HAVE_IPV6
333 if (area->spftree6[1] == NULL)
334 area->spftree6[1] = isis_spftree_new (area);
335#endif
336 }
337
338 return;
339}
340
341void
342spftree_area_del (struct isis_area *area)
343{
344 if (area->is_type & IS_LEVEL_1)
345 {
346 if (area->spftree[0] != NULL)
347 {
348 isis_spftree_del (area->spftree[0]);
349 area->spftree[0] = NULL;
350 }
351#ifdef HAVE_IPV6
352 if (area->spftree6[0])
353 {
354 isis_spftree_del (area->spftree6[0]);
355 area->spftree6[0] = NULL;
356 }
357#endif
358 }
359
360 if (area->is_type & IS_LEVEL_2)
361 {
362 if (area->spftree[1] != NULL)
363 {
364 isis_spftree_del (area->spftree[1]);
365 area->spftree[1] = NULL;
366 }
367#ifdef HAVE_IPV6
368 if (area->spftree[1] != NULL)
369 {
370 isis_spftree_del (area->spftree6[1]);
371 area->spftree6[1] = NULL;
372 }
373#endif
374 }
375
376 return;
377}
378
379void
380spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
381{
382 if (area->is_type & IS_LEVEL_1)
383 {
384 if (area->spftree[0] != NULL)
385 isis_spftree_adj_del (area->spftree[0], adj);
386#ifdef HAVE_IPV6
387 if (area->spftree6[0] != NULL)
388 isis_spftree_adj_del (area->spftree6[0], adj);
389#endif
390 }
391
392 if (area->is_type & IS_LEVEL_2)
393 {
394 if (area->spftree[1] != NULL)
395 isis_spftree_adj_del (area->spftree[1], adj);
396#ifdef HAVE_IPV6
397 if (area->spftree6[1] != NULL)
398 isis_spftree_adj_del (area->spftree6[1], adj);
399#endif
400 }
401
402 return;
403}
404
405/*
406 * Find the system LSP: returns the LSP in our LSP database
407 * associated with the given system ID.
408 */
409static struct isis_lsp *
410isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
411{
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700412 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -0700413 u_char lspid[ISIS_SYS_ID_LEN + 2];
414
415 memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
416 LSP_PSEUDO_ID (lspid) = 0;
417 LSP_FRAGMENT (lspid) = 0;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700418 lsp = lsp_search (lspid, area->lspdb[level - 1]);
419 if (lsp && lsp->lsp_header->rem_lifetime != 0)
420 return lsp;
421 return NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -0700422}
423
jardineb5d44e2003-12-23 08:09:43 +0000424/*
425 * Add this IS to the root of SPT
426 */
Josh Bailey3f045a02012-03-24 08:35:20 -0700427static struct isis_vertex *
428isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
jardineb5d44e2003-12-23 08:09:43 +0000429{
430 struct isis_vertex *vertex;
431 struct isis_lsp *lsp;
jardineb5d44e2003-12-23 08:09:43 +0000432#ifdef EXTREME_DEBUG
433 u_char buff[BUFSIZ];
434#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000435
Josh Bailey3f045a02012-03-24 08:35:20 -0700436 lsp = isis_root_system_lsp (spftree->area, level, sysid);
jardineb5d44e2003-12-23 08:09:43 +0000437 if (lsp == NULL)
438 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
hassof390d2c2004-09-10 20:48:21 +0000439
Josh Bailey3f045a02012-03-24 08:35:20 -0700440 if (!spftree->area->oldmetric)
441 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
hasso82a84282005-09-26 18:15:36 +0000442 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700443 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
jardineb5d44e2003-12-23 08:09:43 +0000444
445 listnode_add (spftree->paths, vertex);
446
447#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000448 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
449 vtype2string (vertex->type), vid2string (vertex, buff),
450 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000451#endif /* EXTREME_DEBUG */
452
Josh Bailey3f045a02012-03-24 08:35:20 -0700453 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000454}
455
hasso92365882005-01-18 13:53:33 +0000456static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000457isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
jardineb5d44e2003-12-23 08:09:43 +0000458{
459 struct listnode *node;
460 struct isis_vertex *vertex;
461 struct prefix *p1, *p2;
462
paul1eb8ef22005-04-07 07:30:20 +0000463 for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
hassof390d2c2004-09-10 20:48:21 +0000464 {
hassof390d2c2004-09-10 20:48:21 +0000465 if (vertex->type != vtype)
466 continue;
467 switch (vtype)
468 {
469 case VTYPE_ES:
470 case VTYPE_NONPSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000471 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000472 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
473 return vertex;
474 break;
475 case VTYPE_PSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000476 case VTYPE_PSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000477 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
478 return vertex;
479 break;
480 case VTYPE_IPREACH_INTERNAL:
481 case VTYPE_IPREACH_EXTERNAL:
hasso82a84282005-09-26 18:15:36 +0000482 case VTYPE_IPREACH_TE:
jardineb5d44e2003-12-23 08:09:43 +0000483#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000484 case VTYPE_IP6REACH_INTERNAL:
485 case VTYPE_IP6REACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000486#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000487 p1 = (struct prefix *) id;
488 p2 = (struct prefix *) &vertex->N.id;
489 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
490 memcmp (&p1->u.prefix, &p2->u.prefix,
491 PSIZE (p1->prefixlen)) == 0)
492 return vertex;
493 break;
494 }
jardineb5d44e2003-12-23 08:09:43 +0000495 }
jardineb5d44e2003-12-23 08:09:43 +0000496
497 return NULL;
498}
499
jardineb5d44e2003-12-23 08:09:43 +0000500/*
501 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
502 */
hasso92365882005-01-18 13:53:33 +0000503static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000504isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
Josh Bailey3f045a02012-03-24 08:35:20 -0700505 void *id, uint32_t cost, int depth, int family,
506 struct isis_adjacency *adj, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000507{
508 struct isis_vertex *vertex, *v;
509 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -0700510 struct isis_adjacency *parent_adj;
hassof390d2c2004-09-10 20:48:21 +0000511#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000512 u_char buff[BUFSIZ];
513#endif
514
Josh Bailey3f045a02012-03-24 08:35:20 -0700515 assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
516 assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
jardineb5d44e2003-12-23 08:09:43 +0000517 vertex = isis_vertex_new (id, vtype);
518 vertex->d_N = cost;
519 vertex->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000520
Josh Bailey3f045a02012-03-24 08:35:20 -0700521 if (parent) {
522 listnode_add (vertex->parents, parent);
523 if (listnode_lookup (parent->children, vertex) == NULL)
524 listnode_add (parent->children, vertex);
525 }
526
527 if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
528 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
529 listnode_add (vertex->Adj_N, parent_adj);
530 } else if (adj) {
jardineb5d44e2003-12-23 08:09:43 +0000531 listnode_add (vertex->Adj_N, adj);
Josh Bailey3f045a02012-03-24 08:35:20 -0700532 }
533
hassof390d2c2004-09-10 20:48:21 +0000534#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700535 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
536 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +0000537 vtype2string (vertex->type), vid2string (vertex, buff),
Josh Bailey3f045a02012-03-24 08:35:20 -0700538 vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
jardineb5d44e2003-12-23 08:09:43 +0000539#endif /* EXTREME_DEBUG */
Josh Bailey3f045a02012-03-24 08:35:20 -0700540
hassof390d2c2004-09-10 20:48:21 +0000541 if (list_isempty (spftree->tents))
542 {
543 listnode_add (spftree->tents, vertex);
544 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000545 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700546
547 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
paul1eb8ef22005-04-07 07:30:20 +0000548 for (node = listhead (spftree->tents); node; node = listnextnode (node))
hassof390d2c2004-09-10 20:48:21 +0000549 {
paul1eb8ef22005-04-07 07:30:20 +0000550 v = listgetdata (node);
hassof390d2c2004-09-10 20:48:21 +0000551 if (v->d_N > vertex->d_N)
552 {
553 list_add_node_prev (spftree->tents, node, vertex);
554 break;
555 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700556 else if (v->d_N == vertex->d_N && v->type > vertex->type)
hassof390d2c2004-09-10 20:48:21 +0000557 {
558 /* Tie break, add according to type */
Josh Bailey3f045a02012-03-24 08:35:20 -0700559 list_add_node_prev (spftree->tents, node, vertex);
hassof390d2c2004-09-10 20:48:21 +0000560 break;
561 }
562 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700563
564 if (node == NULL)
565 listnode_add (spftree->tents, vertex);
566
jardineb5d44e2003-12-23 08:09:43 +0000567 return vertex;
568}
569
Josh Bailey3f045a02012-03-24 08:35:20 -0700570static void
hassof390d2c2004-09-10 20:48:21 +0000571isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
Josh Bailey3f045a02012-03-24 08:35:20 -0700572 void *id, struct isis_adjacency *adj, uint32_t cost,
573 int family, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000574{
575 struct isis_vertex *vertex;
jardineb5d44e2003-12-23 08:09:43 +0000576
hassof390d2c2004-09-10 20:48:21 +0000577 vertex = isis_find_vertex (spftree->tents, id, vtype);
578
579 if (vertex)
580 {
581 /* C.2.5 c) */
582 if (vertex->d_N == cost)
583 {
584 if (adj)
585 listnode_add (vertex->Adj_N, adj);
586 /* d) */
587 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
588 remove_excess_adjs (vertex->Adj_N);
Josh Bailey3f045a02012-03-24 08:35:20 -0700589 if (parent && (listnode_lookup (vertex->parents, parent) == NULL))
590 listnode_add (vertex->parents, parent);
591 if (parent && (listnode_lookup (parent->children, vertex) == NULL))
592 listnode_add (parent->children, vertex);
593 return;
hassof390d2c2004-09-10 20:48:21 +0000594 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700595 else if (vertex->d_N < cost)
hassof390d2c2004-09-10 20:48:21 +0000596 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700597 /* e) do nothing */
598 return;
hassof390d2c2004-09-10 20:48:21 +0000599 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700600 else { /* vertex->d_N > cost */
601 /* f) */
602 struct listnode *pnode, *pnextnode;
603 struct isis_vertex *pvertex;
604 listnode_delete (spftree->tents, vertex);
605 assert (listcount (vertex->children) == 0);
606 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
607 listnode_delete(pvertex->children, vertex);
608 isis_vertex_del (vertex);
609 }
hassof390d2c2004-09-10 20:48:21 +0000610 }
611
Josh Bailey3f045a02012-03-24 08:35:20 -0700612 isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
613 return;
jardineb5d44e2003-12-23 08:09:43 +0000614}
615
hasso92365882005-01-18 13:53:33 +0000616static void
hassof390d2c2004-09-10 20:48:21 +0000617process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
Josh Bailey3f045a02012-03-24 08:35:20 -0700618 uint32_t dist, uint16_t depth, int family,
619 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000620{
621 struct isis_vertex *vertex;
622#ifdef EXTREME_DEBUG
623 u_char buff[255];
624#endif
625
Josh Bailey3f045a02012-03-24 08:35:20 -0700626 assert (spftree && parent);
627
628 /* RFC3787 section 5.1 */
629 if (spftree->area->newmetric == 1)
630 {
631 if (dist > MAX_WIDE_PATH_METRIC)
632 return;
633 }
jardineb5d44e2003-12-23 08:09:43 +0000634 /* C.2.6 b) */
Josh Bailey3f045a02012-03-24 08:35:20 -0700635 else if (spftree->area->oldmetric == 1)
636 {
637 if (dist > MAX_NARROW_PATH_METRIC)
638 return;
639 }
640
jardineb5d44e2003-12-23 08:09:43 +0000641 /* c) */
642 vertex = isis_find_vertex (spftree->paths, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000643 if (vertex)
644 {
jardineb5d44e2003-12-23 08:09:43 +0000645#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700646 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
647 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +0000648 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000649#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000650 assert (dist >= vertex->d_N);
651 return;
652 }
jardineb5d44e2003-12-23 08:09:43 +0000653
654 vertex = isis_find_vertex (spftree->tents, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000655 /* d) */
656 if (vertex)
657 {
658 /* 1) */
jardineb5d44e2003-12-23 08:09:43 +0000659#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700660 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
661 print_sys_hostname (vertex->N.id),
662 vtype2string (vtype), vid2string (vertex, buff), dist,
663 (parent ? print_sys_hostname (parent->N.id) : "null"),
664 (parent ? listcount (parent->Adj_N) : 0));
jardineb5d44e2003-12-23 08:09:43 +0000665#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000666 if (vertex->d_N == dist)
667 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700668 struct listnode *node;
669 struct isis_adjacency *parent_adj;
670 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
671 if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL)
672 listnode_add (vertex->Adj_N, parent_adj);
hassof390d2c2004-09-10 20:48:21 +0000673 /* 2) */
674 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
675 remove_excess_adjs (vertex->Adj_N);
Josh Bailey3f045a02012-03-24 08:35:20 -0700676 if (listnode_lookup (vertex->parents, parent) == NULL)
677 listnode_add (vertex->parents, parent);
678 if (listnode_lookup (parent->children, vertex) == NULL)
679 listnode_add (parent->children, vertex);
hassof390d2c2004-09-10 20:48:21 +0000680 /* 3) */
681 return;
682 }
683 else if (vertex->d_N < dist)
684 {
685 return;
686 /* 4) */
687 }
688 else
689 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700690 struct listnode *pnode, *pnextnode;
691 struct isis_vertex *pvertex;
hassof390d2c2004-09-10 20:48:21 +0000692 listnode_delete (spftree->tents, vertex);
Josh Bailey3f045a02012-03-24 08:35:20 -0700693 assert (listcount (vertex->children) == 0);
694 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
695 listnode_delete(pvertex->children, vertex);
696 isis_vertex_del (vertex);
hassof390d2c2004-09-10 20:48:21 +0000697 }
jardineb5d44e2003-12-23 08:09:43 +0000698 }
hassof390d2c2004-09-10 20:48:21 +0000699
Josh Bailey3f045a02012-03-24 08:35:20 -0700700#ifdef EXTREME_DEBUG
701 zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
702 print_sys_hostname(id), vtype2string (vtype), dist,
703 (parent ? print_sys_hostname (parent->N.id) : "null"));
704#endif /* EXTREME_DEBUG */
705
706 isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
jardineb5d44e2003-12-23 08:09:43 +0000707 return;
708}
709
710/*
711 * C.2.6 Step 1
712 */
hasso92365882005-01-18 13:53:33 +0000713static int
hassof390d2c2004-09-10 20:48:21 +0000714isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -0700715 uint32_t cost, uint16_t depth, int family,
716 u_char *root_sysid, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000717{
718 struct listnode *node, *fragnode = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -0700719 uint32_t dist;
jardineb5d44e2003-12-23 08:09:43 +0000720 struct is_neigh *is_neigh;
hasso82a84282005-09-26 18:15:36 +0000721 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +0000722 struct ipv4_reachability *ipreach;
hasso82a84282005-09-26 18:15:36 +0000723 struct te_ipv4_reachability *te_ipv4_reach;
jardineb5d44e2003-12-23 08:09:43 +0000724 enum vertextype vtype;
725 struct prefix prefix;
726#ifdef HAVE_IPV6
727 struct ipv6_reachability *ip6reach;
728#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -0700729 static const u_char null_sysid[ISIS_SYS_ID_LEN];
hassof390d2c2004-09-10 20:48:21 +0000730
Josh Bailey3f045a02012-03-24 08:35:20 -0700731 if (!speaks (lsp->tlv_data.nlpids, family))
jardineb5d44e2003-12-23 08:09:43 +0000732 return ISIS_OK;
733
hassof390d2c2004-09-10 20:48:21 +0000734lspfragloop:
735 if (lsp->lsp_header->seq_num == 0)
736 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700737 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
hassof390d2c2004-09-10 20:48:21 +0000738 return ISIS_WARNING;
739 }
jardineb5d44e2003-12-23 08:09:43 +0000740
Josh Bailey3f045a02012-03-24 08:35:20 -0700741#ifdef EXTREME_DEBUG
742 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
743#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000744
Josh Bailey3f045a02012-03-24 08:35:20 -0700745 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
746 {
747 if (lsp->tlv_data.is_neighs)
748 {
749 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
750 {
751 /* C.2.6 a) */
752 /* Two way connectivity */
753 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
754 continue;
755 if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
756 continue;
757 dist = cost + is_neigh->metrics.metric_default;
758 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
759 : VTYPE_NONPSEUDO_IS;
760 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
761 depth + 1, family, parent);
762 }
hassof390d2c2004-09-10 20:48:21 +0000763 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700764 if (lsp->tlv_data.te_is_neighs)
765 {
766 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
767 te_is_neigh))
768 {
769 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
770 continue;
771 if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
772 continue;
773 dist = cost + GET_TE_METRIC(te_is_neigh);
774 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
775 : VTYPE_NONPSEUDO_TE_IS;
776 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
777 depth + 1, family, parent);
778 }
779 }
780 }
781
782 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
783 {
784 prefix.family = AF_INET;
785 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
786 {
787 dist = cost + ipreach->metrics.metric_default;
788 vtype = VTYPE_IPREACH_INTERNAL;
789 prefix.u.prefix4 = ipreach->prefix;
790 prefix.prefixlen = ip_masklen (ipreach->mask);
791 apply_mask (&prefix);
792 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
793 family, parent);
794 }
795 }
796 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
797 {
798 prefix.family = AF_INET;
799 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
800 {
801 dist = cost + ipreach->metrics.metric_default;
802 vtype = VTYPE_IPREACH_EXTERNAL;
803 prefix.u.prefix4 = ipreach->prefix;
804 prefix.prefixlen = ip_masklen (ipreach->mask);
805 apply_mask (&prefix);
806 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
807 family, parent);
808 }
809 }
810 if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
811 {
812 prefix.family = AF_INET;
813 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
814 node, te_ipv4_reach))
815 {
816 dist = cost + ntohl (te_ipv4_reach->te_metric);
817 vtype = VTYPE_IPREACH_TE;
818 prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
819 te_ipv4_reach->control);
820 prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
821 apply_mask (&prefix);
822 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
823 family, parent);
824 }
825 }
826#ifdef HAVE_IPV6
827 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
828 {
829 prefix.family = AF_INET6;
830 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
831 {
832 dist = cost + ip6reach->metric;
833 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
834 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
835 prefix.prefixlen = ip6reach->prefix_len;
836 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
837 PSIZE (ip6reach->prefix_len));
838 apply_mask (&prefix);
839 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
840 family, parent);
841 }
842 }
843#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000844
jardineb5d44e2003-12-23 08:09:43 +0000845 if (fragnode == NULL)
846 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000847 else
paul1eb8ef22005-04-07 07:30:20 +0000848 fragnode = listnextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000849
hassof390d2c2004-09-10 20:48:21 +0000850 if (fragnode)
851 {
paul1eb8ef22005-04-07 07:30:20 +0000852 lsp = listgetdata (fragnode);
hassof390d2c2004-09-10 20:48:21 +0000853 goto lspfragloop;
854 }
855
jardineb5d44e2003-12-23 08:09:43 +0000856 return ISIS_OK;
857}
858
hasso92365882005-01-18 13:53:33 +0000859static int
hassof390d2c2004-09-10 20:48:21 +0000860isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
Josh Bailey3f045a02012-03-24 08:35:20 -0700861 struct isis_lsp *lsp, uint32_t cost,
862 uint16_t depth, int family,
863 u_char *root_sysid,
864 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000865{
hasso3fdb2dd2005-09-28 18:45:54 +0000866 struct listnode *node, *fragnode = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000867 struct is_neigh *is_neigh;
hasso82a84282005-09-26 18:15:36 +0000868 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +0000869 enum vertextype vtype;
Josh Bailey3f045a02012-03-24 08:35:20 -0700870 uint32_t dist;
hassof390d2c2004-09-10 20:48:21 +0000871
872pseudofragloop:
873
874 if (lsp->lsp_header->seq_num == 0)
875 {
876 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
877 " - do not process");
878 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000879 }
hassof390d2c2004-09-10 20:48:21 +0000880
Josh Bailey3f045a02012-03-24 08:35:20 -0700881#ifdef EXTREME_DEBUG
882 zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
883 print_sys_hostname(lsp->lsp_header->lsp_id));
884#endif /* EXTREME_DEBUG */
885
886 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
887
hasso82a84282005-09-26 18:15:36 +0000888 if (lsp->tlv_data.is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000889 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
hasso82a84282005-09-26 18:15:36 +0000890 {
hasso82a84282005-09-26 18:15:36 +0000891 /* Two way connectivity */
Josh Bailey3f045a02012-03-24 08:35:20 -0700892 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
hasso82a84282005-09-26 18:15:36 +0000893 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700894 dist = cost + is_neigh->metrics.metric_default;
895 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
896 : VTYPE_NONPSEUDO_IS;
897 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
898 depth + 1, family, parent);
hasso82a84282005-09-26 18:15:36 +0000899 }
900 if (lsp->tlv_data.te_is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000901 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
hasso82a84282005-09-26 18:15:36 +0000902 {
hasso82a84282005-09-26 18:15:36 +0000903 /* Two way connectivity */
Josh Bailey3f045a02012-03-24 08:35:20 -0700904 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
hasso82a84282005-09-26 18:15:36 +0000905 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700906 dist = cost + GET_TE_METRIC(te_is_neigh);
907 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
908 : VTYPE_NONPSEUDO_TE_IS;
909 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
910 depth + 1, family, parent);
hasso82a84282005-09-26 18:15:36 +0000911 }
hassof390d2c2004-09-10 20:48:21 +0000912
jardineb5d44e2003-12-23 08:09:43 +0000913 if (fragnode == NULL)
914 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000915 else
paul1eb8ef22005-04-07 07:30:20 +0000916 fragnode = listnextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000917
hassof390d2c2004-09-10 20:48:21 +0000918 if (fragnode)
919 {
paul1eb8ef22005-04-07 07:30:20 +0000920 lsp = listgetdata (fragnode);
hassof390d2c2004-09-10 20:48:21 +0000921 goto pseudofragloop;
922 }
jardineb5d44e2003-12-23 08:09:43 +0000923
jardineb5d44e2003-12-23 08:09:43 +0000924 return ISIS_OK;
925}
hassof390d2c2004-09-10 20:48:21 +0000926
hasso92365882005-01-18 13:53:33 +0000927static int
Josh Bailey3f045a02012-03-24 08:35:20 -0700928isis_spf_preload_tent (struct isis_spftree *spftree, int level,
929 int family, u_char *root_sysid,
930 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000931{
jardineb5d44e2003-12-23 08:09:43 +0000932 struct isis_circuit *circuit;
hasso3fdb2dd2005-09-28 18:45:54 +0000933 struct listnode *cnode, *anode, *ipnode;
jardineb5d44e2003-12-23 08:09:43 +0000934 struct isis_adjacency *adj;
935 struct isis_lsp *lsp;
936 struct list *adj_list;
937 struct list *adjdb;
938 struct prefix_ipv4 *ipv4;
939 struct prefix prefix;
940 int retval = ISIS_OK;
941 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -0700942 static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
jardineb5d44e2003-12-23 08:09:43 +0000943#ifdef HAVE_IPV6
944 struct prefix_ipv6 *ipv6;
945#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000946
Josh Bailey3f045a02012-03-24 08:35:20 -0700947 for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
hassof390d2c2004-09-10 20:48:21 +0000948 {
hassof390d2c2004-09-10 20:48:21 +0000949 if (circuit->state != C_STATE_UP)
jardineb5d44e2003-12-23 08:09:43 +0000950 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700951 if (!(circuit->is_type & level))
hassof390d2c2004-09-10 20:48:21 +0000952 continue;
953 if (family == AF_INET && !circuit->ip_router)
954 continue;
955#ifdef HAVE_IPV6
956 if (family == AF_INET6 && !circuit->ipv6_router)
957 continue;
958#endif /* HAVE_IPV6 */
959 /*
960 * Add IP(v6) addresses of this circuit
jardineb5d44e2003-12-23 08:09:43 +0000961 */
hassof390d2c2004-09-10 20:48:21 +0000962 if (family == AF_INET)
963 {
964 prefix.family = AF_INET;
hasso3fdb2dd2005-09-28 18:45:54 +0000965 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000966 {
hassof390d2c2004-09-10 20:48:21 +0000967 prefix.u.prefix4 = ipv4->prefix;
968 prefix.prefixlen = ipv4->prefixlen;
Josh Bailey3f045a02012-03-24 08:35:20 -0700969 apply_mask (&prefix);
hassof390d2c2004-09-10 20:48:21 +0000970 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
Josh Bailey3f045a02012-03-24 08:35:20 -0700971 NULL, 0, family, parent);
hassof390d2c2004-09-10 20:48:21 +0000972 }
973 }
974#ifdef HAVE_IPV6
975 if (family == AF_INET6)
976 {
977 prefix.family = AF_INET6;
hasso3fdb2dd2005-09-28 18:45:54 +0000978 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
hassof390d2c2004-09-10 20:48:21 +0000979 {
hassof390d2c2004-09-10 20:48:21 +0000980 prefix.prefixlen = ipv6->prefixlen;
981 prefix.u.prefix6 = ipv6->prefix;
Josh Bailey3f045a02012-03-24 08:35:20 -0700982 apply_mask (&prefix);
hassof390d2c2004-09-10 20:48:21 +0000983 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
Josh Bailey3f045a02012-03-24 08:35:20 -0700984 &prefix, NULL, 0, family, parent);
hassof390d2c2004-09-10 20:48:21 +0000985 }
986 }
987#endif /* HAVE_IPV6 */
988 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
989 {
990 /*
991 * Add the adjacencies
992 */
993 adj_list = list_new ();
994 adjdb = circuit->u.bc.adjdb[level - 1];
995 isis_adj_build_up_list (adjdb, adj_list);
996 if (listcount (adj_list) == 0)
997 {
998 list_delete (adj_list);
hassoc89c05d2005-09-04 21:36:36 +0000999 if (isis->debugs & DEBUG_SPF_EVENTS)
1000 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
1001 level, circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001002 continue;
1003 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001004 for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
hassof390d2c2004-09-10 20:48:21 +00001005 {
hassof390d2c2004-09-10 20:48:21 +00001006 if (!speaks (&adj->nlpids, family))
hassof390d2c2004-09-10 20:48:21 +00001007 continue;
hassof390d2c2004-09-10 20:48:21 +00001008 switch (adj->sys_type)
1009 {
1010 case ISIS_SYSTYPE_ES:
1011 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
Josh Bailey3f045a02012-03-24 08:35:20 -07001012 circuit->te_metric[level - 1],
1013 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001014 break;
1015 case ISIS_SYSTYPE_IS:
1016 case ISIS_SYSTYPE_L1_IS:
1017 case ISIS_SYSTYPE_L2_IS:
Josh Bailey3f045a02012-03-24 08:35:20 -07001018 isis_spf_add_local (spftree,
1019 spftree->area->oldmetric ?
1020 VTYPE_NONPSEUDO_IS :
1021 VTYPE_NONPSEUDO_TE_IS,
1022 adj->sysid, adj,
1023 circuit->te_metric[level - 1],
1024 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001025 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1026 LSP_PSEUDO_ID (lsp_id) = 0;
1027 LSP_FRAGMENT (lsp_id) = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001028 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001029 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
Josh Bailey3f045a02012-03-24 08:35:20 -07001030 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
1031 "L%d on %s (ID %u)",
1032 rawlspid_print (lsp_id), level,
1033 circuit->interface->name, circuit->circuit_id);
hassof390d2c2004-09-10 20:48:21 +00001034 break;
1035 case ISIS_SYSTYPE_UNKNOWN:
1036 default:
1037 zlog_warn ("isis_spf_preload_tent unknow adj type");
1038 }
hassof390d2c2004-09-10 20:48:21 +00001039 }
1040 list_delete (adj_list);
1041 /*
1042 * Add the pseudonode
1043 */
1044 if (level == 1)
1045 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1046 else
1047 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
Josh Bailey3f045a02012-03-24 08:35:20 -07001048 /* can happen during DR reboot */
1049 if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
1050 {
1051 if (isis->debugs & DEBUG_SPF_EVENTS)
1052 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
1053 level, circuit->interface->name, circuit->circuit_id);
1054 continue;
1055 }
hassof390d2c2004-09-10 20:48:21 +00001056 adj = isis_adj_lookup (lsp_id, adjdb);
1057 /* if no adj, we are the dis or error */
1058 if (!adj && !circuit->u.bc.is_dr[level - 1])
1059 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001060 zlog_warn ("ISIS-Spf: No adjacency found from root "
1061 "to L%d DR %s on %s (ID %d)",
1062 level, rawlspid_print (lsp_id),
1063 circuit->interface->name, circuit->circuit_id);
1064 continue;
hassof390d2c2004-09-10 20:48:21 +00001065 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001066 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001067 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
1068 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001069 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1070 "to L%d DR %s on %s (ID %d)",
1071 lsp, level, rawlspid_print (lsp_id),
1072 circuit->interface->name, circuit->circuit_id);
1073 continue;
hassof390d2c2004-09-10 20:48:21 +00001074 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001075 isis_spf_process_pseudo_lsp (spftree, lsp,
1076 circuit->te_metric[level - 1], 0,
1077 family, root_sysid, parent);
hassof390d2c2004-09-10 20:48:21 +00001078 }
1079 else if (circuit->circ_type == CIRCUIT_T_P2P)
1080 {
1081 adj = circuit->u.p2p.neighbor;
1082 if (!adj)
1083 continue;
1084 switch (adj->sys_type)
1085 {
1086 case ISIS_SYSTYPE_ES:
1087 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
Josh Bailey3f045a02012-03-24 08:35:20 -07001088 circuit->te_metric[level - 1], family,
1089 parent);
hassof390d2c2004-09-10 20:48:21 +00001090 break;
1091 case ISIS_SYSTYPE_IS:
1092 case ISIS_SYSTYPE_L1_IS:
1093 case ISIS_SYSTYPE_L2_IS:
1094 if (speaks (&adj->nlpids, family))
Josh Bailey3f045a02012-03-24 08:35:20 -07001095 isis_spf_add_local (spftree,
1096 spftree->area->oldmetric ?
1097 VTYPE_NONPSEUDO_IS :
1098 VTYPE_NONPSEUDO_TE_IS,
1099 adj->sysid,
hasso82a84282005-09-26 18:15:36 +00001100 adj, circuit->te_metric[level - 1],
Josh Bailey3f045a02012-03-24 08:35:20 -07001101 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001102 break;
1103 case ISIS_SYSTYPE_UNKNOWN:
1104 default:
Josh Bailey3f045a02012-03-24 08:35:20 -07001105 zlog_warn ("isis_spf_preload_tent unknown adj type");
hassof390d2c2004-09-10 20:48:21 +00001106 break;
1107 }
1108 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001109 else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
1110 {
1111 continue;
1112 }
jardineb5d44e2003-12-23 08:09:43 +00001113 else
hassof390d2c2004-09-10 20:48:21 +00001114 {
1115 zlog_warn ("isis_spf_preload_tent unsupported media");
1116 retval = ISIS_WARNING;
1117 }
jardineb5d44e2003-12-23 08:09:43 +00001118 }
jardineb5d44e2003-12-23 08:09:43 +00001119
1120 return retval;
1121}
1122
1123/*
1124 * The parent(s) for vertex is set when added to TENT list
1125 * now we just put the child pointer(s) in place
1126 */
hasso92365882005-01-18 13:53:33 +00001127static void
jardineb5d44e2003-12-23 08:09:43 +00001128add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
Josh Bailey3f045a02012-03-24 08:35:20 -07001129 int level)
jardineb5d44e2003-12-23 08:09:43 +00001130{
jardineb5d44e2003-12-23 08:09:43 +00001131 u_char buff[BUFSIZ];
Josh Bailey3f045a02012-03-24 08:35:20 -07001132
1133 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
1134 return;
jardineb5d44e2003-12-23 08:09:43 +00001135 listnode_add (spftree->paths, vertex);
1136
hassof390d2c2004-09-10 20:48:21 +00001137#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -07001138 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1139 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +00001140 vtype2string (vertex->type), vid2string (vertex, buff),
1141 vertex->depth, vertex->d_N);
hassof390d2c2004-09-10 20:48:21 +00001142#endif /* EXTREME_DEBUG */
Josh Bailey3f045a02012-03-24 08:35:20 -07001143
hassof390d2c2004-09-10 20:48:21 +00001144 if (vertex->type > VTYPE_ES)
1145 {
1146 if (listcount (vertex->Adj_N) > 0)
hassofac1f7c2005-09-26 18:26:26 +00001147 isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001148 vertex->depth, vertex->Adj_N, spftree->area, level);
hassof390d2c2004-09-10 20:48:21 +00001149 else if (isis->debugs & DEBUG_SPF_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -07001150 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1151 "%s depth %d dist %d", vid2string (vertex, buff),
1152 vertex->depth, vertex->d_N);
hassof390d2c2004-09-10 20:48:21 +00001153 }
1154
jardineb5d44e2003-12-23 08:09:43 +00001155 return;
1156}
1157
hasso92365882005-01-18 13:53:33 +00001158static void
jardineb5d44e2003-12-23 08:09:43 +00001159init_spt (struct isis_spftree *spftree)
1160{
hassof7c43dc2004-09-26 16:24:14 +00001161 spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +00001162 list_delete_all_node (spftree->tents);
1163 list_delete_all_node (spftree->paths);
1164 spftree->tents->del = spftree->paths->del = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001165 return;
1166}
1167
hasso92365882005-01-18 13:53:33 +00001168static int
Josh Bailey3f045a02012-03-24 08:35:20 -07001169isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
jardineb5d44e2003-12-23 08:09:43 +00001170{
1171 int retval = ISIS_OK;
1172 struct listnode *node;
1173 struct isis_vertex *vertex;
Josh Bailey3f045a02012-03-24 08:35:20 -07001174 struct isis_vertex *root_vertex;
hassof390d2c2004-09-10 20:48:21 +00001175 struct isis_spftree *spftree = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001176 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1177 struct isis_lsp *lsp;
hassofac1f7c2005-09-26 18:26:26 +00001178 struct route_table *table = NULL;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001179 struct timespec time_now;
1180 unsigned long long start_time, end_time;
1181
1182 /* Get time that can't roll backwards. */
1183 clock_gettime(CLOCK_MONOTONIC, &time_now);
1184 start_time = time_now.tv_sec;
1185 start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000);
hassof390d2c2004-09-10 20:48:21 +00001186
jardineb5d44e2003-12-23 08:09:43 +00001187 if (family == AF_INET)
1188 spftree = area->spftree[level - 1];
1189#ifdef HAVE_IPV6
1190 else if (family == AF_INET6)
1191 spftree = area->spftree6[level - 1];
1192#endif
jardineb5d44e2003-12-23 08:09:43 +00001193 assert (spftree);
Josh Bailey3f045a02012-03-24 08:35:20 -07001194 assert (sysid);
jardineb5d44e2003-12-23 08:09:43 +00001195
hassofac1f7c2005-09-26 18:26:26 +00001196 /* Make all routes in current route table inactive. */
1197 if (family == AF_INET)
1198 table = area->route_table[level - 1];
Paul Jakma41b36e92006-12-08 01:09:50 +00001199#ifdef HAVE_IPV6
hassofac1f7c2005-09-26 18:26:26 +00001200 else if (family == AF_INET6)
1201 table = area->route_table6[level - 1];
Paul Jakma41b36e92006-12-08 01:09:50 +00001202#endif
hassofac1f7c2005-09-26 18:26:26 +00001203
Josh Bailey3f045a02012-03-24 08:35:20 -07001204 isis_route_invalidate_table (area, table);
hassofac1f7c2005-09-26 18:26:26 +00001205
jardineb5d44e2003-12-23 08:09:43 +00001206 /*
1207 * C.2.5 Step 0
1208 */
1209 init_spt (spftree);
1210 /* a) */
Josh Bailey3f045a02012-03-24 08:35:20 -07001211 root_vertex = isis_spf_add_root (spftree, level, sysid);
jardineb5d44e2003-12-23 08:09:43 +00001212 /* b) */
Josh Bailey3f045a02012-03-24 08:35:20 -07001213 retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
1214 if (retval != ISIS_OK)
1215 {
1216 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
1217 goto out;
1218 }
hassof390d2c2004-09-10 20:48:21 +00001219
jardineb5d44e2003-12-23 08:09:43 +00001220 /*
1221 * C.2.7 Step 2
1222 */
hassof390d2c2004-09-10 20:48:21 +00001223 if (listcount (spftree->tents) == 0)
1224 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001225 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
hasso13fb40a2005-10-01 06:03:04 +00001226 goto out;
jardineb5d44e2003-12-23 08:09:43 +00001227 }
hassof390d2c2004-09-10 20:48:21 +00001228
1229 while (listcount (spftree->tents) > 0)
1230 {
1231 node = listhead (spftree->tents);
paul1eb8ef22005-04-07 07:30:20 +00001232 vertex = listgetdata (node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001233
1234#ifdef EXTREME_DEBUG
1235 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1236 print_sys_hostname (vertex->N.id),
1237 vtype2string (vertex->type), vertex->depth, vertex->d_N);
1238#endif /* EXTREME_DEBUG */
1239
1240 /* Remove from tent list and add to paths list */
hassof390d2c2004-09-10 20:48:21 +00001241 list_delete_node (spftree->tents, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001242 add_to_paths (spftree, vertex, level);
1243 switch (vertex->type)
1244 {
1245 case VTYPE_PSEUDO_IS:
1246 case VTYPE_NONPSEUDO_IS:
1247 case VTYPE_PSEUDO_TE_IS:
1248 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +00001249 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1250 LSP_FRAGMENT (lsp_id) = 0;
1251 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001252 if (lsp && lsp->lsp_header->rem_lifetime != 0)
hassof390d2c2004-09-10 20:48:21 +00001253 {
1254 if (LSP_PSEUDO_ID (lsp_id))
1255 {
1256 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001257 vertex->depth, family, sysid,
1258 vertex);
hassof390d2c2004-09-10 20:48:21 +00001259 }
1260 else
1261 {
1262 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001263 vertex->depth, family, sysid, vertex);
hassof390d2c2004-09-10 20:48:21 +00001264 }
1265 }
1266 else
1267 {
1268 zlog_warn ("ISIS-Spf: No LSP found for %s",
1269 rawlspid_print (lsp_id));
1270 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001271 break;
1272 default:;
hassof390d2c2004-09-10 20:48:21 +00001273 }
1274 }
1275
hasso13fb40a2005-10-01 06:03:04 +00001276out:
Josh Bailey3f045a02012-03-24 08:35:20 -07001277 isis_route_validate (area);
jardineb5d44e2003-12-23 08:09:43 +00001278 spftree->pending = 0;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001279 spftree->runcount++;
1280 spftree->last_run_timestamp = time (NULL);
1281 clock_gettime(CLOCK_MONOTONIC, &time_now);
1282 end_time = time_now.tv_sec;
1283 end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000);
1284 spftree->last_run_duration = end_time - start_time;
1285
hassof390d2c2004-09-10 20:48:21 +00001286
jardineb5d44e2003-12-23 08:09:43 +00001287 return retval;
1288}
1289
1290int
1291isis_run_spf_l1 (struct thread *thread)
1292{
1293 struct isis_area *area;
1294 int retval = ISIS_OK;
1295
hassof390d2c2004-09-10 20:48:21 +00001296 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001297 assert (area);
1298
hasso12a5cae2004-09-19 19:39:26 +00001299 area->spftree[0]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001300 area->spftree[0]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001301
hassof390d2c2004-09-10 20:48:21 +00001302 if (!(area->is_type & IS_LEVEL_1))
1303 {
1304 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001305 zlog_warn ("ISIS-SPF (%s) area does not share level",
1306 area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001307 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001308 }
jardineb5d44e2003-12-23 08:09:43 +00001309
hassof390d2c2004-09-10 20:48:21 +00001310 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001311 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001312
jardineb5d44e2003-12-23 08:09:43 +00001313 if (area->ip_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001314 retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001315
jardineb5d44e2003-12-23 08:09:43 +00001316 return retval;
1317}
1318
1319int
1320isis_run_spf_l2 (struct thread *thread)
1321{
1322 struct isis_area *area;
1323 int retval = ISIS_OK;
1324
hassof390d2c2004-09-10 20:48:21 +00001325 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001326 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001327
hasso12a5cae2004-09-19 19:39:26 +00001328 area->spftree[1]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001329 area->spftree[1]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001330
hassof390d2c2004-09-10 20:48:21 +00001331 if (!(area->is_type & IS_LEVEL_2))
1332 {
1333 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001334 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001335 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001336 }
hassof390d2c2004-09-10 20:48:21 +00001337
1338 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001339 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
jardineb5d44e2003-12-23 08:09:43 +00001340
1341 if (area->ip_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001342 retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
jardineb5d44e2003-12-23 08:09:43 +00001343
1344 return retval;
1345}
1346
hassof390d2c2004-09-10 20:48:21 +00001347int
jardineb5d44e2003-12-23 08:09:43 +00001348isis_spf_schedule (struct isis_area *area, int level)
1349{
jardineb5d44e2003-12-23 08:09:43 +00001350 struct isis_spftree *spftree = area->spftree[level - 1];
Josh Bailey3f045a02012-03-24 08:35:20 -07001351 time_t now = time (NULL);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001352 int diff = now - spftree->last_run_timestamp;
Josh Bailey3f045a02012-03-24 08:35:20 -07001353
1354 assert (diff >= 0);
1355 assert (area->is_type & level);
1356
1357 if (isis->debugs & DEBUG_SPF_EVENTS)
1358 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1359 area->area_tag, level, diff);
jardineb5d44e2003-12-23 08:09:43 +00001360
1361 if (spftree->pending)
Josh Bailey3f045a02012-03-24 08:35:20 -07001362 return ISIS_OK;
hasso12a5cae2004-09-19 19:39:26 +00001363
1364 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001365
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001366 /* wait configured min_spf_interval before doing the SPF */
1367 if (diff >= area->min_spf_interval[level-1])
Josh Bailey3f045a02012-03-24 08:35:20 -07001368 return isis_run_spf (area, level, AF_INET, isis->sysid);
jardineb5d44e2003-12-23 08:09:43 +00001369
Josh Bailey3f045a02012-03-24 08:35:20 -07001370 if (level == 1)
1371 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001372 area->min_spf_interval[0] - diff);
hassof390d2c2004-09-10 20:48:21 +00001373 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001374 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001375 area->min_spf_interval[1] - diff);
jardineb5d44e2003-12-23 08:09:43 +00001376
Josh Bailey3f045a02012-03-24 08:35:20 -07001377 if (isis->debugs & DEBUG_SPF_EVENTS)
1378 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001379 area->area_tag, level, area->min_spf_interval[level-1] - diff);
Josh Bailey3f045a02012-03-24 08:35:20 -07001380
1381 spftree->pending = 1;
1382
1383 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001384}
1385
1386#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +00001387static int
hasso12a5cae2004-09-19 19:39:26 +00001388isis_run_spf6_l1 (struct thread *thread)
1389{
1390 struct isis_area *area;
1391 int retval = ISIS_OK;
1392
1393 area = THREAD_ARG (thread);
1394 assert (area);
1395
1396 area->spftree6[0]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001397 area->spftree6[0]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001398
1399 if (!(area->is_type & IS_LEVEL_1))
1400 {
1401 if (isis->debugs & DEBUG_SPF_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -07001402 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001403 return ISIS_WARNING;
1404 }
1405
1406 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001407 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001408
1409 if (area->ipv6_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001410 retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001411
1412 return retval;
1413}
1414
hasso92365882005-01-18 13:53:33 +00001415static int
hasso12a5cae2004-09-19 19:39:26 +00001416isis_run_spf6_l2 (struct thread *thread)
1417{
1418 struct isis_area *area;
1419 int retval = ISIS_OK;
1420
1421 area = THREAD_ARG (thread);
1422 assert (area);
1423
1424 area->spftree6[1]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001425 area->spftree6[1]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001426
1427 if (!(area->is_type & IS_LEVEL_2))
1428 {
1429 if (isis->debugs & DEBUG_SPF_EVENTS)
1430 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1431 return ISIS_WARNING;
1432 }
1433
1434 if (isis->debugs & DEBUG_SPF_EVENTS)
hassofac1f7c2005-09-26 18:26:26 +00001435 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001436
1437 if (area->ipv6_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001438 retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001439
1440 return retval;
1441}
1442
1443int
jardineb5d44e2003-12-23 08:09:43 +00001444isis_spf_schedule6 (struct isis_area *area, int level)
1445{
1446 int retval = ISIS_OK;
1447 struct isis_spftree *spftree = area->spftree6[level - 1];
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001448 time_t now = time (NULL);
1449 time_t diff = now - spftree->last_run_timestamp;
1450
1451 assert (diff >= 0);
1452 assert (area->is_type & level);
1453
1454 if (isis->debugs & DEBUG_SPF_EVENTS)
1455 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1456 area->area_tag, level, diff);
jardineb5d44e2003-12-23 08:09:43 +00001457
1458 if (spftree->pending)
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001459 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001460
hasso12a5cae2004-09-19 19:39:26 +00001461 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001462
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001463 /* wait configured min_spf_interval before doing the SPF */
1464 if (diff >= area->min_spf_interval[level-1])
1465 return isis_run_spf (area, level, AF_INET6, isis->sysid);
Josh Bailey3f045a02012-03-24 08:35:20 -07001466
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001467 if (level == 1)
1468 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1469 area->min_spf_interval[0] - diff);
hassof390d2c2004-09-10 20:48:21 +00001470 else
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001471 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1472 area->min_spf_interval[1] - diff);
1473
1474 if (isis->debugs & DEBUG_SPF_EVENTS)
1475 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
1476 area->area_tag, level, area->min_spf_interval[level-1] - diff);
1477
1478 spftree->pending = 1;
jardineb5d44e2003-12-23 08:09:43 +00001479
1480 return retval;
1481}
jardineb5d44e2003-12-23 08:09:43 +00001482#endif
1483
hasso92365882005-01-18 13:53:33 +00001484static void
Josh Bailey3f045a02012-03-24 08:35:20 -07001485isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
jardineb5d44e2003-12-23 08:09:43 +00001486{
paul1eb8ef22005-04-07 07:30:20 +00001487 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -07001488 struct listnode *anode;
jardineb5d44e2003-12-23 08:09:43 +00001489 struct isis_vertex *vertex;
jardineb5d44e2003-12-23 08:09:43 +00001490 struct isis_adjacency *adj;
jardineb5d44e2003-12-23 08:09:43 +00001491 u_char buff[255];
jardineb5d44e2003-12-23 08:09:43 +00001492
Josh Bailey3f045a02012-03-24 08:35:20 -07001493 vty_out (vty, "Vertex Type Metric "
1494 "Next-Hop Interface Parent%s", VTY_NEWLINE);
paul1eb8ef22005-04-07 07:30:20 +00001495
Josh Bailey3f045a02012-03-24 08:35:20 -07001496 for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) {
1497 if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
1498 vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid),
1499 "", "");
1500 vty_out (vty, "%-30s", "");
1501 } else {
1502 int rows = 0;
1503 vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff),
1504 vtype2string (vertex->type), vertex->d_N);
1505 for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) {
1506 if (adj) {
1507 if (rows) {
1508 vty_out (vty, "%s", VTY_NEWLINE);
1509 vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
hassof390d2c2004-09-10 20:48:21 +00001510 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001511 vty_out (vty, "%-20s %-9s ",
1512 print_sys_hostname (adj->sysid),
1513 adj->circuit->interface->name);
1514 ++rows;
1515 }
hassof390d2c2004-09-10 20:48:21 +00001516 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001517 if (rows == 0)
1518 vty_out (vty, "%-30s ", "");
1519 }
1520
1521 /* Print list of parents for the ECMP DAG */
1522 if (listcount (vertex->parents) > 0) {
1523 struct listnode *pnode;
1524 struct isis_vertex *pvertex;
1525 int rows = 0;
1526 for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
1527 if (rows) {
1528 vty_out (vty, "%s", VTY_NEWLINE);
1529 vty_out (vty, "%-72s", "");
1530 }
1531 vty_out (vty, "%s(%d)",
1532 vid2string (pvertex, buff), pvertex->type);
1533 ++rows;
1534 }
1535 } else {
1536 vty_out (vty, " NULL ");
1537 }
1538
jardineb5d44e2003-12-23 08:09:43 +00001539#if 0
Josh Bailey3f045a02012-03-24 08:35:20 -07001540 if (listcount (vertex->children) > 0) {
1541 struct listnode *cnode;
1542 struct isis_vertex *cvertex;
1543 for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) {
1544 vty_out (vty, "%s", VTY_NEWLINE);
1545 vty_out (vty, "%-72s", "");
1546 vty_out (vty, "%s(%d) ",
1547 vid2string (cvertex, buff), cvertex->type);
1548 }
1549 }
jardineb5d44e2003-12-23 08:09:43 +00001550#endif
Josh Bailey3f045a02012-03-24 08:35:20 -07001551 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001552 }
jardineb5d44e2003-12-23 08:09:43 +00001553}
1554
1555DEFUN (show_isis_topology,
1556 show_isis_topology_cmd,
1557 "show isis topology",
1558 SHOW_STR
1559 "IS-IS information\n"
1560 "IS-IS paths to Intermediate Systems\n")
1561{
1562 struct listnode *node;
1563 struct isis_area *area;
1564 int level;
hassof390d2c2004-09-10 20:48:21 +00001565
jardineb5d44e2003-12-23 08:09:43 +00001566 if (!isis->area_list || isis->area_list->count == 0)
1567 return CMD_SUCCESS;
1568
paul1eb8ef22005-04-07 07:30:20 +00001569 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
hassof390d2c2004-09-10 20:48:21 +00001570 {
hassof390d2c2004-09-10 20:48:21 +00001571 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1572 VTY_NEWLINE);
1573
1574 for (level = 0; level < ISIS_LEVELS; level++)
1575 {
1576 if (area->ip_circuits > 0 && area->spftree[level]
1577 && area->spftree[level]->paths->count > 0)
1578 {
1579 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1580 level + 1, VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001581 isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
1582 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001583 }
jardineb5d44e2003-12-23 08:09:43 +00001584#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001585 if (area->ipv6_circuits > 0 && area->spftree6[level]
1586 && area->spftree6[level]->paths->count > 0)
1587 {
1588 vty_out (vty,
1589 "IS-IS paths to level-%d routers that speak IPv6%s",
1590 level + 1, VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001591 isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
1592 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001593 }
jardineb5d44e2003-12-23 08:09:43 +00001594#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001595 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001596
1597 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001598 }
jardineb5d44e2003-12-23 08:09:43 +00001599
1600 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001601}
jardineb5d44e2003-12-23 08:09:43 +00001602
1603DEFUN (show_isis_topology_l1,
1604 show_isis_topology_l1_cmd,
1605 "show isis topology level-1",
1606 SHOW_STR
1607 "IS-IS information\n"
1608 "IS-IS paths to Intermediate Systems\n"
1609 "Paths to all level-1 routers in the area\n")
1610{
1611 struct listnode *node;
1612 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001613
jardineb5d44e2003-12-23 08:09:43 +00001614 if (!isis->area_list || isis->area_list->count == 0)
1615 return CMD_SUCCESS;
1616
paul1eb8ef22005-04-07 07:30:20 +00001617 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
hassof390d2c2004-09-10 20:48:21 +00001618 {
hassof390d2c2004-09-10 20:48:21 +00001619 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1620 VTY_NEWLINE);
1621
1622 if (area->ip_circuits > 0 && area->spftree[0]
1623 && area->spftree[0]->paths->count > 0)
1624 {
1625 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1626 VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001627 isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
1628 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001629 }
jardineb5d44e2003-12-23 08:09:43 +00001630#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001631 if (area->ipv6_circuits > 0 && area->spftree6[0]
1632 && area->spftree6[0]->paths->count > 0)
1633 {
1634 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1635 VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001636 isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
1637 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001638 }
jardineb5d44e2003-12-23 08:09:43 +00001639#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001640 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001641 }
1642
jardineb5d44e2003-12-23 08:09:43 +00001643 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001644}
jardineb5d44e2003-12-23 08:09:43 +00001645
1646DEFUN (show_isis_topology_l2,
1647 show_isis_topology_l2_cmd,
1648 "show isis topology level-2",
1649 SHOW_STR
1650 "IS-IS information\n"
1651 "IS-IS paths to Intermediate Systems\n"
1652 "Paths to all level-2 routers in the domain\n")
1653{
1654 struct listnode *node;
1655 struct isis_area *area;
hassof390d2c2004-09-10 20:48:21 +00001656
jardineb5d44e2003-12-23 08:09:43 +00001657 if (!isis->area_list || isis->area_list->count == 0)
1658 return CMD_SUCCESS;
1659
paul1eb8ef22005-04-07 07:30:20 +00001660 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
hassof390d2c2004-09-10 20:48:21 +00001661 {
hassof390d2c2004-09-10 20:48:21 +00001662 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1663 VTY_NEWLINE);
1664
1665 if (area->ip_circuits > 0 && area->spftree[1]
1666 && area->spftree[1]->paths->count > 0)
1667 {
1668 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1669 VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001670 isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
1671 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001672 }
jardineb5d44e2003-12-23 08:09:43 +00001673#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001674 if (area->ipv6_circuits > 0 && area->spftree6[1]
1675 && area->spftree6[1]->paths->count > 0)
1676 {
1677 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1678 VTY_NEWLINE);
Josh Bailey3f045a02012-03-24 08:35:20 -07001679 isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
1680 vty_out (vty, "%s", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +00001681 }
jardineb5d44e2003-12-23 08:09:43 +00001682#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001683 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001684 }
1685
jardineb5d44e2003-12-23 08:09:43 +00001686 return CMD_SUCCESS;
hassof390d2c2004-09-10 20:48:21 +00001687}
jardineb5d44e2003-12-23 08:09:43 +00001688
1689void
1690isis_spf_cmds_init ()
1691{
1692 install_element (VIEW_NODE, &show_isis_topology_cmd);
1693 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1694 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1695
1696 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1697 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1698 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1699}