]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_spf.c
isisd: add Google's changes to IS-IS
[mirror_frr.git] / isisd / isis_spf.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_spf.c
3 * The SPT algorithm
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
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
eb5d44eb 24#include <zebra.h>
eb5d44eb 25
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"
3f045a08 39#include "isis_flags.h"
eb5d44eb 40#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
eb5d44eb 53int isis_run_spf_l1 (struct thread *thread);
54int isis_run_spf_l2 (struct thread *thread);
55
eb5d44eb 56/* 7.2.7 */
92365889 57static void
eb5d44eb 58remove_excess_adjs (struct list *adjs)
59{
3fdb2dd9 60 struct listnode *node, *excess = NULL;
eb5d44eb 61 struct isis_adjacency *adj, *candidate = NULL;
62 int comp;
63
3fdb2dd9 64 for (ALL_LIST_ELEMENTS_RO (adjs, node, adj))
f390d2c7 65 {
66 if (excess == NULL)
67 excess = node;
1eb8ef25 68 candidate = listgetdata (excess);
69
f390d2c7 70 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;
eb5d44eb 88
f390d2c7 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 }
eb5d44eb 106 }
f390d2c7 107
eb5d44eb 108 list_delete_node (adjs, excess);
109
110 return;
111}
112
92365889 113static const char *
eb5d44eb 114vtype2string (enum vertextype vtype)
115{
f390d2c7 116 switch (vtype)
117 {
118 case VTYPE_PSEUDO_IS:
119 return "pseudo_IS";
120 break;
82a8428c 121 case VTYPE_PSEUDO_TE_IS:
122 return "pseudo_TE-IS";
123 break;
f390d2c7 124 case VTYPE_NONPSEUDO_IS:
125 return "IS";
126 break;
82a8428c 127 case VTYPE_NONPSEUDO_TE_IS:
128 return "TE-IS";
129 break;
f390d2c7 130 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;
82a8428c 139 case VTYPE_IPREACH_TE:
140 return "IP TE";
141 break;
eb5d44eb 142#ifdef HAVE_IPV6
f390d2c7 143 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 */
eb5d44eb 154}
155
92365889 156static const char *
f390d2c7 157vid2string (struct isis_vertex *vertex, u_char * buff)
eb5d44eb 158{
f390d2c7 159 switch (vertex->type)
160 {
161 case VTYPE_PSEUDO_IS:
82a8428c 162 case VTYPE_PSEUDO_TE_IS:
3f045a08 163 return print_sys_hostname (vertex->N.id);
f390d2c7 164 break;
165 case VTYPE_NONPSEUDO_IS:
82a8428c 166 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 167 case VTYPE_ES:
3f045a08 168 return print_sys_hostname (vertex->N.id);
f390d2c7 169 break;
170 case VTYPE_IPREACH_INTERNAL:
171 case VTYPE_IPREACH_EXTERNAL:
82a8428c 172 case VTYPE_IPREACH_TE:
eb5d44eb 173#ifdef HAVE_IPV6
f390d2c7 174 case VTYPE_IP6REACH_INTERNAL:
175 case VTYPE_IP6REACH_EXTERNAL:
176#endif /* HAVE_IPV6 */
f7c43dcb 177 prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ);
f390d2c7 178 break;
179 default:
180 return "UNKNOWN";
181 }
182
f7c43dcb 183 return (char *) buff;
eb5d44eb 184}
185
3f045a08
JB
186static struct isis_vertex *
187isis_vertex_new (void *id, enum vertextype vtype)
eb5d44eb 188{
3f045a08 189 struct isis_vertex *vertex;
eb5d44eb 190
3f045a08
JB
191 vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
192 if (vertex == NULL)
f390d2c7 193 {
3f045a08 194 zlog_err ("isis_vertex_new Out of memory!");
f390d2c7 195 return NULL;
196 }
eb5d44eb 197
3f045a08
JB
198 vertex->type = vtype;
199 switch (vtype)
200 {
201 case VTYPE_ES:
202 case VTYPE_NONPSEUDO_IS:
203 case VTYPE_NONPSEUDO_TE_IS:
204 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN);
205 break;
206 case VTYPE_PSEUDO_IS:
207 case VTYPE_PSEUDO_TE_IS:
208 memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1);
209 break;
210 case VTYPE_IPREACH_INTERNAL:
211 case VTYPE_IPREACH_EXTERNAL:
212 case VTYPE_IPREACH_TE:
213#ifdef HAVE_IPV6
214 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 }
223
224 vertex->Adj_N = list_new ();
225 vertex->parents = list_new ();
226 vertex->children = list_new ();
227
228 return vertex;
eb5d44eb 229}
230
92365889 231static void
eb5d44eb 232isis_vertex_del (struct isis_vertex *vertex)
233{
eb5d44eb 234 list_delete (vertex->Adj_N);
3f045a08
JB
235 vertex->Adj_N = NULL;
236 list_delete (vertex->parents);
237 vertex->parents = NULL;
238 list_delete (vertex->children);
239 vertex->children = NULL;
eb5d44eb 240
3f045a08 241 memset(vertex, 0, sizeof(struct isis_vertex));
eb5d44eb 242 XFREE (MTYPE_ISIS_VERTEX, vertex);
f390d2c7 243
eb5d44eb 244 return;
245}
246
92365889 247static void
3f045a08
JB
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;
277 tree->lastrun = 0;
278 tree->runcount = 0;
279 tree->pending = 0;
280 return tree;
281}
282
283void
eb5d44eb 284isis_spftree_del (struct isis_spftree *spftree)
285{
3f045a08
JB
286 THREAD_TIMER_OFF (spftree->t_spf);
287
f7c43dcb 288 spftree->tents->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 289 list_delete (spftree->tents);
3f045a08 290 spftree->tents = NULL;
f390d2c7 291
f7c43dcb 292 spftree->paths->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 293 list_delete (spftree->paths);
3f045a08 294 spftree->paths = NULL;
eb5d44eb 295
296 XFREE (MTYPE_ISIS_SPFTREE, spftree);
297
298 return;
299}
3f045a08
JB
300
301void
302isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
303{
304 struct listnode *node;
305 if (!adj)
306 return;
307 for (node = listhead (spftree->tents); node; node = listnextnode (node))
308 isis_vertex_adj_del (listgetdata (node), adj);
309 for (node = listhead (spftree->paths); node; node = listnextnode (node))
310 isis_vertex_adj_del (listgetdata (node), adj);
311 return;
312}
eb5d44eb 313
f390d2c7 314void
eb5d44eb 315spftree_area_init (struct isis_area *area)
316{
3f045a08
JB
317 if (area->is_type & IS_LEVEL_1)
318 {
319 if (area->spftree[0] == NULL)
320 area->spftree[0] = isis_spftree_new (area);
eb5d44eb 321#ifdef HAVE_IPV6
3f045a08
JB
322 if (area->spftree6[0] == NULL)
323 area->spftree6[0] = isis_spftree_new (area);
eb5d44eb 324#endif
3f045a08 325 }
eb5d44eb 326
3f045a08
JB
327 if (area->is_type & IS_LEVEL_2)
328 {
329 if (area->spftree[1] == NULL)
330 area->spftree[1] = isis_spftree_new (area);
eb5d44eb 331#ifdef HAVE_IPV6
3f045a08
JB
332 if (area->spftree6[1] == NULL)
333 area->spftree6[1] = isis_spftree_new (area);
eb5d44eb 334#endif
3f045a08 335 }
eb5d44eb 336
337 return;
338}
339
3f045a08
JB
340void
341spftree_area_del (struct isis_area *area)
eb5d44eb 342{
3f045a08
JB
343 if (area->is_type & IS_LEVEL_1)
344 {
345 if (area->spftree[0] != NULL)
f390d2c7 346 {
3f045a08
JB
347 isis_spftree_del (area->spftree[0]);
348 area->spftree[0] = NULL;
349 }
350#ifdef HAVE_IPV6
351 if (area->spftree6[0])
352 {
353 isis_spftree_del (area->spftree6[0]);
354 area->spftree6[0] = NULL;
f390d2c7 355 }
3f045a08
JB
356#endif
357 }
f390d2c7 358
3f045a08
JB
359 if (area->is_type & IS_LEVEL_2)
360 {
361 if (area->spftree[1] != NULL)
f390d2c7 362 {
3f045a08
JB
363 isis_spftree_del (area->spftree[1]);
364 area->spftree[1] = NULL;
365 }
eb5d44eb 366#ifdef HAVE_IPV6
3f045a08
JB
367 if (area->spftree[1] != NULL)
368 {
369 isis_spftree_del (area->spftree6[1]);
370 area->spftree6[1] = NULL;
f390d2c7 371 }
3f045a08
JB
372#endif
373 }
eb5d44eb 374
3f045a08
JB
375 return;
376}
f390d2c7 377
3f045a08
JB
378void
379spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
380{
381 if (area->is_type & IS_LEVEL_1)
382 {
383 if (area->spftree[0] != NULL)
384 isis_spftree_adj_del (area->spftree[0], adj);
385#ifdef HAVE_IPV6
386 if (area->spftree6[0] != NULL)
387 isis_spftree_adj_del (area->spftree6[0], adj);
388#endif
389 }
390
391 if (area->is_type & IS_LEVEL_2)
392 {
393 if (area->spftree[1] != NULL)
394 isis_spftree_adj_del (area->spftree[1], adj);
395#ifdef HAVE_IPV6
396 if (area->spftree6[1] != NULL)
397 isis_spftree_adj_del (area->spftree6[1], adj);
398#endif
399 }
400
401 return;
402}
403
404/*
405 * Find the system LSP: returns the LSP in our LSP database
406 * associated with the given system ID.
407 */
408static struct isis_lsp *
409isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
410{
411 u_char lspid[ISIS_SYS_ID_LEN + 2];
412
413 memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
414 LSP_PSEUDO_ID (lspid) = 0;
415 LSP_FRAGMENT (lspid) = 0;
416 return (lsp_search (lspid, area->lspdb[level - 1]));
eb5d44eb 417}
418
419/*
420 * Add this IS to the root of SPT
421 */
3f045a08
JB
422static struct isis_vertex *
423isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
eb5d44eb 424{
425 struct isis_vertex *vertex;
426 struct isis_lsp *lsp;
eb5d44eb 427#ifdef EXTREME_DEBUG
428 u_char buff[BUFSIZ];
429#endif /* EXTREME_DEBUG */
f390d2c7 430
3f045a08 431 lsp = isis_root_system_lsp (spftree->area, level, sysid);
eb5d44eb 432 if (lsp == NULL)
433 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
f390d2c7 434
3f045a08
JB
435 if (!spftree->area->oldmetric)
436 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
82a8428c 437 else
3f045a08 438 vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
eb5d44eb 439
440 listnode_add (spftree->paths, vertex);
441
442#ifdef EXTREME_DEBUG
529d65b3 443 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);
eb5d44eb 446#endif /* EXTREME_DEBUG */
447
3f045a08 448 return vertex;
eb5d44eb 449}
450
92365889 451static struct isis_vertex *
f390d2c7 452isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
eb5d44eb 453{
454 struct listnode *node;
455 struct isis_vertex *vertex;
456 struct prefix *p1, *p2;
457
1eb8ef25 458 for (ALL_LIST_ELEMENTS_RO (list, node, vertex))
f390d2c7 459 {
f390d2c7 460 if (vertex->type != vtype)
461 continue;
462 switch (vtype)
463 {
464 case VTYPE_ES:
465 case VTYPE_NONPSEUDO_IS:
82a8428c 466 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 467 if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
468 return vertex;
469 break;
470 case VTYPE_PSEUDO_IS:
82a8428c 471 case VTYPE_PSEUDO_TE_IS:
f390d2c7 472 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:
82a8428c 477 case VTYPE_IPREACH_TE:
eb5d44eb 478#ifdef HAVE_IPV6
f390d2c7 479 case VTYPE_IP6REACH_INTERNAL:
480 case VTYPE_IP6REACH_EXTERNAL:
eb5d44eb 481#endif /* HAVE_IPV6 */
f390d2c7 482 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 }
eb5d44eb 490 }
eb5d44eb 491
492 return NULL;
493}
494
eb5d44eb 495/*
496 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
497 */
92365889 498static struct isis_vertex *
f390d2c7 499isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
3f045a08
JB
500 void *id, uint32_t cost, int depth, int family,
501 struct isis_adjacency *adj, struct isis_vertex *parent)
eb5d44eb 502{
503 struct isis_vertex *vertex, *v;
504 struct listnode *node;
3f045a08 505 struct isis_adjacency *parent_adj;
f390d2c7 506#ifdef EXTREME_DEBUG
eb5d44eb 507 u_char buff[BUFSIZ];
508#endif
509
3f045a08
JB
510 assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
511 assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
eb5d44eb 512 vertex = isis_vertex_new (id, vtype);
513 vertex->d_N = cost;
514 vertex->depth = depth;
f390d2c7 515
3f045a08
JB
516 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) {
eb5d44eb 526 listnode_add (vertex->Adj_N, adj);
3f045a08
JB
527 }
528
f390d2c7 529#ifdef EXTREME_DEBUG
3f045a08
JB
530 zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
531 print_sys_hostname (vertex->N.id),
529d65b3 532 vtype2string (vertex->type), vid2string (vertex, buff),
3f045a08 533 vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
eb5d44eb 534#endif /* EXTREME_DEBUG */
3f045a08 535
f390d2c7 536 if (list_isempty (spftree->tents))
537 {
538 listnode_add (spftree->tents, vertex);
539 return vertex;
540 }
3f045a08
JB
541
542 /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
1eb8ef25 543 for (node = listhead (spftree->tents); node; node = listnextnode (node))
f390d2c7 544 {
1eb8ef25 545 v = listgetdata (node);
f390d2c7 546 if (v->d_N > vertex->d_N)
547 {
548 list_add_node_prev (spftree->tents, node, vertex);
549 break;
550 }
3f045a08 551 else if (v->d_N == vertex->d_N && v->type > vertex->type)
f390d2c7 552 {
553 /* Tie break, add according to type */
3f045a08 554 list_add_node_prev (spftree->tents, node, vertex);
f390d2c7 555 break;
556 }
eb5d44eb 557 }
3f045a08
JB
558
559 if (node == NULL)
560 listnode_add (spftree->tents, vertex);
561
eb5d44eb 562 return vertex;
563}
564
3f045a08 565static void
f390d2c7 566isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
3f045a08
JB
567 void *id, struct isis_adjacency *adj, uint32_t cost,
568 int family, struct isis_vertex *parent)
eb5d44eb 569{
570 struct isis_vertex *vertex;
f390d2c7 571
572 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);
3f045a08
JB
584 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;
f390d2c7 589 }
3f045a08 590 else if (vertex->d_N < cost)
f390d2c7 591 {
3f045a08
JB
592 /* e) do nothing */
593 return;
f390d2c7 594 }
3f045a08
JB
595 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 }
eb5d44eb 605 }
eb5d44eb 606
3f045a08
JB
607 isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
608 return;
eb5d44eb 609}
610
92365889 611static void
f390d2c7 612process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
3f045a08
JB
613 uint32_t dist, uint16_t depth, int family,
614 struct isis_vertex *parent)
eb5d44eb 615{
616 struct isis_vertex *vertex;
617#ifdef EXTREME_DEBUG
618 u_char buff[255];
619#endif
620
3f045a08
JB
621 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 }
eb5d44eb 629 /* C.2.6 b) */
3f045a08
JB
630 else if (spftree->area->oldmetric == 1)
631 {
632 if (dist > MAX_NARROW_PATH_METRIC)
633 return;
634 }
635
eb5d44eb 636 /* c) */
637 vertex = isis_find_vertex (spftree->paths, id, vtype);
f390d2c7 638 if (vertex)
639 {
eb5d44eb 640#ifdef EXTREME_DEBUG
3f045a08
JB
641 zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
642 print_sys_hostname (vertex->N.id),
529d65b3 643 vtype2string (vtype), vid2string (vertex, buff), dist);
eb5d44eb 644#endif /* EXTREME_DEBUG */
f390d2c7 645 assert (dist >= vertex->d_N);
646 return;
647 }
eb5d44eb 648
649 vertex = isis_find_vertex (spftree->tents, id, vtype);
f390d2c7 650 /* d) */
651 if (vertex)
652 {
653 /* 1) */
eb5d44eb 654#ifdef EXTREME_DEBUG
3f045a08
JB
655 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));
eb5d44eb 660#endif /* EXTREME_DEBUG */
f390d2c7 661 if (vertex->d_N == dist)
662 {
3f045a08
JB
663 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);
f390d2c7 668 /* 2) */
669 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
670 remove_excess_adjs (vertex->Adj_N);
3f045a08
JB
671 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);
f390d2c7 675 /* 3) */
676 return;
677 }
678 else if (vertex->d_N < dist)
679 {
680 return;
681 /* 4) */
682 }
683 else
684 {
3f045a08
JB
685 struct listnode *pnode, *pnextnode;
686 struct isis_vertex *pvertex;
f390d2c7 687 listnode_delete (spftree->tents, vertex);
3f045a08
JB
688 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);
f390d2c7 692 }
eb5d44eb 693 }
f390d2c7 694
3f045a08
JB
695#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);
eb5d44eb 702 return;
703}
704
705/*
706 * C.2.6 Step 1
707 */
92365889 708static int
f390d2c7 709isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
3f045a08
JB
710 uint32_t cost, uint16_t depth, int family,
711 u_char *root_sysid, struct isis_vertex *parent)
eb5d44eb 712{
713 struct listnode *node, *fragnode = NULL;
3f045a08 714 uint32_t dist;
eb5d44eb 715 struct is_neigh *is_neigh;
82a8428c 716 struct te_is_neigh *te_is_neigh;
eb5d44eb 717 struct ipv4_reachability *ipreach;
82a8428c 718 struct te_ipv4_reachability *te_ipv4_reach;
eb5d44eb 719 enum vertextype vtype;
720 struct prefix prefix;
721#ifdef HAVE_IPV6
722 struct ipv6_reachability *ip6reach;
723#endif /* HAVE_IPV6 */
3f045a08 724 static const u_char null_sysid[ISIS_SYS_ID_LEN];
f390d2c7 725
3f045a08 726 if (!speaks (lsp->tlv_data.nlpids, family))
eb5d44eb 727 return ISIS_OK;
728
f390d2c7 729lspfragloop:
730 if (lsp->lsp_header->seq_num == 0)
731 {
3f045a08 732 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
f390d2c7 733 return ISIS_WARNING;
eb5d44eb 734 }
f390d2c7 735
3f045a08
JB
736#ifdef EXTREME_DEBUG
737 zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
738#endif /* EXTREME_DEBUG */
739
f390d2c7 740 if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
3f045a08
JB
741 {
742 if (lsp->tlv_data.is_neighs)
f390d2c7 743 {
3f045a08
JB
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 }
758 }
759 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 }
f390d2c7 776
3f045a08
JB
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 {
811 dist = cost + ntohl (te_ipv4_reach->te_metric);
812 vtype = VTYPE_IPREACH_TE;
813 prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
814 te_ipv4_reach->control);
815 prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
816 apply_mask (&prefix);
817 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
818 family, parent);
819 }
820 }
eb5d44eb 821#ifdef HAVE_IPV6
3f045a08
JB
822 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
823 {
824 prefix.family = AF_INET6;
825 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
826 {
827 dist = cost + ip6reach->metric;
828 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
829 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
830 prefix.prefixlen = ip6reach->prefix_len;
831 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
832 PSIZE (ip6reach->prefix_len));
833 apply_mask (&prefix);
834 process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
835 family, parent);
f390d2c7 836 }
3f045a08
JB
837 }
838#endif /* HAVE_IPV6 */
f390d2c7 839
eb5d44eb 840 if (fragnode == NULL)
841 fragnode = listhead (lsp->lspu.frags);
f390d2c7 842 else
1eb8ef25 843 fragnode = listnextnode (fragnode);
eb5d44eb 844
f390d2c7 845 if (fragnode)
846 {
1eb8ef25 847 lsp = listgetdata (fragnode);
f390d2c7 848 goto lspfragloop;
849 }
850
eb5d44eb 851 return ISIS_OK;
852}
853
92365889 854static int
f390d2c7 855isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
3f045a08
JB
856 struct isis_lsp *lsp, uint32_t cost,
857 uint16_t depth, int family,
858 u_char *root_sysid,
859 struct isis_vertex *parent)
eb5d44eb 860{
3fdb2dd9 861 struct listnode *node, *fragnode = NULL;
eb5d44eb 862 struct is_neigh *is_neigh;
82a8428c 863 struct te_is_neigh *te_is_neigh;
eb5d44eb 864 enum vertextype vtype;
3f045a08 865 uint32_t dist;
f390d2c7 866
867pseudofragloop:
868
869 if (lsp->lsp_header->seq_num == 0)
870 {
871 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
872 " - do not process");
873 return ISIS_WARNING;
eb5d44eb 874 }
f390d2c7 875
3f045a08
JB
876#ifdef EXTREME_DEBUG
877 zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
878 print_sys_hostname(lsp->lsp_header->lsp_id));
879#endif /* EXTREME_DEBUG */
880
881 /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
882
82a8428c 883 if (lsp->tlv_data.is_neighs)
3fdb2dd9 884 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
82a8428c 885 {
82a8428c 886 /* Two way connectivity */
3f045a08 887 if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
82a8428c 888 continue;
3f045a08
JB
889 dist = cost + is_neigh->metrics.metric_default;
890 vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
891 : VTYPE_NONPSEUDO_IS;
892 process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
893 depth + 1, family, parent);
82a8428c 894 }
895 if (lsp->tlv_data.te_is_neighs)
3fdb2dd9 896 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
82a8428c 897 {
82a8428c 898 /* Two way connectivity */
3f045a08 899 if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
82a8428c 900 continue;
3f045a08
JB
901 dist = cost + GET_TE_METRIC(te_is_neigh);
902 vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
903 : VTYPE_NONPSEUDO_TE_IS;
904 process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
905 depth + 1, family, parent);
82a8428c 906 }
f390d2c7 907
eb5d44eb 908 if (fragnode == NULL)
909 fragnode = listhead (lsp->lspu.frags);
f390d2c7 910 else
1eb8ef25 911 fragnode = listnextnode (fragnode);
eb5d44eb 912
f390d2c7 913 if (fragnode)
914 {
1eb8ef25 915 lsp = listgetdata (fragnode);
f390d2c7 916 goto pseudofragloop;
917 }
eb5d44eb 918
eb5d44eb 919 return ISIS_OK;
920}
f390d2c7 921
92365889 922static int
3f045a08
JB
923isis_spf_preload_tent (struct isis_spftree *spftree, int level,
924 int family, u_char *root_sysid,
925 struct isis_vertex *parent)
eb5d44eb 926{
eb5d44eb 927 struct isis_circuit *circuit;
3fdb2dd9 928 struct listnode *cnode, *anode, *ipnode;
eb5d44eb 929 struct isis_adjacency *adj;
930 struct isis_lsp *lsp;
931 struct list *adj_list;
932 struct list *adjdb;
933 struct prefix_ipv4 *ipv4;
934 struct prefix prefix;
935 int retval = ISIS_OK;
936 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
3f045a08 937 static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
eb5d44eb 938#ifdef HAVE_IPV6
939 struct prefix_ipv6 *ipv6;
940#endif /* HAVE_IPV6 */
f390d2c7 941
3f045a08 942 for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
f390d2c7 943 {
f390d2c7 944 if (circuit->state != C_STATE_UP)
945 continue;
3f045a08 946 if (!(circuit->is_type & level))
f390d2c7 947 continue;
948 if (family == AF_INET && !circuit->ip_router)
949 continue;
eb5d44eb 950#ifdef HAVE_IPV6
f390d2c7 951 if (family == AF_INET6 && !circuit->ipv6_router)
952 continue;
eb5d44eb 953#endif /* HAVE_IPV6 */
f390d2c7 954 /*
955 * Add IP(v6) addresses of this circuit
956 */
957 if (family == AF_INET)
958 {
959 prefix.family = AF_INET;
3fdb2dd9 960 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
f390d2c7 961 {
f390d2c7 962 prefix.u.prefix4 = ipv4->prefix;
963 prefix.prefixlen = ipv4->prefixlen;
3f045a08 964 apply_mask (&prefix);
f390d2c7 965 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
3f045a08 966 NULL, 0, family, parent);
f390d2c7 967 }
968 }
eb5d44eb 969#ifdef HAVE_IPV6
f390d2c7 970 if (family == AF_INET6)
971 {
972 prefix.family = AF_INET6;
3fdb2dd9 973 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
f390d2c7 974 {
f390d2c7 975 prefix.prefixlen = ipv6->prefixlen;
976 prefix.u.prefix6 = ipv6->prefix;
3f045a08 977 apply_mask (&prefix);
f390d2c7 978 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
3f045a08 979 &prefix, NULL, 0, family, parent);
f390d2c7 980 }
981 }
eb5d44eb 982#endif /* HAVE_IPV6 */
f390d2c7 983 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
984 {
985 /*
986 * Add the adjacencies
987 */
988 adj_list = list_new ();
989 adjdb = circuit->u.bc.adjdb[level - 1];
990 isis_adj_build_up_list (adjdb, adj_list);
991 if (listcount (adj_list) == 0)
992 {
993 list_delete (adj_list);
c89c05dd 994 if (isis->debugs & DEBUG_SPF_EVENTS)
995 zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s",
996 level, circuit->interface->name);
f390d2c7 997 continue;
998 }
3f045a08 999 for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
f390d2c7 1000 {
f390d2c7 1001 if (!speaks (&adj->nlpids, family))
f390d2c7 1002 continue;
f390d2c7 1003 switch (adj->sys_type)
1004 {
1005 case ISIS_SYSTYPE_ES:
1006 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
3f045a08
JB
1007 circuit->te_metric[level - 1],
1008 family, parent);
f390d2c7 1009 break;
1010 case ISIS_SYSTYPE_IS:
1011 case ISIS_SYSTYPE_L1_IS:
1012 case ISIS_SYSTYPE_L2_IS:
3f045a08
JB
1013 isis_spf_add_local (spftree,
1014 spftree->area->oldmetric ?
1015 VTYPE_NONPSEUDO_IS :
1016 VTYPE_NONPSEUDO_TE_IS,
1017 adj->sysid, adj,
1018 circuit->te_metric[level - 1],
1019 family, parent);
f390d2c7 1020 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
1021 LSP_PSEUDO_ID (lsp_id) = 0;
1022 LSP_FRAGMENT (lsp_id) = 0;
3f045a08 1023 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
f390d2c7 1024 if (!lsp)
3f045a08
JB
1025 zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
1026 "L%d on %s (ID %u)",
1027 rawlspid_print (lsp_id), level,
1028 circuit->interface->name, circuit->circuit_id);
f390d2c7 1029 break;
1030 case ISIS_SYSTYPE_UNKNOWN:
1031 default:
1032 zlog_warn ("isis_spf_preload_tent unknow adj type");
1033 }
f390d2c7 1034 }
1035 list_delete (adj_list);
1036 /*
1037 * Add the pseudonode
1038 */
1039 if (level == 1)
1040 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1041 else
1042 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
3f045a08
JB
1043 /* can happen during DR reboot */
1044 if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
1045 {
1046 if (isis->debugs & DEBUG_SPF_EVENTS)
1047 zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
1048 level, circuit->interface->name, circuit->circuit_id);
1049 continue;
1050 }
f390d2c7 1051 adj = isis_adj_lookup (lsp_id, adjdb);
1052 /* if no adj, we are the dis or error */
1053 if (!adj && !circuit->u.bc.is_dr[level - 1])
1054 {
3f045a08
JB
1055 zlog_warn ("ISIS-Spf: No adjacency found from root "
1056 "to L%d DR %s on %s (ID %d)",
1057 level, rawlspid_print (lsp_id),
1058 circuit->interface->name, circuit->circuit_id);
1059 continue;
f390d2c7 1060 }
3f045a08 1061 lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
f390d2c7 1062 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
1063 {
3f045a08
JB
1064 zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
1065 "to L%d DR %s on %s (ID %d)",
1066 lsp, level, rawlspid_print (lsp_id),
1067 circuit->interface->name, circuit->circuit_id);
1068 continue;
f390d2c7 1069 }
3f045a08
JB
1070 isis_spf_process_pseudo_lsp (spftree, lsp,
1071 circuit->te_metric[level - 1], 0,
1072 family, root_sysid, parent);
f390d2c7 1073 }
1074 else if (circuit->circ_type == CIRCUIT_T_P2P)
1075 {
1076 adj = circuit->u.p2p.neighbor;
1077 if (!adj)
1078 continue;
1079 switch (adj->sys_type)
1080 {
1081 case ISIS_SYSTYPE_ES:
1082 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
3f045a08
JB
1083 circuit->te_metric[level - 1], family,
1084 parent);
f390d2c7 1085 break;
1086 case ISIS_SYSTYPE_IS:
1087 case ISIS_SYSTYPE_L1_IS:
1088 case ISIS_SYSTYPE_L2_IS:
1089 if (speaks (&adj->nlpids, family))
3f045a08
JB
1090 isis_spf_add_local (spftree,
1091 spftree->area->oldmetric ?
1092 VTYPE_NONPSEUDO_IS :
1093 VTYPE_NONPSEUDO_TE_IS,
1094 adj->sysid,
82a8428c 1095 adj, circuit->te_metric[level - 1],
3f045a08 1096 family, parent);
f390d2c7 1097 break;
1098 case ISIS_SYSTYPE_UNKNOWN:
1099 default:
3f045a08 1100 zlog_warn ("isis_spf_preload_tent unknown adj type");
f390d2c7 1101 break;
1102 }
1103 }
3f045a08
JB
1104 else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
1105 {
1106 continue;
1107 }
eb5d44eb 1108 else
f390d2c7 1109 {
1110 zlog_warn ("isis_spf_preload_tent unsupported media");
1111 retval = ISIS_WARNING;
1112 }
eb5d44eb 1113 }
eb5d44eb 1114
1115 return retval;
1116}
1117
1118/*
1119 * The parent(s) for vertex is set when added to TENT list
1120 * now we just put the child pointer(s) in place
1121 */
92365889 1122static void
eb5d44eb 1123add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
3f045a08 1124 int level)
eb5d44eb 1125{
eb5d44eb 1126 u_char buff[BUFSIZ];
3f045a08
JB
1127
1128 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
1129 return;
eb5d44eb 1130 listnode_add (spftree->paths, vertex);
1131
f390d2c7 1132#ifdef EXTREME_DEBUG
3f045a08
JB
1133 zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
1134 print_sys_hostname (vertex->N.id),
529d65b3 1135 vtype2string (vertex->type), vid2string (vertex, buff),
1136 vertex->depth, vertex->d_N);
f390d2c7 1137#endif /* EXTREME_DEBUG */
3f045a08 1138
f390d2c7 1139 if (vertex->type > VTYPE_ES)
1140 {
1141 if (listcount (vertex->Adj_N) > 0)
fac1f7cc 1142 isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
3f045a08 1143 vertex->depth, vertex->Adj_N, spftree->area, level);
f390d2c7 1144 else if (isis->debugs & DEBUG_SPF_EVENTS)
3f045a08
JB
1145 zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
1146 "%s depth %d dist %d", vid2string (vertex, buff),
1147 vertex->depth, vertex->d_N);
f390d2c7 1148 }
1149
eb5d44eb 1150 return;
1151}
1152
92365889 1153static void
eb5d44eb 1154init_spt (struct isis_spftree *spftree)
1155{
f7c43dcb 1156 spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del;
eb5d44eb 1157 list_delete_all_node (spftree->tents);
1158 list_delete_all_node (spftree->paths);
1159 spftree->tents->del = spftree->paths->del = NULL;
eb5d44eb 1160 return;
1161}
1162
92365889 1163static int
3f045a08 1164isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
eb5d44eb 1165{
1166 int retval = ISIS_OK;
1167 struct listnode *node;
1168 struct isis_vertex *vertex;
3f045a08 1169 struct isis_vertex *root_vertex;
f390d2c7 1170 struct isis_spftree *spftree = NULL;
eb5d44eb 1171 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1172 struct isis_lsp *lsp;
fac1f7cc 1173 struct route_table *table = NULL;
f390d2c7 1174
eb5d44eb 1175 if (family == AF_INET)
1176 spftree = area->spftree[level - 1];
1177#ifdef HAVE_IPV6
1178 else if (family == AF_INET6)
1179 spftree = area->spftree6[level - 1];
1180#endif
eb5d44eb 1181 assert (spftree);
3f045a08 1182 assert (sysid);
eb5d44eb 1183
fac1f7cc 1184 /* Make all routes in current route table inactive. */
1185 if (family == AF_INET)
1186 table = area->route_table[level - 1];
41b36e90 1187#ifdef HAVE_IPV6
fac1f7cc 1188 else if (family == AF_INET6)
1189 table = area->route_table6[level - 1];
41b36e90 1190#endif
fac1f7cc 1191
3f045a08 1192 isis_route_invalidate_table (area, table);
fac1f7cc 1193
eb5d44eb 1194 /*
1195 * C.2.5 Step 0
1196 */
1197 init_spt (spftree);
1198 /* a) */
3f045a08 1199 root_vertex = isis_spf_add_root (spftree, level, sysid);
eb5d44eb 1200 /* b) */
3f045a08
JB
1201 retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
1202 if (retval != ISIS_OK)
1203 {
1204 zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
1205 goto out;
1206 }
f390d2c7 1207
eb5d44eb 1208 /*
1209 * C.2.7 Step 2
1210 */
f390d2c7 1211 if (listcount (spftree->tents) == 0)
1212 {
3f045a08 1213 zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
13fb40ac 1214 goto out;
f390d2c7 1215 }
1216
1217 while (listcount (spftree->tents) > 0)
1218 {
1219 node = listhead (spftree->tents);
1eb8ef25 1220 vertex = listgetdata (node);
3f045a08
JB
1221
1222#ifdef EXTREME_DEBUG
1223 zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
1224 print_sys_hostname (vertex->N.id),
1225 vtype2string (vertex->type), vertex->depth, vertex->d_N);
1226#endif /* EXTREME_DEBUG */
1227
1228 /* Remove from tent list and add to paths list */
f390d2c7 1229 list_delete_node (spftree->tents, node);
3f045a08
JB
1230 add_to_paths (spftree, vertex, level);
1231 switch (vertex->type)
1232 {
1233 case VTYPE_PSEUDO_IS:
1234 case VTYPE_NONPSEUDO_IS:
1235 case VTYPE_PSEUDO_TE_IS:
1236 case VTYPE_NONPSEUDO_TE_IS:
f390d2c7 1237 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
1238 LSP_FRAGMENT (lsp_id) = 0;
1239 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
1240 if (lsp)
1241 {
1242 if (LSP_PSEUDO_ID (lsp_id))
1243 {
1244 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
3f045a08
JB
1245 vertex->depth, family, sysid,
1246 vertex);
f390d2c7 1247 }
1248 else
1249 {
1250 isis_spf_process_lsp (spftree, lsp, vertex->d_N,
3f045a08 1251 vertex->depth, family, sysid, vertex);
f390d2c7 1252 }
1253 }
1254 else
1255 {
1256 zlog_warn ("ISIS-Spf: No LSP found for %s",
1257 rawlspid_print (lsp_id));
1258 }
3f045a08
JB
1259 break;
1260 default:;
eb5d44eb 1261 }
eb5d44eb 1262 }
f390d2c7 1263
13fb40ac 1264out:
3f045a08 1265 isis_route_validate (area);
eb5d44eb 1266 spftree->lastrun = time (NULL);
3f045a08 1267 spftree->runcount++;
eb5d44eb 1268 spftree->pending = 0;
f390d2c7 1269
eb5d44eb 1270 return retval;
1271}
1272
1273int
1274isis_run_spf_l1 (struct thread *thread)
1275{
1276 struct isis_area *area;
1277 int retval = ISIS_OK;
1278
f390d2c7 1279 area = THREAD_ARG (thread);
eb5d44eb 1280 assert (area);
1281
12a5cae7 1282 area->spftree[0]->t_spf = NULL;
3f045a08 1283 area->spftree[0]->pending = 0;
12a5cae7 1284
f390d2c7 1285 if (!(area->is_type & IS_LEVEL_1))
1286 {
1287 if (isis->debugs & DEBUG_SPF_EVENTS)
12a5cae7 1288 zlog_warn ("ISIS-SPF (%s) area does not share level",
1289 area->area_tag);
f390d2c7 1290 return ISIS_WARNING;
1291 }
1292
1293 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1294 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
eb5d44eb 1295
eb5d44eb 1296 if (area->ip_circuits)
3f045a08 1297 retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
12a5cae7 1298
eb5d44eb 1299 return retval;
1300}
1301
1302int
1303isis_run_spf_l2 (struct thread *thread)
1304{
1305 struct isis_area *area;
1306 int retval = ISIS_OK;
1307
f390d2c7 1308 area = THREAD_ARG (thread);
eb5d44eb 1309 assert (area);
f390d2c7 1310
12a5cae7 1311 area->spftree[1]->t_spf = NULL;
3f045a08 1312 area->spftree[1]->pending = 0;
12a5cae7 1313
f390d2c7 1314 if (!(area->is_type & IS_LEVEL_2))
1315 {
1316 if (isis->debugs & DEBUG_SPF_EVENTS)
12a5cae7 1317 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
f390d2c7 1318 return ISIS_WARNING;
1319 }
1320
1321 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1322 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
eb5d44eb 1323
1324 if (area->ip_circuits)
3f045a08 1325 retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
eb5d44eb 1326
1327 return retval;
1328}
1329
f390d2c7 1330int
eb5d44eb 1331isis_spf_schedule (struct isis_area *area, int level)
1332{
eb5d44eb 1333 struct isis_spftree *spftree = area->spftree[level - 1];
3f045a08
JB
1334 time_t now = time (NULL);
1335 int diff = now - spftree->lastrun;
eb5d44eb 1336
3f045a08
JB
1337 assert (diff >= 0);
1338 assert (area->is_type & level);
eb5d44eb 1339
3f045a08
JB
1340 if (isis->debugs & DEBUG_SPF_EVENTS)
1341 zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
1342 area->area_tag, level, diff);
f390d2c7 1343
3f045a08
JB
1344 if (spftree->pending)
1345 return ISIS_OK;
12a5cae7 1346
1347 THREAD_TIMER_OFF (spftree->t_spf);
f390d2c7 1348
3f045a08
JB
1349 /* wait MINIMUM_SPF_INTERVAL before doing the SPF */
1350 if (diff >= MINIMUM_SPF_INTERVAL)
1351 return isis_run_spf (area, level, AF_INET, isis->sysid);
f390d2c7 1352
3f045a08
JB
1353 if (level == 1)
1354 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
1355 MINIMUM_SPF_INTERVAL - diff);
f390d2c7 1356 else
3f045a08
JB
1357 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
1358 MINIMUM_SPF_INTERVAL - diff);
eb5d44eb 1359
3f045a08
JB
1360 if (isis->debugs & DEBUG_SPF_EVENTS)
1361 zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
1362 area->area_tag, level, MINIMUM_SPF_INTERVAL - diff);
1363
1364 spftree->pending = 1;
1365
1366 return ISIS_OK;
eb5d44eb 1367}
1368
1369#ifdef HAVE_IPV6
92365889 1370static int
12a5cae7 1371isis_run_spf6_l1 (struct thread *thread)
1372{
1373 struct isis_area *area;
1374 int retval = ISIS_OK;
1375
1376 area = THREAD_ARG (thread);
1377 assert (area);
1378
1379 area->spftree6[0]->t_spf = NULL;
3f045a08 1380 area->spftree6[0]->pending = 0;
12a5cae7 1381
1382 if (!(area->is_type & IS_LEVEL_1))
1383 {
1384 if (isis->debugs & DEBUG_SPF_EVENTS)
3f045a08 1385 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
12a5cae7 1386 return ISIS_WARNING;
1387 }
1388
1389 if (isis->debugs & DEBUG_SPF_EVENTS)
529d65b3 1390 zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
12a5cae7 1391
1392 if (area->ipv6_circuits)
3f045a08 1393 retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
12a5cae7 1394
1395 return retval;
1396}
1397
92365889 1398static int
12a5cae7 1399isis_run_spf6_l2 (struct thread *thread)
1400{
1401 struct isis_area *area;
1402 int retval = ISIS_OK;
1403
1404 area = THREAD_ARG (thread);
1405 assert (area);
1406
1407 area->spftree6[1]->t_spf = NULL;
3f045a08 1408 area->spftree6[1]->pending = 0;
12a5cae7 1409
1410 if (!(area->is_type & IS_LEVEL_2))
1411 {
1412 if (isis->debugs & DEBUG_SPF_EVENTS)
1413 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1414 return ISIS_WARNING;
1415 }
1416
1417 if (isis->debugs & DEBUG_SPF_EVENTS)
fac1f7cc 1418 zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
12a5cae7 1419
1420 if (area->ipv6_circuits)
3f045a08 1421 retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
12a5cae7 1422
1423 return retval;
1424}
1425
f390d2c7 1426int
eb5d44eb 1427isis_spf_schedule6 (struct isis_area *area, int level)
1428{
1429 int retval = ISIS_OK;
1430 struct isis_spftree *spftree = area->spftree6[level - 1];
1431 time_t diff, now = time (NULL);
1432
1433 if (spftree->pending)
1434 return retval;
1435
12a5cae7 1436 THREAD_TIMER_OFF (spftree->t_spf);
eb5d44eb 1437
3f045a08
JB
1438 /* FIXME: let's wait MINIMUM_SPF_INTERVAL before doing the SPF */
1439 if (now - isis->uptime < MINIMUM_SPF_INTERVAL || isis->uptime == 0)
1440 diff = 0;
1441 else
1442 diff = now - spftree->lastrun;
1443
f390d2c7 1444 if (diff < MINIMUM_SPF_INTERVAL)
1445 {
1446 if (level == 1)
12a5cae7 1447 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
1448 MINIMUM_SPF_INTERVAL - diff);
f390d2c7 1449 else
12a5cae7 1450 THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
1451 MINIMUM_SPF_INTERVAL - diff);
f390d2c7 1452
1453 spftree->pending = 1;
1454 }
1455 else
1456 {
3f045a08 1457 retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
f390d2c7 1458 }
eb5d44eb 1459
1460 return retval;
1461}
eb5d44eb 1462#endif
1463
92365889 1464static void
3f045a08 1465isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
eb5d44eb 1466{
1eb8ef25 1467 struct listnode *node;
3f045a08 1468 struct listnode *anode;
eb5d44eb 1469 struct isis_vertex *vertex;
eb5d44eb 1470 struct isis_adjacency *adj;
eb5d44eb 1471 u_char buff[255];
eb5d44eb 1472
3f045a08
JB
1473 vty_out (vty, "Vertex Type Metric "
1474 "Next-Hop Interface Parent%s", VTY_NEWLINE);
1475
1476 for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) {
1477 if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
1478 vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid),
1479 "", "");
1480 vty_out (vty, "%-30s", "");
1481 } else {
1482 int rows = 0;
1483 vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff),
1484 vtype2string (vertex->type), vertex->d_N);
1485 for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) {
1486 if (adj) {
1487 if (rows) {
1488 vty_out (vty, "%s", VTY_NEWLINE);
1489 vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
1490 }
1491 vty_out (vty, "%-20s %-9s ",
1492 print_sys_hostname (adj->sysid),
1493 adj->circuit->interface->name);
1494 ++rows;
1495 }
1496 }
1497 if (rows == 0)
1498 vty_out (vty, "%-30s ", "");
1499 }
1eb8ef25 1500
3f045a08
JB
1501 /* Print list of parents for the ECMP DAG */
1502 if (listcount (vertex->parents) > 0) {
1503 struct listnode *pnode;
1504 struct isis_vertex *pvertex;
1505 int rows = 0;
1506 for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
1507 if (rows) {
1508 vty_out (vty, "%s", VTY_NEWLINE);
1509 vty_out (vty, "%-72s", "");
1510 }
1511 vty_out (vty, "%s(%d)",
1512 vid2string (pvertex, buff), pvertex->type);
1513 ++rows;
f390d2c7 1514 }
3f045a08
JB
1515 } else {
1516 vty_out (vty, " NULL ");
1517 }
1518
1519#if 0
1520 if (listcount (vertex->children) > 0) {
1521 struct listnode *cnode;
1522 struct isis_vertex *cvertex;
1523 for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) {
1524 vty_out (vty, "%s", VTY_NEWLINE);
1525 vty_out (vty, "%-72s", "");
1526 vty_out (vty, "%s(%d) ",
1527 vid2string (cvertex, buff), cvertex->type);
f390d2c7 1528 }
1529 }
eb5d44eb 1530#endif
3f045a08 1531 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1532 }
eb5d44eb 1533}
1534
1535DEFUN (show_isis_topology,
1536 show_isis_topology_cmd,
1537 "show isis topology",
1538 SHOW_STR
1539 "IS-IS information\n"
1540 "IS-IS paths to Intermediate Systems\n")
1541{
1542 struct listnode *node;
1543 struct isis_area *area;
1544 int level;
f390d2c7 1545
eb5d44eb 1546 if (!isis->area_list || isis->area_list->count == 0)
1547 return CMD_SUCCESS;
1548
1eb8ef25 1549 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1550 {
f390d2c7 1551 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1552 VTY_NEWLINE);
1553
1554 for (level = 0; level < ISIS_LEVELS; level++)
1555 {
1556 if (area->ip_circuits > 0 && area->spftree[level]
1557 && area->spftree[level]->paths->count > 0)
1558 {
1559 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1560 level + 1, VTY_NEWLINE);
3f045a08
JB
1561 isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
1562 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1563 }
eb5d44eb 1564#ifdef HAVE_IPV6
f390d2c7 1565 if (area->ipv6_circuits > 0 && area->spftree6[level]
1566 && area->spftree6[level]->paths->count > 0)
1567 {
1568 vty_out (vty,
1569 "IS-IS paths to level-%d routers that speak IPv6%s",
1570 level + 1, VTY_NEWLINE);
3f045a08
JB
1571 isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
1572 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1573 }
eb5d44eb 1574#endif /* HAVE_IPV6 */
f390d2c7 1575 }
3f045a08
JB
1576
1577 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1578 }
eb5d44eb 1579
1580 return CMD_SUCCESS;
f390d2c7 1581}
eb5d44eb 1582
1583DEFUN (show_isis_topology_l1,
1584 show_isis_topology_l1_cmd,
1585 "show isis topology level-1",
1586 SHOW_STR
1587 "IS-IS information\n"
1588 "IS-IS paths to Intermediate Systems\n"
1589 "Paths to all level-1 routers in the area\n")
1590{
1591 struct listnode *node;
1592 struct isis_area *area;
f390d2c7 1593
eb5d44eb 1594 if (!isis->area_list || isis->area_list->count == 0)
1595 return CMD_SUCCESS;
1596
1eb8ef25 1597 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1598 {
f390d2c7 1599 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1600 VTY_NEWLINE);
1601
1602 if (area->ip_circuits > 0 && area->spftree[0]
1603 && area->spftree[0]->paths->count > 0)
1604 {
1605 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1606 VTY_NEWLINE);
3f045a08
JB
1607 isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
1608 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1609 }
eb5d44eb 1610#ifdef HAVE_IPV6
f390d2c7 1611 if (area->ipv6_circuits > 0 && area->spftree6[0]
1612 && area->spftree6[0]->paths->count > 0)
1613 {
1614 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1615 VTY_NEWLINE);
3f045a08
JB
1616 isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
1617 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1618 }
eb5d44eb 1619#endif /* HAVE_IPV6 */
3f045a08 1620 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1621 }
1622
eb5d44eb 1623 return CMD_SUCCESS;
f390d2c7 1624}
eb5d44eb 1625
1626DEFUN (show_isis_topology_l2,
1627 show_isis_topology_l2_cmd,
1628 "show isis topology level-2",
1629 SHOW_STR
1630 "IS-IS information\n"
1631 "IS-IS paths to Intermediate Systems\n"
1632 "Paths to all level-2 routers in the domain\n")
1633{
1634 struct listnode *node;
1635 struct isis_area *area;
f390d2c7 1636
eb5d44eb 1637 if (!isis->area_list || isis->area_list->count == 0)
1638 return CMD_SUCCESS;
1639
1eb8ef25 1640 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
f390d2c7 1641 {
f390d2c7 1642 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1643 VTY_NEWLINE);
1644
1645 if (area->ip_circuits > 0 && area->spftree[1]
1646 && area->spftree[1]->paths->count > 0)
1647 {
1648 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1649 VTY_NEWLINE);
3f045a08
JB
1650 isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
1651 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1652 }
eb5d44eb 1653#ifdef HAVE_IPV6
f390d2c7 1654 if (area->ipv6_circuits > 0 && area->spftree6[1]
1655 && area->spftree6[1]->paths->count > 0)
1656 {
1657 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1658 VTY_NEWLINE);
3f045a08
JB
1659 isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
1660 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 1661 }
eb5d44eb 1662#endif /* HAVE_IPV6 */
3f045a08 1663 vty_out (vty, "%s", VTY_NEWLINE);
eb5d44eb 1664 }
1665
eb5d44eb 1666 return CMD_SUCCESS;
f390d2c7 1667}
eb5d44eb 1668
1669void
1670isis_spf_cmds_init ()
1671{
1672 install_element (VIEW_NODE, &show_isis_topology_cmd);
1673 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1674 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1675
1676 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1677 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1678 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1679}