blob: 1e414c6ca7352b6b5ba796d90356231210793ac2 [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * IS-IS Rout(e)ing protocol - isis_spf.c
3 * The SPT algorithm
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000027
28#include "thread.h"
29#include "linklist.h"
30#include "vty.h"
31#include "log.h"
32#include "command.h"
33#include "memory.h"
34#include "prefix.h"
35#include "hash.h"
36#include "if.h"
37#include "table.h"
38
39#include "isis_constants.h"
40#include "isis_common.h"
41#include "dict.h"
42#include "isisd.h"
43#include "isis_misc.h"
44#include "isis_adjacency.h"
45#include "isis_circuit.h"
46#include "isis_tlv.h"
47#include "isis_pdu.h"
48#include "isis_lsp.h"
49#include "isis_dynhn.h"
50#include "isis_spf.h"
51#include "isis_route.h"
52#include "isis_csm.h"
53
54extern struct isis *isis;
55extern struct thread_master *master;
56extern struct host host;
57
58int isis_run_spf_l1 (struct thread *thread);
59int isis_run_spf_l2 (struct thread *thread);
60
61/* performace issue ???? */
62void
63union_adjlist( struct list *target, struct list *source )
64{
65 struct isis_adjacency *adj, *adj2;
66 struct listnode *node, *node2;
67
68 zlog_info ("Union adjlist!");
69 for (node = listhead (source); node; nextnode (node)) {
70 adj = getdata (node);
71
72 /* lookup adjacency in the source list */
73 for (node2 = listhead (target); node2; nextnode (node2)) {
74 adj2 = getdata(node2);
75 if (adj == adj2) break;
76 }
77
78 if (!node2) listnode_add (target, adj);
79 }
80}
81
82
83/* 7.2.7 */
84void
85remove_excess_adjs (struct list *adjs)
86{
87 struct listnode *node, *excess = NULL;
88 struct isis_adjacency *adj, *candidate = NULL;
89 int comp;
90
91 for (node = listhead (adjs); node; nextnode (node)) {
92 if (excess == NULL)
93 excess = node;
94 candidate = getdata (excess);
95 adj = getdata (node);
96 if (candidate->sys_type < adj->sys_type) {
97 excess = node;
98 candidate = adj;
99 continue;
100 }
101 if (candidate->sys_type > adj->sys_type)
102 continue;
103
104 comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
105 if (comp > 0) {
106 excess = node;
107 candidate = adj;
108 continue;
109 }
110 if (comp < 0)
111 continue;
112
113 if (candidate->circuit->circuit_id > adj->circuit->circuit_id) {
114 excess = node;
115 candidate = adj;
116 continue;
117 }
118
119 if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
120 continue;
121
122 comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN);
123 if (comp > 0) {
124 excess = node;
125 candidate = adj;
126 continue;
127 }
128 }
129
130 list_delete_node (adjs, excess);
131
132 return;
133}
134
135const char *
136vtype2string (enum vertextype vtype)
137{
138 switch (vtype) {
139 case VTYPE_PSEUDO_IS:
140 return "pseudo_IS";
141 break;
142 case VTYPE_NONPSEUDO_IS:
143 return "IS";
144 break;
145 case VTYPE_ES:
146 return "ES";
147 break;
148 case VTYPE_IPREACH_INTERNAL:
149 return "IP internal";
150 break;
151 case VTYPE_IPREACH_EXTERNAL:
152 return "IP external";
153 break;
154#ifdef HAVE_IPV6
155 case VTYPE_IP6REACH_INTERNAL:
156 return "IP6 internal";
157 break;
158 case VTYPE_IP6REACH_EXTERNAL:
159 return "IP6 external";
160 break;
161#endif /* HAVE_IPV6 */
162 default:
163 return "UNKNOWN";
164 }
165 return NULL; /* Not reached */
166}
167
168char *
169vid2string (struct isis_vertex *vertex, u_char *buff)
170{
171 switch (vertex->type) {
172 case VTYPE_PSEUDO_IS:
173 return rawlspid_print (vertex->N.id);
174 break;
175 case VTYPE_NONPSEUDO_IS:
176 case VTYPE_ES:
177 return sysid_print (vertex->N.id);
178 break;
179 case VTYPE_IPREACH_INTERNAL:
180 case VTYPE_IPREACH_EXTERNAL:
181#ifdef HAVE_IPV6
182 case VTYPE_IP6REACH_INTERNAL:
183 case VTYPE_IP6REACH_EXTERNAL:
184#endif /* HAVE_IPV6 */
185 prefix2str ((struct prefix *)&vertex->N.prefix, buff, BUFSIZ);
186 break;
187 default:
188 return "UNKNOWN";
189 }
190
191 return buff;
192}
193
194struct isis_spftree *
195isis_spftree_new ()
196{
197 struct isis_spftree *tree;
198
199 tree = XMALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
200 if (tree == NULL) {
201 zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
202 return NULL;
203 }
204 memset (tree, 0, sizeof (struct isis_spftree));
205
206 tree->tents = list_new ();
207 tree->paths = list_new ();
208 return tree;
209}
210
211void
212isis_vertex_del (struct isis_vertex *vertex)
213{
214
215 list_delete (vertex->Adj_N);
216
217 XFREE (MTYPE_ISIS_VERTEX, vertex);
218
219 return;
220}
221
222void
223isis_spftree_del (struct isis_spftree *spftree)
224{
225
226 spftree->tents->del = (void *)isis_vertex_del;
227 list_delete (spftree->tents);
228
229 spftree->paths->del = (void *)isis_vertex_del;
230 list_delete (spftree->paths);
231
232 XFREE (MTYPE_ISIS_SPFTREE, spftree);
233
234 return;
235}
236
237void
238spftree_area_init (struct isis_area *area)
239{
240
241 if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL) {
242 area->spftree[0] = isis_spftree_new ();
243#ifdef HAVE_IPV6
244 area->spftree6[0] = isis_spftree_new ();
245#endif
246
247 /* thread_add_timer (master, isis_run_spf_l1, area,
248 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
249 }
250
251 if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL) {
252 area->spftree[1] = isis_spftree_new ();
253#ifdef HAVE_IPV6
254 area->spftree6[1] = isis_spftree_new ();
255#endif
256 /* thread_add_timer (master, isis_run_spf_l2, area,
257 isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
258 }
259
260 return;
261}
262
263struct isis_vertex *
264isis_vertex_new (void *id, enum vertextype vtype)
265{
266 struct isis_vertex *vertex;
267
268 vertex = XMALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex));
269 if (vertex == NULL) {
270 zlog_err ("isis_vertex_new Out of memory!");
271 return NULL;
272 }
273
274 memset (vertex, 0, sizeof (struct isis_vertex));
275 vertex->type = vtype;
276 switch (vtype) {
277 case VTYPE_ES:
278 case VTYPE_NONPSEUDO_IS:
279 memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN);
280 break;
281 case VTYPE_PSEUDO_IS:
282 memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN + 1);
283 break;
284 case VTYPE_IPREACH_INTERNAL:
285 case VTYPE_IPREACH_EXTERNAL:
286#ifdef HAVE_IPV6
287 case VTYPE_IP6REACH_INTERNAL:
288 case VTYPE_IP6REACH_EXTERNAL:
289#endif /* HAVE_IPV6 */
290 memcpy (&vertex->N.prefix, (struct prefix *)id,
291 sizeof (struct prefix));
292 break;
293 default:
294 zlog_err ("WTF!");
295 }
296
297 vertex->Adj_N = list_new ();
298
299 return vertex;
300}
301
302/*
303 * Add this IS to the root of SPT
304 */
305void
306isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
307 int level)
308{
309 struct isis_vertex *vertex;
310 struct isis_lsp *lsp;
311 u_char lspid[ISIS_SYS_ID_LEN + 2];
312#ifdef EXTREME_DEBUG
313 u_char buff[BUFSIZ];
314#endif /* EXTREME_DEBUG */
315 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
316 LSP_PSEUDO_ID(lspid) = 0;
317 LSP_FRAGMENT(lspid) = 0;
318
319 lsp = lsp_search (lspid, area->lspdb[level - 1]);
320
321 if (lsp == NULL)
322 zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
323
324 vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
325 vertex->lsp = lsp;
326
327 listnode_add (spftree->paths, vertex);
328
329#ifdef EXTREME_DEBUG
330 zlog_info ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
331 vtype2string(vertex->type), vid2string(vertex, buff),
332 vertex->depth, vertex->d_N);
333#endif /* EXTREME_DEBUG */
334
335 return;
336}
337
338struct isis_vertex *
339isis_find_vertex (struct list *list, void *id, enum vertextype vtype)
340{
341 struct listnode *node;
342 struct isis_vertex *vertex;
343 struct prefix *p1, *p2;
344
345 for (node = listhead (list); node; nextnode (node)) {
346 vertex = getdata (node);
347 if (vertex->type != vtype)
348 continue;
349 switch (vtype) {
350 case VTYPE_ES:
351 case VTYPE_NONPSEUDO_IS:
352 if (memcmp ((u_char *)id, vertex->N.id, ISIS_SYS_ID_LEN) == 0)
353 return vertex;
354 break;
355 case VTYPE_PSEUDO_IS:
356 if (memcmp ((u_char *)id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0)
357 return vertex;
358 break;
359 case VTYPE_IPREACH_INTERNAL:
360 case VTYPE_IPREACH_EXTERNAL:
361#ifdef HAVE_IPV6
362 case VTYPE_IP6REACH_INTERNAL:
363 case VTYPE_IP6REACH_EXTERNAL:
364#endif /* HAVE_IPV6 */
365 p1 = (struct prefix *)id;
366 p2 = (struct prefix *)&vertex->N.id;
367 if (p1->family == p2->family && p1->prefixlen == p2->prefixlen &&
368 memcmp (&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)) == 0)
369 return vertex;
370 break;
371 }
372 }
373
374 return NULL;
375}
376
377
378
379/*
380 * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
381 */
382struct isis_vertex *
383isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
384 void *id, struct isis_adjacency *adj, u_int16_t cost,
385 int depth, int family)
386{
387 struct isis_vertex *vertex, *v;
388 struct listnode *node;
389#ifdef EXTREME_DEBUG
390 u_char buff[BUFSIZ];
391#endif
392
393 vertex = isis_vertex_new (id, vtype);
394 vertex->d_N = cost;
395 vertex->depth = depth;
396
397 if (adj)
398 listnode_add (vertex->Adj_N, adj);
399#ifdef EXTREME_DEBUG
400 zlog_info ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
401 vtype2string(vertex->type), vid2string(vertex, buff),
402 vertex->depth, vertex->d_N);
403#endif /* EXTREME_DEBUG */
404 listnode_add (spftree->tents, vertex);
405 if (list_isempty (spftree->tents)) {
406 listnode_add (spftree->tents, vertex);
407 return vertex;
408 }
409 for (node = listhead (spftree->tents); node; nextnode (node)) {
410 v = getdata (node);
411 if (v->d_N > vertex->d_N) {
412 list_add_node_prev (spftree->tents, node, vertex);
413 break;
414 } else if (v->d_N == vertex->d_N) {
415 /* Tie break, add according to type */
416 while (v && v->d_N == vertex->d_N && v->type > vertex->type) {
417 if (v->type > vertex->type) {
418 break;
419 }
420 nextnode (node);
421 (node) ? (v = getdata (node)) : (v = NULL);
422 }
423 list_add_node_prev (spftree->tents, node, vertex);
424 break;
425 } else if (node->next == NULL) {
426 list_add_node_next (spftree->tents, node, vertex);
427 break;
428 }
429 }
430 return vertex;
431}
432
433struct isis_vertex *
434isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
435 void *id, struct isis_adjacency *adj, u_int16_t cost,
436 int family)
437{
438 struct isis_vertex *vertex;
439
440 vertex = isis_find_vertex (spftree->tents, id, vtype);
441
442 if (vertex) {
443 /* C.2.5 c) */
444 if (vertex->d_N == cost) {
445 if (adj)
446 listnode_add (vertex->Adj_N, adj);
447 /* d) */
448 if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
449 remove_excess_adjs (vertex->Adj_N);
450 }
451 /* f) */
452 else if (vertex->d_N > cost) {
453 listnode_delete (spftree->tents, vertex);
454 goto add2tent;
455 }
456 /* e) do nothing */
457 return vertex;
458 }
459
460 add2tent:
461 return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
462}
463
464void
465process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
466 u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
467 int family)
468{
469 struct isis_vertex *vertex;
470#ifdef EXTREME_DEBUG
471 u_char buff[255];
472#endif
473
474 /* C.2.6 b) */
475 if (dist > MAX_PATH_METRIC)
476 return;
477 /* c) */
478 vertex = isis_find_vertex (spftree->paths, id, vtype);
479 if (vertex) {
480#ifdef EXTREME_DEBUG
481 zlog_info ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
482 vtype2string(vtype), vid2string(vertex, buff), dist);
483#endif /* EXTREME_DEBUG */
484 assert (dist >= vertex->d_N);
485 return;
486 }
487
488 vertex = isis_find_vertex (spftree->tents, id, vtype);
489 /* d) */
490 if (vertex) {
491 /* 1) */
492#ifdef EXTREME_DEBUG
493 zlog_info ("ISIS-Spf: process_N %s %s dist %d",
494 vtype2string(vtype), vid2string(vertex, buff), dist);
495#endif /* EXTREME_DEBUG */
496 if (vertex->d_N == dist) {
497 if (adj)
498 listnode_add (vertex->Adj_N, adj);
499 /* 2) */
500 if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
501 remove_excess_adjs (vertex->Adj_N);
502 /* 3) */
503 return;
504 } else if (vertex->d_N < dist) {
505 return;
506 /* 4) */
507 } else {
508 listnode_delete (spftree->tents, vertex);
509 }
510 }
511
512 isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
513 return;
514}
515
516/*
517 * C.2.6 Step 1
518 */
519int
520isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
521 uint16_t cost, uint16_t depth, int family)
522{
523 struct listnode *node, *fragnode = NULL;
524 u_int16_t dist;
525 struct is_neigh *is_neigh;
526 struct ipv4_reachability *ipreach;
527 enum vertextype vtype;
528 struct prefix prefix;
529#ifdef HAVE_IPV6
530 struct ipv6_reachability *ip6reach;
531#endif /* HAVE_IPV6 */
532
533
534 if (!lsp->adj)
535 return ISIS_WARNING;
536 if (lsp->tlv_data.nlpids == NULL ||
537 !speaks (lsp->tlv_data.nlpids, family))
538 return ISIS_OK;
539
540 lspfragloop:
541 if (lsp->lsp_header->seq_num == 0) {
542 zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
543 " - do not process");
544 return ISIS_WARNING;
545 }
546
547 if (!ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits)) {
548 if (lsp->tlv_data.is_neighs) {
549 for (node = listhead (lsp->tlv_data.is_neighs); node; nextnode (node)) {
550 is_neigh = getdata (node);
551 /* C.2.6 a) */
552 /* Two way connectivity */
553 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
554 continue;
555 dist = cost + is_neigh->metrics.metric_default;
556 vtype = LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
557 : VTYPE_NONPSEUDO_IS;
558 process_N (spftree, vtype, (void *)is_neigh->neigh_id, dist, depth+1,
559 lsp->adj, family);
560 }
561 }
562 if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) {
563 prefix.family = AF_INET;
564 for (node = listhead (lsp->tlv_data.ipv4_int_reachs); node;
565 nextnode (node)) {
566 ipreach = getdata (node);
567 dist = cost + ipreach->metrics.metric_default;
568 vtype = VTYPE_IPREACH_INTERNAL;
569 prefix.u.prefix4 = ipreach->prefix;
570 prefix.prefixlen = ip_masklen (ipreach->mask);
571 process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
572 lsp->adj, family);
573 }
574 }
575
576 if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) {
577 prefix.family = AF_INET;
578 for (node = listhead (lsp->tlv_data.ipv4_ext_reachs); node;
579 nextnode (node)) {
580 ipreach = getdata (node);
581 dist = cost + ipreach->metrics.metric_default;
582 vtype = VTYPE_IPREACH_EXTERNAL;
583 prefix.u.prefix4 = ipreach->prefix;
584 prefix.prefixlen = ip_masklen (ipreach->mask);
585 process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
586 lsp->adj, family);
587 }
588 }
589#ifdef HAVE_IPV6
590 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) {
591 prefix.family = AF_INET6;
592 for (node = listhead (lsp->tlv_data.ipv6_reachs); node;
593 nextnode (node)) {
594 ip6reach = getdata (node);
595 dist = cost + ip6reach->metric;
596 vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
597 VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
598 prefix.prefixlen = ip6reach->prefix_len;
599 memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
600 PSIZE(ip6reach->prefix_len));
601 process_N (spftree, vtype, (void *)&prefix, dist, depth + 1,
602 lsp->adj, family);
603 }
604 }
605#endif /* HAVE_IPV6 */
606 }
607
608 if (fragnode == NULL)
609 fragnode = listhead (lsp->lspu.frags);
610 else
611 fragnode = nextnode (fragnode);
612
613 if (fragnode) {
614 lsp = getdata (fragnode);
615 goto lspfragloop;
616 }
617
618 return ISIS_OK;
619}
620
621int
622isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,struct isis_lsp *lsp,
623 uint16_t cost, uint16_t depth, int family)
624{
625 struct listnode *node, *fragnode = NULL;
626 struct is_neigh *is_neigh;
627 enum vertextype vtype;
628
629 pseudofragloop:
630
631 if (lsp->lsp_header->seq_num == 0) {
632 zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num"
633 " - do not process");
634 return ISIS_WARNING;
635 }
636
637 for (node = (lsp->tlv_data.is_neighs ?
638 listhead (lsp->tlv_data.is_neighs) : NULL);
639 node; nextnode (node)) {
640 is_neigh = getdata (node);
641 vtype = LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
642 : VTYPE_NONPSEUDO_IS;
643 /* Two way connectivity */
644 if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
645 continue;
646 if (isis_find_vertex (spftree->tents, (void *)is_neigh->neigh_id, vtype)
647 == NULL &&
648 isis_find_vertex (spftree->paths, (void *)is_neigh->neigh_id, vtype)
649 == NULL) {
650 /* C.2.5 i) */
651 isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj,
652 cost, depth, family);
653 }
654 }
655
656 if (fragnode == NULL)
657 fragnode = listhead (lsp->lspu.frags);
658 else
659 fragnode = nextnode (fragnode);
660
661 if (fragnode) {
662 lsp = getdata (fragnode);
663 goto pseudofragloop;
664 }
665
666
667 return ISIS_OK;
668}
669
670int
671isis_spf_preload_tent (struct isis_spftree *spftree,
672 struct isis_area *area, int level, int family)
673{
674 struct isis_vertex *vertex;
675 struct isis_circuit *circuit;
676 struct listnode *cnode, *anode, *ipnode;
677 struct isis_adjacency *adj;
678 struct isis_lsp *lsp;
679 struct list *adj_list;
680 struct list *adjdb;
681 struct prefix_ipv4 *ipv4;
682 struct prefix prefix;
683 int retval = ISIS_OK;
684 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
685#ifdef HAVE_IPV6
686 struct prefix_ipv6 *ipv6;
687#endif /* HAVE_IPV6 */
688
689 for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode)) {
690 circuit = getdata (cnode);
691 if (circuit->state != C_STATE_UP)
692 continue;
693 if (!(circuit->circuit_is_type & level))
694 continue;
695 if (family == AF_INET && !circuit->ip_router)
696 continue;
697#ifdef HAVE_IPV6
698 if (family == AF_INET6 && !circuit->ipv6_router)
699 continue;
700#endif /* HAVE_IPV6 */
701 /*
702 * Add IP(v6) addresses of this circuit
703 */
704 if (family == AF_INET) {
705 prefix.family = AF_INET;
706 for (ipnode = (circuit->ip_addrs ? listhead (circuit->ip_addrs) : NULL);
707 ipnode; nextnode (ipnode)) {
708 ipv4 = getdata (ipnode);
709 prefix.u.prefix4 = ipv4->prefix;
710 prefix.prefixlen = ipv4->prefixlen;
711 isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, NULL, 0,
712 family);
713 }
714 }
715#ifdef HAVE_IPV6
716 if (family == AF_INET6) {
717 prefix.family = AF_INET6;
718 for (ipnode = (circuit->ipv6_non_link ? listhead
719 (circuit->ipv6_non_link) : NULL); ipnode;
720 nextnode (ipnode)) {
721 ipv6 = getdata (ipnode);
722 prefix.prefixlen = ipv6->prefixlen;
723 prefix.u.prefix6 = ipv6->prefix;
724 isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
725 &prefix, NULL, 0, family);
726 }
727 }
728#endif /* HAVE_IPV6 */
729 if (circuit->circ_type == CIRCUIT_T_BROADCAST ) {
730 /*
731 * Add the adjacencies
732 */
733 adj_list = list_new ();
734 adjdb = circuit->u.bc.adjdb[level - 1];
735 isis_adj_build_up_list (adjdb, adj_list);
736 if (listcount (adj_list) == 0) {
737 list_delete (adj_list);
738 zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s",
739 level, circuit->interface->name);
740 continue;
741 }
742 anode = listhead (adj_list);
743 while (anode) {
744 adj = getdata (anode);
hasso2097cd82003-12-23 11:51:08 +0000745 if (!speaks (&adj->nlpids, family)) {
746 anode = nextnode (anode);
jardineb5d44e2003-12-23 08:09:43 +0000747 continue;
hasso2097cd82003-12-23 11:51:08 +0000748 }
jardineb5d44e2003-12-23 08:09:43 +0000749 switch (adj->sys_type) {
750 case ISIS_SYSTYPE_ES:
751 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
752 circuit->metrics[level - 1].metric_default,
753 family);
754 break;
755 case ISIS_SYSTYPE_IS:
756 case ISIS_SYSTYPE_L1_IS:
757 case ISIS_SYSTYPE_L2_IS:
758 vertex =
759 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
760 adj->sysid, adj,
761 circuit->metrics[level - 1].metric_default,
762 family);
763 memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
764 LSP_PSEUDO_ID(lsp_id) = 0;
765 LSP_FRAGMENT(lsp_id) = 0;
766 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
767 if (!lsp)
768 zlog_warn ("No lsp found for IS adjacency");
769 /* else {
770 isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family);
771 } */
772 break;
773 case ISIS_SYSTYPE_UNKNOWN:
774 default:
775 zlog_warn ("isis_spf_preload_tent unknow adj type");
776 }
777 anode = nextnode (anode);
778 }
779 list_delete (adj_list);
780 /*
781 * Add the pseudonode
782 */
783 if (level == 1)
784 memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
785 else
786 memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
787 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
788 adj = isis_adj_lookup (lsp_id, adjdb);
789 /* if no adj, we are the dis or error */
790 if (!adj && !circuit->u.bc.is_dr[level - 1]) {
791 zlog_warn ("ISIS-Spf: No adjacency found for DR");
792 }
793 if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) {
794 zlog_warn ("ISIS-Spf: No lsp found for DR");
795 } else {
796 isis_spf_process_pseudo_lsp
797 (spftree, lsp, circuit->metrics[level - 1].metric_default, 0,
798 family);
799
800 }
801 } else if (circuit->circ_type == CIRCUIT_T_P2P ) {
802 adj = circuit->u.p2p.neighbor;
803 if (!adj)
804 continue;
805 switch (adj->sys_type) {
806 case ISIS_SYSTYPE_ES:
807 isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
808 circuit->metrics[level - 1].metric_default,
809 family);
810 break;
811 case ISIS_SYSTYPE_IS:
812 case ISIS_SYSTYPE_L1_IS:
813 case ISIS_SYSTYPE_L2_IS:
814 if (speaks (&adj->nlpids, family))
815 isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid, adj,
816 circuit->metrics[level - 1].metric_default,
817 family);
818 break;
819 case ISIS_SYSTYPE_UNKNOWN:
820 default:
821 zlog_warn ("isis_spf_preload_tent unknow adj type");
822 break;
823 }
824 } else {
825 zlog_warn ("isis_spf_preload_tent unsupported media");
826 retval = ISIS_WARNING;
827 }
828
829 }
830
831 return retval;
832}
833
834/*
835 * The parent(s) for vertex is set when added to TENT list
836 * now we just put the child pointer(s) in place
837 */
838void
839add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
840 struct isis_area *area)
841{
842
843#ifdef EXTREME_DEBUG
844 u_char buff[BUFSIZ];
845#endif /* EXTREME_DEBUG */
846 listnode_add (spftree->paths, vertex);
847
848#ifdef EXTREME_DEBUG
849 zlog_info ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
850 vtype2string(vertex->type), vid2string(vertex, buff),
851 vertex->depth, vertex->d_N);
852#endif /* EXTREME_DEBUG */
853 if (vertex->type > VTYPE_ES) {
854 if (listcount(vertex->Adj_N) > 0)
855 isis_route_create ((struct prefix *)&vertex->N.prefix,
856 vertex->d_N, vertex->depth, vertex->Adj_N, area);
857 else if (isis->debugs & DEBUG_SPF_EVENTS)
858 zlog_info ("ISIS-Spf: no adjacencies do not install route");
859 }
860
861 return;
862}
863
864
865void
866init_spt (struct isis_spftree *spftree)
867{
868 spftree->tents->del = spftree->paths->del = (void *)isis_vertex_del;
869 list_delete_all_node (spftree->tents);
870 list_delete_all_node (spftree->paths);
871 spftree->tents->del = spftree->paths->del = NULL;
872
873 return;
874}
875
876int
877isis_run_spf (struct isis_area *area, int level, int family)
878{
879 int retval = ISIS_OK;
880 struct listnode *node;
881 struct isis_vertex *vertex;
882 struct isis_spftree *spftree = NULL;
883 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
884 struct isis_lsp *lsp;
885
886 if (family == AF_INET)
887 spftree = area->spftree[level - 1];
888#ifdef HAVE_IPV6
889 else if (family == AF_INET6)
890 spftree = area->spftree6[level - 1];
891#endif
892
893 assert (spftree);
894
895 /*
896 * C.2.5 Step 0
897 */
898 init_spt (spftree);
899 /* a) */
900 isis_spf_add_self (spftree, area, level);
901 /* b) */
902 retval = isis_spf_preload_tent (spftree, area, level, family);
903
904 /*
905 * C.2.7 Step 2
906 */
907 if (listcount (spftree->tents) == 0) {
908 zlog_warn ("ISIS-Spf: TENT is empty");
909 spftree->lastrun = time (NULL);
910 return retval;
911 }
912
913 while (listcount (spftree->tents) > 0) {
914 node = listhead (spftree->tents);
915 vertex = getdata (node);
916 /* Remove from tent list */
917 list_delete_node (spftree->tents, node);
918 if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
919 continue;
920 add_to_paths (spftree, vertex, area);
921 if (vertex->type == VTYPE_PSEUDO_IS ||
922 vertex->type == VTYPE_NONPSEUDO_IS) {
923 memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
924 LSP_FRAGMENT(lsp_id) = 0;
925 lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
926 if (lsp) {
927 if (LSP_PSEUDO_ID (lsp_id)) {
928 isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
929 vertex->depth, family);
930
931 } else {
932 isis_spf_process_lsp (spftree, lsp, vertex->d_N, vertex->depth,
933 family);
934 }
935 } else {
936 zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id));
937 }
938 }
939 }
940
941 thread_add_event (master, isis_route_validate, area, 0);
942 spftree->lastrun = time (NULL);
943 spftree->pending = 0;
944
hasso62843e42004-05-19 18:45:03 +0000945 if (level == 1) {
946 /* FIXME: Should do it earlier. */
947 spftree->t_spf_periodic = NULL;
hassod70f99e2004-02-11 20:26:31 +0000948 THREAD_TIMER_ON(master, spftree->t_spf_periodic, isis_run_spf_l1, area,
949 isis_jitter(PERIODIC_SPF_INTERVAL, 10));
hasso62843e42004-05-19 18:45:03 +0000950 }
951 else {
952 /* FIXME: Should do it earlier. */
953 spftree->t_spf_periodic = NULL;
hassod70f99e2004-02-11 20:26:31 +0000954 THREAD_TIMER_ON(master, spftree->t_spf_periodic, isis_run_spf_l2, area,
955 isis_jitter(PERIODIC_SPF_INTERVAL, 10));
hasso62843e42004-05-19 18:45:03 +0000956 }
jardineb5d44e2003-12-23 08:09:43 +0000957
958 return retval;
959}
960
961int
962isis_run_spf_l1 (struct thread *thread)
963{
964 struct isis_area *area;
965 int retval = ISIS_OK;
966
967 area = THREAD_ARG(thread);
968 assert (area);
969
970 if (!(area->is_type & IS_LEVEL_1)) {
971 if (isis->debugs & DEBUG_SPF_EVENTS) {
972 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
973 }
974 return ISIS_WARNING;
975 }
976
977 if (isis->debugs & DEBUG_SPF_EVENTS) {
978 zlog_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF",
979 area->area_tag);
980 }
981
982 if (area->ip_circuits)
983 retval = isis_run_spf (area, 1, AF_INET);
984#ifdef HAVE_IPV6
985 if (area->ipv6_circuits)
986 retval = isis_run_spf (area, 1, AF_INET6);
987#endif
988 return retval;
989}
990
991int
992isis_run_spf_l2 (struct thread *thread)
993{
994 struct isis_area *area;
995 int retval = ISIS_OK;
996
997 area = THREAD_ARG(thread);
998 assert (area);
999
1000 if (!(area->is_type & IS_LEVEL_2)) {
1001 if (isis->debugs & DEBUG_SPF_EVENTS) {
1002 zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
1003 }
1004 return ISIS_WARNING;
1005 }
1006
1007 if (isis->debugs & DEBUG_SPF_EVENTS) {
1008 zlog_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF",
1009 area->area_tag);
1010 }
1011
1012 if (area->ip_circuits)
1013 retval = isis_run_spf (area, 2, AF_INET);
1014#ifdef HAVE_IPV6
1015 if (area->ipv6_circuits)
1016 retval = isis_run_spf (area, 2, AF_INET6);
1017#endif
1018
1019 return retval;
1020}
1021
1022int
1023isis_spf_schedule (struct isis_area *area, int level)
1024{
1025 int retval = ISIS_OK;
1026 struct isis_spftree *spftree = area->spftree[level - 1];
1027 time_t diff, now = time (NULL);
1028
1029 if (spftree->pending)
1030 return retval;
1031
1032 diff = now - spftree->lastrun;
1033
1034 /* FIXME: let's wait a minute before doing the SPF */
1035 if (now - isis->uptime < 60 || isis->uptime == 0) {
1036 if (level == 1)
1037 thread_add_timer (master, isis_run_spf_l1, area,
1038 60);
1039 else
1040 thread_add_timer (master, isis_run_spf_l2, area,
1041 60);
1042
1043 spftree->pending = 1;
1044 return retval;
1045 }
hasso00995cf2004-05-19 13:43:50 +00001046 /* FIXME: This stuff is just mess. All spf thread add/cancel
1047 logic should be reviewed. */
hasso62843e42004-05-19 18:45:03 +00001048 THREAD_TIMER_OFF(spftree->t_spf_periodic);
jardineb5d44e2003-12-23 08:09:43 +00001049
1050 if (diff < MINIMUM_SPF_INTERVAL) {
1051 if (level == 1)
1052 thread_add_timer (master, isis_run_spf_l1, area,
1053 MINIMUM_SPF_INTERVAL - diff);
1054 else
1055 thread_add_timer (master, isis_run_spf_l2, area,
1056 MINIMUM_SPF_INTERVAL - diff);
1057
1058 spftree->pending = 1;
1059 } else {
1060 spftree->pending = 0;
1061 retval = isis_run_spf (area, level, AF_INET);
1062 }
1063
1064 return retval;
1065}
1066
1067#ifdef HAVE_IPV6
1068int
1069isis_spf_schedule6 (struct isis_area *area, int level)
1070{
1071 int retval = ISIS_OK;
1072 struct isis_spftree *spftree = area->spftree6[level - 1];
1073 time_t diff, now = time (NULL);
1074
1075 if (spftree->pending)
1076 return retval;
1077
1078 diff = now - spftree->lastrun;
1079
hassod70f99e2004-02-11 20:26:31 +00001080 THREAD_TIMER_OFF(spftree->t_spf_periodic);
jardineb5d44e2003-12-23 08:09:43 +00001081
1082 /* FIXME: let's wait a minute before doing the SPF */
1083 if (now - isis->uptime < 60 || isis->uptime == 0) {
1084 if (level == 1)
1085 thread_add_timer (master, isis_run_spf_l1, area,
1086 60);
1087 else
1088 thread_add_timer (master, isis_run_spf_l2, area,
1089 60);
1090
1091 spftree->pending = 1;
1092 return retval;
1093 }
1094
1095
1096 if (diff < MINIMUM_SPF_INTERVAL) {
1097 if (level == 1)
1098 thread_add_timer (master, isis_run_spf_l1, area,
1099 MINIMUM_SPF_INTERVAL - diff);
1100 else
1101 thread_add_timer (master, isis_run_spf_l2, area,
1102 MINIMUM_SPF_INTERVAL - diff);
1103
1104 spftree->pending = 1;
1105 } else {
1106 spftree->pending = 0;
1107 retval = isis_run_spf (area, level, AF_INET6);
1108 }
1109
1110 return retval;
1111}
1112
1113#endif
1114
1115void
1116isis_print_paths (struct vty *vty, struct list *paths)
1117{
1118 struct listnode *node, *anode;
1119 struct isis_vertex *vertex;
1120 struct isis_dynhn *dyn, *nh_dyn = NULL;
1121 struct isis_adjacency *adj;
1122#ifdef EXTREME_DEBUG
1123 u_char buff[255];
1124#endif
1125
1126 vty_out (vty, "System Id Metric Next-Hop"
1127 " Interface SNPA%s", VTY_NEWLINE);
1128 for (node = listhead (paths); node; nextnode (node)) {
1129 vertex = getdata (node);
1130 if (vertex->type != VTYPE_NONPSEUDO_IS)
1131 continue;
1132 if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
1133 vty_out (vty, "%s --%s", host.name, VTY_NEWLINE);
1134 } else {
1135 dyn = dynhn_find_by_id ((u_char *)vertex->N.id);
1136 anode = listhead (vertex->Adj_N);
1137 adj = getdata (anode);
1138 if (adj) {
1139 nh_dyn = dynhn_find_by_id (adj->sysid);
1140 vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
1141 (dyn != NULL) ? dyn->name.name :
1142 (u_char *)rawlspid_print ((u_char *)vertex->N.id),
1143 vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
1144 (u_char *)rawlspid_print (adj->sysid),
1145 adj->circuit->interface->name,
1146 snpa_print (adj->snpa), VTY_NEWLINE);
1147 } else {
1148 vty_out (vty, "%s %u %s", dyn ? dyn->name.name :
1149 (u_char *)rawlspid_print (vertex->N.id),
1150 vertex->d_N, VTY_NEWLINE);
1151 }
1152
1153 }
1154#if 0
1155 vty_out (vty, "%s %s %u %s", vtype2string(vertex->type),
1156 vid2string(vertex, buff), vertex->d_N, VTY_NEWLINE);
1157#endif
1158 }
1159
1160
1161}
1162
1163DEFUN (show_isis_topology,
1164 show_isis_topology_cmd,
1165 "show isis topology",
1166 SHOW_STR
1167 "IS-IS information\n"
1168 "IS-IS paths to Intermediate Systems\n")
1169{
1170 struct listnode *node;
1171 struct isis_area *area;
1172 int level;
1173
1174 if (!isis->area_list || isis->area_list->count == 0)
1175 return CMD_SUCCESS;
1176
1177 for (node = listhead (isis->area_list); node; nextnode (node)) {
1178 area = getdata (node);
1179
1180 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1181 VTY_NEWLINE);
1182
1183 for (level=0; level < ISIS_LEVELS; level++) {
1184 if (area->ip_circuits > 0 && area->spftree[level]
1185 && area->spftree[level]->paths->count > 0) {
1186 vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
1187 level+1, VTY_NEWLINE);
1188 isis_print_paths (vty, area->spftree[level]->paths);
1189 }
1190#ifdef HAVE_IPV6
1191 if (area->ipv6_circuits > 0 && area->spftree6[level]
1192 && area->spftree6[level]->paths->count > 0) {
1193 vty_out (vty, "IS-IS paths to level-%d routers that speak IPv6%s",
1194 level+1, VTY_NEWLINE);
1195 isis_print_paths (vty, area->spftree6[level]->paths);
1196 }
1197#endif /* HAVE_IPV6 */
1198 }
1199 }
1200
1201 return CMD_SUCCESS;
1202}
1203
1204
1205DEFUN (show_isis_topology_l1,
1206 show_isis_topology_l1_cmd,
1207 "show isis topology level-1",
1208 SHOW_STR
1209 "IS-IS information\n"
1210 "IS-IS paths to Intermediate Systems\n"
1211 "Paths to all level-1 routers in the area\n")
1212{
1213 struct listnode *node;
1214 struct isis_area *area;
1215
1216 if (!isis->area_list || isis->area_list->count == 0)
1217 return CMD_SUCCESS;
1218
1219 for (node = listhead (isis->area_list); node; nextnode (node)) {
1220 area = getdata (node);
1221
1222 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1223 VTY_NEWLINE);
1224
1225 if (area->ip_circuits > 0 && area->spftree[0]
1226 && area->spftree[0]->paths->count > 0) {
1227 vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
1228 VTY_NEWLINE);
1229 isis_print_paths (vty, area->spftree[0]->paths);
1230 }
1231#ifdef HAVE_IPV6
1232 if (area->ipv6_circuits > 0 && area->spftree6[0]
1233 && area->spftree6[0]->paths->count > 0) {
1234 vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
1235 VTY_NEWLINE);
1236 isis_print_paths (vty, area->spftree6[0]->paths);
1237 }
1238#endif /* HAVE_IPV6 */
1239 }
1240
1241
1242 return CMD_SUCCESS;
1243}
1244
1245DEFUN (show_isis_topology_l2,
1246 show_isis_topology_l2_cmd,
1247 "show isis topology level-2",
1248 SHOW_STR
1249 "IS-IS information\n"
1250 "IS-IS paths to Intermediate Systems\n"
1251 "Paths to all level-2 routers in the domain\n")
1252{
1253 struct listnode *node;
1254 struct isis_area *area;
1255
1256 if (!isis->area_list || isis->area_list->count == 0)
1257 return CMD_SUCCESS;
1258
1259 for (node = listhead (isis->area_list); node; nextnode (node)) {
1260 area = getdata (node);
1261
1262 vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
1263 VTY_NEWLINE);
1264
1265 if (area->ip_circuits > 0 && area->spftree[1]
1266 && area->spftree[1]->paths->count > 0) {
1267 vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
1268 VTY_NEWLINE);
1269 isis_print_paths (vty, area->spftree[1]->paths);
1270 }
1271#ifdef HAVE_IPV6
1272 if (area->ipv6_circuits > 0 && area->spftree6[1]
1273 && area->spftree6[1]->paths->count > 0) {
1274 vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
1275 VTY_NEWLINE);
1276 isis_print_paths (vty, area->spftree6[1]->paths);
1277 }
1278#endif /* HAVE_IPV6 */
1279 }
1280
1281
1282 return CMD_SUCCESS;
1283}
1284
1285
1286void
1287isis_spf_cmds_init ()
1288{
1289 install_element (VIEW_NODE, &show_isis_topology_cmd);
1290 install_element (VIEW_NODE, &show_isis_topology_l1_cmd);
1291 install_element (VIEW_NODE, &show_isis_topology_l2_cmd);
1292
1293 install_element (ENABLE_NODE, &show_isis_topology_cmd);
1294 install_element (ENABLE_NODE, &show_isis_topology_l1_cmd);
1295 install_element (ENABLE_NODE, &show_isis_topology_l2_cmd);
1296}