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
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 */
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"
43 #include "ospf6_abr.h"
45 unsigned char conf_debug_ospf6_spf = 0;
48 ospf6_vertex_cmp (void *a, void *b)
50 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
51 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
54 if (va->cost != vb->cost)
55 return (va->cost - vb->cost);
56 return (va->hops - vb->hops);
60 ospf6_vertex_id_cmp (void *a, void *b)
62 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
63 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
66 ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
67 ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
71 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
72 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
76 static struct ospf6_vertex *
77 ospf6_vertex_create (struct ospf6_lsa *lsa)
79 struct ospf6_vertex *v;
82 v = (struct ospf6_vertex *)
83 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
86 if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
87 v->type = OSPF6_VERTEX_TYPE_ROUTER;
88 else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
89 v->type = OSPF6_VERTEX_TYPE_NETWORK;
94 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
98 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
103 /* capability bits + options */
104 v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
105 v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
106 v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
107 v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
109 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
110 ospf6_nexthop_clear (&v->nexthop[i]);
113 v->child_list = list_new ();
114 v->child_list->cmp = ospf6_vertex_id_cmp;
120 ospf6_vertex_delete (struct ospf6_vertex *v)
122 list_delete (v->child_list);
123 XFREE (MTYPE_OSPF6_VERTEX, v);
126 static struct ospf6_lsa *
127 ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
129 struct ospf6_lsa *lsa;
131 u_int32_t id = 0, adv_router = 0;
133 if (VERTEX_IS_TYPE (NETWORK, v))
135 type = htons (OSPF6_LSTYPE_ROUTER);
137 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
141 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
143 type = htons (OSPF6_LSTYPE_ROUTER);
145 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
147 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
149 type = htons (OSPF6_LSTYPE_NETWORK);
150 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
151 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
155 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
157 if (IS_OSPF6_DEBUG_SPF (PROCESS))
159 char ibuf[16], abuf[16];
160 inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
161 inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
163 zlog_debug (" Link to: %s", lsa->name);
165 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
166 ospf6_lstype_name (type), ibuf, abuf);
173 ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
174 caddr_t lsdesc, struct ospf6_vertex *v)
176 caddr_t backlink, found = NULL;
179 size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
180 sizeof (struct ospf6_router_lsdesc) :
181 sizeof (struct ospf6_network_lsdesc));
182 for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
183 backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
185 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
186 VERTEX_IS_TYPE (NETWORK, v)));
188 if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
189 NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
190 == v->lsa->header->adv_router)
192 else if (VERTEX_IS_TYPE (NETWORK, v) &&
193 ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
194 ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
195 == v->lsa->header->adv_router &&
196 ROUTER_LSDESC_GET_NBR_IFID (backlink)
197 == ntohl (v->lsa->header->id))
201 if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
202 ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
204 if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
205 ROUTER_LSDESC_GET_IFID (lsdesc) ||
206 ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
207 ROUTER_LSDESC_GET_IFID (backlink))
209 if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
210 v->lsa->header->adv_router ||
211 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
212 lsa->header->adv_router)
218 if (IS_OSPF6_DEBUG_SPF (PROCESS))
219 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
225 ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
230 struct ospf6_interface *oi;
232 u_int32_t adv_router;
233 struct ospf6_lsa *lsa;
234 struct ospf6_link_lsa *link_lsa;
237 assert (VERTEX_IS_TYPE (ROUTER, w));
238 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
239 /* v is the local router & the interface_id is a local ifindex */
240 (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc));
241 assert (ifindex >= 0);
243 oi = ospf6_interface_lookup_by_ifindex (ifindex);
246 if (IS_OSPF6_DEBUG_SPF (PROCESS))
247 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
251 type = htons (OSPF6_LSTYPE_LINK);
252 adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
253 NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
254 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
257 for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
258 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
260 if (VERTEX_IS_TYPE (ROUTER, v) &&
261 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
264 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
265 if (IS_OSPF6_DEBUG_SPF (PROCESS))
267 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
268 zlog_debug (" nexthop %s from %s", buf, lsa->name);
271 if (i < OSPF6_MULTI_PATH_LIMIT)
273 memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
274 sizeof (struct in6_addr));
275 w->nexthop[i].ifindex = ifindex;
280 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
281 zlog_debug ("No nexthop for %s found", w->name);
285 ospf6_spf_install (struct ospf6_vertex *v,
286 struct ospf6_route_table *result_table)
288 struct ospf6_route *route;
290 struct ospf6_vertex *prev;
292 if (IS_OSPF6_DEBUG_SPF (PROCESS))
293 zlog_debug ("SPF install %s hops %d cost %d",
294 v->name, v->hops, v->cost);
296 route = ospf6_route_lookup (&v->vertex_id, result_table);
297 if (route && route->path.cost < v->cost)
299 if (IS_OSPF6_DEBUG_SPF (PROCESS))
300 zlog_debug (" already installed with lower cost (%d), ignore",
302 ospf6_vertex_delete (v);
305 else if (route && route->path.cost == v->cost)
307 if (IS_OSPF6_DEBUG_SPF (PROCESS))
308 zlog_debug (" another path found, merge");
310 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT &&
311 ospf6_nexthop_is_set (&v->nexthop[i]); i++)
313 for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
315 if (ospf6_nexthop_is_set (&route->nexthop[j]))
317 if (ospf6_nexthop_is_same (&route->nexthop[j],
323 ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
328 prev = (struct ospf6_vertex *) route->route_option;
329 assert (prev->hops <= v->hops);
330 ospf6_vertex_delete (v);
335 /* There should be no case where candidate being installed (variable
336 "v") is closer than the one in the SPF tree (variable "route").
337 In the case something has gone wrong with the behavior of
340 /* the case where the route exists already is handled and returned
342 assert (route == NULL);
344 route = ospf6_route_create ();
345 memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
346 route->type = OSPF6_DEST_TYPE_LINKSTATE;
347 route->path.type = OSPF6_PATH_TYPE_INTRA;
348 route->path.origin.type = v->lsa->header->type;
349 route->path.origin.id = v->lsa->header->id;
350 route->path.origin.adv_router = v->lsa->header->adv_router;
351 route->path.metric_type = 1;
352 route->path.cost = v->cost;
353 route->path.cost_e2 = v->hops;
354 route->path.router_bits = v->capability;
355 route->path.options[0] = v->options[0];
356 route->path.options[1] = v->options[1];
357 route->path.options[2] = v->options[2];
359 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT &&
360 ospf6_nexthop_is_set (&v->nexthop[i]); i++)
361 ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
364 listnode_add_sort (v->parent->child_list, v);
365 route->route_option = v;
367 ospf6_route_add (route, result_table);
372 ospf6_spf_table_finish (struct ospf6_route_table *result_table)
374 struct ospf6_route *route, *nroute;
375 struct ospf6_vertex *v;
376 for (route = ospf6_route_head (result_table); route;
379 nroute = ospf6_route_next (route);
380 v = (struct ospf6_vertex *) route->route_option;
381 ospf6_vertex_delete (v);
382 ospf6_route_remove (route, result_table);
386 static const char *ospf6_spf_reason_str[] =
398 void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
406 for (bit = 0; bit < array_size(ospf6_spf_reason_str); bit++)
408 if ((reason & (1 << bit)) && (len < size))
410 len += snprintf((buf + len), (size - len), "%s%s",
411 (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]);
416 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
417 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
419 ospf6_spf_calculation (u_int32_t router_id,
420 struct ospf6_route_table *result_table,
421 struct ospf6_area *oa)
423 struct pqueue *candidate_list;
424 struct ospf6_vertex *root, *v, *w;
428 struct ospf6_lsa *lsa;
430 ospf6_spf_table_finish (result_table);
432 /* Install the calculating router itself as the root of the SPF tree */
433 /* construct root vertex */
434 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
435 router_id, oa->lsdb);
440 candidate_list = pqueue_create ();
441 candidate_list->cmp = ospf6_vertex_cmp;
443 root = ospf6_vertex_create (lsa);
447 root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
448 inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
450 /* Actually insert root to the candidate-list as the only candidate */
451 pqueue_enqueue (root, candidate_list);
453 /* Iterate until candidate-list becomes empty */
454 while (candidate_list->size)
456 /* get closest candidate from priority queue */
457 v = pqueue_dequeue (candidate_list);
459 /* installing may result in merging or rejecting of the vertex */
460 if (ospf6_spf_install (v, result_table) < 0)
463 /* Skip overloaded routers */
464 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
465 ospf6_router_is_stub_router (v->lsa)))
468 /* For each LS description in the just-added vertex V's LSA */
469 size = (VERTEX_IS_TYPE (ROUTER, v) ?
470 sizeof (struct ospf6_router_lsdesc) :
471 sizeof (struct ospf6_network_lsdesc));
472 for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
473 lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
475 lsa = ospf6_lsdesc_lsa (lsdesc, v);
479 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
482 w = ospf6_vertex_create (lsa);
485 if (VERTEX_IS_TYPE (ROUTER, v))
487 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
488 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
493 w->hops = v->hops + 1;
496 /* nexthop calculation */
498 w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
499 else if (w->hops == 1 && v->hops == 0)
500 ospf6_nexthop_calc (w, v, lsdesc);
503 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT &&
504 ospf6_nexthop_is_set (&v->nexthop[i]); i++)
505 ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
508 /* add new candidate to the candidate_list */
509 if (IS_OSPF6_DEBUG_SPF (PROCESS))
510 zlog_debug (" New candidate: %s hops %d cost %d",
511 w->name, w->hops, w->cost);
512 pqueue_enqueue (w, candidate_list);
516 pqueue_delete (candidate_list);
518 oa->spf_calculation++;
522 ospf6_spf_log_database (struct ospf6_area *oa)
524 char *p, *end, buffer[256];
525 struct listnode *node;
526 struct ospf6_interface *oi;
529 end = buffer + sizeof (buffer);
531 snprintf (p, end - p, "SPF on DB (#LSAs):");
532 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
533 snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
534 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
536 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
538 snprintf (p, end - p, " I/F %s: %d",
539 oi->interface->name, oi->lsdb->count);
540 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
543 zlog_debug ("%s", buffer);
547 ospf6_spf_calculation_thread (struct thread *t)
549 struct ospf6_area *oa;
551 struct timeval start, end, runtime;
552 struct listnode *node;
553 struct ospf6_route *route;
554 int areas_processed = 0;
557 ospf6 = (struct ospf6 *)THREAD_ARG (t);
558 ospf6->t_spf_calc = NULL;
560 /* execute SPF calculation */
561 quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
563 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
566 if (oa == ospf6->backbone)
569 if (IS_OSPF6_DEBUG_SPF (PROCESS))
570 zlog_debug ("SPF calculation for Area %s", oa->name);
571 if (IS_OSPF6_DEBUG_SPF (DATABASE))
572 ospf6_spf_log_database (oa);
574 ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
575 ospf6_intra_route_calculation (oa);
576 ospf6_intra_brouter_calculation (oa);
583 if (IS_OSPF6_DEBUG_SPF (PROCESS))
584 zlog_debug ("SPF calculation for Backbone area %s",
585 ospf6->backbone->name);
586 if (IS_OSPF6_DEBUG_SPF (DATABASE))
587 ospf6_spf_log_database(ospf6->backbone);
589 ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
591 ospf6_intra_route_calculation(ospf6->backbone);
592 ospf6_intra_brouter_calculation(ospf6->backbone);
596 /* Redo summaries if required */
597 for (route = ospf6_route_head (ospf6->route_table); route;
598 route = ospf6_route_next (route))
599 ospf6_abr_originate_summary(route);
601 quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
602 timersub (&end, &start, &runtime);
604 ospf6->ts_spf_duration = runtime;
606 ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
608 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
609 zlog_debug ("SPF runtime: %lld sec %lld usec",
610 (long long)runtime.tv_sec, (long long)runtime.tv_usec);
612 zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
613 "Reason: %s\n", areas_processed,
614 (long long)runtime.tv_sec, (long long)runtime.tv_usec,
616 ospf6->last_spf_reason = ospf6->spf_reason;
617 ospf6_reset_spf_reason(ospf6);
621 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
622 set timer for SPF calc. */
624 ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
626 unsigned long delay, elapsed, ht;
627 struct timeval now, result;
629 ospf6_set_spf_reason(ospf6, reason);
631 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
634 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
635 zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
638 /* OSPF instance does not exist. */
642 /* SPF calculation timer is already scheduled. */
643 if (ospf6->t_spf_calc)
645 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
646 zlog_debug ("SPF: calculation timer is already scheduled: %p",
647 (void *)ospf6->t_spf_calc);
651 /* XXX Monotic timers: we only care about relative time here. */
652 now = recent_relative_time ();
653 timersub (&now, &ospf6->ts_spf, &result);
655 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
656 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
658 if (ht > ospf6->spf_max_holdtime)
659 ht = ospf6->spf_max_holdtime;
661 /* Get SPF calculation delay time. */
664 /* Got an event within the hold time of last SPF. We need to
665 * increase the hold_multiplier, if it's not already at/past
666 * maximum value, and wasn't already increased..
668 if (ht < ospf6->spf_max_holdtime)
669 ospf6->spf_hold_multiplier++;
671 /* always honour the SPF initial delay */
672 if ( (ht - elapsed) < ospf6->spf_delay)
673 delay = ospf6->spf_delay;
675 delay = ht - elapsed;
679 /* Event is past required hold-time of last SPF */
680 delay = ospf6->spf_delay;
681 ospf6->spf_hold_multiplier = 1;
684 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
685 zlog_debug ("SPF: calculation timer delay = %ld", delay);
687 zlog_info ("SPF: Scheduled in %ld msec", delay);
690 thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
694 ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
695 struct ospf6_vertex *v)
697 struct listnode *node, *nnode;
698 struct ospf6_vertex *c;
703 /* "prefix" is the space prefix of the display line */
704 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
706 len = strlen (prefix) + 4;
707 next_prefix = (char *) malloc (len);
708 if (next_prefix == NULL)
710 vty_out (vty, "malloc failed%s", VNL);
713 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
715 restnum = listcount (v->child_list);
716 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
719 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
725 DEFUN (debug_ospf6_spf_process,
726 debug_ospf6_spf_process_cmd,
727 "debug ospf6 spf process",
730 "Debug SPF Calculation\n"
731 "Debug Detailed SPF Process\n"
734 unsigned char level = 0;
735 level = OSPF6_DEBUG_SPF_PROCESS;
736 OSPF6_DEBUG_SPF_ON (level);
740 DEFUN (debug_ospf6_spf_time,
741 debug_ospf6_spf_time_cmd,
742 "debug ospf6 spf time",
745 "Debug SPF Calculation\n"
746 "Measure time taken by SPF Calculation\n"
749 unsigned char level = 0;
750 level = OSPF6_DEBUG_SPF_TIME;
751 OSPF6_DEBUG_SPF_ON (level);
755 DEFUN (debug_ospf6_spf_database,
756 debug_ospf6_spf_database_cmd,
757 "debug ospf6 spf database",
760 "Debug SPF Calculation\n"
761 "Log number of LSAs at SPF Calculation time\n"
764 unsigned char level = 0;
765 level = OSPF6_DEBUG_SPF_DATABASE;
766 OSPF6_DEBUG_SPF_ON (level);
770 DEFUN (no_debug_ospf6_spf_process,
771 no_debug_ospf6_spf_process_cmd,
772 "no debug ospf6 spf process",
776 "Quit Debugging SPF Calculation\n"
777 "Quit Debugging Detailed SPF Process\n"
780 unsigned char level = 0;
781 level = OSPF6_DEBUG_SPF_PROCESS;
782 OSPF6_DEBUG_SPF_OFF (level);
786 DEFUN (no_debug_ospf6_spf_time,
787 no_debug_ospf6_spf_time_cmd,
788 "no debug ospf6 spf time",
792 "Quit Debugging SPF Calculation\n"
793 "Quit Measuring time taken by SPF Calculation\n"
796 unsigned char level = 0;
797 level = OSPF6_DEBUG_SPF_TIME;
798 OSPF6_DEBUG_SPF_OFF (level);
802 DEFUN (no_debug_ospf6_spf_database,
803 no_debug_ospf6_spf_database_cmd,
804 "no debug ospf6 spf database",
808 "Debug SPF Calculation\n"
809 "Quit Logging number of LSAs at SPF Calculation time\n"
812 unsigned char level = 0;
813 level = OSPF6_DEBUG_SPF_DATABASE;
814 OSPF6_DEBUG_SPF_OFF (level);
819 ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
823 struct ospf6 *ospf = vty->index;
825 ospf->spf_delay = delay;
826 ospf->spf_holdtime = hold;
827 ospf->spf_max_holdtime = max;
832 DEFUN (ospf6_timers_throttle_spf,
833 ospf6_timers_throttle_spf_cmd,
834 "timers throttle spf <0-600000> <0-600000> <0-600000>",
835 "Adjust routing timers\n"
836 "Throttling adaptive timer\n"
838 "Delay (msec) from first change received till SPF calculation\n"
839 "Initial hold time (msec) between consecutive SPF calculations\n"
840 "Maximum hold time (msec)\n")
842 unsigned int delay, hold, max;
846 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
850 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
851 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
852 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
854 return ospf6_timers_spf_set (vty, delay, hold, max);
857 DEFUN (no_ospf6_timers_throttle_spf,
858 no_ospf6_timers_throttle_spf_cmd,
859 "no timers throttle spf",
861 "Adjust routing timers\n"
862 "Throttling adaptive timer\n"
863 "OSPF6 SPF timers\n")
865 return ospf6_timers_spf_set (vty,
866 OSPF_SPF_DELAY_DEFAULT,
867 OSPF_SPF_HOLDTIME_DEFAULT,
868 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
872 config_write_ospf6_debug_spf (struct vty *vty)
874 if (IS_OSPF6_DEBUG_SPF (PROCESS))
875 vty_out (vty, "debug ospf6 spf process%s", VNL);
876 if (IS_OSPF6_DEBUG_SPF (TIME))
877 vty_out (vty, "debug ospf6 spf time%s", VNL);
878 if (IS_OSPF6_DEBUG_SPF (DATABASE))
879 vty_out (vty, "debug ospf6 spf database%s", VNL);
884 ospf6_spf_config_write (struct vty *vty)
887 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
888 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
889 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
890 vty_out (vty, " timers throttle spf %d %d %d%s",
891 ospf6->spf_delay, ospf6->spf_holdtime,
892 ospf6->spf_max_holdtime, VTY_NEWLINE);
897 install_element_ospf6_debug_spf (void)
899 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
900 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
901 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
902 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
903 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
904 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
905 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
906 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
907 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
908 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
909 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
910 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
914 ospf6_spf_init (void)
916 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
917 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);