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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 /* Shortest Path First calculation for OSPFv3 */
32 #include "lib_errors.h"
34 #include "ospf6_lsa.h"
35 #include "ospf6_lsdb.h"
36 #include "ospf6_route.h"
37 #include "ospf6_area.h"
38 #include "ospf6_proto.h"
39 #include "ospf6_abr.h"
40 #include "ospf6_asbr.h"
41 #include "ospf6_spf.h"
42 #include "ospf6_intra.h"
43 #include "ospf6_interface.h"
45 #include "ospf6_abr.h"
46 #include "ospf6_nssa.h"
48 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_VERTEX
, "OSPF6 vertex");
50 unsigned char conf_debug_ospf6_spf
= 0;
52 static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route
*rt
,
53 struct ospf6_vertex
*v
)
56 ospf6_copy_nexthops(rt
->nh_list
, v
->nh_list
);
59 static void ospf6_spf_merge_nexthops_to_route(struct ospf6_route
*rt
,
60 struct ospf6_vertex
*v
)
63 ospf6_merge_nexthops(rt
->nh_list
, v
->nh_list
);
66 static unsigned int ospf6_spf_get_ifindex_from_nh(struct ospf6_vertex
*v
)
68 struct ospf6_nexthop
*nh
;
69 struct listnode
*node
;
72 node
= listhead(v
->nh_list
);
74 nh
= listgetdata(node
);
82 static int ospf6_vertex_cmp(const struct ospf6_vertex
*va
,
83 const struct ospf6_vertex
*vb
)
86 if (va
->cost
!= vb
->cost
)
87 return (va
->cost
- vb
->cost
);
88 if (va
->hops
!= vb
->hops
)
89 return (va
->hops
- vb
->hops
);
92 DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue
, struct ospf6_vertex
, pqi
,
95 static int ospf6_vertex_id_cmp(void *a
, void *b
)
97 struct ospf6_vertex
*va
= (struct ospf6_vertex
*)a
;
98 struct ospf6_vertex
*vb
= (struct ospf6_vertex
*)b
;
101 ret
= ntohl(ospf6_linkstate_prefix_adv_router(&va
->vertex_id
))
102 - ntohl(ospf6_linkstate_prefix_adv_router(&vb
->vertex_id
));
106 ret
= ntohl(ospf6_linkstate_prefix_id(&va
->vertex_id
))
107 - ntohl(ospf6_linkstate_prefix_id(&vb
->vertex_id
));
111 static struct ospf6_vertex
*ospf6_vertex_create(struct ospf6_lsa
*lsa
)
113 struct ospf6_vertex
*v
;
115 v
= XMALLOC(MTYPE_OSPF6_VERTEX
, sizeof(struct ospf6_vertex
));
118 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
) {
119 v
->type
= OSPF6_VERTEX_TYPE_ROUTER
;
120 /* Router LSA use Link ID 0 as base in vertex_id */
121 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0),
123 } else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_NETWORK
) {
124 v
->type
= OSPF6_VERTEX_TYPE_NETWORK
;
126 ospf6_linkstate_prefix(lsa
->header
->adv_router
, lsa
->header
->id
,
132 ospf6_linkstate_prefix2str(&v
->vertex_id
, v
->name
, sizeof(v
->name
));
134 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
135 zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s",
137 ((ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
)
140 ntohs(lsa
->header
->type
), lsa
->name
);
146 /* capability bits + options */
147 v
->capability
= *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
));
148 v
->options
[0] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 1);
149 v
->options
[1] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 2);
150 v
->options
[2] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 3);
152 v
->nh_list
= list_new();
153 v
->nh_list
->cmp
= (int (*)(void *, void *))ospf6_nexthop_cmp
;
154 v
->nh_list
->del
= (void (*)(void *))ospf6_nexthop_delete
;
157 v
->child_list
= list_new();
158 v
->child_list
->cmp
= ospf6_vertex_id_cmp
;
163 static void ospf6_vertex_delete(struct ospf6_vertex
*v
)
165 list_delete(&v
->nh_list
);
166 list_delete(&v
->child_list
);
167 XFREE(MTYPE_OSPF6_VERTEX
, v
);
170 static struct ospf6_lsa
*ospf6_lsdesc_lsa(caddr_t lsdesc
,
171 struct ospf6_vertex
*v
)
173 struct ospf6_lsa
*lsa
= NULL
;
175 uint32_t id
= 0, adv_router
= 0;
177 if (VERTEX_IS_TYPE(NETWORK
, v
)) {
178 type
= htons(OSPF6_LSTYPE_ROUTER
);
180 adv_router
= NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
);
182 if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
)) {
183 type
= htons(OSPF6_LSTYPE_ROUTER
);
185 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
186 } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, lsdesc
)) {
187 type
= htons(OSPF6_LSTYPE_NETWORK
);
188 id
= htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
));
189 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
193 if (type
== htons(OSPF6_LSTYPE_NETWORK
))
194 lsa
= ospf6_lsdb_lookup(type
, id
, adv_router
, v
->area
->lsdb
);
196 lsa
= ospf6_create_single_router_lsa(v
->area
, v
->area
->lsdb
,
198 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
199 char ibuf
[16], abuf
[16];
200 inet_ntop(AF_INET
, &id
, ibuf
, sizeof(ibuf
));
201 inet_ntop(AF_INET
, &adv_router
, abuf
, sizeof(abuf
));
203 zlog_debug(" Link to: %s len %u, V %s", lsa
->name
,
204 ntohs(lsa
->header
->length
), v
->name
);
206 zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s",
207 ospf6_lstype_name(type
), ibuf
, abuf
,
214 static char *ospf6_lsdesc_backlink(struct ospf6_lsa
*lsa
, caddr_t lsdesc
,
215 struct ospf6_vertex
*v
)
217 caddr_t backlink
, found
= NULL
;
220 size
= (OSPF6_LSA_IS_TYPE(ROUTER
, lsa
)
221 ? sizeof(struct ospf6_router_lsdesc
)
222 : sizeof(struct ospf6_network_lsdesc
));
223 for (backlink
= OSPF6_LSA_HEADER_END(lsa
->header
) + 4;
224 backlink
+ size
<= OSPF6_LSA_END(lsa
->header
); backlink
+= size
) {
225 assert(!(OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)
226 && VERTEX_IS_TYPE(NETWORK
, v
)));
228 if (OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)
229 && NETWORK_LSDESC_GET_NBR_ROUTERID(backlink
)
230 == v
->lsa
->header
->adv_router
)
232 else if (VERTEX_IS_TYPE(NETWORK
, v
)
233 && ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, backlink
)
234 && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
235 == v
->lsa
->header
->adv_router
236 && ROUTER_LSDESC_GET_NBR_IFID(backlink
)
237 == ntohl(v
->lsa
->header
->id
))
240 if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, backlink
)
241 || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
))
243 if (ROUTER_LSDESC_GET_NBR_IFID(backlink
)
244 != ROUTER_LSDESC_GET_IFID(lsdesc
)
245 || ROUTER_LSDESC_GET_NBR_IFID(lsdesc
)
246 != ROUTER_LSDESC_GET_IFID(backlink
))
248 if (ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
249 != v
->lsa
->header
->adv_router
250 || ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
)
251 != lsa
->header
->adv_router
)
257 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
258 zlog_debug("Vertex %s Lsa %s Backlink %s", v
->name
, lsa
->name
,
259 (found
? "OK" : "FAIL"));
264 static void ospf6_nexthop_calc(struct ospf6_vertex
*w
, struct ospf6_vertex
*v
,
265 caddr_t lsdesc
, struct ospf6
*ospf6
)
269 struct ospf6_interface
*oi
;
272 struct ospf6_lsa
*lsa
;
273 struct ospf6_link_lsa
*link_lsa
;
276 assert(VERTEX_IS_TYPE(ROUTER
, w
));
277 ifindex
= (VERTEX_IS_TYPE(NETWORK
, v
) ? ospf6_spf_get_ifindex_from_nh(v
)
278 : ROUTER_LSDESC_GET_IFID(lsdesc
));
280 flog_err(EC_LIB_DEVELOPMENT
, "No nexthop ifindex at vertex %s",
285 oi
= ospf6_interface_lookup_by_ifindex(ifindex
, ospf6
->vrf_id
);
287 zlog_warn("Can't find interface in SPF: ifindex %d", ifindex
);
291 type
= htons(OSPF6_LSTYPE_LINK
);
292 adv_router
= (VERTEX_IS_TYPE(NETWORK
, v
)
293 ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
)
294 : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
));
297 for (ALL_LSDB_TYPED_ADVRTR(oi
->lsdb
, type
, adv_router
, lsa
)) {
298 if (VERTEX_IS_TYPE(ROUTER
, v
)
299 && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
))
303 link_lsa
= (struct ospf6_link_lsa
*)OSPF6_LSA_HEADER_END(
305 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
306 inet_ntop(AF_INET6
, &link_lsa
->linklocal_addr
, buf
,
308 zlog_debug(" nexthop %s from %s", buf
, lsa
->name
);
311 ospf6_add_nexthop(w
->nh_list
, ifindex
,
312 &link_lsa
->linklocal_addr
);
316 if (i
== 0 && IS_OSPF6_DEBUG_SPF(PROCESS
))
317 zlog_debug("No nexthop for %s found", w
->name
);
320 static int ospf6_spf_install(struct ospf6_vertex
*v
,
321 struct ospf6_route_table
*result_table
)
323 struct ospf6_route
*route
, *parent_route
;
324 struct ospf6_vertex
*prev
;
326 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
327 zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v
->name
,
328 v
->lsa
->name
, v
->hops
, v
->cost
);
330 route
= ospf6_route_lookup(&v
->vertex_id
, result_table
);
331 if (route
&& route
->path
.cost
< v
->cost
) {
332 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
334 " already installed with lower cost (%d), ignore",
336 ospf6_vertex_delete(v
);
338 } else if (route
&& route
->path
.cost
== v
->cost
) {
339 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
341 " another path found to route %pFX lsa %s, merge",
342 &route
->prefix
, v
->lsa
->name
);
343 ospf6_spf_merge_nexthops_to_route(route
, v
);
345 prev
= (struct ospf6_vertex
*)route
->route_option
;
346 assert(prev
->hops
<= v
->hops
);
348 if ((VERTEX_IS_TYPE(ROUTER
, v
)
349 && route
->path
.origin
.id
!= v
->lsa
->header
->id
)) {
350 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
352 "%s: V lsa %s id %u, route id %u are different",
353 __func__
, v
->lsa
->name
,
354 ntohl(v
->lsa
->header
->id
),
355 ntohl(route
->path
.origin
.id
));
360 ospf6_vertex_delete(v
);
364 /* There should be no case where candidate being installed (variable
365 "v") is closer than the one in the SPF tree (variable "route").
366 In the case something has gone wrong with the behavior of
369 /* the case where the route exists already is handled and returned
371 assert(route
== NULL
);
373 route
= ospf6_route_create();
374 memcpy(&route
->prefix
, &v
->vertex_id
, sizeof(struct prefix
));
375 route
->type
= OSPF6_DEST_TYPE_LINKSTATE
;
376 route
->path
.type
= OSPF6_PATH_TYPE_INTRA
;
377 route
->path
.origin
.type
= v
->lsa
->header
->type
;
378 route
->path
.origin
.id
= v
->lsa
->header
->id
;
379 route
->path
.origin
.adv_router
= v
->lsa
->header
->adv_router
;
380 route
->path
.metric_type
= 1;
381 route
->path
.cost
= v
->cost
;
382 route
->path
.u
.cost_e2
= v
->hops
;
383 route
->path
.router_bits
= v
->capability
;
384 route
->path
.options
[0] = v
->options
[0];
385 route
->path
.options
[1] = v
->options
[1];
386 route
->path
.options
[2] = v
->options
[2];
388 ospf6_spf_copy_nexthops_to_route(route
, v
);
391 * The SPF logic implementation does not transfer the multipathing
393 * of a parent to a child node. Thus if there was a 3-way multipath to a
394 * node's parent and a single hop from the parent to the child, the
396 * creating new vertices and computing next hops prevents there from
398 * paths to the child node. This is primarily because the resolution of
399 * multipath is done in this routine, not in the main spf loop.
401 * The following logic addresses that problem by merging the parent's
403 * information with the child's, if the parent is not the root of the
405 * This is based on the assumption that before a node's route is
407 * its parent's route's nexthops have already been installed.
409 if (v
->parent
&& v
->parent
->hops
) {
411 ospf6_route_lookup(&v
->parent
->vertex_id
, result_table
);
413 ospf6_route_merge_nexthops(route
, parent_route
);
418 listnode_add_sort(v
->parent
->child_list
, v
);
419 route
->route_option
= v
;
421 ospf6_route_add(route
, result_table
);
425 void ospf6_spf_table_finish(struct ospf6_route_table
*result_table
)
427 struct ospf6_route
*route
, *nroute
;
428 struct ospf6_vertex
*v
;
429 for (route
= ospf6_route_head(result_table
); route
; route
= nroute
) {
430 nroute
= ospf6_route_next(route
);
431 v
= (struct ospf6_vertex
*)route
->route_option
;
432 ospf6_vertex_delete(v
);
433 ospf6_route_remove(route
, result_table
);
437 static const char *const ospf6_spf_reason_str
[] = {"R+", "R-", "N+", "N-", "L+",
438 "L-", "R*", "N*", "C"};
440 void ospf6_spf_reason_string(unsigned int reason
, char *buf
, int size
)
448 for (bit
= 0; bit
< array_size(ospf6_spf_reason_str
); bit
++) {
449 if ((reason
& (1 << bit
)) && (len
< size
)) {
450 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
451 (len
> 0) ? ", " : "",
452 ospf6_spf_reason_str
[bit
]);
457 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
458 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
459 void ospf6_spf_calculation(uint32_t router_id
,
460 struct ospf6_route_table
*result_table
,
461 struct ospf6_area
*oa
)
463 struct vertex_pqueue_head candidate_list
;
464 struct ospf6_vertex
*root
, *v
, *w
;
467 struct ospf6_lsa
*lsa
;
468 struct in6_addr address
;
470 ospf6_spf_table_finish(result_table
);
472 /* Install the calculating router itself as the root of the SPF tree */
473 /* construct root vertex */
474 lsa
= ospf6_create_single_router_lsa(oa
, oa
->lsdb_self
, router_id
);
476 zlog_warn("%s: No router LSA for area %s", __func__
, oa
->name
);
481 vertex_pqueue_init(&candidate_list
);
483 root
= ospf6_vertex_create(lsa
);
487 root
->link_id
= lsa
->header
->id
;
488 inet_pton(AF_INET6
, "::1", &address
);
490 /* Actually insert root to the candidate-list as the only candidate */
491 vertex_pqueue_add(&candidate_list
, root
);
493 /* Iterate until candidate-list becomes empty */
494 while ((v
= vertex_pqueue_pop(&candidate_list
))) {
495 /* installing may result in merging or rejecting of the vertex
497 if (ospf6_spf_install(v
, result_table
) < 0)
500 /* Skip overloaded routers */
501 if ((OSPF6_LSA_IS_TYPE(ROUTER
, v
->lsa
)
502 && ospf6_router_is_stub_router(v
->lsa
)))
505 /* For each LS description in the just-added vertex V's LSA */
506 size
= (VERTEX_IS_TYPE(ROUTER
, v
)
507 ? sizeof(struct ospf6_router_lsdesc
)
508 : sizeof(struct ospf6_network_lsdesc
));
509 for (lsdesc
= OSPF6_LSA_HEADER_END(v
->lsa
->header
) + 4;
510 lsdesc
+ size
<= OSPF6_LSA_END(v
->lsa
->header
);
512 lsa
= ospf6_lsdesc_lsa(lsdesc
, v
);
516 if (OSPF6_LSA_IS_MAXAGE(lsa
))
519 if (!ospf6_lsdesc_backlink(lsa
, lsdesc
, v
))
522 w
= ospf6_vertex_create(lsa
);
525 if (VERTEX_IS_TYPE(ROUTER
, v
)) {
527 + ROUTER_LSDESC_GET_METRIC(lsdesc
);
530 + (VERTEX_IS_TYPE(NETWORK
, w
) ? 0 : 1);
534 w
->hops
= v
->hops
+ 1;
537 /* nexthop calculation */
541 ROUTER_LSDESC_GET_IFID(lsdesc
), NULL
);
542 else if (w
->hops
== 1 && v
->hops
== 0)
543 ospf6_nexthop_calc(w
, v
, lsdesc
, oa
->ospf6
);
545 ospf6_copy_nexthops(w
->nh_list
, v
->nh_list
);
548 /* add new candidate to the candidate_list */
549 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
551 " New candidate: %s hops %d cost %d",
552 w
->name
, w
->hops
, w
->cost
);
553 vertex_pqueue_add(&candidate_list
, w
);
557 //vertex_pqueue_fini(&candidate_list);
559 ospf6_remove_temp_router_lsa(oa
);
561 oa
->spf_calculation
++;
564 static void ospf6_spf_log_database(struct ospf6_area
*oa
)
566 char *p
, *end
, buffer
[256];
567 struct listnode
*node
;
568 struct ospf6_interface
*oi
;
571 end
= buffer
+ sizeof(buffer
);
573 snprintf(p
, end
- p
, "SPF on DB (#LSAs):");
574 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
575 snprintf(p
, end
- p
, " Area %s: %d", oa
->name
, oa
->lsdb
->count
);
576 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
578 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
579 snprintf(p
, end
- p
, " I/F %s: %d", oi
->interface
->name
,
581 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
)
585 zlog_debug("%s", buffer
);
588 static int ospf6_spf_calculation_thread(struct thread
*t
)
590 struct ospf6_area
*oa
;
592 struct timeval start
, end
, runtime
;
593 struct listnode
*node
;
594 int areas_processed
= 0;
597 ospf6
= (struct ospf6
*)THREAD_ARG(t
);
598 ospf6
->t_spf_calc
= NULL
;
600 /* execute SPF calculation */
602 ospf6
->ts_spf
= start
;
604 if (ospf6_check_and_set_router_abr(ospf6
))
605 ospf6_abr_range_reset_cost(ospf6
);
607 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, oa
)) {
609 if (oa
== ospf6
->backbone
)
612 monotime(&oa
->ts_spf
);
613 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
614 zlog_debug("SPF calculation for Area %s", oa
->name
);
615 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
616 ospf6_spf_log_database(oa
);
618 ospf6_spf_calculation(ospf6
->router_id
, oa
->spf_table
, oa
);
619 ospf6_intra_route_calculation(oa
);
620 ospf6_intra_brouter_calculation(oa
);
625 if (ospf6
->backbone
) {
626 monotime(&ospf6
->backbone
->ts_spf
);
627 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
628 zlog_debug("SPF calculation for Backbone area %s",
629 ospf6
->backbone
->name
);
630 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
631 ospf6_spf_log_database(ospf6
->backbone
);
633 ospf6_spf_calculation(ospf6
->router_id
,
634 ospf6
->backbone
->spf_table
,
636 ospf6_intra_route_calculation(ospf6
->backbone
);
637 ospf6_intra_brouter_calculation(ospf6
->backbone
);
641 /* External LSA calculation */
642 ospf6_ase_calculate_timer_add(ospf6
);
644 if (ospf6_check_and_set_router_abr(ospf6
))
645 ospf6_abr_defaults_to_stub(ospf6
);
648 timersub(&end
, &start
, &runtime
);
650 ospf6
->ts_spf_duration
= runtime
;
652 ospf6_spf_reason_string(ospf6
->spf_reason
, rbuf
, sizeof(rbuf
));
654 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
656 "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s",
657 areas_processed
, (long long)runtime
.tv_sec
,
658 (long long)runtime
.tv_usec
, rbuf
);
660 ospf6
->last_spf_reason
= ospf6
->spf_reason
;
661 ospf6_reset_spf_reason(ospf6
);
665 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
666 set timer for SPF calc. */
667 void ospf6_spf_schedule(struct ospf6
*ospf6
, unsigned int reason
)
669 unsigned long delay
, elapsed
, ht
;
671 /* OSPF instance does not exist. */
675 ospf6_set_spf_reason(ospf6
, reason
);
677 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
)) {
679 ospf6_spf_reason_string(reason
, rbuf
, sizeof(rbuf
));
680 zlog_debug("SPF: calculation timer scheduled (reason %s)",
684 /* SPF calculation timer is already scheduled. */
685 if (ospf6
->t_spf_calc
) {
686 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
688 "SPF: calculation timer is already scheduled: %p",
689 (void *)ospf6
->t_spf_calc
);
693 elapsed
= monotime_since(&ospf6
->ts_spf
, NULL
) / 1000LL;
694 ht
= ospf6
->spf_holdtime
* ospf6
->spf_hold_multiplier
;
696 if (ht
> ospf6
->spf_max_holdtime
)
697 ht
= ospf6
->spf_max_holdtime
;
699 /* Get SPF calculation delay time. */
701 /* Got an event within the hold time of last SPF. We need to
702 * increase the hold_multiplier, if it's not already at/past
703 * maximum value, and wasn't already increased..
705 if (ht
< ospf6
->spf_max_holdtime
)
706 ospf6
->spf_hold_multiplier
++;
708 /* always honour the SPF initial delay */
709 if ((ht
- elapsed
) < ospf6
->spf_delay
)
710 delay
= ospf6
->spf_delay
;
712 delay
= ht
- elapsed
;
714 /* Event is past required hold-time of last SPF */
715 delay
= ospf6
->spf_delay
;
716 ospf6
->spf_hold_multiplier
= 1;
719 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
720 zlog_debug("SPF: Rescheduling in %ld msec", delay
);
722 ospf6
->t_spf_calc
= NULL
;
723 thread_add_timer_msec(master
, ospf6_spf_calculation_thread
, ospf6
,
724 delay
, &ospf6
->t_spf_calc
);
727 void ospf6_spf_display_subtree(struct vty
*vty
, const char *prefix
, int rest
,
728 struct ospf6_vertex
*v
, json_object
*json_obj
,
731 struct listnode
*node
, *nnode
;
732 struct ospf6_vertex
*c
;
736 json_object
*json_childs
= NULL
;
737 json_object
*json_child
= NULL
;
740 json_childs
= json_object_new_object();
741 json_object_int_add(json_obj
, "cost", v
->cost
);
743 /* "prefix" is the space prefix of the display line */
744 vty_out(vty
, "%s+-%s [%d]\n", prefix
, v
->name
, v
->cost
);
747 len
= strlen(prefix
) + 4;
748 next_prefix
= (char *)malloc(len
);
749 if (next_prefix
== NULL
) {
750 vty_out(vty
, "malloc failed\n");
753 snprintf(next_prefix
, len
, "%s%s", prefix
, (rest
? "| " : " "));
755 restnum
= listcount(v
->child_list
);
756 for (ALL_LIST_ELEMENTS(v
->child_list
, node
, nnode
, c
)) {
758 json_child
= json_object_new_object();
762 ospf6_spf_display_subtree(vty
, next_prefix
, restnum
, c
,
763 json_child
, use_json
);
766 json_object_object_add(json_childs
, c
->name
,
770 json_object_boolean_add(json_obj
, "isLeafNode",
771 !listcount(v
->child_list
));
772 if (listcount(v
->child_list
))
773 json_object_object_add(json_obj
, "children",
776 json_object_free(json_childs
);
781 DEFUN (debug_ospf6_spf_process
,
782 debug_ospf6_spf_process_cmd
,
783 "debug ospf6 spf process",
786 "Debug SPF Calculation\n"
787 "Debug Detailed SPF Process\n"
790 unsigned char level
= 0;
791 level
= OSPF6_DEBUG_SPF_PROCESS
;
792 OSPF6_DEBUG_SPF_ON(level
);
796 DEFUN (debug_ospf6_spf_time
,
797 debug_ospf6_spf_time_cmd
,
798 "debug ospf6 spf time",
801 "Debug SPF Calculation\n"
802 "Measure time taken by SPF Calculation\n"
805 unsigned char level
= 0;
806 level
= OSPF6_DEBUG_SPF_TIME
;
807 OSPF6_DEBUG_SPF_ON(level
);
811 DEFUN (debug_ospf6_spf_database
,
812 debug_ospf6_spf_database_cmd
,
813 "debug ospf6 spf database",
816 "Debug SPF Calculation\n"
817 "Log number of LSAs at SPF Calculation time\n"
820 unsigned char level
= 0;
821 level
= OSPF6_DEBUG_SPF_DATABASE
;
822 OSPF6_DEBUG_SPF_ON(level
);
826 DEFUN (no_debug_ospf6_spf_process
,
827 no_debug_ospf6_spf_process_cmd
,
828 "no debug ospf6 spf process",
832 "Quit Debugging SPF Calculation\n"
833 "Quit Debugging Detailed SPF Process\n"
836 unsigned char level
= 0;
837 level
= OSPF6_DEBUG_SPF_PROCESS
;
838 OSPF6_DEBUG_SPF_OFF(level
);
842 DEFUN (no_debug_ospf6_spf_time
,
843 no_debug_ospf6_spf_time_cmd
,
844 "no debug ospf6 spf time",
848 "Quit Debugging SPF Calculation\n"
849 "Quit Measuring time taken by SPF Calculation\n"
852 unsigned char level
= 0;
853 level
= OSPF6_DEBUG_SPF_TIME
;
854 OSPF6_DEBUG_SPF_OFF(level
);
858 DEFUN (no_debug_ospf6_spf_database
,
859 no_debug_ospf6_spf_database_cmd
,
860 "no debug ospf6 spf database",
864 "Debug SPF Calculation\n"
865 "Quit Logging number of LSAs at SPF Calculation time\n"
868 unsigned char level
= 0;
869 level
= OSPF6_DEBUG_SPF_DATABASE
;
870 OSPF6_DEBUG_SPF_OFF(level
);
874 static int ospf6_timers_spf_set(struct vty
*vty
, unsigned int delay
,
875 unsigned int hold
, unsigned int max
)
877 VTY_DECLVAR_CONTEXT(ospf6
, ospf
);
879 ospf
->spf_delay
= delay
;
880 ospf
->spf_holdtime
= hold
;
881 ospf
->spf_max_holdtime
= max
;
886 DEFUN (ospf6_timers_throttle_spf
,
887 ospf6_timers_throttle_spf_cmd
,
888 "timers throttle spf (0-600000) (0-600000) (0-600000)",
889 "Adjust routing timers\n"
890 "Throttling adaptive timer\n"
892 "Delay (msec) from first change received till SPF calculation\n"
893 "Initial hold time (msec) between consecutive SPF calculations\n"
894 "Maximum hold time (msec)\n")
897 int idx_number_2
= 4;
898 int idx_number_3
= 5;
899 unsigned int delay
, hold
, max
;
901 delay
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
902 hold
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
903 max
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
905 return ospf6_timers_spf_set(vty
, delay
, hold
, max
);
908 DEFUN (no_ospf6_timers_throttle_spf
,
909 no_ospf6_timers_throttle_spf_cmd
,
910 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
912 "Adjust routing timers\n"
913 "Throttling adaptive timer\n"
915 "Delay (msec) from first change received till SPF calculation\n"
916 "Initial hold time (msec) between consecutive SPF calculations\n"
917 "Maximum hold time (msec)\n")
919 return ospf6_timers_spf_set(vty
, OSPF_SPF_DELAY_DEFAULT
,
920 OSPF_SPF_HOLDTIME_DEFAULT
,
921 OSPF_SPF_MAX_HOLDTIME_DEFAULT
);
925 int config_write_ospf6_debug_spf(struct vty
*vty
)
927 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
928 vty_out(vty
, "debug ospf6 spf process\n");
929 if (IS_OSPF6_DEBUG_SPF(TIME
))
930 vty_out(vty
, "debug ospf6 spf time\n");
931 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
932 vty_out(vty
, "debug ospf6 spf database\n");
936 void ospf6_spf_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
939 if (ospf6
->spf_delay
!= OSPF_SPF_DELAY_DEFAULT
940 || ospf6
->spf_holdtime
!= OSPF_SPF_HOLDTIME_DEFAULT
941 || ospf6
->spf_max_holdtime
!= OSPF_SPF_MAX_HOLDTIME_DEFAULT
)
942 vty_out(vty
, " timers throttle spf %d %d %d\n",
943 ospf6
->spf_delay
, ospf6
->spf_holdtime
,
944 ospf6
->spf_max_holdtime
);
947 void install_element_ospf6_debug_spf(void)
949 install_element(ENABLE_NODE
, &debug_ospf6_spf_process_cmd
);
950 install_element(ENABLE_NODE
, &debug_ospf6_spf_time_cmd
);
951 install_element(ENABLE_NODE
, &debug_ospf6_spf_database_cmd
);
952 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_process_cmd
);
953 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_time_cmd
);
954 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_database_cmd
);
955 install_element(CONFIG_NODE
, &debug_ospf6_spf_process_cmd
);
956 install_element(CONFIG_NODE
, &debug_ospf6_spf_time_cmd
);
957 install_element(CONFIG_NODE
, &debug_ospf6_spf_database_cmd
);
958 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_process_cmd
);
959 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_time_cmd
);
960 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_database_cmd
);
963 void ospf6_spf_init(void)
965 install_element(OSPF6_NODE
, &ospf6_timers_throttle_spf_cmd
);
966 install_element(OSPF6_NODE
, &no_ospf6_timers_throttle_spf_cmd
);
969 /* Create Aggregated Large Router-LSA from multiple Link-State IDs
971 * When more than one router-LSA is received from a single router,
972 * the links are processed as if concatenated into a single LSA.*/
973 struct ospf6_lsa
*ospf6_create_single_router_lsa(struct ospf6_area
*area
,
974 struct ospf6_lsdb
*lsdb
,
977 struct ospf6_lsa
*lsa
= NULL
;
978 struct ospf6_lsa
*rtr_lsa
= NULL
;
979 struct ospf6_lsa_header
*lsa_header
= NULL
;
980 uint8_t *new_header
= NULL
;
981 const struct route_node
*end
= NULL
;
982 uint16_t lsa_length
, total_lsa_length
= 0, num_lsa
= 0;
985 uint32_t interface_id
;
988 lsa_length
= sizeof(struct ospf6_lsa_header
)
989 + sizeof(struct ospf6_router_lsa
);
990 total_lsa_length
= lsa_length
;
991 type
= htons(OSPF6_LSTYPE_ROUTER
);
993 /* First check Aggregated LSA formed earlier in Cache */
994 lsa
= ospf6_lsdb_lookup(type
, htonl(0), adv_router
,
995 area
->temp_router_lsa_lsdb
);
999 inet_ntop(AF_INET
, &adv_router
, ifbuf
, sizeof(ifbuf
));
1001 /* Determine total LSA length from all link state ids */
1002 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1005 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1006 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1009 lsa_header
= rtr_lsa
->header
;
1010 total_lsa_length
+= (ntohs(lsa_header
->length
) - lsa_length
);
1012 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1014 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1015 zlog_debug("%s: adv_router %s num_lsa %u to convert.", __func__
,
1021 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1022 zlog_debug("%s: adv_router %s not found in LSDB.",
1027 lsa
= ospf6_lsa_alloc(total_lsa_length
);
1028 new_header
= (uint8_t *)lsa
->header
;
1030 lsa
->lsdb
= area
->temp_router_lsa_lsdb
;
1032 /* Fill Larger LSA Payload */
1033 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1036 * We assume at this point in time that rtr_lsa is
1040 if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1041 /* Append first Link State ID LSA */
1042 lsa_header
= rtr_lsa
->header
;
1043 memcpy(new_header
, lsa_header
, ntohs(lsa_header
->length
));
1044 /* Assign new lsa length as aggregated length. */
1045 ((struct ospf6_lsa_header
*)new_header
)->length
=
1046 htons(total_lsa_length
);
1047 new_header
+= ntohs(lsa_header
->length
);
1051 /* Print LSA Name */
1052 ospf6_lsa_printbuf(lsa
, lsa
->name
, sizeof(lsa
->name
));
1054 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1056 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1057 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1061 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
1062 lsd
= OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4;
1063 interface_id
= ROUTER_LSDESC_GET_IFID(lsd
);
1064 inet_ntop(AF_INET
, &interface_id
, ifbuf
, sizeof(ifbuf
));
1066 "%s: Next Router LSA %s to aggreat with len %u interface_id %s",
1067 __func__
, rtr_lsa
->name
,
1068 ntohs(lsa_header
->length
), ifbuf
);
1071 /* Append Next Link State ID LSA */
1072 lsa_header
= rtr_lsa
->header
;
1073 memcpy(new_header
, (OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4),
1074 (ntohs(lsa_header
->length
) - lsa_length
));
1075 new_header
+= (ntohs(lsa_header
->length
) - lsa_length
);
1078 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1081 /* Calculate birth of this lsa */
1082 ospf6_lsa_age_set(lsa
);
1084 /* Store Aggregated LSA into area temp lsdb */
1085 ospf6_lsdb_add(lsa
, area
->temp_router_lsa_lsdb
);
1087 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1088 zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
1089 __func__
, lsa
->name
, ntohl(lsa
->header
->id
),
1090 ntohs(lsa
->header
->type
), ntohs(lsa
->header
->length
),
1096 void ospf6_remove_temp_router_lsa(struct ospf6_area
*area
)
1098 struct ospf6_lsa
*lsa
= NULL
, *lsanext
;
1100 for (ALL_LSDB(area
->temp_router_lsa_lsdb
, lsa
, lsanext
)) {
1101 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1103 "%s Remove LSA %s lsa->lock %u lsdb count %u",
1104 __func__
, lsa
->name
, lsa
->lock
,
1105 area
->temp_router_lsa_lsdb
->count
);
1106 ospf6_lsdb_remove(lsa
, area
->temp_router_lsa_lsdb
);
1110 int ospf6_ase_calculate_route(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
1111 struct ospf6_area
*area
)
1113 struct ospf6_route
*route
;
1114 struct ospf6_as_external_lsa
*external
;
1115 struct prefix prefix
;
1116 void (*hook_add
)(struct ospf6_route
*) = NULL
;
1117 void (*hook_remove
)(struct ospf6_route
*) = NULL
;
1121 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1122 zlog_debug("%s : start", __func__
);
1124 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
)
1125 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1126 zlog_debug("%s: Processing Type-7", __func__
);
1128 /* Stay away from any Local Translated Type-7 LSAs */
1129 if (CHECK_FLAG(lsa
->flag
, OSPF6_LSA_LOCAL_XLT
)) {
1130 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1131 zlog_debug("%s: Rejecting Local translated LSA",
1136 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1138 prefix
.family
= AF_INET6
;
1139 prefix
.prefixlen
= external
->prefix
.prefix_length
;
1140 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
1142 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1143 hook_add
= ospf6
->route_table
->hook_add
;
1144 hook_remove
= ospf6
->route_table
->hook_remove
;
1145 ospf6
->route_table
->hook_add
= NULL
;
1146 ospf6
->route_table
->hook_remove
= NULL
;
1148 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1149 ospf6_asbr_lsa_add(lsa
);
1151 ospf6
->route_table
->hook_add
= hook_add
;
1152 ospf6
->route_table
->hook_remove
= hook_remove
;
1154 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
1155 if (route
== NULL
) {
1156 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1157 zlog_debug("%s: no external route %pFX",
1162 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1163 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1164 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1165 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1168 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
))
1169 ospf6_route_remove(route
, ospf6
->route_table
);
1170 else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1171 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1173 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1175 "%s: add external route %pFX",
1180 } else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
) {
1181 hook_add
= area
->route_table
->hook_add
;
1182 hook_remove
= area
->route_table
->hook_remove
;
1183 area
->route_table
->hook_add
= NULL
;
1184 area
->route_table
->hook_remove
= NULL
;
1186 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1187 ospf6_asbr_lsa_add(lsa
);
1189 area
->route_table
->hook_add
= hook_add
;
1190 area
->route_table
->hook_remove
= hook_remove
;
1192 route
= ospf6_route_lookup(&prefix
, area
->route_table
);
1193 if (route
== NULL
) {
1194 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1195 zlog_debug("%s: no route %pFX, area %s",
1196 __func__
, &prefix
, area
->name
);
1200 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1201 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1202 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1203 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1206 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
1207 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1208 zlog_debug("%s : remove route %pFX, area %s",
1209 __func__
, &prefix
, area
->name
);
1210 ospf6_route_remove(route
, area
->route_table
);
1211 } else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1212 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1214 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1216 "%s: add nssa route %pFX, area %s",
1217 __func__
, &prefix
, area
->name
);
1220 ospf6_abr_check_translate_nssa(area
, lsa
);
1226 static int ospf6_ase_calculate_timer(struct thread
*t
)
1228 struct ospf6
*ospf6
;
1229 struct ospf6_lsa
*lsa
;
1230 struct listnode
*node
, *nnode
;
1231 struct ospf6_area
*area
;
1234 ospf6
= THREAD_ARG(t
);
1235 ospf6
->t_ase_calc
= NULL
;
1237 /* Calculate external route for each AS-external-LSA */
1238 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1239 for (ALL_LSDB_TYPED(ospf6
->lsdb
, type
, lsa
))
1240 ospf6_ase_calculate_route(ospf6
, lsa
, NULL
);
1242 /* This version simple adds to the table all NSSA areas */
1243 if (ospf6
->anyNSSA
) {
1244 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
)) {
1245 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1246 zlog_debug("%s : looking at area %s", __func__
,
1249 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
1250 type
= htons(OSPF6_LSTYPE_TYPE_7
);
1251 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
))
1252 ospf6_ase_calculate_route(ospf6
, lsa
,
1260 void ospf6_ase_calculate_timer_add(struct ospf6
*ospf6
)
1265 thread_add_timer(master
, ospf6_ase_calculate_timer
, ospf6
,
1266 OSPF6_ASE_CALC_INTERVAL
, &ospf6
->t_ase_calc
);