blob: 845e206c4a4d0c06fc8994357e71b90d367ab68e [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
Dinesh Duttf41b4a02013-08-24 08:00:37 +0000427 /* Skip overloaded routers */
428 if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) &&
429 ospf6_router_is_stub_router (v->lsa)))
430 continue;
431
hasso508e53e2004-05-18 18:57:06 +0000432 /* For each LS description in the just-added vertex V's LSA */
433 size = (VERTEX_IS_TYPE (ROUTER, v) ?
434 sizeof (struct ospf6_router_lsdesc) :
435 sizeof (struct ospf6_network_lsdesc));
436 for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
437 lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
438 {
439 lsa = ospf6_lsdesc_lsa (lsdesc, v);
440 if (lsa == NULL)
441 continue;
442
443 if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
444 continue;
445
446 w = ospf6_vertex_create (lsa);
447 w->area = oa;
448 w->parent = v;
449 if (VERTEX_IS_TYPE (ROUTER, v))
450 {
451 w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
452 w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
453 }
454 else /* NETWORK */
455 {
456 w->cost = v->cost;
457 w->hops = v->hops + 1;
458 }
459
460 /* nexthop calculation */
461 if (w->hops == 0)
462 w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
463 else if (w->hops == 1 && v->hops == 0)
464 ospf6_nexthop_calc (w, v, lsdesc);
465 else
466 {
467 for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
468 i < OSPF6_MULTI_PATH_LIMIT; i++)
469 ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
470 }
471
472 /* add new candidate to the candidate_list */
hasso3b687352004-08-19 06:56:53 +0000473 if (IS_OSPF6_DEBUG_SPF (PROCESS))
hassoc6487d62004-12-24 06:00:11 +0000474 zlog_debug (" New candidate: %s hops %d cost %d",
475 w->name, w->hops, w->cost);
hasso508e53e2004-05-18 18:57:06 +0000476 pqueue_enqueue (w, candidate_list);
477 }
478 }
479
480 pqueue_delete (candidate_list);
Vincent Bernatea86e402012-06-04 10:29:49 +0200481
482 oa->spf_calculation++;
hasso508e53e2004-05-18 18:57:06 +0000483}
484
Paul Jakma6ac29a52008-08-15 13:45:30 +0100485static void
hasso2680aa22004-11-25 20:54:46 +0000486ospf6_spf_log_database (struct ospf6_area *oa)
487{
488 char *p, *end, buffer[256];
489 struct listnode *node;
490 struct ospf6_interface *oi;
491
492 p = buffer;
493 end = buffer + sizeof (buffer);
494
495 snprintf (p, end - p, "SPF on DB (#LSAs):");
496 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
497 snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count);
498 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
499
paul1eb8ef22005-04-07 07:30:20 +0000500 for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi))
hasso2680aa22004-11-25 20:54:46 +0000501 {
hasso2680aa22004-11-25 20:54:46 +0000502 snprintf (p, end - p, " I/F %s: %d",
503 oi->interface->name, oi->lsdb->count);
504 p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end);
505 }
506
hassoc6487d62004-12-24 06:00:11 +0000507 zlog_debug ("%s", buffer);
hasso2680aa22004-11-25 20:54:46 +0000508}
509
Paul Jakma6ac29a52008-08-15 13:45:30 +0100510static int
paul718e3742002-12-13 20:15:29 +0000511ospf6_spf_calculation_thread (struct thread *t)
512{
hasso508e53e2004-05-18 18:57:06 +0000513 struct ospf6_area *oa;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000514 struct ospf6 *ospf6;
hasso508e53e2004-05-18 18:57:06 +0000515 struct timeval start, end, runtime;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000516 struct listnode *node;
517 struct ospf6_route *route;
paul718e3742002-12-13 20:15:29 +0000518
Dinesh Dutt3810e062013-08-24 07:54:09 +0000519 ospf6 = (struct ospf6 *)THREAD_ARG (t);
520 ospf6->t_spf_calc = NULL;
paul718e3742002-12-13 20:15:29 +0000521
522 /* execute SPF calculation */
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900523 quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
Dinesh Dutt3810e062013-08-24 07:54:09 +0000524
525 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa))
526 {
527
528 if (oa == ospf6->backbone)
529 continue;
530
531 if (IS_OSPF6_DEBUG_SPF (PROCESS))
532 zlog_debug ("SPF calculation for Area %s", oa->name);
533 if (IS_OSPF6_DEBUG_SPF (DATABASE))
534 ospf6_spf_log_database (oa);
535
536 ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa);
537 ospf6_intra_route_calculation (oa);
538 ospf6_intra_brouter_calculation (oa);
539 }
540
541 if (ospf6->backbone)
542 {
543 if (IS_OSPF6_DEBUG_SPF (PROCESS))
544 zlog_debug ("SPF calculation for Backbone area %s",
545 ospf6->backbone->name);
546 if (IS_OSPF6_DEBUG_SPF (DATABASE))
547 ospf6_spf_log_database(ospf6->backbone);
548
549 ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table,
550 ospf6->backbone);
551 ospf6_intra_route_calculation(ospf6->backbone);
552 ospf6_intra_brouter_calculation(ospf6->backbone);
553 }
554
555 /* Redo summaries if required */
556 for (route = ospf6_route_head (ospf6->route_table); route;
557 route = ospf6_route_next (route))
558 ospf6_abr_originate_summary(route);
559
Takashi Sogabe86f72dc2009-06-22 13:07:02 +0900560 quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
hasso2680aa22004-11-25 20:54:46 +0000561 timersub (&end, &start, &runtime);
paul718e3742002-12-13 20:15:29 +0000562
Dinesh Dutt3810e062013-08-24 07:54:09 +0000563 ospf6->ts_spf_duration = runtime;
564
hasso3b687352004-08-19 06:56:53 +0000565 if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
hassoc6487d62004-12-24 06:00:11 +0000566 zlog_debug ("SPF runtime: %ld sec %ld usec",
567 runtime.tv_sec, runtime.tv_usec);
paul718e3742002-12-13 20:15:29 +0000568
paul718e3742002-12-13 20:15:29 +0000569 return 0;
570}
571
Dinesh Dutt3810e062013-08-24 07:54:09 +0000572/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
573 set timer for SPF calc. */
paul718e3742002-12-13 20:15:29 +0000574void
Dinesh Dutt3810e062013-08-24 07:54:09 +0000575ospf6_spf_schedule (struct ospf6 *ospf6)
paul718e3742002-12-13 20:15:29 +0000576{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000577 unsigned long delay, elapsed, ht;
578 struct timeval now, result;
579
580 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
581 zlog_debug ("SPF: calculation timer scheduled");
582
583 /* OSPF instance does not exist. */
584 if (ospf6 == NULL)
paul718e3742002-12-13 20:15:29 +0000585 return;
Dinesh Dutt3810e062013-08-24 07:54:09 +0000586
587 /* SPF calculation timer is already scheduled. */
588 if (ospf6->t_spf_calc)
589 {
590 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
591 zlog_debug ("SPF: calculation timer is already scheduled: %p",
592 ospf6->t_spf_calc);
593 return;
594 }
595
596 /* XXX Monotic timers: we only care about relative time here. */
597 now = recent_relative_time ();
598 timersub (&now, &ospf6->ts_spf, &result);
599
600 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
601 ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
602
603 if (ht > ospf6->spf_max_holdtime)
604 ht = ospf6->spf_max_holdtime;
605
606 /* Get SPF calculation delay time. */
607 if (elapsed < ht)
608 {
609 /* Got an event within the hold time of last SPF. We need to
610 * increase the hold_multiplier, if it's not already at/past
611 * maximum value, and wasn't already increased..
612 */
613 if (ht < ospf6->spf_max_holdtime)
614 ospf6->spf_hold_multiplier++;
615
616 /* always honour the SPF initial delay */
617 if ( (ht - elapsed) < ospf6->spf_delay)
618 delay = ospf6->spf_delay;
619 else
620 delay = ht - elapsed;
621 }
622 else
623 {
624 /* Event is past required hold-time of last SPF */
625 delay = ospf6->spf_delay;
626 ospf6->spf_hold_multiplier = 1;
627 }
628
629 if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME))
630 zlog_debug ("SPF: calculation timer delay = %ld", delay);
631
632 zlog_info ("SPF: Scheduled in %ld msec", delay);
633
634 ospf6->t_spf_calc =
635 thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay);
paul718e3742002-12-13 20:15:29 +0000636}
637
638void
paul0c083ee2004-10-10 12:54:58 +0000639ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest,
hasso508e53e2004-05-18 18:57:06 +0000640 struct ospf6_vertex *v)
paul718e3742002-12-13 20:15:29 +0000641{
paul1eb8ef22005-04-07 07:30:20 +0000642 struct listnode *node, *nnode;
hasso508e53e2004-05-18 18:57:06 +0000643 struct ospf6_vertex *c;
644 char *next_prefix;
645 int len;
paul718e3742002-12-13 20:15:29 +0000646 int restnum;
paul718e3742002-12-13 20:15:29 +0000647
hasso508e53e2004-05-18 18:57:06 +0000648 /* "prefix" is the space prefix of the display line */
hasso049207c2004-08-04 20:02:13 +0000649 vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL);
paul718e3742002-12-13 20:15:29 +0000650
hasso508e53e2004-05-18 18:57:06 +0000651 len = strlen (prefix) + 4;
652 next_prefix = (char *) malloc (len);
653 if (next_prefix == NULL)
paul718e3742002-12-13 20:15:29 +0000654 {
hasso049207c2004-08-04 20:02:13 +0000655 vty_out (vty, "malloc failed%s", VNL);
paul718e3742002-12-13 20:15:29 +0000656 return;
657 }
hasso508e53e2004-05-18 18:57:06 +0000658 snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " "));
paul718e3742002-12-13 20:15:29 +0000659
hasso508e53e2004-05-18 18:57:06 +0000660 restnum = listcount (v->child_list);
paul1eb8ef22005-04-07 07:30:20 +0000661 for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c))
paul718e3742002-12-13 20:15:29 +0000662 {
hasso508e53e2004-05-18 18:57:06 +0000663 restnum--;
664 ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
paul718e3742002-12-13 20:15:29 +0000665 }
666
hasso508e53e2004-05-18 18:57:06 +0000667 free (next_prefix);
paul718e3742002-12-13 20:15:29 +0000668}
669
hasso3b687352004-08-19 06:56:53 +0000670DEFUN (debug_ospf6_spf_process,
671 debug_ospf6_spf_process_cmd,
672 "debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000673 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000674 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000675 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000676 "Debug Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000677 )
paul718e3742002-12-13 20:15:29 +0000678{
hasso508e53e2004-05-18 18:57:06 +0000679 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000680 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000681 OSPF6_DEBUG_SPF_ON (level);
paul718e3742002-12-13 20:15:29 +0000682 return CMD_SUCCESS;
683}
684
hasso3b687352004-08-19 06:56:53 +0000685DEFUN (debug_ospf6_spf_time,
686 debug_ospf6_spf_time_cmd,
687 "debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000688 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000689 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000690 "Debug SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000691 "Measure time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000692 )
paul718e3742002-12-13 20:15:29 +0000693{
hasso508e53e2004-05-18 18:57:06 +0000694 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000695 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000696 OSPF6_DEBUG_SPF_ON (level);
697 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +0000698}
699
hasso2680aa22004-11-25 20:54:46 +0000700DEFUN (debug_ospf6_spf_database,
701 debug_ospf6_spf_database_cmd,
702 "debug ospf6 spf database",
703 DEBUG_STR
704 OSPF6_STR
705 "Debug SPF Calculation\n"
706 "Log number of LSAs at SPF Calculation time\n"
707 )
708{
709 unsigned char level = 0;
710 level = OSPF6_DEBUG_SPF_DATABASE;
711 OSPF6_DEBUG_SPF_ON (level);
712 return CMD_SUCCESS;
713}
714
hasso3b687352004-08-19 06:56:53 +0000715DEFUN (no_debug_ospf6_spf_process,
716 no_debug_ospf6_spf_process_cmd,
717 "no debug ospf6 spf process",
hasso508e53e2004-05-18 18:57:06 +0000718 NO_STR
719 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000720 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000721 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000722 "Quit Debugging Detailed SPF Process\n"
hasso508e53e2004-05-18 18:57:06 +0000723 )
724{
725 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000726 level = OSPF6_DEBUG_SPF_PROCESS;
hasso508e53e2004-05-18 18:57:06 +0000727 OSPF6_DEBUG_SPF_OFF (level);
728 return CMD_SUCCESS;
729}
paul718e3742002-12-13 20:15:29 +0000730
hasso3b687352004-08-19 06:56:53 +0000731DEFUN (no_debug_ospf6_spf_time,
732 no_debug_ospf6_spf_time_cmd,
733 "no debug ospf6 spf time",
hasso508e53e2004-05-18 18:57:06 +0000734 NO_STR
735 DEBUG_STR
paul718e3742002-12-13 20:15:29 +0000736 OSPF6_STR
hasso508e53e2004-05-18 18:57:06 +0000737 "Quit Debugging SPF Calculation\n"
hasso3b687352004-08-19 06:56:53 +0000738 "Quit Measuring time taken by SPF Calculation\n"
hasso508e53e2004-05-18 18:57:06 +0000739 )
740{
741 unsigned char level = 0;
hasso3b687352004-08-19 06:56:53 +0000742 level = OSPF6_DEBUG_SPF_TIME;
hasso508e53e2004-05-18 18:57:06 +0000743 OSPF6_DEBUG_SPF_OFF (level);
744 return CMD_SUCCESS;
745}
746
hasso2680aa22004-11-25 20:54:46 +0000747DEFUN (no_debug_ospf6_spf_database,
748 no_debug_ospf6_spf_database_cmd,
749 "no debug ospf6 spf database",
750 NO_STR
751 DEBUG_STR
752 OSPF6_STR
753 "Debug SPF Calculation\n"
754 "Quit Logging number of LSAs at SPF Calculation time\n"
755 )
756{
757 unsigned char level = 0;
758 level = OSPF6_DEBUG_SPF_DATABASE;
759 OSPF6_DEBUG_SPF_OFF (level);
760 return CMD_SUCCESS;
761}
762
Dinesh Dutt3810e062013-08-24 07:54:09 +0000763static int
764ospf6_timers_spf_set (struct vty *vty, unsigned int delay,
765 unsigned int hold,
766 unsigned int max)
767{
768 struct ospf6 *ospf = vty->index;
769
770 ospf->spf_delay = delay;
771 ospf->spf_holdtime = hold;
772 ospf->spf_max_holdtime = max;
773
774 return CMD_SUCCESS;
775}
776
777DEFUN (ospf6_timers_throttle_spf,
778 ospf6_timers_throttle_spf_cmd,
779 "timers throttle spf <0-600000> <0-600000> <0-600000>",
780 "Adjust routing timers\n"
781 "Throttling adaptive timer\n"
782 "OSPF6 SPF timers\n"
783 "Delay (msec) from first change received till SPF calculation\n"
784 "Initial hold time (msec) between consecutive SPF calculations\n"
785 "Maximum hold time (msec)\n")
786{
787 unsigned int delay, hold, max;
788
789 if (argc != 3)
790 {
791 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
792 return CMD_WARNING;
793 }
794
795 VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000);
796 VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000);
797 VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000);
798
799 return ospf6_timers_spf_set (vty, delay, hold, max);
800}
801
802DEFUN (no_ospf6_timers_throttle_spf,
803 no_ospf6_timers_throttle_spf_cmd,
804 "no timers throttle spf",
805 NO_STR
806 "Adjust routing timers\n"
807 "Throttling adaptive timer\n"
808 "OSPF6 SPF timers\n")
809{
810 return ospf6_timers_spf_set (vty,
811 OSPF_SPF_DELAY_DEFAULT,
812 OSPF_SPF_HOLDTIME_DEFAULT,
813 OSPF_SPF_MAX_HOLDTIME_DEFAULT);
814}
815
hasso508e53e2004-05-18 18:57:06 +0000816int
817config_write_ospf6_debug_spf (struct vty *vty)
818{
hasso3b687352004-08-19 06:56:53 +0000819 if (IS_OSPF6_DEBUG_SPF (PROCESS))
820 vty_out (vty, "debug ospf6 spf process%s", VNL);
821 if (IS_OSPF6_DEBUG_SPF (TIME))
822 vty_out (vty, "debug ospf6 spf time%s", VNL);
hasso2680aa22004-11-25 20:54:46 +0000823 if (IS_OSPF6_DEBUG_SPF (DATABASE))
824 vty_out (vty, "debug ospf6 spf database%s", VNL);
hasso508e53e2004-05-18 18:57:06 +0000825 return 0;
826}
827
828void
Dinesh Dutt3810e062013-08-24 07:54:09 +0000829ospf6_spf_config_write (struct vty *vty)
830{
831
832 if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT ||
833 ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT ||
834 ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT)
835 vty_out (vty, " timers throttle spf %d %d %d%s",
836 ospf6->spf_delay, ospf6->spf_holdtime,
837 ospf6->spf_max_holdtime, VTY_NEWLINE);
838
839}
840
841void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100842install_element_ospf6_debug_spf (void)
hasso508e53e2004-05-18 18:57:06 +0000843{
hasso3b687352004-08-19 06:56:53 +0000844 install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd);
845 install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000846 install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000847 install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd);
848 install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000849 install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000850 install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd);
851 install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000852 install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd);
hasso3b687352004-08-19 06:56:53 +0000853 install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd);
854 install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd);
hasso2680aa22004-11-25 20:54:46 +0000855 install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd);
hasso508e53e2004-05-18 18:57:06 +0000856}
paul718e3742002-12-13 20:15:29 +0000857
858void
Paul Jakma6ac29a52008-08-15 13:45:30 +0100859ospf6_spf_init (void)
paul718e3742002-12-13 20:15:29 +0000860{
Dinesh Dutt3810e062013-08-24 07:54:09 +0000861 install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
862 install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
paul718e3742002-12-13 20:15:29 +0000863}