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