]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_spf.c
Merge pull request #794 from opensourcerouting/table-hash-ospf6-lsdb-refactor
[mirror_frr.git] / ospf6d / ospf6_spf.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
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 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
19 */
20
21 /* Shortest Path First calculation for OSPFv3 */
22
23 #include <zebra.h>
24
25 #include "log.h"
26 #include "memory.h"
27 #include "command.h"
28 #include "vty.h"
29 #include "prefix.h"
30 #include "pqueue.h"
31 #include "linklist.h"
32 #include "thread.h"
33
34 #include "ospf6_lsa.h"
35 #include "ospf6_lsdb.h"
36 #include "ospf6_route.h"
37 #include "ospf6_area.h"
38 #include "ospf6_proto.h"
39 #include "ospf6_abr.h"
40 #include "ospf6_spf.h"
41 #include "ospf6_intra.h"
42 #include "ospf6_interface.h"
43 #include "ospf6d.h"
44 #include "ospf6_abr.h"
45
46 unsigned char conf_debug_ospf6_spf = 0;
47
48 static void
49 ospf6_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
56 static void
57 ospf6_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
64 static unsigned int
65 ospf6_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 }
80 return 0;
81 }
82
83 static int
84 ospf6_vertex_cmp (void *a, void *b)
85 {
86 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
87 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
88
89 /* ascending order */
90 if (va->cost != vb->cost)
91 return (va->cost - vb->cost);
92 return (va->hops - vb->hops);
93 }
94
95 static int
96 ospf6_vertex_id_cmp (void *a, void *b)
97 {
98 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
99 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
100 int ret = 0;
101
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;
106
107 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
108 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
109 return ret;
110 }
111
112 static struct ospf6_vertex *
113 ospf6_vertex_create (struct ospf6_lsa *lsa)
114 {
115 struct ospf6_vertex *v;
116
117 v = (struct ospf6_vertex *)
118 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
119
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;
125 else
126 assert (0);
127
128 /* vertex_id */
129 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
130 &v->vertex_id);
131
132 /* name */
133 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
134
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
139 /* Associated LSA */
140 v->lsa = lsa;
141
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);
147
148 v->nh_list = list_new();
149
150 v->parent = NULL;
151 v->child_list = list_new ();
152 v->child_list->cmp = ospf6_vertex_id_cmp;
153
154 return v;
155 }
156
157 static void
158 ospf6_vertex_delete (struct ospf6_vertex *v)
159 {
160 list_delete(v->nh_list);
161 list_delete (v->child_list);
162 XFREE (MTYPE_OSPF6_VERTEX, v);
163 }
164
165 static struct ospf6_lsa *
166 ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
167 {
168 struct ospf6_lsa *lsa;
169 u_int16_t type = 0;
170 u_int32_t id = 0, adv_router = 0;
171
172 if (VERTEX_IS_TYPE (NETWORK, v))
173 {
174 type = htons (OSPF6_LSTYPE_ROUTER);
175 id = htonl (0);
176 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
177 }
178 else
179 {
180 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
181 {
182 type = htons (OSPF6_LSTYPE_ROUTER);
183 id = htonl (0);
184 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
185 }
186 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
187 {
188 type = htons (OSPF6_LSTYPE_NETWORK);
189 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
190 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
191 }
192 }
193
194 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
195
196 if (IS_OSPF6_DEBUG_SPF (PROCESS))
197 {
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)
202 zlog_debug (" Link to: %s", lsa->name);
203 else
204 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
205 ospf6_lstype_name (type), ibuf, abuf);
206 }
207
208 return lsa;
209 }
210
211 static char *
212 ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
213 caddr_t lsdesc, struct ospf6_vertex *v)
214 {
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 {
224 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
225 VERTEX_IS_TYPE (NETWORK, v)));
226
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 }
255 }
256
257 if (IS_OSPF6_DEBUG_SPF (PROCESS))
258 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
259
260 return found;
261 }
262
263 static void
264 ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
265 caddr_t lsdesc)
266 {
267 int i;
268 ifindex_t ifindex;
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];
275
276 assert (VERTEX_IS_TYPE (ROUTER, w));
277 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) :
278 ROUTER_LSDESC_GET_IFID (lsdesc));
279 if (ifindex == 0)
280 {
281 zlog_err ("No nexthop ifindex at vertex %s", v->name);
282 return;
283 }
284
285 oi = ospf6_interface_lookup_by_ifindex (ifindex);
286 if (oi == NULL)
287 {
288 if (IS_OSPF6_DEBUG_SPF (PROCESS))
289 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
290 return;
291 }
292
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));
297
298 i = 0;
299 for (ALL_LSDB_TYPED_ADVRTR(oi->lsdb, type, adv_router, lsa))
300 {
301 if (VERTEX_IS_TYPE (ROUTER, v) &&
302 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
303 continue;
304
305 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
306 if (IS_OSPF6_DEBUG_SPF (PROCESS))
307 {
308 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
309 zlog_debug (" nexthop %s from %s", buf, lsa->name);
310 }
311
312 ospf6_add_nexthop (w->nh_list, ifindex, &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);
318 }
319
320 static int
321 ospf6_spf_install (struct ospf6_vertex *v,
322 struct ospf6_route_table *result_table)
323 {
324 struct ospf6_route *route, *parent_route;
325 struct ospf6_vertex *prev;
326
327 if (IS_OSPF6_DEBUG_SPF (PROCESS))
328 zlog_debug ("SPF install %s hops %d cost %d",
329 v->name, v->hops, v->cost);
330
331 route = ospf6_route_lookup (&v->vertex_id, result_table);
332 if (route && route->path.cost < v->cost)
333 {
334 if (IS_OSPF6_DEBUG_SPF (PROCESS))
335 zlog_debug (" already installed with lower cost (%d), ignore",
336 route->path.cost);
337 ospf6_vertex_delete (v);
338 return -1;
339 }
340 else if (route && route->path.cost == v->cost)
341 {
342 if (IS_OSPF6_DEBUG_SPF (PROCESS))
343 zlog_debug (" another path found, merge");
344
345 ospf6_spf_merge_nexthops_to_route (route, v);
346
347 prev = (struct ospf6_vertex *) route->route_option;
348 assert (prev->hops <= v->hops);
349 ospf6_vertex_delete (v);
350
351 return -1;
352 }
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").
356 In the case something has gone wrong with the behavior of
357 Priority-Queue. */
358
359 /* the case where the route exists already is handled and returned
360 up to here. */
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;
372 route->path.u.cost_e2 = v->hops;
373 route->path.router_bits = v->capability;
374 route->path.options[0] = v->options[0];
375 route->path.options[1] = v->options[1];
376 route->path.options[2] = v->options[2];
377
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 }
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;
408 }
409
410 void
411 ospf6_spf_table_finish (struct ospf6_route_table *result_table)
412 {
413 struct ospf6_route *route, *nroute;
414 struct ospf6_vertex *v;
415 for (route = ospf6_route_head (result_table); route;
416 route = nroute)
417 {
418 nroute = ospf6_route_next (route);
419 v = (struct ospf6_vertex *) route->route_option;
420 ospf6_vertex_delete (v);
421 ospf6_route_remove (route, result_table);
422 }
423 }
424
425 static 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
437 void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
438 {
439 unsigned int bit;
440 int len = 0;
441
442 if (!buf)
443 return;
444
445 for (bit = 0; bit < array_size(ospf6_spf_reason_str); 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
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 */
457 void
458 ospf6_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;
464 int size;
465 caddr_t lsdesc;
466 struct ospf6_lsa *lsa;
467 struct in6_addr address;
468
469 ospf6_spf_table_finish (result_table);
470
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),
474 router_id, oa->lsdb_self);
475 if (lsa == NULL)
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 }
482
483 /* initialize */
484 candidate_list = pqueue_create ();
485 candidate_list->cmp = ospf6_vertex_cmp;
486
487 root = ospf6_vertex_create (lsa);
488 root->area = oa;
489 root->cost = 0;
490 root->hops = 0;
491 inet_pton (AF_INET6, "::1", &address);
492
493 /* Actually insert root to the candidate-list as the only candidate */
494 pqueue_enqueue (root, candidate_list);
495
496 /* Iterate until candidate-list becomes empty */
497 while (candidate_list->size)
498 {
499 /* get closest candidate from priority queue */
500 v = pqueue_dequeue (candidate_list);
501
502 /* installing may result in merging or rejecting of the vertex */
503 if (ospf6_spf_install (v, result_table) < 0)
504 continue;
505
506 /* Skip overloaded routers */
507 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
508 ospf6_router_is_stub_router (v->lsa)))
509 continue;
510
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)
517 {
518 lsa = ospf6_lsdesc_lsa (lsdesc, v);
519 if (lsa == NULL)
520 continue;
521
522 if (OSPF6_LSA_IS_MAXAGE (lsa))
523 continue;
524
525 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
526 continue;
527
528 w = ospf6_vertex_create (lsa);
529 w->area = oa;
530 w->parent = v;
531 if (VERTEX_IS_TYPE (ROUTER, v))
532 {
533 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
534 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
535 }
536 else /* NETWORK */
537 {
538 w->cost = v->cost;
539 w->hops = v->hops + 1;
540 }
541
542 /* nexthop calculation */
543 if (w->hops == 0)
544 ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
545 else if (w->hops == 1 && v->hops == 0)
546 ospf6_nexthop_calc (w, v, lsdesc);
547 else
548 {
549 ospf6_copy_nexthops (w->nh_list, v->nh_list);
550 }
551
552 /* add new candidate to the candidate_list */
553 if (IS_OSPF6_DEBUG_SPF (PROCESS))
554 zlog_debug (" New candidate: %s hops %d cost %d",
555 w->name, w->hops, w->cost);
556 pqueue_enqueue (w, candidate_list);
557 }
558 }
559
560 pqueue_delete (candidate_list);
561
562 oa->spf_calculation++;
563 }
564
565 static void
566 ospf6_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
580 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
581 {
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
587 zlog_debug ("%s", buffer);
588 }
589
590 static int
591 ospf6_spf_calculation_thread (struct thread *t)
592 {
593 struct ospf6_area *oa;
594 struct ospf6 *ospf6;
595 struct timeval start, end, runtime;
596 struct listnode *node;
597 int areas_processed = 0;
598 char rbuf[32];
599
600 ospf6 = (struct ospf6 *)THREAD_ARG (t);
601 ospf6->t_spf_calc = NULL;
602
603 /* execute SPF calculation */
604 monotime(&start);
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
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);
623
624 areas_processed++;
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);
639 areas_processed++;
640 }
641
642 if (ospf6_is_router_abr (ospf6))
643 ospf6_abr_defaults_to_stub (ospf6);
644
645 monotime(&end);
646 timersub (&end, &start, &runtime);
647
648 ospf6->ts_spf_duration = runtime;
649
650 ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
651
652 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
653 zlog_debug ("SPF runtime: %lld sec %lld usec",
654 (long long)runtime.tv_sec, (long long)runtime.tv_usec);
655
656 zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
657 "Reason: %s\n", areas_processed,
658 (long long)runtime.tv_sec, (long long)runtime.tv_usec,
659 rbuf);
660 ospf6->last_spf_reason = ospf6->spf_reason;
661 ospf6_reset_spf_reason(ospf6);
662 return 0;
663 }
664
665 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
666 set timer for SPF calc. */
667 void
668 ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
669 {
670 unsigned long delay, elapsed, ht;
671
672 ospf6_set_spf_reason(ospf6, reason);
673
674 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
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 }
680
681 /* OSPF instance does not exist. */
682 if (ospf6 == NULL)
683 return;
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 (void *)ospf6->t_spf_calc);
691 return;
692 }
693
694 elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
695 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
696
697 if (ht > ospf6->spf_max_holdtime)
698 ht = ospf6->spf_max_holdtime;
699
700 /* Get SPF calculation delay time. */
701 if (elapsed < ht)
702 {
703 /* Got an event within the hold time of last SPF. We need to
704 * increase the hold_multiplier, if it's not already at/past
705 * maximum value, and wasn't already increased..
706 */
707 if (ht < ospf6->spf_max_holdtime)
708 ospf6->spf_hold_multiplier++;
709
710 /* always honour the SPF initial delay */
711 if ( (ht - elapsed) < ospf6->spf_delay)
712 delay = ospf6->spf_delay;
713 else
714 delay = ht - elapsed;
715 }
716 else
717 {
718 /* Event is past required hold-time of last SPF */
719 delay = ospf6->spf_delay;
720 ospf6->spf_hold_multiplier = 1;
721 }
722
723 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
724 zlog_debug ("SPF: calculation timer delay = %ld", delay);
725
726 zlog_info ("SPF: Scheduled in %ld msec", delay);
727
728 ospf6->t_spf_calc = NULL;
729 thread_add_timer_msec(master, ospf6_spf_calculation_thread, ospf6, delay,
730 &ospf6->t_spf_calc);
731 }
732
733 void
734 ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
735 struct ospf6_vertex *v)
736 {
737 struct listnode *node, *nnode;
738 struct ospf6_vertex *c;
739 char *next_prefix;
740 int len;
741 int restnum;
742
743 /* "prefix" is the space prefix of the display line */
744 vty_out (vty, "%s+-%s [%d]\n", prefix, v->name, v->cost);
745
746 len = strlen (prefix) + 4;
747 next_prefix = (char *) malloc (len);
748 if (next_prefix == NULL)
749 {
750 vty_out (vty, "malloc failed\n");
751 return;
752 }
753 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
754
755 restnum = listcount (v->child_list);
756 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
757 {
758 restnum--;
759 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
760 }
761
762 free (next_prefix);
763 }
764
765 DEFUN (debug_ospf6_spf_process,
766 debug_ospf6_spf_process_cmd,
767 "debug ospf6 spf process",
768 DEBUG_STR
769 OSPF6_STR
770 "Debug SPF Calculation\n"
771 "Debug Detailed SPF Process\n"
772 )
773 {
774 unsigned char level = 0;
775 level = OSPF6_DEBUG_SPF_PROCESS;
776 OSPF6_DEBUG_SPF_ON (level);
777 return CMD_SUCCESS;
778 }
779
780 DEFUN (debug_ospf6_spf_time,
781 debug_ospf6_spf_time_cmd,
782 "debug ospf6 spf time",
783 DEBUG_STR
784 OSPF6_STR
785 "Debug SPF Calculation\n"
786 "Measure time taken by SPF Calculation\n"
787 )
788 {
789 unsigned char level = 0;
790 level = OSPF6_DEBUG_SPF_TIME;
791 OSPF6_DEBUG_SPF_ON (level);
792 return CMD_SUCCESS;
793 }
794
795 DEFUN (debug_ospf6_spf_database,
796 debug_ospf6_spf_database_cmd,
797 "debug ospf6 spf database",
798 DEBUG_STR
799 OSPF6_STR
800 "Debug SPF Calculation\n"
801 "Log number of LSAs at SPF Calculation time\n"
802 )
803 {
804 unsigned char level = 0;
805 level = OSPF6_DEBUG_SPF_DATABASE;
806 OSPF6_DEBUG_SPF_ON (level);
807 return CMD_SUCCESS;
808 }
809
810 DEFUN (no_debug_ospf6_spf_process,
811 no_debug_ospf6_spf_process_cmd,
812 "no debug ospf6 spf process",
813 NO_STR
814 DEBUG_STR
815 OSPF6_STR
816 "Quit Debugging SPF Calculation\n"
817 "Quit Debugging Detailed SPF Process\n"
818 )
819 {
820 unsigned char level = 0;
821 level = OSPF6_DEBUG_SPF_PROCESS;
822 OSPF6_DEBUG_SPF_OFF (level);
823 return CMD_SUCCESS;
824 }
825
826 DEFUN (no_debug_ospf6_spf_time,
827 no_debug_ospf6_spf_time_cmd,
828 "no debug ospf6 spf time",
829 NO_STR
830 DEBUG_STR
831 OSPF6_STR
832 "Quit Debugging SPF Calculation\n"
833 "Quit Measuring time taken by SPF Calculation\n"
834 )
835 {
836 unsigned char level = 0;
837 level = OSPF6_DEBUG_SPF_TIME;
838 OSPF6_DEBUG_SPF_OFF (level);
839 return CMD_SUCCESS;
840 }
841
842 DEFUN (no_debug_ospf6_spf_database,
843 no_debug_ospf6_spf_database_cmd,
844 "no debug ospf6 spf database",
845 NO_STR
846 DEBUG_STR
847 OSPF6_STR
848 "Debug SPF Calculation\n"
849 "Quit Logging number of LSAs at SPF Calculation time\n"
850 )
851 {
852 unsigned char level = 0;
853 level = OSPF6_DEBUG_SPF_DATABASE;
854 OSPF6_DEBUG_SPF_OFF (level);
855 return CMD_SUCCESS;
856 }
857
858 static int
859 ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
860 unsigned int hold,
861 unsigned int max)
862 {
863 VTY_DECLVAR_CONTEXT(ospf6, ospf);
864
865 ospf->spf_delay = delay;
866 ospf->spf_holdtime = hold;
867 ospf->spf_max_holdtime = max;
868
869 return CMD_SUCCESS;
870 }
871
872 DEFUN (ospf6_timers_throttle_spf,
873 ospf6_timers_throttle_spf_cmd,
874 "timers throttle spf (0-600000) (0-600000) (0-600000)",
875 "Adjust routing timers\n"
876 "Throttling adaptive timer\n"
877 "OSPF6 SPF timers\n"
878 "Delay (msec) from first change received till SPF calculation\n"
879 "Initial hold time (msec) between consecutive SPF calculations\n"
880 "Maximum hold time (msec)\n")
881 {
882 int idx_number = 3;
883 int idx_number_2 = 4;
884 int idx_number_3 = 5;
885 unsigned int delay, hold, max;
886
887 delay = strtoul(argv[idx_number]->arg, NULL, 10);
888 hold = strtoul(argv[idx_number_2]->arg, NULL, 10);
889 max = strtoul(argv[idx_number_3]->arg, NULL, 10);
890
891 return ospf6_timers_spf_set (vty, delay, hold, max);
892 }
893
894 DEFUN (no_ospf6_timers_throttle_spf,
895 no_ospf6_timers_throttle_spf_cmd,
896 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
897 NO_STR
898 "Adjust routing timers\n"
899 "Throttling adaptive timer\n"
900 "OSPF6 SPF timers\n"
901 "Delay (msec) from first change received till SPF calculation\n"
902 "Initial hold time (msec) between consecutive SPF calculations\n"
903 "Maximum hold time (msec)\n")
904 {
905 return ospf6_timers_spf_set (vty,
906 OSPF_SPF_DELAY_DEFAULT,
907 OSPF_SPF_HOLDTIME_DEFAULT,
908 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
909 }
910
911
912 int
913 config_write_ospf6_debug_spf (struct vty *vty)
914 {
915 if (IS_OSPF6_DEBUG_SPF (PROCESS))
916 vty_out (vty, "debug ospf6 spf process\n");
917 if (IS_OSPF6_DEBUG_SPF (TIME))
918 vty_out (vty, "debug ospf6 spf time\n");
919 if (IS_OSPF6_DEBUG_SPF (DATABASE))
920 vty_out (vty, "debug ospf6 spf database\n");
921 return 0;
922 }
923
924 void
925 ospf6_spf_config_write (struct vty *vty)
926 {
927
928 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
929 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
930 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
931 vty_out (vty, " timers throttle spf %d %d %d\n",
932 ospf6->spf_delay, ospf6->spf_holdtime,
933 ospf6->spf_max_holdtime);
934
935 }
936
937 void
938 install_element_ospf6_debug_spf (void)
939 {
940 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
941 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
942 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
943 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
944 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
945 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
946 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
947 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
948 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
949 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
950 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
951 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
952 }
953
954 void
955 ospf6_spf_init (void)
956 {
957 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
958 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
959 }