blob: 956684357059385afb76c0eb2933ed7df7fbc843 [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;
pauleb3da6d2005-10-18 04:20:33 +0000175 new->children = list_new ();
176 new->parents = list_new ();
Paul Jakma9c27ef92006-05-04 07:32:57 +0000177 new->parents->del = vertex_parent_free;
pauleb3da6d2005-10-18 04:20:33 +0000178
Paul Jakma9c27ef92006-05-04 07:32:57 +0000179 listnode_add (&vertex_list, new);
180
181 if (IS_DEBUG_OSPF_EVENT)
182 zlog_debug ("%s: Created %s vertex %s", __func__,
183 new->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
184 inet_ntoa (new->lsa->id));
paul718e3742002-12-13 20:15:29 +0000185 return new;
186}
187
paul4dadc292005-05-06 21:37:42 +0000188static void
Paul Jakma9c27ef92006-05-04 07:32:57 +0000189ospf_vertex_free (void *data)
paul718e3742002-12-13 20:15:29 +0000190{
Paul Jakma9c27ef92006-05-04 07:32:57 +0000191 struct vertex *v = data;
paul7461d452005-06-13 13:57:16 +0000192
Paul Jakma9c27ef92006-05-04 07:32:57 +0000193 if (IS_DEBUG_OSPF_EVENT)
194 zlog_debug ("%s: Free %s vertex %s", __func__,
195 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
196 inet_ntoa (v->lsa->id));
pauleb3da6d2005-10-18 04:20:33 +0000197
Paul Jakma9c27ef92006-05-04 07:32:57 +0000198 /* There should be no parents potentially holding references to this vertex
199 * Children however may still be there, but presumably referenced by other
200 * vertices
pauleb3da6d2005-10-18 04:20:33 +0000201 */
Paul Jakma9c27ef92006-05-04 07:32:57 +0000202 //assert (listcount (v->parents) == 0);
pauleb3da6d2005-10-18 04:20:33 +0000203
Paul Jakma9c27ef92006-05-04 07:32:57 +0000204 if (v->children)
205 list_delete (v->children);
206 v->children = NULL;
207
208 if (v->parents)
209 list_delete (v->parents);
pauleb3da6d2005-10-18 04:20:33 +0000210 v->parents = NULL;
211
212 v->lsa = NULL;
paul7461d452005-06-13 13:57:16 +0000213
paul718e3742002-12-13 20:15:29 +0000214 XFREE (MTYPE_OSPF_VERTEX, v);
215}
216
paul4dadc292005-05-06 21:37:42 +0000217static void
hassoeb1ce602004-10-08 08:17:22 +0000218ospf_vertex_dump(const char *msg, struct vertex *v,
pauleb3da6d2005-10-18 04:20:33 +0000219 int print_parents, int print_children)
gdt630e4802004-08-31 17:28:41 +0000220{
221 if ( ! IS_DEBUG_OSPF_EVENT)
222 return;
223
pauleb3da6d2005-10-18 04:20:33 +0000224 zlog_debug("%s %s vertex %s distance %u flags %u",
gdt630e4802004-08-31 17:28:41 +0000225 msg,
226 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
227 inet_ntoa(v->lsa->id),
228 v->distance,
gdt630e4802004-08-31 17:28:41 +0000229 (unsigned int)v->flags);
230
pauleb3da6d2005-10-18 04:20:33 +0000231 if (print_parents)
gdt630e4802004-08-31 17:28:41 +0000232 {
paul1eb8ef22005-04-07 07:30:20 +0000233 struct listnode *node;
pauleb3da6d2005-10-18 04:20:33 +0000234 struct vertex_parent *vp;
paul1eb8ef22005-04-07 07:30:20 +0000235
pauleb3da6d2005-10-18 04:20:33 +0000236 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
gdt630e4802004-08-31 17:28:41 +0000237 {
238 char buf1[BUFSIZ];
pauleb3da6d2005-10-18 04:20:33 +0000239
240 if (vp)
gdt630e4802004-08-31 17:28:41 +0000241 {
pauleb3da6d2005-10-18 04:20:33 +0000242 zlog_debug ("parent %s backlink %d nexthop %s interface %s",
243 inet_ntoa(vp->parent->lsa->id), vp->backlink,
244 inet_ntop(AF_INET, &vp->nexthop->router, buf1, BUFSIZ),
245 vp->nexthop->oi ? IF_NAME(vp->nexthop->oi) : "NULL");
gdt630e4802004-08-31 17:28:41 +0000246 }
247 }
248 }
249
250 if (print_children)
251 {
hasso52dc7ee2004-09-23 19:18:23 +0000252 struct listnode *cnode;
paul1eb8ef22005-04-07 07:30:20 +0000253 struct vertex *cv;
254
pauleb3da6d2005-10-18 04:20:33 +0000255 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv))
paul1eb8ef22005-04-07 07:30:20 +0000256 ospf_vertex_dump(" child:", cv, 0, 0);
gdt630e4802004-08-31 17:28:41 +0000257 }
258}
259
260
261/* Add a vertex to the list of children in each of its parents. */
paul4dadc292005-05-06 21:37:42 +0000262static void
paul718e3742002-12-13 20:15:29 +0000263ospf_vertex_add_parent (struct vertex *v)
264{
pauleb3da6d2005-10-18 04:20:33 +0000265 struct vertex_parent *vp;
hasso52dc7ee2004-09-23 19:18:23 +0000266 struct listnode *node;
paul7461d452005-06-13 13:57:16 +0000267
Paul Jakma9c27ef92006-05-04 07:32:57 +0000268 assert (v && v->parents);
paul7461d452005-06-13 13:57:16 +0000269
pauleb3da6d2005-10-18 04:20:33 +0000270 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
paul718e3742002-12-13 20:15:29 +0000271 {
pauleb3da6d2005-10-18 04:20:33 +0000272 assert (vp->parent && vp->parent->children);
paul7461d452005-06-13 13:57:16 +0000273
paul718e3742002-12-13 20:15:29 +0000274 /* No need to add two links from the same parent. */
pauleb3da6d2005-10-18 04:20:33 +0000275 if (listnode_lookup (vp->parent->children, v) == NULL)
276 listnode_add (vp->parent->children, v);
paul718e3742002-12-13 20:15:29 +0000277 }
278}
279
paul4dadc292005-05-06 21:37:42 +0000280static void
paul718e3742002-12-13 20:15:29 +0000281ospf_spf_init (struct ospf_area *area)
282{
283 struct vertex *v;
Paul Jakma9c27ef92006-05-04 07:32:57 +0000284
paul718e3742002-12-13 20:15:29 +0000285 /* Create root node. */
286 v = ospf_vertex_new (area->router_lsa_self);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000287
paul718e3742002-12-13 20:15:29 +0000288 area->spf = v;
289
290 /* Reset ABR and ASBR router counts. */
291 area->abr_count = 0;
292 area->asbr_count = 0;
293}
294
pauld355bfa2004-04-08 07:43:45 +0000295/* return index of link back to V from W, or -1 if no link found */
paul4dadc292005-05-06 21:37:42 +0000296static int
paul718e3742002-12-13 20:15:29 +0000297ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v)
298{
hassoeb1ce602004-10-08 08:17:22 +0000299 unsigned int i, length;
paul718e3742002-12-13 20:15:29 +0000300 struct router_lsa *rl;
301 struct network_lsa *nl;
302
303 /* In case of W is Network LSA. */
304 if (w->type == OSPF_NETWORK_LSA)
305 {
306 if (v->type == OSPF_NETWORK_LSA)
pauld355bfa2004-04-08 07:43:45 +0000307 return -1;
paul718e3742002-12-13 20:15:29 +0000308
309 nl = (struct network_lsa *) w;
310 length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
paul0c0f9cd2003-06-06 23:27:04 +0000311
paul718e3742002-12-13 20:15:29 +0000312 for (i = 0; i < length; i++)
313 if (IPV4_ADDR_SAME (&nl->routers[i], &v->id))
pauld355bfa2004-04-08 07:43:45 +0000314 return i;
315 return -1;
paul718e3742002-12-13 20:15:29 +0000316 }
317
318 /* In case of W is Router LSA. */
319 if (w->type == OSPF_ROUTER_LSA)
320 {
321 rl = (struct router_lsa *) w;
322
323 length = ntohs (w->length);
324
325 for (i = 0;
paul0c0f9cd2003-06-06 23:27:04 +0000326 i < ntohs (rl->links) && length >= sizeof (struct router_lsa);
327 i++, length -= 12)
paul718e3742002-12-13 20:15:29 +0000328 {
329 switch (rl->link[i].type)
330 {
331 case LSA_LINK_TYPE_POINTOPOINT:
332 case LSA_LINK_TYPE_VIRTUALLINK:
333 /* Router LSA ID. */
334 if (v->type == OSPF_ROUTER_LSA &&
335 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
336 {
pauld355bfa2004-04-08 07:43:45 +0000337 return i;
paul718e3742002-12-13 20:15:29 +0000338 }
339 break;
340 case LSA_LINK_TYPE_TRANSIT:
341 /* Network LSA ID. */
342 if (v->type == OSPF_NETWORK_LSA &&
343 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
344 {
pauld355bfa2004-04-08 07:43:45 +0000345 return i;
paul0c0f9cd2003-06-06 23:27:04 +0000346 }
paul718e3742002-12-13 20:15:29 +0000347 break;
348 case LSA_LINK_TYPE_STUB:
pauleb3da6d2005-10-18 04:20:33 +0000349 /* Stub can't lead anywhere, carry on */
paul718e3742002-12-13 20:15:29 +0000350 continue;
351 default:
352 break;
353 }
354 }
355 }
pauld355bfa2004-04-08 07:43:45 +0000356 return -1;
paul718e3742002-12-13 20:15:29 +0000357}
358
paul718e3742002-12-13 20:15:29 +0000359#define ROUTER_LSA_MIN_SIZE 12
360#define ROUTER_LSA_TOS_SIZE 4
361
gdt630e4802004-08-31 17:28:41 +0000362/* Find the next link after prev_link from v to w. If prev_link is
363 * NULL, return the first link from v to w. Ignore stub and virtual links;
364 * these link types will never be returned.
365 */
paul4dadc292005-05-06 21:37:42 +0000366static struct router_lsa_link *
paul718e3742002-12-13 20:15:29 +0000367ospf_get_next_link (struct vertex *v, struct vertex *w,
paul0c0f9cd2003-06-06 23:27:04 +0000368 struct router_lsa_link *prev_link)
paul718e3742002-12-13 20:15:29 +0000369{
370 u_char *p;
371 u_char *lim;
Joakim Tjernlundbd540372009-07-27 12:42:31 +0200372 u_char lsa_type = LSA_LINK_TYPE_TRANSIT;
paul718e3742002-12-13 20:15:29 +0000373 struct router_lsa_link *l;
374
Joakim Tjernlundbd540372009-07-27 12:42:31 +0200375 if (w->type == OSPF_VERTEX_ROUTER)
376 lsa_type = LSA_LINK_TYPE_POINTOPOINT;
377
paul718e3742002-12-13 20:15:29 +0000378 if (prev_link == NULL)
gdt630e4802004-08-31 17:28:41 +0000379 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul718e3742002-12-13 20:15:29 +0000380 else
381 {
paul0c0f9cd2003-06-06 23:27:04 +0000382 p = (u_char *) prev_link;
paul718e3742002-12-13 20:15:29 +0000383 p += (ROUTER_LSA_MIN_SIZE +
384 (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
385 }
paul0c0f9cd2003-06-06 23:27:04 +0000386
paul718e3742002-12-13 20:15:29 +0000387 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
388
389 while (p < lim)
390 {
391 l = (struct router_lsa_link *) p;
392
paul0c0f9cd2003-06-06 23:27:04 +0000393 p += (ROUTER_LSA_MIN_SIZE + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
paul718e3742002-12-13 20:15:29 +0000394
Joakim Tjernlundbd540372009-07-27 12:42:31 +0200395 if (l->m[0].type != lsa_type)
paul0c0f9cd2003-06-06 23:27:04 +0000396 continue;
paul718e3742002-12-13 20:15:29 +0000397
398 if (IPV4_ADDR_SAME (&l->link_id, &w->id))
paul0c0f9cd2003-06-06 23:27:04 +0000399 return l;
paul718e3742002-12-13 20:15:29 +0000400 }
401
402 return NULL;
403}
404
pauleb3da6d2005-10-18 04:20:33 +0000405static void
406ospf_spf_flush_parents (struct vertex *w)
407{
408 struct vertex_parent *vp;
409 struct listnode *ln, *nn;
410
411 /* delete the existing nexthops */
412 for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp))
413 {
414 list_delete_node (w->parents, ln);
415 vertex_parent_free (vp);
416 }
417}
418
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000419/*
420 * Consider supplied next-hop for inclusion to the supplied list of
421 * equal-cost next-hops, adjust list as neccessary.
422 */
423static void
424ospf_spf_add_parent (struct vertex *v, struct vertex *w,
425 struct vertex_nexthop *newhop,
Paul Jakmabd34fb32007-02-26 17:14:48 +0000426 unsigned int distance)
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000427{
428 struct vertex_parent *vp;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000429
Paul Jakma08d3d5b2007-05-07 16:38:35 +0000430 /* we must have a newhop, and a distance */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000431 assert (v && w && newhop);
Paul Jakma08d3d5b2007-05-07 16:38:35 +0000432 assert (distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000433
Paul Jakma08d3d5b2007-05-07 16:38:35 +0000434 /* IFF w has already been assigned a distance, then we shouldn't get here
435 * unless callers have determined V(l)->W is shortest / equal-shortest
436 * path (0 is a special case distance (no distance yet assigned)).
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000437 */
Paul Jakma08d3d5b2007-05-07 16:38:35 +0000438 if (w->distance)
439 assert (distance <= w->distance);
440 else
441 w->distance = distance;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000442
Paul Jakmab75ae992007-03-23 11:17:28 +0000443 if (IS_DEBUG_OSPF_EVENT)
444 {
445 char buf[2][INET_ADDRSTRLEN];
446 zlog_debug ("%s: Adding %s as parent of %s",
447 __func__,
448 inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])),
449 inet_ntop(AF_INET, &w->lsa->id, buf[1], sizeof(buf[1])));
450 }
451
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000452 /* Adding parent for a new, better path: flush existing parents from W. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000453 if (distance < w->distance)
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000454 {
Paul Jakmab75ae992007-03-23 11:17:28 +0000455 if (IS_DEBUG_OSPF_EVENT)
456 zlog_debug ("%s: distance %d better than %d, flushing existing parents",
457 __func__, distance, w->distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000458 ospf_spf_flush_parents (w);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000459 w->distance = distance;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000460 }
461
462 /* new parent is <= existing parents, add it to parent list */
463 vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop);
464 listnode_add (w->parents, vp);
465
466 return;
467}
468
gdt630e4802004-08-31 17:28:41 +0000469/* 16.1.1. Calculate nexthop from root through V (parent) to
Paul Jakmabd34fb32007-02-26 17:14:48 +0000470 * vertex W (destination), with given distance from root->W.
pauleb3da6d2005-10-18 04:20:33 +0000471 *
472 * The link must be supplied if V is the root vertex. In all other cases
473 * it may be NULL.
Paul Jakmabd34fb32007-02-26 17:14:48 +0000474 *
475 * Note that this function may fail, hence the state of the destination
476 * vertex, W, should /not/ be modified in a dependent manner until
477 * this function returns. This function will update the W vertex with the
478 * provided distance as appropriate.
gdt630e4802004-08-31 17:28:41 +0000479 */
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000480static unsigned int
pauleb3da6d2005-10-18 04:20:33 +0000481ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
Paul Jakmabd34fb32007-02-26 17:14:48 +0000482 struct vertex *w, struct router_lsa_link *l,
483 unsigned int distance)
paul718e3742002-12-13 20:15:29 +0000484{
paul1eb8ef22005-04-07 07:30:20 +0000485 struct listnode *node, *nnode;
pauleb3da6d2005-10-18 04:20:33 +0000486 struct vertex_nexthop *nh;
487 struct vertex_parent *vp;
paul718e3742002-12-13 20:15:29 +0000488 struct ospf_interface *oi = NULL;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000489 unsigned int added = 0;
paul0c0f9cd2003-06-06 23:27:04 +0000490
paul718e3742002-12-13 20:15:29 +0000491 if (IS_DEBUG_OSPF_EVENT)
gdt630e4802004-08-31 17:28:41 +0000492 {
ajs2a42e282004-12-08 18:43:03 +0000493 zlog_debug ("ospf_nexthop_calculation(): Start");
gdt630e4802004-08-31 17:28:41 +0000494 ospf_vertex_dump("V (parent):", v, 1, 1);
495 ospf_vertex_dump("W (dest) :", w, 1, 1);
Paul Jakmabd34fb32007-02-26 17:14:48 +0000496 zlog_debug ("V->W distance: %d", distance);
gdt630e4802004-08-31 17:28:41 +0000497 }
paul718e3742002-12-13 20:15:29 +0000498
paul718e3742002-12-13 20:15:29 +0000499 if (v == area->spf)
Paul Jakma9c27ef92006-05-04 07:32:57 +0000500 {
gdt630e4802004-08-31 17:28:41 +0000501 /* 16.1.1 para 4. In the first case, the parent vertex (V) is the
502 root (the calculating router itself). This means that the
503 destination is either a directly connected network or directly
504 connected router. The outgoing interface in this case is simply
505 the OSPF interface connecting to the destination network/router.
506 */
507
paul718e3742002-12-13 20:15:29 +0000508 if (w->type == OSPF_VERTEX_ROUTER)
paul0c0f9cd2003-06-06 23:27:04 +0000509 {
pauleb3da6d2005-10-18 04:20:33 +0000510 /* l is a link from v to w
511 * l2 will be link from w to v
512 */
513 struct router_lsa_link *l2 = NULL;
514
515 /* we *must* be supplied with the link data */
516 assert (l != NULL);
517
518 if (IS_DEBUG_OSPF_EVENT)
paul0c0f9cd2003-06-06 23:27:04 +0000519 {
pauleb3da6d2005-10-18 04:20:33 +0000520 char buf1[BUFSIZ];
521 char buf2[BUFSIZ];
522
523 zlog_debug("ospf_nexthop_calculation(): considering link "
524 "type %d link_id %s link_data %s",
525 l->m[0].type,
526 inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
527 inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
528 }
paul0c0f9cd2003-06-06 23:27:04 +0000529
pauleb3da6d2005-10-18 04:20:33 +0000530 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
531 {
532 /* If the destination is a router which connects to
533 the calculating router via a Point-to-MultiPoint
534 network, the destination's next hop IP address(es)
535 can be determined by examining the destination's
536 router-LSA: each link pointing back to the
537 calculating router and having a Link Data field
538 belonging to the Point-to-MultiPoint network
539 provides an IP address of the next hop router.
gdt630e4802004-08-31 17:28:41 +0000540
pauleb3da6d2005-10-18 04:20:33 +0000541 At this point l is a link from V to W, and V is the
542 root ("us"). Find the local interface associated
543 with l (its address is in l->link_data). If it
544 is a point-to-multipoint interface, then look through
545 the links in the opposite direction (W to V). If
546 any of them have an address that lands within the
547 subnet declared by the PtMP link, then that link
548 is a constituent of the PtMP link, and its address is
549 a nexthop address for V.
550 */
551 oi = ospf_if_is_configured (area->ospf, &l->link_data);
552 if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
paul0c0f9cd2003-06-06 23:27:04 +0000553 {
pauleb3da6d2005-10-18 04:20:33 +0000554 struct prefix_ipv4 la;
gdt630e4802004-08-31 17:28:41 +0000555
pauleb3da6d2005-10-18 04:20:33 +0000556 la.family = AF_INET;
557 la.prefixlen = oi->address->prefixlen;
558
559 /* V links to W on PtMP interface
560 - find the interface address on W */
561 while ((l2 = ospf_get_next_link (w, v, l2)))
paul0c0f9cd2003-06-06 23:27:04 +0000562 {
pauleb3da6d2005-10-18 04:20:33 +0000563 la.prefix = l2->link_data;
gdt630e4802004-08-31 17:28:41 +0000564
pauleb3da6d2005-10-18 04:20:33 +0000565 if (prefix_cmp ((struct prefix *) &la,
566 oi->address) == 0)
567 /* link_data is on our PtMP network */
568 break;
paul0c0f9cd2003-06-06 23:27:04 +0000569 }
pauleb3da6d2005-10-18 04:20:33 +0000570 } /* end l is on point-to-multipoint link */
571 else
572 {
573 /* l is a regular point-to-point link.
574 Look for a link from W to V.
575 */
576 while ((l2 = ospf_get_next_link (w, v, l2)))
paul0c0f9cd2003-06-06 23:27:04 +0000577 {
pauleb3da6d2005-10-18 04:20:33 +0000578 oi = ospf_if_is_configured (area->ospf,
579 &(l2->link_data));
580
581 if (oi == NULL)
582 continue;
583
584 if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
585 &l->link_data))
586 continue;
587
588 break;
paul0c0f9cd2003-06-06 23:27:04 +0000589 }
pauleb3da6d2005-10-18 04:20:33 +0000590 }
591
592 if (oi && l2)
593 {
594 /* found all necessary info to build nexthop */
595 nh = vertex_nexthop_new ();
596 nh->oi = oi;
597 nh->router = l2->link_data;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000598 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000599 return 1;
pauleb3da6d2005-10-18 04:20:33 +0000600 }
601 else
Paul Jakma9c27ef92006-05-04 07:32:57 +0000602 zlog_info("ospf_nexthop_calculation(): "
603 "could not determine nexthop for link");
pauleb3da6d2005-10-18 04:20:33 +0000604 } /* end point-to-point link from V to W */
Paul Jakma9c27ef92006-05-04 07:32:57 +0000605 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
606 {
607 struct ospf_vl_data *vl_data;
608
609 /* VLink implementation limitations:
610 * a) vl_data can only reference one nexthop, so no ECMP
611 * to backbone through VLinks. Though transit-area
612 * summaries may be considered, and those can be ECMP.
613 * b) We can only use /one/ VLink, even if multiple ones
614 * exist this router through multiple transit-areas.
615 */
616 vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id);
617
618 if (vl_data
619 && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED))
620 {
621 nh = vertex_nexthop_new ();
622 nh->oi = vl_data->nexthop.oi;
623 nh->router = vl_data->nexthop.router;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000624 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000625 return 1;
Paul Jakma9c27ef92006-05-04 07:32:57 +0000626 }
627 else
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000628 zlog_info("ospf_nexthop_calculation(): "
629 "vl_data for VL link not found");
Paul Jakma9c27ef92006-05-04 07:32:57 +0000630 } /* end virtual-link from V to W */
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000631 return 0;
gdt630e4802004-08-31 17:28:41 +0000632 } /* end W is a Router vertex */
paul718e3742002-12-13 20:15:29 +0000633 else
paul0c0f9cd2003-06-06 23:27:04 +0000634 {
pauleb3da6d2005-10-18 04:20:33 +0000635 assert(w->type == OSPF_VERTEX_NETWORK);
636 oi = ospf_if_is_configured (area->ospf, &(l->link_data));
637 if (oi)
paul0c0f9cd2003-06-06 23:27:04 +0000638 {
pauleb3da6d2005-10-18 04:20:33 +0000639 nh = vertex_nexthop_new ();
640 nh->oi = oi;
641 nh->router.s_addr = 0;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000642 ospf_spf_add_parent (v, w, nh, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000643 return 1;
paul0c0f9cd2003-06-06 23:27:04 +0000644 }
645 }
Paul Jakma9c27ef92006-05-04 07:32:57 +0000646 zlog_info("ospf_nexthop_calculation(): "
647 "Unknown attached link");
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000648 return 0;
gdt630e4802004-08-31 17:28:41 +0000649 } /* end V is the root */
gdt630e4802004-08-31 17:28:41 +0000650 /* Check if W's parent is a network connected to root. */
paul718e3742002-12-13 20:15:29 +0000651 else if (v->type == OSPF_VERTEX_NETWORK)
652 {
gdt630e4802004-08-31 17:28:41 +0000653 /* See if any of V's parents are the root. */
pauleb3da6d2005-10-18 04:20:33 +0000654 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
paul718e3742002-12-13 20:15:29 +0000655 {
pauleb3da6d2005-10-18 04:20:33 +0000656 if (vp->parent == area->spf) /* connects to root? */
gdt630e4802004-08-31 17:28:41 +0000657 {
658 /* 16.1.1 para 5. ...the parent vertex is a network that
659 * directly connects the calculating router to the destination
660 * router. The list of next hops is then determined by
661 * examining the destination's router-LSA...
662 */
663
664 assert(w->type == OSPF_VERTEX_ROUTER);
paul0c0f9cd2003-06-06 23:27:04 +0000665 while ((l = ospf_get_next_link (w, v, l)))
666 {
gdt630e4802004-08-31 17:28:41 +0000667 /* ...For each link in the router-LSA that points back to the
668 * parent network, the link's Link Data field provides the IP
669 * address of a next hop router. The outgoing interface to
670 * use can then be derived from the next hop IP address (or
671 * it can be inherited from the parent network).
672 */
pauleb3da6d2005-10-18 04:20:33 +0000673 nh = vertex_nexthop_new ();
674 nh->oi = vp->nexthop->oi;
675 nh->router = l->link_data;
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000676 added = 1;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000677 ospf_spf_add_parent (v, w, nh, distance);
paul0c0f9cd2003-06-06 23:27:04 +0000678 }
paul0c0f9cd2003-06-06 23:27:04 +0000679 }
paul718e3742002-12-13 20:15:29 +0000680 }
Paul Jakma85ef7842007-03-23 11:19:08 +0000681 if (added)
682 return added;
paul718e3742002-12-13 20:15:29 +0000683 }
684
gdt630e4802004-08-31 17:28:41 +0000685 /* 16.1.1 para 4. If there is at least one intervening router in the
686 * current shortest path between the destination and the root, the
687 * destination simply inherits the set of next hops from the
688 * parent.
689 */
Paul Jakmab75ae992007-03-23 11:17:28 +0000690 if (IS_DEBUG_OSPF_EVENT)
691 zlog_debug ("%s: Intervening routers, adding parent(s)", __func__);
692
pauleb3da6d2005-10-18 04:20:33 +0000693 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000694 {
695 added = 1;
Paul Jakmabd34fb32007-02-26 17:14:48 +0000696 ospf_spf_add_parent (v, w, vp->nexthop, distance);
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000697 }
Paul Jakma9c27ef92006-05-04 07:32:57 +0000698
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000699 return added;
paul718e3742002-12-13 20:15:29 +0000700}
701
gdt630e4802004-08-31 17:28:41 +0000702/* RFC2328 Section 16.1 (2).
703 * v is on the SPF tree. Examine the links in v's LSA. Update the list
704 * of candidates with any vertices not already on the list. If a lower-cost
705 * path is found to a vertex already on the candidate list, store the new cost.
706 */
paul4dadc292005-05-06 21:37:42 +0000707static void
paul718e3742002-12-13 20:15:29 +0000708ospf_spf_next (struct vertex *v, struct ospf_area *area,
hasso462f20d2005-02-23 11:29:02 +0000709 struct pqueue * candidate)
paul718e3742002-12-13 20:15:29 +0000710{
711 struct ospf_lsa *w_lsa = NULL;
paul718e3742002-12-13 20:15:29 +0000712 u_char *p;
713 u_char *lim;
714 struct router_lsa_link *l = NULL;
715 struct in_addr *r;
paul718e3742002-12-13 20:15:29 +0000716 int type = 0;
717
718 /* If this is a router-LSA, and bit V of the router-LSA (see Section
719 A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
720 if (v->type == OSPF_VERTEX_ROUTER)
721 {
722 if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa))
723 area->transit = OSPF_TRANSIT_TRUE;
724 }
Paul Jakmab75ae992007-03-23 11:17:28 +0000725
726 if (IS_DEBUG_OSPF_EVENT)
727 zlog_debug ("%s: Next vertex of %s vertex %s",
728 __func__,
729 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
730 inet_ntoa(v->lsa->id));
731
paul718e3742002-12-13 20:15:29 +0000732 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul0c0f9cd2003-06-06 23:27:04 +0000733 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
734
paul718e3742002-12-13 20:15:29 +0000735 while (p < lim)
736 {
pauleb3da6d2005-10-18 04:20:33 +0000737 struct vertex *w;
738 unsigned int distance;
pauld355bfa2004-04-08 07:43:45 +0000739
paul718e3742002-12-13 20:15:29 +0000740 /* In case of V is Router-LSA. */
741 if (v->lsa->type == OSPF_ROUTER_LSA)
742 {
743 l = (struct router_lsa_link *) p;
744
paul0c0f9cd2003-06-06 23:27:04 +0000745 p += (ROUTER_LSA_MIN_SIZE +
paul718e3742002-12-13 20:15:29 +0000746 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
747
748 /* (a) If this is a link to a stub network, examine the next
749 link in V's LSA. Links to stub networks will be
750 considered in the second stage of the shortest path
751 calculation. */
752 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
753 continue;
Paul Jakma08d3d5b2007-05-07 16:38:35 +0000754
755 /* Infinite distance links shouldn't be followed, except
756 * for local links (a stub-routed router still wants to
757 * calculate tree, so must follow its own links).
758 */
759 if ((v != area->spf) && l->m[0].metric >= OSPF_OUTPUT_COST_INFINITE)
760 continue;
paul718e3742002-12-13 20:15:29 +0000761
762 /* (b) Otherwise, W is a transit vertex (router or transit
763 network). Look up the vertex W's LSA (router-LSA or
764 network-LSA) in Area A's link state database. */
765 switch (type)
766 {
767 case LSA_LINK_TYPE_POINTOPOINT:
768 case LSA_LINK_TYPE_VIRTUALLINK:
769 if (type == LSA_LINK_TYPE_VIRTUALLINK)
paul0c0f9cd2003-06-06 23:27:04 +0000770 {
771 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000772 zlog_debug ("looking up LSA through VL: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000773 inet_ntoa (l->link_id));
774 }
paul718e3742002-12-13 20:15:29 +0000775
776 w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id,
777 l->link_id);
778 if (w_lsa)
paul0c0f9cd2003-06-06 23:27:04 +0000779 {
780 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000781 zlog_debug ("found Router LSA %s", inet_ntoa (l->link_id));
paul0c0f9cd2003-06-06 23:27:04 +0000782 }
paul718e3742002-12-13 20:15:29 +0000783 break;
784 case LSA_LINK_TYPE_TRANSIT:
paul0c0f9cd2003-06-06 23:27:04 +0000785 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000786 zlog_debug ("Looking up Network LSA, ID: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000787 inet_ntoa (l->link_id));
paul718e3742002-12-13 20:15:29 +0000788 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA,
paul0c0f9cd2003-06-06 23:27:04 +0000789 l->link_id);
paul718e3742002-12-13 20:15:29 +0000790 if (w_lsa)
paul0c0f9cd2003-06-06 23:27:04 +0000791 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000792 zlog_debug ("found the LSA");
paul718e3742002-12-13 20:15:29 +0000793 break;
794 default:
paul0c0f9cd2003-06-06 23:27:04 +0000795 zlog_warn ("Invalid LSA link type %d", type);
paul718e3742002-12-13 20:15:29 +0000796 continue;
797 }
798 }
799 else
800 {
801 /* In case of V is Network-LSA. */
paul0c0f9cd2003-06-06 23:27:04 +0000802 r = (struct in_addr *) p;
paul718e3742002-12-13 20:15:29 +0000803 p += sizeof (struct in_addr);
804
805 /* Lookup the vertex W's LSA. */
806 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r);
Paul Jakmab75ae992007-03-23 11:17:28 +0000807 if (w_lsa)
808 {
809 if (IS_DEBUG_OSPF_EVENT)
810 zlog_debug ("found Router LSA %s", inet_ntoa (w_lsa->data->id));
811 }
paul718e3742002-12-13 20:15:29 +0000812 }
813
814 /* (b cont.) If the LSA does not exist, or its LS age is equal
815 to MaxAge, or it does not have a link back to vertex V,
816 examine the next link in V's LSA.[23] */
817 if (w_lsa == NULL)
Paul Jakmab75ae992007-03-23 11:17:28 +0000818 {
819 if (IS_DEBUG_OSPF_EVENT)
820 zlog_debug ("No LSA found");
821 continue;
822 }
paul718e3742002-12-13 20:15:29 +0000823
824 if (IS_LSA_MAXAGE (w_lsa))
Paul Jakmab75ae992007-03-23 11:17:28 +0000825 {
826 if (IS_DEBUG_OSPF_EVENT)
827 zlog_debug ("LSA is MaxAge");
828 continue;
829 }
paul718e3742002-12-13 20:15:29 +0000830
pauleb3da6d2005-10-18 04:20:33 +0000831 if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 )
paul718e3742002-12-13 20:15:29 +0000832 {
paul0c0f9cd2003-06-06 23:27:04 +0000833 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000834 zlog_debug ("The LSA doesn't have a link back");
paul718e3742002-12-13 20:15:29 +0000835 continue;
836 }
837
838 /* (c) If vertex W is already on the shortest-path tree, examine
839 the next link in the LSA. */
hasso462f20d2005-02-23 11:29:02 +0000840 if (w_lsa->stat == LSA_SPF_IN_SPFTREE)
841 {
842 if (IS_DEBUG_OSPF_EVENT)
843 zlog_debug ("The LSA is already in SPF");
844 continue;
845 }
paul718e3742002-12-13 20:15:29 +0000846
847 /* (d) Calculate the link state cost D of the resulting path
848 from the root to vertex W. D is equal to the sum of the link
849 state cost of the (already calculated) shortest path to
850 vertex V and the advertised cost of the link between vertices
851 V and W. If D is: */
852
paul718e3742002-12-13 20:15:29 +0000853 /* calculate link cost D. */
854 if (v->lsa->type == OSPF_ROUTER_LSA)
pauleb3da6d2005-10-18 04:20:33 +0000855 distance = v->distance + ntohs (l->m[0].metric);
gdt630e4802004-08-31 17:28:41 +0000856 else /* v is not a Router-LSA */
pauleb3da6d2005-10-18 04:20:33 +0000857 distance = v->distance;
paul718e3742002-12-13 20:15:29 +0000858
859 /* Is there already vertex W in candidate list? */
hasso462f20d2005-02-23 11:29:02 +0000860 if (w_lsa->stat == LSA_SPF_NOT_EXPLORED)
861 {
pauleb3da6d2005-10-18 04:20:33 +0000862 /* prepare vertex W. */
863 w = ospf_vertex_new (w_lsa);
864
hasso462f20d2005-02-23 11:29:02 +0000865 /* Calculate nexthop to W. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000866 if (ospf_nexthop_calculation (area, v, w, l, distance))
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000867 pqueue_enqueue (w, candidate);
Paul Jakmab75ae992007-03-23 11:17:28 +0000868 else if (IS_DEBUG_OSPF_EVENT)
869 zlog_debug ("Nexthop Calc failed");
hasso462f20d2005-02-23 11:29:02 +0000870 }
871 else if (w_lsa->stat >= 0)
872 {
873 /* Get the vertex from candidates. */
pauleb3da6d2005-10-18 04:20:33 +0000874 w = candidate->array[w_lsa->stat];
paul718e3742002-12-13 20:15:29 +0000875
hasso462f20d2005-02-23 11:29:02 +0000876 /* if D is greater than. */
pauleb3da6d2005-10-18 04:20:33 +0000877 if (w->distance < distance)
paul718e3742002-12-13 20:15:29 +0000878 {
paul718e3742002-12-13 20:15:29 +0000879 continue;
880 }
hasso462f20d2005-02-23 11:29:02 +0000881 /* equal to. */
pauleb3da6d2005-10-18 04:20:33 +0000882 else if (w->distance == distance)
paul718e3742002-12-13 20:15:29 +0000883 {
pauleb3da6d2005-10-18 04:20:33 +0000884 /* Found an equal-cost path to W.
885 * Calculate nexthop of to W from V. */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000886 ospf_nexthop_calculation (area, v, w, l, distance);
paul718e3742002-12-13 20:15:29 +0000887 }
hasso462f20d2005-02-23 11:29:02 +0000888 /* less than. */
889 else
paul718e3742002-12-13 20:15:29 +0000890 {
Paul Jakmabc20c1a2007-01-24 14:51:51 +0000891 /* Found a lower-cost path to W.
892 * nexthop_calculation is conditional, if it finds
893 * valid nexthop it will call spf_add_parents, which
894 * will flush the old parents
895 */
Paul Jakmabd34fb32007-02-26 17:14:48 +0000896 if (ospf_nexthop_calculation (area, v, w, l, distance))
Paul Jakma7591d8b2007-08-06 18:52:45 +0000897 /* Decrease the key of the node in the heap.
898 * trickle-sort it up towards root, just in case this
899 * node should now be the new root due the cost change.
Paul Jakmae95537f2007-08-07 16:22:05 +0000900 * (next pqueu_{de,en}queue will fully re-heap the queue).
Paul Jakma7591d8b2007-08-06 18:52:45 +0000901 */
902 trickle_up (w_lsa->stat, candidate);
paul718e3742002-12-13 20:15:29 +0000903 }
gdt630e4802004-08-31 17:28:41 +0000904 } /* end W is already on the candidate list */
905 } /* end loop over the links in V's LSA */
paul718e3742002-12-13 20:15:29 +0000906}
907
paul4dadc292005-05-06 21:37:42 +0000908static void
paul718e3742002-12-13 20:15:29 +0000909ospf_spf_dump (struct vertex *v, int i)
910{
hasso52dc7ee2004-09-23 19:18:23 +0000911 struct listnode *cnode;
912 struct listnode *nnode;
pauleb3da6d2005-10-18 04:20:33 +0000913 struct vertex_parent *parent;
paul718e3742002-12-13 20:15:29 +0000914
915 if (v->type == OSPF_VERTEX_ROUTER)
916 {
917 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000918 zlog_debug ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id));
paul718e3742002-12-13 20:15:29 +0000919 }
920 else
921 {
922 struct network_lsa *lsa = (struct network_lsa *) v->lsa;
923 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000924 zlog_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id),
paul0c0f9cd2003-06-06 23:27:04 +0000925 ip_masklen (lsa->mask));
gdt630e4802004-08-31 17:28:41 +0000926 }
paul718e3742002-12-13 20:15:29 +0000927
paul1eb8ef22005-04-07 07:30:20 +0000928 if (IS_DEBUG_OSPF_EVENT)
pauleb3da6d2005-10-18 04:20:33 +0000929 for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent))
930 {
931 zlog_debug (" nexthop %p %s %s",
932 parent->nexthop,
933 inet_ntoa (parent->nexthop->router),
934 parent->nexthop->oi ? IF_NAME(parent->nexthop->oi)
935 : "NULL");
936 }
paul718e3742002-12-13 20:15:29 +0000937
938 i++;
939
pauleb3da6d2005-10-18 04:20:33 +0000940 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v))
paul1eb8ef22005-04-07 07:30:20 +0000941 ospf_spf_dump (v, i);
paul718e3742002-12-13 20:15:29 +0000942}
943
944/* Second stage of SPF calculation. */
paul4dadc292005-05-06 21:37:42 +0000945static void
paul0c0f9cd2003-06-06 23:27:04 +0000946ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v,
Paul Jakmab3bc68e2008-09-04 13:52:07 +0100947 struct route_table *rt,
948 int parent_is_root)
paul718e3742002-12-13 20:15:29 +0000949{
paul1eb8ef22005-04-07 07:30:20 +0000950 struct listnode *cnode, *cnnode;
paul718e3742002-12-13 20:15:29 +0000951 struct vertex *child;
952
953 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000954 zlog_debug ("ospf_process_stub():processing stubs for area %s",
paul0c0f9cd2003-06-06 23:27:04 +0000955 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +0000956 if (v->type == OSPF_VERTEX_ROUTER)
957 {
958 u_char *p;
959 u_char *lim;
960 struct router_lsa_link *l;
961 struct router_lsa *rlsa;
962
paul0c0f9cd2003-06-06 23:27:04 +0000963 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000964 zlog_debug ("ospf_process_stubs():processing router LSA, id: %s",
paul0c0f9cd2003-06-06 23:27:04 +0000965 inet_ntoa (v->lsa->id));
paul718e3742002-12-13 20:15:29 +0000966 rlsa = (struct router_lsa *) v->lsa;
967
968
paul0c0f9cd2003-06-06 23:27:04 +0000969 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +0000970 zlog_debug ("ospf_process_stubs(): we have %d links to process",
paul0c0f9cd2003-06-06 23:27:04 +0000971 ntohs (rlsa->links));
gdt630e4802004-08-31 17:28:41 +0000972 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
paul718e3742002-12-13 20:15:29 +0000973 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
974
975 while (p < lim)
976 {
977 l = (struct router_lsa_link *) p;
978
979 p += (ROUTER_LSA_MIN_SIZE +
980 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
981
982 if (l->m[0].type == LSA_LINK_TYPE_STUB)
Paul Jakmab3bc68e2008-09-04 13:52:07 +0100983 ospf_intra_add_stub (rt, l, v, area, parent_is_root);
paul718e3742002-12-13 20:15:29 +0000984 }
985 }
986
gdt630e4802004-08-31 17:28:41 +0000987 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1);
paul718e3742002-12-13 20:15:29 +0000988
pauleb3da6d2005-10-18 04:20:33 +0000989 for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child))
paul718e3742002-12-13 20:15:29 +0000990 {
paul718e3742002-12-13 20:15:29 +0000991 if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED))
paul0c0f9cd2003-06-06 23:27:04 +0000992 continue;
Paul Jakmab3bc68e2008-09-04 13:52:07 +0100993
994 /* the first level of routers connected to the root
995 * should have 'parent_is_root' set, including those
996 * connected via a network vertex.
997 */
998 if (area->spf == v)
999 parent_is_root = 1;
1000 else if (v->type == OSPF_VERTEX_ROUTER)
1001 parent_is_root = 0;
1002
1003 ospf_spf_process_stubs (area, child, rt, parent_is_root);
paul718e3742002-12-13 20:15:29 +00001004
1005 SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED);
1006 }
1007}
1008
1009void
1010ospf_rtrs_free (struct route_table *rtrs)
1011{
1012 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +00001013 struct list *or_list;
paul1eb8ef22005-04-07 07:30:20 +00001014 struct ospf_route *or;
1015 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001016
1017 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001018 zlog_debug ("Route: Router Routing Table free");
paul718e3742002-12-13 20:15:29 +00001019
1020 for (rn = route_top (rtrs); rn; rn = route_next (rn))
1021 if ((or_list = rn->info) != NULL)
1022 {
paul1eb8ef22005-04-07 07:30:20 +00001023 for (ALL_LIST_ELEMENTS (or_list, node, nnode, or))
1024 ospf_route_free (or);
paul718e3742002-12-13 20:15:29 +00001025
paul0c0f9cd2003-06-06 23:27:04 +00001026 list_delete (or_list);
paul718e3742002-12-13 20:15:29 +00001027
paul0c0f9cd2003-06-06 23:27:04 +00001028 /* Unlock the node. */
1029 rn->info = NULL;
1030 route_unlock_node (rn);
paul718e3742002-12-13 20:15:29 +00001031 }
1032 route_table_finish (rtrs);
1033}
1034
paul4dadc292005-05-06 21:37:42 +00001035static void
paul718e3742002-12-13 20:15:29 +00001036ospf_rtrs_print (struct route_table *rtrs)
1037{
1038 struct route_node *rn;
hasso52dc7ee2004-09-23 19:18:23 +00001039 struct list *or_list;
1040 struct listnode *ln;
1041 struct listnode *pnode;
paul718e3742002-12-13 20:15:29 +00001042 struct ospf_route *or;
1043 struct ospf_path *path;
1044 char buf1[BUFSIZ];
1045 char buf2[BUFSIZ];
1046
1047 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001048 zlog_debug ("ospf_rtrs_print() start");
paul718e3742002-12-13 20:15:29 +00001049
1050 for (rn = route_top (rtrs); rn; rn = route_next (rn))
1051 if ((or_list = rn->info) != NULL)
paul1eb8ef22005-04-07 07:30:20 +00001052 for (ALL_LIST_ELEMENTS_RO (or_list, ln, or))
paul718e3742002-12-13 20:15:29 +00001053 {
paul718e3742002-12-13 20:15:29 +00001054 switch (or->path_type)
1055 {
1056 case OSPF_PATH_INTRA_AREA:
paul0c0f9cd2003-06-06 23:27:04 +00001057 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001058 zlog_debug ("%s [%d] area: %s",
paul0c0f9cd2003-06-06 23:27:04 +00001059 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1060 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1061 buf2, BUFSIZ));
paul718e3742002-12-13 20:15:29 +00001062 break;
1063 case OSPF_PATH_INTER_AREA:
paul0c0f9cd2003-06-06 23:27:04 +00001064 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001065 zlog_debug ("%s IA [%d] area: %s",
paul0c0f9cd2003-06-06 23:27:04 +00001066 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1067 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1068 buf2, BUFSIZ));
paul718e3742002-12-13 20:15:29 +00001069 break;
1070 default:
1071 break;
1072 }
1073
paul1eb8ef22005-04-07 07:30:20 +00001074 for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
paul718e3742002-12-13 20:15:29 +00001075 {
paul718e3742002-12-13 20:15:29 +00001076 if (path->nexthop.s_addr == 0)
paul0c0f9cd2003-06-06 23:27:04 +00001077 {
1078 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001079 zlog_debug (" directly attached to %s\r\n",
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +02001080 ifindex2ifname (path->ifindex));
paul0c0f9cd2003-06-06 23:27:04 +00001081 }
1082 else
1083 {
1084 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001085 zlog_debug (" via %s, %s\r\n",
Joakim Tjernlunda8ba8472009-07-27 12:42:34 +02001086 inet_ntoa (path->nexthop),
1087 ifindex2ifname (path->ifindex));
paul0c0f9cd2003-06-06 23:27:04 +00001088 }
paul718e3742002-12-13 20:15:29 +00001089 }
1090 }
1091
ajs2a42e282004-12-08 18:43:03 +00001092 zlog_debug ("ospf_rtrs_print() end");
paul718e3742002-12-13 20:15:29 +00001093}
1094
1095/* Calculating the shortest-path tree for an area. */
paul4dadc292005-05-06 21:37:42 +00001096static void
paul0c0f9cd2003-06-06 23:27:04 +00001097ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
paul718e3742002-12-13 20:15:29 +00001098 struct route_table *new_rtrs)
1099{
hasso462f20d2005-02-23 11:29:02 +00001100 struct pqueue *candidate;
paul718e3742002-12-13 20:15:29 +00001101 struct vertex *v;
pauleb3da6d2005-10-18 04:20:33 +00001102
paul718e3742002-12-13 20:15:29 +00001103 if (IS_DEBUG_OSPF_EVENT)
1104 {
ajs2a42e282004-12-08 18:43:03 +00001105 zlog_debug ("ospf_spf_calculate: Start");
1106 zlog_debug ("ospf_spf_calculate: running Dijkstra for area %s",
paul0c0f9cd2003-06-06 23:27:04 +00001107 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +00001108 }
1109
1110 /* Check router-lsa-self. If self-router-lsa is not yet allocated,
1111 return this area's calculation. */
paul0c0f9cd2003-06-06 23:27:04 +00001112 if (!area->router_lsa_self)
paul718e3742002-12-13 20:15:29 +00001113 {
1114 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001115 zlog_debug ("ospf_spf_calculate: "
paul0c0f9cd2003-06-06 23:27:04 +00001116 "Skip area %s's calculation due to empty router_lsa_self",
1117 inet_ntoa (area->area_id));
paul718e3742002-12-13 20:15:29 +00001118 return;
1119 }
1120
1121 /* RFC2328 16.1. (1). */
paul0c0f9cd2003-06-06 23:27:04 +00001122 /* Initialize the algorithm's data structures. */
hasso462f20d2005-02-23 11:29:02 +00001123
1124 /* This function scans all the LSA database and set the stat field to
1125 * LSA_SPF_NOT_EXPLORED. */
1126 ospf_lsdb_clean_stat (area->lsdb);
1127 /* Create a new heap for the candidates. */
1128 candidate = pqueue_create();
1129 candidate->cmp = cmp;
1130 candidate->update = update_stat;
paul718e3742002-12-13 20:15:29 +00001131
1132 /* Initialize the shortest-path tree to only the root (which is the
1133 router doing the calculation). */
1134 ospf_spf_init (area);
1135 v = area->spf;
hasso462f20d2005-02-23 11:29:02 +00001136 /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the
1137 * spanning tree. */
1138 *(v->stat) = LSA_SPF_IN_SPFTREE;
paul718e3742002-12-13 20:15:29 +00001139
1140 /* Set Area A's TransitCapability to FALSE. */
1141 area->transit = OSPF_TRANSIT_FALSE;
1142 area->shortcut_capability = 1;
pauleb3da6d2005-10-18 04:20:33 +00001143
paul718e3742002-12-13 20:15:29 +00001144 for (;;)
1145 {
1146 /* RFC2328 16.1. (2). */
hasso462f20d2005-02-23 11:29:02 +00001147 ospf_spf_next (v, area, candidate);
paul718e3742002-12-13 20:15:29 +00001148
1149 /* RFC2328 16.1. (3). */
1150 /* If at this step the candidate list is empty, the shortest-
1151 path tree (of transit vertices) has been completely built and
1152 this stage of the procedure terminates. */
hasso462f20d2005-02-23 11:29:02 +00001153 if (candidate->size == 0)
paul718e3742002-12-13 20:15:29 +00001154 break;
1155
1156 /* Otherwise, choose the vertex belonging to the candidate list
1157 that is closest to the root, and add it to the shortest-path
1158 tree (removing it from the candidate list in the
paul0c0f9cd2003-06-06 23:27:04 +00001159 process). */
hasso462f20d2005-02-23 11:29:02 +00001160 /* Extract from the candidates the node with the lower key. */
1161 v = (struct vertex *) pqueue_dequeue (candidate);
1162 /* Update stat field in vertex. */
1163 *(v->stat) = LSA_SPF_IN_SPFTREE;
pauleb3da6d2005-10-18 04:20:33 +00001164
paul718e3742002-12-13 20:15:29 +00001165 ospf_vertex_add_parent (v);
1166
paul718e3742002-12-13 20:15:29 +00001167 /* Note that when there is a choice of vertices closest to the
1168 root, network vertices must be chosen before router vertices
1169 in order to necessarily find all equal-cost paths. */
1170 /* We don't do this at this moment, we should add the treatment
1171 above codes. -- kunihiro. */
1172
1173 /* RFC2328 16.1. (4). */
1174 if (v->type == OSPF_VERTEX_ROUTER)
1175 ospf_intra_add_router (new_rtrs, v, area);
paul0c0f9cd2003-06-06 23:27:04 +00001176 else
paul718e3742002-12-13 20:15:29 +00001177 ospf_intra_add_transit (new_table, v, area);
1178
1179 /* RFC2328 16.1. (5). */
1180 /* Iterate the algorithm by returning to Step 2. */
gdt630e4802004-08-31 17:28:41 +00001181
1182 } /* end loop until no more candidate vertices */
paul718e3742002-12-13 20:15:29 +00001183
1184 if (IS_DEBUG_OSPF_EVENT)
1185 {
1186 ospf_spf_dump (area->spf, 0);
1187 ospf_route_table_dump (new_table);
1188 }
1189
1190 /* Second stage of SPF calculation procedure's */
Paul Jakmab3bc68e2008-09-04 13:52:07 +01001191 ospf_spf_process_stubs (area, area->spf, new_table, 0);
paul718e3742002-12-13 20:15:29 +00001192
pauleb3da6d2005-10-18 04:20:33 +00001193 /* Free candidate queue. */
hasso462f20d2005-02-23 11:29:02 +00001194 pqueue_delete (candidate);
pauleb3da6d2005-10-18 04:20:33 +00001195
1196 ospf_vertex_dump (__func__, area->spf, 0, 1);
1197 /* Free nexthop information, canonical versions of which are attached
1198 * the first level of router vertices attached to the root vertex, see
1199 * ospf_nexthop_calculation.
1200 */
1201 ospf_canonical_nexthops_free (area->spf);
1202
Paul Jakma9c27ef92006-05-04 07:32:57 +00001203 /* Free SPF vertices, but not the list. List has ospf_vertex_free
1204 * as deconstructor.
1205 */
1206 list_delete_all_node (&vertex_list);
pauleb3da6d2005-10-18 04:20:33 +00001207
paul718e3742002-12-13 20:15:29 +00001208 /* Increment SPF Calculation Counter. */
1209 area->spf_calculation++;
1210
Paul Jakma2518efd2006-08-27 06:49:29 +00001211 quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf);
paul718e3742002-12-13 20:15:29 +00001212
1213 if (IS_DEBUG_OSPF_EVENT)
Paul Jakma9c27ef92006-05-04 07:32:57 +00001214 zlog_debug ("ospf_spf_calculate: Stop. %ld vertices",
1215 mtype_stats_alloc(MTYPE_OSPF_VERTEX));
paul718e3742002-12-13 20:15:29 +00001216}
1217
1218/* Timer for SPF calculation. */
paul4dadc292005-05-06 21:37:42 +00001219static int
paul68980082003-03-25 05:07:42 +00001220ospf_spf_calculate_timer (struct thread *thread)
paul718e3742002-12-13 20:15:29 +00001221{
paul68980082003-03-25 05:07:42 +00001222 struct ospf *ospf = THREAD_ARG (thread);
paul718e3742002-12-13 20:15:29 +00001223 struct route_table *new_table, *new_rtrs;
paul1eb8ef22005-04-07 07:30:20 +00001224 struct ospf_area *area;
1225 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +00001226
1227 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001228 zlog_debug ("SPF: Timer (SPF calculation expire)");
paul0c0f9cd2003-06-06 23:27:04 +00001229
paul718e3742002-12-13 20:15:29 +00001230 ospf->t_spf_calc = NULL;
1231
1232 /* Allocate new table tree. */
1233 new_table = route_table_init ();
paul0c0f9cd2003-06-06 23:27:04 +00001234 new_rtrs = route_table_init ();
paul718e3742002-12-13 20:15:29 +00001235
paul68980082003-03-25 05:07:42 +00001236 ospf_vl_unapprove (ospf);
paul718e3742002-12-13 20:15:29 +00001237
1238 /* Calculate SPF for each area. */
paul1eb8ef22005-04-07 07:30:20 +00001239 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
Paul Jakma9c27ef92006-05-04 07:32:57 +00001240 {
1241 /* Do backbone last, so as to first discover intra-area paths
1242 * for any back-bone virtual-links
1243 */
1244 if (ospf->backbone && ospf->backbone == area)
1245 continue;
1246
1247 ospf_spf_calculate (area, new_table, new_rtrs);
1248 }
1249
1250 /* SPF for backbone, if required */
1251 if (ospf->backbone)
1252 ospf_spf_calculate (ospf->backbone, new_table, new_rtrs);
1253
paul68980082003-03-25 05:07:42 +00001254 ospf_vl_shut_unapproved (ospf);
paul718e3742002-12-13 20:15:29 +00001255
paul68980082003-03-25 05:07:42 +00001256 ospf_ia_routing (ospf, new_table, new_rtrs);
paul718e3742002-12-13 20:15:29 +00001257
1258 ospf_prune_unreachable_networks (new_table);
1259 ospf_prune_unreachable_routers (new_rtrs);
1260
1261 /* AS-external-LSA calculation should not be performed here. */
1262
1263 /* If new Router Route is installed,
1264 then schedule re-calculate External routes. */
1265 if (1)
paul68980082003-03-25 05:07:42 +00001266 ospf_ase_calculate_schedule (ospf);
paul718e3742002-12-13 20:15:29 +00001267
paul68980082003-03-25 05:07:42 +00001268 ospf_ase_calculate_timer_add (ospf);
paul718e3742002-12-13 20:15:29 +00001269
1270 /* Update routing table. */
paul68980082003-03-25 05:07:42 +00001271 ospf_route_install (ospf, new_table);
paul718e3742002-12-13 20:15:29 +00001272
1273 /* Update ABR/ASBR routing table */
paul68980082003-03-25 05:07:42 +00001274 if (ospf->old_rtrs)
paul718e3742002-12-13 20:15:29 +00001275 {
1276 /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */
paul68980082003-03-25 05:07:42 +00001277 /* ospf_route_delete (ospf->old_rtrs); */
1278 ospf_rtrs_free (ospf->old_rtrs);
paul718e3742002-12-13 20:15:29 +00001279 }
1280
paul68980082003-03-25 05:07:42 +00001281 ospf->old_rtrs = ospf->new_rtrs;
1282 ospf->new_rtrs = new_rtrs;
paul718e3742002-12-13 20:15:29 +00001283
paul0c0f9cd2003-06-06 23:27:04 +00001284 if (IS_OSPF_ABR (ospf))
paul68980082003-03-25 05:07:42 +00001285 ospf_abr_task (ospf);
paul718e3742002-12-13 20:15:29 +00001286
1287 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001288 zlog_debug ("SPF: calculation complete");
paul718e3742002-12-13 20:15:29 +00001289
1290 return 0;
1291}
1292
1293/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
1294 set timer for SPF calc. */
1295void
paul68980082003-03-25 05:07:42 +00001296ospf_spf_calculate_schedule (struct ospf *ospf)
paul718e3742002-12-13 20:15:29 +00001297{
pauld24f6e22005-10-21 09:23:12 +00001298 unsigned long delay, elapsed, ht;
1299 struct timeval result;
paul718e3742002-12-13 20:15:29 +00001300
1301 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001302 zlog_debug ("SPF: calculation timer scheduled");
paul718e3742002-12-13 20:15:29 +00001303
1304 /* OSPF instance does not exist. */
paul68980082003-03-25 05:07:42 +00001305 if (ospf == NULL)
paul718e3742002-12-13 20:15:29 +00001306 return;
pauld24f6e22005-10-21 09:23:12 +00001307
paul718e3742002-12-13 20:15:29 +00001308 /* SPF calculation timer is already scheduled. */
paul68980082003-03-25 05:07:42 +00001309 if (ospf->t_spf_calc)
paul718e3742002-12-13 20:15:29 +00001310 {
1311 if (IS_DEBUG_OSPF_EVENT)
ajs2a42e282004-12-08 18:43:03 +00001312 zlog_debug ("SPF: calculation timer is already scheduled: %p",
paul0c0f9cd2003-06-06 23:27:04 +00001313 ospf->t_spf_calc);
paul718e3742002-12-13 20:15:29 +00001314 return;
1315 }
pauld24f6e22005-10-21 09:23:12 +00001316
1317 /* XXX Monotic timers: we only care about relative time here. */
Paul Jakma2518efd2006-08-27 06:49:29 +00001318 result = tv_sub (recent_relative_time (), ospf->ts_spf);
pauld24f6e22005-10-21 09:23:12 +00001319
1320 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
1321 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1322
1323 if (ht > ospf->spf_max_holdtime)
1324 ht = ospf->spf_max_holdtime;
1325
paul718e3742002-12-13 20:15:29 +00001326 /* Get SPF calculation delay time. */
pauld24f6e22005-10-21 09:23:12 +00001327 if (elapsed < ht)
paul718e3742002-12-13 20:15:29 +00001328 {
pauld24f6e22005-10-21 09:23:12 +00001329 /* Got an event within the hold time of last SPF. We need to
1330 * increase the hold_multiplier, if it's not already at/past
1331 * maximum value, and wasn't already increased..
1332 */
1333 if (ht < ospf->spf_max_holdtime)
1334 ospf->spf_hold_multiplier++;
1335
1336 /* always honour the SPF initial delay */
1337 if ( (ht - elapsed) < ospf->spf_delay)
paul0c0f9cd2003-06-06 23:27:04 +00001338 delay = ospf->spf_delay;
paul718e3742002-12-13 20:15:29 +00001339 else
pauld24f6e22005-10-21 09:23:12 +00001340 delay = ht - elapsed;
paul718e3742002-12-13 20:15:29 +00001341 }
1342 else
pauld24f6e22005-10-21 09:23:12 +00001343 {
1344 /* Event is past required hold-time of last SPF */
1345 delay = ospf->spf_delay;
1346 ospf->spf_hold_multiplier = 1;
1347 }
1348
paul718e3742002-12-13 20:15:29 +00001349 if (IS_DEBUG_OSPF_EVENT)
pauld24f6e22005-10-21 09:23:12 +00001350 zlog_debug ("SPF: calculation timer delay = %ld", delay);
1351
paul68980082003-03-25 05:07:42 +00001352 ospf->t_spf_calc =
pauld24f6e22005-10-21 09:23:12 +00001353 thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay);
paul718e3742002-12-13 20:15:29 +00001354}