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