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 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
288 zlog_debug("Can't find interface in SPF: ifindex %d",
293 type
= htons(OSPF6_LSTYPE_LINK
);
294 adv_router
= (VERTEX_IS_TYPE(NETWORK
, v
)
295 ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
)
296 : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
));
299 for (ALL_LSDB_TYPED_ADVRTR(oi
->lsdb
, type
, adv_router
, lsa
)) {
300 if (VERTEX_IS_TYPE(ROUTER
, v
)
301 && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
))
305 link_lsa
= (struct ospf6_link_lsa
*)OSPF6_LSA_HEADER_END(
307 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
308 inet_ntop(AF_INET6
, &link_lsa
->linklocal_addr
, buf
,
310 zlog_debug(" nexthop %s from %s", buf
, lsa
->name
);
313 ospf6_add_nexthop(w
->nh_list
, ifindex
,
314 &link_lsa
->linklocal_addr
);
318 if (i
== 0 && IS_OSPF6_DEBUG_SPF(PROCESS
))
319 zlog_debug("No nexthop for %s found", w
->name
);
322 static int ospf6_spf_install(struct ospf6_vertex
*v
,
323 struct ospf6_route_table
*result_table
)
325 struct ospf6_route
*route
, *parent_route
;
326 struct ospf6_vertex
*prev
;
328 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
329 zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v
->name
,
330 v
->lsa
->name
, v
->hops
, v
->cost
);
332 route
= ospf6_route_lookup(&v
->vertex_id
, result_table
);
333 if (route
&& route
->path
.cost
< v
->cost
) {
334 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
336 " already installed with lower cost (%d), ignore",
338 ospf6_vertex_delete(v
);
340 } else if (route
&& route
->path
.cost
== v
->cost
) {
341 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
343 " another path found to route %pFX lsa %s, merge",
344 &route
->prefix
, v
->lsa
->name
);
345 ospf6_spf_merge_nexthops_to_route(route
, v
);
347 prev
= (struct ospf6_vertex
*)route
->route_option
;
348 assert(prev
->hops
<= v
->hops
);
350 if ((VERTEX_IS_TYPE(ROUTER
, v
)
351 && route
->path
.origin
.id
!= v
->lsa
->header
->id
)) {
352 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
354 "%s: V lsa %s id %u, route id %u are different",
355 __func__
, v
->lsa
->name
,
356 ntohl(v
->lsa
->header
->id
),
357 ntohl(route
->path
.origin
.id
));
362 ospf6_vertex_delete(v
);
366 /* There should be no case where candidate being installed (variable
367 "v") is closer than the one in the SPF tree (variable "route").
368 In the case something has gone wrong with the behavior of
371 /* the case where the route exists already is handled and returned
373 assert(route
== NULL
);
375 route
= ospf6_route_create();
376 memcpy(&route
->prefix
, &v
->vertex_id
, sizeof(struct prefix
));
377 route
->type
= OSPF6_DEST_TYPE_LINKSTATE
;
378 route
->path
.type
= OSPF6_PATH_TYPE_INTRA
;
379 route
->path
.origin
.type
= v
->lsa
->header
->type
;
380 route
->path
.origin
.id
= v
->lsa
->header
->id
;
381 route
->path
.origin
.adv_router
= v
->lsa
->header
->adv_router
;
382 route
->path
.metric_type
= 1;
383 route
->path
.cost
= v
->cost
;
384 route
->path
.u
.cost_e2
= v
->hops
;
385 route
->path
.router_bits
= v
->capability
;
386 route
->path
.options
[0] = v
->options
[0];
387 route
->path
.options
[1] = v
->options
[1];
388 route
->path
.options
[2] = v
->options
[2];
390 ospf6_spf_copy_nexthops_to_route(route
, v
);
393 * The SPF logic implementation does not transfer the multipathing
395 * of a parent to a child node. Thus if there was a 3-way multipath to a
396 * node's parent and a single hop from the parent to the child, the
398 * creating new vertices and computing next hops prevents there from
400 * paths to the child node. This is primarily because the resolution of
401 * multipath is done in this routine, not in the main spf loop.
403 * The following logic addresses that problem by merging the parent's
405 * information with the child's, if the parent is not the root of the
407 * This is based on the assumption that before a node's route is
409 * its parent's route's nexthops have already been installed.
411 if (v
->parent
&& v
->parent
->hops
) {
413 ospf6_route_lookup(&v
->parent
->vertex_id
, result_table
);
415 ospf6_route_merge_nexthops(route
, parent_route
);
420 listnode_add_sort(v
->parent
->child_list
, v
);
421 route
->route_option
= v
;
423 ospf6_route_add(route
, result_table
);
427 void ospf6_spf_table_finish(struct ospf6_route_table
*result_table
)
429 struct ospf6_route
*route
, *nroute
;
430 struct ospf6_vertex
*v
;
431 for (route
= ospf6_route_head(result_table
); route
; route
= nroute
) {
432 nroute
= ospf6_route_next(route
);
433 v
= (struct ospf6_vertex
*)route
->route_option
;
434 ospf6_vertex_delete(v
);
435 ospf6_route_remove(route
, result_table
);
439 static const char *const ospf6_spf_reason_str
[] = {"R+", "R-", "N+", "N-", "L+",
440 "L-", "R*", "N*", "C"};
442 void ospf6_spf_reason_string(unsigned int reason
, char *buf
, int size
)
450 for (bit
= 0; bit
< array_size(ospf6_spf_reason_str
); bit
++) {
451 if ((reason
& (1 << bit
)) && (len
< size
)) {
452 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
453 (len
> 0) ? ", " : "",
454 ospf6_spf_reason_str
[bit
]);
459 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
460 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
461 void ospf6_spf_calculation(uint32_t router_id
,
462 struct ospf6_route_table
*result_table
,
463 struct ospf6_area
*oa
)
465 struct vertex_pqueue_head candidate_list
;
466 struct ospf6_vertex
*root
, *v
, *w
;
469 struct ospf6_lsa
*lsa
;
470 struct in6_addr address
;
472 ospf6_spf_table_finish(result_table
);
474 /* Install the calculating router itself as the root of the SPF tree */
475 /* construct root vertex */
476 lsa
= ospf6_create_single_router_lsa(oa
, oa
->lsdb_self
, router_id
);
478 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
479 zlog_debug("%s: No router LSA for area %s", __func__
,
485 vertex_pqueue_init(&candidate_list
);
487 root
= ospf6_vertex_create(lsa
);
491 root
->link_id
= lsa
->header
->id
;
492 inet_pton(AF_INET6
, "::1", &address
);
494 /* Actually insert root to the candidate-list as the only candidate */
495 vertex_pqueue_add(&candidate_list
, root
);
497 /* Iterate until candidate-list becomes empty */
498 while ((v
= vertex_pqueue_pop(&candidate_list
))) {
499 /* installing may result in merging or rejecting of the vertex
501 if (ospf6_spf_install(v
, result_table
) < 0)
504 /* Skip overloaded routers */
505 if ((OSPF6_LSA_IS_TYPE(ROUTER
, v
->lsa
)
506 && ospf6_router_is_stub_router(v
->lsa
)))
509 /* For each LS description in the just-added vertex V's LSA */
510 size
= (VERTEX_IS_TYPE(ROUTER
, v
)
511 ? sizeof(struct ospf6_router_lsdesc
)
512 : sizeof(struct ospf6_network_lsdesc
));
513 for (lsdesc
= OSPF6_LSA_HEADER_END(v
->lsa
->header
) + 4;
514 lsdesc
+ size
<= OSPF6_LSA_END(v
->lsa
->header
);
516 lsa
= ospf6_lsdesc_lsa(lsdesc
, v
);
520 if (OSPF6_LSA_IS_MAXAGE(lsa
))
523 if (!ospf6_lsdesc_backlink(lsa
, lsdesc
, v
))
526 w
= ospf6_vertex_create(lsa
);
529 if (VERTEX_IS_TYPE(ROUTER
, v
)) {
531 + ROUTER_LSDESC_GET_METRIC(lsdesc
);
534 + (VERTEX_IS_TYPE(NETWORK
, w
) ? 0 : 1);
538 w
->hops
= v
->hops
+ 1;
541 /* nexthop calculation */
545 ROUTER_LSDESC_GET_IFID(lsdesc
), NULL
);
546 else if (w
->hops
== 1 && v
->hops
== 0)
547 ospf6_nexthop_calc(w
, v
, lsdesc
, oa
->ospf6
);
549 ospf6_copy_nexthops(w
->nh_list
, v
->nh_list
);
552 /* add new candidate to the candidate_list */
553 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
555 " New candidate: %s hops %d cost %d",
556 w
->name
, w
->hops
, w
->cost
);
557 vertex_pqueue_add(&candidate_list
, w
);
561 //vertex_pqueue_fini(&candidate_list);
563 ospf6_remove_temp_router_lsa(oa
);
565 oa
->spf_calculation
++;
568 static void ospf6_spf_log_database(struct ospf6_area
*oa
)
570 char *p
, *end
, buffer
[256];
571 struct listnode
*node
;
572 struct ospf6_interface
*oi
;
575 end
= buffer
+ sizeof(buffer
);
577 snprintf(p
, end
- p
, "SPF on DB (#LSAs):");
578 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
579 snprintf(p
, end
- p
, " Area %s: %d", oa
->name
, oa
->lsdb
->count
);
580 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
582 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
583 snprintf(p
, end
- p
, " I/F %s: %d", oi
->interface
->name
,
585 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
)
589 zlog_debug("%s", buffer
);
592 static int ospf6_spf_calculation_thread(struct thread
*t
)
594 struct ospf6_area
*oa
;
596 struct timeval start
, end
, runtime
;
597 struct listnode
*node
;
598 int areas_processed
= 0;
601 ospf6
= (struct ospf6
*)THREAD_ARG(t
);
602 ospf6
->t_spf_calc
= NULL
;
604 /* execute SPF calculation */
606 ospf6
->ts_spf
= start
;
608 if (ospf6_is_router_abr(ospf6
))
609 ospf6_abr_range_reset_cost(ospf6
);
611 for (ALL_LIST_ELEMENTS_RO(ospf6
->area_list
, node
, oa
)) {
613 if (oa
== ospf6
->backbone
)
616 monotime(&oa
->ts_spf
);
617 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
618 zlog_debug("SPF calculation for Area %s", oa
->name
);
619 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
620 ospf6_spf_log_database(oa
);
622 ospf6_spf_calculation(ospf6
->router_id
, oa
->spf_table
, oa
);
623 ospf6_intra_route_calculation(oa
);
624 ospf6_intra_brouter_calculation(oa
);
629 if (ospf6
->backbone
) {
630 monotime(&ospf6
->backbone
->ts_spf
);
631 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
632 zlog_debug("SPF calculation for Backbone area %s",
633 ospf6
->backbone
->name
);
634 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
635 ospf6_spf_log_database(ospf6
->backbone
);
637 ospf6_spf_calculation(ospf6
->router_id
,
638 ospf6
->backbone
->spf_table
,
640 ospf6_intra_route_calculation(ospf6
->backbone
);
641 ospf6_intra_brouter_calculation(ospf6
->backbone
);
645 /* External LSA calculation */
646 ospf6_ase_calculate_timer_add(ospf6
);
648 if (ospf6_is_router_abr(ospf6
))
649 ospf6_abr_defaults_to_stub(ospf6
);
652 timersub(&end
, &start
, &runtime
);
654 ospf6
->ts_spf_duration
= runtime
;
656 ospf6_spf_reason_string(ospf6
->spf_reason
, rbuf
, sizeof(rbuf
));
658 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
660 "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s",
661 areas_processed
, (long long)runtime
.tv_sec
,
662 (long long)runtime
.tv_usec
, rbuf
);
664 ospf6
->last_spf_reason
= ospf6
->spf_reason
;
665 ospf6_reset_spf_reason(ospf6
);
669 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
670 set timer for SPF calc. */
671 void ospf6_spf_schedule(struct ospf6
*ospf6
, unsigned int reason
)
673 unsigned long delay
, elapsed
, ht
;
675 /* OSPF instance does not exist. */
679 ospf6_set_spf_reason(ospf6
, reason
);
681 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
)) {
683 ospf6_spf_reason_string(reason
, rbuf
, sizeof(rbuf
));
684 zlog_debug("SPF: calculation timer scheduled (reason %s)",
688 /* SPF calculation timer is already scheduled. */
689 if (ospf6
->t_spf_calc
) {
690 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
692 "SPF: calculation timer is already scheduled: %p",
693 (void *)ospf6
->t_spf_calc
);
697 elapsed
= monotime_since(&ospf6
->ts_spf
, NULL
) / 1000LL;
698 ht
= ospf6
->spf_holdtime
* ospf6
->spf_hold_multiplier
;
700 if (ht
> ospf6
->spf_max_holdtime
)
701 ht
= ospf6
->spf_max_holdtime
;
703 /* Get SPF calculation delay time. */
705 /* Got an event within the hold time of last SPF. We need to
706 * increase the hold_multiplier, if it's not already at/past
707 * maximum value, and wasn't already increased..
709 if (ht
< ospf6
->spf_max_holdtime
)
710 ospf6
->spf_hold_multiplier
++;
712 /* always honour the SPF initial delay */
713 if ((ht
- elapsed
) < ospf6
->spf_delay
)
714 delay
= ospf6
->spf_delay
;
716 delay
= ht
- elapsed
;
718 /* Event is past required hold-time of last SPF */
719 delay
= ospf6
->spf_delay
;
720 ospf6
->spf_hold_multiplier
= 1;
723 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
724 zlog_debug("SPF: Rescheduling in %ld msec", delay
);
726 ospf6
->t_spf_calc
= NULL
;
727 thread_add_timer_msec(master
, ospf6_spf_calculation_thread
, ospf6
,
728 delay
, &ospf6
->t_spf_calc
);
731 void ospf6_spf_display_subtree(struct vty
*vty
, const char *prefix
, int rest
,
732 struct ospf6_vertex
*v
, json_object
*json_obj
,
735 struct listnode
*node
, *nnode
;
736 struct ospf6_vertex
*c
;
740 json_object
*json_childs
= NULL
;
741 json_object
*json_child
= NULL
;
744 json_childs
= json_object_new_object();
745 json_object_int_add(json_obj
, "cost", v
->cost
);
747 /* "prefix" is the space prefix of the display line */
748 vty_out(vty
, "%s+-%s [%d]\n", prefix
, v
->name
, v
->cost
);
751 len
= strlen(prefix
) + 4;
752 next_prefix
= (char *)malloc(len
);
753 if (next_prefix
== NULL
) {
754 vty_out(vty
, "malloc failed\n");
757 snprintf(next_prefix
, len
, "%s%s", prefix
, (rest
? "| " : " "));
759 restnum
= listcount(v
->child_list
);
760 for (ALL_LIST_ELEMENTS(v
->child_list
, node
, nnode
, c
)) {
762 json_child
= json_object_new_object();
766 ospf6_spf_display_subtree(vty
, next_prefix
, restnum
, c
,
767 json_child
, use_json
);
770 json_object_object_add(json_childs
, c
->name
,
774 json_object_boolean_add(json_obj
, "isLeafNode",
775 !listcount(v
->child_list
));
776 if (listcount(v
->child_list
))
777 json_object_object_add(json_obj
, "children",
780 json_object_free(json_childs
);
785 DEFUN (debug_ospf6_spf_process
,
786 debug_ospf6_spf_process_cmd
,
787 "debug ospf6 spf process",
790 "Debug SPF Calculation\n"
791 "Debug Detailed SPF Process\n"
794 unsigned char level
= 0;
795 level
= OSPF6_DEBUG_SPF_PROCESS
;
796 OSPF6_DEBUG_SPF_ON(level
);
800 DEFUN (debug_ospf6_spf_time
,
801 debug_ospf6_spf_time_cmd
,
802 "debug ospf6 spf time",
805 "Debug SPF Calculation\n"
806 "Measure time taken by SPF Calculation\n"
809 unsigned char level
= 0;
810 level
= OSPF6_DEBUG_SPF_TIME
;
811 OSPF6_DEBUG_SPF_ON(level
);
815 DEFUN (debug_ospf6_spf_database
,
816 debug_ospf6_spf_database_cmd
,
817 "debug ospf6 spf database",
820 "Debug SPF Calculation\n"
821 "Log number of LSAs at SPF Calculation time\n"
824 unsigned char level
= 0;
825 level
= OSPF6_DEBUG_SPF_DATABASE
;
826 OSPF6_DEBUG_SPF_ON(level
);
830 DEFUN (no_debug_ospf6_spf_process
,
831 no_debug_ospf6_spf_process_cmd
,
832 "no debug ospf6 spf process",
836 "Quit Debugging SPF Calculation\n"
837 "Quit Debugging Detailed SPF Process\n"
840 unsigned char level
= 0;
841 level
= OSPF6_DEBUG_SPF_PROCESS
;
842 OSPF6_DEBUG_SPF_OFF(level
);
846 DEFUN (no_debug_ospf6_spf_time
,
847 no_debug_ospf6_spf_time_cmd
,
848 "no debug ospf6 spf time",
852 "Quit Debugging SPF Calculation\n"
853 "Quit Measuring time taken by SPF Calculation\n"
856 unsigned char level
= 0;
857 level
= OSPF6_DEBUG_SPF_TIME
;
858 OSPF6_DEBUG_SPF_OFF(level
);
862 DEFUN (no_debug_ospf6_spf_database
,
863 no_debug_ospf6_spf_database_cmd
,
864 "no debug ospf6 spf database",
868 "Debug SPF Calculation\n"
869 "Quit Logging number of LSAs at SPF Calculation time\n"
872 unsigned char level
= 0;
873 level
= OSPF6_DEBUG_SPF_DATABASE
;
874 OSPF6_DEBUG_SPF_OFF(level
);
878 static int ospf6_timers_spf_set(struct vty
*vty
, unsigned int delay
,
879 unsigned int hold
, unsigned int max
)
881 VTY_DECLVAR_CONTEXT(ospf6
, ospf
);
883 ospf
->spf_delay
= delay
;
884 ospf
->spf_holdtime
= hold
;
885 ospf
->spf_max_holdtime
= max
;
890 DEFUN (ospf6_timers_throttle_spf
,
891 ospf6_timers_throttle_spf_cmd
,
892 "timers throttle spf (0-600000) (0-600000) (0-600000)",
893 "Adjust routing timers\n"
894 "Throttling adaptive timer\n"
896 "Delay (msec) from first change received till SPF calculation\n"
897 "Initial hold time (msec) between consecutive SPF calculations\n"
898 "Maximum hold time (msec)\n")
901 int idx_number_2
= 4;
902 int idx_number_3
= 5;
903 unsigned int delay
, hold
, max
;
905 delay
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
906 hold
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
907 max
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
909 return ospf6_timers_spf_set(vty
, delay
, hold
, max
);
912 DEFUN (no_ospf6_timers_throttle_spf
,
913 no_ospf6_timers_throttle_spf_cmd
,
914 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
916 "Adjust routing timers\n"
917 "Throttling adaptive timer\n"
919 "Delay (msec) from first change received till SPF calculation\n"
920 "Initial hold time (msec) between consecutive SPF calculations\n"
921 "Maximum hold time (msec)\n")
923 return ospf6_timers_spf_set(vty
, OSPF_SPF_DELAY_DEFAULT
,
924 OSPF_SPF_HOLDTIME_DEFAULT
,
925 OSPF_SPF_MAX_HOLDTIME_DEFAULT
);
929 int config_write_ospf6_debug_spf(struct vty
*vty
)
931 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
932 vty_out(vty
, "debug ospf6 spf process\n");
933 if (IS_OSPF6_DEBUG_SPF(TIME
))
934 vty_out(vty
, "debug ospf6 spf time\n");
935 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
936 vty_out(vty
, "debug ospf6 spf database\n");
940 void ospf6_spf_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
943 if (ospf6
->spf_delay
!= OSPF_SPF_DELAY_DEFAULT
944 || ospf6
->spf_holdtime
!= OSPF_SPF_HOLDTIME_DEFAULT
945 || ospf6
->spf_max_holdtime
!= OSPF_SPF_MAX_HOLDTIME_DEFAULT
)
946 vty_out(vty
, " timers throttle spf %d %d %d\n",
947 ospf6
->spf_delay
, ospf6
->spf_holdtime
,
948 ospf6
->spf_max_holdtime
);
951 void install_element_ospf6_debug_spf(void)
953 install_element(ENABLE_NODE
, &debug_ospf6_spf_process_cmd
);
954 install_element(ENABLE_NODE
, &debug_ospf6_spf_time_cmd
);
955 install_element(ENABLE_NODE
, &debug_ospf6_spf_database_cmd
);
956 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_process_cmd
);
957 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_time_cmd
);
958 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_database_cmd
);
959 install_element(CONFIG_NODE
, &debug_ospf6_spf_process_cmd
);
960 install_element(CONFIG_NODE
, &debug_ospf6_spf_time_cmd
);
961 install_element(CONFIG_NODE
, &debug_ospf6_spf_database_cmd
);
962 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_process_cmd
);
963 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_time_cmd
);
964 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_database_cmd
);
967 void ospf6_spf_init(void)
969 install_element(OSPF6_NODE
, &ospf6_timers_throttle_spf_cmd
);
970 install_element(OSPF6_NODE
, &no_ospf6_timers_throttle_spf_cmd
);
973 /* Create Aggregated Large Router-LSA from multiple Link-State IDs
975 * When more than one router-LSA is received from a single router,
976 * the links are processed as if concatenated into a single LSA.*/
977 struct ospf6_lsa
*ospf6_create_single_router_lsa(struct ospf6_area
*area
,
978 struct ospf6_lsdb
*lsdb
,
981 struct ospf6_lsa
*lsa
= NULL
;
982 struct ospf6_lsa
*rtr_lsa
= NULL
;
983 struct ospf6_lsa_header
*lsa_header
= NULL
;
984 uint8_t *new_header
= NULL
;
985 const struct route_node
*end
= NULL
;
986 uint16_t lsa_length
, total_lsa_length
= 0, num_lsa
= 0;
989 uint32_t interface_id
;
992 lsa_length
= sizeof(struct ospf6_lsa_header
)
993 + sizeof(struct ospf6_router_lsa
);
994 total_lsa_length
= lsa_length
;
995 type
= htons(OSPF6_LSTYPE_ROUTER
);
997 /* First check Aggregated LSA formed earlier in Cache */
998 lsa
= ospf6_lsdb_lookup(type
, htonl(0), adv_router
,
999 area
->temp_router_lsa_lsdb
);
1003 inet_ntop(AF_INET
, &adv_router
, ifbuf
, sizeof(ifbuf
));
1005 /* Determine total LSA length from all link state ids */
1006 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1009 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1010 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1013 lsa_header
= rtr_lsa
->header
;
1014 total_lsa_length
+= (ntohs(lsa_header
->length
) - lsa_length
);
1016 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1018 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1019 zlog_debug("%s: adv_router %s num_lsa %u to convert.", __func__
,
1025 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1026 zlog_debug("%s: adv_router %s not found in LSDB.",
1031 lsa
= ospf6_lsa_alloc(total_lsa_length
);
1032 new_header
= (uint8_t *)lsa
->header
;
1034 lsa
->lsdb
= area
->temp_router_lsa_lsdb
;
1036 /* Fill Larger LSA Payload */
1037 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1040 * We assume at this point in time that rtr_lsa is
1044 if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1045 /* Append first Link State ID LSA */
1046 lsa_header
= rtr_lsa
->header
;
1047 memcpy(new_header
, lsa_header
, ntohs(lsa_header
->length
));
1048 /* Assign new lsa length as aggregated length. */
1049 ((struct ospf6_lsa_header
*)new_header
)->length
=
1050 htons(total_lsa_length
);
1051 new_header
+= ntohs(lsa_header
->length
);
1055 /* Print LSA Name */
1056 ospf6_lsa_printbuf(lsa
, lsa
->name
, sizeof(lsa
->name
));
1058 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1060 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1061 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1065 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
1066 lsd
= OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4;
1067 interface_id
= ROUTER_LSDESC_GET_IFID(lsd
);
1068 inet_ntop(AF_INET
, &interface_id
, ifbuf
, sizeof(ifbuf
));
1070 "%s: Next Router LSA %s to aggreat with len %u interface_id %s",
1071 __func__
, rtr_lsa
->name
,
1072 ntohs(lsa_header
->length
), ifbuf
);
1075 /* Append Next Link State ID LSA */
1076 lsa_header
= rtr_lsa
->header
;
1077 memcpy(new_header
, (OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4),
1078 (ntohs(lsa_header
->length
) - lsa_length
));
1079 new_header
+= (ntohs(lsa_header
->length
) - lsa_length
);
1082 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1085 /* Calculate birth of this lsa */
1086 ospf6_lsa_age_set(lsa
);
1088 /* Store Aggregated LSA into area temp lsdb */
1089 ospf6_lsdb_add(lsa
, area
->temp_router_lsa_lsdb
);
1091 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1092 zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
1093 __func__
, lsa
->name
, ntohl(lsa
->header
->id
),
1094 ntohs(lsa
->header
->type
), ntohs(lsa
->header
->length
),
1100 void ospf6_remove_temp_router_lsa(struct ospf6_area
*area
)
1102 struct ospf6_lsa
*lsa
= NULL
, *lsanext
;
1104 for (ALL_LSDB(area
->temp_router_lsa_lsdb
, lsa
, lsanext
)) {
1105 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1107 "%s Remove LSA %s lsa->lock %u lsdb count %u",
1108 __func__
, lsa
->name
, lsa
->lock
,
1109 area
->temp_router_lsa_lsdb
->count
);
1110 ospf6_lsdb_remove(lsa
, area
->temp_router_lsa_lsdb
);
1114 int ospf6_ase_calculate_route(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
1115 struct ospf6_area
*area
)
1117 struct ospf6_route
*route
;
1118 struct ospf6_as_external_lsa
*external
;
1119 struct prefix prefix
;
1120 void (*hook_add
)(struct ospf6_route
*) = NULL
;
1121 void (*hook_remove
)(struct ospf6_route
*) = NULL
;
1125 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1126 zlog_debug("%s : start", __func__
);
1128 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
)
1129 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1130 zlog_debug("%s: Processing Type-7", __func__
);
1132 /* Stay away from any Local Translated Type-7 LSAs */
1133 if (CHECK_FLAG(lsa
->flag
, OSPF6_LSA_LOCAL_XLT
)) {
1134 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1135 zlog_debug("%s: Rejecting Local translated LSA",
1140 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1142 prefix
.family
= AF_INET6
;
1143 prefix
.prefixlen
= external
->prefix
.prefix_length
;
1144 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
1146 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1147 hook_add
= ospf6
->route_table
->hook_add
;
1148 hook_remove
= ospf6
->route_table
->hook_remove
;
1149 ospf6
->route_table
->hook_add
= NULL
;
1150 ospf6
->route_table
->hook_remove
= NULL
;
1152 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1153 ospf6_asbr_lsa_add(lsa
);
1155 ospf6
->route_table
->hook_add
= hook_add
;
1156 ospf6
->route_table
->hook_remove
= hook_remove
;
1158 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
1159 if (route
== NULL
) {
1160 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1161 zlog_debug("%s: no external route %pFX",
1166 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1167 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1168 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1169 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1172 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
))
1173 ospf6_route_remove(route
, ospf6
->route_table
);
1174 else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1175 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1177 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1179 "%s: add external route %pFX",
1184 } else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
) {
1185 hook_add
= area
->route_table
->hook_add
;
1186 hook_remove
= area
->route_table
->hook_remove
;
1187 area
->route_table
->hook_add
= NULL
;
1188 area
->route_table
->hook_remove
= NULL
;
1190 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1191 ospf6_asbr_lsa_add(lsa
);
1193 area
->route_table
->hook_add
= hook_add
;
1194 area
->route_table
->hook_remove
= hook_remove
;
1196 route
= ospf6_route_lookup(&prefix
, area
->route_table
);
1197 if (route
== NULL
) {
1198 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1199 zlog_debug("%s: no route %pFX, area %s",
1200 __func__
, &prefix
, area
->name
);
1204 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1205 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1206 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1207 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1210 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
1211 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1212 zlog_debug("%s : remove route %pFX, area %s",
1213 __func__
, &prefix
, area
->name
);
1214 ospf6_route_remove(route
, area
->route_table
);
1215 } else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1216 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1218 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1220 "%s: add nssa route %pFX, area %s",
1221 __func__
, &prefix
, area
->name
);
1224 ospf6_abr_check_translate_nssa(area
, lsa
);
1230 static int ospf6_ase_calculate_timer(struct thread
*t
)
1232 struct ospf6
*ospf6
;
1233 struct ospf6_lsa
*lsa
;
1234 struct listnode
*node
, *nnode
;
1235 struct ospf6_area
*area
;
1238 ospf6
= THREAD_ARG(t
);
1239 ospf6
->t_ase_calc
= NULL
;
1241 /* Calculate external route for each AS-external-LSA */
1242 type
= htons(OSPF6_LSTYPE_AS_EXTERNAL
);
1243 for (ALL_LSDB_TYPED(ospf6
->lsdb
, type
, lsa
))
1244 ospf6_ase_calculate_route(ospf6
, lsa
, NULL
);
1246 /* This version simple adds to the table all NSSA areas */
1247 if (ospf6
->anyNSSA
) {
1248 for (ALL_LIST_ELEMENTS(ospf6
->area_list
, node
, nnode
, area
)) {
1249 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1250 zlog_debug("%s : looking at area %s", __func__
,
1253 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
1254 type
= htons(OSPF6_LSTYPE_TYPE_7
);
1255 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
))
1256 ospf6_ase_calculate_route(ospf6
, lsa
,
1264 void ospf6_ase_calculate_timer_add(struct ospf6
*ospf6
)
1269 thread_add_timer(master
, ospf6_ase_calculate_timer
, ospf6
,
1270 OSPF6_ASE_CALC_INTERVAL
, &ospf6
->t_ase_calc
);