1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2003 Yasuhiro Ohara
6 /* Shortest Path First calculation for OSPFv3 */
17 #include "lib_errors.h"
19 #include "ospf6_lsa.h"
20 #include "ospf6_lsdb.h"
21 #include "ospf6_route.h"
22 #include "ospf6_area.h"
23 #include "ospf6_proto.h"
24 #include "ospf6_abr.h"
25 #include "ospf6_asbr.h"
26 #include "ospf6_spf.h"
27 #include "ospf6_intra.h"
28 #include "ospf6_interface.h"
30 #include "ospf6_abr.h"
31 #include "ospf6_nssa.h"
32 #include "ospf6_zebra.h"
34 DEFINE_MTYPE_STATIC(OSPF6D
, OSPF6_VERTEX
, "OSPF6 vertex");
36 unsigned char conf_debug_ospf6_spf
= 0;
38 static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route
*rt
,
39 struct ospf6_vertex
*v
)
42 ospf6_copy_nexthops(rt
->nh_list
, v
->nh_list
);
45 static void ospf6_spf_merge_nexthops_to_route(struct ospf6_route
*rt
,
46 struct ospf6_vertex
*v
)
49 ospf6_merge_nexthops(rt
->nh_list
, v
->nh_list
);
52 static unsigned int ospf6_spf_get_ifindex_from_nh(struct ospf6_vertex
*v
)
54 struct ospf6_nexthop
*nh
;
55 struct listnode
*node
;
58 node
= listhead(v
->nh_list
);
60 nh
= listgetdata(node
);
68 static int ospf6_vertex_cmp(const struct ospf6_vertex
*va
,
69 const struct ospf6_vertex
*vb
)
72 if (va
->cost
!= vb
->cost
)
73 return (va
->cost
- vb
->cost
);
74 if (va
->hops
!= vb
->hops
)
75 return (va
->hops
- vb
->hops
);
78 DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue
, struct ospf6_vertex
, pqi
,
81 static int ospf6_vertex_id_cmp(void *a
, void *b
)
83 struct ospf6_vertex
*va
= (struct ospf6_vertex
*)a
;
84 struct ospf6_vertex
*vb
= (struct ospf6_vertex
*)b
;
87 ret
= ntohl(ospf6_linkstate_prefix_adv_router(&va
->vertex_id
))
88 - ntohl(ospf6_linkstate_prefix_adv_router(&vb
->vertex_id
));
92 ret
= ntohl(ospf6_linkstate_prefix_id(&va
->vertex_id
))
93 - ntohl(ospf6_linkstate_prefix_id(&vb
->vertex_id
));
97 static struct ospf6_vertex
*ospf6_vertex_create(struct ospf6_lsa
*lsa
)
99 struct ospf6_vertex
*v
;
101 v
= XMALLOC(MTYPE_OSPF6_VERTEX
, sizeof(struct ospf6_vertex
));
104 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
) {
105 v
->type
= OSPF6_VERTEX_TYPE_ROUTER
;
106 /* Router LSA use Link ID 0 as base in vertex_id */
107 ospf6_linkstate_prefix(lsa
->header
->adv_router
, htonl(0),
109 } else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_NETWORK
) {
110 v
->type
= OSPF6_VERTEX_TYPE_NETWORK
;
112 ospf6_linkstate_prefix(lsa
->header
->adv_router
, lsa
->header
->id
,
118 ospf6_linkstate_prefix2str(&v
->vertex_id
, v
->name
, sizeof(v
->name
));
120 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
121 zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s",
123 ((ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_ROUTER
)
126 ntohs(lsa
->header
->type
), lsa
->name
);
132 /* capability bits + options */
133 v
->capability
= *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
));
134 v
->options
[0] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 1);
135 v
->options
[1] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 2);
136 v
->options
[2] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa
->header
) + 3);
138 v
->nh_list
= list_new();
139 v
->nh_list
->cmp
= (int (*)(void *, void *))ospf6_nexthop_cmp
;
140 v
->nh_list
->del
= (void (*)(void *))ospf6_nexthop_delete
;
143 v
->child_list
= list_new();
144 v
->child_list
->cmp
= ospf6_vertex_id_cmp
;
149 static void ospf6_vertex_delete(struct ospf6_vertex
*v
)
151 list_delete(&v
->nh_list
);
152 list_delete(&v
->child_list
);
153 XFREE(MTYPE_OSPF6_VERTEX
, v
);
156 static struct ospf6_lsa
*ospf6_lsdesc_lsa(caddr_t lsdesc
,
157 struct ospf6_vertex
*v
)
159 struct ospf6_lsa
*lsa
= NULL
;
161 uint32_t id
= 0, adv_router
= 0;
163 if (VERTEX_IS_TYPE(NETWORK
, v
)) {
164 type
= htons(OSPF6_LSTYPE_ROUTER
);
166 adv_router
= NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
);
168 if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
)) {
169 type
= htons(OSPF6_LSTYPE_ROUTER
);
171 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
172 } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, lsdesc
)) {
173 type
= htons(OSPF6_LSTYPE_NETWORK
);
174 id
= htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
));
175 adv_router
= ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
);
179 if (type
== htons(OSPF6_LSTYPE_NETWORK
))
180 lsa
= ospf6_lsdb_lookup(type
, id
, adv_router
, v
->area
->lsdb
);
182 lsa
= ospf6_create_single_router_lsa(v
->area
, v
->area
->lsdb
,
184 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
185 char ibuf
[16], abuf
[16];
186 inet_ntop(AF_INET
, &id
, ibuf
, sizeof(ibuf
));
187 inet_ntop(AF_INET
, &adv_router
, abuf
, sizeof(abuf
));
189 zlog_debug(" Link to: %s len %u, V %s", lsa
->name
,
190 ntohs(lsa
->header
->length
), v
->name
);
192 zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s",
193 ospf6_lstype_name(type
), ibuf
, abuf
,
200 static char *ospf6_lsdesc_backlink(struct ospf6_lsa
*lsa
, caddr_t lsdesc
,
201 struct ospf6_vertex
*v
)
203 caddr_t backlink
, found
= NULL
;
206 size
= (OSPF6_LSA_IS_TYPE(ROUTER
, lsa
)
207 ? sizeof(struct ospf6_router_lsdesc
)
208 : sizeof(struct ospf6_network_lsdesc
));
209 for (backlink
= OSPF6_LSA_HEADER_END(lsa
->header
) + 4;
210 backlink
+ size
<= OSPF6_LSA_END(lsa
->header
); backlink
+= size
) {
211 assert(!(OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)
212 && VERTEX_IS_TYPE(NETWORK
, v
)));
214 if (OSPF6_LSA_IS_TYPE(NETWORK
, lsa
)) {
215 if (NETWORK_LSDESC_GET_NBR_ROUTERID(backlink
)
216 == v
->lsa
->header
->adv_router
)
218 } else if (VERTEX_IS_TYPE(NETWORK
, v
)) {
219 if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK
, backlink
)
220 && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
221 == v
->lsa
->header
->adv_router
222 && ROUTER_LSDESC_GET_NBR_IFID(backlink
)
223 == ntohl(v
->lsa
->header
->id
))
226 assert(OSPF6_LSA_IS_TYPE(ROUTER
, lsa
)
227 && VERTEX_IS_TYPE(ROUTER
, v
));
229 if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, backlink
)
230 || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT
, lsdesc
))
233 if (ROUTER_LSDESC_GET_NBR_IFID(backlink
)
234 != ROUTER_LSDESC_GET_IFID(lsdesc
)
235 || ROUTER_LSDESC_GET_NBR_IFID(lsdesc
)
236 != ROUTER_LSDESC_GET_IFID(backlink
))
238 if (ROUTER_LSDESC_GET_NBR_ROUTERID(backlink
)
239 != v
->lsa
->header
->adv_router
240 || ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
)
241 != lsa
->header
->adv_router
)
247 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
248 zlog_debug("Vertex %s Lsa %s Backlink %s", v
->name
, lsa
->name
,
249 (found
? "OK" : "FAIL"));
254 static void ospf6_nexthop_calc(struct ospf6_vertex
*w
, struct ospf6_vertex
*v
,
255 caddr_t lsdesc
, struct ospf6
*ospf6
)
259 struct ospf6_interface
*oi
;
262 struct ospf6_lsa
*lsa
;
263 struct ospf6_link_lsa
*link_lsa
;
266 assert(VERTEX_IS_TYPE(ROUTER
, w
));
267 ifindex
= (VERTEX_IS_TYPE(NETWORK
, v
) ? ospf6_spf_get_ifindex_from_nh(v
)
268 : ROUTER_LSDESC_GET_IFID(lsdesc
));
270 flog_err(EC_LIB_DEVELOPMENT
, "No nexthop ifindex at vertex %s",
275 oi
= ospf6_interface_lookup_by_ifindex(ifindex
, ospf6
->vrf_id
);
277 zlog_warn("Can't find interface in SPF: ifindex %d", ifindex
);
281 type
= htons(OSPF6_LSTYPE_LINK
);
282 adv_router
= (VERTEX_IS_TYPE(NETWORK
, v
)
283 ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc
)
284 : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc
));
287 for (ALL_LSDB_TYPED_ADVRTR(oi
->lsdb
, type
, adv_router
, lsa
)) {
288 if (VERTEX_IS_TYPE(ROUTER
, v
)
289 && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc
))
293 link_lsa
= (struct ospf6_link_lsa
*)OSPF6_LSA_HEADER_END(
295 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
296 inet_ntop(AF_INET6
, &link_lsa
->linklocal_addr
, buf
,
298 zlog_debug(" nexthop %s from %s", buf
, lsa
->name
);
301 ospf6_add_nexthop(w
->nh_list
, ifindex
,
302 &link_lsa
->linklocal_addr
);
306 if (i
== 0 && IS_OSPF6_DEBUG_SPF(PROCESS
))
307 zlog_debug("No nexthop for %s found", w
->name
);
310 static int ospf6_spf_install(struct ospf6_vertex
*v
,
311 struct ospf6_route_table
*result_table
)
313 struct ospf6_route
*route
, *parent_route
;
314 struct ospf6_vertex
*prev
;
316 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
317 zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v
->name
,
318 v
->lsa
->name
, v
->hops
, v
->cost
);
320 route
= ospf6_route_lookup(&v
->vertex_id
, result_table
);
321 if (route
&& route
->path
.cost
< v
->cost
) {
322 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
324 " already installed with lower cost (%d), ignore",
326 ospf6_vertex_delete(v
);
328 } else if (route
&& route
->path
.cost
== v
->cost
) {
329 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
331 " another path found to route %pFX lsa %s, merge",
332 &route
->prefix
, v
->lsa
->name
);
333 ospf6_spf_merge_nexthops_to_route(route
, v
);
335 prev
= (struct ospf6_vertex
*)route
->route_option
;
336 assert(prev
->hops
<= v
->hops
);
338 if ((VERTEX_IS_TYPE(ROUTER
, v
)
339 && route
->path
.origin
.id
!= v
->lsa
->header
->id
)) {
340 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
342 "%s: V lsa %s id %u, route id %u are different",
343 __func__
, v
->lsa
->name
,
344 ntohl(v
->lsa
->header
->id
),
345 ntohl(route
->path
.origin
.id
));
350 ospf6_vertex_delete(v
);
354 /* There should be no case where candidate being installed (variable
355 "v") is closer than the one in the SPF tree (variable "route").
356 In the case something has gone wrong with the behavior of
359 /* the case where the route exists already is handled and returned
361 assert(route
== NULL
);
363 route
= ospf6_route_create(v
->area
->ospf6
);
364 memcpy(&route
->prefix
, &v
->vertex_id
, sizeof(struct prefix
));
365 route
->type
= OSPF6_DEST_TYPE_LINKSTATE
;
366 route
->path
.type
= OSPF6_PATH_TYPE_INTRA
;
367 route
->path
.origin
.type
= v
->lsa
->header
->type
;
368 route
->path
.origin
.id
= v
->lsa
->header
->id
;
369 route
->path
.origin
.adv_router
= v
->lsa
->header
->adv_router
;
370 route
->path
.metric_type
= 1;
371 route
->path
.cost
= v
->cost
;
372 route
->path
.u
.cost_e2
= v
->hops
;
373 route
->path
.router_bits
= v
->capability
;
374 route
->path
.options
[0] = v
->options
[0];
375 route
->path
.options
[1] = v
->options
[1];
376 route
->path
.options
[2] = v
->options
[2];
378 ospf6_spf_copy_nexthops_to_route(route
, v
);
381 * The SPF logic implementation does not transfer the multipathing
383 * of a parent to a child node. Thus if there was a 3-way multipath to a
384 * node's parent and a single hop from the parent to the child, the
386 * creating new vertices and computing next hops prevents there from
388 * paths to the child node. This is primarily because the resolution of
389 * multipath is done in this routine, not in the main spf loop.
391 * The following logic addresses that problem by merging the parent's
393 * information with the child's, if the parent is not the root of the
395 * This is based on the assumption that before a node's route is
397 * its parent's route's nexthops have already been installed.
399 if (v
->parent
&& v
->parent
->hops
) {
401 ospf6_route_lookup(&v
->parent
->vertex_id
, result_table
);
403 ospf6_route_merge_nexthops(route
, parent_route
);
408 listnode_add_sort(v
->parent
->child_list
, v
);
409 route
->route_option
= v
;
411 ospf6_route_add(route
, result_table
);
415 void ospf6_spf_table_finish(struct ospf6_route_table
*result_table
)
417 struct ospf6_route
*route
, *nroute
;
418 struct ospf6_vertex
*v
;
419 for (route
= ospf6_route_head(result_table
); route
; route
= nroute
) {
420 nroute
= ospf6_route_next(route
);
421 v
= (struct ospf6_vertex
*)route
->route_option
;
422 ospf6_vertex_delete(v
);
423 ospf6_route_remove(route
, result_table
);
427 static const char *const ospf6_spf_reason_str
[] = {
428 "R+", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED */
429 "R-", /* OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED */
430 "N+", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED */
431 "N-", /* OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED */
432 "L+", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_ADDED */
433 "L-", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_REMOVED */
434 "R*", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED */
435 "N*", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED */
436 "C", /* OSPF6_SPF_FLAGS_CONFIG_CHANGE */
437 "A", /* OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE */
438 "GR", /* OSPF6_SPF_FLAGS_GR_FINISH */
441 void ospf6_spf_reason_string(uint32_t reason
, char *buf
, int size
)
453 for (bit
= 0; bit
< array_size(ospf6_spf_reason_str
); bit
++) {
454 if ((reason
& (1 << bit
)) && (len
< size
)) {
455 len
+= snprintf((buf
+ len
), (size
- len
), "%s%s",
456 (len
> 0) ? ", " : "",
457 ospf6_spf_reason_str
[bit
]);
462 /* RFC2328 16.1. Calculating the shortest-path tree for an area */
463 /* RFC2740 3.8.1. Calculating the shortest path tree for an area */
464 void ospf6_spf_calculation(uint32_t router_id
,
465 struct ospf6_route_table
*result_table
,
466 struct ospf6_area
*oa
)
468 struct vertex_pqueue_head candidate_list
;
469 struct ospf6_vertex
*root
, *v
, *w
;
472 struct ospf6_lsa
*lsa
;
473 struct in6_addr address
;
475 ospf6_spf_table_finish(result_table
);
477 /* Install the calculating router itself as the root of the SPF tree */
478 /* construct root vertex */
479 lsa
= ospf6_create_single_router_lsa(oa
, oa
->lsdb_self
, router_id
);
481 zlog_warn("%s: No router LSA for area %s", __func__
, oa
->name
);
486 vertex_pqueue_init(&candidate_list
);
488 root
= ospf6_vertex_create(lsa
);
492 root
->link_id
= lsa
->header
->id
;
493 inet_pton(AF_INET6
, "::1", &address
);
495 /* Actually insert root to the candidate-list as the only candidate */
496 vertex_pqueue_add(&candidate_list
, root
);
498 /* Iterate until candidate-list becomes empty */
499 while ((v
= vertex_pqueue_pop(&candidate_list
))) {
500 /* installing may result in merging or rejecting of the vertex
502 if (ospf6_spf_install(v
, result_table
) < 0)
505 /* Skip overloaded routers */
506 if ((OSPF6_LSA_IS_TYPE(ROUTER
, v
->lsa
)
507 && ospf6_router_is_stub_router(v
->lsa
)))
510 /* For each LS description in the just-added vertex V's LSA */
511 size
= (VERTEX_IS_TYPE(ROUTER
, v
)
512 ? sizeof(struct ospf6_router_lsdesc
)
513 : sizeof(struct ospf6_network_lsdesc
));
514 for (lsdesc
= OSPF6_LSA_HEADER_END(v
->lsa
->header
) + 4;
515 lsdesc
+ size
<= OSPF6_LSA_END(v
->lsa
->header
);
517 lsa
= ospf6_lsdesc_lsa(lsdesc
, v
);
521 if (OSPF6_LSA_IS_MAXAGE(lsa
))
524 if (!ospf6_lsdesc_backlink(lsa
, lsdesc
, v
))
527 w
= ospf6_vertex_create(lsa
);
530 if (VERTEX_IS_TYPE(ROUTER
, v
)) {
532 + ROUTER_LSDESC_GET_METRIC(lsdesc
);
535 + (VERTEX_IS_TYPE(NETWORK
, w
) ? 0 : 1);
539 w
->hops
= v
->hops
+ 1;
542 /* nexthop calculation */
546 ROUTER_LSDESC_GET_IFID(lsdesc
), NULL
);
547 else if (w
->hops
== 1 && v
->hops
== 0)
548 ospf6_nexthop_calc(w
, v
, lsdesc
, oa
->ospf6
);
550 ospf6_copy_nexthops(w
->nh_list
, v
->nh_list
);
553 /* add new candidate to the candidate_list */
554 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
556 " New candidate: %s hops %d cost %d",
557 w
->name
, w
->hops
, w
->cost
);
558 vertex_pqueue_add(&candidate_list
, w
);
562 //vertex_pqueue_fini(&candidate_list);
564 ospf6_remove_temp_router_lsa(oa
);
566 oa
->spf_calculation
++;
569 static void ospf6_spf_log_database(struct ospf6_area
*oa
)
571 char *p
, *end
, buffer
[256];
572 struct listnode
*node
;
573 struct ospf6_interface
*oi
;
576 end
= buffer
+ sizeof(buffer
);
578 snprintf(p
, end
- p
, "SPF on DB (#LSAs):");
579 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
580 snprintf(p
, end
- p
, " Area %s: %d", oa
->name
, oa
->lsdb
->count
);
581 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
) : end
);
583 for (ALL_LIST_ELEMENTS_RO(oa
->if_list
, node
, oi
)) {
584 snprintf(p
, end
- p
, " I/F %s: %d", oi
->interface
->name
,
586 p
= (buffer
+ strlen(buffer
) < end
? buffer
+ strlen(buffer
)
590 zlog_debug("%s", buffer
);
593 static void ospf6_spf_calculation_thread(struct thread
*t
)
595 struct ospf6_area
*oa
;
597 struct timeval start
, end
, runtime
;
598 struct listnode
*node
;
599 int areas_processed
= 0;
602 ospf6
= (struct ospf6
*)THREAD_ARG(t
);
604 /* execute SPF calculation */
606 ospf6
->ts_spf
= start
;
608 if (ospf6_check_and_set_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_check_and_set_router_abr(ospf6
)) {
649 ospf6_abr_defaults_to_stub(ospf6
);
650 ospf6_abr_nssa_type_7_defaults(ospf6
);
654 timersub(&end
, &start
, &runtime
);
656 ospf6
->ts_spf_duration
= runtime
;
658 ospf6_spf_reason_string(ospf6
->spf_reason
, rbuf
, sizeof(rbuf
));
660 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
662 "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s",
663 areas_processed
, (long long)runtime
.tv_sec
,
664 (long long)runtime
.tv_usec
, rbuf
);
666 ospf6
->last_spf_reason
= ospf6
->spf_reason
;
667 ospf6_reset_spf_reason(ospf6
);
670 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
671 set timer for SPF calc. */
672 void ospf6_spf_schedule(struct ospf6
*ospf6
, unsigned int reason
)
674 unsigned long delay
, elapsed
, ht
;
676 /* OSPF instance does not exist. */
680 ospf6_set_spf_reason(ospf6
, reason
);
682 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
)) {
684 ospf6_spf_reason_string(reason
, rbuf
, sizeof(rbuf
));
685 zlog_debug("SPF: calculation timer scheduled (reason %s)",
689 /* SPF calculation timer is already scheduled. */
690 if (thread_is_scheduled(ospf6
->t_spf_calc
)) {
691 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
693 "SPF: calculation timer is already scheduled: %p",
694 (void *)ospf6
->t_spf_calc
);
698 elapsed
= monotime_since(&ospf6
->ts_spf
, NULL
) / 1000LL;
699 ht
= ospf6
->spf_holdtime
* ospf6
->spf_hold_multiplier
;
701 if (ht
> ospf6
->spf_max_holdtime
)
702 ht
= ospf6
->spf_max_holdtime
;
704 /* Get SPF calculation delay time. */
706 /* Got an event within the hold time of last SPF. We need to
707 * increase the hold_multiplier, if it's not already at/past
708 * maximum value, and wasn't already increased..
710 if (ht
< ospf6
->spf_max_holdtime
)
711 ospf6
->spf_hold_multiplier
++;
713 /* always honour the SPF initial delay */
714 if ((ht
- elapsed
) < ospf6
->spf_delay
)
715 delay
= ospf6
->spf_delay
;
717 delay
= ht
- elapsed
;
719 /* Event is past required hold-time of last SPF */
720 delay
= ospf6
->spf_delay
;
721 ospf6
->spf_hold_multiplier
= 1;
724 if (IS_OSPF6_DEBUG_SPF(PROCESS
) || IS_OSPF6_DEBUG_SPF(TIME
))
725 zlog_debug("SPF: Rescheduling in %ld msec", delay
);
727 THREAD_OFF(ospf6
->t_spf_calc
);
728 thread_add_timer_msec(master
, ospf6_spf_calculation_thread
, ospf6
,
729 delay
, &ospf6
->t_spf_calc
);
732 void ospf6_spf_display_subtree(struct vty
*vty
, const char *prefix
, int rest
,
733 struct ospf6_vertex
*v
, json_object
*json_obj
,
736 struct listnode
*node
, *nnode
;
737 struct ospf6_vertex
*c
;
741 json_object
*json_childs
= NULL
;
742 json_object
*json_child
= NULL
;
745 json_childs
= json_object_new_object();
746 json_object_int_add(json_obj
, "cost", v
->cost
);
748 /* "prefix" is the space prefix of the display line */
749 vty_out(vty
, "%s+-%s [%d]\n", prefix
, v
->name
, v
->cost
);
752 len
= strlen(prefix
) + 4;
753 next_prefix
= (char *)malloc(len
);
754 if (next_prefix
== NULL
) {
755 vty_out(vty
, "malloc failed\n");
758 snprintf(next_prefix
, len
, "%s%s", prefix
, (rest
? "| " : " "));
760 restnum
= listcount(v
->child_list
);
761 for (ALL_LIST_ELEMENTS(v
->child_list
, node
, nnode
, c
)) {
763 json_child
= json_object_new_object();
767 ospf6_spf_display_subtree(vty
, next_prefix
, restnum
, c
,
768 json_child
, use_json
);
771 json_object_object_add(json_childs
, c
->name
,
775 json_object_boolean_add(json_obj
, "isLeafNode",
776 !listcount(v
->child_list
));
777 if (listcount(v
->child_list
))
778 json_object_object_add(json_obj
, "children",
781 json_object_free(json_childs
);
786 DEFUN (debug_ospf6_spf_process
,
787 debug_ospf6_spf_process_cmd
,
788 "debug ospf6 spf process",
791 "Debug SPF Calculation\n"
792 "Debug Detailed SPF Process\n"
795 unsigned char level
= 0;
796 level
= OSPF6_DEBUG_SPF_PROCESS
;
797 OSPF6_DEBUG_SPF_ON(level
);
801 DEFUN (debug_ospf6_spf_time
,
802 debug_ospf6_spf_time_cmd
,
803 "debug ospf6 spf time",
806 "Debug SPF Calculation\n"
807 "Measure time taken by SPF Calculation\n"
810 unsigned char level
= 0;
811 level
= OSPF6_DEBUG_SPF_TIME
;
812 OSPF6_DEBUG_SPF_ON(level
);
816 DEFUN (debug_ospf6_spf_database
,
817 debug_ospf6_spf_database_cmd
,
818 "debug ospf6 spf database",
821 "Debug SPF Calculation\n"
822 "Log number of LSAs at SPF Calculation time\n"
825 unsigned char level
= 0;
826 level
= OSPF6_DEBUG_SPF_DATABASE
;
827 OSPF6_DEBUG_SPF_ON(level
);
831 DEFUN (no_debug_ospf6_spf_process
,
832 no_debug_ospf6_spf_process_cmd
,
833 "no debug ospf6 spf process",
837 "Quit Debugging SPF Calculation\n"
838 "Quit Debugging Detailed SPF Process\n"
841 unsigned char level
= 0;
842 level
= OSPF6_DEBUG_SPF_PROCESS
;
843 OSPF6_DEBUG_SPF_OFF(level
);
847 DEFUN (no_debug_ospf6_spf_time
,
848 no_debug_ospf6_spf_time_cmd
,
849 "no debug ospf6 spf time",
853 "Quit Debugging SPF Calculation\n"
854 "Quit Measuring time taken by SPF Calculation\n"
857 unsigned char level
= 0;
858 level
= OSPF6_DEBUG_SPF_TIME
;
859 OSPF6_DEBUG_SPF_OFF(level
);
863 DEFUN (no_debug_ospf6_spf_database
,
864 no_debug_ospf6_spf_database_cmd
,
865 "no debug ospf6 spf database",
869 "Debug SPF Calculation\n"
870 "Quit Logging number of LSAs at SPF Calculation time\n"
873 unsigned char level
= 0;
874 level
= OSPF6_DEBUG_SPF_DATABASE
;
875 OSPF6_DEBUG_SPF_OFF(level
);
879 static int ospf6_timers_spf_set(struct vty
*vty
, unsigned int delay
,
880 unsigned int hold
, unsigned int max
)
882 VTY_DECLVAR_CONTEXT(ospf6
, ospf
);
884 ospf
->spf_delay
= delay
;
885 ospf
->spf_holdtime
= hold
;
886 ospf
->spf_max_holdtime
= max
;
891 DEFUN (ospf6_timers_throttle_spf
,
892 ospf6_timers_throttle_spf_cmd
,
893 "timers throttle spf (0-600000) (0-600000) (0-600000)",
894 "Adjust routing timers\n"
895 "Throttling adaptive timer\n"
897 "Delay (msec) from first change received till SPF calculation\n"
898 "Initial hold time (msec) between consecutive SPF calculations\n"
899 "Maximum hold time (msec)\n")
902 int idx_number_2
= 4;
903 int idx_number_3
= 5;
904 unsigned int delay
, hold
, max
;
906 delay
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
907 hold
= strtoul(argv
[idx_number_2
]->arg
, NULL
, 10);
908 max
= strtoul(argv
[idx_number_3
]->arg
, NULL
, 10);
910 return ospf6_timers_spf_set(vty
, delay
, hold
, max
);
913 DEFUN (no_ospf6_timers_throttle_spf
,
914 no_ospf6_timers_throttle_spf_cmd
,
915 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
917 "Adjust routing timers\n"
918 "Throttling adaptive timer\n"
920 "Delay (msec) from first change received till SPF calculation\n"
921 "Initial hold time (msec) between consecutive SPF calculations\n"
922 "Maximum hold time (msec)\n")
924 return ospf6_timers_spf_set(vty
, OSPF_SPF_DELAY_DEFAULT
,
925 OSPF_SPF_HOLDTIME_DEFAULT
,
926 OSPF_SPF_MAX_HOLDTIME_DEFAULT
);
930 int config_write_ospf6_debug_spf(struct vty
*vty
)
932 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
933 vty_out(vty
, "debug ospf6 spf process\n");
934 if (IS_OSPF6_DEBUG_SPF(TIME
))
935 vty_out(vty
, "debug ospf6 spf time\n");
936 if (IS_OSPF6_DEBUG_SPF(DATABASE
))
937 vty_out(vty
, "debug ospf6 spf database\n");
941 void ospf6_spf_config_write(struct vty
*vty
, struct ospf6
*ospf6
)
944 if (ospf6
->spf_delay
!= OSPF_SPF_DELAY_DEFAULT
945 || ospf6
->spf_holdtime
!= OSPF_SPF_HOLDTIME_DEFAULT
946 || ospf6
->spf_max_holdtime
!= OSPF_SPF_MAX_HOLDTIME_DEFAULT
)
947 vty_out(vty
, " timers throttle spf %d %d %d\n",
948 ospf6
->spf_delay
, ospf6
->spf_holdtime
,
949 ospf6
->spf_max_holdtime
);
952 void install_element_ospf6_debug_spf(void)
954 install_element(ENABLE_NODE
, &debug_ospf6_spf_process_cmd
);
955 install_element(ENABLE_NODE
, &debug_ospf6_spf_time_cmd
);
956 install_element(ENABLE_NODE
, &debug_ospf6_spf_database_cmd
);
957 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_process_cmd
);
958 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_time_cmd
);
959 install_element(ENABLE_NODE
, &no_debug_ospf6_spf_database_cmd
);
960 install_element(CONFIG_NODE
, &debug_ospf6_spf_process_cmd
);
961 install_element(CONFIG_NODE
, &debug_ospf6_spf_time_cmd
);
962 install_element(CONFIG_NODE
, &debug_ospf6_spf_database_cmd
);
963 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_process_cmd
);
964 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_time_cmd
);
965 install_element(CONFIG_NODE
, &no_debug_ospf6_spf_database_cmd
);
968 void ospf6_spf_init(void)
970 install_element(OSPF6_NODE
, &ospf6_timers_throttle_spf_cmd
);
971 install_element(OSPF6_NODE
, &no_ospf6_timers_throttle_spf_cmd
);
974 /* Create Aggregated Large Router-LSA from multiple Link-State IDs
976 * When more than one router-LSA is received from a single router,
977 * the links are processed as if concatenated into a single LSA.*/
978 struct ospf6_lsa
*ospf6_create_single_router_lsa(struct ospf6_area
*area
,
979 struct ospf6_lsdb
*lsdb
,
982 struct ospf6_lsa
*lsa
= NULL
;
983 struct ospf6_lsa
*rtr_lsa
= NULL
;
984 struct ospf6_lsa_header
*lsa_header
= NULL
;
985 uint8_t *new_header
= NULL
;
986 const struct route_node
*end
= NULL
;
987 uint16_t lsa_length
, total_lsa_length
= 0, num_lsa
= 0;
990 uint32_t interface_id
;
993 lsa_length
= sizeof(struct ospf6_lsa_header
)
994 + sizeof(struct ospf6_router_lsa
);
995 total_lsa_length
= lsa_length
;
996 type
= htons(OSPF6_LSTYPE_ROUTER
);
998 /* First check Aggregated LSA formed earlier in Cache */
999 lsa
= ospf6_lsdb_lookup(type
, htonl(0), adv_router
,
1000 area
->temp_router_lsa_lsdb
);
1004 inet_ntop(AF_INET
, &adv_router
, ifbuf
, sizeof(ifbuf
));
1006 /* Determine total LSA length from all link state ids */
1007 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1010 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1011 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1014 lsa_header
= rtr_lsa
->header
;
1015 total_lsa_length
+= (ntohs(lsa_header
->length
) - lsa_length
);
1017 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1019 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1020 zlog_debug("%s: adv_router %s num_lsa %u to convert.", __func__
,
1026 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1027 zlog_debug("%s: adv_router %s not found in LSDB.",
1032 lsa
= ospf6_lsa_alloc(total_lsa_length
);
1033 new_header
= (uint8_t *)lsa
->header
;
1035 lsa
->lsdb
= area
->temp_router_lsa_lsdb
;
1037 /* Fill Larger LSA Payload */
1038 end
= ospf6_lsdb_head(lsdb
, 2, type
, adv_router
, &rtr_lsa
);
1041 * We assume at this point in time that rtr_lsa is
1045 if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1046 /* Append first Link State ID LSA */
1047 lsa_header
= rtr_lsa
->header
;
1048 memcpy(new_header
, lsa_header
, ntohs(lsa_header
->length
));
1049 /* Assign new lsa length as aggregated length. */
1050 ((struct ospf6_lsa_header
*)new_header
)->length
=
1051 htons(total_lsa_length
);
1052 new_header
+= ntohs(lsa_header
->length
);
1056 /* Print LSA Name */
1057 ospf6_lsa_printbuf(lsa
, lsa
->name
, sizeof(lsa
->name
));
1059 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1061 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa
)) {
1062 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1066 if (IS_OSPF6_DEBUG_SPF(PROCESS
)) {
1067 lsd
= OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4;
1068 interface_id
= ROUTER_LSDESC_GET_IFID(lsd
);
1069 inet_ntop(AF_INET
, &interface_id
, ifbuf
, sizeof(ifbuf
));
1071 "%s: Next Router LSA %s to aggreat with len %u interface_id %s",
1072 __func__
, rtr_lsa
->name
,
1073 ntohs(lsa_header
->length
), ifbuf
);
1076 /* Append Next Link State ID LSA */
1077 lsa_header
= rtr_lsa
->header
;
1078 memcpy(new_header
, (OSPF6_LSA_HEADER_END(rtr_lsa
->header
) + 4),
1079 (ntohs(lsa_header
->length
) - lsa_length
));
1080 new_header
+= (ntohs(lsa_header
->length
) - lsa_length
);
1083 rtr_lsa
= ospf6_lsdb_next(end
, rtr_lsa
);
1086 /* Calculate birth of this lsa */
1087 ospf6_lsa_age_set(lsa
);
1089 /* Store Aggregated LSA into area temp lsdb */
1090 ospf6_lsdb_add(lsa
, area
->temp_router_lsa_lsdb
);
1092 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1093 zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
1094 __func__
, lsa
->name
, ntohl(lsa
->header
->id
),
1095 ntohs(lsa
->header
->type
), ntohs(lsa
->header
->length
),
1101 void ospf6_remove_temp_router_lsa(struct ospf6_area
*area
)
1103 struct ospf6_lsa
*lsa
= NULL
, *lsanext
;
1105 for (ALL_LSDB(area
->temp_router_lsa_lsdb
, lsa
, lsanext
)) {
1106 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1108 "%s Remove LSA %s lsa->lock %u lsdb count %u",
1109 __func__
, lsa
->name
, lsa
->lock
,
1110 area
->temp_router_lsa_lsdb
->count
);
1111 ospf6_lsdb_remove(lsa
, area
->temp_router_lsa_lsdb
);
1115 int ospf6_ase_calculate_route(struct ospf6
*ospf6
, struct ospf6_lsa
*lsa
,
1116 struct ospf6_area
*area
)
1118 struct ospf6_route
*route
;
1119 struct ospf6_as_external_lsa
*external
;
1120 struct prefix prefix
;
1121 void (*hook_add
)(struct ospf6_route
*) = NULL
;
1122 void (*hook_remove
)(struct ospf6_route
*) = NULL
;
1126 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1127 zlog_debug("%s : start", __func__
);
1129 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
)
1130 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1131 zlog_debug("%s: Processing Type-7", __func__
);
1133 /* Stay away from any Local Translated Type-7 LSAs */
1134 if (CHECK_FLAG(lsa
->flag
, OSPF6_LSA_LOCAL_XLT
)) {
1135 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1136 zlog_debug("%s: Rejecting Local translated LSA",
1141 external
= (struct ospf6_as_external_lsa
*)OSPF6_LSA_HEADER_END(
1143 prefix
.family
= AF_INET6
;
1144 prefix
.prefixlen
= external
->prefix
.prefix_length
;
1145 ospf6_prefix_in6_addr(&prefix
.u
.prefix6
, external
, &external
->prefix
);
1147 if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_AS_EXTERNAL
) {
1148 hook_add
= ospf6
->route_table
->hook_add
;
1149 hook_remove
= ospf6
->route_table
->hook_remove
;
1150 ospf6
->route_table
->hook_add
= NULL
;
1151 ospf6
->route_table
->hook_remove
= NULL
;
1153 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1154 ospf6_asbr_lsa_add(lsa
);
1156 ospf6
->route_table
->hook_add
= hook_add
;
1157 ospf6
->route_table
->hook_remove
= hook_remove
;
1159 route
= ospf6_route_lookup(&prefix
, ospf6
->route_table
);
1160 if (route
== NULL
) {
1161 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1162 zlog_debug("%s: no external route %pFX",
1167 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1168 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1169 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1170 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1173 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
))
1174 ospf6_route_remove(route
, ospf6
->route_table
);
1175 else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1176 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1178 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1180 "%s: add external route %pFX",
1185 } else if (ntohs(lsa
->header
->type
) == OSPF6_LSTYPE_TYPE_7
) {
1186 hook_add
= area
->route_table
->hook_add
;
1187 hook_remove
= area
->route_table
->hook_remove
;
1188 area
->route_table
->hook_add
= NULL
;
1189 area
->route_table
->hook_remove
= NULL
;
1191 if (!OSPF6_LSA_IS_MAXAGE(lsa
))
1192 ospf6_asbr_lsa_add(lsa
);
1194 area
->route_table
->hook_add
= hook_add
;
1195 area
->route_table
->hook_remove
= hook_remove
;
1197 route
= ospf6_route_lookup(&prefix
, area
->route_table
);
1198 if (route
== NULL
) {
1199 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1200 zlog_debug("%s: no route %pFX, area %s",
1201 __func__
, &prefix
, area
->name
);
1205 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)
1206 && CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)) {
1207 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
);
1208 UNSET_FLAG(route
->flag
, OSPF6_ROUTE_ADD
);
1211 if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_REMOVE
)) {
1212 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1213 zlog_debug("%s : remove route %pFX, area %s",
1214 __func__
, &prefix
, area
->name
);
1215 ospf6_route_remove(route
, area
->route_table
);
1216 } else if (CHECK_FLAG(route
->flag
, OSPF6_ROUTE_ADD
)
1217 || CHECK_FLAG(route
->flag
, OSPF6_ROUTE_CHANGE
)) {
1219 if (IS_OSPF6_DEBUG_SPF(PROCESS
))
1221 "%s: add nssa route %pFX, area %s",
1222 __func__
, &prefix
, area
->name
);
1225 ospf6_abr_check_translate_nssa(area
, lsa
);
1231 static void ospf6_ase_calculate_timer(struct thread
*t
)
1233 struct ospf6
*ospf6
;
1234 struct ospf6_lsa
*lsa
;
1235 struct listnode
*node
, *nnode
;
1236 struct ospf6_area
*area
;
1239 ospf6
= THREAD_ARG(t
);
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 type
= htons(OSPF6_LSTYPE_TYPE_7
);
1254 for (ALL_LSDB_TYPED(area
->lsdb
, type
, lsa
))
1255 ospf6_ase_calculate_route(ospf6
, lsa
, area
);
1259 if (ospf6
->gr_info
.finishing_restart
) {
1261 * The routing table computation is complete. Uninstall remnant
1262 * routes that were installed before the restart, but that are
1265 ospf6_zebra_gr_disable(ospf6
);
1266 ospf6
->gr_info
.finishing_restart
= false;
1270 void ospf6_ase_calculate_timer_add(struct ospf6
*ospf6
)
1275 thread_add_timer(master
, ospf6_ase_calculate_timer
, ospf6
,
1276 OSPF6_ASE_CALC_INTERVAL
, &ospf6
->t_ase_calc
);