]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_spf.c
Should be able to "no" the full text of any config line
[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 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
508e53e2 21
718e3744 22/* Shortest Path First calculation for OSPFv3 */
23
508e53e2 24#include <zebra.h>
718e3744 25
508e53e2 26#include "log.h"
27#include "memory.h"
28#include "command.h"
29#include "vty.h"
718e3744 30#include "prefix.h"
508e53e2 31#include "pqueue.h"
32#include "linklist.h"
33#include "thread.h"
718e3744 34
718e3744 35#include "ospf6_lsa.h"
36#include "ospf6_lsdb.h"
37#include "ospf6_route.h"
508e53e2 38#include "ospf6_area.h"
ca1f4309
DS
39#include "ospf6_proto.h"
40#include "ospf6_abr.h"
718e3744 41#include "ospf6_spf.h"
508e53e2 42#include "ospf6_intra.h"
718e3744 43#include "ospf6_interface.h"
049207c3 44#include "ospf6d.h"
718e3744 45
508e53e2 46unsigned char conf_debug_ospf6_spf = 0;
718e3744 47
c3c0ac83
DS
48static void
49ospf6_spf_copy_nexthops_to_route (struct ospf6_route *rt,
50 struct ospf6_vertex *v)
51{
52 if (rt && v)
53 ospf6_copy_nexthops (rt->nh_list, v->nh_list);
54}
55
56static void
57ospf6_spf_merge_nexthops_to_route (struct ospf6_route *rt,
58 struct ospf6_vertex *v)
59{
60 if (rt && v)
61 ospf6_merge_nexthops (rt->nh_list, v->nh_list);
62}
63
ed2eb093 64static unsigned int
c3c0ac83
DS
65ospf6_spf_get_ifindex_from_nh (struct ospf6_vertex *v)
66{
67 struct ospf6_nexthop *nh;
68 struct listnode *node;
69
70 if (v)
71 {
72 node = listhead(v->nh_list);
73 if (node)
74 {
75 nh = listgetdata (node);
76 if (nh)
77 return (nh->ifindex);
78 }
79 }
ed2eb093 80 return 0;
c3c0ac83
DS
81}
82
6ac29a51 83static int
508e53e2 84ospf6_vertex_cmp (void *a, void *b)
718e3744 85{
508e53e2 86 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
87 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
718e3744 88
508e53e2 89 /* ascending order */
403138e1
DT
90 if (va->cost != vb->cost)
91 return (va->cost - vb->cost);
92 return (va->hops - vb->hops);
718e3744 93}
94
6ac29a51 95static int
508e53e2 96ospf6_vertex_id_cmp (void *a, void *b)
718e3744 97{
508e53e2 98 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
99 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
100 int ret = 0;
718e3744 101
508e53e2 102 ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
103 ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
104 if (ret)
105 return ret;
718e3744 106
508e53e2 107 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
108 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
718e3744 109 return ret;
110}
111
6ac29a51 112static struct ospf6_vertex *
508e53e2 113ospf6_vertex_create (struct ospf6_lsa *lsa)
718e3744 114{
508e53e2 115 struct ospf6_vertex *v;
718e3744 116
508e53e2 117 v = (struct ospf6_vertex *)
118 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
718e3744 119
508e53e2 120 /* type */
121 if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
122 v->type = OSPF6_VERTEX_TYPE_ROUTER;
123 else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
124 v->type = OSPF6_VERTEX_TYPE_NETWORK;
718e3744 125 else
508e53e2 126 assert (0);
718e3744 127
508e53e2 128 /* vertex_id */
129 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
130 &v->vertex_id);
718e3744 131
508e53e2 132 /* name */
133 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
718e3744 134
c3c0ac83
DS
135 if (IS_OSPF6_DEBUG_SPF (PROCESS))
136 zlog_debug ("%s: Creating vertex %s of type %s", __func__, v->name,
137 ((ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" : "N/W"));
138
508e53e2 139 /* Associated LSA */
140 v->lsa = lsa;
718e3744 141
508e53e2 142 /* capability bits + options */
143 v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
144 v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
145 v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
146 v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
718e3744 147
c3c0ac83 148 v->nh_list = list_new();
718e3744 149
508e53e2 150 v->parent = NULL;
151 v->child_list = list_new ();
152 v->child_list->cmp = ospf6_vertex_id_cmp;
718e3744 153
508e53e2 154 return v;
718e3744 155}
156
6ac29a51 157static void
508e53e2 158ospf6_vertex_delete (struct ospf6_vertex *v)
718e3744 159{
508e53e2 160 list_delete (v->child_list);
161 XFREE (MTYPE_OSPF6_VERTEX, v);
718e3744 162}
163
6ac29a51 164static struct ospf6_lsa *
508e53e2 165ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
718e3744 166{
508e53e2 167 struct ospf6_lsa *lsa;
168 u_int16_t type = 0;
169 u_int32_t id = 0, adv_router = 0;
718e3744 170
508e53e2 171 if (VERTEX_IS_TYPE (NETWORK, v))
718e3744 172 {
508e53e2 173 type = htons (OSPF6_LSTYPE_ROUTER);
174 id = htonl (0);
175 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
718e3744 176 }
177 else
178 {
508e53e2 179 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
718e3744 180 {
508e53e2 181 type = htons (OSPF6_LSTYPE_ROUTER);
718e3744 182 id = htonl (0);
508e53e2 183 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
718e3744 184 }
508e53e2 185 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
718e3744 186 {
508e53e2 187 type = htons (OSPF6_LSTYPE_NETWORK);
188 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
189 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
718e3744 190 }
718e3744 191 }
192
508e53e2 193 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
718e3744 194
3b68735f 195 if (IS_OSPF6_DEBUG_SPF (PROCESS))
718e3744 196 {
508e53e2 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)
c6487d61 201 zlog_debug (" Link to: %s", lsa->name);
508e53e2 202 else
c6487d61 203 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
204 ospf6_lstype_name (type), ibuf, abuf);
718e3744 205 }
206
508e53e2 207 return lsa;
718e3744 208}
209
6ac29a51 210static char *
508e53e2 211ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
212 caddr_t lsdesc, struct ospf6_vertex *v)
718e3744 213{
508e53e2 214 caddr_t backlink, found = NULL;
215 int size;
718e3744 216
508e53e2 217 size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
218 sizeof (struct ospf6_router_lsdesc) :
219 sizeof (struct ospf6_network_lsdesc));
220 for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
221 backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
718e3744 222 {
508e53e2 223 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
224 VERTEX_IS_TYPE (NETWORK, v)));
718e3744 225
508e53e2 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 {
239 if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
240 ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
241 continue;
242 if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
243 ROUTER_LSDESC_GET_IFID (lsdesc) ||
244 ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
245 ROUTER_LSDESC_GET_IFID (backlink))
246 continue;
247 if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
248 v->lsa->header->adv_router ||
249 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
250 lsa->header->adv_router)
251 continue;
252 found = backlink;
253 }
718e3744 254 }
718e3744 255
3b68735f 256 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 257 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
718e3744 258
508e53e2 259 return found;
718e3744 260}
261
6ac29a51 262static void
508e53e2 263ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
264 caddr_t lsdesc)
718e3744 265{
c3c0ac83 266 int i;
ed2eb093 267 unsigned int ifindex;
508e53e2 268 struct ospf6_interface *oi;
269 u_int16_t type;
270 u_int32_t adv_router;
271 struct ospf6_lsa *lsa;
272 struct ospf6_link_lsa *link_lsa;
273 char buf[64];
718e3744 274
508e53e2 275 assert (VERTEX_IS_TYPE (ROUTER, w));
c3c0ac83 276 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) :
508e53e2 277 ROUTER_LSDESC_GET_IFID (lsdesc));
ed2eb093 278 if (ifindex == 0)
c3c0ac83
DS
279 {
280 zlog_err ("No nexthop ifindex at vertex %s", v->name);
281 return;
282 }
283
508e53e2 284 oi = ospf6_interface_lookup_by_ifindex (ifindex);
285 if (oi == NULL)
718e3744 286 {
3b68735f 287 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 288 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
508e53e2 289 return;
718e3744 290 }
291
508e53e2 292 type = htons (OSPF6_LSTYPE_LINK);
293 adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
294 NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
295 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
718e3744 296
508e53e2 297 i = 0;
298 for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
299 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
718e3744 300 {
508e53e2 301 if (VERTEX_IS_TYPE (ROUTER, v) &&
302 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
718e3744 303 continue;
304
508e53e2 305 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
3b68735f 306 if (IS_OSPF6_DEBUG_SPF (PROCESS))
508e53e2 307 {
308 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
c6487d61 309 zlog_debug (" nexthop %s from %s", buf, lsa->name);
508e53e2 310 }
718e3744 311
c3c0ac83
DS
312 ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr);
313 i++;
718e3744 314 }
315
3b68735f 316 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 317 zlog_debug ("No nexthop for %s found", w->name);
718e3744 318}
319
6ac29a51 320static int
508e53e2 321ospf6_spf_install (struct ospf6_vertex *v,
322 struct ospf6_route_table *result_table)
718e3744 323{
c3c0ac83 324 struct ospf6_route *route, *parent_route;
87362ceb 325 struct ospf6_vertex *prev;
718e3744 326
3b68735f 327 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 328 zlog_debug ("SPF install %s hops %d cost %d",
329 v->name, v->hops, v->cost);
718e3744 330
508e53e2 331 route = ospf6_route_lookup (&v->vertex_id, result_table);
332 if (route && route->path.cost < v->cost)
718e3744 333 {
3b68735f 334 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 335 zlog_debug (" already installed with lower cost (%d), ignore",
336 route->path.cost);
508e53e2 337 ospf6_vertex_delete (v);
338 return -1;
718e3744 339 }
508e53e2 340 else if (route && route->path.cost == v->cost)
718e3744 341 {
3b68735f 342 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 343 zlog_debug (" another path found, merge");
718e3744 344
c3c0ac83 345 ospf6_spf_merge_nexthops_to_route (route, v);
718e3744 346
508e53e2 347 prev = (struct ospf6_vertex *) route->route_option;
403138e1
DT
348 assert (prev->hops <= v->hops);
349 ospf6_vertex_delete (v);
718e3744 350
508e53e2 351 return -1;
718e3744 352 }
508e53e2 353
354 /* There should be no case where candidate being installed (variable
355 "v") is closer than the one in the SPF tree (variable "route").
6452df09 356 In the case something has gone wrong with the behavior of
508e53e2 357 Priority-Queue. */
6452df09 358
359 /* the case where the route exists already is handled and returned
360 up to here. */
508e53e2 361 assert (route == NULL);
362
363 route = ospf6_route_create ();
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;
c3c0ac83 372 route->path.u.cost_e2 = v->hops;
508e53e2 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];
377
c3c0ac83
DS
378 ospf6_spf_copy_nexthops_to_route (route, v);
379
380 /*
381 * The SPF logic implementation does not transfer the multipathing properties
382 * of a parent to a child node. Thus if there was a 3-way multipath to a
383 * node's parent and a single hop from the parent to the child, the logic of
384 * creating new vertices and computing next hops prevents there from being 3
385 * paths to the child node. This is primarily because the resolution of
386 * multipath is done in this routine, not in the main spf loop.
387 *
388 * The following logic addresses that problem by merging the parent's nexthop
389 * information with the child's, if the parent is not the root of the tree.
390 * This is based on the assumption that before a node's route is installed,
391 * its parent's route's nexthops have already been installed.
392 */
393 if (v->parent && v->parent->hops)
394 {
395 parent_route = ospf6_route_lookup (&v->parent->vertex_id, result_table);
396 if (parent_route)
397 {
398 ospf6_route_merge_nexthops (route, parent_route);
399 }
400 }
508e53e2 401
402 if (v->parent)
403 listnode_add_sort (v->parent->child_list, v);
404 route->route_option = v;
405
406 ospf6_route_add (route, result_table);
407 return 0;
718e3744 408}
409
508e53e2 410void
411ospf6_spf_table_finish (struct ospf6_route_table *result_table)
718e3744 412{
0f23bb67 413 struct ospf6_route *route, *nroute;
718e3744 414 struct ospf6_vertex *v;
508e53e2 415 for (route = ospf6_route_head (result_table); route;
0f23bb67 416 route = nroute)
718e3744 417 {
0f23bb67 418 nroute = ospf6_route_next (route);
508e53e2 419 v = (struct ospf6_vertex *) route->route_option;
420 ospf6_vertex_delete (v);
421 ospf6_route_remove (route, result_table);
718e3744 422 }
718e3744 423}
424
a0edf674
DD
425static const char *ospf6_spf_reason_str[] =
426 {
427 "R+",
428 "R-",
429 "N+",
430 "N-",
431 "L+",
432 "L-",
433 "R*",
434 "N*",
435 };
436
437void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
438{
ed2eb093 439 unsigned int bit;
a0edf674
DD
440 int len = 0;
441
442 if (!buf)
443 return;
444
445 for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++)
446 {
447 if ((reason & (1 << bit)) && (len < size))
448 {
449 len += snprintf((buf + len), (size - len), "%s%s",
450 (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]);
451 }
452 }
453}
454
6452df09 455/* RFC2328 16.1. Calculating the shortest-path tree for an area */
456/* RFC2740 3.8.1. Calculating the shortest path tree for an area */
508e53e2 457void
458ospf6_spf_calculation (u_int32_t router_id,
459 struct ospf6_route_table *result_table,
460 struct ospf6_area *oa)
461{
462 struct pqueue *candidate_list;
463 struct ospf6_vertex *root, *v, *w;
508e53e2 464 int size;
465 caddr_t lsdesc;
466 struct ospf6_lsa *lsa;
c3c0ac83 467 struct in6_addr address;
718e3744 468
b48cebbb
TG
469 ospf6_spf_table_finish (result_table);
470
508e53e2 471 /* Install the calculating router itself as the root of the SPF tree */
472 /* construct root vertex */
473 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
c3c0ac83 474 router_id, oa->lsdb_self);
508e53e2 475 if (lsa == NULL)
c3c0ac83
DS
476 {
477 if (IS_OSPF6_DEBUG_SPF (PROCESS))
478 zlog_debug ("%s: No router LSA for area %s\n",
479 __func__, oa->name);
480 return;
481 }
1d19234e
TG
482
483 /* initialize */
484 candidate_list = pqueue_create ();
485 candidate_list->cmp = ospf6_vertex_cmp;
486
508e53e2 487 root = ospf6_vertex_create (lsa);
488 root->area = oa;
489 root->cost = 0;
490 root->hops = 0;
c3c0ac83 491 inet_pton (AF_INET6, "::1", &address);
718e3744 492
508e53e2 493 /* Actually insert root to the candidate-list as the only candidate */
494 pqueue_enqueue (root, candidate_list);
718e3744 495
508e53e2 496 /* Iterate until candidate-list becomes empty */
497 while (candidate_list->size)
718e3744 498 {
508e53e2 499 /* get closest candidate from priority queue */
500 v = pqueue_dequeue (candidate_list);
718e3744 501
6452df09 502 /* installing may result in merging or rejecting of the vertex */
508e53e2 503 if (ospf6_spf_install (v, result_table) < 0)
504 continue;
718e3744 505
f41b4a02
DD
506 /* Skip overloaded routers */
507 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
508 ospf6_router_is_stub_router (v->lsa)))
509 continue;
510
508e53e2 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); lsdesc += size)
718e3744 517 {
508e53e2 518 lsa = ospf6_lsdesc_lsa (lsdesc, v);
519 if (lsa == NULL)
718e3744 520 continue;
521
c3c0ac83
DS
522 if (OSPF6_LSA_IS_MAXAGE (lsa))
523 continue;
524
508e53e2 525 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
526 continue;
718e3744 527
508e53e2 528 w = ospf6_vertex_create (lsa);
529 w->area = oa;
530 w->parent = v;
531 if (VERTEX_IS_TYPE (ROUTER, v))
718e3744 532 {
508e53e2 533 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
534 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
718e3744 535 }
508e53e2 536 else /* NETWORK */
718e3744 537 {
508e53e2 538 w->cost = v->cost;
539 w->hops = v->hops + 1;
718e3744 540 }
541
508e53e2 542 /* nexthop calculation */
543 if (w->hops == 0)
c3c0ac83 544 ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
508e53e2 545 else if (w->hops == 1 && v->hops == 0)
546 ospf6_nexthop_calc (w, v, lsdesc);
718e3744 547 else
548 {
c3c0ac83 549 ospf6_copy_nexthops (w->nh_list, v->nh_list);
718e3744 550 }
551
508e53e2 552 /* add new candidate to the candidate_list */
3b68735f 553 if (IS_OSPF6_DEBUG_SPF (PROCESS))
c6487d61 554 zlog_debug (" New candidate: %s hops %d cost %d",
555 w->name, w->hops, w->cost);
508e53e2 556 pqueue_enqueue (w, candidate_list);
718e3744 557 }
558 }
559
508e53e2 560 pqueue_delete (candidate_list);
ea86e404
VB
561
562 oa->spf_calculation++;
718e3744 563}
564
6ac29a51 565static void
2680aa2b 566ospf6_spf_log_database (struct ospf6_area *oa)
567{
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
1eb8ef25 580 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
2680aa2b 581 {
2680aa2b 582 snprintf (p, end - p, " I/F %s: %d",
583 oi->interface->name, oi->lsdb->count);
584 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
585 }
586
c6487d61 587 zlog_debug ("%s", buffer);
2680aa2b 588}
589
6ac29a51 590static int
718e3744 591ospf6_spf_calculation_thread (struct thread *t)
592{
508e53e2 593 struct ospf6_area *oa;
3810e06e 594 struct ospf6 *ospf6;
508e53e2 595 struct timeval start, end, runtime;
3810e06e 596 struct listnode *node;
a0edf674
DD
597 int areas_processed = 0;
598 char rbuf[32];
718e3744 599
3810e06e
DD
600 ospf6 = (struct ospf6 *)THREAD_ARG (t);
601 ospf6->t_spf_calc = NULL;
718e3744 602
603 /* execute SPF calculation */
86f72dcb 604 quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
3810e06e 605
ca1f4309
DS
606 if (ospf6_is_router_abr (ospf6))
607 ospf6_abr_range_reset_cost (ospf6);
608
3810e06e
DD
609 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
610 {
611
612 if (oa == ospf6->backbone)
613 continue;
614
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);
a0edf674
DD
623
624 areas_processed++;
3810e06e
DD
625 }
626
627 if (ospf6->backbone)
628 {
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, ospf6->backbone->spf_table,
636 ospf6->backbone);
637 ospf6_intra_route_calculation(ospf6->backbone);
638 ospf6_intra_brouter_calculation(ospf6->backbone);
a0edf674 639 areas_processed++;
3810e06e
DD
640 }
641
ca1f4309
DS
642 if (ospf6_is_router_abr (ospf6))
643 ospf6_abr_defaults_to_stub (ospf6);
3810e06e 644
86f72dcb 645 quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
2680aa2b 646 timersub (&end, &start, &runtime);
718e3744 647
3810e06e
DD
648 ospf6->ts_spf_duration = runtime;
649
a0edf674
DD
650 ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
651
3b68735f 652 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
c6487d61 653 zlog_debug ("SPF runtime: %ld sec %ld usec",
654 runtime.tv_sec, runtime.tv_usec);
718e3744 655
a0edf674
DD
656 zlog_info("SPF processing: # Areas: %d, SPF runtime: %ld sec %ld usec, "
657 "Reason: %s\n", areas_processed, runtime.tv_sec, runtime.tv_usec,
658 rbuf);
659 ospf6->last_spf_reason = ospf6->spf_reason;
660 ospf6_reset_spf_reason(ospf6);
718e3744 661 return 0;
662}
663
3810e06e
DD
664/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
665 set timer for SPF calc. */
718e3744 666void
a0edf674 667ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
718e3744 668{
3810e06e
DD
669 unsigned long delay, elapsed, ht;
670 struct timeval now, result;
671
a0edf674
DD
672 ospf6_set_spf_reason(ospf6, reason);
673
3810e06e 674 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
a0edf674
DD
675 {
676 char rbuf[32];
677 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
678 zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
679 }
3810e06e
DD
680
681 /* OSPF instance does not exist. */
682 if (ospf6 == NULL)
718e3744 683 return;
3810e06e
DD
684
685 /* SPF calculation timer is already scheduled. */
686 if (ospf6->t_spf_calc)
687 {
688 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
689 zlog_debug ("SPF: calculation timer is already scheduled: %p",
690 ospf6->t_spf_calc);
691 return;
692 }
693
694 /* XXX Monotic timers: we only care about relative time here. */
695 now = recent_relative_time ();
696 timersub (&now, &ospf6->ts_spf, &result);
697
698 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
699 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
700
701 if (ht > ospf6->spf_max_holdtime)
702 ht = ospf6->spf_max_holdtime;
703
704 /* Get SPF calculation delay time. */
705 if (elapsed < ht)
706 {
707 /* Got an event within the hold time of last SPF. We need to
708 * increase the hold_multiplier, if it's not already at/past
709 * maximum value, and wasn't already increased..
710 */
711 if (ht < ospf6->spf_max_holdtime)
712 ospf6->spf_hold_multiplier++;
713
714 /* always honour the SPF initial delay */
715 if ( (ht - elapsed) < ospf6->spf_delay)
716 delay = ospf6->spf_delay;
717 else
718 delay = ht - elapsed;
719 }
720 else
721 {
722 /* Event is past required hold-time of last SPF */
723 delay = ospf6->spf_delay;
724 ospf6->spf_hold_multiplier = 1;
725 }
726
727 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
728 zlog_debug ("SPF: calculation timer delay = %ld", delay);
729
730 zlog_info ("SPF: Scheduled in %ld msec", delay);
731
732 ospf6->t_spf_calc =
733 thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
718e3744 734}
735
736void
0c083ee9 737ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
508e53e2 738 struct ospf6_vertex *v)
718e3744 739{
1eb8ef25 740 struct listnode *node, *nnode;
508e53e2 741 struct ospf6_vertex *c;
742 char *next_prefix;
743 int len;
744 int restnum;
718e3744 745
508e53e2 746 /* "prefix" is the space prefix of the display line */
049207c3 747 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
718e3744 748
508e53e2 749 len = strlen (prefix) + 4;
750 next_prefix = (char *) malloc (len);
751 if (next_prefix == NULL)
718e3744 752 {
049207c3 753 vty_out (vty, "malloc failed%s", VNL);
508e53e2 754 return;
718e3744 755 }
508e53e2 756 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
718e3744 757
508e53e2 758 restnum = listcount (v->child_list);
1eb8ef25 759 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
718e3744 760 {
508e53e2 761 restnum--;
762 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
718e3744 763 }
718e3744 764
508e53e2 765 free (next_prefix);
718e3744 766}
767
3b68735f 768DEFUN (debug_ospf6_spf_process,
769 debug_ospf6_spf_process_cmd,
770 "debug ospf6 spf process",
508e53e2 771 DEBUG_STR
772 OSPF6_STR
773 "Debug SPF Calculation\n"
3b68735f 774 "Debug Detailed SPF Process\n"
508e53e2 775 )
718e3744 776{
508e53e2 777 unsigned char level = 0;
3b68735f 778 level = OSPF6_DEBUG_SPF_PROCESS;
508e53e2 779 OSPF6_DEBUG_SPF_ON (level);
780 return CMD_SUCCESS;
718e3744 781}
782
3b68735f 783DEFUN (debug_ospf6_spf_time,
784 debug_ospf6_spf_time_cmd,
785 "debug ospf6 spf time",
508e53e2 786 DEBUG_STR
718e3744 787 OSPF6_STR
508e53e2 788 "Debug SPF Calculation\n"
3b68735f 789 "Measure time taken by SPF Calculation\n"
508e53e2 790 )
718e3744 791{
508e53e2 792 unsigned char level = 0;
3b68735f 793 level = OSPF6_DEBUG_SPF_TIME;
508e53e2 794 OSPF6_DEBUG_SPF_ON (level);
718e3744 795 return CMD_SUCCESS;
796}
797
2680aa2b 798DEFUN (debug_ospf6_spf_database,
799 debug_ospf6_spf_database_cmd,
800 "debug ospf6 spf database",
801 DEBUG_STR
802 OSPF6_STR
803 "Debug SPF Calculation\n"
804 "Log number of LSAs at SPF Calculation time\n"
805 )
806{
807 unsigned char level = 0;
808 level = OSPF6_DEBUG_SPF_DATABASE;
809 OSPF6_DEBUG_SPF_ON (level);
810 return CMD_SUCCESS;
811}
812
3b68735f 813DEFUN (no_debug_ospf6_spf_process,
814 no_debug_ospf6_spf_process_cmd,
815 "no debug ospf6 spf process",
508e53e2 816 NO_STR
817 DEBUG_STR
818 OSPF6_STR
819 "Quit Debugging SPF Calculation\n"
3b68735f 820 "Quit Debugging Detailed SPF Process\n"
508e53e2 821 )
718e3744 822{
508e53e2 823 unsigned char level = 0;
3b68735f 824 level = OSPF6_DEBUG_SPF_PROCESS;
508e53e2 825 OSPF6_DEBUG_SPF_OFF (level);
826 return CMD_SUCCESS;
718e3744 827}
828
3b68735f 829DEFUN (no_debug_ospf6_spf_time,
830 no_debug_ospf6_spf_time_cmd,
831 "no debug ospf6 spf time",
508e53e2 832 NO_STR
833 DEBUG_STR
718e3744 834 OSPF6_STR
508e53e2 835 "Quit Debugging SPF Calculation\n"
3b68735f 836 "Quit Measuring time taken by SPF Calculation\n"
508e53e2 837 )
718e3744 838{
508e53e2 839 unsigned char level = 0;
3b68735f 840 level = OSPF6_DEBUG_SPF_TIME;
508e53e2 841 OSPF6_DEBUG_SPF_OFF (level);
718e3744 842 return CMD_SUCCESS;
843}
844
2680aa2b 845DEFUN (no_debug_ospf6_spf_database,
846 no_debug_ospf6_spf_database_cmd,
847 "no debug ospf6 spf database",
848 NO_STR
849 DEBUG_STR
850 OSPF6_STR
851 "Debug SPF Calculation\n"
852 "Quit Logging number of LSAs at SPF Calculation time\n"
853 )
854{
855 unsigned char level = 0;
856 level = OSPF6_DEBUG_SPF_DATABASE;
857 OSPF6_DEBUG_SPF_OFF (level);
858 return CMD_SUCCESS;
859}
860
3810e06e
DD
861static int
862ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
863 unsigned int hold,
864 unsigned int max)
865{
866 struct ospf6 *ospf = vty->index;
867
868 ospf->spf_delay = delay;
869 ospf->spf_holdtime = hold;
870 ospf->spf_max_holdtime = max;
871
872 return CMD_SUCCESS;
873}
874
875DEFUN (ospf6_timers_throttle_spf,
876 ospf6_timers_throttle_spf_cmd,
877 "timers throttle spf <0-600000> <0-600000> <0-600000>",
878 "Adjust routing timers\n"
879 "Throttling adaptive timer\n"
880 "OSPF6 SPF timers\n"
881 "Delay (msec) from first change received till SPF calculation\n"
882 "Initial hold time (msec) between consecutive SPF calculations\n"
883 "Maximum hold time (msec)\n")
884{
885 unsigned int delay, hold, max;
886
887 if (argc != 3)
888 {
889 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
890 return CMD_WARNING;
891 }
892
893 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
894 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
895 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
896
897 return ospf6_timers_spf_set (vty, delay, hold, max);
898}
899
900DEFUN (no_ospf6_timers_throttle_spf,
901 no_ospf6_timers_throttle_spf_cmd,
902 "no timers throttle spf",
903 NO_STR
904 "Adjust routing timers\n"
905 "Throttling adaptive timer\n"
906 "OSPF6 SPF timers\n")
907{
908 return ospf6_timers_spf_set (vty,
909 OSPF_SPF_DELAY_DEFAULT,
910 OSPF_SPF_HOLDTIME_DEFAULT,
911 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
912}
913
813d4307
DW
914ALIAS (no_ospf6_timers_throttle_spf,
915 no_ospf6_timers_throttle_spf_val_cmd,
916 "no timers throttle spf <0-600000> <0-600000> <0-600000>",
917 NO_STR
918 "Adjust routing timers\n"
919 "Throttling adaptive timer\n"
920 "OSPF6 SPF timers\n"
921 "Delay (msec) from first change received till SPF calculation\n"
922 "Initial hold time (msec) between consecutive SPF calculations\n"
923 "Maximum hold time (msec)\n")
924
508e53e2 925int
926config_write_ospf6_debug_spf (struct vty *vty)
718e3744 927{
3b68735f 928 if (IS_OSPF6_DEBUG_SPF (PROCESS))
929 vty_out (vty, "debug ospf6 spf process%s", VNL);
930 if (IS_OSPF6_DEBUG_SPF (TIME))
931 vty_out (vty, "debug ospf6 spf time%s", VNL);
2680aa2b 932 if (IS_OSPF6_DEBUG_SPF (DATABASE))
933 vty_out (vty, "debug ospf6 spf database%s", VNL);
508e53e2 934 return 0;
718e3744 935}
936
3810e06e
DD
937void
938ospf6_spf_config_write (struct vty *vty)
939{
940
941 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
942 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
943 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
944 vty_out (vty, " timers throttle spf %d %d %d%s",
945 ospf6->spf_delay, ospf6->spf_holdtime,
946 ospf6->spf_max_holdtime, VTY_NEWLINE);
947
948}
949
508e53e2 950void
6ac29a51 951install_element_ospf6_debug_spf (void)
508e53e2 952{
3b68735f 953 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
954 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
2680aa2b 955 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
3b68735f 956 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
957 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
2680aa2b 958 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
3b68735f 959 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
960 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
2680aa2b 961 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
3b68735f 962 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
963 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
2680aa2b 964 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
508e53e2 965}
718e3744 966
967void
6ac29a51 968ospf6_spf_init (void)
718e3744 969{
3810e06e
DD
970 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
971 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
813d4307 972 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_val_cmd);
718e3744 973}