]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_spf.c
79539b2fb64d807950045814f0179b19497266e0
[mirror_frr.git] / ospf6d / ospf6_spf.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
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.
10 *
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.
15 *
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.
20 */
21
22 /* Shortest Path First calculation for OSPFv3 */
23
24 #include <zebra.h>
25
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"
34
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"
43
44 unsigned char conf_debug_ospf6_spf = 0;
45
46 int
47 ospf6_vertex_cmp (void *a, void *b)
48 {
49 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
50 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
51
52 /* ascending order */
53 return (va->cost - vb->cost);
54 }
55
56 int
57 ospf6_vertex_id_cmp (void *a, void *b)
58 {
59 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
60 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
61 int ret = 0;
62
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;
67
68 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
69 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
70 return ret;
71 }
72
73 struct ospf6_vertex *
74 ospf6_vertex_create (struct ospf6_lsa *lsa)
75 {
76 struct ospf6_vertex *v;
77 int i;
78
79 v = (struct ospf6_vertex *)
80 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
81
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);
89
90 /* vertex_id */
91 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
92 &v->vertex_id);
93
94 /* name */
95 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
96
97 /* Associated LSA */
98 v->lsa = lsa;
99
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);
105
106 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
107 ospf6_nexthop_clear (&v->nexthop[i]);
108
109 v->parent = NULL;
110 v->child_list = list_new ();
111 v->child_list->cmp = ospf6_vertex_id_cmp;
112
113 return v;
114 }
115
116 void
117 ospf6_vertex_delete (struct ospf6_vertex *v)
118 {
119 list_delete (v->child_list);
120 XFREE (MTYPE_OSPF6_VERTEX, v);
121 }
122
123 struct ospf6_lsa *
124 ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
125 {
126 struct ospf6_lsa *lsa;
127 u_int16_t type = 0;
128 u_int32_t id = 0, adv_router = 0;
129
130 if (VERTEX_IS_TYPE (NETWORK, v))
131 {
132 type = htons (OSPF6_LSTYPE_ROUTER);
133 id = htonl (0);
134 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
135 }
136 else
137 {
138 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
139 {
140 type = htons (OSPF6_LSTYPE_ROUTER);
141 id = htonl (0);
142 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
143 }
144 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
145 {
146 type = htons (OSPF6_LSTYPE_NETWORK);
147 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
148 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
149 }
150 }
151
152 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
153
154 if (IS_OSPF6_DEBUG_SPF (PROCESS))
155 {
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_info (" Link to: %s", lsa->name);
161 else
162 zlog_info (" Link to: [%s Id:%s Adv:%s] No LSA",
163 ospf6_lstype_name (type), ibuf, abuf);
164 }
165
166 return lsa;
167 }
168
169 char *
170 ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
171 caddr_t lsdesc, struct ospf6_vertex *v)
172 {
173 caddr_t backlink, found = NULL;
174 int size;
175
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)
181 {
182 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
183 VERTEX_IS_TYPE (NETWORK, v)));
184
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
197 {
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;
212 }
213 }
214
215 if (IS_OSPF6_DEBUG_SPF (PROCESS))
216 zlog_info (" Backlink %s", (found ? "OK" : "FAIL"));
217
218 return found;
219 }
220
221 void
222 ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
223 caddr_t lsdesc)
224 {
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];
232
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)
238 {
239 if (IS_OSPF6_DEBUG_SPF (PROCESS))
240 zlog_warn ("Can't find interface in SPF: ifindex %d", ifindex);
241 return;
242 }
243
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));
248
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))
252 {
253 if (VERTEX_IS_TYPE (ROUTER, v) &&
254 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
255 continue;
256
257 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
258 if (IS_OSPF6_DEBUG_SPF (PROCESS))
259 {
260 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
261 zlog_info (" nexthop %s from %s", buf, lsa->name);
262 }
263
264 if (i < OSPF6_MULTI_PATH_LIMIT)
265 {
266 memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
267 sizeof (struct in6_addr));
268 w->nexthop[i].ifindex = ifindex;
269 i++;
270 }
271 }
272
273 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
274 zlog_info ("No nexthop for %s found", w->name);
275 }
276
277 int
278 ospf6_spf_install (struct ospf6_vertex *v,
279 struct ospf6_route_table *result_table)
280 {
281 struct ospf6_route *route;
282 int i, j;
283 struct ospf6_vertex *prev, *w;
284 struct listnode *node;
285
286 if (IS_OSPF6_DEBUG_SPF (PROCESS))
287 zlog_info ("SPF install %s hops %d cost %d",
288 v->name, v->hops, v->cost);
289
290 route = ospf6_route_lookup (&v->vertex_id, result_table);
291 if (route && route->path.cost < v->cost)
292 {
293 if (IS_OSPF6_DEBUG_SPF (PROCESS))
294 zlog_info (" already installed with lower cost (%d), ignore",
295 route->path.cost);
296 ospf6_vertex_delete (v);
297 return -1;
298 }
299 else if (route && route->path.cost == v->cost)
300 {
301 if (IS_OSPF6_DEBUG_SPF (PROCESS))
302 zlog_info (" another path found, merge");
303
304 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
305 i < OSPF6_MULTI_PATH_LIMIT; i++)
306 {
307 for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
308 {
309 if (ospf6_nexthop_is_set (&route->nexthop[j]))
310 {
311 if (ospf6_nexthop_is_same (&route->nexthop[j],
312 &v->nexthop[i]))
313 break;
314 else
315 continue;
316 }
317 ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
318 break;
319 }
320 }
321
322 prev = (struct ospf6_vertex *) route->route_option;
323 if (prev->hops > v->hops)
324 {
325 LIST_LOOP (prev->child_list, w, node)
326 {
327 assert (w->parent == prev);
328 w->parent = v;
329 listnode_add_sort (v->child_list, w);
330 }
331 listnode_delete (prev->parent->child_list, prev);
332 listnode_add_sort (v->parent->child_list, v);
333
334 ospf6_vertex_delete (prev);
335 route->route_option = v;
336 }
337 else
338 ospf6_vertex_delete (v);
339
340 return -1;
341 }
342
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. */
347
348 /* the case where the route exists already is handled and returned
349 up to here. */
350 assert (route == NULL);
351
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];
366
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]);
370
371 if (v->parent)
372 listnode_add_sort (v->parent->child_list, v);
373 route->route_option = v;
374
375 ospf6_route_add (route, result_table);
376 return 0;
377 }
378
379 void
380 ospf6_spf_table_finish (struct ospf6_route_table *result_table)
381 {
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))
386 {
387 v = (struct ospf6_vertex *) route->route_option;
388 ospf6_vertex_delete (v);
389 ospf6_route_remove (route, result_table);
390 }
391 }
392
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)
399 {
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;
406
407 /* initialize */
408 candidate_list = pqueue_create ();
409 candidate_list->cmp = ospf6_vertex_cmp;
410
411 ospf6_spf_table_finish (result_table);
412
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);
425
426 /* Actually insert root to the candidate-list as the only candidate */
427 pqueue_enqueue (root, candidate_list);
428
429 /* Iterate until candidate-list becomes empty */
430 while (candidate_list->size)
431 {
432 /* get closest candidate from priority queue */
433 v = pqueue_dequeue (candidate_list);
434
435 /* installing may result in merging or rejecting of the vertex */
436 if (ospf6_spf_install (v, result_table) < 0)
437 continue;
438
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)
445 {
446 lsa = ospf6_lsdesc_lsa (lsdesc, v);
447 if (lsa == NULL)
448 continue;
449
450 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
451 continue;
452
453 w = ospf6_vertex_create (lsa);
454 w->area = oa;
455 w->parent = v;
456 if (VERTEX_IS_TYPE (ROUTER, v))
457 {
458 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
459 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
460 }
461 else /* NETWORK */
462 {
463 w->cost = v->cost;
464 w->hops = v->hops + 1;
465 }
466
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
473 {
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]);
477 }
478
479 /* add new candidate to the candidate_list */
480 if (IS_OSPF6_DEBUG_SPF (PROCESS))
481 zlog_info (" New candidate: %s hops %d cost %d",
482 w->name, w->hops, w->cost);
483 pqueue_enqueue (w, candidate_list);
484 }
485 }
486
487 pqueue_delete (candidate_list);
488 }
489
490 int
491 ospf6_spf_calculation_thread (struct thread *t)
492 {
493 struct ospf6_area *oa;
494 struct timeval start, end, runtime;
495
496 oa = (struct ospf6_area *) THREAD_ARG (t);
497 oa->thread_spf_calculation = NULL;
498
499 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
500 zlog_info ("SPF calculation for area %s", oa->name);
501
502 /* execute SPF calculation */
503 gettimeofday (&start, (struct timezone *) NULL);
504 ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa);
505 gettimeofday (&end, (struct timezone *) NULL);
506
507 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
508 {
509 timersub (&end, &start, &runtime);
510 zlog_info ("SPF calculation for area %s: runtime %ld sec %ld usec",
511 oa->name, runtime.tv_sec, runtime.tv_usec);
512 }
513
514 ospf6_intra_route_calculation (oa);
515 ospf6_intra_brouter_calculation (oa);
516
517 return 0;
518 }
519
520 void
521 ospf6_spf_schedule (struct ospf6_area *oa)
522 {
523 if (oa->thread_spf_calculation)
524 return;
525 oa->thread_spf_calculation =
526 thread_add_event (master, ospf6_spf_calculation_thread, oa, 0);
527 }
528
529 void
530 ospf6_spf_display_subtree (struct vty *vty, char *prefix, int rest,
531 struct ospf6_vertex *v)
532 {
533 struct listnode *node;
534 struct ospf6_vertex *c;
535 char *next_prefix;
536 int len;
537 int restnum;
538
539 /* "prefix" is the space prefix of the display line */
540 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
541
542 len = strlen (prefix) + 4;
543 next_prefix = (char *) malloc (len);
544 if (next_prefix == NULL)
545 {
546 vty_out (vty, "malloc failed%s", VNL);
547 return;
548 }
549 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
550
551 restnum = listcount (v->child_list);
552 LIST_LOOP (v->child_list, c, node)
553 {
554 restnum--;
555 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
556 }
557
558 free (next_prefix);
559 }
560
561 DEFUN (debug_ospf6_spf_process,
562 debug_ospf6_spf_process_cmd,
563 "debug ospf6 spf process",
564 DEBUG_STR
565 OSPF6_STR
566 "Debug SPF Calculation\n"
567 "Debug Detailed SPF Process\n"
568 )
569 {
570 unsigned char level = 0;
571 level = OSPF6_DEBUG_SPF_PROCESS;
572 OSPF6_DEBUG_SPF_ON (level);
573 return CMD_SUCCESS;
574 }
575
576 DEFUN (debug_ospf6_spf_time,
577 debug_ospf6_spf_time_cmd,
578 "debug ospf6 spf time",
579 DEBUG_STR
580 OSPF6_STR
581 "Debug SPF Calculation\n"
582 "Measure time taken by SPF Calculation\n"
583 )
584 {
585 unsigned char level = 0;
586 level = OSPF6_DEBUG_SPF_TIME;
587 OSPF6_DEBUG_SPF_ON (level);
588 return CMD_SUCCESS;
589 }
590
591 DEFUN (no_debug_ospf6_spf_process,
592 no_debug_ospf6_spf_process_cmd,
593 "no debug ospf6 spf process",
594 NO_STR
595 DEBUG_STR
596 OSPF6_STR
597 "Quit Debugging SPF Calculation\n"
598 "Quit Debugging Detailed SPF Process\n"
599 )
600 {
601 unsigned char level = 0;
602 level = OSPF6_DEBUG_SPF_PROCESS;
603 OSPF6_DEBUG_SPF_OFF (level);
604 return CMD_SUCCESS;
605 }
606
607 DEFUN (no_debug_ospf6_spf_time,
608 no_debug_ospf6_spf_time_cmd,
609 "no debug ospf6 spf time",
610 NO_STR
611 DEBUG_STR
612 OSPF6_STR
613 "Quit Debugging SPF Calculation\n"
614 "Quit Measuring time taken by SPF Calculation\n"
615 )
616 {
617 unsigned char level = 0;
618 level = OSPF6_DEBUG_SPF_TIME;
619 OSPF6_DEBUG_SPF_OFF (level);
620 return CMD_SUCCESS;
621 }
622
623 int
624 config_write_ospf6_debug_spf (struct vty *vty)
625 {
626 if (IS_OSPF6_DEBUG_SPF (PROCESS))
627 vty_out (vty, "debug ospf6 spf process%s", VNL);
628 if (IS_OSPF6_DEBUG_SPF (TIME))
629 vty_out (vty, "debug ospf6 spf time%s", VNL);
630 return 0;
631 }
632
633 void
634 install_element_ospf6_debug_spf ()
635 {
636 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
637 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
638 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
639 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
640 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
641 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
642 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
643 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
644 }
645
646 void
647 ospf6_spf_init ()
648 {
649 }
650
651