blob: e4c424dbbb91c27df0a95183170c9d3532b9a41e [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"
paul718e3742002-12-13 20:15:29 +000043
hasso508e53e2004-05-18 18:57:06 +000044unsigned char conf_debug_ospf6_spf = 0;
paul718e3742002-12-13 20:15:29 +000045
Paul Jakma6ac29a52008-08-15 13:45:30 +010046static int
hasso508e53e2004-05-18 18:57:06 +000047ospf6_vertex_cmp (void *a, void *b)
paul718e3742002-12-13 20:15:29 +000048{
hasso508e53e2004-05-18 18:57:06 +000049 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
50 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
51
52 /* ascending order */
Dmitrij Tejblum403138e2011-01-13 18:25:40 +030053 if (va->cost != vb->cost)
54 return (va->cost - vb->cost);
55 return (va->hops - vb->hops);
paul718e3742002-12-13 20:15:29 +000056}
57
Paul Jakma6ac29a52008-08-15 13:45:30 +010058static int
hasso508e53e2004-05-18 18:57:06 +000059ospf6_vertex_id_cmp (void *a, void *b)
paul718e3742002-12-13 20:15:29 +000060{
hasso508e53e2004-05-18 18:57:06 +000061 struct ospf6_vertex *va = (struct ospf6_vertex *) a;
62 struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
63 int ret = 0;
paul718e3742002-12-13 20:15:29 +000064
hasso508e53e2004-05-18 18:57:06 +000065 ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
66 ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
67 if (ret)
68 return ret;
paul718e3742002-12-13 20:15:29 +000069
hasso508e53e2004-05-18 18:57:06 +000070 ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
71 ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
paul718e3742002-12-13 20:15:29 +000072 return ret;
73}
74
Paul Jakma6ac29a52008-08-15 13:45:30 +010075static struct ospf6_vertex *
hasso508e53e2004-05-18 18:57:06 +000076ospf6_vertex_create (struct ospf6_lsa *lsa)
77{
78 struct ospf6_vertex *v;
79 int i;
80
81 v = (struct ospf6_vertex *)
82 XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
83
84 /* type */
85 if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
86 v->type = OSPF6_VERTEX_TYPE_ROUTER;
87 else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
88 v->type = OSPF6_VERTEX_TYPE_NETWORK;
89 else
90 assert (0);
91
92 /* vertex_id */
93 ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
94 &v->vertex_id);
95
96 /* name */
97 ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
98
99 /* Associated LSA */
100 v->lsa = lsa;
101
102 /* capability bits + options */
103 v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
104 v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
105 v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
106 v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
107
108 for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
109 ospf6_nexthop_clear (&v->nexthop[i]);
110
111 v->parent = NULL;
112 v->child_list = list_new ();
113 v->child_list->cmp = ospf6_vertex_id_cmp;
114
115 return v;
116}
117
Paul Jakma6ac29a52008-08-15 13:45:30 +0100118static void
hasso508e53e2004-05-18 18:57:06 +0000119ospf6_vertex_delete (struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000120{
hasso508e53e2004-05-18 18:57:06 +0000121 list_delete (v->child_list);
paul718e3742002-12-13 20:15:29 +0000122 XFREE (MTYPE_OSPF6_VERTEX, v);
123}
124
Paul Jakma6ac29a52008-08-15 13:45:30 +0100125static struct ospf6_lsa *
hasso508e53e2004-05-18 18:57:06 +0000126ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000127{
paul718e3742002-12-13 20:15:29 +0000128 struct ospf6_lsa *lsa;
hasso508e53e2004-05-18 18:57:06 +0000129 u_int16_t type = 0;
130 u_int32_t id = 0, adv_router = 0;
paul718e3742002-12-13 20:15:29 +0000131
hasso508e53e2004-05-18 18:57:06 +0000132 if (VERTEX_IS_TYPE (NETWORK, v))
paul718e3742002-12-13 20:15:29 +0000133 {
hasso508e53e2004-05-18 18:57:06 +0000134 type = htons (OSPF6_LSTYPE_ROUTER);
135 id = htonl (0);
136 adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
paul718e3742002-12-13 20:15:29 +0000137 }
paul718e3742002-12-13 20:15:29 +0000138 else
paul718e3742002-12-13 20:15:29 +0000139 {
hasso508e53e2004-05-18 18:57:06 +0000140 if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
paul718e3742002-12-13 20:15:29 +0000141 {
hasso508e53e2004-05-18 18:57:06 +0000142 type = htons (OSPF6_LSTYPE_ROUTER);
143 id = htonl (0);
144 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
145 }
146 else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
147 {
148 type = htons (OSPF6_LSTYPE_NETWORK);
149 id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
150 adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
paul718e3742002-12-13 20:15:29 +0000151 }
152 }
153
hasso508e53e2004-05-18 18:57:06 +0000154 lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
paul718e3742002-12-13 20:15:29 +0000155
hasso3b687352004-08-19 06:56:53 +0000156 if (IS_OSPF6_DEBUG_SPF (PROCESS))
paul718e3742002-12-13 20:15:29 +0000157 {
hasso508e53e2004-05-18 18:57:06 +0000158 char ibuf[16], abuf[16];
159 inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
160 inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
161 if (lsa)
hassoc6487d62004-12-24 06:00:11 +0000162 zlog_debug (" Link to: %s", lsa->name);
hasso508e53e2004-05-18 18:57:06 +0000163 else
hassoc6487d62004-12-24 06:00:11 +0000164 zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA",
165 ospf6_lstype_name (type), ibuf, abuf);
paul718e3742002-12-13 20:15:29 +0000166 }
167
hasso508e53e2004-05-18 18:57:06 +0000168 return lsa;
169}
170
Paul Jakma6ac29a52008-08-15 13:45:30 +0100171static char *
hasso508e53e2004-05-18 18:57:06 +0000172ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
173 caddr_t lsdesc, struct ospf6_vertex *v)
174{
175 caddr_t backlink, found = NULL;
176 int size;
177
178 size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
179 sizeof (struct ospf6_router_lsdesc) :
180 sizeof (struct ospf6_network_lsdesc));
181 for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
182 backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
183 {
184 assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
185 VERTEX_IS_TYPE (NETWORK, v)));
186
187 if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
188 NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
189 == v->lsa->header->adv_router)
190 found = backlink;
191 else if (VERTEX_IS_TYPE (NETWORK, v) &&
192 ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
193 ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
194 == v->lsa->header->adv_router &&
195 ROUTER_LSDESC_GET_NBR_IFID (backlink)
196 == ntohl (v->lsa->header->id))
197 found = backlink;
198 else
199 {
200 if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
201 ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
202 continue;
203 if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
204 ROUTER_LSDESC_GET_IFID (lsdesc) ||
205 ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
206 ROUTER_LSDESC_GET_IFID (backlink))
207 continue;
208 if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
209 v->lsa->header->adv_router ||
210 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
211 lsa->header->adv_router)
212 continue;
213 found = backlink;
214 }
215 }
216
hasso3b687352004-08-19 06:56:53 +0000217 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000218 zlog_debug (" Backlink %s", (found ? "OK" : "FAIL"));
hasso508e53e2004-05-18 18:57:06 +0000219
220 return found;
221}
222
Paul Jakma6ac29a52008-08-15 13:45:30 +0100223static void
hasso508e53e2004-05-18 18:57:06 +0000224ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
225 caddr_t lsdesc)
226{
227 int i, ifindex;
228 struct ospf6_interface *oi;
229 u_int16_t type;
230 u_int32_t adv_router;
231 struct ospf6_lsa *lsa;
232 struct ospf6_link_lsa *link_lsa;
233 char buf[64];
234
235 assert (VERTEX_IS_TYPE (ROUTER, w));
236 ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
237 ROUTER_LSDESC_GET_IFID (lsdesc));
238 oi = ospf6_interface_lookup_by_ifindex (ifindex);
239 if (oi == NULL)
240 {
hasso3b687352004-08-19 06:56:53 +0000241 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000242 zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex);
hasso508e53e2004-05-18 18:57:06 +0000243 return;
244 }
245
246 type = htons (OSPF6_LSTYPE_LINK);
247 adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
248 NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
249 ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
250
251 i = 0;
252 for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
253 lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
254 {
255 if (VERTEX_IS_TYPE (ROUTER, v) &&
256 htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
257 continue;
258
259 link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
hasso3b687352004-08-19 06:56:53 +0000260 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hasso508e53e2004-05-18 18:57:06 +0000261 {
262 inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
hassoc6487d62004-12-24 06:00:11 +0000263 zlog_debug (" nexthop %s from %s", buf, lsa->name);
hasso508e53e2004-05-18 18:57:06 +0000264 }
265
266 if (i < OSPF6_MULTI_PATH_LIMIT)
267 {
268 memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
269 sizeof (struct in6_addr));
270 w->nexthop[i].ifindex = ifindex;
271 i++;
272 }
273 }
274
hasso3b687352004-08-19 06:56:53 +0000275 if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000276 zlog_debug ("No nexthop for %s found", w->name);
hasso508e53e2004-05-18 18:57:06 +0000277}
278
Paul Jakma6ac29a52008-08-15 13:45:30 +0100279static int
hasso508e53e2004-05-18 18:57:06 +0000280ospf6_spf_install (struct ospf6_vertex *v,
281 struct ospf6_route_table *result_table)
282{
283 struct ospf6_route *route;
284 int i, j;
Denis Ovsienko87362ce2011-08-27 22:19:34 +0400285 struct ospf6_vertex *prev;
hasso508e53e2004-05-18 18:57:06 +0000286
hasso3b687352004-08-19 06:56:53 +0000287 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000288 zlog_debug ("SPF install %s hops %d cost %d",
289 v->name, v->hops, v->cost);
hasso508e53e2004-05-18 18:57:06 +0000290
291 route = ospf6_route_lookup (&v->vertex_id, result_table);
292 if (route && route->path.cost < v->cost)
293 {
hasso3b687352004-08-19 06:56:53 +0000294 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000295 zlog_debug (" already installed with lower cost (%d), ignore",
296 route->path.cost);
hasso508e53e2004-05-18 18:57:06 +0000297 ospf6_vertex_delete (v);
298 return -1;
299 }
300 else if (route && route->path.cost == v->cost)
301 {
hasso3b687352004-08-19 06:56:53 +0000302 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000303 zlog_debug (" another path found, merge");
hasso508e53e2004-05-18 18:57:06 +0000304
305 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
306 i < OSPF6_MULTI_PATH_LIMIT; i++)
307 {
308 for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
309 {
310 if (ospf6_nexthop_is_set (&route->nexthop[j]))
311 {
312 if (ospf6_nexthop_is_same (&route->nexthop[j],
313 &v->nexthop[i]))
314 break;
315 else
316 continue;
317 }
318 ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
319 break;
320 }
321 }
322
323 prev = (struct ospf6_vertex *) route->route_option;
Dmitrij Tejblum403138e2011-01-13 18:25:40 +0300324 assert (prev->hops <= v->hops);
325 ospf6_vertex_delete (v);
hasso508e53e2004-05-18 18:57:06 +0000326
327 return -1;
328 }
329
330 /* There should be no case where candidate being installed (variable
331 "v") is closer than the one in the SPF tree (variable "route").
hasso6452df02004-08-15 05:52:07 +0000332 In the case something has gone wrong with the behavior of
hasso508e53e2004-05-18 18:57:06 +0000333 Priority-Queue. */
hasso6452df02004-08-15 05:52:07 +0000334
335 /* the case where the route exists already is handled and returned
336 up to here. */
hasso508e53e2004-05-18 18:57:06 +0000337 assert (route == NULL);
338
339 route = ospf6_route_create ();
340 memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
341 route->type = OSPF6_DEST_TYPE_LINKSTATE;
342 route->path.type = OSPF6_PATH_TYPE_INTRA;
343 route->path.origin.type = v->lsa->header->type;
344 route->path.origin.id = v->lsa->header->id;
345 route->path.origin.adv_router = v->lsa->header->adv_router;
346 route->path.metric_type = 1;
347 route->path.cost = v->cost;
348 route->path.cost_e2 = v->hops;
349 route->path.router_bits = v->capability;
350 route->path.options[0] = v->options[0];
351 route->path.options[1] = v->options[1];
352 route->path.options[2] = v->options[2];
353
354 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
355 i < OSPF6_MULTI_PATH_LIMIT; i++)
356 ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
357
358 if (v->parent)
359 listnode_add_sort (v->parent->child_list, v);
360 route->route_option = v;
361
362 ospf6_route_add (route, result_table);
paul718e3742002-12-13 20:15:29 +0000363 return 0;
364}
365
hasso508e53e2004-05-18 18:57:06 +0000366void
367ospf6_spf_table_finish (struct ospf6_route_table *result_table)
368{
369 struct ospf6_route *route;
370 struct ospf6_vertex *v;
371 for (route = ospf6_route_head (result_table); route;
372 route = ospf6_route_next (route))
373 {
374 v = (struct ospf6_vertex *) route->route_option;
375 ospf6_vertex_delete (v);
376 ospf6_route_remove (route, result_table);
377 }
378}
379
hasso6452df02004-08-15 05:52:07 +0000380/* RFC2328 16.1. Calculating the shortest-path tree for an area */
381/* RFC2740 3.8.1. Calculating the shortest path tree for an area */
hasso508e53e2004-05-18 18:57:06 +0000382void
383ospf6_spf_calculation (u_int32_t router_id,
384 struct ospf6_route_table *result_table,
385 struct ospf6_area *oa)
386{
387 struct pqueue *candidate_list;
388 struct ospf6_vertex *root, *v, *w;
389 int i;
390 int size;
391 caddr_t lsdesc;
392 struct ospf6_lsa *lsa;
393
Tom Goffb48cebb2011-12-14 14:11:29 +0400394 ospf6_spf_table_finish (result_table);
395
hasso508e53e2004-05-18 18:57:06 +0000396 /* Install the calculating router itself as the root of the SPF tree */
397 /* construct root vertex */
398 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
399 router_id, oa->lsdb);
400 if (lsa == NULL)
401 return;
Tom Goff1d192342010-11-10 13:02:38 -0800402
403 /* initialize */
404 candidate_list = pqueue_create ();
405 candidate_list->cmp = ospf6_vertex_cmp;
406
hasso508e53e2004-05-18 18:57:06 +0000407 root = ospf6_vertex_create (lsa);
408 root->area = oa;
409 root->cost = 0;
410 root->hops = 0;
hasso6452df02004-08-15 05:52:07 +0000411 root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
hasso508e53e2004-05-18 18:57:06 +0000412 inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
413
414 /* Actually insert root to the candidate-list as the only candidate */
415 pqueue_enqueue (root, candidate_list);
416
417 /* Iterate until candidate-list becomes empty */
418 while (candidate_list->size)
419 {
420 /* get closest candidate from priority queue */
421 v = pqueue_dequeue (candidate_list);
422
hasso6452df02004-08-15 05:52:07 +0000423 /* installing may result in merging or rejecting of the vertex */
hasso508e53e2004-05-18 18:57:06 +0000424 if (ospf6_spf_install (v, result_table) < 0)
425 continue;
426
427 /* For each LS description in the just-added vertex V's LSA */
428 size = (VERTEX_IS_TYPE (ROUTER, v) ?
429 sizeof (struct ospf6_router_lsdesc) :
430 sizeof (struct ospf6_network_lsdesc));
431 for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
432 lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
433 {
434 lsa = ospf6_lsdesc_lsa (lsdesc, v);
435 if (lsa == NULL)
436 continue;
437
438 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
439 continue;
440
441 w = ospf6_vertex_create (lsa);
442 w->area = oa;
443 w->parent = v;
444 if (VERTEX_IS_TYPE (ROUTER, v))
445 {
446 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
447 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
448 }
449 else /* NETWORK */
450 {
451 w->cost = v->cost;
452 w->hops = v->hops + 1;
453 }
454
455 /* nexthop calculation */
456 if (w->hops == 0)
457 w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
458 else if (w->hops == 1 && v->hops == 0)
459 ospf6_nexthop_calc (w, v, lsdesc);
460 else
461 {
462 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
463 i < OSPF6_MULTI_PATH_LIMIT; i++)
464 ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
465 }
466
467 /* add new candidate to the candidate_list */
hasso3b687352004-08-19 06:56:53 +0000468 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000469 zlog_debug (" New candidate: %s hops %d cost %d",
470 w->name, w->hops, w->cost);
hasso508e53e2004-05-18 18:57:06 +0000471 pqueue_enqueue (w, candidate_list);
472 }
473 }
474
475 pqueue_delete (candidate_list);
Vincent Bernatea86e402012-06-04 10:29:49 +0200476
477 oa->spf_calculation++;
hasso508e53e2004-05-18 18:57:06 +0000478}
479
Paul Jakma6ac29a52008-08-15 13:45:30 +0100480static void
hasso2680aa22004-11-25 20:54:46 +0000481ospf6_spf_log_database (struct ospf6_area *oa)
482{
483 char *p, *end, buffer[256];
484 struct listnode *node;
485 struct ospf6_interface *oi;
486
487 p = buffer;
488 end = buffer + sizeof (buffer);
489
490 snprintf (p, end - p, "SPF on DB (#LSAs):");
491 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
492 snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
493 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
494
paul1eb8ef22005-04-07 07:30:20 +0000495 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
hasso2680aa22004-11-25 20:54:46 +0000496 {
hasso2680aa22004-11-25 20:54:46 +0000497 snprintf (p, end - p, " I/F %s: %d",
498 oi->interface->name, oi->lsdb->count);
499 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
500 }
501
hassoc6487d62004-12-24 06:00:11 +0000502 zlog_debug ("%s", buffer);
hasso2680aa22004-11-25 20:54:46 +0000503}
504
Paul Jakma6ac29a52008-08-15 13:45:30 +0100505static int
paul718e3742002-12-13 20:15:29 +0000506ospf6_spf_calculation_thread (struct thread *t)
507{
hasso508e53e2004-05-18 18:57:06 +0000508 struct ospf6_area *oa;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000509 struct ospf6 *ospf6;
hasso508e53e2004-05-18 18:57:06 +0000510 struct timeval start, end, runtime;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000511 struct listnode *node;
512 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000513
Dinesh Dutt3810e062013-08-24 07:54:09 +0000514 ospf6 = (struct ospf6 *)THREAD_ARG (t);
515 ospf6->t_spf_calc = NULL;
paul718e3742002-12-13 20:15:29 +0000516
517 /* execute SPF calculation */
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900518 quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
Dinesh Dutt3810e062013-08-24 07:54:09 +0000519
520 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
521 {
522
523 if (oa == ospf6->backbone)
524 continue;
525
526 if (IS_OSPF6_DEBUG_SPF (PROCESS))
527 zlog_debug ("SPF calculation for Area %s", oa->name);
528 if (IS_OSPF6_DEBUG_SPF (DATABASE))
529 ospf6_spf_log_database (oa);
530
531 ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
532 ospf6_intra_route_calculation (oa);
533 ospf6_intra_brouter_calculation (oa);
534 }
535
536 if (ospf6->backbone)
537 {
538 if (IS_OSPF6_DEBUG_SPF (PROCESS))
539 zlog_debug ("SPF calculation for Backbone area %s",
540 ospf6->backbone->name);
541 if (IS_OSPF6_DEBUG_SPF (DATABASE))
542 ospf6_spf_log_database(ospf6->backbone);
543
544 ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
545 ospf6->backbone);
546 ospf6_intra_route_calculation(ospf6->backbone);
547 ospf6_intra_brouter_calculation(ospf6->backbone);
548 }
549
550 /* Redo summaries if required */
551 for (route = ospf6_route_head (ospf6->route_table); route;
552 route = ospf6_route_next (route))
553 ospf6_abr_originate_summary(route);
554
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900555 quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
hasso2680aa22004-11-25 20:54:46 +0000556 timersub (&end, &start, &runtime);
paul718e3742002-12-13 20:15:29 +0000557
Dinesh Dutt3810e062013-08-24 07:54:09 +0000558 ospf6->ts_spf_duration = runtime;
559
hasso3b687352004-08-19 06:56:53 +0000560 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
hassoc6487d62004-12-24 06:00:11 +0000561 zlog_debug ("SPF runtime: %ld sec %ld usec",
562 runtime.tv_sec, runtime.tv_usec);
paul718e3742002-12-13 20:15:29 +0000563
paul718e3742002-12-13 20:15:29 +0000564 return 0;
565}
566
Dinesh Dutt3810e062013-08-24 07:54:09 +0000567/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
568 set timer for SPF calc. */
paul718e3742002-12-13 20:15:29 +0000569void
Dinesh Dutt3810e062013-08-24 07:54:09 +0000570ospf6_spf_schedule (struct ospf6 *ospf6)
paul718e3742002-12-13 20:15:29 +0000571{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000572 unsigned long delay, elapsed, ht;
573 struct timeval now, result;
574
575 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
576 zlog_debug ("SPF: calculation timer scheduled");
577
578 /* OSPF instance does not exist. */
579 if (ospf6 == NULL)
paul718e3742002-12-13 20:15:29 +0000580 return;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000581
582 /* SPF calculation timer is already scheduled. */
583 if (ospf6->t_spf_calc)
584 {
585 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
586 zlog_debug ("SPF: calculation timer is already scheduled: %p",
587 ospf6->t_spf_calc);
588 return;
589 }
590
591 /* XXX Monotic timers: we only care about relative time here. */
592 now = recent_relative_time ();
593 timersub (&now, &ospf6->ts_spf, &result);
594
595 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
596 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
597
598 if (ht > ospf6->spf_max_holdtime)
599 ht = ospf6->spf_max_holdtime;
600
601 /* Get SPF calculation delay time. */
602 if (elapsed < ht)
603 {
604 /* Got an event within the hold time of last SPF. We need to
605 * increase the hold_multiplier, if it's not already at/past
606 * maximum value, and wasn't already increased..
607 */
608 if (ht < ospf6->spf_max_holdtime)
609 ospf6->spf_hold_multiplier++;
610
611 /* always honour the SPF initial delay */
612 if ( (ht - elapsed) < ospf6->spf_delay)
613 delay = ospf6->spf_delay;
614 else
615 delay = ht - elapsed;
616 }
617 else
618 {
619 /* Event is past required hold-time of last SPF */
620 delay = ospf6->spf_delay;
621 ospf6->spf_hold_multiplier = 1;
622 }
623
624 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
625 zlog_debug ("SPF: calculation timer delay = %ld", delay);
626
627 zlog_info ("SPF: Scheduled in %ld msec", delay);
628
629 ospf6->t_spf_calc =
630 thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
paul718e3742002-12-13 20:15:29 +0000631}
632
633void
paul0c083ee2004-10-10 12:54:58 +0000634ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
hasso508e53e2004-05-18 18:57:06 +0000635 struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000636{
paul1eb8ef22005-04-07 07:30:20 +0000637 struct listnode *node, *nnode;
hasso508e53e2004-05-18 18:57:06 +0000638 struct ospf6_vertex *c;
639 char *next_prefix;
640 int len;
paul718e3742002-12-13 20:15:29 +0000641 int restnum;
paul718e3742002-12-13 20:15:29 +0000642
hasso508e53e2004-05-18 18:57:06 +0000643 /* "prefix" is the space prefix of the display line */
hasso049207c2004-08-04 20:02:13 +0000644 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
paul718e3742002-12-13 20:15:29 +0000645
hasso508e53e2004-05-18 18:57:06 +0000646 len = strlen (prefix) + 4;
647 next_prefix = (char *) malloc (len);
648 if (next_prefix == NULL)
paul718e3742002-12-13 20:15:29 +0000649 {
hasso049207c2004-08-04 20:02:13 +0000650 vty_out (vty, "malloc failed%s", VNL);
paul718e3742002-12-13 20:15:29 +0000651 return;
652 }
hasso508e53e2004-05-18 18:57:06 +0000653 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
paul718e3742002-12-13 20:15:29 +0000654
hasso508e53e2004-05-18 18:57:06 +0000655 restnum = listcount (v->child_list);
paul1eb8ef22005-04-07 07:30:20 +0000656 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
paul718e3742002-12-13 20:15:29 +0000657 {
hasso508e53e2004-05-18 18:57:06 +0000658 restnum--;
659 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
paul718e3742002-12-13 20:15:29 +0000660 }
661
hasso508e53e2004-05-18 18:57:06 +0000662 free (next_prefix);
paul718e3742002-12-13 20:15:29 +0000663}
664
hasso3b687352004-08-19 06:56:53 +0000665DEFUN (debug_ospf6_spf_process,
666 debug_ospf6_spf_process_cmd,
667 "debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000668 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000669 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000670 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000671 "Debug Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000672 )
paul718e3742002-12-13 20:15:29 +0000673{
hasso508e53e2004-05-18 18:57:06 +0000674 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000675 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000676 OSPF6_DEBUG_SPF_ON (level);
paul718e3742002-12-13 20:15:29 +0000677 return CMD_SUCCESS;
678}
679
hasso3b687352004-08-19 06:56:53 +0000680DEFUN (debug_ospf6_spf_time,
681 debug_ospf6_spf_time_cmd,
682 "debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000683 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000684 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000685 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000686 "Measure time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000687 )
paul718e3742002-12-13 20:15:29 +0000688{
hasso508e53e2004-05-18 18:57:06 +0000689 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000690 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000691 OSPF6_DEBUG_SPF_ON (level);
692 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +0000693}
694
hasso2680aa22004-11-25 20:54:46 +0000695DEFUN (debug_ospf6_spf_database,
696 debug_ospf6_spf_database_cmd,
697 "debug ospf6 spf database",
698 DEBUG_STR
699 OSPF6_STR
700 "Debug SPF Calculation\n"
701 "Log number of LSAs at SPF Calculation time\n"
702 )
703{
704 unsigned char level = 0;
705 level = OSPF6_DEBUG_SPF_DATABASE;
706 OSPF6_DEBUG_SPF_ON (level);
707 return CMD_SUCCESS;
708}
709
hasso3b687352004-08-19 06:56:53 +0000710DEFUN (no_debug_ospf6_spf_process,
711 no_debug_ospf6_spf_process_cmd,
712 "no debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000713 NO_STR
714 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000715 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000716 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000717 "Quit Debugging Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000718 )
719{
720 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000721 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000722 OSPF6_DEBUG_SPF_OFF (level);
723 return CMD_SUCCESS;
724}
paul718e3742002-12-13 20:15:29 +0000725
hasso3b687352004-08-19 06:56:53 +0000726DEFUN (no_debug_ospf6_spf_time,
727 no_debug_ospf6_spf_time_cmd,
728 "no debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000729 NO_STR
730 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000731 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000732 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000733 "Quit Measuring time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000734 )
735{
736 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000737 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000738 OSPF6_DEBUG_SPF_OFF (level);
739 return CMD_SUCCESS;
740}
741
hasso2680aa22004-11-25 20:54:46 +0000742DEFUN (no_debug_ospf6_spf_database,
743 no_debug_ospf6_spf_database_cmd,
744 "no debug ospf6 spf database",
745 NO_STR
746 DEBUG_STR
747 OSPF6_STR
748 "Debug SPF Calculation\n"
749 "Quit Logging number of LSAs at SPF Calculation time\n"
750 )
751{
752 unsigned char level = 0;
753 level = OSPF6_DEBUG_SPF_DATABASE;
754 OSPF6_DEBUG_SPF_OFF (level);
755 return CMD_SUCCESS;
756}
757
Dinesh Dutt3810e062013-08-24 07:54:09 +0000758static int
759ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
760 unsigned int hold,
761 unsigned int max)
762{
763 struct ospf6 *ospf = vty->index;
764
765 ospf->spf_delay = delay;
766 ospf->spf_holdtime = hold;
767 ospf->spf_max_holdtime = max;
768
769 return CMD_SUCCESS;
770}
771
772DEFUN (ospf6_timers_throttle_spf,
773 ospf6_timers_throttle_spf_cmd,
774 "timers throttle spf <0-600000> <0-600000> <0-600000>",
775 "Adjust routing timers\n"
776 "Throttling adaptive timer\n"
777 "OSPF6 SPF timers\n"
778 "Delay (msec) from first change received till SPF calculation\n"
779 "Initial hold time (msec) between consecutive SPF calculations\n"
780 "Maximum hold time (msec)\n")
781{
782 unsigned int delay, hold, max;
783
784 if (argc != 3)
785 {
786 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
787 return CMD_WARNING;
788 }
789
790 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
791 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
792 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
793
794 return ospf6_timers_spf_set (vty, delay, hold, max);
795}
796
797DEFUN (no_ospf6_timers_throttle_spf,
798 no_ospf6_timers_throttle_spf_cmd,
799 "no timers throttle spf",
800 NO_STR
801 "Adjust routing timers\n"
802 "Throttling adaptive timer\n"
803 "OSPF6 SPF timers\n")
804{
805 return ospf6_timers_spf_set (vty,
806 OSPF_SPF_DELAY_DEFAULT,
807 OSPF_SPF_HOLDTIME_DEFAULT,
808 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
809}
810
hasso508e53e2004-05-18 18:57:06 +0000811int
812config_write_ospf6_debug_spf (struct vty *vty)
813{
hasso3b687352004-08-19 06:56:53 +0000814 if (IS_OSPF6_DEBUG_SPF (PROCESS))
815 vty_out (vty, "debug ospf6 spf process%s", VNL);
816 if (IS_OSPF6_DEBUG_SPF (TIME))
817 vty_out (vty, "debug ospf6 spf time%s", VNL);
hasso2680aa22004-11-25 20:54:46 +0000818 if (IS_OSPF6_DEBUG_SPF (DATABASE))
819 vty_out (vty, "debug ospf6 spf database%s", VNL);
hasso508e53e2004-05-18 18:57:06 +0000820 return 0;
821}
822
823void
Dinesh Dutt3810e062013-08-24 07:54:09 +0000824ospf6_spf_config_write (struct vty *vty)
825{
826
827 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
828 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
829 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
830 vty_out (vty, " timers throttle spf %d %d %d%s",
831 ospf6->spf_delay, ospf6->spf_holdtime,
832 ospf6->spf_max_holdtime, VTY_NEWLINE);
833
834}
835
836void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100837install_element_ospf6_debug_spf (void)
hasso508e53e2004-05-18 18:57:06 +0000838{
hasso3b687352004-08-19 06:56:53 +0000839 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
840 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000841 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000842 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
843 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000844 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000845 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
846 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000847 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000848 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
849 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000850 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
hasso508e53e2004-05-18 18:57:06 +0000851}
paul718e3742002-12-13 20:15:29 +0000852
853void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100854ospf6_spf_init (void)
paul718e3742002-12-13 20:15:29 +0000855{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000856 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
857 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
paul718e3742002-12-13 20:15:29 +0000858}