blob: 6b2456f9feb4fbc1d029d9ca84fb81a2bdc5cadf [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
jardineb5d44e2003-12-23 08:09:43 +0000193 vertex->type = vtype;
hassof390d2c2004-09-10 20:48:21 +0000194 switch (vtype)
195 {
196 case VTYPE_ES:
197 case VTYPE_NONPSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000198 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000199 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
200 break;
201 case VTYPE_PSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000202 case VTYPE_PSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000203 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
204 break;
205 case VTYPE_IPREACH_INTERNAL:
206 case VTYPE_IPREACH_EXTERNAL:
hasso82a84282005-09-26 18:15:36 +0000207 case VTYPE_IPREACH_TE:
jardineb5d44e2003-12-23 08:09:43 +0000208#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000209 case VTYPE_IP6REACH_INTERNAL:
210 case VTYPE_IP6REACH_EXTERNAL:
211#endif /* HAVE_IPV6 */
212 memcpy (&vertex->N.prefix, (struct prefix *) id,
213 sizeof (struct prefix));
214 break;
215 default:
216 zlog_err ("WTF!");
217 }
jardineb5d44e2003-12-23 08:09:43 +0000218
219 vertex->Adj_N = list_new ();
Josh Bailey3f045a02012-03-24 08:35:20 -0700220 vertex->parents = list_new ();
221 vertex->children = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000222
jardineb5d44e2003-12-23 08:09:43 +0000223 return vertex;
224}
225
Josh Bailey3f045a02012-03-24 08:35:20 -0700226static void
227isis_vertex_del (struct isis_vertex *vertex)
228{
229 list_delete (vertex->Adj_N);
230 vertex->Adj_N = NULL;
231 list_delete (vertex->parents);
232 vertex->parents = NULL;
233 list_delete (vertex->children);
234 vertex->children = NULL;
235
236 memset(vertex, 0, sizeof(struct isis_vertex));
237 XFREE (MTYPE_ISIS_VERTEX, vertex);
238
239 return;
240}
241
242static void
243isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
244{
245 struct listnode *node, *nextnode;
246 if (!vertex)
247 return;
248 for (node = listhead (vertex->Adj_N); node; node = nextnode)
249 {
250 nextnode = listnextnode(node);
251 if (listgetdata(node) == adj)
252 list_delete_node(vertex->Adj_N, node);
253 }
254 return;
255}
256
257struct isis_spftree *
258isis_spftree_new (struct isis_area *area)
259{
260 struct isis_spftree *tree;
261
262 tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
263 if (tree == NULL)
264 {
265 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
266 return NULL;
267 }
268
269 tree->tents = list_new ();
270 tree->paths = list_new ();
271 tree->area = area;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700272 tree->last_run_timestamp = 0;
273 tree->last_run_duration = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -0700274 tree->runcount = 0;
275 tree->pending = 0;
276 return tree;
277}
278
279void
280isis_spftree_del (struct isis_spftree *spftree)
281{
282 THREAD_TIMER_OFF (spftree->t_spf);
283
284 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
285 list_delete (spftree->tents);
286 spftree->tents = NULL;
287
288 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
289 list_delete (spftree->paths);
290 spftree->paths = NULL;
291
292 XFREE (MTYPE_ISIS_SPFTREE, spftree);
293
294 return;
295}
296
297void
298isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
299{
300 struct listnode *node;
301 if (!adj)
302 return;
303 for (node = listhead (spftree->tents); node; node = listnextnode (node))
304 isis_vertex_adj_del (listgetdata (node), adj);
305 for (node = listhead (spftree->paths); node; node = listnextnode (node))
306 isis_vertex_adj_del (listgetdata (node), adj);
307 return;
308}
309
310void
311spftree_area_init (struct isis_area *area)
312{
313 if (area->is_type & IS_LEVEL_1)
314 {
315 if (area->spftree[0] == NULL)
316 area->spftree[0] = isis_spftree_new (area);
317#ifdef HAVE_IPV6
318 if (area->spftree6[0] == NULL)
319 area->spftree6[0] = isis_spftree_new (area);
320#endif
321 }
322
323 if (area->is_type & IS_LEVEL_2)
324 {
325 if (area->spftree[1] == NULL)
326 area->spftree[1] = isis_spftree_new (area);
327#ifdef HAVE_IPV6
328 if (area->spftree6[1] == NULL)
329 area->spftree6[1] = isis_spftree_new (area);
330#endif
331 }
332
333 return;
334}
335
336void
337spftree_area_del (struct isis_area *area)
338{
339 if (area->is_type & IS_LEVEL_1)
340 {
341 if (area->spftree[0] != NULL)
342 {
343 isis_spftree_del (area->spftree[0]);
344 area->spftree[0] = NULL;
345 }
346#ifdef HAVE_IPV6
347 if (area->spftree6[0])
348 {
349 isis_spftree_del (area->spftree6[0]);
350 area->spftree6[0] = NULL;
351 }
352#endif
353 }
354
355 if (area->is_type & IS_LEVEL_2)
356 {
357 if (area->spftree[1] != NULL)
358 {
359 isis_spftree_del (area->spftree[1]);
360 area->spftree[1] = NULL;
361 }
362#ifdef HAVE_IPV6
David Lamparterde543de2012-11-27 01:10:27 +0000363 if (area->spftree6[1] != NULL)
Josh Bailey3f045a02012-03-24 08:35:20 -0700364 {
365 isis_spftree_del (area->spftree6[1]);
366 area->spftree6[1] = NULL;
367 }
368#endif
369 }
370
371 return;
372}
373
374void
375spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
376{
377 if (area->is_type & IS_LEVEL_1)
378 {
379 if (area->spftree[0] != NULL)
380 isis_spftree_adj_del (area->spftree[0], adj);
381#ifdef HAVE_IPV6
382 if (area->spftree6[0] != NULL)
383 isis_spftree_adj_del (area->spftree6[0], adj);
384#endif
385 }
386
387 if (area->is_type & IS_LEVEL_2)
388 {
389 if (area->spftree[1] != NULL)
390 isis_spftree_adj_del (area->spftree[1], adj);
391#ifdef HAVE_IPV6
392 if (area->spftree6[1] != NULL)
393 isis_spftree_adj_del (area->spftree6[1], adj);
394#endif
395 }
396
397 return;
398}
399
400/*
401 * Find the system LSP: returns the LSP in our LSP database
402 * associated with the given system ID.
403 */
404static struct isis_lsp *
405isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
406{
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700407 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -0700408 u_char lspid[ISIS_SYS_ID_LEN + 2];
409
410 memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
411 LSP_PSEUDO_ID (lspid) = 0;
412 LSP_FRAGMENT (lspid) = 0;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700413 lsp = lsp_search (lspid, area->lspdb[level - 1]);
414 if (lsp && lsp->lsp_header->rem_lifetime != 0)
415 return lsp;
416 return NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -0700417}
418
jardineb5d44e2003-12-23 08:09:43 +0000419/*
420 * Add this IS to the root of SPT
421 */
Josh Bailey3f045a02012-03-24 08:35:20 -0700422static struct isis_vertex *
423isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
jardineb5d44e2003-12-23 08:09:43 +0000424{
425 struct isis_vertex *vertex;
426 struct isis_lsp *lsp;
jardineb5d44e2003-12-23 08:09:43 +0000427#ifdef EXTREME_DEBUG
428 u_char buff[BUFSIZ];
429#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000430
Josh Bailey3f045a02012-03-24 08:35:20 -0700431 lsp = isis_root_system_lsp (spftree->area, level, sysid);
jardineb5d44e2003-12-23 08:09:43 +0000432 if (lsp == NULL)
433 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
hassof390d2c2004-09-10 20:48:21 +0000434
Josh Bailey3f045a02012-03-24 08:35:20 -0700435 if (!spftree->area->oldmetric)
436 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
hasso82a84282005-09-26 18:15:36 +0000437 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700438 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
jardineb5d44e2003-12-23 08:09:43 +0000439
440 listnode_add (spftree->paths, vertex);
441
442#ifdef EXTREME_DEBUG
hasso529d65b2004-12-24 00:14:50 +0000443 zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
444 vtype2string (vertex->type), vid2string (vertex, buff),
445 vertex->depth, vertex->d_N);
jardineb5d44e2003-12-23 08:09:43 +0000446#endif /* EXTREME_DEBUG */
447
Josh Bailey3f045a02012-03-24 08:35:20 -0700448 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000449}
450
hasso92365882005-01-18 13:53:33 +0000451static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000452isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
jardineb5d44e2003-12-23 08:09:43 +0000453{
454 struct listnode *node;
455 struct isis_vertex *vertex;
456 struct prefix *p1, *p2;
457
paul1eb8ef22005-04-07 07:30:20 +0000458 for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
hassof390d2c2004-09-10 20:48:21 +0000459 {
hassof390d2c2004-09-10 20:48:21 +0000460 if (vertex->type != vtype)
461 continue;
462 switch (vtype)
463 {
464 case VTYPE_ES:
465 case VTYPE_NONPSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000466 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000467 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
468 return vertex;
469 break;
470 case VTYPE_PSEUDO_IS:
hasso82a84282005-09-26 18:15:36 +0000471 case VTYPE_PSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +0000472 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
473 return vertex;
474 break;
475 case VTYPE_IPREACH_INTERNAL:
476 case VTYPE_IPREACH_EXTERNAL:
hasso82a84282005-09-26 18:15:36 +0000477 case VTYPE_IPREACH_TE:
jardineb5d44e2003-12-23 08:09:43 +0000478#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +0000479 case VTYPE_IP6REACH_INTERNAL:
480 case VTYPE_IP6REACH_EXTERNAL:
jardineb5d44e2003-12-23 08:09:43 +0000481#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000482 p1 = (struct prefix *) id;
483 p2 = (struct prefix *) &vertex->N.id;
484 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
485 memcmp (&p1->u.prefix, &p2->u.prefix,
486 PSIZE (p1->prefixlen)) == 0)
487 return vertex;
488 break;
489 }
jardineb5d44e2003-12-23 08:09:43 +0000490 }
jardineb5d44e2003-12-23 08:09:43 +0000491
492 return NULL;
493}
494
jardineb5d44e2003-12-23 08:09:43 +0000495/*
496 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
497 */
hasso92365882005-01-18 13:53:33 +0000498static struct isis_vertex *
hassof390d2c2004-09-10 20:48:21 +0000499isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
Josh Bailey3f045a02012-03-24 08:35:20 -0700500 void *id, uint32_t cost, int depth, int family,
501 struct isis_adjacency *adj, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000502{
503 struct isis_vertex *vertex, *v;
504 struct listnode *node;
Josh Bailey3f045a02012-03-24 08:35:20 -0700505 struct isis_adjacency *parent_adj;
hassof390d2c2004-09-10 20:48:21 +0000506#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +0000507 u_char buff[BUFSIZ];
508#endif
509
Josh Bailey3f045a02012-03-24 08:35:20 -0700510 assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
511 assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
jardineb5d44e2003-12-23 08:09:43 +0000512 vertex = isis_vertex_new (id, vtype);
513 vertex->d_N = cost;
514 vertex->depth = depth;
hassof390d2c2004-09-10 20:48:21 +0000515
Josh Bailey3f045a02012-03-24 08:35:20 -0700516 if (parent) {
517 listnode_add (vertex->parents, parent);
518 if (listnode_lookup (parent->children, vertex) == NULL)
519 listnode_add (parent->children, vertex);
520 }
521
522 if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
523 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
524 listnode_add (vertex->Adj_N, parent_adj);
525 } else if (adj) {
jardineb5d44e2003-12-23 08:09:43 +0000526 listnode_add (vertex->Adj_N, adj);
Josh Bailey3f045a02012-03-24 08:35:20 -0700527 }
528
hassof390d2c2004-09-10 20:48:21 +0000529#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700530 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
531 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +0000532 vtype2string (vertex->type), vid2string (vertex, buff),
Josh Bailey3f045a02012-03-24 08:35:20 -0700533 vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
jardineb5d44e2003-12-23 08:09:43 +0000534#endif /* EXTREME_DEBUG */
Josh Bailey3f045a02012-03-24 08:35:20 -0700535
hassof390d2c2004-09-10 20:48:21 +0000536 if (list_isempty (spftree->tents))
537 {
538 listnode_add (spftree->tents, vertex);
539 return vertex;
jardineb5d44e2003-12-23 08:09:43 +0000540 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700541
542 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
paul1eb8ef22005-04-07 07:30:20 +0000543 for (node = listhead (spftree->tents); node; node = listnextnode (node))
hassof390d2c2004-09-10 20:48:21 +0000544 {
paul1eb8ef22005-04-07 07:30:20 +0000545 v = listgetdata (node);
hassof390d2c2004-09-10 20:48:21 +0000546 if (v->d_N > vertex->d_N)
547 {
548 list_add_node_prev (spftree->tents, node, vertex);
549 break;
550 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700551 else if (v->d_N == vertex->d_N && v->type > vertex->type)
hassof390d2c2004-09-10 20:48:21 +0000552 {
553 /* Tie break, add according to type */
Josh Bailey3f045a02012-03-24 08:35:20 -0700554 list_add_node_prev (spftree->tents, node, vertex);
hassof390d2c2004-09-10 20:48:21 +0000555 break;
556 }
557 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700558
559 if (node == NULL)
560 listnode_add (spftree->tents, vertex);
561
jardineb5d44e2003-12-23 08:09:43 +0000562 return vertex;
563}
564
Josh Bailey3f045a02012-03-24 08:35:20 -0700565static void
hassof390d2c2004-09-10 20:48:21 +0000566isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
Josh Bailey3f045a02012-03-24 08:35:20 -0700567 void *id, struct isis_adjacency *adj, uint32_t cost,
568 int family, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000569{
570 struct isis_vertex *vertex;
jardineb5d44e2003-12-23 08:09:43 +0000571
hassof390d2c2004-09-10 20:48:21 +0000572 vertex = isis_find_vertex (spftree->tents, id, vtype);
573
574 if (vertex)
575 {
576 /* C.2.5 c) */
577 if (vertex->d_N == cost)
578 {
579 if (adj)
580 listnode_add (vertex->Adj_N, adj);
581 /* d) */
582 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
583 remove_excess_adjs (vertex->Adj_N);
Josh Bailey3f045a02012-03-24 08:35:20 -0700584 if (parent && (listnode_lookup (vertex->parents, parent) == NULL))
585 listnode_add (vertex->parents, parent);
586 if (parent && (listnode_lookup (parent->children, vertex) == NULL))
587 listnode_add (parent->children, vertex);
588 return;
hassof390d2c2004-09-10 20:48:21 +0000589 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700590 else if (vertex->d_N < cost)
hassof390d2c2004-09-10 20:48:21 +0000591 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700592 /* e) do nothing */
593 return;
hassof390d2c2004-09-10 20:48:21 +0000594 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700595 else { /* vertex->d_N > cost */
596 /* f) */
597 struct listnode *pnode, *pnextnode;
598 struct isis_vertex *pvertex;
599 listnode_delete (spftree->tents, vertex);
600 assert (listcount (vertex->children) == 0);
601 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
602 listnode_delete(pvertex->children, vertex);
603 isis_vertex_del (vertex);
604 }
hassof390d2c2004-09-10 20:48:21 +0000605 }
606
Josh Bailey3f045a02012-03-24 08:35:20 -0700607 isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
608 return;
jardineb5d44e2003-12-23 08:09:43 +0000609}
610
hasso92365882005-01-18 13:53:33 +0000611static void
hassof390d2c2004-09-10 20:48:21 +0000612process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
Josh Bailey3f045a02012-03-24 08:35:20 -0700613 uint32_t dist, uint16_t depth, int family,
614 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000615{
616 struct isis_vertex *vertex;
617#ifdef EXTREME_DEBUG
618 u_char buff[255];
619#endif
620
Josh Bailey3f045a02012-03-24 08:35:20 -0700621 assert (spftree && parent);
622
623 /* RFC3787 section 5.1 */
624 if (spftree->area->newmetric == 1)
625 {
626 if (dist > MAX_WIDE_PATH_METRIC)
627 return;
628 }
jardineb5d44e2003-12-23 08:09:43 +0000629 /* C.2.6 b) */
Josh Bailey3f045a02012-03-24 08:35:20 -0700630 else if (spftree->area->oldmetric == 1)
631 {
632 if (dist > MAX_NARROW_PATH_METRIC)
633 return;
634 }
635
jardineb5d44e2003-12-23 08:09:43 +0000636 /* c) */
637 vertex = isis_find_vertex (spftree->paths, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000638 if (vertex)
639 {
jardineb5d44e2003-12-23 08:09:43 +0000640#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700641 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
642 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +0000643 vtype2string (vtype), vid2string (vertex, buff), dist);
jardineb5d44e2003-12-23 08:09:43 +0000644#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000645 assert (dist >= vertex->d_N);
646 return;
647 }
jardineb5d44e2003-12-23 08:09:43 +0000648
649 vertex = isis_find_vertex (spftree->tents, id, vtype);
hassof390d2c2004-09-10 20:48:21 +0000650 /* d) */
651 if (vertex)
652 {
653 /* 1) */
jardineb5d44e2003-12-23 08:09:43 +0000654#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -0700655 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
656 print_sys_hostname (vertex->N.id),
657 vtype2string (vtype), vid2string (vertex, buff), dist,
658 (parent ? print_sys_hostname (parent->N.id) : "null"),
659 (parent ? listcount (parent->Adj_N) : 0));
jardineb5d44e2003-12-23 08:09:43 +0000660#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000661 if (vertex->d_N == dist)
662 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700663 struct listnode *node;
664 struct isis_adjacency *parent_adj;
665 for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
666 if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL)
667 listnode_add (vertex->Adj_N, parent_adj);
hassof390d2c2004-09-10 20:48:21 +0000668 /* 2) */
669 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
670 remove_excess_adjs (vertex->Adj_N);
Josh Bailey3f045a02012-03-24 08:35:20 -0700671 if (listnode_lookup (vertex->parents, parent) == NULL)
672 listnode_add (vertex->parents, parent);
673 if (listnode_lookup (parent->children, vertex) == NULL)
674 listnode_add (parent->children, vertex);
hassof390d2c2004-09-10 20:48:21 +0000675 /* 3) */
676 return;
677 }
678 else if (vertex->d_N < dist)
679 {
680 return;
681 /* 4) */
682 }
683 else
684 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700685 struct listnode *pnode, *pnextnode;
686 struct isis_vertex *pvertex;
hassof390d2c2004-09-10 20:48:21 +0000687 listnode_delete (spftree->tents, vertex);
Josh Bailey3f045a02012-03-24 08:35:20 -0700688 assert (listcount (vertex->children) == 0);
689 for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
690 listnode_delete(pvertex->children, vertex);
691 isis_vertex_del (vertex);
hassof390d2c2004-09-10 20:48:21 +0000692 }
jardineb5d44e2003-12-23 08:09:43 +0000693 }
hassof390d2c2004-09-10 20:48:21 +0000694
Josh Bailey3f045a02012-03-24 08:35:20 -0700695#ifdef EXTREME_DEBUG
696 zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
697 print_sys_hostname(id), vtype2string (vtype), dist,
698 (parent ? print_sys_hostname (parent->N.id) : "null"));
699#endif /* EXTREME_DEBUG */
700
701 isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
jardineb5d44e2003-12-23 08:09:43 +0000702 return;
703}
704
705/*
706 * C.2.6 Step 1
707 */
hasso92365882005-01-18 13:53:33 +0000708static int
hassof390d2c2004-09-10 20:48:21 +0000709isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -0700710 uint32_t cost, uint16_t depth, int family,
711 u_char *root_sysid, struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000712{
713 struct listnode *node, *fragnode = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -0700714 uint32_t dist;
jardineb5d44e2003-12-23 08:09:43 +0000715 struct is_neigh *is_neigh;
hasso82a84282005-09-26 18:15:36 +0000716 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +0000717 struct ipv4_reachability *ipreach;
hasso82a84282005-09-26 18:15:36 +0000718 struct te_ipv4_reachability *te_ipv4_reach;
jardineb5d44e2003-12-23 08:09:43 +0000719 enum vertextype vtype;
720 struct prefix prefix;
721#ifdef HAVE_IPV6
722 struct ipv6_reachability *ip6reach;
723#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -0700724 static const u_char null_sysid[ISIS_SYS_ID_LEN];
hassof390d2c2004-09-10 20:48:21 +0000725
Josh Bailey3f045a02012-03-24 08:35:20 -0700726 if (!speaks (lsp->tlv_data.nlpids, family))
jardineb5d44e2003-12-23 08:09:43 +0000727 return ISIS_OK;
728
hassof390d2c2004-09-10 20:48:21 +0000729lspfragloop:
730 if (lsp->lsp_header->seq_num == 0)
731 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700732 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
hassof390d2c2004-09-10 20:48:21 +0000733 return ISIS_WARNING;
734 }
jardineb5d44e2003-12-23 08:09:43 +0000735
Josh Bailey3f045a02012-03-24 08:35:20 -0700736#ifdef EXTREME_DEBUG
737 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
738#endif /* EXTREME_DEBUG */
hassof390d2c2004-09-10 20:48:21 +0000739
Josh Bailey3f045a02012-03-24 08:35:20 -0700740 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
741 {
742 if (lsp->tlv_data.is_neighs)
743 {
744 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
745 {
746 /* C.2.6 a) */
747 /* Two way connectivity */
748 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
749 continue;
750 if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
751 continue;
752 dist = cost + is_neigh->metrics.metric_default;
753 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
754 : VTYPE_NONPSEUDO_IS;
755 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
756 depth + 1, family, parent);
757 }
hassof390d2c2004-09-10 20:48:21 +0000758 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700759 if (lsp->tlv_data.te_is_neighs)
760 {
761 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
762 te_is_neigh))
763 {
764 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
765 continue;
766 if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
767 continue;
768 dist = cost + GET_TE_METRIC(te_is_neigh);
769 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
770 : VTYPE_NONPSEUDO_TE_IS;
771 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
772 depth + 1, family, parent);
773 }
774 }
775 }
776
777 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
778 {
779 prefix.family = AF_INET;
780 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
781 {
782 dist = cost + ipreach->metrics.metric_default;
783 vtype = VTYPE_IPREACH_INTERNAL;
784 prefix.u.prefix4 = ipreach->prefix;
785 prefix.prefixlen = ip_masklen (ipreach->mask);
786 apply_mask (&prefix);
787 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
788 family, parent);
789 }
790 }
791 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
792 {
793 prefix.family = AF_INET;
794 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
795 {
796 dist = cost + ipreach->metrics.metric_default;
797 vtype = VTYPE_IPREACH_EXTERNAL;
798 prefix.u.prefix4 = ipreach->prefix;
799 prefix.prefixlen = ip_masklen (ipreach->mask);
800 apply_mask (&prefix);
801 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
802 family, parent);
803 }
804 }
805 if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
806 {
807 prefix.family = AF_INET;
808 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
809 node, te_ipv4_reach))
810 {
David Lamparter948b6be2012-05-08 06:27:04 +0200811 assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN);
812
Josh Bailey3f045a02012-03-24 08:35:20 -0700813 dist = cost + ntohl (te_ipv4_reach->te_metric);
814 vtype = VTYPE_IPREACH_TE;
815 prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
816 te_ipv4_reach->control);
817 prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
818 apply_mask (&prefix);
819 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
820 family, parent);
821 }
822 }
823#ifdef HAVE_IPV6
824 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
825 {
826 prefix.family = AF_INET6;
827 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
828 {
David Lamparter948b6be2012-05-08 06:27:04 +0200829 assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN);
830
Nick Hilliarde1a555b2012-11-28 14:39:56 +0000831 dist = cost + ntohl(ip6reach->metric);
Josh Bailey3f045a02012-03-24 08:35:20 -0700832 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
833 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
834 prefix.prefixlen = ip6reach->prefix_len;
835 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
836 PSIZE (ip6reach->prefix_len));
837 apply_mask (&prefix);
838 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
839 family, parent);
840 }
841 }
842#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000843
jardineb5d44e2003-12-23 08:09:43 +0000844 if (fragnode == NULL)
845 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000846 else
paul1eb8ef22005-04-07 07:30:20 +0000847 fragnode = listnextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000848
hassof390d2c2004-09-10 20:48:21 +0000849 if (fragnode)
850 {
paul1eb8ef22005-04-07 07:30:20 +0000851 lsp = listgetdata (fragnode);
hassof390d2c2004-09-10 20:48:21 +0000852 goto lspfragloop;
853 }
854
jardineb5d44e2003-12-23 08:09:43 +0000855 return ISIS_OK;
856}
857
hasso92365882005-01-18 13:53:33 +0000858static int
hassof390d2c2004-09-10 20:48:21 +0000859isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
Josh Bailey3f045a02012-03-24 08:35:20 -0700860 struct isis_lsp *lsp, uint32_t cost,
861 uint16_t depth, int family,
862 u_char *root_sysid,
863 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000864{
hasso3fdb2dd2005-09-28 18:45:54 +0000865 struct listnode *node, *fragnode = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000866 struct is_neigh *is_neigh;
hasso82a84282005-09-26 18:15:36 +0000867 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +0000868 enum vertextype vtype;
Josh Bailey3f045a02012-03-24 08:35:20 -0700869 uint32_t dist;
hassof390d2c2004-09-10 20:48:21 +0000870
871pseudofragloop:
872
873 if (lsp->lsp_header->seq_num == 0)
874 {
875 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
876 " - do not process");
877 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +0000878 }
hassof390d2c2004-09-10 20:48:21 +0000879
Josh Bailey3f045a02012-03-24 08:35:20 -0700880#ifdef EXTREME_DEBUG
881 zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
882 print_sys_hostname(lsp->lsp_header->lsp_id));
883#endif /* EXTREME_DEBUG */
884
885 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
886
hasso82a84282005-09-26 18:15:36 +0000887 if (lsp->tlv_data.is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000888 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
hasso82a84282005-09-26 18:15:36 +0000889 {
hasso82a84282005-09-26 18:15:36 +0000890 /* Two way connectivity */
Josh Bailey3f045a02012-03-24 08:35:20 -0700891 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
hasso82a84282005-09-26 18:15:36 +0000892 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700893 dist = cost + is_neigh->metrics.metric_default;
894 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
895 : VTYPE_NONPSEUDO_IS;
896 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
897 depth + 1, family, parent);
hasso82a84282005-09-26 18:15:36 +0000898 }
899 if (lsp->tlv_data.te_is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000900 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
hasso82a84282005-09-26 18:15:36 +0000901 {
hasso82a84282005-09-26 18:15:36 +0000902 /* Two way connectivity */
Josh Bailey3f045a02012-03-24 08:35:20 -0700903 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
hasso82a84282005-09-26 18:15:36 +0000904 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700905 dist = cost + GET_TE_METRIC(te_is_neigh);
906 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
907 : VTYPE_NONPSEUDO_TE_IS;
908 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
909 depth + 1, family, parent);
hasso82a84282005-09-26 18:15:36 +0000910 }
hassof390d2c2004-09-10 20:48:21 +0000911
jardineb5d44e2003-12-23 08:09:43 +0000912 if (fragnode == NULL)
913 fragnode = listhead (lsp->lspu.frags);
hassof390d2c2004-09-10 20:48:21 +0000914 else
paul1eb8ef22005-04-07 07:30:20 +0000915 fragnode = listnextnode (fragnode);
jardineb5d44e2003-12-23 08:09:43 +0000916
hassof390d2c2004-09-10 20:48:21 +0000917 if (fragnode)
918 {
paul1eb8ef22005-04-07 07:30:20 +0000919 lsp = listgetdata (fragnode);
hassof390d2c2004-09-10 20:48:21 +0000920 goto pseudofragloop;
921 }
jardineb5d44e2003-12-23 08:09:43 +0000922
jardineb5d44e2003-12-23 08:09:43 +0000923 return ISIS_OK;
924}
hassof390d2c2004-09-10 20:48:21 +0000925
hasso92365882005-01-18 13:53:33 +0000926static int
Josh Bailey3f045a02012-03-24 08:35:20 -0700927isis_spf_preload_tent (struct isis_spftree *spftree, int level,
928 int family, u_char *root_sysid,
929 struct isis_vertex *parent)
jardineb5d44e2003-12-23 08:09:43 +0000930{
jardineb5d44e2003-12-23 08:09:43 +0000931 struct isis_circuit *circuit;
hasso3fdb2dd2005-09-28 18:45:54 +0000932 struct listnode *cnode, *anode, *ipnode;
jardineb5d44e2003-12-23 08:09:43 +0000933 struct isis_adjacency *adj;
934 struct isis_lsp *lsp;
935 struct list *adj_list;
936 struct list *adjdb;
937 struct prefix_ipv4 *ipv4;
938 struct prefix prefix;
939 int retval = ISIS_OK;
940 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -0700941 static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
jardineb5d44e2003-12-23 08:09:43 +0000942#ifdef HAVE_IPV6
943 struct prefix_ipv6 *ipv6;
944#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000945
Josh Bailey3f045a02012-03-24 08:35:20 -0700946 for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
hassof390d2c2004-09-10 20:48:21 +0000947 {
hassof390d2c2004-09-10 20:48:21 +0000948 if (circuit->state != C_STATE_UP)
jardineb5d44e2003-12-23 08:09:43 +0000949 continue;
Josh Bailey3f045a02012-03-24 08:35:20 -0700950 if (!(circuit->is_type & level))
hassof390d2c2004-09-10 20:48:21 +0000951 continue;
952 if (family == AF_INET && !circuit->ip_router)
953 continue;
954#ifdef HAVE_IPV6
955 if (family == AF_INET6 && !circuit->ipv6_router)
956 continue;
957#endif /* HAVE_IPV6 */
958 /*
959 * Add IP(v6) addresses of this circuit
jardineb5d44e2003-12-23 08:09:43 +0000960 */
hassof390d2c2004-09-10 20:48:21 +0000961 if (family == AF_INET)
962 {
963 prefix.family = AF_INET;
hasso3fdb2dd2005-09-28 18:45:54 +0000964 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassof390d2c2004-09-10 20:48:21 +0000965 {
hassof390d2c2004-09-10 20:48:21 +0000966 prefix.u.prefix4 = ipv4->prefix;
967 prefix.prefixlen = ipv4->prefixlen;
Josh Bailey3f045a02012-03-24 08:35:20 -0700968 apply_mask (&prefix);
hassof390d2c2004-09-10 20:48:21 +0000969 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
Josh Bailey3f045a02012-03-24 08:35:20 -0700970 NULL, 0, family, parent);
hassof390d2c2004-09-10 20:48:21 +0000971 }
972 }
973#ifdef HAVE_IPV6
974 if (family == AF_INET6)
975 {
976 prefix.family = AF_INET6;
hasso3fdb2dd2005-09-28 18:45:54 +0000977 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
hassof390d2c2004-09-10 20:48:21 +0000978 {
hassof390d2c2004-09-10 20:48:21 +0000979 prefix.prefixlen = ipv6->prefixlen;
980 prefix.u.prefix6 = ipv6->prefix;
Josh Bailey3f045a02012-03-24 08:35:20 -0700981 apply_mask (&prefix);
hassof390d2c2004-09-10 20:48:21 +0000982 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
Josh Bailey3f045a02012-03-24 08:35:20 -0700983 &prefix, NULL, 0, family, parent);
hassof390d2c2004-09-10 20:48:21 +0000984 }
985 }
986#endif /* HAVE_IPV6 */
987 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
988 {
989 /*
990 * Add the adjacencies
991 */
992 adj_list = list_new ();
993 adjdb = circuit->u.bc.adjdb[level - 1];
994 isis_adj_build_up_list (adjdb, adj_list);
995 if (listcount (adj_list) == 0)
996 {
997 list_delete (adj_list);
hassoc89c05d2005-09-04 21:36:36 +0000998 if (isis->debugs & DEBUG_SPF_EVENTS)
999 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
1000 level, circuit->interface->name);
hassof390d2c2004-09-10 20:48:21 +00001001 continue;
1002 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001003 for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
hassof390d2c2004-09-10 20:48:21 +00001004 {
hassof390d2c2004-09-10 20:48:21 +00001005 if (!speaks (&adj->nlpids, family))
hassof390d2c2004-09-10 20:48:21 +00001006 continue;
hassof390d2c2004-09-10 20:48:21 +00001007 switch (adj->sys_type)
1008 {
1009 case ISIS_SYSTYPE_ES:
1010 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
Josh Bailey3f045a02012-03-24 08:35:20 -07001011 circuit->te_metric[level - 1],
1012 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001013 break;
1014 case ISIS_SYSTYPE_IS:
1015 case ISIS_SYSTYPE_L1_IS:
1016 case ISIS_SYSTYPE_L2_IS:
Josh Bailey3f045a02012-03-24 08:35:20 -07001017 isis_spf_add_local (spftree,
1018 spftree->area->oldmetric ?
1019 VTYPE_NONPSEUDO_IS :
1020 VTYPE_NONPSEUDO_TE_IS,
1021 adj->sysid, adj,
1022 circuit->te_metric[level - 1],
1023 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001024 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1025 LSP_PSEUDO_ID (lsp_id) = 0;
1026 LSP_FRAGMENT (lsp_id) = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001027 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001028 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
Josh Bailey3f045a02012-03-24 08:35:20 -07001029 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
1030 "L%d on %s (ID %u)",
1031 rawlspid_print (lsp_id), level,
1032 circuit->interface->name, circuit->circuit_id);
hassof390d2c2004-09-10 20:48:21 +00001033 break;
1034 case ISIS_SYSTYPE_UNKNOWN:
1035 default:
1036 zlog_warn ("isis_spf_preload_tent unknow adj type");
1037 }
hassof390d2c2004-09-10 20:48:21 +00001038 }
1039 list_delete (adj_list);
1040 /*
1041 * Add the pseudonode
1042 */
1043 if (level == 1)
1044 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1045 else
1046 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
Josh Bailey3f045a02012-03-24 08:35:20 -07001047 /* can happen during DR reboot */
1048 if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
1049 {
1050 if (isis->debugs & DEBUG_SPF_EVENTS)
1051 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
1052 level, circuit->interface->name, circuit->circuit_id);
1053 continue;
1054 }
hassof390d2c2004-09-10 20:48:21 +00001055 adj = isis_adj_lookup (lsp_id, adjdb);
1056 /* if no adj, we are the dis or error */
1057 if (!adj && !circuit->u.bc.is_dr[level - 1])
1058 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001059 zlog_warn ("ISIS-Spf: No adjacency found from root "
1060 "to L%d DR %s on %s (ID %d)",
1061 level, rawlspid_print (lsp_id),
1062 circuit->interface->name, circuit->circuit_id);
1063 continue;
hassof390d2c2004-09-10 20:48:21 +00001064 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001065 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001066 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
1067 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001068 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1069 "to L%d DR %s on %s (ID %d)",
David Lampartereed3c482015-03-03 08:51:53 +01001070 (void *)lsp, level, rawlspid_print (lsp_id),
1071 circuit->interface->name, circuit->circuit_id);
Josh Bailey3f045a02012-03-24 08:35:20 -07001072 continue;
hassof390d2c2004-09-10 20:48:21 +00001073 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001074 isis_spf_process_pseudo_lsp (spftree, lsp,
1075 circuit->te_metric[level - 1], 0,
1076 family, root_sysid, parent);
hassof390d2c2004-09-10 20:48:21 +00001077 }
1078 else if (circuit->circ_type == CIRCUIT_T_P2P)
1079 {
1080 adj = circuit->u.p2p.neighbor;
1081 if (!adj)
1082 continue;
1083 switch (adj->sys_type)
1084 {
1085 case ISIS_SYSTYPE_ES:
1086 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
Josh Bailey3f045a02012-03-24 08:35:20 -07001087 circuit->te_metric[level - 1], family,
1088 parent);
hassof390d2c2004-09-10 20:48:21 +00001089 break;
1090 case ISIS_SYSTYPE_IS:
1091 case ISIS_SYSTYPE_L1_IS:
1092 case ISIS_SYSTYPE_L2_IS:
1093 if (speaks (&adj->nlpids, family))
Josh Bailey3f045a02012-03-24 08:35:20 -07001094 isis_spf_add_local (spftree,
1095 spftree->area->oldmetric ?
1096 VTYPE_NONPSEUDO_IS :
1097 VTYPE_NONPSEUDO_TE_IS,
1098 adj->sysid,
hasso82a84282005-09-26 18:15:36 +00001099 adj, circuit->te_metric[level - 1],
Josh Bailey3f045a02012-03-24 08:35:20 -07001100 family, parent);
hassof390d2c2004-09-10 20:48:21 +00001101 break;
1102 case ISIS_SYSTYPE_UNKNOWN:
1103 default:
Josh Bailey3f045a02012-03-24 08:35:20 -07001104 zlog_warn ("isis_spf_preload_tent unknown adj type");
hassof390d2c2004-09-10 20:48:21 +00001105 break;
1106 }
1107 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001108 else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
1109 {
1110 continue;
1111 }
jardineb5d44e2003-12-23 08:09:43 +00001112 else
hassof390d2c2004-09-10 20:48:21 +00001113 {
1114 zlog_warn ("isis_spf_preload_tent unsupported media");
1115 retval = ISIS_WARNING;
1116 }
jardineb5d44e2003-12-23 08:09:43 +00001117 }
jardineb5d44e2003-12-23 08:09:43 +00001118
1119 return retval;
1120}
1121
1122/*
1123 * The parent(s) for vertex is set when added to TENT list
1124 * now we just put the child pointer(s) in place
1125 */
hasso92365882005-01-18 13:53:33 +00001126static void
jardineb5d44e2003-12-23 08:09:43 +00001127add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
Josh Bailey3f045a02012-03-24 08:35:20 -07001128 int level)
jardineb5d44e2003-12-23 08:09:43 +00001129{
jardineb5d44e2003-12-23 08:09:43 +00001130 u_char buff[BUFSIZ];
Josh Bailey3f045a02012-03-24 08:35:20 -07001131
1132 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
1133 return;
jardineb5d44e2003-12-23 08:09:43 +00001134 listnode_add (spftree->paths, vertex);
1135
hassof390d2c2004-09-10 20:48:21 +00001136#ifdef EXTREME_DEBUG
Josh Bailey3f045a02012-03-24 08:35:20 -07001137 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1138 print_sys_hostname (vertex->N.id),
hasso529d65b2004-12-24 00:14:50 +00001139 vtype2string (vertex->type), vid2string (vertex, buff),
1140 vertex->depth, vertex->d_N);
hassof390d2c2004-09-10 20:48:21 +00001141#endif /* EXTREME_DEBUG */
Josh Bailey3f045a02012-03-24 08:35:20 -07001142
hassof390d2c2004-09-10 20:48:21 +00001143 if (vertex->type > VTYPE_ES)
1144 {
1145 if (listcount (vertex->Adj_N) > 0)
hassofac1f7c2005-09-26 18:26:26 +00001146 isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001147 vertex->depth, vertex->Adj_N, spftree->area, level);
hassof390d2c2004-09-10 20:48:21 +00001148 else if (isis->debugs & DEBUG_SPF_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -07001149 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1150 "%s depth %d dist %d", vid2string (vertex, buff),
1151 vertex->depth, vertex->d_N);
hassof390d2c2004-09-10 20:48:21 +00001152 }
1153
jardineb5d44e2003-12-23 08:09:43 +00001154 return;
1155}
1156
hasso92365882005-01-18 13:53:33 +00001157static void
jardineb5d44e2003-12-23 08:09:43 +00001158init_spt (struct isis_spftree *spftree)
1159{
hassof7c43dc2004-09-26 16:24:14 +00001160 spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
jardineb5d44e2003-12-23 08:09:43 +00001161 list_delete_all_node (spftree->tents);
1162 list_delete_all_node (spftree->paths);
1163 spftree->tents->del = spftree->paths->del = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001164 return;
1165}
1166
hasso92365882005-01-18 13:53:33 +00001167static int
Josh Bailey3f045a02012-03-24 08:35:20 -07001168isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
jardineb5d44e2003-12-23 08:09:43 +00001169{
1170 int retval = ISIS_OK;
1171 struct listnode *node;
1172 struct isis_vertex *vertex;
Josh Bailey3f045a02012-03-24 08:35:20 -07001173 struct isis_vertex *root_vertex;
hassof390d2c2004-09-10 20:48:21 +00001174 struct isis_spftree *spftree = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001175 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1176 struct isis_lsp *lsp;
hassofac1f7c2005-09-26 18:26:26 +00001177 struct route_table *table = NULL;
Hasso Tepper43057bf2012-10-11 11:19:51 +00001178 struct timeval time_now;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001179 unsigned long long start_time, end_time;
1180
1181 /* Get time that can't roll backwards. */
Hasso Tepper43057bf2012-10-11 11:19:51 +00001182 quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001183 start_time = time_now.tv_sec;
Hasso Tepper43057bf2012-10-11 11:19:51 +00001184 start_time = (start_time * 1000000) + time_now.tv_usec;
hassof390d2c2004-09-10 20:48:21 +00001185
jardineb5d44e2003-12-23 08:09:43 +00001186 if (family == AF_INET)
1187 spftree = area->spftree[level - 1];
1188#ifdef HAVE_IPV6
1189 else if (family == AF_INET6)
1190 spftree = area->spftree6[level - 1];
1191#endif
jardineb5d44e2003-12-23 08:09:43 +00001192 assert (spftree);
Josh Bailey3f045a02012-03-24 08:35:20 -07001193 assert (sysid);
jardineb5d44e2003-12-23 08:09:43 +00001194
hassofac1f7c2005-09-26 18:26:26 +00001195 /* Make all routes in current route table inactive. */
1196 if (family == AF_INET)
1197 table = area->route_table[level - 1];
Paul Jakma41b36e92006-12-08 01:09:50 +00001198#ifdef HAVE_IPV6
hassofac1f7c2005-09-26 18:26:26 +00001199 else if (family == AF_INET6)
1200 table = area->route_table6[level - 1];
Paul Jakma41b36e92006-12-08 01:09:50 +00001201#endif
hassofac1f7c2005-09-26 18:26:26 +00001202
Josh Bailey3f045a02012-03-24 08:35:20 -07001203 isis_route_invalidate_table (area, table);
hassofac1f7c2005-09-26 18:26:26 +00001204
jardineb5d44e2003-12-23 08:09:43 +00001205 /*
1206 * C.2.5 Step 0
1207 */
1208 init_spt (spftree);
1209 /* a) */
Josh Bailey3f045a02012-03-24 08:35:20 -07001210 root_vertex = isis_spf_add_root (spftree, level, sysid);
jardineb5d44e2003-12-23 08:09:43 +00001211 /* b) */
Josh Bailey3f045a02012-03-24 08:35:20 -07001212 retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
1213 if (retval != ISIS_OK)
1214 {
1215 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
1216 goto out;
1217 }
hassof390d2c2004-09-10 20:48:21 +00001218
jardineb5d44e2003-12-23 08:09:43 +00001219 /*
1220 * C.2.7 Step 2
1221 */
hassof390d2c2004-09-10 20:48:21 +00001222 if (listcount (spftree->tents) == 0)
1223 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001224 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
hasso13fb40a2005-10-01 06:03:04 +00001225 goto out;
jardineb5d44e2003-12-23 08:09:43 +00001226 }
hassof390d2c2004-09-10 20:48:21 +00001227
1228 while (listcount (spftree->tents) > 0)
1229 {
1230 node = listhead (spftree->tents);
paul1eb8ef22005-04-07 07:30:20 +00001231 vertex = listgetdata (node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001232
1233#ifdef EXTREME_DEBUG
1234 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1235 print_sys_hostname (vertex->N.id),
1236 vtype2string (vertex->type), vertex->depth, vertex->d_N);
1237#endif /* EXTREME_DEBUG */
1238
1239 /* Remove from tent list and add to paths list */
hassof390d2c2004-09-10 20:48:21 +00001240 list_delete_node (spftree->tents, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001241 add_to_paths (spftree, vertex, level);
1242 switch (vertex->type)
1243 {
1244 case VTYPE_PSEUDO_IS:
1245 case VTYPE_NONPSEUDO_IS:
1246 case VTYPE_PSEUDO_TE_IS:
1247 case VTYPE_NONPSEUDO_TE_IS:
hassof390d2c2004-09-10 20:48:21 +00001248 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1249 LSP_FRAGMENT (lsp_id) = 0;
1250 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001251 if (lsp && lsp->lsp_header->rem_lifetime != 0)
hassof390d2c2004-09-10 20:48:21 +00001252 {
1253 if (LSP_PSEUDO_ID (lsp_id))
1254 {
1255 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001256 vertex->depth, family, sysid,
1257 vertex);
hassof390d2c2004-09-10 20:48:21 +00001258 }
1259 else
1260 {
1261 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
Josh Bailey3f045a02012-03-24 08:35:20 -07001262 vertex->depth, family, sysid, vertex);
hassof390d2c2004-09-10 20:48:21 +00001263 }
1264 }
1265 else
1266 {
1267 zlog_warn ("ISIS-Spf: No LSP found for %s",
1268 rawlspid_print (lsp_id));
1269 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001270 break;
1271 default:;
hassof390d2c2004-09-10 20:48:21 +00001272 }
1273 }
1274
hasso13fb40a2005-10-01 06:03:04 +00001275out:
Josh Bailey3f045a02012-03-24 08:35:20 -07001276 isis_route_validate (area);
jardineb5d44e2003-12-23 08:09:43 +00001277 spftree->pending = 0;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001278 spftree->runcount++;
1279 spftree->last_run_timestamp = time (NULL);
Hasso Tepper43057bf2012-10-11 11:19:51 +00001280 quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001281 end_time = time_now.tv_sec;
Hasso Tepper43057bf2012-10-11 11:19:51 +00001282 end_time = (end_time * 1000000) + time_now.tv_usec;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001283 spftree->last_run_duration = end_time - start_time;
1284
hassof390d2c2004-09-10 20:48:21 +00001285
jardineb5d44e2003-12-23 08:09:43 +00001286 return retval;
1287}
1288
1289int
1290isis_run_spf_l1 (struct thread *thread)
1291{
1292 struct isis_area *area;
1293 int retval = ISIS_OK;
1294
hassof390d2c2004-09-10 20:48:21 +00001295 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001296 assert (area);
1297
hasso12a5cae2004-09-19 19:39:26 +00001298 area->spftree[0]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001299 area->spftree[0]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001300
hassof390d2c2004-09-10 20:48:21 +00001301 if (!(area->is_type & IS_LEVEL_1))
1302 {
1303 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001304 zlog_warn ("ISIS-SPF (%s) area does not share level",
1305 area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001306 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001307 }
jardineb5d44e2003-12-23 08:09:43 +00001308
hassof390d2c2004-09-10 20:48:21 +00001309 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001310 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001311
jardineb5d44e2003-12-23 08:09:43 +00001312 if (area->ip_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001313 retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001314
jardineb5d44e2003-12-23 08:09:43 +00001315 return retval;
1316}
1317
1318int
1319isis_run_spf_l2 (struct thread *thread)
1320{
1321 struct isis_area *area;
1322 int retval = ISIS_OK;
1323
hassof390d2c2004-09-10 20:48:21 +00001324 area = THREAD_ARG (thread);
jardineb5d44e2003-12-23 08:09:43 +00001325 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001326
hasso12a5cae2004-09-19 19:39:26 +00001327 area->spftree[1]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001328 area->spftree[1]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001329
hassof390d2c2004-09-10 20:48:21 +00001330 if (!(area->is_type & IS_LEVEL_2))
1331 {
1332 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso12a5cae2004-09-19 19:39:26 +00001333 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001334 return ISIS_WARNING;
jardineb5d44e2003-12-23 08:09:43 +00001335 }
hassof390d2c2004-09-10 20:48:21 +00001336
1337 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001338 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
jardineb5d44e2003-12-23 08:09:43 +00001339
1340 if (area->ip_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001341 retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
jardineb5d44e2003-12-23 08:09:43 +00001342
1343 return retval;
1344}
1345
hassof390d2c2004-09-10 20:48:21 +00001346int
jardineb5d44e2003-12-23 08:09:43 +00001347isis_spf_schedule (struct isis_area *area, int level)
1348{
jardineb5d44e2003-12-23 08:09:43 +00001349 struct isis_spftree *spftree = area->spftree[level - 1];
Josh Bailey3f045a02012-03-24 08:35:20 -07001350 time_t now = time (NULL);
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001351 int diff = now - spftree->last_run_timestamp;
Josh Bailey3f045a02012-03-24 08:35:20 -07001352
1353 assert (diff >= 0);
1354 assert (area->is_type & level);
1355
1356 if (isis->debugs & DEBUG_SPF_EVENTS)
1357 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1358 area->area_tag, level, diff);
jardineb5d44e2003-12-23 08:09:43 +00001359
1360 if (spftree->pending)
Josh Bailey3f045a02012-03-24 08:35:20 -07001361 return ISIS_OK;
hasso12a5cae2004-09-19 19:39:26 +00001362
1363 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001364
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001365 /* wait configured min_spf_interval before doing the SPF */
1366 if (diff >= area->min_spf_interval[level-1])
Josh Bailey3f045a02012-03-24 08:35:20 -07001367 return isis_run_spf (area, level, AF_INET, isis->sysid);
jardineb5d44e2003-12-23 08:09:43 +00001368
Josh Bailey3f045a02012-03-24 08:35:20 -07001369 if (level == 1)
1370 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001371 area->min_spf_interval[0] - diff);
hassof390d2c2004-09-10 20:48:21 +00001372 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001373 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001374 area->min_spf_interval[1] - diff);
jardineb5d44e2003-12-23 08:09:43 +00001375
Josh Bailey3f045a02012-03-24 08:35:20 -07001376 if (isis->debugs & DEBUG_SPF_EVENTS)
1377 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001378 area->area_tag, level, area->min_spf_interval[level-1] - diff);
Josh Bailey3f045a02012-03-24 08:35:20 -07001379
1380 spftree->pending = 1;
1381
1382 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001383}
1384
1385#ifdef HAVE_IPV6
hasso92365882005-01-18 13:53:33 +00001386static int
hasso12a5cae2004-09-19 19:39:26 +00001387isis_run_spf6_l1 (struct thread *thread)
1388{
1389 struct isis_area *area;
1390 int retval = ISIS_OK;
1391
1392 area = THREAD_ARG (thread);
1393 assert (area);
1394
1395 area->spftree6[0]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001396 area->spftree6[0]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001397
1398 if (!(area->is_type & IS_LEVEL_1))
1399 {
1400 if (isis->debugs & DEBUG_SPF_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -07001401 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001402 return ISIS_WARNING;
1403 }
1404
1405 if (isis->debugs & DEBUG_SPF_EVENTS)
hasso529d65b2004-12-24 00:14:50 +00001406 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001407
1408 if (area->ipv6_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001409 retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001410
1411 return retval;
1412}
1413
hasso92365882005-01-18 13:53:33 +00001414static int
hasso12a5cae2004-09-19 19:39:26 +00001415isis_run_spf6_l2 (struct thread *thread)
1416{
1417 struct isis_area *area;
1418 int retval = ISIS_OK;
1419
1420 area = THREAD_ARG (thread);
1421 assert (area);
1422
1423 area->spftree6[1]->t_spf = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001424 area->spftree6[1]->pending = 0;
hasso12a5cae2004-09-19 19:39:26 +00001425
1426 if (!(area->is_type & IS_LEVEL_2))
1427 {
1428 if (isis->debugs & DEBUG_SPF_EVENTS)
1429 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1430 return ISIS_WARNING;
1431 }
1432
1433 if (isis->debugs & DEBUG_SPF_EVENTS)
hassofac1f7c2005-09-26 18:26:26 +00001434 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
hasso12a5cae2004-09-19 19:39:26 +00001435
1436 if (area->ipv6_circuits)
Josh Bailey3f045a02012-03-24 08:35:20 -07001437 retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
hasso12a5cae2004-09-19 19:39:26 +00001438
1439 return retval;
1440}
1441
1442int
jardineb5d44e2003-12-23 08:09:43 +00001443isis_spf_schedule6 (struct isis_area *area, int level)
1444{
1445 int retval = ISIS_OK;
1446 struct isis_spftree *spftree = area->spftree6[level - 1];
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001447 time_t now = time (NULL);
1448 time_t diff = now - spftree->last_run_timestamp;
1449
1450 assert (diff >= 0);
1451 assert (area->is_type & level);
1452
1453 if (isis->debugs & DEBUG_SPF_EVENTS)
David Lamparteref008d22015-03-03 08:48:11 +01001454 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago",
1455 area->area_tag, level, (long long)diff);
jardineb5d44e2003-12-23 08:09:43 +00001456
1457 if (spftree->pending)
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001458 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001459
hasso12a5cae2004-09-19 19:39:26 +00001460 THREAD_TIMER_OFF (spftree->t_spf);
jardineb5d44e2003-12-23 08:09:43 +00001461
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001462 /* wait configured min_spf_interval before doing the SPF */
1463 if (diff >= area->min_spf_interval[level-1])
1464 return isis_run_spf (area, level, AF_INET6, isis->sysid);
Josh Bailey3f045a02012-03-24 08:35:20 -07001465
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001466 if (level == 1)
1467 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1468 area->min_spf_interval[0] - diff);
hassof390d2c2004-09-10 20:48:21 +00001469 else
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001470 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1471 area->min_spf_interval[1] - diff);
1472
1473 if (isis->debugs & DEBUG_SPF_EVENTS)
David Lamparteref008d22015-03-03 08:48:11 +01001474 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now",
1475 area->area_tag, level,
1476 (long long)(area->min_spf_interval[level-1] - diff));
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001477
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;
David Lampartere8aca322012-11-27 01:10:30 +00001491 u_char buff[BUFSIZ];
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);
jardineb5d44e2003-12-23 08:09:43 +00001695}