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_proto.h"
40 #include "ospf6_abr.h"
41 #include "ospf6_spf.h"
42 #include "ospf6_intra.h"
43 #include "ospf6_interface.h"
45 #include "ospf6_abr.h"
47 unsigned char conf_debug_ospf6_spf
= 0;
49 static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route
*rt
,
50 struct ospf6_vertex
*v
)
53 ospf6_copy_nexthops(rt
->nh_list
, v
->nh_list
);
56 static void ospf6_spf_merge_nexthops_to_route(struct ospf6_route
*rt
,
57 struct ospf6_vertex
*v
)
60 ospf6_merge_nexthops(rt
->nh_list
, v
->nh_list
);
63 static unsigned int ospf6_spf_get_ifindex_from_nh(struct ospf6_vertex
*v
)
65 struct ospf6_nexthop
*nh
;
66 struct listnode
*node
;
69 node
= listhead(v
->nh_list
);
71 nh
= listgetdata(node
);
79 static int ospf6_vertex_cmp(void *a
, void *b
)
81 struct ospf6_vertex
*va
= (struct ospf6_vertex
*)a
;
82 struct ospf6_vertex
*vb
= (struct ospf6_vertex
*)b
;
85 if (va
->cost
!= vb
->cost
)
86 return (va
->cost
- vb
->cost
);
87 return (va
->hops
- vb
->hops
);
90 static int ospf6_vertex_id_cmp(void *a
, void *b
)
92 struct ospf6_vertex
*va
= (struct ospf6_vertex
*)a
;
93 struct ospf6_vertex
*vb
= (struct ospf6_vertex
*)b
;
96 ret
= ntohl(ospf6_linkstate_prefix_adv_router(&va
->vertex_id
))
97 - ntohl(ospf6_linkstate_prefix_adv_router(&vb
->vertex_id
));
101 ret
= ntohl(ospf6_linkstate_prefix_id(&va
->vertex_id
))
102 - ntohl(ospf6_linkstate_prefix_id(&vb
->vertex_id
));
106 static struct ospf6_vertex
*ospf6_vertex_create(struct ospf6_lsa
*lsa
)
108 struct ospf6_vertex
*v
;
110 v
= (struct ospf6_vertex
*)XMALLOC(MTYPE_OSPF6_VERTEX
,
111 sizeof(struct ospf6_vertex
));
114 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
)
115 v
->type
= OSPF6_VERTEX_TYPE_ROUTER
;
116 else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_NETWORK
)
117 v
->type
= OSPF6_VERTEX_TYPE_NETWORK
;
122 ospf6_linkstate_prefix(lsa
->header
->adv_router
, lsa
->header
->id
,
126 ospf6_linkstate_prefix2str(&v
->vertex_id
, v
->name
, sizeof(v
->name
));
128 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
129 zlog_debug("%s: Creating vertex %s of type %s", __func__
,
131 ((ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
)
138 /* capability bits + options */
139 v
->capability
= *(u_char
*)(OSPF6_LSA_HEADER_END(lsa
->header
));
140 v
->options
[0] = *(u_char
*)(OSPF6_LSA_HEADER_END(lsa
->header
) + 1);
141 v
->options
[1] = *(u_char
*)(OSPF6_LSA_HEADER_END(lsa
->header
) + 2);
142 v
->options
[2] = *(u_char
*)(OSPF6_LSA_HEADER_END(lsa
->header
) + 3);
144 v
->nh_list
= list_new();
147 v
->child_list
= list_new();
148 v
->child_list
->cmp
= ospf6_vertex_id_cmp
;
153 static void ospf6_vertex_delete(struct ospf6_vertex
*v
)
155 ospf6_free_nexthops(v
->nh_list
);
156 list_delete(v
->nh_list
);
158 list_delete(v
->child_list
);
159 XFREE(MTYPE_OSPF6_VERTEX
, v
);
162 static struct ospf6_lsa
*ospf6_lsdesc_lsa(caddr_t lsdesc
,
163 struct ospf6_vertex
*v
)
165 struct ospf6_lsa
*lsa
;
167 u_int32_t id
= 0, adv_router
= 0;
169 if (VERTEX_IS_TYPE(NETWORK
, v
)) {
170 type
= htons(OSPF6_LSTYPE_ROUTER
);
172 adv_router
= NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
);
174 if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
)) {
175 type
= htons(OSPF6_LSTYPE_ROUTER
);
177 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
178 } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, lsdesc
)) {
179 type
= htons(OSPF6_LSTYPE_NETWORK
);
180 id
= htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
));
181 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
185 lsa
= ospf6_lsdb_lookup(type
, id
, adv_router
, v
->area
->lsdb
);
187 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
188 char ibuf
[16], abuf
[16];
189 inet_ntop(AF_INET
, &id
, ibuf
, sizeof(ibuf
));
190 inet_ntop(AF_INET
, &adv_router
, abuf
, sizeof(abuf
));
192 zlog_debug(" Link to: %s", lsa
->name
);
194 zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA",
195 ospf6_lstype_name(type
), ibuf
, abuf
);
201 static char *ospf6_lsdesc_backlink(struct ospf6_lsa
*lsa
, caddr_t lsdesc
,
202 struct ospf6_vertex
*v
)
204 caddr_t backlink
, found
= NULL
;
207 size
= (OSPF6_LSA_IS_TYPE(ROUTER
, lsa
)
208 ? sizeof(struct ospf6_router_lsdesc
)
209 : sizeof(struct ospf6_network_lsdesc
));
210 for (backlink
= OSPF6_LSA_HEADER_END(lsa
->header
) + 4;
211 backlink
+ size
<= OSPF6_LSA_END(lsa
->header
); backlink
+= size
) {
212 assert(!(OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)
213 && VERTEX_IS_TYPE(NETWORK
, v
)));
215 if (OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)
216 && NETWORK_LSDESC_GET_NBR_ROUTERID(backlink
)
217 == v
->lsa
->header
->adv_router
)
219 else if (VERTEX_IS_TYPE(NETWORK
, v
)
220 && ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, backlink
)
221 && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
222 == v
->lsa
->header
->adv_router
223 && ROUTER_LSDESC_GET_NBR_IFID(backlink
)
224 == ntohl(v
->lsa
->header
->id
))
227 if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, backlink
)
228 || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
))
230 if (ROUTER_LSDESC_GET_NBR_IFID(backlink
)
231 != ROUTER_LSDESC_GET_IFID(lsdesc
)
232 || ROUTER_LSDESC_GET_NBR_IFID(lsdesc
)
233 != ROUTER_LSDESC_GET_IFID(backlink
))
235 if (ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
236 != v
->lsa
->header
->adv_router
237 || ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
)
238 != lsa
->header
->adv_router
)
244 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
245 zlog_debug(" Backlink %s", (found
? "OK" : "FAIL"));
250 static void ospf6_nexthop_calc(struct ospf6_vertex
*w
, struct ospf6_vertex
*v
,
255 struct ospf6_interface
*oi
;
257 u_int32_t adv_router
;
258 struct ospf6_lsa
*lsa
;
259 struct ospf6_link_lsa
*link_lsa
;
262 assert(VERTEX_IS_TYPE(ROUTER
, w
));
263 ifindex
= (VERTEX_IS_TYPE(NETWORK
, v
) ? ospf6_spf_get_ifindex_from_nh(v
)
264 : ROUTER_LSDESC_GET_IFID(lsdesc
));
266 zlog_err("No nexthop ifindex at vertex %s", v
->name
);
270 oi
= ospf6_interface_lookup_by_ifindex(ifindex
);
272 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
273 zlog_debug("Can't find interface in SPF: ifindex %d",
278 type
= htons(OSPF6_LSTYPE_LINK
);
279 adv_router
= (VERTEX_IS_TYPE(NETWORK
, v
)
280 ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
)
281 : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
));
284 for (lsa
= ospf6_lsdb_type_router_head(type
, adv_router
, oi
->lsdb
); lsa
;
285 lsa
= ospf6_lsdb_type_router_next(type
, adv_router
, lsa
)) {
286 if (VERTEX_IS_TYPE(ROUTER
, v
)
287 && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
))
291 link_lsa
= (struct ospf6_link_lsa
*)OSPF6_LSA_HEADER_END(
293 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
294 inet_ntop(AF_INET6
, &link_lsa
->linklocal_addr
, buf
,
296 zlog_debug(" nexthop %s from %s", buf
, lsa
->name
);
299 ospf6_add_nexthop(w
->nh_list
, ifindex
,
300 &link_lsa
->linklocal_addr
);
304 if (i
== 0 && IS_OSPF6_DEBUG_SPF(PROCESS
))
305 zlog_debug("No nexthop for %s found", w
->name
);
308 static int ospf6_spf_install(struct ospf6_vertex
*v
,
309 struct ospf6_route_table
*result_table
)
311 struct ospf6_route
*route
, *parent_route
;
312 struct ospf6_vertex
*prev
;
314 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
315 zlog_debug("SPF install %s hops %d cost %d", v
->name
, v
->hops
,
318 route
= ospf6_route_lookup(&v
->vertex_id
, result_table
);
319 if (route
&& route
->path
.cost
< v
->cost
) {
320 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
322 " already installed with lower cost (%d), ignore",
324 ospf6_vertex_delete(v
);
326 } else if (route
&& route
->path
.cost
== v
->cost
) {
327 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
328 zlog_debug(" another path found, merge");
330 ospf6_spf_merge_nexthops_to_route(route
, v
);
332 prev
= (struct ospf6_vertex
*)route
->route_option
;
333 assert(prev
->hops
<= v
->hops
);
334 ospf6_vertex_delete(v
);
339 /* There should be no case where candidate being installed (variable
340 "v") is closer than the one in the SPF tree (variable "route").
341 In the case something has gone wrong with the behavior of
344 /* the case where the route exists already is handled and returned
346 assert(route
== NULL
);
348 route
= ospf6_route_create();
349 memcpy(&route
->prefix
, &v
->vertex_id
, sizeof(struct prefix
));
350 route
->type
= OSPF6_DEST_TYPE_LINKSTATE
;
351 route
->path
.type
= OSPF6_PATH_TYPE_INTRA
;
352 route
->path
.origin
.type
= v
->lsa
->header
->type
;
353 route
->path
.origin
.id
= v
->lsa
->header
->id
;
354 route
->path
.origin
.adv_router
= v
->lsa
->header
->adv_router
;
355 route
->path
.metric_type
= 1;
356 route
->path
.cost
= v
->cost
;
357 route
->path
.u
.cost_e2
= v
->hops
;
358 route
->path
.router_bits
= v
->capability
;
359 route
->path
.options
[0] = v
->options
[0];
360 route
->path
.options
[1] = v
->options
[1];
361 route
->path
.options
[2] = v
->options
[2];
363 ospf6_spf_copy_nexthops_to_route(route
, v
);
366 * The SPF logic implementation does not transfer the multipathing
368 * of a parent to a child node. Thus if there was a 3-way multipath to a
369 * node's parent and a single hop from the parent to the child, the
371 * creating new vertices and computing next hops prevents there from
373 * paths to the child node. This is primarily because the resolution of
374 * multipath is done in this routine, not in the main spf loop.
376 * The following logic addresses that problem by merging the parent's
378 * information with the child's, if the parent is not the root of the
380 * This is based on the assumption that before a node's route is
382 * its parent's route's nexthops have already been installed.
384 if (v
->parent
&& v
->parent
->hops
) {
386 ospf6_route_lookup(&v
->parent
->vertex_id
, result_table
);
388 ospf6_route_merge_nexthops(route
, parent_route
);
393 listnode_add_sort(v
->parent
->child_list
, v
);
394 route
->route_option
= v
;
396 ospf6_route_add(route
, result_table
);
400 void ospf6_spf_table_finish(struct ospf6_route_table
*result_table
)
402 struct ospf6_route
*route
, *nroute
;
403 struct ospf6_vertex
*v
;
404 for (route
= ospf6_route_head(result_table
); route
; route
= nroute
) {
405 nroute
= ospf6_route_next(route
);
406 v
= (struct ospf6_vertex
*)route
->route_option
;
407 ospf6_vertex_delete(v
);
408 ospf6_route_remove(route
, result_table
);
412 static const char *ospf6_spf_reason_str
[] = {
413 "R+", "R-", "N+", "N-", "L+", "L-", "R*", "N*",
416 void ospf6_spf_reason_string(unsigned int reason
, char *buf
, int size
)
424 for (bit
= 0; bit
< array_size(ospf6_spf_reason_str
); bit
++) {
425 if ((reason
& (1 << bit
)) && (len
< size
)) {
426 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
427 (len
> 0) ? ", " : "",
428 ospf6_spf_reason_str
[bit
]);
433 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
434 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
435 void ospf6_spf_calculation(u_int32_t router_id
,
436 struct ospf6_route_table
*result_table
,
437 struct ospf6_area
*oa
)
439 struct pqueue
*candidate_list
;
440 struct ospf6_vertex
*root
, *v
, *w
;
443 struct ospf6_lsa
*lsa
;
444 struct in6_addr address
;
446 ospf6_spf_table_finish(result_table
);
448 /* Install the calculating router itself as the root of the SPF tree */
449 /* construct root vertex */
450 lsa
= ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER
), htonl(0), router_id
,
453 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
454 zlog_debug("%s: No router LSA for area %s\n", __func__
,
460 candidate_list
= pqueue_create();
461 candidate_list
->cmp
= ospf6_vertex_cmp
;
463 root
= ospf6_vertex_create(lsa
);
467 inet_pton(AF_INET6
, "::1", &address
);
469 /* Actually insert root to the candidate-list as the only candidate */
470 pqueue_enqueue(root
, candidate_list
);
472 /* Iterate until candidate-list becomes empty */
473 while (candidate_list
->size
) {
474 /* get closest candidate from priority queue */
475 v
= pqueue_dequeue(candidate_list
);
477 /* installing may result in merging or rejecting of the vertex
479 if (ospf6_spf_install(v
, result_table
) < 0)
482 /* Skip overloaded routers */
483 if ((OSPF6_LSA_IS_TYPE(ROUTER
, v
->lsa
)
484 && ospf6_router_is_stub_router(v
->lsa
)))
487 /* For each LS description in the just-added vertex V's LSA */
488 size
= (VERTEX_IS_TYPE(ROUTER
, v
)
489 ? sizeof(struct ospf6_router_lsdesc
)
490 : sizeof(struct ospf6_network_lsdesc
));
491 for (lsdesc
= OSPF6_LSA_HEADER_END(v
->lsa
->header
) + 4;
492 lsdesc
+ size
<= OSPF6_LSA_END(v
->lsa
->header
);
494 lsa
= ospf6_lsdesc_lsa(lsdesc
, v
);
498 if (OSPF6_LSA_IS_MAXAGE(lsa
))
501 if (!ospf6_lsdesc_backlink(lsa
, lsdesc
, v
))
504 w
= ospf6_vertex_create(lsa
);
507 if (VERTEX_IS_TYPE(ROUTER
, v
)) {
509 + ROUTER_LSDESC_GET_METRIC(lsdesc
);
512 + (VERTEX_IS_TYPE(NETWORK
, w
) ? 0 : 1);
516 w
->hops
= v
->hops
+ 1;
519 /* nexthop calculation */
523 ROUTER_LSDESC_GET_IFID(lsdesc
), NULL
);
524 else if (w
->hops
== 1 && v
->hops
== 0)
525 ospf6_nexthop_calc(w
, v
, lsdesc
);
527 ospf6_copy_nexthops(w
->nh_list
, v
->nh_list
);
530 /* add new candidate to the candidate_list */
531 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
533 " New candidate: %s hops %d cost %d",
534 w
->name
, w
->hops
, w
->cost
);
535 pqueue_enqueue(w
, candidate_list
);
539 pqueue_delete(candidate_list
);
541 oa
->spf_calculation
++;
544 static void ospf6_spf_log_database(struct ospf6_area
*oa
)
546 char *p
, *end
, buffer
[256];
547 struct listnode
*node
;
548 struct ospf6_interface
*oi
;
551 end
= buffer
+ sizeof(buffer
);
553 snprintf(p
, end
- p
, "SPF on DB (#LSAs):");
554 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
555 snprintf(p
, end
- p
, " Area %s: %d", oa
->name
, oa
->lsdb
->count
);
556 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
558 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
559 snprintf(p
, end
- p
, " I/F %s: %d", oi
->interface
->name
,
561 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
)
565 zlog_debug("%s", buffer
);
568 static int ospf6_spf_calculation_thread(struct thread
*t
)
570 struct ospf6_area
*oa
;
572 struct timeval start
, end
, runtime
;
573 struct listnode
*node
;
574 int areas_processed
= 0;
577 ospf6
= (struct ospf6
*)THREAD_ARG(t
);
578 ospf6
->t_spf_calc
= NULL
;
580 /* execute SPF calculation */
583 if (ospf6_is_router_abr(ospf6
))
584 ospf6_abr_range_reset_cost(ospf6
);
586 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, oa
)) {
588 if (oa
== ospf6
->backbone
)
591 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
592 zlog_debug("SPF calculation for Area %s", oa
->name
);
593 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
594 ospf6_spf_log_database(oa
);
596 ospf6_spf_calculation(ospf6
->router_id
, oa
->spf_table
, oa
);
597 ospf6_intra_route_calculation(oa
);
598 ospf6_intra_brouter_calculation(oa
);
603 if (ospf6
->backbone
) {
604 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
605 zlog_debug("SPF calculation for Backbone area %s",
606 ospf6
->backbone
->name
);
607 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
608 ospf6_spf_log_database(ospf6
->backbone
);
610 ospf6_spf_calculation(ospf6
->router_id
,
611 ospf6
->backbone
->spf_table
,
613 ospf6_intra_route_calculation(ospf6
->backbone
);
614 ospf6_intra_brouter_calculation(ospf6
->backbone
);
618 if (ospf6_is_router_abr(ospf6
))
619 ospf6_abr_defaults_to_stub(ospf6
);
622 timersub(&end
, &start
, &runtime
);
624 ospf6
->ts_spf_duration
= runtime
;
626 ospf6_spf_reason_string(ospf6
->spf_reason
, rbuf
, sizeof(rbuf
));
628 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
629 zlog_debug("SPF runtime: %lld sec %lld usec",
630 (long long)runtime
.tv_sec
,
631 (long long)runtime
.tv_usec
);
634 "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
636 areas_processed
, (long long)runtime
.tv_sec
,
637 (long long)runtime
.tv_usec
, rbuf
);
638 ospf6
->last_spf_reason
= ospf6
->spf_reason
;
639 ospf6_reset_spf_reason(ospf6
);
643 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
644 set timer for SPF calc. */
645 void ospf6_spf_schedule(struct ospf6
*ospf6
, unsigned int reason
)
647 unsigned long delay
, elapsed
, ht
;
649 ospf6_set_spf_reason(ospf6
, reason
);
651 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
)) {
653 ospf6_spf_reason_string(reason
, rbuf
, sizeof(rbuf
));
654 zlog_debug("SPF: calculation timer scheduled (reason %s)",
658 /* OSPF instance does not exist. */
662 /* SPF calculation timer is already scheduled. */
663 if (ospf6
->t_spf_calc
) {
664 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
666 "SPF: calculation timer is already scheduled: %p",
667 (void *)ospf6
->t_spf_calc
);
671 elapsed
= monotime_since(&ospf6
->ts_spf
, NULL
) / 1000LL;
672 ht
= ospf6
->spf_holdtime
* ospf6
->spf_hold_multiplier
;
674 if (ht
> ospf6
->spf_max_holdtime
)
675 ht
= ospf6
->spf_max_holdtime
;
677 /* Get SPF calculation delay time. */
679 /* Got an event within the hold time of last SPF. We need to
680 * increase the hold_multiplier, if it's not already at/past
681 * maximum value, and wasn't already increased..
683 if (ht
< ospf6
->spf_max_holdtime
)
684 ospf6
->spf_hold_multiplier
++;
686 /* always honour the SPF initial delay */
687 if ((ht
- elapsed
) < ospf6
->spf_delay
)
688 delay
= ospf6
->spf_delay
;
690 delay
= ht
- elapsed
;
692 /* Event is past required hold-time of last SPF */
693 delay
= ospf6
->spf_delay
;
694 ospf6
->spf_hold_multiplier
= 1;
697 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
698 zlog_debug("SPF: calculation timer delay = %ld", delay
);
700 zlog_info("SPF: Scheduled in %ld msec", delay
);
702 ospf6
->t_spf_calc
= thread_add_timer_msec(
703 master
, ospf6_spf_calculation_thread
, ospf6
, delay
);
706 void ospf6_spf_display_subtree(struct vty
*vty
, const char *prefix
, int rest
,
707 struct ospf6_vertex
*v
)
709 struct listnode
*node
, *nnode
;
710 struct ospf6_vertex
*c
;
715 /* "prefix" is the space prefix of the display line */
716 vty_out(vty
, "%s+-%s [%d]%s", prefix
, v
->name
, v
->cost
, VNL
);
718 len
= strlen(prefix
) + 4;
719 next_prefix
= (char *)malloc(len
);
720 if (next_prefix
== NULL
) {
721 vty_out(vty
, "malloc failed%s", VNL
);
724 snprintf(next_prefix
, len
, "%s%s", prefix
, (rest
? "| " : " "));
726 restnum
= listcount(v
->child_list
);
727 for (ALL_LIST_ELEMENTS(v
->child_list
, node
, nnode
, c
)) {
729 ospf6_spf_display_subtree(vty
, next_prefix
, restnum
, c
);
735 DEFUN (debug_ospf6_spf_process
,
736 debug_ospf6_spf_process_cmd
,
737 "debug ospf6 spf process",
740 "Debug SPF Calculation\n"
741 "Debug Detailed SPF Process\n"
744 unsigned char level
= 0;
745 level
= OSPF6_DEBUG_SPF_PROCESS
;
746 OSPF6_DEBUG_SPF_ON(level
);
750 DEFUN (debug_ospf6_spf_time
,
751 debug_ospf6_spf_time_cmd
,
752 "debug ospf6 spf time",
755 "Debug SPF Calculation\n"
756 "Measure time taken by SPF Calculation\n"
759 unsigned char level
= 0;
760 level
= OSPF6_DEBUG_SPF_TIME
;
761 OSPF6_DEBUG_SPF_ON(level
);
765 DEFUN (debug_ospf6_spf_database
,
766 debug_ospf6_spf_database_cmd
,
767 "debug ospf6 spf database",
770 "Debug SPF Calculation\n"
771 "Log number of LSAs at SPF Calculation time\n"
774 unsigned char level
= 0;
775 level
= OSPF6_DEBUG_SPF_DATABASE
;
776 OSPF6_DEBUG_SPF_ON(level
);
780 DEFUN (no_debug_ospf6_spf_process
,
781 no_debug_ospf6_spf_process_cmd
,
782 "no debug ospf6 spf process",
786 "Quit Debugging SPF Calculation\n"
787 "Quit Debugging Detailed SPF Process\n"
790 unsigned char level
= 0;
791 level
= OSPF6_DEBUG_SPF_PROCESS
;
792 OSPF6_DEBUG_SPF_OFF(level
);
796 DEFUN (no_debug_ospf6_spf_time
,
797 no_debug_ospf6_spf_time_cmd
,
798 "no debug ospf6 spf time",
802 "Quit Debugging SPF Calculation\n"
803 "Quit Measuring time taken by SPF Calculation\n"
806 unsigned char level
= 0;
807 level
= OSPF6_DEBUG_SPF_TIME
;
808 OSPF6_DEBUG_SPF_OFF(level
);
812 DEFUN (no_debug_ospf6_spf_database
,
813 no_debug_ospf6_spf_database_cmd
,
814 "no debug ospf6 spf database",
818 "Debug SPF Calculation\n"
819 "Quit Logging number of LSAs at SPF Calculation time\n"
822 unsigned char level
= 0;
823 level
= OSPF6_DEBUG_SPF_DATABASE
;
824 OSPF6_DEBUG_SPF_OFF(level
);
828 static int ospf6_timers_spf_set(struct vty
*vty
, unsigned int delay
,
829 unsigned int hold
, unsigned int max
)
831 VTY_DECLVAR_CONTEXT(ospf6
, ospf
);
833 ospf
->spf_delay
= delay
;
834 ospf
->spf_holdtime
= hold
;
835 ospf
->spf_max_holdtime
= max
;
840 DEFUN (ospf6_timers_throttle_spf
,
841 ospf6_timers_throttle_spf_cmd
,
842 "timers throttle spf (0-600000) (0-600000) (0-600000)",
843 "Adjust routing timers\n"
844 "Throttling adaptive timer\n"
846 "Delay (msec) from first change received till SPF calculation\n"
847 "Initial hold time (msec) between consecutive SPF calculations\n"
848 "Maximum hold time (msec)\n")
851 int idx_number_2
= 4;
852 int idx_number_3
= 5;
853 unsigned int delay
, hold
, max
;
855 VTY_GET_INTEGER_RANGE("SPF delay timer", delay
, argv
[idx_number
]->arg
,
857 VTY_GET_INTEGER_RANGE("SPF hold timer", hold
, argv
[idx_number_2
]->arg
,
859 VTY_GET_INTEGER_RANGE("SPF max-hold timer", max
,
860 argv
[idx_number_3
]->arg
, 0, 600000);
862 return ospf6_timers_spf_set(vty
, delay
, hold
, max
);
865 DEFUN (no_ospf6_timers_throttle_spf
,
866 no_ospf6_timers_throttle_spf_cmd
,
867 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
869 "Adjust routing timers\n"
870 "Throttling adaptive timer\n"
872 "Delay (msec) from first change received till SPF calculation\n"
873 "Initial hold time (msec) between consecutive SPF calculations\n"
874 "Maximum hold time (msec)\n")
876 return ospf6_timers_spf_set(vty
, OSPF_SPF_DELAY_DEFAULT
,
877 OSPF_SPF_HOLDTIME_DEFAULT
,
878 OSPF_SPF_MAX_HOLDTIME_DEFAULT
);
882 int config_write_ospf6_debug_spf(struct vty
*vty
)
884 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
885 vty_out(vty
, "debug ospf6 spf process%s", VNL
);
886 if (IS_OSPF6_DEBUG_SPF(TIME
))
887 vty_out(vty
, "debug ospf6 spf time%s", VNL
);
888 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
889 vty_out(vty
, "debug ospf6 spf database%s", VNL
);
893 void ospf6_spf_config_write(struct vty
*vty
)
896 if (ospf6
->spf_delay
!= OSPF_SPF_DELAY_DEFAULT
897 || ospf6
->spf_holdtime
!= OSPF_SPF_HOLDTIME_DEFAULT
898 || ospf6
->spf_max_holdtime
!= OSPF_SPF_MAX_HOLDTIME_DEFAULT
)
899 vty_out(vty
, " timers throttle spf %d %d %d%s",
900 ospf6
->spf_delay
, ospf6
->spf_holdtime
,
901 ospf6
->spf_max_holdtime
, VTY_NEWLINE
);
904 void install_element_ospf6_debug_spf(void)
906 install_element(ENABLE_NODE
, &debug_ospf6_spf_process_cmd
);
907 install_element(ENABLE_NODE
, &debug_ospf6_spf_time_cmd
);
908 install_element(ENABLE_NODE
, &debug_ospf6_spf_database_cmd
);
909 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_process_cmd
);
910 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_time_cmd
);
911 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_database_cmd
);
912 install_element(CONFIG_NODE
, &debug_ospf6_spf_process_cmd
);
913 install_element(CONFIG_NODE
, &debug_ospf6_spf_time_cmd
);
914 install_element(CONFIG_NODE
, &debug_ospf6_spf_database_cmd
);
915 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_process_cmd
);
916 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_time_cmd
);
917 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_database_cmd
);
920 void ospf6_spf_init(void)
922 install_element(OSPF6_NODE
, &ospf6_timers_throttle_spf_cmd
);
923 install_element(OSPF6_NODE
, &no_ospf6_timers_throttle_spf_cmd
);