]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_spf.c
[zebra] IRDP should ignore non-IPv4 addresses
[mirror_frr.git] / ospfd / ospf_spf.c
CommitLineData
718e3744 1/* 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 () */
462f20d5 32#include "pqueue.h"
718e3744 33
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
9c27ef9b
PJ
49static 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\f
462f20d5 56/* 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 )
9c27ef9b
PJ
64 {
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;
462f20d5 83}
84
85static void
eb3da6df 86update_stat (void *node , int position)
462f20d5 87{
eb3da6df 88 struct vertex *v = node;
89
462f20d5 90 /* Set the status of the vertex, when its position changes. */
91 *(v->stat) = position;
92}
eb3da6df 93\f
4dadc291 94static struct vertex_nexthop *
eb3da6df 95vertex_nexthop_new (void)
718e3744 96{
eb3da6df 97 return XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop));
718e3744 98}
99
4dadc291 100static void
718e3744 101vertex_nexthop_free (struct vertex_nexthop *nh)
102{
103 XFREE (MTYPE_OSPF_NEXTHOP, nh);
104}
105
eb3da6df 106/* Free the canonical nexthop objects for an area, ie the nexthop objects
9c27ef9b
PJ
107 * attached to the first-hop router vertices, and any intervening network
108 * vertices.
eb3da6df 109 */
110static void
111ospf_canonical_nexthops_free (struct vertex *root)
718e3744 112{
eb3da6df 113 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
58e1befe 121 /* 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 */
eb3da6df 128 if (child->type == OSPF_VERTEX_NETWORK)
129 ospf_canonical_nexthops_free (child);
130
58e1befe 131 /* Free child nexthops pointing back to this root vertex */
eb3da6df 132 for (ALL_LIST_ELEMENTS (child->parents, n2, nn2, vp))
9c27ef9b 133 if (vp->parent == root && vp->nexthop)
58e1befe 134 vertex_nexthop_free (vp->nexthop);
eb3da6df 135 }
136}
137\f
9c27ef9b
PJ
138/* TODO: Parent list should be excised, in favour of maintaining only
139 * vertex_nexthop, with refcounts.
140 */
eb3da6df 141static 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;
718e3744 154 return new;
155}
0c0f9cd5 156
eb3da6df 157static void
9c27ef9b 158vertex_parent_free (void *p)
eb3da6df 159{
160 XFREE (MTYPE_OSPF_VERTEX_PARENT, p);
161}
162\f
4dadc291 163static struct vertex *
718e3744 164ospf_vertex_new (struct ospf_lsa *lsa)
165{
166 struct vertex *new;
167
eb3da6df 168 new = XCALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex));
718e3744 169
170 new->flags = 0;
462f20d5 171 new->stat = &(lsa->stat);
718e3744 172 new->type = lsa->data->type;
173 new->id = lsa->data->id;
174 new->lsa = lsa->data;
175 new->distance = 0;
eb3da6df 176 new->children = list_new ();
177 new->parents = list_new ();
9c27ef9b
PJ
178 new->parents->del = vertex_parent_free;
179
180 listnode_add (&vertex_list, new);
eb3da6df 181
9c27ef9b
PJ
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));
718e3744 186 return new;
187}
188
4dadc291 189static void
9c27ef9b 190ospf_vertex_free (void *data)
718e3744 191{
9c27ef9b 192 struct vertex *v = data;
eb3da6df 193
9c27ef9b
PJ
194 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));
7461d459 198
9c27ef9b
PJ
199 /* 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
eb3da6df 202 */
9c27ef9b 203 //assert (listcount (v->parents) == 0);
eb3da6df 204
9c27ef9b
PJ
205 if (v->children)
206 list_delete (v->children);
207 v->children = NULL;
208
209 if (v->parents)
210 list_delete (v->parents);
eb3da6df 211 v->parents = NULL;
212
213 v->lsa = NULL;
7461d459 214
718e3744 215 XFREE (MTYPE_OSPF_VERTEX, v);
216}
217
4dadc291 218static void
eb1ce605 219ospf_vertex_dump(const char *msg, struct vertex *v,
eb3da6df 220 int print_parents, int print_children)
630e4807 221{
222 if ( ! IS_DEBUG_OSPF_EVENT)
223 return;
224
eb3da6df 225 zlog_debug("%s %s vertex %s distance %u flags %u",
630e4807 226 msg,
227 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
228 inet_ntoa(v->lsa->id),
229 v->distance,
630e4807 230 (unsigned int)v->flags);
231
eb3da6df 232 if (print_parents)
630e4807 233 {
1eb8ef25 234 struct listnode *node;
eb3da6df 235 struct vertex_parent *vp;
1eb8ef25 236
eb3da6df 237 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
630e4807 238 {
239 char buf1[BUFSIZ];
eb3da6df 240
241 if (vp)
630e4807 242 {
eb3da6df 243 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");
630e4807 247 }
248 }
249 }
250
251 if (print_children)
252 {
52dc7ee6 253 struct listnode *cnode;
1eb8ef25 254 struct vertex *cv;
255
eb3da6df 256 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv))
1eb8ef25 257 ospf_vertex_dump(" child:", cv, 0, 0);
630e4807 258 }
259}
260
261
262/* Add a vertex to the list of children in each of its parents. */
4dadc291 263static void
718e3744 264ospf_vertex_add_parent (struct vertex *v)
265{
eb3da6df 266 struct vertex_parent *vp;
52dc7ee6 267 struct listnode *node;
7461d459 268
9c27ef9b 269 assert (v && v->parents);
7461d459 270
eb3da6df 271 for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp))
718e3744 272 {
eb3da6df 273 assert (vp->parent && vp->parent->children);
7461d459 274
718e3744 275 /* No need to add two links from the same parent. */
eb3da6df 276 if (listnode_lookup (vp->parent->children, v) == NULL)
277 listnode_add (vp->parent->children, v);
718e3744 278 }
279}
280\f
4dadc291 281static void
718e3744 282ospf_spf_init (struct ospf_area *area)
283{
284 struct vertex *v;
9c27ef9b 285
718e3744 286 /* Create root node. */
287 v = ospf_vertex_new (area->router_lsa_self);
288
289 area->spf = v;
290
291 /* Reset ABR and ASBR router counts. */
292 area->abr_count = 0;
293 area->asbr_count = 0;
294}
295
d355bfa7 296/* return index of link back to V from W, or -1 if no link found */
4dadc291 297static int
718e3744 298ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v)
299{
eb1ce605 300 unsigned int i, length;
718e3744 301 struct router_lsa *rl;
302 struct network_lsa *nl;
303
304 /* In case of W is Network LSA. */
305 if (w->type == OSPF_NETWORK_LSA)
306 {
307 if (v->type == OSPF_NETWORK_LSA)
d355bfa7 308 return -1;
718e3744 309
310 nl = (struct network_lsa *) w;
311 length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
0c0f9cd5 312
718e3744 313 for (i = 0; i < length; i++)
314 if (IPV4_ADDR_SAME (&nl->routers[i], &v->id))
d355bfa7 315 return i;
316 return -1;
718e3744 317 }
318
319 /* In case of W is Router LSA. */
320 if (w->type == OSPF_ROUTER_LSA)
321 {
322 rl = (struct router_lsa *) w;
323
324 length = ntohs (w->length);
325
326 for (i = 0;
0c0f9cd5 327 i < ntohs (rl->links) && length >= sizeof (struct router_lsa);
328 i++, length -= 12)
718e3744 329 {
330 switch (rl->link[i].type)
331 {
332 case LSA_LINK_TYPE_POINTOPOINT:
333 case LSA_LINK_TYPE_VIRTUALLINK:
334 /* Router LSA ID. */
335 if (v->type == OSPF_ROUTER_LSA &&
336 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
337 {
d355bfa7 338 return i;
718e3744 339 }
340 break;
341 case LSA_LINK_TYPE_TRANSIT:
342 /* Network LSA ID. */
343 if (v->type == OSPF_NETWORK_LSA &&
344 IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id))
345 {
d355bfa7 346 return i;
0c0f9cd5 347 }
718e3744 348 break;
349 case LSA_LINK_TYPE_STUB:
eb3da6df 350 /* Stub can't lead anywhere, carry on */
718e3744 351 continue;
352 default:
353 break;
354 }
355 }
356 }
d355bfa7 357 return -1;
718e3744 358}
359
718e3744 360#define ROUTER_LSA_MIN_SIZE 12
361#define ROUTER_LSA_TOS_SIZE 4
362
630e4807 363/* Find the next link after prev_link from v to w. If prev_link is
364 * NULL, return the first link from v to w. Ignore stub and virtual links;
365 * these link types will never be returned.
366 */
4dadc291 367static struct router_lsa_link *
718e3744 368ospf_get_next_link (struct vertex *v, struct vertex *w,
0c0f9cd5 369 struct router_lsa_link *prev_link)
718e3744 370{
371 u_char *p;
372 u_char *lim;
373 struct router_lsa_link *l;
374
375 if (prev_link == NULL)
630e4807 376 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
718e3744 377 else
378 {
0c0f9cd5 379 p = (u_char *) prev_link;
718e3744 380 p += (ROUTER_LSA_MIN_SIZE +
381 (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
382 }
0c0f9cd5 383
718e3744 384 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
385
386 while (p < lim)
387 {
388 l = (struct router_lsa_link *) p;
389
0c0f9cd5 390 p += (ROUTER_LSA_MIN_SIZE + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
718e3744 391
392 if (l->m[0].type == LSA_LINK_TYPE_STUB)
393 continue;
394
395 /* Defer NH calculation via VLs until summaries from
396 transit areas area confidered */
397
398 if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
0c0f9cd5 399 continue;
718e3744 400
401 if (IPV4_ADDR_SAME (&l->link_id, &w->id))
0c0f9cd5 402 return l;
718e3744 403 }
404
405 return NULL;
406}
407
bc20c1a4
PJ
408static void
409ospf_spf_flush_parents (struct vertex *w)
410{
411 struct vertex_parent *vp;
412 struct listnode *ln, *nn;
413
414 /* delete the existing nexthops */
415 for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp))
416 {
417 list_delete_node (w->parents, ln);
418 vertex_parent_free (vp);
419 }
420}
421
75ee0b8e 422/*
423 * Consider supplied next-hop for inclusion to the supplied list of
424 * equal-cost next-hops, adjust list as neccessary.
bf9392c6 425 */
4dadc291 426static void
eb3da6df 427ospf_spf_add_parent (struct vertex *v, struct vertex *w,
bc20c1a4
PJ
428 struct vertex_nexthop *newhop,
429 struct router_lsa_link *l)
bf9392c6 430{
eb3da6df 431 struct vertex_parent *vp;
bc20c1a4 432 unsigned int new_distance;
eb3da6df 433
434 /* we must have a newhop.. */
bc20c1a4
PJ
435 assert (v && w && l && newhop);
436
437 new_distance = v->distance + ntohs (l->m[0].metric);
eb3da6df 438
bc20c1a4
PJ
439 /* We shouldn't get here unless callers have determined V(l)->W is
440 * shortest / equal-shortest path.
441 */
442 assert (new_distance <= w->distance);
443
444 /* Adding parent for a new, better path: flush existing parents from W. */
445 if (new_distance < w->distance)
446 {
447 ospf_spf_flush_parents (w);
448 w->distance = new_distance;
449 }
450
451 /* new parent is <= existing parents, add it to parent list */
eb3da6df 452 vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop);
453 listnode_add (w->parents, vp);
0c0f9cd5 454
eb3da6df 455 return;
456}
457
630e4807 458/* 16.1.1. Calculate nexthop from root through V (parent) to
459 * vertex W (destination).
eb3da6df 460 *
461 * The link must be supplied if V is the root vertex. In all other cases
462 * it may be NULL.
630e4807 463 */
bc20c1a4 464static unsigned int
eb3da6df 465ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
466 struct vertex *w, struct router_lsa_link *l)
718e3744 467{
1eb8ef25 468 struct listnode *node, *nnode;
eb3da6df 469 struct vertex_nexthop *nh;
470 struct vertex_parent *vp;
718e3744 471 struct ospf_interface *oi = NULL;
bc20c1a4 472 unsigned int added = 0;
0c0f9cd5 473
718e3744 474 if (IS_DEBUG_OSPF_EVENT)
630e4807 475 {
2a42e285 476 zlog_debug ("ospf_nexthop_calculation(): Start");
630e4807 477 ospf_vertex_dump("V (parent):", v, 1, 1);
478 ospf_vertex_dump("W (dest) :", w, 1, 1);
479 }
718e3744 480
718e3744 481 if (v == area->spf)
9c27ef9b 482 {
630e4807 483 /* 16.1.1 para 4. In the first case, the parent vertex (V) is the
484 root (the calculating router itself). This means that the
485 destination is either a directly connected network or directly
486 connected router. The outgoing interface in this case is simply
487 the OSPF interface connecting to the destination network/router.
488 */
489
718e3744 490 if (w->type == OSPF_VERTEX_ROUTER)
0c0f9cd5 491 {
eb3da6df 492 /* l is a link from v to w
493 * l2 will be link from w to v
494 */
495 struct router_lsa_link *l2 = NULL;
496
497 /* we *must* be supplied with the link data */
498 assert (l != NULL);
499
500 if (IS_DEBUG_OSPF_EVENT)
0c0f9cd5 501 {
eb3da6df 502 char buf1[BUFSIZ];
503 char buf2[BUFSIZ];
504
505 zlog_debug("ospf_nexthop_calculation(): considering link "
506 "type %d link_id %s link_data %s",
507 l->m[0].type,
508 inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
509 inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
510 }
511
512 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
513 {
514 /* If the destination is a router which connects to
515 the calculating router via a Point-to-MultiPoint
516 network, the destination's next hop IP address(es)
517 can be determined by examining the destination's
518 router-LSA: each link pointing back to the
519 calculating router and having a Link Data field
520 belonging to the Point-to-MultiPoint network
521 provides an IP address of the next hop router.
522
523 At this point l is a link from V to W, and V is the
524 root ("us"). Find the local interface associated
525 with l (its address is in l->link_data). If it
526 is a point-to-multipoint interface, then look through
527 the links in the opposite direction (W to V). If
528 any of them have an address that lands within the
529 subnet declared by the PtMP link, then that link
530 is a constituent of the PtMP link, and its address is
531 a nexthop address for V.
532 */
533 oi = ospf_if_is_configured (area->ospf, &l->link_data);
534 if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
0c0f9cd5 535 {
eb3da6df 536 struct prefix_ipv4 la;
537
538 la.family = AF_INET;
539 la.prefixlen = oi->address->prefixlen;
540
541 /* V links to W on PtMP interface
542 - find the interface address on W */
543 while ((l2 = ospf_get_next_link (w, v, l2)))
0c0f9cd5 544 {
eb3da6df 545 la.prefix = l2->link_data;
0c0f9cd5 546
eb3da6df 547 if (prefix_cmp ((struct prefix *) &la,
548 oi->address) == 0)
549 /* link_data is on our PtMP network */
550 break;
551 }
552 } /* end l is on point-to-multipoint link */
553 else
554 {
555 /* l is a regular point-to-point link.
556 Look for a link from W to V.
557 */
558 while ((l2 = ospf_get_next_link (w, v, l2)))
0c0f9cd5 559 {
eb3da6df 560 oi = ospf_if_is_configured (area->ospf,
561 &(l2->link_data));
562
563 if (oi == NULL)
564 continue;
565
566 if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
567 &l->link_data))
568 continue;
569
570 break;
0c0f9cd5 571 }
eb3da6df 572 }
573
574 if (oi && l2)
575 {
576 /* found all necessary info to build nexthop */
577 nh = vertex_nexthop_new ();
578 nh->oi = oi;
579 nh->router = l2->link_data;
bc20c1a4
PJ
580 ospf_spf_add_parent (v, w, nh, l);
581 return 1;
eb3da6df 582 }
583 else
9c27ef9b
PJ
584 zlog_info("ospf_nexthop_calculation(): "
585 "could not determine nexthop for link");
586 } /* end point-to-point link from V to W */
587 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
588 {
589 struct ospf_vl_data *vl_data;
590
591 /* VLink implementation limitations:
592 * a) vl_data can only reference one nexthop, so no ECMP
593 * to backbone through VLinks. Though transit-area
594 * summaries may be considered, and those can be ECMP.
595 * b) We can only use /one/ VLink, even if multiple ones
596 * exist this router through multiple transit-areas.
597 */
598 vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id);
599
600 if (vl_data
601 && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED))
eb3da6df 602 {
9c27ef9b
PJ
603 nh = vertex_nexthop_new ();
604 nh->oi = vl_data->nexthop.oi;
605 nh->router = vl_data->nexthop.router;
bc20c1a4
PJ
606 ospf_spf_add_parent (v, w, nh, l);
607 return 1;
eb3da6df 608 }
9c27ef9b 609 else
bc20c1a4
PJ
610 zlog_info("ospf_nexthop_calculation(): "
611 "vl_data for VL link not found");
9c27ef9b 612 } /* end virtual-link from V to W */
bc20c1a4 613 return 0;
630e4807 614 } /* end W is a Router vertex */
718e3744 615 else
0c0f9cd5 616 {
eb3da6df 617 assert(w->type == OSPF_VERTEX_NETWORK);
618 oi = ospf_if_is_configured (area->ospf, &(l->link_data));
619 if (oi)
0c0f9cd5 620 {
eb3da6df 621 nh = vertex_nexthop_new ();
622 nh->oi = oi;
623 nh->router.s_addr = 0;
bc20c1a4
PJ
624 ospf_spf_add_parent (v, w, nh, l);
625 return 1;
0c0f9cd5 626 }
627 }
9c27ef9b
PJ
628 zlog_info("ospf_nexthop_calculation(): "
629 "Unknown attached link");
bc20c1a4 630 return 0;
630e4807 631 } /* end V is the root */
630e4807 632 /* Check if W's parent is a network connected to root. */
718e3744 633 else if (v->type == OSPF_VERTEX_NETWORK)
634 {
630e4807 635 /* See if any of V's parents are the root. */
eb3da6df 636 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
718e3744 637 {
eb3da6df 638 if (vp->parent == area->spf) /* connects to root? */
630e4807 639 {
640 /* 16.1.1 para 5. ...the parent vertex is a network that
641 * directly connects the calculating router to the destination
642 * router. The list of next hops is then determined by
643 * examining the destination's router-LSA...
644 */
645
646 assert(w->type == OSPF_VERTEX_ROUTER);
0c0f9cd5 647 while ((l = ospf_get_next_link (w, v, l)))
648 {
630e4807 649 /* ...For each link in the router-LSA that points back to the
650 * parent network, the link's Link Data field provides the IP
651 * address of a next hop router. The outgoing interface to
652 * use can then be derived from the next hop IP address (or
653 * it can be inherited from the parent network).
654 */
eb3da6df 655 nh = vertex_nexthop_new ();
656 nh->oi = vp->nexthop->oi;
657 nh->router = l->link_data;
bc20c1a4
PJ
658 added = 1;
659 ospf_spf_add_parent (v, w, nh, l);
0c0f9cd5 660 }
0c0f9cd5 661 }
718e3744 662 }
bc20c1a4 663 return added;
718e3744 664 }
665
630e4807 666 /* 16.1.1 para 4. If there is at least one intervening router in the
667 * current shortest path between the destination and the root, the
668 * destination simply inherits the set of next hops from the
669 * parent.
670 */
eb3da6df 671 for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
bc20c1a4
PJ
672 {
673 added = 1;
674 ospf_spf_add_parent (v, w, vp->nexthop, l);
675 }
9c27ef9b 676
bc20c1a4 677 return added;
718e3744 678}
679
630e4807 680/* RFC2328 Section 16.1 (2).
681 * v is on the SPF tree. Examine the links in v's LSA. Update the list
682 * of candidates with any vertices not already on the list. If a lower-cost
683 * path is found to a vertex already on the candidate list, store the new cost.
684 */
4dadc291 685static void
718e3744 686ospf_spf_next (struct vertex *v, struct ospf_area *area,
462f20d5 687 struct pqueue * candidate)
718e3744 688{
689 struct ospf_lsa *w_lsa = NULL;
718e3744 690 u_char *p;
691 u_char *lim;
692 struct router_lsa_link *l = NULL;
693 struct in_addr *r;
718e3744 694 int type = 0;
695
696 /* If this is a router-LSA, and bit V of the router-LSA (see Section
697 A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
698 if (v->type == OSPF_VERTEX_ROUTER)
699 {
700 if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa))
701 area->transit = OSPF_TRANSIT_TRUE;
702 }
703
704 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
0c0f9cd5 705 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
706
718e3744 707 while (p < lim)
708 {
eb3da6df 709 struct vertex *w;
710 unsigned int distance;
d355bfa7 711
718e3744 712 /* In case of V is Router-LSA. */
713 if (v->lsa->type == OSPF_ROUTER_LSA)
714 {
715 l = (struct router_lsa_link *) p;
716
0c0f9cd5 717 p += (ROUTER_LSA_MIN_SIZE +
718e3744 718 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
719
720 /* (a) If this is a link to a stub network, examine the next
721 link in V's LSA. Links to stub networks will be
722 considered in the second stage of the shortest path
723 calculation. */
724 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
725 continue;
726
727 /* (b) Otherwise, W is a transit vertex (router or transit
728 network). Look up the vertex W's LSA (router-LSA or
729 network-LSA) in Area A's link state database. */
730 switch (type)
731 {
732 case LSA_LINK_TYPE_POINTOPOINT:
733 case LSA_LINK_TYPE_VIRTUALLINK:
734 if (type == LSA_LINK_TYPE_VIRTUALLINK)
0c0f9cd5 735 {
736 if (IS_DEBUG_OSPF_EVENT)
2a42e285 737 zlog_debug ("looking up LSA through VL: %s",
0c0f9cd5 738 inet_ntoa (l->link_id));
739 }
718e3744 740
741 w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id,
742 l->link_id);
743 if (w_lsa)
0c0f9cd5 744 {
745 if (IS_DEBUG_OSPF_EVENT)
2a42e285 746 zlog_debug ("found Router LSA %s", inet_ntoa (l->link_id));
0c0f9cd5 747 }
718e3744 748 break;
749 case LSA_LINK_TYPE_TRANSIT:
0c0f9cd5 750 if (IS_DEBUG_OSPF_EVENT)
2a42e285 751 zlog_debug ("Looking up Network LSA, ID: %s",
0c0f9cd5 752 inet_ntoa (l->link_id));
718e3744 753 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA,
0c0f9cd5 754 l->link_id);
718e3744 755 if (w_lsa)
0c0f9cd5 756 if (IS_DEBUG_OSPF_EVENT)
2a42e285 757 zlog_debug ("found the LSA");
718e3744 758 break;
759 default:
0c0f9cd5 760 zlog_warn ("Invalid LSA link type %d", type);
718e3744 761 continue;
762 }
763 }
764 else
765 {
766 /* In case of V is Network-LSA. */
0c0f9cd5 767 r = (struct in_addr *) p;
718e3744 768 p += sizeof (struct in_addr);
769
770 /* Lookup the vertex W's LSA. */
771 w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r);
772 }
773
774 /* (b cont.) If the LSA does not exist, or its LS age is equal
775 to MaxAge, or it does not have a link back to vertex V,
776 examine the next link in V's LSA.[23] */
777 if (w_lsa == NULL)
778 continue;
779
780 if (IS_LSA_MAXAGE (w_lsa))
781 continue;
782
eb3da6df 783 if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 )
718e3744 784 {
0c0f9cd5 785 if (IS_DEBUG_OSPF_EVENT)
2a42e285 786 zlog_debug ("The LSA doesn't have a link back");
718e3744 787 continue;
788 }
789
790 /* (c) If vertex W is already on the shortest-path tree, examine
791 the next link in the LSA. */
462f20d5 792 if (w_lsa->stat == LSA_SPF_IN_SPFTREE)
793 {
794 if (IS_DEBUG_OSPF_EVENT)
795 zlog_debug ("The LSA is already in SPF");
796 continue;
797 }
718e3744 798
799 /* (d) Calculate the link state cost D of the resulting path
800 from the root to vertex W. D is equal to the sum of the link
801 state cost of the (already calculated) shortest path to
802 vertex V and the advertised cost of the link between vertices
803 V and W. If D is: */
804
718e3744 805 /* calculate link cost D. */
806 if (v->lsa->type == OSPF_ROUTER_LSA)
eb3da6df 807 distance = v->distance + ntohs (l->m[0].metric);
630e4807 808 else /* v is not a Router-LSA */
eb3da6df 809 distance = v->distance;
718e3744 810
811 /* Is there already vertex W in candidate list? */
462f20d5 812 if (w_lsa->stat == LSA_SPF_NOT_EXPLORED)
813 {
eb3da6df 814 /* prepare vertex W. */
815 w = ospf_vertex_new (w_lsa);
bc20c1a4 816 w->distance = distance;
eb3da6df 817
462f20d5 818 /* Calculate nexthop to W. */
bc20c1a4
PJ
819 if (ospf_nexthop_calculation (area, v, w, l))
820 pqueue_enqueue (w, candidate);
462f20d5 821 }
822 else if (w_lsa->stat >= 0)
823 {
824 /* Get the vertex from candidates. */
eb3da6df 825 w = candidate->array[w_lsa->stat];
718e3744 826
462f20d5 827 /* if D is greater than. */
eb3da6df 828 if (w->distance < distance)
718e3744 829 {
718e3744 830 continue;
831 }
462f20d5 832 /* equal to. */
eb3da6df 833 else if (w->distance == distance)
718e3744 834 {
eb3da6df 835 /* Found an equal-cost path to W.
836 * Calculate nexthop of to W from V. */
837 ospf_nexthop_calculation (area, v, w, l);
718e3744 838 }
462f20d5 839 /* less than. */
840 else
718e3744 841 {
bc20c1a4
PJ
842 /* Found a lower-cost path to W.
843 * nexthop_calculation is conditional, if it finds
844 * valid nexthop it will call spf_add_parents, which
845 * will flush the old parents
846 */
847 if (ospf_nexthop_calculation (area, v, w, l))
848 /* Decrease the key of the node in the heap,
849 * re-sort the heap. */
850 trickle_down (w_lsa->stat, candidate);
718e3744 851 }
630e4807 852 } /* end W is already on the candidate list */
853 } /* end loop over the links in V's LSA */
718e3744 854}
855
4dadc291 856static void
718e3744 857ospf_spf_dump (struct vertex *v, int i)
858{
52dc7ee6 859 struct listnode *cnode;
860 struct listnode *nnode;
eb3da6df 861 struct vertex_parent *parent;
718e3744 862
863 if (v->type == OSPF_VERTEX_ROUTER)
864 {
865 if (IS_DEBUG_OSPF_EVENT)
2a42e285 866 zlog_debug ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id));
718e3744 867 }
868 else
869 {
870 struct network_lsa *lsa = (struct network_lsa *) v->lsa;
871 if (IS_DEBUG_OSPF_EVENT)
2a42e285 872 zlog_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id),
0c0f9cd5 873 ip_masklen (lsa->mask));
630e4807 874 }
718e3744 875
1eb8ef25 876 if (IS_DEBUG_OSPF_EVENT)
eb3da6df 877 for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent))
878 {
879 zlog_debug (" nexthop %p %s %s",
880 parent->nexthop,
881 inet_ntoa (parent->nexthop->router),
882 parent->nexthop->oi ? IF_NAME(parent->nexthop->oi)
883 : "NULL");
884 }
718e3744 885
886 i++;
887
eb3da6df 888 for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v))
1eb8ef25 889 ospf_spf_dump (v, i);
718e3744 890}
891
892/* Second stage of SPF calculation. */
4dadc291 893static void
0c0f9cd5 894ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v,
718e3744 895 struct route_table *rt)
896{
1eb8ef25 897 struct listnode *cnode, *cnnode;
718e3744 898 struct vertex *child;
899
900 if (IS_DEBUG_OSPF_EVENT)
2a42e285 901 zlog_debug ("ospf_process_stub():processing stubs for area %s",
0c0f9cd5 902 inet_ntoa (area->area_id));
718e3744 903 if (v->type == OSPF_VERTEX_ROUTER)
904 {
905 u_char *p;
906 u_char *lim;
907 struct router_lsa_link *l;
908 struct router_lsa *rlsa;
909
0c0f9cd5 910 if (IS_DEBUG_OSPF_EVENT)
2a42e285 911 zlog_debug ("ospf_process_stubs():processing router LSA, id: %s",
0c0f9cd5 912 inet_ntoa (v->lsa->id));
718e3744 913 rlsa = (struct router_lsa *) v->lsa;
914
915
0c0f9cd5 916 if (IS_DEBUG_OSPF_EVENT)
2a42e285 917 zlog_debug ("ospf_process_stubs(): we have %d links to process",
0c0f9cd5 918 ntohs (rlsa->links));
630e4807 919 p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
718e3744 920 lim = ((u_char *) v->lsa) + ntohs (v->lsa->length);
921
922 while (p < lim)
923 {
924 l = (struct router_lsa_link *) p;
925
926 p += (ROUTER_LSA_MIN_SIZE +
927 (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE));
928
929 if (l->m[0].type == LSA_LINK_TYPE_STUB)
930 ospf_intra_add_stub (rt, l, v, area);
931 }
932 }
933
630e4807 934 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1);
718e3744 935
eb3da6df 936 for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child))
718e3744 937 {
718e3744 938 if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED))
0c0f9cd5 939 continue;
718e3744 940
941 ospf_spf_process_stubs (area, child, rt);
942
943 SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED);
944 }
945}
946
947void
948ospf_rtrs_free (struct route_table *rtrs)
949{
950 struct route_node *rn;
52dc7ee6 951 struct list *or_list;
1eb8ef25 952 struct ospf_route *or;
953 struct listnode *node, *nnode;
718e3744 954
955 if (IS_DEBUG_OSPF_EVENT)
2a42e285 956 zlog_debug ("Route: Router Routing Table free");
718e3744 957
958 for (rn = route_top (rtrs); rn; rn = route_next (rn))
959 if ((or_list = rn->info) != NULL)
960 {
1eb8ef25 961 for (ALL_LIST_ELEMENTS (or_list, node, nnode, or))
962 ospf_route_free (or);
718e3744 963
0c0f9cd5 964 list_delete (or_list);
718e3744 965
0c0f9cd5 966 /* Unlock the node. */
967 rn->info = NULL;
968 route_unlock_node (rn);
718e3744 969 }
970 route_table_finish (rtrs);
971}
972
4dadc291 973static void
718e3744 974ospf_rtrs_print (struct route_table *rtrs)
975{
976 struct route_node *rn;
52dc7ee6 977 struct list *or_list;
978 struct listnode *ln;
979 struct listnode *pnode;
718e3744 980 struct ospf_route *or;
981 struct ospf_path *path;
982 char buf1[BUFSIZ];
983 char buf2[BUFSIZ];
984
985 if (IS_DEBUG_OSPF_EVENT)
2a42e285 986 zlog_debug ("ospf_rtrs_print() start");
718e3744 987
988 for (rn = route_top (rtrs); rn; rn = route_next (rn))
989 if ((or_list = rn->info) != NULL)
1eb8ef25 990 for (ALL_LIST_ELEMENTS_RO (or_list, ln, or))
718e3744 991 {
718e3744 992 switch (or->path_type)
993 {
994 case OSPF_PATH_INTRA_AREA:
0c0f9cd5 995 if (IS_DEBUG_OSPF_EVENT)
2a42e285 996 zlog_debug ("%s [%d] area: %s",
0c0f9cd5 997 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
998 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
999 buf2, BUFSIZ));
718e3744 1000 break;
1001 case OSPF_PATH_INTER_AREA:
0c0f9cd5 1002 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1003 zlog_debug ("%s IA [%d] area: %s",
0c0f9cd5 1004 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1005 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1006 buf2, BUFSIZ));
718e3744 1007 break;
1008 default:
1009 break;
1010 }
1011
1eb8ef25 1012 for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
718e3744 1013 {
718e3744 1014 if (path->nexthop.s_addr == 0)
0c0f9cd5 1015 {
1016 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1017 zlog_debug (" directly attached to %s\r\n",
0c0f9cd5 1018 IF_NAME (path->oi));
1019 }
1020 else
1021 {
1022 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1023 zlog_debug (" via %s, %s\r\n",
0c0f9cd5 1024 inet_ntoa (path->nexthop), IF_NAME (path->oi));
1025 }
718e3744 1026 }
1027 }
1028
2a42e285 1029 zlog_debug ("ospf_rtrs_print() end");
718e3744 1030}
1031
1032/* Calculating the shortest-path tree for an area. */
4dadc291 1033static void
0c0f9cd5 1034ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
718e3744 1035 struct route_table *new_rtrs)
1036{
462f20d5 1037 struct pqueue *candidate;
718e3744 1038 struct vertex *v;
eb3da6df 1039
718e3744 1040 if (IS_DEBUG_OSPF_EVENT)
1041 {
2a42e285 1042 zlog_debug ("ospf_spf_calculate: Start");
1043 zlog_debug ("ospf_spf_calculate: running Dijkstra for area %s",
0c0f9cd5 1044 inet_ntoa (area->area_id));
718e3744 1045 }
1046
1047 /* Check router-lsa-self. If self-router-lsa is not yet allocated,
1048 return this area's calculation. */
0c0f9cd5 1049 if (!area->router_lsa_self)
718e3744 1050 {
1051 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1052 zlog_debug ("ospf_spf_calculate: "
0c0f9cd5 1053 "Skip area %s's calculation due to empty router_lsa_self",
1054 inet_ntoa (area->area_id));
718e3744 1055 return;
1056 }
1057
1058 /* RFC2328 16.1. (1). */
0c0f9cd5 1059 /* Initialize the algorithm's data structures. */
462f20d5 1060
1061 /* This function scans all the LSA database and set the stat field to
1062 * LSA_SPF_NOT_EXPLORED. */
1063 ospf_lsdb_clean_stat (area->lsdb);
1064 /* Create a new heap for the candidates. */
1065 candidate = pqueue_create();
1066 candidate->cmp = cmp;
1067 candidate->update = update_stat;
718e3744 1068
1069 /* Initialize the shortest-path tree to only the root (which is the
1070 router doing the calculation). */
1071 ospf_spf_init (area);
1072 v = area->spf;
462f20d5 1073 /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the
1074 * spanning tree. */
1075 *(v->stat) = LSA_SPF_IN_SPFTREE;
718e3744 1076
1077 /* Set Area A's TransitCapability to FALSE. */
1078 area->transit = OSPF_TRANSIT_FALSE;
1079 area->shortcut_capability = 1;
eb3da6df 1080
718e3744 1081 for (;;)
1082 {
1083 /* RFC2328 16.1. (2). */
462f20d5 1084 ospf_spf_next (v, area, candidate);
718e3744 1085
1086 /* RFC2328 16.1. (3). */
1087 /* If at this step the candidate list is empty, the shortest-
1088 path tree (of transit vertices) has been completely built and
1089 this stage of the procedure terminates. */
462f20d5 1090 if (candidate->size == 0)
718e3744 1091 break;
1092
1093 /* Otherwise, choose the vertex belonging to the candidate list
1094 that is closest to the root, and add it to the shortest-path
1095 tree (removing it from the candidate list in the
0c0f9cd5 1096 process). */
462f20d5 1097 /* Extract from the candidates the node with the lower key. */
1098 v = (struct vertex *) pqueue_dequeue (candidate);
1099 /* Update stat field in vertex. */
1100 *(v->stat) = LSA_SPF_IN_SPFTREE;
eb3da6df 1101
718e3744 1102 ospf_vertex_add_parent (v);
1103
718e3744 1104 /* Note that when there is a choice of vertices closest to the
1105 root, network vertices must be chosen before router vertices
1106 in order to necessarily find all equal-cost paths. */
1107 /* We don't do this at this moment, we should add the treatment
1108 above codes. -- kunihiro. */
1109
1110 /* RFC2328 16.1. (4). */
1111 if (v->type == OSPF_VERTEX_ROUTER)
1112 ospf_intra_add_router (new_rtrs, v, area);
0c0f9cd5 1113 else
718e3744 1114 ospf_intra_add_transit (new_table, v, area);
1115
1116 /* RFC2328 16.1. (5). */
1117 /* Iterate the algorithm by returning to Step 2. */
630e4807 1118
1119 } /* end loop until no more candidate vertices */
718e3744 1120
1121 if (IS_DEBUG_OSPF_EVENT)
1122 {
1123 ospf_spf_dump (area->spf, 0);
1124 ospf_route_table_dump (new_table);
1125 }
1126
1127 /* Second stage of SPF calculation procedure's */
1128 ospf_spf_process_stubs (area, area->spf, new_table);
1129
eb3da6df 1130 /* Free candidate queue. */
462f20d5 1131 pqueue_delete (candidate);
eb3da6df 1132
1133 ospf_vertex_dump (__func__, area->spf, 0, 1);
1134 /* Free nexthop information, canonical versions of which are attached
1135 * the first level of router vertices attached to the root vertex, see
1136 * ospf_nexthop_calculation.
1137 */
1138 ospf_canonical_nexthops_free (area->spf);
1139
9c27ef9b
PJ
1140 /* Free SPF vertices, but not the list. List has ospf_vertex_free
1141 * as deconstructor.
1142 */
1143 list_delete_all_node (&vertex_list);
eb3da6df 1144
718e3744 1145 /* Increment SPF Calculation Counter. */
1146 area->spf_calculation++;
1147
2518efd1 1148 quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf);
718e3744 1149
1150 if (IS_DEBUG_OSPF_EVENT)
9c27ef9b
PJ
1151 zlog_debug ("ospf_spf_calculate: Stop. %ld vertices",
1152 mtype_stats_alloc(MTYPE_OSPF_VERTEX));
718e3744 1153}
1154\f
1155/* Timer for SPF calculation. */
4dadc291 1156static int
68980084 1157ospf_spf_calculate_timer (struct thread *thread)
718e3744 1158{
68980084 1159 struct ospf *ospf = THREAD_ARG (thread);
718e3744 1160 struct route_table *new_table, *new_rtrs;
1eb8ef25 1161 struct ospf_area *area;
1162 struct listnode *node, *nnode;
718e3744 1163
1164 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1165 zlog_debug ("SPF: Timer (SPF calculation expire)");
0c0f9cd5 1166
718e3744 1167 ospf->t_spf_calc = NULL;
1168
1169 /* Allocate new table tree. */
1170 new_table = route_table_init ();
0c0f9cd5 1171 new_rtrs = route_table_init ();
718e3744 1172
68980084 1173 ospf_vl_unapprove (ospf);
718e3744 1174
1175 /* Calculate SPF for each area. */
1eb8ef25 1176 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
9c27ef9b
PJ
1177 {
1178 /* Do backbone last, so as to first discover intra-area paths
1179 * for any back-bone virtual-links
1180 */
1181 if (ospf->backbone && ospf->backbone == area)
1182 continue;
1183
1184 ospf_spf_calculate (area, new_table, new_rtrs);
1185 }
1186
1187 /* SPF for backbone, if required */
1188 if (ospf->backbone)
1189 ospf_spf_calculate (ospf->backbone, new_table, new_rtrs);
1190
68980084 1191 ospf_vl_shut_unapproved (ospf);
718e3744 1192
68980084 1193 ospf_ia_routing (ospf, new_table, new_rtrs);
718e3744 1194
1195 ospf_prune_unreachable_networks (new_table);
1196 ospf_prune_unreachable_routers (new_rtrs);
1197
1198 /* AS-external-LSA calculation should not be performed here. */
1199
1200 /* If new Router Route is installed,
1201 then schedule re-calculate External routes. */
1202 if (1)
68980084 1203 ospf_ase_calculate_schedule (ospf);
718e3744 1204
68980084 1205 ospf_ase_calculate_timer_add (ospf);
718e3744 1206
1207 /* Update routing table. */
68980084 1208 ospf_route_install (ospf, new_table);
718e3744 1209
1210 /* Update ABR/ASBR routing table */
68980084 1211 if (ospf->old_rtrs)
718e3744 1212 {
1213 /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */
68980084 1214 /* ospf_route_delete (ospf->old_rtrs); */
1215 ospf_rtrs_free (ospf->old_rtrs);
718e3744 1216 }
1217
68980084 1218 ospf->old_rtrs = ospf->new_rtrs;
1219 ospf->new_rtrs = new_rtrs;
718e3744 1220
0c0f9cd5 1221 if (IS_OSPF_ABR (ospf))
68980084 1222 ospf_abr_task (ospf);
718e3744 1223
1224 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1225 zlog_debug ("SPF: calculation complete");
718e3744 1226
1227 return 0;
1228}
1229
1230/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
1231 set timer for SPF calc. */
1232void
68980084 1233ospf_spf_calculate_schedule (struct ospf *ospf)
718e3744 1234{
d24f6e2a 1235 unsigned long delay, elapsed, ht;
1236 struct timeval result;
718e3744 1237
1238 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1239 zlog_debug ("SPF: calculation timer scheduled");
718e3744 1240
1241 /* OSPF instance does not exist. */
68980084 1242 if (ospf == NULL)
718e3744 1243 return;
d24f6e2a 1244
718e3744 1245 /* SPF calculation timer is already scheduled. */
68980084 1246 if (ospf->t_spf_calc)
718e3744 1247 {
1248 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1249 zlog_debug ("SPF: calculation timer is already scheduled: %p",
0c0f9cd5 1250 ospf->t_spf_calc);
718e3744 1251 return;
1252 }
d24f6e2a 1253
1254 /* XXX Monotic timers: we only care about relative time here. */
2518efd1 1255 result = tv_sub (recent_relative_time (), ospf->ts_spf);
d24f6e2a 1256
1257 elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
1258 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1259
1260 if (ht > ospf->spf_max_holdtime)
1261 ht = ospf->spf_max_holdtime;
1262
718e3744 1263 /* Get SPF calculation delay time. */
d24f6e2a 1264 if (elapsed < ht)
718e3744 1265 {
d24f6e2a 1266 /* Got an event within the hold time of last SPF. We need to
1267 * increase the hold_multiplier, if it's not already at/past
1268 * maximum value, and wasn't already increased..
1269 */
1270 if (ht < ospf->spf_max_holdtime)
1271 ospf->spf_hold_multiplier++;
1272
1273 /* always honour the SPF initial delay */
1274 if ( (ht - elapsed) < ospf->spf_delay)
0c0f9cd5 1275 delay = ospf->spf_delay;
718e3744 1276 else
d24f6e2a 1277 delay = ht - elapsed;
718e3744 1278 }
1279 else
d24f6e2a 1280 {
1281 /* Event is past required hold-time of last SPF */
1282 delay = ospf->spf_delay;
1283 ospf->spf_hold_multiplier = 1;
1284 }
1285
718e3744 1286 if (IS_DEBUG_OSPF_EVENT)
d24f6e2a 1287 zlog_debug ("SPF: calculation timer delay = %ld", delay);
1288
68980084 1289 ospf->t_spf_calc =
d24f6e2a 1290 thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay);
718e3744 1291}