blob: 88e128536952729b721cdd033b2374e438ea79d9 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
hasso508e53e2004-05-18 18:57:06 +00002 * Copyright (C) 2003 Yasuhiro Ohara
paul718e3742002-12-13 20:15:29 +00003 *
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 */
hasso508e53e2004-05-18 18:57:06 +000021
paul718e3742002-12-13 20:15:29 +000022/* Shortest Path First calculation for OSPFv3 */
23
hasso508e53e2004-05-18 18:57:06 +000024#include <zebra.h>
paul718e3742002-12-13 20:15:29 +000025
hasso508e53e2004-05-18 18:57:06 +000026#include "log.h"
27#include "memory.h"
28#include "command.h"
29#include "vty.h"
paul718e3742002-12-13 20:15:29 +000030#include "prefix.h"
hasso508e53e2004-05-18 18:57:06 +000031#include "pqueue.h"
32#include "linklist.h"
33#include "thread.h"
paul718e3742002-12-13 20:15:29 +000034
paul718e3742002-12-13 20:15:29 +000035#include "ospf6_lsa.h"
36#include "ospf6_lsdb.h"
37#include "ospf6_route.h"
paul718e3742002-12-13 20:15:29 +000038#include "ospf6_area.h"
hasso508e53e2004-05-18 18:57:06 +000039#include "ospf6_spf.h"
40#include "ospf6_intra.h"
41#include "ospf6_interface.h"
hasso049207c2004-08-04 20:02:13 +000042#include "ospf6d.h"
Paul Jakma7aa9dce2014-09-19 14:42:23 +010043#include "ospf6_abr.h"
paul718e3742002-12-13 20:15:29 +000044
hasso508e53e2004-05-18 18:57:06 +000045unsigned char conf_debug_ospf6_spf = 0;
paul718e3742002-12-13 20:15:29 +000046
Paul Jakma6ac29a52008-08-15 13:45:30 +010047static int
hasso508e53e2004-05-18 18:57:06 +000048ospf6_vertex_cmp (void *a, void *b)
paul718e3742002-12-13 20:15:29 +000049{
hasso508e53e2004-05-18 18:57:06 +000050 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
51 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
52
53 /* ascending order */
Dmitrij Tejblum403138e2011-01-13 18:25:40 +030054 if (va->cost != vb->cost)
55 return (va->cost - vb->cost);
56 return (va->hops - vb->hops);
paul718e3742002-12-13 20:15:29 +000057}
58
Paul Jakma6ac29a52008-08-15 13:45:30 +010059static int
hasso508e53e2004-05-18 18:57:06 +000060ospf6_vertex_id_cmp (void *a, void *b)
paul718e3742002-12-13 20:15:29 +000061{
hasso508e53e2004-05-18 18:57:06 +000062 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
63 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
64 int ret = 0;
paul718e3742002-12-13 20:15:29 +000065
hasso508e53e2004-05-18 18:57:06 +000066 ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
67 ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
68 if (ret)
69 return ret;
paul718e3742002-12-13 20:15:29 +000070
hasso508e53e2004-05-18 18:57:06 +000071 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
72 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
paul718e3742002-12-13 20:15:29 +000073 return ret;
74}
75
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static struct ospf6_vertex *
hasso508e53e2004-05-18 18:57:06 +000077ospf6_vertex_create (struct ospf6_lsa *lsa)
78{
79 struct ospf6_vertex *v;
80 int i;
81
82 v = (struct ospf6_vertex *)
83 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
84
85 /* type */
86 if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
87 v->type = OSPF6_VERTEX_TYPE_ROUTER;
88 else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
89 v->type = OSPF6_VERTEX_TYPE_NETWORK;
90 else
91 assert (0);
92
93 /* vertex_id */
94 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
95 &v->vertex_id);
96
97 /* name */
98 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
99
100 /* Associated LSA */
101 v->lsa = lsa;
102
103 /* capability bits + options */
104 v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
105 v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
106 v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
107 v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
108
109 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
110 ospf6_nexthop_clear (&v->nexthop[i]);
111
112 v->parent = NULL;
113 v->child_list = list_new ();
114 v->child_list->cmp = ospf6_vertex_id_cmp;
115
116 return v;
117}
118
Paul Jakma6ac29a52008-08-15 13:45:30 +0100119static void
hasso508e53e2004-05-18 18:57:06 +0000120ospf6_vertex_delete (struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000121{
hasso508e53e2004-05-18 18:57:06 +0000122 list_delete (v->child_list);
paul718e3742002-12-13 20:15:29 +0000123 XFREE (MTYPE_OSPF6_VERTEX, v);
124}
125
Paul Jakma6ac29a52008-08-15 13:45:30 +0100126static struct ospf6_lsa *
hasso508e53e2004-05-18 18:57:06 +0000127ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000128{
paul718e3742002-12-13 20:15:29 +0000129 struct ospf6_lsa *lsa;
hasso508e53e2004-05-18 18:57:06 +0000130 u_int16_t type = 0;
131 u_int32_t id = 0, adv_router = 0;
paul718e3742002-12-13 20:15:29 +0000132
hasso508e53e2004-05-18 18:57:06 +0000133 if (VERTEX_IS_TYPE (NETWORK, v))
paul718e3742002-12-13 20:15:29 +0000134 {
hasso508e53e2004-05-18 18:57:06 +0000135 type = htons (OSPF6_LSTYPE_ROUTER);
136 id = htonl (0);
137 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
paul718e3742002-12-13 20:15:29 +0000138 }
paul718e3742002-12-13 20:15:29 +0000139 else
paul718e3742002-12-13 20:15:29 +0000140 {
hasso508e53e2004-05-18 18:57:06 +0000141 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
paul718e3742002-12-13 20:15:29 +0000142 {
hasso508e53e2004-05-18 18:57:06 +0000143 type = htons (OSPF6_LSTYPE_ROUTER);
144 id = htonl (0);
145 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
146 }
147 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
148 {
149 type = htons (OSPF6_LSTYPE_NETWORK);
150 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
151 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
paul718e3742002-12-13 20:15:29 +0000152 }
153 }
154
hasso508e53e2004-05-18 18:57:06 +0000155 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
paul718e3742002-12-13 20:15:29 +0000156
hasso3b687352004-08-19 06:56:53 +0000157 if (IS_OSPF6_DEBUG_SPF (PROCESS))
paul718e3742002-12-13 20:15:29 +0000158 {
hasso508e53e2004-05-18 18:57:06 +0000159 char ibuf[16], abuf[16];
160 inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
161 inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
162 if (lsa)
hassoc6487d62004-12-24 06:00:11 +0000163 zlog_debug (" Link to: %s", lsa->name);
hasso508e53e2004-05-18 18:57:06 +0000164 else
hassoc6487d62004-12-24 06:00:11 +0000165 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
166 ospf6_lstype_name (type), ibuf, abuf);
paul718e3742002-12-13 20:15:29 +0000167 }
168
hasso508e53e2004-05-18 18:57:06 +0000169 return lsa;
170}
171
Paul Jakma6ac29a52008-08-15 13:45:30 +0100172static char *
hasso508e53e2004-05-18 18:57:06 +0000173ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
174 caddr_t lsdesc, struct ospf6_vertex *v)
175{
176 caddr_t backlink, found = NULL;
177 int size;
178
179 size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
180 sizeof (struct ospf6_router_lsdesc) :
181 sizeof (struct ospf6_network_lsdesc));
182 for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
183 backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
184 {
185 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
186 VERTEX_IS_TYPE (NETWORK, v)));
187
188 if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
189 NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
190 == v->lsa->header->adv_router)
191 found = backlink;
192 else if (VERTEX_IS_TYPE (NETWORK, v) &&
193 ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
194 ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
195 == v->lsa->header->adv_router &&
196 ROUTER_LSDESC_GET_NBR_IFID (backlink)
197 == ntohl (v->lsa->header->id))
198 found = backlink;
199 else
200 {
201 if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
202 ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
203 continue;
204 if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
205 ROUTER_LSDESC_GET_IFID (lsdesc) ||
206 ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
207 ROUTER_LSDESC_GET_IFID (backlink))
208 continue;
209 if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
210 v->lsa->header->adv_router ||
211 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
212 lsa->header->adv_router)
213 continue;
214 found = backlink;
215 }
216 }
217
hasso3b687352004-08-19 06:56:53 +0000218 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000219 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
hasso508e53e2004-05-18 18:57:06 +0000220
221 return found;
222}
223
Paul Jakma6ac29a52008-08-15 13:45:30 +0100224static void
hasso508e53e2004-05-18 18:57:06 +0000225ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
226 caddr_t lsdesc)
227{
228 int i, ifindex;
229 struct ospf6_interface *oi;
230 u_int16_t type;
231 u_int32_t adv_router;
232 struct ospf6_lsa *lsa;
233 struct ospf6_link_lsa *link_lsa;
234 char buf[64];
235
236 assert (VERTEX_IS_TYPE (ROUTER, w));
237 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
238 ROUTER_LSDESC_GET_IFID (lsdesc));
239 oi = ospf6_interface_lookup_by_ifindex (ifindex);
240 if (oi == NULL)
241 {
hasso3b687352004-08-19 06:56:53 +0000242 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000243 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
hasso508e53e2004-05-18 18:57:06 +0000244 return;
245 }
246
247 type = htons (OSPF6_LSTYPE_LINK);
248 adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
249 NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
250 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
251
252 i = 0;
253 for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
254 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
255 {
256 if (VERTEX_IS_TYPE (ROUTER, v) &&
257 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
258 continue;
259
260 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
hasso3b687352004-08-19 06:56:53 +0000261 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hasso508e53e2004-05-18 18:57:06 +0000262 {
263 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
hassoc6487d62004-12-24 06:00:11 +0000264 zlog_debug (" nexthop %s from %s", buf, lsa->name);
hasso508e53e2004-05-18 18:57:06 +0000265 }
266
267 if (i < OSPF6_MULTI_PATH_LIMIT)
268 {
269 memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
270 sizeof (struct in6_addr));
271 w->nexthop[i].ifindex = ifindex;
272 i++;
273 }
274 }
275
hasso3b687352004-08-19 06:56:53 +0000276 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000277 zlog_debug ("No nexthop for %s found", w->name);
hasso508e53e2004-05-18 18:57:06 +0000278}
279
Paul Jakma6ac29a52008-08-15 13:45:30 +0100280static int
hasso508e53e2004-05-18 18:57:06 +0000281ospf6_spf_install (struct ospf6_vertex *v,
282 struct ospf6_route_table *result_table)
283{
284 struct ospf6_route *route;
285 int i, j;
Denis Ovsienko87362ce2011-08-27 22:19:34 +0400286 struct ospf6_vertex *prev;
hasso508e53e2004-05-18 18:57:06 +0000287
hasso3b687352004-08-19 06:56:53 +0000288 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000289 zlog_debug ("SPF install %s hops %d cost %d",
290 v->name, v->hops, v->cost);
hasso508e53e2004-05-18 18:57:06 +0000291
292 route = ospf6_route_lookup (&v->vertex_id, result_table);
293 if (route && route->path.cost < v->cost)
294 {
hasso3b687352004-08-19 06:56:53 +0000295 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000296 zlog_debug (" already installed with lower cost (%d), ignore",
297 route->path.cost);
hasso508e53e2004-05-18 18:57:06 +0000298 ospf6_vertex_delete (v);
299 return -1;
300 }
301 else if (route && route->path.cost == v->cost)
302 {
hasso3b687352004-08-19 06:56:53 +0000303 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000304 zlog_debug (" another path found, merge");
hasso508e53e2004-05-18 18:57:06 +0000305
306 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
307 i < OSPF6_MULTI_PATH_LIMIT; i++)
308 {
309 for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
310 {
311 if (ospf6_nexthop_is_set (&route->nexthop[j]))
312 {
313 if (ospf6_nexthop_is_same (&route->nexthop[j],
314 &v->nexthop[i]))
315 break;
316 else
317 continue;
318 }
319 ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
320 break;
321 }
322 }
323
324 prev = (struct ospf6_vertex *) route->route_option;
Dmitrij Tejblum403138e2011-01-13 18:25:40 +0300325 assert (prev->hops <= v->hops);
326 ospf6_vertex_delete (v);
hasso508e53e2004-05-18 18:57:06 +0000327
328 return -1;
329 }
330
331 /* There should be no case where candidate being installed (variable
332 "v") is closer than the one in the SPF tree (variable "route").
hasso6452df02004-08-15 05:52:07 +0000333 In the case something has gone wrong with the behavior of
hasso508e53e2004-05-18 18:57:06 +0000334 Priority-Queue. */
hasso6452df02004-08-15 05:52:07 +0000335
336 /* the case where the route exists already is handled and returned
337 up to here. */
hasso508e53e2004-05-18 18:57:06 +0000338 assert (route == NULL);
339
340 route = ospf6_route_create ();
341 memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
342 route->type = OSPF6_DEST_TYPE_LINKSTATE;
343 route->path.type = OSPF6_PATH_TYPE_INTRA;
344 route->path.origin.type = v->lsa->header->type;
345 route->path.origin.id = v->lsa->header->id;
346 route->path.origin.adv_router = v->lsa->header->adv_router;
347 route->path.metric_type = 1;
348 route->path.cost = v->cost;
349 route->path.cost_e2 = v->hops;
350 route->path.router_bits = v->capability;
351 route->path.options[0] = v->options[0];
352 route->path.options[1] = v->options[1];
353 route->path.options[2] = v->options[2];
354
355 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
356 i < OSPF6_MULTI_PATH_LIMIT; i++)
357 ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
358
359 if (v->parent)
360 listnode_add_sort (v->parent->child_list, v);
361 route->route_option = v;
362
363 ospf6_route_add (route, result_table);
paul718e3742002-12-13 20:15:29 +0000364 return 0;
365}
366
hasso508e53e2004-05-18 18:57:06 +0000367void
368ospf6_spf_table_finish (struct ospf6_route_table *result_table)
369{
370 struct ospf6_route *route;
371 struct ospf6_vertex *v;
372 for (route = ospf6_route_head (result_table); route;
373 route = ospf6_route_next (route))
374 {
375 v = (struct ospf6_vertex *) route->route_option;
376 ospf6_vertex_delete (v);
377 ospf6_route_remove (route, result_table);
378 }
379}
380
Dinesh Dutta0edf672013-08-26 03:40:23 +0000381static const char *ospf6_spf_reason_str[] =
382 {
383 "R+",
384 "R-",
385 "N+",
386 "N-",
387 "L+",
388 "L-",
389 "R*",
390 "N*",
391 };
392
393void ospf6_spf_reason_string (unsigned int reason, char *buf, int size)
394{
Paul Jakma7aa9dce2014-09-19 14:42:23 +0100395 size_t bit;
Dinesh Dutta0edf672013-08-26 03:40:23 +0000396 int len = 0;
397
398 if (!buf)
399 return;
400
401 for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++)
402 {
403 if ((reason & (1 << bit)) && (len < size))
404 {
405 len += snprintf((buf + len), (size - len), "%s%s",
406 (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]);
407 }
408 }
409}
410
hasso6452df02004-08-15 05:52:07 +0000411/* RFC2328 16.1. Calculating the shortest-path tree for an area */
412/* RFC2740 3.8.1. Calculating the shortest path tree for an area */
hasso508e53e2004-05-18 18:57:06 +0000413void
414ospf6_spf_calculation (u_int32_t router_id,
415 struct ospf6_route_table *result_table,
416 struct ospf6_area *oa)
417{
418 struct pqueue *candidate_list;
419 struct ospf6_vertex *root, *v, *w;
420 int i;
421 int size;
422 caddr_t lsdesc;
423 struct ospf6_lsa *lsa;
424
Tom Goffb48cebb2011-12-14 14:11:29 +0400425 ospf6_spf_table_finish (result_table);
426
hasso508e53e2004-05-18 18:57:06 +0000427 /* Install the calculating router itself as the root of the SPF tree */
428 /* construct root vertex */
429 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
430 router_id, oa->lsdb);
431 if (lsa == NULL)
432 return;
Tom Goff1d192342010-11-10 13:02:38 -0800433
434 /* initialize */
435 candidate_list = pqueue_create ();
436 candidate_list->cmp = ospf6_vertex_cmp;
437
hasso508e53e2004-05-18 18:57:06 +0000438 root = ospf6_vertex_create (lsa);
439 root->area = oa;
440 root->cost = 0;
441 root->hops = 0;
hasso6452df02004-08-15 05:52:07 +0000442 root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
hasso508e53e2004-05-18 18:57:06 +0000443 inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
444
445 /* Actually insert root to the candidate-list as the only candidate */
446 pqueue_enqueue (root, candidate_list);
447
448 /* Iterate until candidate-list becomes empty */
449 while (candidate_list->size)
450 {
451 /* get closest candidate from priority queue */
452 v = pqueue_dequeue (candidate_list);
453
hasso6452df02004-08-15 05:52:07 +0000454 /* installing may result in merging or rejecting of the vertex */
hasso508e53e2004-05-18 18:57:06 +0000455 if (ospf6_spf_install (v, result_table) < 0)
456 continue;
457
Dinesh Duttf41b4a02013-08-24 08:00:37 +0000458 /* Skip overloaded routers */
459 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
460 ospf6_router_is_stub_router (v->lsa)))
461 continue;
462
hasso508e53e2004-05-18 18:57:06 +0000463 /* For each LS description in the just-added vertex V's LSA */
464 size = (VERTEX_IS_TYPE (ROUTER, v) ?
465 sizeof (struct ospf6_router_lsdesc) :
466 sizeof (struct ospf6_network_lsdesc));
467 for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
468 lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
469 {
470 lsa = ospf6_lsdesc_lsa (lsdesc, v);
471 if (lsa == NULL)
472 continue;
473
474 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
475 continue;
476
477 w = ospf6_vertex_create (lsa);
478 w->area = oa;
479 w->parent = v;
480 if (VERTEX_IS_TYPE (ROUTER, v))
481 {
482 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
483 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
484 }
485 else /* NETWORK */
486 {
487 w->cost = v->cost;
488 w->hops = v->hops + 1;
489 }
490
491 /* nexthop calculation */
492 if (w->hops == 0)
493 w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
494 else if (w->hops == 1 && v->hops == 0)
495 ospf6_nexthop_calc (w, v, lsdesc);
496 else
497 {
498 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
499 i < OSPF6_MULTI_PATH_LIMIT; i++)
500 ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
501 }
502
503 /* add new candidate to the candidate_list */
hasso3b687352004-08-19 06:56:53 +0000504 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000505 zlog_debug (" New candidate: %s hops %d cost %d",
506 w->name, w->hops, w->cost);
hasso508e53e2004-05-18 18:57:06 +0000507 pqueue_enqueue (w, candidate_list);
508 }
509 }
510
511 pqueue_delete (candidate_list);
Vincent Bernatea86e402012-06-04 10:29:49 +0200512
513 oa->spf_calculation++;
hasso508e53e2004-05-18 18:57:06 +0000514}
515
Paul Jakma6ac29a52008-08-15 13:45:30 +0100516static void
hasso2680aa22004-11-25 20:54:46 +0000517ospf6_spf_log_database (struct ospf6_area *oa)
518{
519 char *p, *end, buffer[256];
520 struct listnode *node;
521 struct ospf6_interface *oi;
522
523 p = buffer;
524 end = buffer + sizeof (buffer);
525
526 snprintf (p, end - p, "SPF on DB (#LSAs):");
527 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
528 snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
529 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
530
paul1eb8ef22005-04-07 07:30:20 +0000531 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
hasso2680aa22004-11-25 20:54:46 +0000532 {
hasso2680aa22004-11-25 20:54:46 +0000533 snprintf (p, end - p, " I/F %s: %d",
534 oi->interface->name, oi->lsdb->count);
535 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
536 }
537
hassoc6487d62004-12-24 06:00:11 +0000538 zlog_debug ("%s", buffer);
hasso2680aa22004-11-25 20:54:46 +0000539}
540
Paul Jakma6ac29a52008-08-15 13:45:30 +0100541static int
paul718e3742002-12-13 20:15:29 +0000542ospf6_spf_calculation_thread (struct thread *t)
543{
hasso508e53e2004-05-18 18:57:06 +0000544 struct ospf6_area *oa;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000545 struct ospf6 *ospf6;
hasso508e53e2004-05-18 18:57:06 +0000546 struct timeval start, end, runtime;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000547 struct listnode *node;
548 struct ospf6_route *route;
Dinesh Dutta0edf672013-08-26 03:40:23 +0000549 int areas_processed = 0;
550 char rbuf[32];
paul718e3742002-12-13 20:15:29 +0000551
Dinesh Dutt3810e062013-08-24 07:54:09 +0000552 ospf6 = (struct ospf6 *)THREAD_ARG (t);
553 ospf6->t_spf_calc = NULL;
paul718e3742002-12-13 20:15:29 +0000554
555 /* execute SPF calculation */
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900556 quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
Dinesh Dutt3810e062013-08-24 07:54:09 +0000557
558 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
559 {
560
561 if (oa == ospf6->backbone)
562 continue;
563
564 if (IS_OSPF6_DEBUG_SPF (PROCESS))
565 zlog_debug ("SPF calculation for Area %s", oa->name);
566 if (IS_OSPF6_DEBUG_SPF (DATABASE))
567 ospf6_spf_log_database (oa);
568
569 ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
570 ospf6_intra_route_calculation (oa);
571 ospf6_intra_brouter_calculation (oa);
Dinesh Dutta0edf672013-08-26 03:40:23 +0000572
573 areas_processed++;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000574 }
575
576 if (ospf6->backbone)
577 {
578 if (IS_OSPF6_DEBUG_SPF (PROCESS))
579 zlog_debug ("SPF calculation for Backbone area %s",
580 ospf6->backbone->name);
581 if (IS_OSPF6_DEBUG_SPF (DATABASE))
582 ospf6_spf_log_database(ospf6->backbone);
583
584 ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
585 ospf6->backbone);
586 ospf6_intra_route_calculation(ospf6->backbone);
587 ospf6_intra_brouter_calculation(ospf6->backbone);
Dinesh Dutta0edf672013-08-26 03:40:23 +0000588 areas_processed++;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000589 }
590
591 /* Redo summaries if required */
592 for (route = ospf6_route_head (ospf6->route_table); route;
593 route = ospf6_route_next (route))
594 ospf6_abr_originate_summary(route);
595
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900596 quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
hasso2680aa22004-11-25 20:54:46 +0000597 timersub (&end, &start, &runtime);
paul718e3742002-12-13 20:15:29 +0000598
Dinesh Dutt3810e062013-08-24 07:54:09 +0000599 ospf6->ts_spf_duration = runtime;
600
Dinesh Dutta0edf672013-08-26 03:40:23 +0000601 ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf));
602
hasso3b687352004-08-19 06:56:53 +0000603 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
David Lamparteref008d22015-03-03 08:48:11 +0100604 zlog_debug ("SPF runtime: %lld sec %lld usec",
605 (long long)runtime.tv_sec, (long long)runtime.tv_usec);
paul718e3742002-12-13 20:15:29 +0000606
David Lamparteref008d22015-03-03 08:48:11 +0100607 zlog_info("SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, "
608 "Reason: %s\n", areas_processed,
609 (long long)runtime.tv_sec, (long long)runtime.tv_usec,
Dinesh Dutta0edf672013-08-26 03:40:23 +0000610 rbuf);
611 ospf6->last_spf_reason = ospf6->spf_reason;
612 ospf6_reset_spf_reason(ospf6);
paul718e3742002-12-13 20:15:29 +0000613 return 0;
614}
615
Dinesh Dutt3810e062013-08-24 07:54:09 +0000616/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
617 set timer for SPF calc. */
paul718e3742002-12-13 20:15:29 +0000618void
Dinesh Dutta0edf672013-08-26 03:40:23 +0000619ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
paul718e3742002-12-13 20:15:29 +0000620{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000621 unsigned long delay, elapsed, ht;
622 struct timeval now, result;
623
Dinesh Dutta0edf672013-08-26 03:40:23 +0000624 ospf6_set_spf_reason(ospf6, reason);
625
Dinesh Dutt3810e062013-08-24 07:54:09 +0000626 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
Dinesh Dutta0edf672013-08-26 03:40:23 +0000627 {
628 char rbuf[32];
629 ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf));
630 zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf);
631 }
Dinesh Dutt3810e062013-08-24 07:54:09 +0000632
633 /* OSPF instance does not exist. */
634 if (ospf6 == NULL)
paul718e3742002-12-13 20:15:29 +0000635 return;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000636
637 /* SPF calculation timer is already scheduled. */
638 if (ospf6->t_spf_calc)
639 {
640 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
641 zlog_debug ("SPF: calculation timer is already scheduled: %p",
David Lampartereed3c482015-03-03 08:51:53 +0100642 (void *)ospf6->t_spf_calc);
Dinesh Dutt3810e062013-08-24 07:54:09 +0000643 return;
644 }
645
646 /* XXX Monotic timers: we only care about relative time here. */
647 now = recent_relative_time ();
648 timersub (&now, &ospf6->ts_spf, &result);
649
650 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
651 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
652
653 if (ht > ospf6->spf_max_holdtime)
654 ht = ospf6->spf_max_holdtime;
655
656 /* Get SPF calculation delay time. */
657 if (elapsed < ht)
658 {
659 /* Got an event within the hold time of last SPF. We need to
660 * increase the hold_multiplier, if it's not already at/past
661 * maximum value, and wasn't already increased..
662 */
663 if (ht < ospf6->spf_max_holdtime)
664 ospf6->spf_hold_multiplier++;
665
666 /* always honour the SPF initial delay */
667 if ( (ht - elapsed) < ospf6->spf_delay)
668 delay = ospf6->spf_delay;
669 else
670 delay = ht - elapsed;
671 }
672 else
673 {
674 /* Event is past required hold-time of last SPF */
675 delay = ospf6->spf_delay;
676 ospf6->spf_hold_multiplier = 1;
677 }
678
679 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
680 zlog_debug ("SPF: calculation timer delay = %ld", delay);
681
682 zlog_info ("SPF: Scheduled in %ld msec", delay);
683
684 ospf6->t_spf_calc =
685 thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
paul718e3742002-12-13 20:15:29 +0000686}
687
688void
paul0c083ee2004-10-10 12:54:58 +0000689ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
hasso508e53e2004-05-18 18:57:06 +0000690 struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000691{
paul1eb8ef22005-04-07 07:30:20 +0000692 struct listnode *node, *nnode;
hasso508e53e2004-05-18 18:57:06 +0000693 struct ospf6_vertex *c;
694 char *next_prefix;
695 int len;
paul718e3742002-12-13 20:15:29 +0000696 int restnum;
paul718e3742002-12-13 20:15:29 +0000697
hasso508e53e2004-05-18 18:57:06 +0000698 /* "prefix" is the space prefix of the display line */
hasso049207c2004-08-04 20:02:13 +0000699 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
paul718e3742002-12-13 20:15:29 +0000700
hasso508e53e2004-05-18 18:57:06 +0000701 len = strlen (prefix) + 4;
702 next_prefix = (char *) malloc (len);
703 if (next_prefix == NULL)
paul718e3742002-12-13 20:15:29 +0000704 {
hasso049207c2004-08-04 20:02:13 +0000705 vty_out (vty, "malloc failed%s", VNL);
paul718e3742002-12-13 20:15:29 +0000706 return;
707 }
hasso508e53e2004-05-18 18:57:06 +0000708 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
paul718e3742002-12-13 20:15:29 +0000709
hasso508e53e2004-05-18 18:57:06 +0000710 restnum = listcount (v->child_list);
paul1eb8ef22005-04-07 07:30:20 +0000711 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
paul718e3742002-12-13 20:15:29 +0000712 {
hasso508e53e2004-05-18 18:57:06 +0000713 restnum--;
714 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
paul718e3742002-12-13 20:15:29 +0000715 }
716
hasso508e53e2004-05-18 18:57:06 +0000717 free (next_prefix);
paul718e3742002-12-13 20:15:29 +0000718}
719
hasso3b687352004-08-19 06:56:53 +0000720DEFUN (debug_ospf6_spf_process,
721 debug_ospf6_spf_process_cmd,
722 "debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000723 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000724 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000725 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000726 "Debug Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000727 )
paul718e3742002-12-13 20:15:29 +0000728{
hasso508e53e2004-05-18 18:57:06 +0000729 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000730 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000731 OSPF6_DEBUG_SPF_ON (level);
paul718e3742002-12-13 20:15:29 +0000732 return CMD_SUCCESS;
733}
734
hasso3b687352004-08-19 06:56:53 +0000735DEFUN (debug_ospf6_spf_time,
736 debug_ospf6_spf_time_cmd,
737 "debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000738 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000739 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000740 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000741 "Measure time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000742 )
paul718e3742002-12-13 20:15:29 +0000743{
hasso508e53e2004-05-18 18:57:06 +0000744 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000745 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000746 OSPF6_DEBUG_SPF_ON (level);
747 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +0000748}
749
hasso2680aa22004-11-25 20:54:46 +0000750DEFUN (debug_ospf6_spf_database,
751 debug_ospf6_spf_database_cmd,
752 "debug ospf6 spf database",
753 DEBUG_STR
754 OSPF6_STR
755 "Debug SPF Calculation\n"
756 "Log number of LSAs at SPF Calculation time\n"
757 )
758{
759 unsigned char level = 0;
760 level = OSPF6_DEBUG_SPF_DATABASE;
761 OSPF6_DEBUG_SPF_ON (level);
762 return CMD_SUCCESS;
763}
764
hasso3b687352004-08-19 06:56:53 +0000765DEFUN (no_debug_ospf6_spf_process,
766 no_debug_ospf6_spf_process_cmd,
767 "no debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000768 NO_STR
769 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000770 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000771 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000772 "Quit Debugging Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000773 )
774{
775 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000776 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000777 OSPF6_DEBUG_SPF_OFF (level);
778 return CMD_SUCCESS;
779}
paul718e3742002-12-13 20:15:29 +0000780
hasso3b687352004-08-19 06:56:53 +0000781DEFUN (no_debug_ospf6_spf_time,
782 no_debug_ospf6_spf_time_cmd,
783 "no debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000784 NO_STR
785 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000786 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000787 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000788 "Quit Measuring time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000789 )
790{
791 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000792 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000793 OSPF6_DEBUG_SPF_OFF (level);
794 return CMD_SUCCESS;
795}
796
hasso2680aa22004-11-25 20:54:46 +0000797DEFUN (no_debug_ospf6_spf_database,
798 no_debug_ospf6_spf_database_cmd,
799 "no debug ospf6 spf database",
800 NO_STR
801 DEBUG_STR
802 OSPF6_STR
803 "Debug SPF Calculation\n"
804 "Quit Logging 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_OFF (level);
810 return CMD_SUCCESS;
811}
812
Dinesh Dutt3810e062013-08-24 07:54:09 +0000813static int
814ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
815 unsigned int hold,
816 unsigned int max)
817{
818 struct ospf6 *ospf = vty->index;
819
820 ospf->spf_delay = delay;
821 ospf->spf_holdtime = hold;
822 ospf->spf_max_holdtime = max;
823
824 return CMD_SUCCESS;
825}
826
827DEFUN (ospf6_timers_throttle_spf,
828 ospf6_timers_throttle_spf_cmd,
829 "timers throttle spf <0-600000> <0-600000> <0-600000>",
830 "Adjust routing timers\n"
831 "Throttling adaptive timer\n"
832 "OSPF6 SPF timers\n"
833 "Delay (msec) from first change received till SPF calculation\n"
834 "Initial hold time (msec) between consecutive SPF calculations\n"
835 "Maximum hold time (msec)\n")
836{
837 unsigned int delay, hold, max;
838
839 if (argc != 3)
840 {
841 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
842 return CMD_WARNING;
843 }
844
845 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
846 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
847 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
848
849 return ospf6_timers_spf_set (vty, delay, hold, max);
850}
851
852DEFUN (no_ospf6_timers_throttle_spf,
853 no_ospf6_timers_throttle_spf_cmd,
854 "no timers throttle spf",
855 NO_STR
856 "Adjust routing timers\n"
857 "Throttling adaptive timer\n"
858 "OSPF6 SPF timers\n")
859{
860 return ospf6_timers_spf_set (vty,
861 OSPF_SPF_DELAY_DEFAULT,
862 OSPF_SPF_HOLDTIME_DEFAULT,
863 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
864}
865
hasso508e53e2004-05-18 18:57:06 +0000866int
867config_write_ospf6_debug_spf (struct vty *vty)
868{
hasso3b687352004-08-19 06:56:53 +0000869 if (IS_OSPF6_DEBUG_SPF (PROCESS))
870 vty_out (vty, "debug ospf6 spf process%s", VNL);
871 if (IS_OSPF6_DEBUG_SPF (TIME))
872 vty_out (vty, "debug ospf6 spf time%s", VNL);
hasso2680aa22004-11-25 20:54:46 +0000873 if (IS_OSPF6_DEBUG_SPF (DATABASE))
874 vty_out (vty, "debug ospf6 spf database%s", VNL);
hasso508e53e2004-05-18 18:57:06 +0000875 return 0;
876}
877
878void
Dinesh Dutt3810e062013-08-24 07:54:09 +0000879ospf6_spf_config_write (struct vty *vty)
880{
881
882 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
883 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
884 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
885 vty_out (vty, " timers throttle spf %d %d %d%s",
886 ospf6->spf_delay, ospf6->spf_holdtime,
887 ospf6->spf_max_holdtime, VTY_NEWLINE);
888
889}
890
891void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100892install_element_ospf6_debug_spf (void)
hasso508e53e2004-05-18 18:57:06 +0000893{
hasso3b687352004-08-19 06:56:53 +0000894 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
895 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000896 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000897 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
898 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000899 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000900 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
901 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000902 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000903 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
904 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000905 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
hasso508e53e2004-05-18 18:57:06 +0000906}
paul718e3742002-12-13 20:15:29 +0000907
908void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100909ospf6_spf_init (void)
paul718e3742002-12-13 20:15:29 +0000910{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000911 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
912 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
paul718e3742002-12-13 20:15:29 +0000913}