[vty] CMD_AS_RANGE accidently quoted and so not expanded in vty
[jleu-quagga.git] / ospf6d / ospf6_spf.c
blob08c1eb73bc070e4cbd2df5272653d5f1ee05e4b8
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 /* Shortest Path First calculation for OSPFv3 */
24 #include <zebra.h>
26 #include "log.h"
27 #include "memory.h"
28 #include "command.h"
29 #include "vty.h"
30 #include "prefix.h"
31 #include "pqueue.h"
32 #include "linklist.h"
33 #include "thread.h"
35 #include "ospf6_lsa.h"
36 #include "ospf6_lsdb.h"
37 #include "ospf6_route.h"
38 #include "ospf6_area.h"
39 #include "ospf6_spf.h"
40 #include "ospf6_intra.h"
41 #include "ospf6_interface.h"
42 #include "ospf6d.h"
44 unsigned char conf_debug_ospf6_spf = 0;
46 int
47 ospf6_vertex_cmp (void *a, void *b)
49 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
50 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
52 /* ascending order */
53 return (va->cost - vb->cost);
56 int
57 ospf6_vertex_id_cmp (void *a, void *b)
59 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
60 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
61 int ret = 0;
63 ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
64 ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
65 if (ret)
66 return ret;
68 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
69 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
70 return ret;
73 struct ospf6_vertex *
74 ospf6_vertex_create (struct ospf6_lsa *lsa)
76 struct ospf6_vertex *v;
77 int i;
79 v = (struct ospf6_vertex *)
80 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
82 /* type */
83 if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
84 v->type = OSPF6_VERTEX_TYPE_ROUTER;
85 else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
86 v->type = OSPF6_VERTEX_TYPE_NETWORK;
87 else
88 assert (0);
90 /* vertex_id */
91 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
92 &v->vertex_id);
94 /* name */
95 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
97 /* Associated LSA */
98 v->lsa = lsa;
100 /* capability bits + options */
101 v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
102 v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
103 v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
104 v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
106 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
107 ospf6_nexthop_clear (&v->nexthop[i]);
109 v->parent = NULL;
110 v->child_list = list_new ();
111 v->child_list->cmp = ospf6_vertex_id_cmp;
113 return v;
116 void
117 ospf6_vertex_delete (struct ospf6_vertex *v)
119 list_delete (v->child_list);
120 XFREE (MTYPE_OSPF6_VERTEX, v);
123 struct ospf6_lsa *
124 ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
126 struct ospf6_lsa *lsa;
127 u_int16_t type = 0;
128 u_int32_t id = 0, adv_router = 0;
130 if (VERTEX_IS_TYPE (NETWORK, v))
132 type = htons (OSPF6_LSTYPE_ROUTER);
133 id = htonl (0);
134 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
136 else
138 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
140 type = htons (OSPF6_LSTYPE_ROUTER);
141 id = htonl (0);
142 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
144 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
146 type = htons (OSPF6_LSTYPE_NETWORK);
147 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
148 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
152 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
154 if (IS_OSPF6_DEBUG_SPF (PROCESS))
156 char ibuf[16], abuf[16];
157 inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
158 inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
159 if (lsa)
160 zlog_debug (" Link to: %s", lsa->name);
161 else
162 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
163 ospf6_lstype_name (type), ibuf, abuf);
166 return lsa;
169 char *
170 ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
171 caddr_t lsdesc, struct ospf6_vertex *v)
173 caddr_t backlink, found = NULL;
174 int size;
176 size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
177 sizeof (struct ospf6_router_lsdesc) :
178 sizeof (struct ospf6_network_lsdesc));
179 for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
180 backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
182 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
183 VERTEX_IS_TYPE (NETWORK, v)));
185 if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
186 NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
187 == v->lsa->header->adv_router)
188 found = backlink;
189 else if (VERTEX_IS_TYPE (NETWORK, v) &&
190 ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
191 ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
192 == v->lsa->header->adv_router &&
193 ROUTER_LSDESC_GET_NBR_IFID (backlink)
194 == ntohl (v->lsa->header->id))
195 found = backlink;
196 else
198 if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
199 ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
200 continue;
201 if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
202 ROUTER_LSDESC_GET_IFID (lsdesc) ||
203 ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
204 ROUTER_LSDESC_GET_IFID (backlink))
205 continue;
206 if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
207 v->lsa->header->adv_router ||
208 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
209 lsa->header->adv_router)
210 continue;
211 found = backlink;
215 if (IS_OSPF6_DEBUG_SPF (PROCESS))
216 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
218 return found;
221 void
222 ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
223 caddr_t lsdesc)
225 int i, ifindex;
226 struct ospf6_interface *oi;
227 u_int16_t type;
228 u_int32_t adv_router;
229 struct ospf6_lsa *lsa;
230 struct ospf6_link_lsa *link_lsa;
231 char buf[64];
233 assert (VERTEX_IS_TYPE (ROUTER, w));
234 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
235 ROUTER_LSDESC_GET_IFID (lsdesc));
236 oi = ospf6_interface_lookup_by_ifindex (ifindex);
237 if (oi == NULL)
239 if (IS_OSPF6_DEBUG_SPF (PROCESS))
240 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
241 return;
244 type = htons (OSPF6_LSTYPE_LINK);
245 adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
246 NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
247 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
249 i = 0;
250 for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
251 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
253 if (VERTEX_IS_TYPE (ROUTER, v) &&
254 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
255 continue;
257 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
258 if (IS_OSPF6_DEBUG_SPF (PROCESS))
260 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
261 zlog_debug (" nexthop %s from %s", buf, lsa->name);
264 if (i < OSPF6_MULTI_PATH_LIMIT)
266 memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
267 sizeof (struct in6_addr));
268 w->nexthop[i].ifindex = ifindex;
269 i++;
273 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
274 zlog_debug ("No nexthop for %s found", w->name);
278 ospf6_spf_install (struct ospf6_vertex *v,
279 struct ospf6_route_table *result_table)
281 struct ospf6_route *route;
282 int i, j;
283 struct ospf6_vertex *prev, *w;
284 struct listnode *node, *nnode;
286 if (IS_OSPF6_DEBUG_SPF (PROCESS))
287 zlog_debug ("SPF install %s hops %d cost %d",
288 v->name, v->hops, v->cost);
290 route = ospf6_route_lookup (&v->vertex_id, result_table);
291 if (route && route->path.cost < v->cost)
293 if (IS_OSPF6_DEBUG_SPF (PROCESS))
294 zlog_debug (" already installed with lower cost (%d), ignore",
295 route->path.cost);
296 ospf6_vertex_delete (v);
297 return -1;
299 else if (route && route->path.cost == v->cost)
301 if (IS_OSPF6_DEBUG_SPF (PROCESS))
302 zlog_debug (" another path found, merge");
304 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
305 i < OSPF6_MULTI_PATH_LIMIT; i++)
307 for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
309 if (ospf6_nexthop_is_set (&route->nexthop[j]))
311 if (ospf6_nexthop_is_same (&route->nexthop[j],
312 &v->nexthop[i]))
313 break;
314 else
315 continue;
317 ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
318 break;
322 prev = (struct ospf6_vertex *) route->route_option;
323 if (prev->hops > v->hops)
325 for (ALL_LIST_ELEMENTS (prev->child_list, node, nnode, w))
327 assert (w->parent == prev);
328 w->parent = v;
329 listnode_add_sort (v->child_list, w);
331 listnode_delete (prev->parent->child_list, prev);
332 listnode_add_sort (v->parent->child_list, v);
334 ospf6_vertex_delete (prev);
335 route->route_option = v;
337 else
338 ospf6_vertex_delete (v);
340 return -1;
343 /* There should be no case where candidate being installed (variable
344 "v") is closer than the one in the SPF tree (variable "route").
345 In the case something has gone wrong with the behavior of
346 Priority-Queue. */
348 /* the case where the route exists already is handled and returned
349 up to here. */
350 assert (route == NULL);
352 route = ospf6_route_create ();
353 memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
354 route->type = OSPF6_DEST_TYPE_LINKSTATE;
355 route->path.type = OSPF6_PATH_TYPE_INTRA;
356 route->path.origin.type = v->lsa->header->type;
357 route->path.origin.id = v->lsa->header->id;
358 route->path.origin.adv_router = v->lsa->header->adv_router;
359 route->path.metric_type = 1;
360 route->path.cost = v->cost;
361 route->path.cost_e2 = v->hops;
362 route->path.router_bits = v->capability;
363 route->path.options[0] = v->options[0];
364 route->path.options[1] = v->options[1];
365 route->path.options[2] = v->options[2];
367 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
368 i < OSPF6_MULTI_PATH_LIMIT; i++)
369 ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
371 if (v->parent)
372 listnode_add_sort (v->parent->child_list, v);
373 route->route_option = v;
375 ospf6_route_add (route, result_table);
376 return 0;
379 void
380 ospf6_spf_table_finish (struct ospf6_route_table *result_table)
382 struct ospf6_route *route;
383 struct ospf6_vertex *v;
384 for (route = ospf6_route_head (result_table); route;
385 route = ospf6_route_next (route))
387 v = (struct ospf6_vertex *) route->route_option;
388 ospf6_vertex_delete (v);
389 ospf6_route_remove (route, result_table);
393 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
394 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
395 void
396 ospf6_spf_calculation (u_int32_t router_id,
397 struct ospf6_route_table *result_table,
398 struct ospf6_area *oa)
400 struct pqueue *candidate_list;
401 struct ospf6_vertex *root, *v, *w;
402 int i;
403 int size;
404 caddr_t lsdesc;
405 struct ospf6_lsa *lsa;
407 /* initialize */
408 candidate_list = pqueue_create ();
409 candidate_list->cmp = ospf6_vertex_cmp;
411 ospf6_spf_table_finish (result_table);
413 /* Install the calculating router itself as the root of the SPF tree */
414 /* construct root vertex */
415 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
416 router_id, oa->lsdb);
417 if (lsa == NULL)
418 return;
419 root = ospf6_vertex_create (lsa);
420 root->area = oa;
421 root->cost = 0;
422 root->hops = 0;
423 root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
424 inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
426 /* Actually insert root to the candidate-list as the only candidate */
427 pqueue_enqueue (root, candidate_list);
429 /* Iterate until candidate-list becomes empty */
430 while (candidate_list->size)
432 /* get closest candidate from priority queue */
433 v = pqueue_dequeue (candidate_list);
435 /* installing may result in merging or rejecting of the vertex */
436 if (ospf6_spf_install (v, result_table) < 0)
437 continue;
439 /* For each LS description in the just-added vertex V's LSA */
440 size = (VERTEX_IS_TYPE (ROUTER, v) ?
441 sizeof (struct ospf6_router_lsdesc) :
442 sizeof (struct ospf6_network_lsdesc));
443 for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
444 lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
446 lsa = ospf6_lsdesc_lsa (lsdesc, v);
447 if (lsa == NULL)
448 continue;
450 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
451 continue;
453 w = ospf6_vertex_create (lsa);
454 w->area = oa;
455 w->parent = v;
456 if (VERTEX_IS_TYPE (ROUTER, v))
458 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
459 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
461 else /* NETWORK */
463 w->cost = v->cost;
464 w->hops = v->hops + 1;
467 /* nexthop calculation */
468 if (w->hops == 0)
469 w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
470 else if (w->hops == 1 && v->hops == 0)
471 ospf6_nexthop_calc (w, v, lsdesc);
472 else
474 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
475 i < OSPF6_MULTI_PATH_LIMIT; i++)
476 ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
479 /* add new candidate to the candidate_list */
480 if (IS_OSPF6_DEBUG_SPF (PROCESS))
481 zlog_debug (" New candidate: %s hops %d cost %d",
482 w->name, w->hops, w->cost);
483 pqueue_enqueue (w, candidate_list);
487 pqueue_delete (candidate_list);
490 void
491 ospf6_spf_log_database (struct ospf6_area *oa)
493 char *p, *end, buffer[256];
494 struct listnode *node;
495 struct ospf6_interface *oi;
497 p = buffer;
498 end = buffer + sizeof (buffer);
500 snprintf (p, end - p, "SPF on DB (#LSAs):");
501 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
502 snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
503 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
505 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
507 snprintf (p, end - p, " I/F %s: %d",
508 oi->interface->name, oi->lsdb->count);
509 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
512 zlog_debug ("%s", buffer);
516 ospf6_spf_calculation_thread (struct thread *t)
518 struct ospf6_area *oa;
519 struct timeval start, end, runtime;
521 oa = (struct ospf6_area *) THREAD_ARG (t);
522 oa->thread_spf_calculation = NULL;
524 if (IS_OSPF6_DEBUG_SPF (PROCESS))
525 zlog_debug ("SPF calculation for Area %s", oa->name);
526 if (IS_OSPF6_DEBUG_SPF (DATABASE))
527 ospf6_spf_log_database (oa);
529 /* execute SPF calculation */
530 gettimeofday (&start, (struct timezone *) NULL);
531 ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa);
532 gettimeofday (&end, (struct timezone *) NULL);
533 timersub (&end, &start, &runtime);
535 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
536 zlog_debug ("SPF runtime: %ld sec %ld usec",
537 runtime.tv_sec, runtime.tv_usec);
539 ospf6_intra_route_calculation (oa);
540 ospf6_intra_brouter_calculation (oa);
542 return 0;
545 void
546 ospf6_spf_schedule (struct ospf6_area *oa)
548 if (oa->thread_spf_calculation)
549 return;
550 oa->thread_spf_calculation =
551 thread_add_event (master, ospf6_spf_calculation_thread, oa, 0);
554 void
555 ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
556 struct ospf6_vertex *v)
558 struct listnode *node, *nnode;
559 struct ospf6_vertex *c;
560 char *next_prefix;
561 int len;
562 int restnum;
564 /* "prefix" is the space prefix of the display line */
565 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
567 len = strlen (prefix) + 4;
568 next_prefix = (char *) malloc (len);
569 if (next_prefix == NULL)
571 vty_out (vty, "malloc failed%s", VNL);
572 return;
574 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
576 restnum = listcount (v->child_list);
577 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
579 restnum--;
580 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
583 free (next_prefix);
586 DEFUN (debug_ospf6_spf_process,
587 debug_ospf6_spf_process_cmd,
588 "debug ospf6 spf process",
589 DEBUG_STR
590 OSPF6_STR
591 "Debug SPF Calculation\n"
592 "Debug Detailed SPF Process\n"
595 unsigned char level = 0;
596 level = OSPF6_DEBUG_SPF_PROCESS;
597 OSPF6_DEBUG_SPF_ON (level);
598 return CMD_SUCCESS;
601 DEFUN (debug_ospf6_spf_time,
602 debug_ospf6_spf_time_cmd,
603 "debug ospf6 spf time",
604 DEBUG_STR
605 OSPF6_STR
606 "Debug SPF Calculation\n"
607 "Measure time taken by SPF Calculation\n"
610 unsigned char level = 0;
611 level = OSPF6_DEBUG_SPF_TIME;
612 OSPF6_DEBUG_SPF_ON (level);
613 return CMD_SUCCESS;
616 DEFUN (debug_ospf6_spf_database,
617 debug_ospf6_spf_database_cmd,
618 "debug ospf6 spf database",
619 DEBUG_STR
620 OSPF6_STR
621 "Debug SPF Calculation\n"
622 "Log number of LSAs at SPF Calculation time\n"
625 unsigned char level = 0;
626 level = OSPF6_DEBUG_SPF_DATABASE;
627 OSPF6_DEBUG_SPF_ON (level);
628 return CMD_SUCCESS;
631 DEFUN (no_debug_ospf6_spf_process,
632 no_debug_ospf6_spf_process_cmd,
633 "no debug ospf6 spf process",
634 NO_STR
635 DEBUG_STR
636 OSPF6_STR
637 "Quit Debugging SPF Calculation\n"
638 "Quit Debugging Detailed SPF Process\n"
641 unsigned char level = 0;
642 level = OSPF6_DEBUG_SPF_PROCESS;
643 OSPF6_DEBUG_SPF_OFF (level);
644 return CMD_SUCCESS;
647 DEFUN (no_debug_ospf6_spf_time,
648 no_debug_ospf6_spf_time_cmd,
649 "no debug ospf6 spf time",
650 NO_STR
651 DEBUG_STR
652 OSPF6_STR
653 "Quit Debugging SPF Calculation\n"
654 "Quit Measuring time taken by SPF Calculation\n"
657 unsigned char level = 0;
658 level = OSPF6_DEBUG_SPF_TIME;
659 OSPF6_DEBUG_SPF_OFF (level);
660 return CMD_SUCCESS;
663 DEFUN (no_debug_ospf6_spf_database,
664 no_debug_ospf6_spf_database_cmd,
665 "no debug ospf6 spf database",
666 NO_STR
667 DEBUG_STR
668 OSPF6_STR
669 "Debug SPF Calculation\n"
670 "Quit Logging number of LSAs at SPF Calculation time\n"
673 unsigned char level = 0;
674 level = OSPF6_DEBUG_SPF_DATABASE;
675 OSPF6_DEBUG_SPF_OFF (level);
676 return CMD_SUCCESS;
680 config_write_ospf6_debug_spf (struct vty *vty)
682 if (IS_OSPF6_DEBUG_SPF (PROCESS))
683 vty_out (vty, "debug ospf6 spf process%s", VNL);
684 if (IS_OSPF6_DEBUG_SPF (TIME))
685 vty_out (vty, "debug ospf6 spf time%s", VNL);
686 if (IS_OSPF6_DEBUG_SPF (DATABASE))
687 vty_out (vty, "debug ospf6 spf database%s", VNL);
688 return 0;
691 void
692 install_element_ospf6_debug_spf ()
694 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
695 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
696 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
697 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
698 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
699 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
700 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
701 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
702 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
703 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
704 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
705 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
708 void
709 ospf6_spf_init ()