blob: f6e5e6630d517f749e37f6c6544c8f5af07eafa7 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* OSPF SPF calculation.
2 Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "thread.h"
24#include "memory.h"
25#include "hash.h"
26#include "linklist.h"
27#include "prefix.h"
28#include "if.h"
29#include "table.h"
30#include "log.h"
31#include "sockunion.h" /* for inet_ntop () */
hasso462f20d2005-02-23 11:29:02 +000032#include "pqueue.h"
paul718e3742002-12-13 20:15:29 +000033
34#include "ospfd/ospfd.h"
35#include "ospfd/ospf_interface.h"
36#include "ospfd/ospf_ism.h"
37#include "ospfd/ospf_asbr.h"
38#include "ospfd/ospf_lsa.h"
39#include "ospfd/ospf_lsdb.h"
40#include "ospfd/ospf_neighbor.h"
41#include "ospfd/ospf_nsm.h"
42#include "ospfd/ospf_spf.h"
43#include "ospfd/ospf_route.h"
44#include "ospfd/ospf_ia.h"
45#include "ospfd/ospf_ase.h"
46#include "ospfd/ospf_abr.h"
47#include "ospfd/ospf_dump.h"
48
Paul Jakma9c27ef92006-05-04 07:32:57 +000049static void ospf_vertex_free (void *);
50/* List of allocated vertices, to simplify cleanup of SPF.
51 * Not thread-safe obviously. If it ever needs to be, it'd have to be
52 * dynamically allocated at begin of ospf_spf_calculate
53 */
54static struct list vertex_list = { .del = ospf_vertex_free };
55
hasso462f20d2005-02-23 11:29:02 +000056/* Heap related functions, for the managment of the candidates, to
57 * be used with pqueue. */
58static int
59cmp (void * node1 , void * node2)
60{
61 struct vertex * v1 = (struct vertex *) node1;
62 struct vertex * v2 = (struct vertex *) node2;
63 if (v1 != NULL && v2 != NULL )
Paul Jakma9c27ef92006-05-04 07:32:57 +000064 {
65 /* network vertices must be chosen before router vertices of same
66 * cost in order to find all shortest paths
67 */
68 if ( ((v1->distance - v2->distance) == 0)
69 && (v1->type != v2->type))
70 {
71 switch (v1->type)
72 {
73 case OSPF_VERTEX_NETWORK:
74 return -1;
75 case OSPF_VERTEX_ROUTER:
76 return 1;
77 }
78 }
79 else
80 return (v1->distance - v2->distance);
81 }
82 return 0;
hasso462f20d2005-02-23 11:29:02 +000083}
84
85static void
pauleb3da6d2005-10-18 04:20:33 +000086update_stat (void *node , int position)
hasso462f20d2005-02-23 11:29:02 +000087{
pauleb3da6d2005-10-18 04:20:33 +000088 struct vertex *v = node;
89
hasso462f20d2005-02-23 11:29:02 +000090 /* Set the status of the vertex, when its position changes. */
91 *(v->stat) = position;
92}
pauleb3da6d2005-10-18 04:20:33 +000093
paul4dadc292005-05-06 21:37:42 +000094static struct vertex_nexthop *
pauleb3da6d2005-10-18 04:20:33 +000095vertex_nexthop_new (void)
paul718e3742002-12-13 20:15:29 +000096{
pauleb3da6d2005-10-18 04:20:33 +000097 return XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop));
paul718e3742002-12-13 20:15:29 +000098}
99
paul4dadc292005-05-06 21:37:42 +0000100static void
paul718e3742002-12-13 20:15:29 +0000101vertex_nexthop_free (struct vertex_nexthop *nh)
102{
103 XFREE (MTYPE_OSPF_NEXTHOP, nh);
104}
105
pauleb3da6d2005-10-18 04:20:33 +0000106/* Free the canonical nexthop objects for an area, ie the nexthop objects
Paul Jakma9c27ef92006-05-04 07:32:57 +0000107 * attached to the first-hop router vertices, and any intervening network
108 * vertices.
pauleb3da6d2005-10-18 04:20:33 +0000109 */
110static void
111ospf_canonical_nexthops_free (struct vertex *root)
paul718e3742002-12-13 20:15:29 +0000112{
pauleb3da6d2005-10-18 04:20:33 +0000113 struct listnode *node, *nnode;
114 struct vertex *child;
115
116 for (ALL_LIST_ELEMENTS (root->children, node, nnode, child))
117 {
118 struct listnode *n2, *nn2;
119 struct vertex_parent *vp;
120
paul58e1bef2005-11-11 12:10:03 +0000121 /* router vertices through an attached network each
122 * have a distinct (canonical / not inherited) nexthop
123 * which must be freed.
124 *
125 * A network vertex can only have router vertices as its
126 * children, so only one level of recursion is possible.
127 */
pauleb3da6d2005-10-18 04:20:33 +0000128 if (child->type == OSPF_VERTEX_NETWORK)
129 ospf_canonical_nexthops_free (child);
130
paul58e1bef2005-11-11 12:10:03 +0000131 /* Free child nexthops pointing back to this root vertex */
pauleb3da6d2005-10-18 04:20:33 +0000132 for (ALL_LIST_ELEMENTS (child->parents, n2, nn2, vp))
Paul Jakma9c27ef92006-05-04 07:32:57 +0000133 if (vp->parent == root && vp->nexthop)
paul58e1bef2005-11-11 12:10:03 +0000134 vertex_nexthop_free (vp->nexthop);
pauleb3da6d2005-10-18 04:20:33 +0000135 }
136}
137
Paul Jakma9c27ef92006-05-04 07:32:57 +0000138/* TODO: Parent list should be excised, in favour of maintaining only
139 * vertex_nexthop, with refcounts.
140 */
pauleb3da6d2005-10-18 04:20:33 +0000141static struct vertex_parent *
142vertex_parent_new (struct vertex *v, int backlink, struct vertex_nexthop *hop)
143{
144 struct vertex_parent *new;
145
146 new = XMALLOC (MTYPE_OSPF_VERTEX_PARENT, sizeof (struct vertex_parent));
147
148 if (new == NULL)
149 return NULL;
150
151 new->parent = v;
152 new->backlink = backlink;
153 new->nexthop = hop;
paul718e3742002-12-13 20:15:29 +0000154 return new;
155}
paul0c0f9cd2003-06-06 23:27:04 +0000156
pauleb3da6d2005-10-18 04:20:33 +0000157static void
Paul Jakma9c27ef92006-05-04 07:32:57 +0000158vertex_parent_free (void *p)
pauleb3da6d2005-10-18 04:20:33 +0000159{
160 XFREE (MTYPE_OSPF_VERTEX_PARENT, p);
161}
162
paul4dadc292005-05-06 21:37:42 +0000163static struct vertex *
paul718e3742002-12-13 20:15:29 +0000164ospf_vertex_new (struct ospf_lsa *lsa)
165{
166 struct vertex *new;
167
pauleb3da6d2005-10-18 04:20:33 +0000168 new = XCALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex));
paul718e3742002-12-13 20:15:29 +0000169
170 new->flags = 0;
hasso462f20d2005-02-23 11:29:02 +0000171 new->stat = &(lsa->stat);
paul718e3742002-12-13 20:15:29 +0000172 new->type = lsa->data->type;
173 new->id = lsa->data->id;
174 new->lsa = lsa->data;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000175 new->distance = OSPF_OUTPUT_COST_INFINITE;
pauleb3da6d2005-10-18 04:20:33 +0000176 new->children = list_new ();
177 new->parents = list_new ();
Paul Jakma9c27ef92006-05-04 07:32:57 +0000178 new->parents->del = vertex_parent_free;
pauleb3da6d2005-10-18 04:20:33 +0000179
Paul Jakma9c27ef92006-05-04 07:32:57 +0000180 listnode_add (&vertex_list, new);
181
182 if (IS_DEBUG_OSPF_EVENT)
183 zlog_debug ("%s: Created %s vertex %s", __func__,
184 new->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
185 inet_ntoa (new->lsa->id));
paul718e3742002-12-13 20:15:29 +0000186 return new;
187}
188
paul4dadc292005-05-06 21:37:42 +0000189static void
Paul Jakma9c27ef92006-05-04 07:32:57 +0000190ospf_vertex_free (void *data)
paul718e3742002-12-13 20:15:29 +0000191{
Paul Jakma9c27ef92006-05-04 07:32:57 +0000192 struct vertex *v = data;
paul7461d452005-06-13 13:57:16 +0000193
Paul Jakma9c27ef92006-05-04 07:32:57 +0000194 if (IS_DEBUG_OSPF_EVENT)
195 zlog_debug ("%s: Free %s vertex %s", __func__,
196 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
197 inet_ntoa (v->lsa->id));
pauleb3da6d2005-10-18 04:20:33 +0000198
Paul Jakma9c27ef92006-05-04 07:32:57 +0000199 /* There should be no parents potentially holding references to this vertex
200 * Children however may still be there, but presumably referenced by other
201 * vertices
pauleb3da6d2005-10-18 04:20:33 +0000202 */
Paul Jakma9c27ef92006-05-04 07:32:57 +0000203 //assert (listcount (v->parents) == 0);
pauleb3da6d2005-10-18 04:20:33 +0000204
Paul Jakma9c27ef92006-05-04 07:32:57 +0000205 if (v->children)
206 list_delete (v->children);
207 v->children = NULL;
208
209 if (v->parents)
210 list_delete (v->parents);
pauleb3da6d2005-10-18 04:20:33 +0000211 v->parents = NULL;
212
213 v->lsa = NULL;
paul7461d452005-06-13 13:57:16 +0000214
paul718e3742002-12-13 20:15:29 +0000215 XFREE (MTYPE_OSPF_VERTEX, v);
216}
217
paul4dadc292005-05-06 21:37:42 +0000218static void
hassoeb1ce602004-10-08 08:17:22 +0000219ospf_vertex_dump(const char *msg, struct vertex *v,
pauleb3da6d2005-10-18 04:20:33 +0000220 int print_parents, int print_children)
gdt630e4802004-08-31 17:28:41 +0000221{
222 if ( ! IS_DEBUG_OSPF_EVENT)
223 return;
224
pauleb3da6d2005-10-18 04:20:33 +0000225 zlog_debug("%s %s vertex %s distance %u flags %u",
gdt630e4802004-08-31 17:28:41 +0000226 msg,
227 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
228 inet_ntoa(v->lsa->id),
229 v->distance,
gdt630e4802004-08-31 17:28:41 +0000230 (unsigned int)v->flags);
231
pauleb3da6d2005-10-18 04:20:33 +0000232 if (print_parents)
gdt630e4802004-08-31 17:28:41 +0000233 {
paul1eb8ef22005-04-07 07:30:20 +0000234 struct listnode *node;
pauleb3da6d2005-10-18 04:20:33 +0000235 struct vertex_parent *vp;
paul1eb8ef22005-04-07 07:30:20 +0000236
pauleb3da6d2005-10-18 04:20:33 +0000237 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
gdt630e4802004-08-31 17:28:41 +0000238 {
239 char buf1[BUFSIZ];
pauleb3da6d2005-10-18 04:20:33 +0000240
241 if (vp)
gdt630e4802004-08-31 17:28:41 +0000242 {
pauleb3da6d2005-10-18 04:20:33 +0000243 zlog_debug ("parent %s backlink %d nexthop %s interface %s",
244 inet_ntoa(vp->parent->lsa->id), vp->backlink,
245 inet_ntop(AF_INET, &vp->nexthop->router, buf1, BUFSIZ),
246 vp->nexthop->oi ? IF_NAME(vp->nexthop->oi) : "NULL");
gdt630e4802004-08-31 17:28:41 +0000247 }
248 }
249 }
250
251 if (print_children)
252 {
hasso52dc7ee2004-09-23 19:18:23 +0000253 struct listnode *cnode;
paul1eb8ef22005-04-07 07:30:20 +0000254 struct vertex *cv;
255
pauleb3da6d2005-10-18 04:20:33 +0000256 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv))
paul1eb8ef22005-04-07 07:30:20 +0000257 ospf_vertex_dump(" child:", cv, 0, 0);
gdt630e4802004-08-31 17:28:41 +0000258 }
259}
260
261
262/* Add a vertex to the list of children in each of its parents. */
paul4dadc292005-05-06 21:37:42 +0000263static void
paul718e3742002-12-13 20:15:29 +0000264ospf_vertex_add_parent (struct vertex *v)
265{
pauleb3da6d2005-10-18 04:20:33 +0000266 struct vertex_parent *vp;
hasso52dc7ee2004-09-23 19:18:23 +0000267 struct listnode *node;
paul7461d452005-06-13 13:57:16 +0000268
Paul Jakma9c27ef92006-05-04 07:32:57 +0000269 assert (v && v->parents);
paul7461d452005-06-13 13:57:16 +0000270
pauleb3da6d2005-10-18 04:20:33 +0000271 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
paul718e3742002-12-13 20:15:29 +0000272 {
pauleb3da6d2005-10-18 04:20:33 +0000273 assert (vp->parent && vp->parent->children);
paul7461d452005-06-13 13:57:16 +0000274
paul718e3742002-12-13 20:15:29 +0000275 /* No need to add two links from the same parent. */
pauleb3da6d2005-10-18 04:20:33 +0000276 if (listnode_lookup (vp->parent->children, v) == NULL)
277 listnode_add (vp->parent->children, v);
paul718e3742002-12-13 20:15:29 +0000278 }
279}
280
paul4dadc292005-05-06 21:37:42 +0000281static void
paul718e3742002-12-13 20:15:29 +0000282ospf_spf_init (struct ospf_area *area)
283{
284 struct vertex *v;
Paul Jakma9c27ef92006-05-04 07:32:57 +0000285
paul718e3742002-12-13 20:15:29 +0000286 /* Create root node. */
287 v = ospf_vertex_new (area->router_lsa_self);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000288 v->distance = 0;
289
paul718e3742002-12-13 20:15:29 +0000290 area->spf = v;
291
292 /* Reset ABR and ASBR router counts. */
293 area->abr_count = 0;
294 area->asbr_count = 0;
295}
296
pauld355bfa2004-04-08 07:43:45 +0000297/* return index of link back to V from W, or -1 if no link found */
paul4dadc292005-05-06 21:37:42 +0000298static int
paul718e3742002-12-13 20:15:29 +0000299ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v)
300{
hassoeb1ce602004-10-08 08:17:22 +0000301 unsigned int i, length;
paul718e3742002-12-13 20:15:29 +0000302 struct router_lsa *rl;
303 struct network_lsa *nl;
304
305 /* In case of W is Network LSA. */
306 if (w->type == OSPF_NETWORK_LSA)
307 {
308 if (v->type == OSPF_NETWORK_LSA)
pauld355bfa2004-04-08 07:43:45 +0000309 return -1;
paul718e3742002-12-13 20:15:29 +0000310
311 nl = (struct network_lsa *) w;
312 length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
paul0c0f9cd2003-06-06 23:27:04 +0000313
paul718e3742002-12-13 20:15:29 +0000314 for (i = 0; i < length; i++)
315 if (IPV4_ADDR_SAME (&nl->routers[i], &v->id))
pauld355bfa2004-04-08 07:43:45 +0000316 return i;
317 return -1;
paul718e3742002-12-13 20:15:29 +0000318 }
319
320 /* In case of W is Router LSA. */
321 if (w->type == OSPF_ROUTER_LSA)
322 {
323 rl = (struct router_lsa *) w;
324
325 length = ntohs (w->length);
326
327 for (i = 0;
paul0c0f9cd2003-06-06 23:27:04 +0000328 i < ntohs (rl->links) && length >= sizeof (struct router_lsa);
329 i++, length -= 12)
paul718e3742002-12-13 20:15:29 +0000330 {
331 switch (rl->link[i].type)
332 {
333 case LSA_LINK_TYPE_POINTOPOINT:
334 case LSA_LINK_TYPE_VIRTUALLINK:
335 /* Router LSA ID. */
336 if (v->type == OSPF_ROUTER_LSA &&
337 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
338 {
pauld355bfa2004-04-08 07:43:45 +0000339 return i;
paul718e3742002-12-13 20:15:29 +0000340 }
341 break;
342 case LSA_LINK_TYPE_TRANSIT:
343 /* Network LSA ID. */
344 if (v->type == OSPF_NETWORK_LSA &&
345 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
346 {
pauld355bfa2004-04-08 07:43:45 +0000347 return i;
paul0c0f9cd2003-06-06 23:27:04 +0000348 }
paul718e3742002-12-13 20:15:29 +0000349 break;
350 case LSA_LINK_TYPE_STUB:
pauleb3da6d2005-10-18 04:20:33 +0000351 /* Stub can't lead anywhere, carry on */
paul718e3742002-12-13 20:15:29 +0000352 continue;
353 default:
354 break;
355 }
356 }
357 }
pauld355bfa2004-04-08 07:43:45 +0000358 return -1;
paul718e3742002-12-13 20:15:29 +0000359}
360
paul718e3742002-12-13 20:15:29 +0000361#define ROUTER_LSA_MIN_SIZE 12
362#define ROUTER_LSA_TOS_SIZE 4
363
gdt630e4802004-08-31 17:28:41 +0000364/* Find the next link after prev_link from v to w. If prev_link is
365 * NULL, return the first link from v to w. Ignore stub and virtual links;
366 * these link types will never be returned.
367 */
paul4dadc292005-05-06 21:37:42 +0000368static struct router_lsa_link *
paul718e3742002-12-13 20:15:29 +0000369ospf_get_next_link (struct vertex *v, struct vertex *w,
paul0c0f9cd2003-06-06 23:27:04 +0000370 struct router_lsa_link *prev_link)
paul718e3742002-12-13 20:15:29 +0000371{
372 u_char *p;
373 u_char *lim;
374 struct router_lsa_link *l;
375
376 if (prev_link == NULL)
gdt630e4802004-08-31 17:28:41 +0000377 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul718e3742002-12-13 20:15:29 +0000378 else
379 {
paul0c0f9cd2003-06-06 23:27:04 +0000380 p = (u_char *) prev_link;
paul718e3742002-12-13 20:15:29 +0000381 p += (ROUTER_LSA_MIN_SIZE +
382 (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
383 }
paul0c0f9cd2003-06-06 23:27:04 +0000384
paul718e3742002-12-13 20:15:29 +0000385 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
386
387 while (p < lim)
388 {
389 l = (struct router_lsa_link *) p;
390
paul0c0f9cd2003-06-06 23:27:04 +0000391 p += (ROUTER_LSA_MIN_SIZE + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
paul718e3742002-12-13 20:15:29 +0000392
393 if (l->m[0].type == LSA_LINK_TYPE_STUB)
394 continue;
395
396 /* Defer NH calculation via VLs until summaries from
397 transit areas area confidered */
398
399 if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
paul0c0f9cd2003-06-06 23:27:04 +0000400 continue;
paul718e3742002-12-13 20:15:29 +0000401
402 if (IPV4_ADDR_SAME (&l->link_id, &w->id))
paul0c0f9cd2003-06-06 23:27:04 +0000403 return l;
paul718e3742002-12-13 20:15:29 +0000404 }
405
406 return NULL;
407}
408
pauleb3da6d2005-10-18 04:20:33 +0000409static void
410ospf_spf_flush_parents (struct vertex *w)
411{
412 struct vertex_parent *vp;
413 struct listnode *ln, *nn;
414
415 /* delete the existing nexthops */
416 for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp))
417 {
418 list_delete_node (w->parents, ln);
419 vertex_parent_free (vp);
420 }
421}
422
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000423/*
424 * Consider supplied next-hop for inclusion to the supplied list of
425 * equal-cost next-hops, adjust list as neccessary.
426 */
427static void
428ospf_spf_add_parent (struct vertex *v, struct vertex *w,
429 struct vertex_nexthop *newhop,
Paul Jakmabd34fb32007-02-26 17:14:48 +0000430 unsigned int distance)
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000431{
432 struct vertex_parent *vp;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000433
434 /* we must have a newhop.. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000435 assert (v && w && newhop);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000436
437 /* We shouldn't get here unless callers have determined V(l)->W is
438 * shortest / equal-shortest path.
439 */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000440 assert (distance <= w->distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000441
Paul Jakmab75ae992007-03-23 11:17:28 +0000442 if (IS_DEBUG_OSPF_EVENT)
443 {
444 char buf[2][INET_ADDRSTRLEN];
445 zlog_debug ("%s: Adding %s as parent of %s",
446 __func__,
447 inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])),
448 inet_ntop(AF_INET, &w->lsa->id, buf[1], sizeof(buf[1])));
449 }
450
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000451 /* Adding parent for a new, better path: flush existing parents from W. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000452 if (distance < w->distance)
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000453 {
Paul Jakmab75ae992007-03-23 11:17:28 +0000454 if (IS_DEBUG_OSPF_EVENT)
455 zlog_debug ("%s: distance %d better than %d, flushing existing parents",
456 __func__, distance, w->distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000457 ospf_spf_flush_parents (w);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000458 w->distance = distance;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000459 }
460
461 /* new parent is <= existing parents, add it to parent list */
462 vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop);
463 listnode_add (w->parents, vp);
464
465 return;
466}
467
gdt630e4802004-08-31 17:28:41 +0000468/* 16.1.1. Calculate nexthop from root through V (parent) to
Paul Jakmabd34fb32007-02-26 17:14:48 +0000469 * vertex W (destination), with given distance from root->W.
pauleb3da6d2005-10-18 04:20:33 +0000470 *
471 * The link must be supplied if V is the root vertex. In all other cases
472 * it may be NULL.
Paul Jakmabd34fb32007-02-26 17:14:48 +0000473 *
474 * Note that this function may fail, hence the state of the destination
475 * vertex, W, should /not/ be modified in a dependent manner until
476 * this function returns. This function will update the W vertex with the
477 * provided distance as appropriate.
gdt630e4802004-08-31 17:28:41 +0000478 */
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000479static unsigned int
pauleb3da6d2005-10-18 04:20:33 +0000480ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
Paul Jakmabd34fb32007-02-26 17:14:48 +0000481 struct vertex *w, struct router_lsa_link *l,
482 unsigned int distance)
paul718e3742002-12-13 20:15:29 +0000483{
paul1eb8ef22005-04-07 07:30:20 +0000484 struct listnode *node, *nnode;
pauleb3da6d2005-10-18 04:20:33 +0000485 struct vertex_nexthop *nh;
486 struct vertex_parent *vp;
paul718e3742002-12-13 20:15:29 +0000487 struct ospf_interface *oi = NULL;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000488 unsigned int added = 0;
paul0c0f9cd2003-06-06 23:27:04 +0000489
paul718e3742002-12-13 20:15:29 +0000490 if (IS_DEBUG_OSPF_EVENT)
gdt630e4802004-08-31 17:28:41 +0000491 {
ajs2a42e282004-12-08 18:43:03 +0000492 zlog_debug ("ospf_nexthop_calculation(): Start");
gdt630e4802004-08-31 17:28:41 +0000493 ospf_vertex_dump("V (parent):", v, 1, 1);
494 ospf_vertex_dump("W (dest) :", w, 1, 1);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000495 zlog_debug ("V->W distance: %d", distance);
gdt630e4802004-08-31 17:28:41 +0000496 }
paul718e3742002-12-13 20:15:29 +0000497
paul718e3742002-12-13 20:15:29 +0000498 if (v == area->spf)
Paul Jakma9c27ef92006-05-04 07:32:57 +0000499 {
gdt630e4802004-08-31 17:28:41 +0000500 /* 16.1.1 para 4. In the first case, the parent vertex (V) is the
501 root (the calculating router itself). This means that the
502 destination is either a directly connected network or directly
503 connected router. The outgoing interface in this case is simply
504 the OSPF interface connecting to the destination network/router.
505 */
506
paul718e3742002-12-13 20:15:29 +0000507 if (w->type == OSPF_VERTEX_ROUTER)
paul0c0f9cd2003-06-06 23:27:04 +0000508 {
pauleb3da6d2005-10-18 04:20:33 +0000509 /* l is a link from v to w
510 * l2 will be link from w to v
511 */
512 struct router_lsa_link *l2 = NULL;
513
514 /* we *must* be supplied with the link data */
515 assert (l != NULL);
516
517 if (IS_DEBUG_OSPF_EVENT)
paul0c0f9cd2003-06-06 23:27:04 +0000518 {
pauleb3da6d2005-10-18 04:20:33 +0000519 char buf1[BUFSIZ];
520 char buf2[BUFSIZ];
521
522 zlog_debug("ospf_nexthop_calculation(): considering link "
523 "type %d link_id %s link_data %s",
524 l->m[0].type,
525 inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
526 inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
527 }
paul0c0f9cd2003-06-06 23:27:04 +0000528
pauleb3da6d2005-10-18 04:20:33 +0000529 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
530 {
531 /* If the destination is a router which connects to
532 the calculating router via a Point-to-MultiPoint
533 network, the destination's next hop IP address(es)
534 can be determined by examining the destination's
535 router-LSA: each link pointing back to the
536 calculating router and having a Link Data field
537 belonging to the Point-to-MultiPoint network
538 provides an IP address of the next hop router.
gdt630e4802004-08-31 17:28:41 +0000539
pauleb3da6d2005-10-18 04:20:33 +0000540 At this point l is a link from V to W, and V is the
541 root ("us"). Find the local interface associated
542 with l (its address is in l->link_data). If it
543 is a point-to-multipoint interface, then look through
544 the links in the opposite direction (W to V). If
545 any of them have an address that lands within the
546 subnet declared by the PtMP link, then that link
547 is a constituent of the PtMP link, and its address is
548 a nexthop address for V.
549 */
550 oi = ospf_if_is_configured (area->ospf, &l->link_data);
551 if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
paul0c0f9cd2003-06-06 23:27:04 +0000552 {
pauleb3da6d2005-10-18 04:20:33 +0000553 struct prefix_ipv4 la;
gdt630e4802004-08-31 17:28:41 +0000554
pauleb3da6d2005-10-18 04:20:33 +0000555 la.family = AF_INET;
556 la.prefixlen = oi->address->prefixlen;
557
558 /* V links to W on PtMP interface
559 - find the interface address on W */
560 while ((l2 = ospf_get_next_link (w, v, l2)))
paul0c0f9cd2003-06-06 23:27:04 +0000561 {
pauleb3da6d2005-10-18 04:20:33 +0000562 la.prefix = l2->link_data;
gdt630e4802004-08-31 17:28:41 +0000563
pauleb3da6d2005-10-18 04:20:33 +0000564 if (prefix_cmp ((struct prefix *) &la,
565 oi->address) == 0)
566 /* link_data is on our PtMP network */
567 break;
paul0c0f9cd2003-06-06 23:27:04 +0000568 }
pauleb3da6d2005-10-18 04:20:33 +0000569 } /* end l is on point-to-multipoint link */
570 else
571 {
572 /* l is a regular point-to-point link.
573 Look for a link from W to V.
574 */
575 while ((l2 = ospf_get_next_link (w, v, l2)))
paul0c0f9cd2003-06-06 23:27:04 +0000576 {
pauleb3da6d2005-10-18 04:20:33 +0000577 oi = ospf_if_is_configured (area->ospf,
578 &(l2->link_data));
579
580 if (oi == NULL)
581 continue;
582
583 if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
584 &l->link_data))
585 continue;
586
587 break;
paul0c0f9cd2003-06-06 23:27:04 +0000588 }
pauleb3da6d2005-10-18 04:20:33 +0000589 }
590
591 if (oi && l2)
592 {
593 /* found all necessary info to build nexthop */
594 nh = vertex_nexthop_new ();
595 nh->oi = oi;
596 nh->router = l2->link_data;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000597 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000598 return 1;
pauleb3da6d2005-10-18 04:20:33 +0000599 }
600 else
Paul Jakma9c27ef92006-05-04 07:32:57 +0000601 zlog_info("ospf_nexthop_calculation(): "
602 "could not determine nexthop for link");
pauleb3da6d2005-10-18 04:20:33 +0000603 } /* end point-to-point link from V to W */
Paul Jakma9c27ef92006-05-04 07:32:57 +0000604 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
605 {
606 struct ospf_vl_data *vl_data;
607
608 /* VLink implementation limitations:
609 * a) vl_data can only reference one nexthop, so no ECMP
610 * to backbone through VLinks. Though transit-area
611 * summaries may be considered, and those can be ECMP.
612 * b) We can only use /one/ VLink, even if multiple ones
613 * exist this router through multiple transit-areas.
614 */
615 vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id);
616
617 if (vl_data
618 && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED))
619 {
620 nh = vertex_nexthop_new ();
621 nh->oi = vl_data->nexthop.oi;
622 nh->router = vl_data->nexthop.router;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000623 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000624 return 1;
Paul Jakma9c27ef92006-05-04 07:32:57 +0000625 }
626 else
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000627 zlog_info("ospf_nexthop_calculation(): "
628 "vl_data for VL link not found");
Paul Jakma9c27ef92006-05-04 07:32:57 +0000629 } /* end virtual-link from V to W */
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000630 return 0;
gdt630e4802004-08-31 17:28:41 +0000631 } /* end W is a Router vertex */
paul718e3742002-12-13 20:15:29 +0000632 else
paul0c0f9cd2003-06-06 23:27:04 +0000633 {
pauleb3da6d2005-10-18 04:20:33 +0000634 assert(w->type == OSPF_VERTEX_NETWORK);
635 oi = ospf_if_is_configured (area->ospf, &(l->link_data));
636 if (oi)
paul0c0f9cd2003-06-06 23:27:04 +0000637 {
pauleb3da6d2005-10-18 04:20:33 +0000638 nh = vertex_nexthop_new ();
639 nh->oi = oi;
640 nh->router.s_addr = 0;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000641 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000642 return 1;
paul0c0f9cd2003-06-06 23:27:04 +0000643 }
644 }
Paul Jakma9c27ef92006-05-04 07:32:57 +0000645 zlog_info("ospf_nexthop_calculation(): "
646 "Unknown attached link");
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000647 return 0;
gdt630e4802004-08-31 17:28:41 +0000648 } /* end V is the root */
gdt630e4802004-08-31 17:28:41 +0000649 /* Check if W's parent is a network connected to root. */
paul718e3742002-12-13 20:15:29 +0000650 else if (v->type == OSPF_VERTEX_NETWORK)
651 {
gdt630e4802004-08-31 17:28:41 +0000652 /* See if any of V's parents are the root. */
pauleb3da6d2005-10-18 04:20:33 +0000653 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
paul718e3742002-12-13 20:15:29 +0000654 {
pauleb3da6d2005-10-18 04:20:33 +0000655 if (vp->parent == area->spf) /* connects to root? */
gdt630e4802004-08-31 17:28:41 +0000656 {
657 /* 16.1.1 para 5. ...the parent vertex is a network that
658 * directly connects the calculating router to the destination
659 * router. The list of next hops is then determined by
660 * examining the destination's router-LSA...
661 */
662
663 assert(w->type == OSPF_VERTEX_ROUTER);
paul0c0f9cd2003-06-06 23:27:04 +0000664 while ((l = ospf_get_next_link (w, v, l)))
665 {
gdt630e4802004-08-31 17:28:41 +0000666 /* ...For each link in the router-LSA that points back to the
667 * parent network, the link's Link Data field provides the IP
668 * address of a next hop router. The outgoing interface to
669 * use can then be derived from the next hop IP address (or
670 * it can be inherited from the parent network).
671 */
pauleb3da6d2005-10-18 04:20:33 +0000672 nh = vertex_nexthop_new ();
673 nh->oi = vp->nexthop->oi;
674 nh->router = l->link_data;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000675 added = 1;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000676 ospf_spf_add_parent (v, w, nh, distance);
paul0c0f9cd2003-06-06 23:27:04 +0000677 }
paul0c0f9cd2003-06-06 23:27:04 +0000678 }
paul718e3742002-12-13 20:15:29 +0000679 }
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000680 return added;
paul718e3742002-12-13 20:15:29 +0000681 }
682
gdt630e4802004-08-31 17:28:41 +0000683 /* 16.1.1 para 4. If there is at least one intervening router in the
684 * current shortest path between the destination and the root, the
685 * destination simply inherits the set of next hops from the
686 * parent.
687 */
Paul Jakmab75ae992007-03-23 11:17:28 +0000688 if (IS_DEBUG_OSPF_EVENT)
689 zlog_debug ("%s: Intervening routers, adding parent(s)", __func__);
690
pauleb3da6d2005-10-18 04:20:33 +0000691 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000692 {
693 added = 1;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000694 ospf_spf_add_parent (v, w, vp->nexthop, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000695 }
Paul Jakma9c27ef92006-05-04 07:32:57 +0000696
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000697 return added;
paul718e3742002-12-13 20:15:29 +0000698}
699
gdt630e4802004-08-31 17:28:41 +0000700/* RFC2328 Section 16.1 (2).
701 * v is on the SPF tree. Examine the links in v's LSA. Update the list
702 * of candidates with any vertices not already on the list. If a lower-cost
703 * path is found to a vertex already on the candidate list, store the new cost.
704 */
paul4dadc292005-05-06 21:37:42 +0000705static void
paul718e3742002-12-13 20:15:29 +0000706ospf_spf_next (struct vertex *v, struct ospf_area *area,
hasso462f20d2005-02-23 11:29:02 +0000707 struct pqueue * candidate)
paul718e3742002-12-13 20:15:29 +0000708{
709 struct ospf_lsa *w_lsa = NULL;
paul718e3742002-12-13 20:15:29 +0000710 u_char *p;
711 u_char *lim;
712 struct router_lsa_link *l = NULL;
713 struct in_addr *r;
paul718e3742002-12-13 20:15:29 +0000714 int type = 0;
715
716 /* If this is a router-LSA, and bit V of the router-LSA (see Section
717 A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
718 if (v->type == OSPF_VERTEX_ROUTER)
719 {
720 if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa))
721 area->transit = OSPF_TRANSIT_TRUE;
722 }
Paul Jakmab75ae992007-03-23 11:17:28 +0000723
724 if (IS_DEBUG_OSPF_EVENT)
725 zlog_debug ("%s: Next vertex of %s vertex %s",
726 __func__,
727 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
728 inet_ntoa(v->lsa->id));
729
paul718e3742002-12-13 20:15:29 +0000730 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul0c0f9cd2003-06-06 23:27:04 +0000731 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
732
paul718e3742002-12-13 20:15:29 +0000733 while (p < lim)
734 {
pauleb3da6d2005-10-18 04:20:33 +0000735 struct vertex *w;
736 unsigned int distance;
pauld355bfa2004-04-08 07:43:45 +0000737
paul718e3742002-12-13 20:15:29 +0000738 /* In case of V is Router-LSA. */
739 if (v->lsa->type == OSPF_ROUTER_LSA)
740 {
741 l = (struct router_lsa_link *) p;
742
paul0c0f9cd2003-06-06 23:27:04 +0000743 p += (ROUTER_LSA_MIN_SIZE +
paul718e3742002-12-13 20:15:29 +0000744 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
745
746 /* (a) If this is a link to a stub network, examine the next
747 link in V's LSA. Links to stub networks will be
748 considered in the second stage of the shortest path
749 calculation. */
750 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
751 continue;
752
753 /* (b) Otherwise, W is a transit vertex (router or transit
754 network). Look up the vertex W's LSA (router-LSA or
755 network-LSA) in Area A's link state database. */
756 switch (type)
757 {
758 case LSA_LINK_TYPE_POINTOPOINT:
759 case LSA_LINK_TYPE_VIRTUALLINK:
760 if (type == LSA_LINK_TYPE_VIRTUALLINK)
paul0c0f9cd2003-06-06 23:27:04 +0000761 {
762 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000763 zlog_debug ("looking up LSA through VL: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000764 inet_ntoa (l->link_id));
765 }
paul718e3742002-12-13 20:15:29 +0000766
767 w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id,
768 l->link_id);
769 if (w_lsa)
paul0c0f9cd2003-06-06 23:27:04 +0000770 {
771 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000772 zlog_debug ("found Router LSA %s", inet_ntoa (l->link_id));
paul0c0f9cd2003-06-06 23:27:04 +0000773 }
paul718e3742002-12-13 20:15:29 +0000774 break;
775 case LSA_LINK_TYPE_TRANSIT:
paul0c0f9cd2003-06-06 23:27:04 +0000776 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000777 zlog_debug ("Looking up Network LSA, ID: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000778 inet_ntoa (l->link_id));
paul718e3742002-12-13 20:15:29 +0000779 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA,
paul0c0f9cd2003-06-06 23:27:04 +0000780 l->link_id);
paul718e3742002-12-13 20:15:29 +0000781 if (w_lsa)
paul0c0f9cd2003-06-06 23:27:04 +0000782 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000783 zlog_debug ("found the LSA");
paul718e3742002-12-13 20:15:29 +0000784 break;
785 default:
paul0c0f9cd2003-06-06 23:27:04 +0000786 zlog_warn ("Invalid LSA link type %d", type);
paul718e3742002-12-13 20:15:29 +0000787 continue;
788 }
789 }
790 else
791 {
792 /* In case of V is Network-LSA. */
paul0c0f9cd2003-06-06 23:27:04 +0000793 r = (struct in_addr *) p;
paul718e3742002-12-13 20:15:29 +0000794 p += sizeof (struct in_addr);
795
796 /* Lookup the vertex W's LSA. */
797 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r);
Paul Jakmab75ae992007-03-23 11:17:28 +0000798 if (w_lsa)
799 {
800 if (IS_DEBUG_OSPF_EVENT)
801 zlog_debug ("found Router LSA %s", inet_ntoa (w_lsa->data->id));
802 }
paul718e3742002-12-13 20:15:29 +0000803 }
804
805 /* (b cont.) If the LSA does not exist, or its LS age is equal
806 to MaxAge, or it does not have a link back to vertex V,
807 examine the next link in V's LSA.[23] */
808 if (w_lsa == NULL)
Paul Jakmab75ae992007-03-23 11:17:28 +0000809 {
810 if (IS_DEBUG_OSPF_EVENT)
811 zlog_debug ("No LSA found");
812 continue;
813 }
paul718e3742002-12-13 20:15:29 +0000814
815 if (IS_LSA_MAXAGE (w_lsa))
Paul Jakmab75ae992007-03-23 11:17:28 +0000816 {
817 if (IS_DEBUG_OSPF_EVENT)
818 zlog_debug ("LSA is MaxAge");
819 continue;
820 }
paul718e3742002-12-13 20:15:29 +0000821
pauleb3da6d2005-10-18 04:20:33 +0000822 if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 )
paul718e3742002-12-13 20:15:29 +0000823 {
paul0c0f9cd2003-06-06 23:27:04 +0000824 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000825 zlog_debug ("The LSA doesn't have a link back");
paul718e3742002-12-13 20:15:29 +0000826 continue;
827 }
828
829 /* (c) If vertex W is already on the shortest-path tree, examine
830 the next link in the LSA. */
hasso462f20d2005-02-23 11:29:02 +0000831 if (w_lsa->stat == LSA_SPF_IN_SPFTREE)
832 {
833 if (IS_DEBUG_OSPF_EVENT)
834 zlog_debug ("The LSA is already in SPF");
835 continue;
836 }
paul718e3742002-12-13 20:15:29 +0000837
838 /* (d) Calculate the link state cost D of the resulting path
839 from the root to vertex W. D is equal to the sum of the link
840 state cost of the (already calculated) shortest path to
841 vertex V and the advertised cost of the link between vertices
842 V and W. If D is: */
843
paul718e3742002-12-13 20:15:29 +0000844 /* calculate link cost D. */
845 if (v->lsa->type == OSPF_ROUTER_LSA)
pauleb3da6d2005-10-18 04:20:33 +0000846 distance = v->distance + ntohs (l->m[0].metric);
gdt630e4802004-08-31 17:28:41 +0000847 else /* v is not a Router-LSA */
pauleb3da6d2005-10-18 04:20:33 +0000848 distance = v->distance;
paul718e3742002-12-13 20:15:29 +0000849
850 /* Is there already vertex W in candidate list? */
hasso462f20d2005-02-23 11:29:02 +0000851 if (w_lsa->stat == LSA_SPF_NOT_EXPLORED)
852 {
pauleb3da6d2005-10-18 04:20:33 +0000853 /* prepare vertex W. */
854 w = ospf_vertex_new (w_lsa);
855
hasso462f20d2005-02-23 11:29:02 +0000856 /* Calculate nexthop to W. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000857 if (ospf_nexthop_calculation (area, v, w, l, distance))
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000858 pqueue_enqueue (w, candidate);
Paul Jakmab75ae992007-03-23 11:17:28 +0000859 else if (IS_DEBUG_OSPF_EVENT)
860 zlog_debug ("Nexthop Calc failed");
hasso462f20d2005-02-23 11:29:02 +0000861 }
862 else if (w_lsa->stat >= 0)
863 {
864 /* Get the vertex from candidates. */
pauleb3da6d2005-10-18 04:20:33 +0000865 w = candidate->array[w_lsa->stat];
paul718e3742002-12-13 20:15:29 +0000866
hasso462f20d2005-02-23 11:29:02 +0000867 /* if D is greater than. */
pauleb3da6d2005-10-18 04:20:33 +0000868 if (w->distance < distance)
paul718e3742002-12-13 20:15:29 +0000869 {
paul718e3742002-12-13 20:15:29 +0000870 continue;
871 }
hasso462f20d2005-02-23 11:29:02 +0000872 /* equal to. */
pauleb3da6d2005-10-18 04:20:33 +0000873 else if (w->distance == distance)
paul718e3742002-12-13 20:15:29 +0000874 {
pauleb3da6d2005-10-18 04:20:33 +0000875 /* Found an equal-cost path to W.
876 * Calculate nexthop of to W from V. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000877 ospf_nexthop_calculation (area, v, w, l, distance);
paul718e3742002-12-13 20:15:29 +0000878 }
hasso462f20d2005-02-23 11:29:02 +0000879 /* less than. */
880 else
paul718e3742002-12-13 20:15:29 +0000881 {
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000882 /* Found a lower-cost path to W.
883 * nexthop_calculation is conditional, if it finds
884 * valid nexthop it will call spf_add_parents, which
885 * will flush the old parents
886 */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000887 if (ospf_nexthop_calculation (area, v, w, l, distance))
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000888 /* Decrease the key of the node in the heap,
889 * re-sort the heap. */
890 trickle_down (w_lsa->stat, candidate);
paul718e3742002-12-13 20:15:29 +0000891 }
gdt630e4802004-08-31 17:28:41 +0000892 } /* end W is already on the candidate list */
893 } /* end loop over the links in V's LSA */
paul718e3742002-12-13 20:15:29 +0000894}
895
paul4dadc292005-05-06 21:37:42 +0000896static void
paul718e3742002-12-13 20:15:29 +0000897ospf_spf_dump (struct vertex *v, int i)
898{
hasso52dc7ee2004-09-23 19:18:23 +0000899 struct listnode *cnode;
900 struct listnode *nnode;
pauleb3da6d2005-10-18 04:20:33 +0000901 struct vertex_parent *parent;
paul718e3742002-12-13 20:15:29 +0000902
903 if (v->type == OSPF_VERTEX_ROUTER)
904 {
905 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000906 zlog_debug ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id));
paul718e3742002-12-13 20:15:29 +0000907 }
908 else
909 {
910 struct network_lsa *lsa = (struct network_lsa *) v->lsa;
911 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000912 zlog_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id),
paul0c0f9cd2003-06-06 23:27:04 +0000913 ip_masklen (lsa->mask));
gdt630e4802004-08-31 17:28:41 +0000914 }
paul718e3742002-12-13 20:15:29 +0000915
paul1eb8ef22005-04-07 07:30:20 +0000916 if (IS_DEBUG_OSPF_EVENT)
pauleb3da6d2005-10-18 04:20:33 +0000917 for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent))
918 {
919 zlog_debug (" nexthop %p %s %s",
920 parent->nexthop,
921 inet_ntoa (parent->nexthop->router),
922 parent->nexthop->oi ? IF_NAME(parent->nexthop->oi)
923 : "NULL");
924 }
paul718e3742002-12-13 20:15:29 +0000925
926 i++;
927
pauleb3da6d2005-10-18 04:20:33 +0000928 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v))
paul1eb8ef22005-04-07 07:30:20 +0000929 ospf_spf_dump (v, i);
paul718e3742002-12-13 20:15:29 +0000930}
931
932/* Second stage of SPF calculation. */
paul4dadc292005-05-06 21:37:42 +0000933static void
paul0c0f9cd2003-06-06 23:27:04 +0000934ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v,
paul718e3742002-12-13 20:15:29 +0000935 struct route_table *rt)
936{
paul1eb8ef22005-04-07 07:30:20 +0000937 struct listnode *cnode, *cnnode;
paul718e3742002-12-13 20:15:29 +0000938 struct vertex *child;
939
940 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000941 zlog_debug ("ospf_process_stub():processing stubs for area %s",
paul0c0f9cd2003-06-06 23:27:04 +0000942 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +0000943 if (v->type == OSPF_VERTEX_ROUTER)
944 {
945 u_char *p;
946 u_char *lim;
947 struct router_lsa_link *l;
948 struct router_lsa *rlsa;
949
paul0c0f9cd2003-06-06 23:27:04 +0000950 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000951 zlog_debug ("ospf_process_stubs():processing router LSA, id: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000952 inet_ntoa (v->lsa->id));
paul718e3742002-12-13 20:15:29 +0000953 rlsa = (struct router_lsa *) v->lsa;
954
955
paul0c0f9cd2003-06-06 23:27:04 +0000956 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000957 zlog_debug ("ospf_process_stubs(): we have %d links to process",
paul0c0f9cd2003-06-06 23:27:04 +0000958 ntohs (rlsa->links));
gdt630e4802004-08-31 17:28:41 +0000959 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul718e3742002-12-13 20:15:29 +0000960 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
961
962 while (p < lim)
963 {
964 l = (struct router_lsa_link *) p;
965
966 p += (ROUTER_LSA_MIN_SIZE +
967 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
968
969 if (l->m[0].type == LSA_LINK_TYPE_STUB)
970 ospf_intra_add_stub (rt, l, v, area);
971 }
972 }
973
gdt630e4802004-08-31 17:28:41 +0000974 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1);
paul718e3742002-12-13 20:15:29 +0000975
pauleb3da6d2005-10-18 04:20:33 +0000976 for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child))
paul718e3742002-12-13 20:15:29 +0000977 {
paul718e3742002-12-13 20:15:29 +0000978 if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED))
paul0c0f9cd2003-06-06 23:27:04 +0000979 continue;
paul718e3742002-12-13 20:15:29 +0000980
981 ospf_spf_process_stubs (area, child, rt);
982
983 SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED);
984 }
985}
986
987void
988ospf_rtrs_free (struct route_table *rtrs)
989{
990 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +0000991 struct list *or_list;
paul1eb8ef22005-04-07 07:30:20 +0000992 struct ospf_route *or;
993 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000994
995 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000996 zlog_debug ("Route: Router Routing Table free");
paul718e3742002-12-13 20:15:29 +0000997
998 for (rn = route_top (rtrs); rn; rn = route_next (rn))
999 if ((or_list = rn->info) != NULL)
1000 {
paul1eb8ef22005-04-07 07:30:20 +00001001 for (ALL_LIST_ELEMENTS (or_list, node, nnode, or))
1002 ospf_route_free (or);
paul718e3742002-12-13 20:15:29 +00001003
paul0c0f9cd2003-06-06 23:27:04 +00001004 list_delete (or_list);
paul718e3742002-12-13 20:15:29 +00001005
paul0c0f9cd2003-06-06 23:27:04 +00001006 /* Unlock the node. */
1007 rn->info = NULL;
1008 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +00001009 }
1010 route_table_finish (rtrs);
1011}
1012
paul4dadc292005-05-06 21:37:42 +00001013static void
paul718e3742002-12-13 20:15:29 +00001014ospf_rtrs_print (struct route_table *rtrs)
1015{
1016 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +00001017 struct list *or_list;
1018 struct listnode *ln;
1019 struct listnode *pnode;
paul718e3742002-12-13 20:15:29 +00001020 struct ospf_route *or;
1021 struct ospf_path *path;
1022 char buf1[BUFSIZ];
1023 char buf2[BUFSIZ];
1024
1025 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001026 zlog_debug ("ospf_rtrs_print() start");
paul718e3742002-12-13 20:15:29 +00001027
1028 for (rn = route_top (rtrs); rn; rn = route_next (rn))
1029 if ((or_list = rn->info) != NULL)
paul1eb8ef22005-04-07 07:30:20 +00001030 for (ALL_LIST_ELEMENTS_RO (or_list, ln, or))
paul718e3742002-12-13 20:15:29 +00001031 {
paul718e3742002-12-13 20:15:29 +00001032 switch (or->path_type)
1033 {
1034 case OSPF_PATH_INTRA_AREA:
paul0c0f9cd2003-06-06 23:27:04 +00001035 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001036 zlog_debug ("%s [%d] area: %s",
paul0c0f9cd2003-06-06 23:27:04 +00001037 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1038 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1039 buf2, BUFSIZ));
paul718e3742002-12-13 20:15:29 +00001040 break;
1041 case OSPF_PATH_INTER_AREA:
paul0c0f9cd2003-06-06 23:27:04 +00001042 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001043 zlog_debug ("%s IA [%d] area: %s",
paul0c0f9cd2003-06-06 23:27:04 +00001044 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1045 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1046 buf2, BUFSIZ));
paul718e3742002-12-13 20:15:29 +00001047 break;
1048 default:
1049 break;
1050 }
1051
paul1eb8ef22005-04-07 07:30:20 +00001052 for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
paul718e3742002-12-13 20:15:29 +00001053 {
paul718e3742002-12-13 20:15:29 +00001054 if (path->nexthop.s_addr == 0)
paul0c0f9cd2003-06-06 23:27:04 +00001055 {
1056 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001057 zlog_debug (" directly attached to %s\r\n",
paul0c0f9cd2003-06-06 23:27:04 +00001058 IF_NAME (path->oi));
1059 }
1060 else
1061 {
1062 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001063 zlog_debug (" via %s, %s\r\n",
paul0c0f9cd2003-06-06 23:27:04 +00001064 inet_ntoa (path->nexthop), IF_NAME (path->oi));
1065 }
paul718e3742002-12-13 20:15:29 +00001066 }
1067 }
1068
ajs2a42e282004-12-08 18:43:03 +00001069 zlog_debug ("ospf_rtrs_print() end");
paul718e3742002-12-13 20:15:29 +00001070}
1071
1072/* Calculating the shortest-path tree for an area. */
paul4dadc292005-05-06 21:37:42 +00001073static void
paul0c0f9cd2003-06-06 23:27:04 +00001074ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
paul718e3742002-12-13 20:15:29 +00001075 struct route_table *new_rtrs)
1076{
hasso462f20d2005-02-23 11:29:02 +00001077 struct pqueue *candidate;
paul718e3742002-12-13 20:15:29 +00001078 struct vertex *v;
pauleb3da6d2005-10-18 04:20:33 +00001079
paul718e3742002-12-13 20:15:29 +00001080 if (IS_DEBUG_OSPF_EVENT)
1081 {
ajs2a42e282004-12-08 18:43:03 +00001082 zlog_debug ("ospf_spf_calculate: Start");
1083 zlog_debug ("ospf_spf_calculate: running Dijkstra for area %s",
paul0c0f9cd2003-06-06 23:27:04 +00001084 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +00001085 }
1086
1087 /* Check router-lsa-self. If self-router-lsa is not yet allocated,
1088 return this area's calculation. */
paul0c0f9cd2003-06-06 23:27:04 +00001089 if (!area->router_lsa_self)
paul718e3742002-12-13 20:15:29 +00001090 {
1091 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001092 zlog_debug ("ospf_spf_calculate: "
paul0c0f9cd2003-06-06 23:27:04 +00001093 "Skip area %s's calculation due to empty router_lsa_self",
1094 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +00001095 return;
1096 }
1097
1098 /* RFC2328 16.1. (1). */
paul0c0f9cd2003-06-06 23:27:04 +00001099 /* Initialize the algorithm's data structures. */
hasso462f20d2005-02-23 11:29:02 +00001100
1101 /* This function scans all the LSA database and set the stat field to
1102 * LSA_SPF_NOT_EXPLORED. */
1103 ospf_lsdb_clean_stat (area->lsdb);
1104 /* Create a new heap for the candidates. */
1105 candidate = pqueue_create();
1106 candidate->cmp = cmp;
1107 candidate->update = update_stat;
paul718e3742002-12-13 20:15:29 +00001108
1109 /* Initialize the shortest-path tree to only the root (which is the
1110 router doing the calculation). */
1111 ospf_spf_init (area);
1112 v = area->spf;
hasso462f20d2005-02-23 11:29:02 +00001113 /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the
1114 * spanning tree. */
1115 *(v->stat) = LSA_SPF_IN_SPFTREE;
paul718e3742002-12-13 20:15:29 +00001116
1117 /* Set Area A's TransitCapability to FALSE. */
1118 area->transit = OSPF_TRANSIT_FALSE;
1119 area->shortcut_capability = 1;
pauleb3da6d2005-10-18 04:20:33 +00001120
paul718e3742002-12-13 20:15:29 +00001121 for (;;)
1122 {
1123 /* RFC2328 16.1. (2). */
hasso462f20d2005-02-23 11:29:02 +00001124 ospf_spf_next (v, area, candidate);
paul718e3742002-12-13 20:15:29 +00001125
1126 /* RFC2328 16.1. (3). */
1127 /* If at this step the candidate list is empty, the shortest-
1128 path tree (of transit vertices) has been completely built and
1129 this stage of the procedure terminates. */
hasso462f20d2005-02-23 11:29:02 +00001130 if (candidate->size == 0)
paul718e3742002-12-13 20:15:29 +00001131 break;
1132
1133 /* Otherwise, choose the vertex belonging to the candidate list
1134 that is closest to the root, and add it to the shortest-path
1135 tree (removing it from the candidate list in the
paul0c0f9cd2003-06-06 23:27:04 +00001136 process). */
hasso462f20d2005-02-23 11:29:02 +00001137 /* Extract from the candidates the node with the lower key. */
1138 v = (struct vertex *) pqueue_dequeue (candidate);
1139 /* Update stat field in vertex. */
1140 *(v->stat) = LSA_SPF_IN_SPFTREE;
pauleb3da6d2005-10-18 04:20:33 +00001141
paul718e3742002-12-13 20:15:29 +00001142 ospf_vertex_add_parent (v);
1143
paul718e3742002-12-13 20:15:29 +00001144 /* Note that when there is a choice of vertices closest to the
1145 root, network vertices must be chosen before router vertices
1146 in order to necessarily find all equal-cost paths. */
1147 /* We don't do this at this moment, we should add the treatment
1148 above codes. -- kunihiro. */
1149
1150 /* RFC2328 16.1. (4). */
1151 if (v->type == OSPF_VERTEX_ROUTER)
1152 ospf_intra_add_router (new_rtrs, v, area);
paul0c0f9cd2003-06-06 23:27:04 +00001153 else
paul718e3742002-12-13 20:15:29 +00001154 ospf_intra_add_transit (new_table, v, area);
1155
1156 /* RFC2328 16.1. (5). */
1157 /* Iterate the algorithm by returning to Step 2. */
gdt630e4802004-08-31 17:28:41 +00001158
1159 } /* end loop until no more candidate vertices */
paul718e3742002-12-13 20:15:29 +00001160
1161 if (IS_DEBUG_OSPF_EVENT)
1162 {
1163 ospf_spf_dump (area->spf, 0);
1164 ospf_route_table_dump (new_table);
1165 }
1166
1167 /* Second stage of SPF calculation procedure's */
1168 ospf_spf_process_stubs (area, area->spf, new_table);
1169
pauleb3da6d2005-10-18 04:20:33 +00001170 /* Free candidate queue. */
hasso462f20d2005-02-23 11:29:02 +00001171 pqueue_delete (candidate);
pauleb3da6d2005-10-18 04:20:33 +00001172
1173 ospf_vertex_dump (__func__, area->spf, 0, 1);
1174 /* Free nexthop information, canonical versions of which are attached
1175 * the first level of router vertices attached to the root vertex, see
1176 * ospf_nexthop_calculation.
1177 */
1178 ospf_canonical_nexthops_free (area->spf);
1179
Paul Jakma9c27ef92006-05-04 07:32:57 +00001180 /* Free SPF vertices, but not the list. List has ospf_vertex_free
1181 * as deconstructor.
1182 */
1183 list_delete_all_node (&vertex_list);
pauleb3da6d2005-10-18 04:20:33 +00001184
paul718e3742002-12-13 20:15:29 +00001185 /* Increment SPF Calculation Counter. */
1186 area->spf_calculation++;
1187
Paul Jakma2518efd2006-08-27 06:49:29 +00001188 quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf);
paul718e3742002-12-13 20:15:29 +00001189
1190 if (IS_DEBUG_OSPF_EVENT)
Paul Jakma9c27ef92006-05-04 07:32:57 +00001191 zlog_debug ("ospf_spf_calculate: Stop. %ld vertices",
1192 mtype_stats_alloc(MTYPE_OSPF_VERTEX));
paul718e3742002-12-13 20:15:29 +00001193}
1194
1195/* Timer for SPF calculation. */
paul4dadc292005-05-06 21:37:42 +00001196static int
paul68980082003-03-25 05:07:42 +00001197ospf_spf_calculate_timer (struct thread *thread)
paul718e3742002-12-13 20:15:29 +00001198{
paul68980082003-03-25 05:07:42 +00001199 struct ospf *ospf = THREAD_ARG (thread);
paul718e3742002-12-13 20:15:29 +00001200 struct route_table *new_table, *new_rtrs;
paul1eb8ef22005-04-07 07:30:20 +00001201 struct ospf_area *area;
1202 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001203
1204 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001205 zlog_debug ("SPF: Timer (SPF calculation expire)");
paul0c0f9cd2003-06-06 23:27:04 +00001206
paul718e3742002-12-13 20:15:29 +00001207 ospf->t_spf_calc = NULL;
1208
1209 /* Allocate new table tree. */
1210 new_table = route_table_init ();
paul0c0f9cd2003-06-06 23:27:04 +00001211 new_rtrs = route_table_init ();
paul718e3742002-12-13 20:15:29 +00001212
paul68980082003-03-25 05:07:42 +00001213 ospf_vl_unapprove (ospf);
paul718e3742002-12-13 20:15:29 +00001214
1215 /* Calculate SPF for each area. */
paul1eb8ef22005-04-07 07:30:20 +00001216 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
Paul Jakma9c27ef92006-05-04 07:32:57 +00001217 {
1218 /* Do backbone last, so as to first discover intra-area paths
1219 * for any back-bone virtual-links
1220 */
1221 if (ospf->backbone && ospf->backbone == area)
1222 continue;
1223
1224 ospf_spf_calculate (area, new_table, new_rtrs);
1225 }
1226
1227 /* SPF for backbone, if required */
1228 if (ospf->backbone)
1229 ospf_spf_calculate (ospf->backbone, new_table, new_rtrs);
1230
paul68980082003-03-25 05:07:42 +00001231 ospf_vl_shut_unapproved (ospf);
paul718e3742002-12-13 20:15:29 +00001232
paul68980082003-03-25 05:07:42 +00001233 ospf_ia_routing (ospf, new_table, new_rtrs);
paul718e3742002-12-13 20:15:29 +00001234
1235 ospf_prune_unreachable_networks (new_table);
1236 ospf_prune_unreachable_routers (new_rtrs);
1237
1238 /* AS-external-LSA calculation should not be performed here. */
1239
1240 /* If new Router Route is installed,
1241 then schedule re-calculate External routes. */
1242 if (1)
paul68980082003-03-25 05:07:42 +00001243 ospf_ase_calculate_schedule (ospf);
paul718e3742002-12-13 20:15:29 +00001244
paul68980082003-03-25 05:07:42 +00001245 ospf_ase_calculate_timer_add (ospf);
paul718e3742002-12-13 20:15:29 +00001246
1247 /* Update routing table. */
paul68980082003-03-25 05:07:42 +00001248 ospf_route_install (ospf, new_table);
paul718e3742002-12-13 20:15:29 +00001249
1250 /* Update ABR/ASBR routing table */
paul68980082003-03-25 05:07:42 +00001251 if (ospf->old_rtrs)
paul718e3742002-12-13 20:15:29 +00001252 {
1253 /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */
paul68980082003-03-25 05:07:42 +00001254 /* ospf_route_delete (ospf->old_rtrs); */
1255 ospf_rtrs_free (ospf->old_rtrs);
paul718e3742002-12-13 20:15:29 +00001256 }
1257
paul68980082003-03-25 05:07:42 +00001258 ospf->old_rtrs = ospf->new_rtrs;
1259 ospf->new_rtrs = new_rtrs;
paul718e3742002-12-13 20:15:29 +00001260
paul0c0f9cd2003-06-06 23:27:04 +00001261 if (IS_OSPF_ABR (ospf))
paul68980082003-03-25 05:07:42 +00001262 ospf_abr_task (ospf);
paul718e3742002-12-13 20:15:29 +00001263
1264 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001265 zlog_debug ("SPF: calculation complete");
paul718e3742002-12-13 20:15:29 +00001266
1267 return 0;
1268}
1269
1270/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
1271 set timer for SPF calc. */
1272void
paul68980082003-03-25 05:07:42 +00001273ospf_spf_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +00001274{
pauld24f6e22005-10-21 09:23:12 +00001275 unsigned long delay, elapsed, ht;
1276 struct timeval result;
paul718e3742002-12-13 20:15:29 +00001277
1278 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001279 zlog_debug ("SPF: calculation timer scheduled");
paul718e3742002-12-13 20:15:29 +00001280
1281 /* OSPF instance does not exist. */
paul68980082003-03-25 05:07:42 +00001282 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +00001283 return;
pauld24f6e22005-10-21 09:23:12 +00001284
paul718e3742002-12-13 20:15:29 +00001285 /* SPF calculation timer is already scheduled. */
paul68980082003-03-25 05:07:42 +00001286 if (ospf->t_spf_calc)
paul718e3742002-12-13 20:15:29 +00001287 {
1288 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001289 zlog_debug ("SPF: calculation timer is already scheduled: %p",
paul0c0f9cd2003-06-06 23:27:04 +00001290 ospf->t_spf_calc);
paul718e3742002-12-13 20:15:29 +00001291 return;
1292 }
pauld24f6e22005-10-21 09:23:12 +00001293
1294 /* XXX Monotic timers: we only care about relative time here. */
Paul Jakma2518efd2006-08-27 06:49:29 +00001295 result = tv_sub (recent_relative_time (), ospf->ts_spf);
pauld24f6e22005-10-21 09:23:12 +00001296
1297 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
1298 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1299
1300 if (ht > ospf->spf_max_holdtime)
1301 ht = ospf->spf_max_holdtime;
1302
paul718e3742002-12-13 20:15:29 +00001303 /* Get SPF calculation delay time. */
pauld24f6e22005-10-21 09:23:12 +00001304 if (elapsed < ht)
paul718e3742002-12-13 20:15:29 +00001305 {
pauld24f6e22005-10-21 09:23:12 +00001306 /* Got an event within the hold time of last SPF. We need to
1307 * increase the hold_multiplier, if it's not already at/past
1308 * maximum value, and wasn't already increased..
1309 */
1310 if (ht < ospf->spf_max_holdtime)
1311 ospf->spf_hold_multiplier++;
1312
1313 /* always honour the SPF initial delay */
1314 if ( (ht - elapsed) < ospf->spf_delay)
paul0c0f9cd2003-06-06 23:27:04 +00001315 delay = ospf->spf_delay;
paul718e3742002-12-13 20:15:29 +00001316 else
pauld24f6e22005-10-21 09:23:12 +00001317 delay = ht - elapsed;
paul718e3742002-12-13 20:15:29 +00001318 }
1319 else
pauld24f6e22005-10-21 09:23:12 +00001320 {
1321 /* Event is past required hold-time of last SPF */
1322 delay = ospf->spf_delay;
1323 ospf->spf_hold_multiplier = 1;
1324 }
1325
paul718e3742002-12-13 20:15:29 +00001326 if (IS_DEBUG_OSPF_EVENT)
pauld24f6e22005-10-21 09:23:12 +00001327 zlog_debug ("SPF: calculation timer delay = %ld", delay);
1328
paul68980082003-03-25 05:07:42 +00001329 ospf->t_spf_calc =
pauld24f6e22005-10-21 09:23:12 +00001330 thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay);
paul718e3742002-12-13 20:15:29 +00001331}