]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_spf.c
e7cfd3fc9a4f6c6547aa253d46869f7da5fb9798
[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 (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
300 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
301 {
302 if (VERTEX_IS_TYPE (ROUTER, v) &&
303 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
304 continue;
305
306 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
307 if (IS_OSPF6_DEBUG_SPF (PROCESS))
308 {
309 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
310 zlog_debug (" nexthop %s from %s", buf, lsa->name);
311 }
312
313 ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr);
314 i++;
315 }
316
317 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
318 zlog_debug ("No nexthop for %s found", w->name);
319 }
320
321 static int
322 ospf6_spf_install (struct ospf6_vertex *v,
323 struct ospf6_route_table *result_table)
324 {
325 struct ospf6_route *route, *parent_route;
326 struct ospf6_vertex *prev;
327
328 if (IS_OSPF6_DEBUG_SPF (PROCESS))
329 zlog_debug ("SPF install %s hops %d cost %d",
330 v->name, v->hops, v->cost);
331
332 route = ospf6_route_lookup (&v->vertex_id, result_table);
333 if (route && route->path.cost < v->cost)
334 {
335 if (IS_OSPF6_DEBUG_SPF (PROCESS))
336 zlog_debug (" already installed with lower cost (%d), ignore",
337 route->path.cost);
338 ospf6_vertex_delete (v);
339 return -1;
340 }
341 else if (route && route->path.cost == v->cost)
342 {
343 if (IS_OSPF6_DEBUG_SPF (PROCESS))
344 zlog_debug (" another path found, merge");
345
346 ospf6_spf_merge_nexthops_to_route (route, v);
347
348 prev = (struct ospf6_vertex *) route->route_option;
349 assert (prev->hops <= v->hops);
350 ospf6_vertex_delete (v);
351
352 return -1;
353 }
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").
357 In the case something has gone wrong with the behavior of
358 Priority-Queue. */
359
360 /* the case where the route exists already is handled and returned
361 up to here. */
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;
373 route->path.u.cost_e2 = v->hops;
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
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 }
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;
409 }
410
411 void
412 ospf6_spf_table_finish (struct ospf6_route_table *result_table)
413 {
414 struct ospf6_route *route, *nroute;
415 struct ospf6_vertex *v;
416 for (route = ospf6_route_head (result_table); route;
417 route = nroute)
418 {
419 nroute = ospf6_route_next (route);
420 v = (struct ospf6_vertex *) route->route_option;
421 ospf6_vertex_delete (v);
422 ospf6_route_remove (route, result_table);
423 }
424 }
425
426 static 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
438 void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
439 {
440 unsigned int bit;
441 int len = 0;
442
443 if (!buf)
444 return;
445
446 for (bit = 0; bit < array_size(ospf6_spf_reason_str); 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
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 */
458 void
459 ospf6_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;
465 int size;
466 caddr_t lsdesc;
467 struct ospf6_lsa *lsa;
468 struct in6_addr address;
469
470 ospf6_spf_table_finish (result_table);
471
472 /* Install the calculating router itself as the root of the SPF tree */
473 /* construct root vertex */
474 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
475 router_id, oa->lsdb_self);
476 if (lsa == NULL)
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 }
483
484 /* initialize */
485 candidate_list = pqueue_create ();
486 candidate_list->cmp = ospf6_vertex_cmp;
487
488 root = ospf6_vertex_create (lsa);
489 root->area = oa;
490 root->cost = 0;
491 root->hops = 0;
492 inet_pton (AF_INET6, "::1", &address);
493
494 /* Actually insert root to the candidate-list as the only candidate */
495 pqueue_enqueue (root, candidate_list);
496
497 /* Iterate until candidate-list becomes empty */
498 while (candidate_list->size)
499 {
500 /* get closest candidate from priority queue */
501 v = pqueue_dequeue (candidate_list);
502
503 /* installing may result in merging or rejecting of the vertex */
504 if (ospf6_spf_install (v, result_table) < 0)
505 continue;
506
507 /* Skip overloaded routers */
508 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
509 ospf6_router_is_stub_router (v->lsa)))
510 continue;
511
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)
518 {
519 lsa = ospf6_lsdesc_lsa (lsdesc, v);
520 if (lsa == NULL)
521 continue;
522
523 if (OSPF6_LSA_IS_MAXAGE (lsa))
524 continue;
525
526 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
527 continue;
528
529 w = ospf6_vertex_create (lsa);
530 w->area = oa;
531 w->parent = v;
532 if (VERTEX_IS_TYPE (ROUTER, v))
533 {
534 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
535 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
536 }
537 else /* NETWORK */
538 {
539 w->cost = v->cost;
540 w->hops = v->hops + 1;
541 }
542
543 /* nexthop calculation */
544 if (w->hops == 0)
545 ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
546 else if (w->hops == 1 && v->hops == 0)
547 ospf6_nexthop_calc (w, v, lsdesc);
548 else
549 {
550 ospf6_copy_nexthops (w->nh_list, v->nh_list);
551 }
552
553 /* add new candidate to the candidate_list */
554 if (IS_OSPF6_DEBUG_SPF (PROCESS))
555 zlog_debug (" New candidate: %s hops %d cost %d",
556 w->name, w->hops, w->cost);
557 pqueue_enqueue (w, candidate_list);
558 }
559 }
560
561 pqueue_delete (candidate_list);
562
563 oa->spf_calculation++;
564 }
565
566 static void
567 ospf6_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
581 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
582 {
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
588 zlog_debug ("%s", buffer);
589 }
590
591 static int
592 ospf6_spf_calculation_thread (struct thread *t)
593 {
594 struct ospf6_area *oa;
595 struct ospf6 *ospf6;
596 struct timeval start, end, runtime;
597 struct listnode *node;
598 int areas_processed = 0;
599 char rbuf[32];
600
601 ospf6 = (struct ospf6 *)THREAD_ARG (t);
602 ospf6->t_spf_calc = NULL;
603
604 /* execute SPF calculation */
605 monotime(&start);
606
607 if (ospf6_is_router_abr (ospf6))
608 ospf6_abr_range_reset_cost (ospf6);
609
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);
624
625 areas_processed++;
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);
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))
654 zlog_debug ("SPF runtime: %lld sec %lld usec",
655 (long long)runtime.tv_sec, (long long)runtime.tv_usec);
656
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,
660 rbuf);
661 ospf6->last_spf_reason = ospf6->spf_reason;
662 ospf6_reset_spf_reason(ospf6);
663 return 0;
664 }
665
666 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
667 set timer for SPF calc. */
668 void
669 ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
670 {
671 unsigned long delay, elapsed, ht;
672
673 ospf6_set_spf_reason(ospf6, reason);
674
675 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
676 {
677 char rbuf[32];
678 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
679 zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
680 }
681
682 /* OSPF instance does not exist. */
683 if (ospf6 == NULL)
684 return;
685
686 /* SPF calculation timer is already scheduled. */
687 if (ospf6->t_spf_calc)
688 {
689 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
690 zlog_debug ("SPF: calculation timer is already scheduled: %p",
691 (void *)ospf6->t_spf_calc);
692 return;
693 }
694
695 elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
696 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
697
698 if (ht > ospf6->spf_max_holdtime)
699 ht = ospf6->spf_max_holdtime;
700
701 /* Get SPF calculation delay time. */
702 if (elapsed < ht)
703 {
704 /* Got an event within the hold time of last SPF. We need to
705 * increase the hold_multiplier, if it's not already at/past
706 * maximum value, and wasn't already increased..
707 */
708 if (ht < ospf6->spf_max_holdtime)
709 ospf6->spf_hold_multiplier++;
710
711 /* always honour the SPF initial delay */
712 if ( (ht - elapsed) < ospf6->spf_delay)
713 delay = ospf6->spf_delay;
714 else
715 delay = ht - elapsed;
716 }
717 else
718 {
719 /* Event is past required hold-time of last SPF */
720 delay = ospf6->spf_delay;
721 ospf6->spf_hold_multiplier = 1;
722 }
723
724 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
725 zlog_debug ("SPF: calculation timer delay = %ld", delay);
726
727 zlog_info ("SPF: Scheduled in %ld msec", delay);
728
729 ospf6->t_spf_calc = NULL;
730 thread_add_timer_msec(master, ospf6_spf_calculation_thread, ospf6, delay,
731 &ospf6->t_spf_calc);
732 }
733
734 void
735 ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
736 struct ospf6_vertex *v)
737 {
738 struct listnode *node, *nnode;
739 struct ospf6_vertex *c;
740 char *next_prefix;
741 int len;
742 int restnum;
743
744 /* "prefix" is the space prefix of the display line */
745 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
746
747 len = strlen (prefix) + 4;
748 next_prefix = (char *) malloc (len);
749 if (next_prefix == NULL)
750 {
751 vty_out (vty, "malloc failed%s", VNL);
752 return;
753 }
754 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
755
756 restnum = listcount (v->child_list);
757 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
758 {
759 restnum--;
760 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
761 }
762
763 free (next_prefix);
764 }
765
766 DEFUN (debug_ospf6_spf_process,
767 debug_ospf6_spf_process_cmd,
768 "debug ospf6 spf process",
769 DEBUG_STR
770 OSPF6_STR
771 "Debug SPF Calculation\n"
772 "Debug Detailed SPF Process\n"
773 )
774 {
775 unsigned char level = 0;
776 level = OSPF6_DEBUG_SPF_PROCESS;
777 OSPF6_DEBUG_SPF_ON (level);
778 return CMD_SUCCESS;
779 }
780
781 DEFUN (debug_ospf6_spf_time,
782 debug_ospf6_spf_time_cmd,
783 "debug ospf6 spf time",
784 DEBUG_STR
785 OSPF6_STR
786 "Debug SPF Calculation\n"
787 "Measure time taken by SPF Calculation\n"
788 )
789 {
790 unsigned char level = 0;
791 level = OSPF6_DEBUG_SPF_TIME;
792 OSPF6_DEBUG_SPF_ON (level);
793 return CMD_SUCCESS;
794 }
795
796 DEFUN (debug_ospf6_spf_database,
797 debug_ospf6_spf_database_cmd,
798 "debug ospf6 spf database",
799 DEBUG_STR
800 OSPF6_STR
801 "Debug SPF Calculation\n"
802 "Log number of LSAs at SPF Calculation time\n"
803 )
804 {
805 unsigned char level = 0;
806 level = OSPF6_DEBUG_SPF_DATABASE;
807 OSPF6_DEBUG_SPF_ON (level);
808 return CMD_SUCCESS;
809 }
810
811 DEFUN (no_debug_ospf6_spf_process,
812 no_debug_ospf6_spf_process_cmd,
813 "no debug ospf6 spf process",
814 NO_STR
815 DEBUG_STR
816 OSPF6_STR
817 "Quit Debugging SPF Calculation\n"
818 "Quit Debugging Detailed SPF Process\n"
819 )
820 {
821 unsigned char level = 0;
822 level = OSPF6_DEBUG_SPF_PROCESS;
823 OSPF6_DEBUG_SPF_OFF (level);
824 return CMD_SUCCESS;
825 }
826
827 DEFUN (no_debug_ospf6_spf_time,
828 no_debug_ospf6_spf_time_cmd,
829 "no debug ospf6 spf time",
830 NO_STR
831 DEBUG_STR
832 OSPF6_STR
833 "Quit Debugging SPF Calculation\n"
834 "Quit Measuring time taken by SPF Calculation\n"
835 )
836 {
837 unsigned char level = 0;
838 level = OSPF6_DEBUG_SPF_TIME;
839 OSPF6_DEBUG_SPF_OFF (level);
840 return CMD_SUCCESS;
841 }
842
843 DEFUN (no_debug_ospf6_spf_database,
844 no_debug_ospf6_spf_database_cmd,
845 "no debug ospf6 spf database",
846 NO_STR
847 DEBUG_STR
848 OSPF6_STR
849 "Debug SPF Calculation\n"
850 "Quit Logging number of LSAs at SPF Calculation time\n"
851 )
852 {
853 unsigned char level = 0;
854 level = OSPF6_DEBUG_SPF_DATABASE;
855 OSPF6_DEBUG_SPF_OFF (level);
856 return CMD_SUCCESS;
857 }
858
859 static int
860 ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
861 unsigned int hold,
862 unsigned int max)
863 {
864 VTY_DECLVAR_CONTEXT(ospf6, ospf);
865
866 ospf->spf_delay = delay;
867 ospf->spf_holdtime = hold;
868 ospf->spf_max_holdtime = max;
869
870 return CMD_SUCCESS;
871 }
872
873 DEFUN (ospf6_timers_throttle_spf,
874 ospf6_timers_throttle_spf_cmd,
875 "timers throttle spf (0-600000) (0-600000) (0-600000)",
876 "Adjust routing timers\n"
877 "Throttling adaptive timer\n"
878 "OSPF6 SPF timers\n"
879 "Delay (msec) from first change received till SPF calculation\n"
880 "Initial hold time (msec) between consecutive SPF calculations\n"
881 "Maximum hold time (msec)\n")
882 {
883 int idx_number = 3;
884 int idx_number_2 = 4;
885 int idx_number_3 = 5;
886 unsigned int delay, hold, max;
887
888 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[idx_number]->arg, 0, 600000);
889 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[idx_number_2]->arg, 0, 600000);
890 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[idx_number_3]->arg, 0, 600000);
891
892 return ospf6_timers_spf_set (vty, delay, hold, max);
893 }
894
895 DEFUN (no_ospf6_timers_throttle_spf,
896 no_ospf6_timers_throttle_spf_cmd,
897 "no timers throttle spf [(0-600000) (0-600000) (0-600000)]",
898 NO_STR
899 "Adjust routing timers\n"
900 "Throttling adaptive timer\n"
901 "OSPF6 SPF timers\n"
902 "Delay (msec) from first change received till SPF calculation\n"
903 "Initial hold time (msec) between consecutive SPF calculations\n"
904 "Maximum hold time (msec)\n")
905 {
906 return ospf6_timers_spf_set (vty,
907 OSPF_SPF_DELAY_DEFAULT,
908 OSPF_SPF_HOLDTIME_DEFAULT,
909 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
910 }
911
912
913 int
914 config_write_ospf6_debug_spf (struct vty *vty)
915 {
916 if (IS_OSPF6_DEBUG_SPF (PROCESS))
917 vty_out (vty, "debug ospf6 spf process%s", VNL);
918 if (IS_OSPF6_DEBUG_SPF (TIME))
919 vty_out (vty, "debug ospf6 spf time%s", VNL);
920 if (IS_OSPF6_DEBUG_SPF (DATABASE))
921 vty_out (vty, "debug ospf6 spf database%s", VNL);
922 return 0;
923 }
924
925 void
926 ospf6_spf_config_write (struct vty *vty)
927 {
928
929 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
930 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
931 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
932 vty_out (vty, " timers throttle spf %d %d %d%s",
933 ospf6->spf_delay, ospf6->spf_holdtime,
934 ospf6->spf_max_holdtime, VTY_NEWLINE);
935
936 }
937
938 void
939 install_element_ospf6_debug_spf (void)
940 {
941 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
942 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
943 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
944 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
945 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
946 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
947 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
948 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
949 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
950 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
951 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
952 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
953 }
954
955 void
956 ospf6_spf_init (void)
957 {
958 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
959 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
960 }