]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_spf.c
Merge pull request #2514 from pacovn/Coverity_1462467_1465497_Control_flow_issues
[mirror_frr.git] / ospf6d / ospf6_spf.c
CommitLineData
718e3744 1/*
508e53e2 2 * Copyright (C) 2003 Yasuhiro Ohara
718e3744 3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
896014f4
DL
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
718e3744 19 */
508e53e2 20
718e3744 21/* Shortest Path First calculation for OSPFv3 */
22
508e53e2 23#include <zebra.h>
718e3744 24
508e53e2 25#include "log.h"
26#include "memory.h"
27#include "command.h"
28#include "vty.h"
718e3744 29#include "prefix.h"
508e53e2 30#include "pqueue.h"
31#include "linklist.h"
32#include "thread.h"
718e3744 33
718e3744 34#include "ospf6_lsa.h"
35#include "ospf6_lsdb.h"
36#include "ospf6_route.h"
508e53e2 37#include "ospf6_area.h"
ca1f4309
DS
38#include "ospf6_proto.h"
39#include "ospf6_abr.h"
718e3744 40#include "ospf6_spf.h"
508e53e2 41#include "ospf6_intra.h"
718e3744 42#include "ospf6_interface.h"
049207c3 43#include "ospf6d.h"
1f9a9fff 44#include "ospf6_abr.h"
718e3744 45
508e53e2 46unsigned char conf_debug_ospf6_spf = 0;
718e3744 47
d62a17ae 48static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route *rt,
49 struct ospf6_vertex *v)
c3c0ac83 50{
d62a17ae 51 if (rt && v)
52 ospf6_copy_nexthops(rt->nh_list, v->nh_list);
c3c0ac83
DS
53}
54
d62a17ae 55static void ospf6_spf_merge_nexthops_to_route(struct ospf6_route *rt,
56 struct ospf6_vertex *v)
c3c0ac83 57{
d62a17ae 58 if (rt && v)
59 ospf6_merge_nexthops(rt->nh_list, v->nh_list);
c3c0ac83
DS
60}
61
d62a17ae 62static unsigned int ospf6_spf_get_ifindex_from_nh(struct ospf6_vertex *v)
c3c0ac83 63{
d62a17ae 64 struct ospf6_nexthop *nh;
65 struct listnode *node;
66
67 if (v) {
68 node = listhead(v->nh_list);
69 if (node) {
70 nh = listgetdata(node);
71 if (nh)
72 return (nh->ifindex);
73 }
c3c0ac83 74 }
d62a17ae 75 return 0;
c3c0ac83
DS
76}
77
d62a17ae 78static int ospf6_vertex_cmp(void *a, void *b)
718e3744 79{
d62a17ae 80 struct ospf6_vertex *va = (struct ospf6_vertex *)a;
81 struct ospf6_vertex *vb = (struct ospf6_vertex *)b;
718e3744 82
d62a17ae 83 /* ascending order */
84 if (va->cost != vb->cost)
85 return (va->cost - vb->cost);
86 return (va->hops - vb->hops);
718e3744 87}
88
d62a17ae 89static int ospf6_vertex_id_cmp(void *a, void *b)
718e3744 90{
d62a17ae 91 struct ospf6_vertex *va = (struct ospf6_vertex *)a;
92 struct ospf6_vertex *vb = (struct ospf6_vertex *)b;
93 int ret = 0;
94
95 ret = ntohl(ospf6_linkstate_prefix_adv_router(&va->vertex_id))
96 - ntohl(ospf6_linkstate_prefix_adv_router(&vb->vertex_id));
97 if (ret)
98 return ret;
99
100 ret = ntohl(ospf6_linkstate_prefix_id(&va->vertex_id))
101 - ntohl(ospf6_linkstate_prefix_id(&vb->vertex_id));
102 return ret;
718e3744 103}
104
d62a17ae 105static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
718e3744 106{
d62a17ae 107 struct ospf6_vertex *v;
718e3744 108
d62a17ae 109 v = (struct ospf6_vertex *)XMALLOC(MTYPE_OSPF6_VERTEX,
110 sizeof(struct ospf6_vertex));
718e3744 111
d62a17ae 112 /* type */
26e14616 113 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
d62a17ae 114 v->type = OSPF6_VERTEX_TYPE_ROUTER;
26e14616
CS
115 /* Router LSA use Link ID 0 as base in vertex_id */
116 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0),
996c9314 117 &v->vertex_id);
26e14616 118 } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) {
d62a17ae 119 v->type = OSPF6_VERTEX_TYPE_NETWORK;
26e14616
CS
120 /* vertex_id */
121 ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id,
996c9314 122 &v->vertex_id);
26e14616
CS
123 } else
124 assert(0);
718e3744 125
d62a17ae 126 /* name */
127 ospf6_linkstate_prefix2str(&v->vertex_id, v->name, sizeof(v->name));
718e3744 128
d62a17ae 129 if (IS_OSPF6_DEBUG_SPF(PROCESS))
26e14616
CS
130 zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s",
131 __func__, v->name,
d62a17ae 132 ((ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER)
133 ? "Router"
996c9314
LB
134 : "N/W"),
135 ntohs(lsa->header->type), lsa->name);
26e14616 136
c3c0ac83 137
d62a17ae 138 /* Associated LSA */
139 v->lsa = lsa;
718e3744 140
d62a17ae 141 /* capability bits + options */
d7c0a89a
QY
142 v->capability = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header));
143 v->options[0] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 1);
144 v->options[1] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 2);
145 v->options[2] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
718e3744 146
d62a17ae 147 v->nh_list = list_new();
064d4355 148 v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
996c9314 149 v->nh_list->del = (void (*)(void *))ospf6_nexthop_delete;
718e3744 150
d62a17ae 151 v->parent = NULL;
152 v->child_list = list_new();
153 v->child_list->cmp = ospf6_vertex_id_cmp;
718e3744 154
d62a17ae 155 return v;
718e3744 156}
157
d62a17ae 158static void ospf6_vertex_delete(struct ospf6_vertex *v)
718e3744 159{
affe9e99
DS
160 list_delete_and_null(&v->nh_list);
161 list_delete_and_null(&v->child_list);
d62a17ae 162 XFREE(MTYPE_OSPF6_VERTEX, v);
718e3744 163}
164
d62a17ae 165static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
da086a3b 166 struct ospf6_vertex *v)
718e3744 167{
da086a3b 168 struct ospf6_lsa *lsa = NULL;
d7c0a89a
QY
169 uint16_t type = 0;
170 uint32_t id = 0, adv_router = 0;
d62a17ae 171
172 if (VERTEX_IS_TYPE(NETWORK, v)) {
173 type = htons(OSPF6_LSTYPE_ROUTER);
da086a3b 174 id = htonl(0);
d62a17ae 175 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc);
176 } else {
177 if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) {
178 type = htons(OSPF6_LSTYPE_ROUTER);
da086a3b 179 id = htonl(0);
d62a17ae 180 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
181 } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) {
182 type = htons(OSPF6_LSTYPE_NETWORK);
183 id = htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc));
184 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
185 }
186 }
187
da086a3b
CS
188 if (type == htons(OSPF6_LSTYPE_NETWORK))
189 lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
190 else
191 lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb,
192 adv_router);
d62a17ae 193 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
194 char ibuf[16], abuf[16];
195 inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf));
196 inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf));
197 if (lsa)
da086a3b
CS
198 zlog_debug(" Link to: %s len %u, V %s", lsa->name,
199 ntohs(lsa->header->length), v->name);
d62a17ae 200 else
da086a3b 201 zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s",
26e14616 202 ospf6_lstype_name(type), ibuf, abuf,
da086a3b 203 v->name);
d62a17ae 204 }
205
206 return lsa;
718e3744 207}
208
d62a17ae 209static char *ospf6_lsdesc_backlink(struct ospf6_lsa *lsa, caddr_t lsdesc,
210 struct ospf6_vertex *v)
718e3744 211{
d62a17ae 212 caddr_t backlink, found = NULL;
213 int size;
214
215 size = (OSPF6_LSA_IS_TYPE(ROUTER, lsa)
216 ? sizeof(struct ospf6_router_lsdesc)
217 : sizeof(struct ospf6_network_lsdesc));
218 for (backlink = OSPF6_LSA_HEADER_END(lsa->header) + 4;
219 backlink + size <= OSPF6_LSA_END(lsa->header); backlink += size) {
220 assert(!(OSPF6_LSA_IS_TYPE(NETWORK, lsa)
221 && VERTEX_IS_TYPE(NETWORK, v)));
222
223 if (OSPF6_LSA_IS_TYPE(NETWORK, lsa)
224 && NETWORK_LSDESC_GET_NBR_ROUTERID(backlink)
225 == v->lsa->header->adv_router)
226 found = backlink;
227 else if (VERTEX_IS_TYPE(NETWORK, v)
228 && ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink)
229 && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
230 == v->lsa->header->adv_router
231 && ROUTER_LSDESC_GET_NBR_IFID(backlink)
232 == ntohl(v->lsa->header->id))
233 found = backlink;
234 else {
235 if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, backlink)
236 || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc))
237 continue;
238 if (ROUTER_LSDESC_GET_NBR_IFID(backlink)
239 != ROUTER_LSDESC_GET_IFID(lsdesc)
240 || ROUTER_LSDESC_GET_NBR_IFID(lsdesc)
241 != ROUTER_LSDESC_GET_IFID(backlink))
242 continue;
243 if (ROUTER_LSDESC_GET_NBR_ROUTERID(backlink)
244 != v->lsa->header->adv_router
245 || ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc)
246 != lsa->header->adv_router)
247 continue;
248 found = backlink;
249 }
250 }
251
252 if (IS_OSPF6_DEBUG_SPF(PROCESS))
1ba43456
CS
253 zlog_debug("Vertex %s Lsa %s Backlink %s", v->name, lsa->name,
254 (found ? "OK" : "FAIL"));
d62a17ae 255
256 return found;
718e3744 257}
258
d62a17ae 259static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
260 caddr_t lsdesc)
718e3744 261{
d62a17ae 262 int i;
263 ifindex_t ifindex;
264 struct ospf6_interface *oi;
d7c0a89a
QY
265 uint16_t type;
266 uint32_t adv_router;
d62a17ae 267 struct ospf6_lsa *lsa;
268 struct ospf6_link_lsa *link_lsa;
269 char buf[64];
270
271 assert(VERTEX_IS_TYPE(ROUTER, w));
272 ifindex = (VERTEX_IS_TYPE(NETWORK, v) ? ospf6_spf_get_ifindex_from_nh(v)
273 : ROUTER_LSDESC_GET_IFID(lsdesc));
274 if (ifindex == 0) {
275 zlog_err("No nexthop ifindex at vertex %s", v->name);
276 return;
277 }
278
279 oi = ospf6_interface_lookup_by_ifindex(ifindex);
280 if (oi == NULL) {
281 if (IS_OSPF6_DEBUG_SPF(PROCESS))
282 zlog_debug("Can't find interface in SPF: ifindex %d",
283 ifindex);
284 return;
285 }
286
287 type = htons(OSPF6_LSTYPE_LINK);
288 adv_router = (VERTEX_IS_TYPE(NETWORK, v)
289 ? NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc)
290 : ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc));
291
292 i = 0;
293 for (ALL_LSDB_TYPED_ADVRTR(oi->lsdb, type, adv_router, lsa)) {
294 if (VERTEX_IS_TYPE(ROUTER, v)
295 && htonl(ROUTER_LSDESC_GET_NBR_IFID(lsdesc))
296 != lsa->header->id)
297 continue;
298
299 link_lsa = (struct ospf6_link_lsa *)OSPF6_LSA_HEADER_END(
300 lsa->header);
301 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
302 inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
303 sizeof(buf));
304 zlog_debug(" nexthop %s from %s", buf, lsa->name);
305 }
306
307 ospf6_add_nexthop(w->nh_list, ifindex,
308 &link_lsa->linklocal_addr);
309 i++;
310 }
311
312 if (i == 0 && IS_OSPF6_DEBUG_SPF(PROCESS))
313 zlog_debug("No nexthop for %s found", w->name);
718e3744 314}
315
d62a17ae 316static int ospf6_spf_install(struct ospf6_vertex *v,
317 struct ospf6_route_table *result_table)
718e3744 318{
d62a17ae 319 struct ospf6_route *route, *parent_route;
320 struct ospf6_vertex *prev;
26e14616 321 char pbuf[PREFIX2STR_BUFFER];
d62a17ae 322
323 if (IS_OSPF6_DEBUG_SPF(PROCESS))
26e14616
CS
324 zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v->name,
325 v->lsa->name, v->hops, v->cost);
d62a17ae 326
327 route = ospf6_route_lookup(&v->vertex_id, result_table);
328 if (route && route->path.cost < v->cost) {
329 if (IS_OSPF6_DEBUG_SPF(PROCESS))
330 zlog_debug(
331 " already installed with lower cost (%d), ignore",
332 route->path.cost);
333 ospf6_vertex_delete(v);
334 return -1;
335 } else if (route && route->path.cost == v->cost) {
26e14616
CS
336 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
337 prefix2str(&route->prefix, pbuf, sizeof(pbuf));
996c9314
LB
338 zlog_debug(
339 " another path found to route %s lsa %s, merge",
340 pbuf, v->lsa->name);
26e14616 341 }
d62a17ae 342 ospf6_spf_merge_nexthops_to_route(route, v);
343
344 prev = (struct ospf6_vertex *)route->route_option;
345 assert(prev->hops <= v->hops);
d62a17ae 346
996c9314
LB
347 if ((VERTEX_IS_TYPE(ROUTER, v)
348 && route->path.origin.id != v->lsa->header->id)) {
26e14616 349 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
996c9314
LB
350 zlog_debug(
351 "%s: V lsa %s id %u, route id %u are different",
352 __PRETTY_FUNCTION__, v->lsa->name,
353 ntohl(v->lsa->header->id),
354 ntohl(route->path.origin.id));
26e14616
CS
355 }
356 return 0;
357 }
358
359 ospf6_vertex_delete(v);
d62a17ae 360 return -1;
c3c0ac83 361 }
508e53e2 362
d62a17ae 363 /* There should be no case where candidate being installed (variable
364 "v") is closer than the one in the SPF tree (variable "route").
365 In the case something has gone wrong with the behavior of
366 Priority-Queue. */
367
368 /* the case where the route exists already is handled and returned
369 up to here. */
370 assert(route == NULL);
371
372 route = ospf6_route_create();
373 memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
374 route->type = OSPF6_DEST_TYPE_LINKSTATE;
375 route->path.type = OSPF6_PATH_TYPE_INTRA;
376 route->path.origin.type = v->lsa->header->type;
377 route->path.origin.id = v->lsa->header->id;
378 route->path.origin.adv_router = v->lsa->header->adv_router;
379 route->path.metric_type = 1;
380 route->path.cost = v->cost;
381 route->path.u.cost_e2 = v->hops;
382 route->path.router_bits = v->capability;
383 route->path.options[0] = v->options[0];
384 route->path.options[1] = v->options[1];
385 route->path.options[2] = v->options[2];
386
387 ospf6_spf_copy_nexthops_to_route(route, v);
388
389 /*
390 * The SPF logic implementation does not transfer the multipathing
391 * properties
392 * of a parent to a child node. Thus if there was a 3-way multipath to a
393 * node's parent and a single hop from the parent to the child, the
394 * logic of
395 * creating new vertices and computing next hops prevents there from
396 * being 3
397 * paths to the child node. This is primarily because the resolution of
398 * multipath is done in this routine, not in the main spf loop.
399 *
400 * The following logic addresses that problem by merging the parent's
401 * nexthop
402 * information with the child's, if the parent is not the root of the
403 * tree.
404 * This is based on the assumption that before a node's route is
405 * installed,
406 * its parent's route's nexthops have already been installed.
407 */
408 if (v->parent && v->parent->hops) {
409 parent_route =
410 ospf6_route_lookup(&v->parent->vertex_id, result_table);
411 if (parent_route) {
412 ospf6_route_merge_nexthops(route, parent_route);
413 }
414 }
415
416 if (v->parent)
417 listnode_add_sort(v->parent->child_list, v);
418 route->route_option = v;
508e53e2 419
d62a17ae 420 ospf6_route_add(route, result_table);
421 return 0;
718e3744 422}
423
d62a17ae 424void ospf6_spf_table_finish(struct ospf6_route_table *result_table)
718e3744 425{
d62a17ae 426 struct ospf6_route *route, *nroute;
427 struct ospf6_vertex *v;
428 for (route = ospf6_route_head(result_table); route; route = nroute) {
429 nroute = ospf6_route_next(route);
430 v = (struct ospf6_vertex *)route->route_option;
431 ospf6_vertex_delete(v);
432 ospf6_route_remove(route, result_table);
433 }
718e3744 434}
435
d62a17ae 436static const char *ospf6_spf_reason_str[] = {
437 "R+", "R-", "N+", "N-", "L+", "L-", "R*", "N*",
438};
439
440void ospf6_spf_reason_string(unsigned int reason, char *buf, int size)
a0edf674 441{
d62a17ae 442 unsigned int bit;
443 int len = 0;
444
445 if (!buf)
446 return;
447
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]);
453 }
a0edf674 454 }
a0edf674
DD
455}
456
6452df09 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 */
d7c0a89a 459void ospf6_spf_calculation(uint32_t router_id,
d62a17ae 460 struct ospf6_route_table *result_table,
461 struct ospf6_area *oa)
508e53e2 462{
d62a17ae 463 struct pqueue *candidate_list;
464 struct ospf6_vertex *root, *v, *w;
465 int size;
466 caddr_t lsdesc;
da086a3b 467 struct ospf6_lsa *lsa;
d62a17ae 468 struct in6_addr address;
469
470 ospf6_spf_table_finish(result_table);
471
472 /* Install the calculating router itself as the root of the SPF tree */
473 /* construct root vertex */
da086a3b 474 lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
d62a17ae 475 if (lsa == NULL) {
476 if (IS_OSPF6_DEBUG_SPF(PROCESS))
477 zlog_debug("%s: No router LSA for area %s\n", __func__,
478 oa->name);
479 return;
480 }
481
482 /* initialize */
483 candidate_list = pqueue_create();
484 candidate_list->cmp = ospf6_vertex_cmp;
485
486 root = ospf6_vertex_create(lsa);
487 root->area = oa;
488 root->cost = 0;
489 root->hops = 0;
26e14616 490 root->link_id = lsa->header->id;
d62a17ae 491 inet_pton(AF_INET6, "::1", &address);
492
493 /* Actually insert root to the candidate-list as the only candidate */
494 pqueue_enqueue(root, candidate_list);
495
496 /* Iterate until candidate-list becomes empty */
497 while (candidate_list->size) {
498 /* get closest candidate from priority queue */
499 v = pqueue_dequeue(candidate_list);
500
501 /* installing may result in merging or rejecting of the vertex
502 */
503 if (ospf6_spf_install(v, result_table) < 0)
504 continue;
505
506 /* Skip overloaded routers */
507 if ((OSPF6_LSA_IS_TYPE(ROUTER, v->lsa)
508 && ospf6_router_is_stub_router(v->lsa)))
509 continue;
510
da086a3b
CS
511 /* For each LS description in the just-added vertex V's LSA */
512 size = (VERTEX_IS_TYPE(ROUTER, v)
513 ? sizeof(struct ospf6_router_lsdesc)
514 : sizeof(struct ospf6_network_lsdesc));
515 for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
516 lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
517 lsdesc += size) {
518 lsa = ospf6_lsdesc_lsa(lsdesc, v);
519 if (lsa == NULL)
520 continue;
521
522 if (OSPF6_LSA_IS_MAXAGE(lsa))
523 continue;
524
525 if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
526 continue;
527
528 w = ospf6_vertex_create(lsa);
529 w->area = oa;
530 w->parent = v;
531 if (VERTEX_IS_TYPE(ROUTER, v)) {
532 w->cost = v->cost
26e14616 533 + ROUTER_LSDESC_GET_METRIC(lsdesc);
da086a3b
CS
534 w->hops =
535 v->hops
536 + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1);
537 } else {
538 /* NETWORK */
539 w->cost = v->cost;
540 w->hops = v->hops + 1;
541 }
542
543 /* nexthop calculation */
544 if (w->hops == 0)
545 ospf6_add_nexthop(
546 w->nh_list,
d62a17ae 547 ROUTER_LSDESC_GET_IFID(lsdesc), NULL);
da086a3b
CS
548 else if (w->hops == 1 && v->hops == 0)
549 ospf6_nexthop_calc(w, v, lsdesc);
550 else
551 ospf6_copy_nexthops(w->nh_list, v->nh_list);
552
553
554 /* add new candidate to the candidate_list */
555 if (IS_OSPF6_DEBUG_SPF(PROCESS))
556 zlog_debug(
d62a17ae 557 " New candidate: %s hops %d cost %d",
996c9314 558 w->name, w->hops, w->cost);
da086a3b 559 pqueue_enqueue(w, candidate_list);
d62a17ae 560 }
561 }
562
da086a3b 563
d62a17ae 564 pqueue_delete(candidate_list);
565
da086a3b
CS
566 ospf6_remove_temp_router_lsa(oa);
567
d62a17ae 568 oa->spf_calculation++;
718e3744 569}
570
d62a17ae 571static void ospf6_spf_log_database(struct ospf6_area *oa)
2680aa2b 572{
d62a17ae 573 char *p, *end, buffer[256];
574 struct listnode *node;
575 struct ospf6_interface *oi;
576
577 p = buffer;
578 end = buffer + sizeof(buffer);
579
580 snprintf(p, end - p, "SPF on DB (#LSAs):");
581 p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer) : end);
582 snprintf(p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
583 p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer) : end);
584
585 for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
586 snprintf(p, end - p, " I/F %s: %d", oi->interface->name,
587 oi->lsdb->count);
588 p = (buffer + strlen(buffer) < end ? buffer + strlen(buffer)
589 : end);
590 }
591
592 zlog_debug("%s", buffer);
2680aa2b 593}
594
d62a17ae 595static int ospf6_spf_calculation_thread(struct thread *t)
718e3744 596{
d62a17ae 597 struct ospf6_area *oa;
598 struct ospf6 *ospf6;
599 struct timeval start, end, runtime;
600 struct listnode *node;
601 int areas_processed = 0;
602 char rbuf[32];
603
604 ospf6 = (struct ospf6 *)THREAD_ARG(t);
605 ospf6->t_spf_calc = NULL;
606
607 /* execute SPF calculation */
608 monotime(&start);
ab0f1135 609 ospf6->ts_spf = start;
d62a17ae 610
611 if (ospf6_is_router_abr(ospf6))
612 ospf6_abr_range_reset_cost(ospf6);
613
614 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
615
616 if (oa == ospf6->backbone)
617 continue;
618
ab0f1135 619 monotime(&oa->ts_spf);
d62a17ae 620 if (IS_OSPF6_DEBUG_SPF(PROCESS))
621 zlog_debug("SPF calculation for Area %s", oa->name);
622 if (IS_OSPF6_DEBUG_SPF(DATABASE))
623 ospf6_spf_log_database(oa);
624
625 ospf6_spf_calculation(ospf6->router_id, oa->spf_table, oa);
626 ospf6_intra_route_calculation(oa);
627 ospf6_intra_brouter_calculation(oa);
628
629 areas_processed++;
630 }
631
632 if (ospf6->backbone) {
ab0f1135 633 monotime(&ospf6->backbone->ts_spf);
d62a17ae 634 if (IS_OSPF6_DEBUG_SPF(PROCESS))
635 zlog_debug("SPF calculation for Backbone area %s",
636 ospf6->backbone->name);
637 if (IS_OSPF6_DEBUG_SPF(DATABASE))
638 ospf6_spf_log_database(ospf6->backbone);
639
640 ospf6_spf_calculation(ospf6->router_id,
641 ospf6->backbone->spf_table,
642 ospf6->backbone);
643 ospf6_intra_route_calculation(ospf6->backbone);
644 ospf6_intra_brouter_calculation(ospf6->backbone);
645 areas_processed++;
646 }
647
648 if (ospf6_is_router_abr(ospf6))
649 ospf6_abr_defaults_to_stub(ospf6);
650
651 monotime(&end);
652 timersub(&end, &start, &runtime);
653
654 ospf6->ts_spf_duration = runtime;
655
656 ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
657
658 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
659 zlog_debug("SPF runtime: %lld sec %lld usec",
660 (long long)runtime.tv_sec,
661 (long long)runtime.tv_usec);
662
663 zlog_info(
664 "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
665 "Reason: %s\n",
666 areas_processed, (long long)runtime.tv_sec,
667 (long long)runtime.tv_usec, rbuf);
ab0f1135 668
d62a17ae 669 ospf6->last_spf_reason = ospf6->spf_reason;
670 ospf6_reset_spf_reason(ospf6);
671 return 0;
718e3744 672}
673
3810e06e
DD
674/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
675 set timer for SPF calc. */
d62a17ae 676void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
718e3744 677{
d62a17ae 678 unsigned long delay, elapsed, ht;
679
cac84a16 680 /* OSPF instance does not exist. */
681 if (ospf6 == NULL)
682 return;
683
d62a17ae 684 ospf6_set_spf_reason(ospf6, reason);
685
686 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) {
687 char rbuf[32];
688 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
689 zlog_debug("SPF: calculation timer scheduled (reason %s)",
690 rbuf);
691 }
692
d62a17ae 693 /* SPF calculation timer is already scheduled. */
694 if (ospf6->t_spf_calc) {
695 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
696 zlog_debug(
697 "SPF: calculation timer is already scheduled: %p",
698 (void *)ospf6->t_spf_calc);
699 return;
700 }
701
702 elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
703 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
704
705 if (ht > ospf6->spf_max_holdtime)
706 ht = ospf6->spf_max_holdtime;
707
708 /* Get SPF calculation delay time. */
709 if (elapsed < ht) {
710 /* Got an event within the hold time of last SPF. We need to
711 * increase the hold_multiplier, if it's not already at/past
712 * maximum value, and wasn't already increased..
713 */
714 if (ht < ospf6->spf_max_holdtime)
715 ospf6->spf_hold_multiplier++;
716
717 /* always honour the SPF initial delay */
718 if ((ht - elapsed) < ospf6->spf_delay)
719 delay = ospf6->spf_delay;
720 else
721 delay = ht - elapsed;
722 } else {
723 /* Event is past required hold-time of last SPF */
724 delay = ospf6->spf_delay;
725 ospf6->spf_hold_multiplier = 1;
726 }
727
728 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
729 zlog_debug("SPF: calculation timer delay = %ld", delay);
730
731 zlog_info("SPF: Scheduled in %ld msec", delay);
732
733 ospf6->t_spf_calc = NULL;
734 thread_add_timer_msec(master, ospf6_spf_calculation_thread, ospf6,
735 delay, &ospf6->t_spf_calc);
718e3744 736}
737
d62a17ae 738void ospf6_spf_display_subtree(struct vty *vty, const char *prefix, int rest,
739 struct ospf6_vertex *v)
718e3744 740{
d62a17ae 741 struct listnode *node, *nnode;
742 struct ospf6_vertex *c;
743 char *next_prefix;
744 int len;
745 int restnum;
746
747 /* "prefix" is the space prefix of the display line */
748 vty_out(vty, "%s+-%s [%d]\n", prefix, v->name, v->cost);
749
750 len = strlen(prefix) + 4;
751 next_prefix = (char *)malloc(len);
752 if (next_prefix == NULL) {
753 vty_out(vty, "malloc failed\n");
754 return;
755 }
756 snprintf(next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
757
758 restnum = listcount(v->child_list);
759 for (ALL_LIST_ELEMENTS(v->child_list, node, nnode, c)) {
760 restnum--;
761 ospf6_spf_display_subtree(vty, next_prefix, restnum, c);
762 }
763
764 free(next_prefix);
718e3744 765}
766
3b68735f 767DEFUN (debug_ospf6_spf_process,
768 debug_ospf6_spf_process_cmd,
769 "debug ospf6 spf process",
508e53e2 770 DEBUG_STR
771 OSPF6_STR
772 "Debug SPF Calculation\n"
3b68735f 773 "Debug Detailed SPF Process\n"
508e53e2 774 )
718e3744 775{
d62a17ae 776 unsigned char level = 0;
777 level = OSPF6_DEBUG_SPF_PROCESS;
778 OSPF6_DEBUG_SPF_ON(level);
779 return CMD_SUCCESS;
718e3744 780}
781
3b68735f 782DEFUN (debug_ospf6_spf_time,
783 debug_ospf6_spf_time_cmd,
784 "debug ospf6 spf time",
508e53e2 785 DEBUG_STR
718e3744 786 OSPF6_STR
508e53e2 787 "Debug SPF Calculation\n"
3b68735f 788 "Measure time taken by SPF Calculation\n"
508e53e2 789 )
718e3744 790{
d62a17ae 791 unsigned char level = 0;
792 level = OSPF6_DEBUG_SPF_TIME;
793 OSPF6_DEBUG_SPF_ON(level);
794 return CMD_SUCCESS;
718e3744 795}
796
2680aa2b 797DEFUN (debug_ospf6_spf_database,
798 debug_ospf6_spf_database_cmd,
799 "debug ospf6 spf database",
800 DEBUG_STR
801 OSPF6_STR
802 "Debug SPF Calculation\n"
803 "Log number of LSAs at SPF Calculation time\n"
804 )
805{
d62a17ae 806 unsigned char level = 0;
807 level = OSPF6_DEBUG_SPF_DATABASE;
808 OSPF6_DEBUG_SPF_ON(level);
809 return CMD_SUCCESS;
2680aa2b 810}
811
3b68735f 812DEFUN (no_debug_ospf6_spf_process,
813 no_debug_ospf6_spf_process_cmd,
814 "no debug ospf6 spf process",
508e53e2 815 NO_STR
816 DEBUG_STR
817 OSPF6_STR
818 "Quit Debugging SPF Calculation\n"
3b68735f 819 "Quit Debugging Detailed SPF Process\n"
508e53e2 820 )
718e3744 821{
d62a17ae 822 unsigned char level = 0;
823 level = OSPF6_DEBUG_SPF_PROCESS;
824 OSPF6_DEBUG_SPF_OFF(level);
825 return CMD_SUCCESS;
718e3744 826}
827
3b68735f 828DEFUN (no_debug_ospf6_spf_time,
829 no_debug_ospf6_spf_time_cmd,
830 "no debug ospf6 spf time",
508e53e2 831 NO_STR
832 DEBUG_STR
718e3744 833 OSPF6_STR
508e53e2 834 "Quit Debugging SPF Calculation\n"
3b68735f 835 "Quit Measuring time taken by SPF Calculation\n"
508e53e2 836 )
718e3744 837{
d62a17ae 838 unsigned char level = 0;
839 level = OSPF6_DEBUG_SPF_TIME;
840 OSPF6_DEBUG_SPF_OFF(level);
841 return CMD_SUCCESS;
718e3744 842}
843
2680aa2b 844DEFUN (no_debug_ospf6_spf_database,
845 no_debug_ospf6_spf_database_cmd,
846 "no debug ospf6 spf database",
847 NO_STR
848 DEBUG_STR
849 OSPF6_STR
850 "Debug SPF Calculation\n"
851 "Quit Logging number of LSAs at SPF Calculation time\n"
852 )
853{
d62a17ae 854 unsigned char level = 0;
855 level = OSPF6_DEBUG_SPF_DATABASE;
856 OSPF6_DEBUG_SPF_OFF(level);
857 return CMD_SUCCESS;
2680aa2b 858}
859
d62a17ae 860static int ospf6_timers_spf_set(struct vty *vty, unsigned int delay,
861 unsigned int hold, unsigned int max)
3810e06e 862{
d62a17ae 863 VTY_DECLVAR_CONTEXT(ospf6, ospf);
3810e06e 864
d62a17ae 865 ospf->spf_delay = delay;
866 ospf->spf_holdtime = hold;
867 ospf->spf_max_holdtime = max;
3810e06e 868
d62a17ae 869 return CMD_SUCCESS;
3810e06e
DD
870}
871
872DEFUN (ospf6_timers_throttle_spf,
873 ospf6_timers_throttle_spf_cmd,
6147e2c6 874 "timers throttle spf (0-600000) (0-600000) (0-600000)",
3810e06e
DD
875 "Adjust routing timers\n"
876 "Throttling adaptive timer\n"
877 "OSPF6 SPF timers\n"
878 "Delay (msec) from first change received till SPF calculation\n"
879 "Initial hold time (msec) between consecutive SPF calculations\n"
880 "Maximum hold time (msec)\n")
881{
d62a17ae 882 int idx_number = 3;
883 int idx_number_2 = 4;
884 int idx_number_3 = 5;
885 unsigned int delay, hold, max;
3810e06e 886
d62a17ae 887 delay = strtoul(argv[idx_number]->arg, NULL, 10);
888 hold = strtoul(argv[idx_number_2]->arg, NULL, 10);
889 max = strtoul(argv[idx_number_3]->arg, NULL, 10);
3810e06e 890
d62a17ae 891 return ospf6_timers_spf_set(vty, delay, hold, max);
3810e06e
DD
892}
893
894DEFUN (no_ospf6_timers_throttle_spf,
895 no_ospf6_timers_throttle_spf_cmd,
1d68dbfe 896 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
3810e06e
DD
897 NO_STR
898 "Adjust routing timers\n"
899 "Throttling adaptive timer\n"
1d68dbfe
DW
900 "OSPF6 SPF timers\n"
901 "Delay (msec) from first change received till SPF calculation\n"
902 "Initial hold time (msec) between consecutive SPF calculations\n"
903 "Maximum hold time (msec)\n")
3810e06e 904{
d62a17ae 905 return ospf6_timers_spf_set(vty, OSPF_SPF_DELAY_DEFAULT,
906 OSPF_SPF_HOLDTIME_DEFAULT,
907 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
3810e06e
DD
908}
909
813d4307 910
d62a17ae 911int config_write_ospf6_debug_spf(struct vty *vty)
718e3744 912{
d62a17ae 913 if (IS_OSPF6_DEBUG_SPF(PROCESS))
914 vty_out(vty, "debug ospf6 spf process\n");
915 if (IS_OSPF6_DEBUG_SPF(TIME))
916 vty_out(vty, "debug ospf6 spf time\n");
917 if (IS_OSPF6_DEBUG_SPF(DATABASE))
918 vty_out(vty, "debug ospf6 spf database\n");
919 return 0;
718e3744 920}
921
d62a17ae 922void ospf6_spf_config_write(struct vty *vty)
3810e06e
DD
923{
924
d62a17ae 925 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT
926 || ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT
927 || ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
928 vty_out(vty, " timers throttle spf %d %d %d\n",
929 ospf6->spf_delay, ospf6->spf_holdtime,
930 ospf6->spf_max_holdtime);
3810e06e
DD
931}
932
d62a17ae 933void install_element_ospf6_debug_spf(void)
508e53e2 934{
d62a17ae 935 install_element(ENABLE_NODE, &debug_ospf6_spf_process_cmd);
936 install_element(ENABLE_NODE, &debug_ospf6_spf_time_cmd);
937 install_element(ENABLE_NODE, &debug_ospf6_spf_database_cmd);
938 install_element(ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
939 install_element(ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
940 install_element(ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
941 install_element(CONFIG_NODE, &debug_ospf6_spf_process_cmd);
942 install_element(CONFIG_NODE, &debug_ospf6_spf_time_cmd);
943 install_element(CONFIG_NODE, &debug_ospf6_spf_database_cmd);
944 install_element(CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
945 install_element(CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
946 install_element(CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
508e53e2 947}
718e3744 948
d62a17ae 949void ospf6_spf_init(void)
718e3744 950{
d62a17ae 951 install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
952 install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
718e3744 953}
da086a3b
CS
954
955/* Create Aggregated Large Router-LSA from multiple Link-State IDs
956 * RFC 5340 A 4.3:
957 * When more than one router-LSA is received from a single router,
958 * the links are processed as if concatenated into a single LSA.*/
959struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
960 struct ospf6_lsdb *lsdb,
961 uint32_t adv_router)
962{
963 struct ospf6_lsa *lsa = NULL;
964 struct ospf6_lsa *rtr_lsa = NULL;
965 struct ospf6_lsa_header *lsa_header = NULL;
966 uint8_t *new_header = NULL;
967 const struct route_node *end = NULL;
968 uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0;
d7c0a89a 969 uint16_t type = 0;
da086a3b
CS
970 char ifbuf[16];
971 uint32_t interface_id;
972 caddr_t lsd;
973
996c9314
LB
974 lsa_length = sizeof(struct ospf6_lsa_header)
975 + sizeof(struct ospf6_router_lsa);
da086a3b
CS
976 total_lsa_length = lsa_length;
977 type = htons(OSPF6_LSTYPE_ROUTER);
978
979 /* First check Aggregated LSA formed earlier in Cache */
980 lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router,
981 area->temp_router_lsa_lsdb);
982 if (lsa)
983 return lsa;
984
985 inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf));
986
987 /* Determine total LSA length from all link state ids */
988 end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
989 while (rtr_lsa) {
990 lsa = rtr_lsa;
991 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
992 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
993 continue;
994 }
996c9314
LB
995 lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header;
996 total_lsa_length += (ntohs(lsa_header->length) - lsa_length);
da086a3b
CS
997 num_lsa++;
998 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
999 }
1000 if (IS_OSPF6_DEBUG_SPF(PROCESS))
1001 zlog_debug("%s: adv_router %s num_lsa %u to convert.",
996c9314 1002 __PRETTY_FUNCTION__, ifbuf, num_lsa);
da086a3b
CS
1003 if (num_lsa == 1)
1004 return lsa;
1005
1006 if (num_lsa == 0) {
1007 if (IS_OSPF6_DEBUG_SPF(PROCESS))
1008 zlog_debug("%s: adv_router %s not found in LSDB.",
1009 __PRETTY_FUNCTION__, ifbuf);
1010 return NULL;
1011 }
1012
1013 /* Allocate memory for this LSA */
1014 new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
1015 if (!new_header)
1016 return NULL;
1017
1018 /* LSA information structure */
1019 lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
1020 sizeof(struct ospf6_lsa));
1021 if (!lsa) {
1022 free(new_header);
1023 return NULL;
1024 }
1025
1026 lsa->header = (struct ospf6_lsa_header *)new_header;
1027
1028 lsa->lsdb = area->temp_router_lsa_lsdb;
1029
1030 /* Fill Larger LSA Payload */
1031 end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
cf29dab3
DS
1032
1033 /*
1034 * We assume at this point in time that rtr_lsa is
1035 * a valid pointer.
1036 */
1037 assert(rtr_lsa);
1038 if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
1039 /* Append first Link State ID LSA */
1040 lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header;
1041 memcpy(new_header, lsa_header, ntohs(lsa_header->length));
1042 /* Assign new lsa length as aggregated length. */
1043 ((struct ospf6_lsa_header *)new_header)->length =
1044 htons(total_lsa_length);
1045 new_header += ntohs(lsa_header->length);
1046 num_lsa--;
da086a3b
CS
1047 }
1048
1049 /* Print LSA Name */
1050 ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
1051
1052 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
1053 while (rtr_lsa) {
1054 if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
1055 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
1056 continue;
1057 }
1058
1059 if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
1060 lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4;
1061 interface_id = ROUTER_LSDESC_GET_IFID(lsd);
1062 inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf));
996c9314
LB
1063 zlog_debug(
1064 "%s: Next Router LSA %s to aggreat with len %u interface_id %s",
1065 __PRETTY_FUNCTION__, rtr_lsa->name,
1066 ntohs(lsa_header->length), ifbuf);
da086a3b
CS
1067 }
1068
1069 /* Append Next Link State ID LSA */
996c9314 1070 lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header;
da086a3b
CS
1071 memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4),
1072 (ntohs(lsa_header->length) - lsa_length));
1073 new_header += (ntohs(lsa_header->length) - lsa_length);
1074 num_lsa--;
1075
1076 rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
1077 }
1078
1079 /* Calculate birth of this lsa */
1080 ospf6_lsa_age_set(lsa);
1081
1082 /* Store Aggregated LSA into area temp lsdb */
1083 ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb);
1084
1085 if (IS_OSPF6_DEBUG_SPF(PROCESS))
1086 zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
1087 __PRETTY_FUNCTION__, lsa->name,
1088 ntohl(lsa->header->id), ntohs(lsa->header->type),
1089 ntohs(lsa->header->length), num_lsa);
1090
1091 return lsa;
1092}
1093
1094void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
1095{
1096 struct ospf6_lsa *lsa = NULL;
1097
1098 for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) {
1099 if (IS_OSPF6_DEBUG_SPF(PROCESS))
996c9314
LB
1100 zlog_debug(
1101 "%s Remove LSA %s lsa->lock %u lsdb count %u",
1102 __PRETTY_FUNCTION__, lsa->name, lsa->lock,
1103 area->temp_router_lsa_lsdb->count);
da086a3b
CS
1104 ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
1105 }
1106}