]> git.proxmox.com Git - mirror_frr.git/blob - ospfd/ospf_spf.c
Merge pull request #929 from opensourcerouting/hooks-doc-irdp
[mirror_frr.git] / ospfd / ospf_spf.c
1 /* OSPF SPF calculation.
2 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "monotime.h"
24 #include "thread.h"
25 #include "memory.h"
26 #include "hash.h"
27 #include "linklist.h"
28 #include "prefix.h"
29 #include "if.h"
30 #include "table.h"
31 #include "log.h"
32 #include "sockunion.h" /* for inet_ntop () */
33 #include "pqueue.h"
34
35 #include "ospfd/ospfd.h"
36 #include "ospfd/ospf_interface.h"
37 #include "ospfd/ospf_ism.h"
38 #include "ospfd/ospf_asbr.h"
39 #include "ospfd/ospf_lsa.h"
40 #include "ospfd/ospf_lsdb.h"
41 #include "ospfd/ospf_neighbor.h"
42 #include "ospfd/ospf_nsm.h"
43 #include "ospfd/ospf_spf.h"
44 #include "ospfd/ospf_route.h"
45 #include "ospfd/ospf_ia.h"
46 #include "ospfd/ospf_ase.h"
47 #include "ospfd/ospf_abr.h"
48 #include "ospfd/ospf_dump.h"
49
50 /* Variables to ensure a SPF scheduled log message is printed only once */
51
52 static unsigned int spf_reason_flags = 0;
53
54 static void ospf_clear_spf_reason_flags(void)
55 {
56 spf_reason_flags = 0;
57 }
58
59 static void ospf_spf_set_reason(ospf_spf_reason_t reason)
60 {
61 spf_reason_flags |= 1 << reason;
62 }
63
64 static void ospf_vertex_free(void *);
65 /* List of allocated vertices, to simplify cleanup of SPF.
66 * Not thread-safe obviously. If it ever needs to be, it'd have to be
67 * dynamically allocated at begin of ospf_spf_calculate
68 */
69 static struct list vertex_list = {.del = ospf_vertex_free};
70
71 /* Heap related functions, for the managment of the candidates, to
72 * be used with pqueue. */
73 static int cmp(void *node1, void *node2)
74 {
75 struct vertex *v1 = (struct vertex *)node1;
76 struct vertex *v2 = (struct vertex *)node2;
77 if (v1 != NULL && v2 != NULL) {
78 /* network vertices must be chosen before router vertices of
79 * same
80 * cost in order to find all shortest paths
81 */
82 if (((v1->distance - v2->distance) == 0)
83 && (v1->type != v2->type)) {
84 switch (v1->type) {
85 case OSPF_VERTEX_NETWORK:
86 return -1;
87 case OSPF_VERTEX_ROUTER:
88 return 1;
89 }
90 } else
91 return (v1->distance - v2->distance);
92 }
93 return 0;
94 }
95
96 static void update_stat(void *node, int position)
97 {
98 struct vertex *v = node;
99
100 /* Set the status of the vertex, when its position changes. */
101 *(v->stat) = position;
102 }
103
104 static struct vertex_nexthop *vertex_nexthop_new(void)
105 {
106 return XCALLOC(MTYPE_OSPF_NEXTHOP, sizeof(struct vertex_nexthop));
107 }
108
109 static void vertex_nexthop_free(struct vertex_nexthop *nh)
110 {
111 XFREE(MTYPE_OSPF_NEXTHOP, nh);
112 }
113
114 /* Free the canonical nexthop objects for an area, ie the nexthop objects
115 * attached to the first-hop router vertices, and any intervening network
116 * vertices.
117 */
118 static void ospf_canonical_nexthops_free(struct vertex *root)
119 {
120 struct listnode *node, *nnode;
121 struct vertex *child;
122
123 for (ALL_LIST_ELEMENTS(root->children, node, nnode, child)) {
124 struct listnode *n2, *nn2;
125 struct vertex_parent *vp;
126
127 /* router vertices through an attached network each
128 * have a distinct (canonical / not inherited) nexthop
129 * which must be freed.
130 *
131 * A network vertex can only have router vertices as its
132 * children, so only one level of recursion is possible.
133 */
134 if (child->type == OSPF_VERTEX_NETWORK)
135 ospf_canonical_nexthops_free(child);
136
137 /* Free child nexthops pointing back to this root vertex */
138 for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp))
139 if (vp->parent == root && vp->nexthop) {
140 vertex_nexthop_free(vp->nexthop);
141 vp->nexthop = NULL;
142 }
143 }
144 }
145
146 /* TODO: Parent list should be excised, in favour of maintaining only
147 * vertex_nexthop, with refcounts.
148 */
149 static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
150 struct vertex_nexthop *hop)
151 {
152 struct vertex_parent *new;
153
154 new = XMALLOC(MTYPE_OSPF_VERTEX_PARENT, sizeof(struct vertex_parent));
155
156 if (new == NULL)
157 return NULL;
158
159 new->parent = v;
160 new->backlink = backlink;
161 new->nexthop = hop;
162 return new;
163 }
164
165 static void vertex_parent_free(void *p)
166 {
167 XFREE(MTYPE_OSPF_VERTEX_PARENT, p);
168 }
169
170 static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
171 {
172 struct vertex *new;
173
174 new = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex));
175
176 new->flags = 0;
177 new->stat = &(lsa->stat);
178 new->type = lsa->data->type;
179 new->id = lsa->data->id;
180 new->lsa = lsa->data;
181 new->children = list_new();
182 new->parents = list_new();
183 new->parents->del = vertex_parent_free;
184
185 listnode_add(&vertex_list, new);
186
187 if (IS_DEBUG_OSPF_EVENT)
188 zlog_debug("%s: Created %s vertex %s", __func__,
189 new->type == OSPF_VERTEX_ROUTER ? "Router"
190 : "Network",
191 inet_ntoa(new->lsa->id));
192 return new;
193 }
194
195 static void ospf_vertex_free(void *data)
196 {
197 struct vertex *v = data;
198
199 if (IS_DEBUG_OSPF_EVENT)
200 zlog_debug("%s: Free %s vertex %s", __func__,
201 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
202 inet_ntoa(v->lsa->id));
203
204 /* There should be no parents potentially holding references to this
205 * vertex
206 * Children however may still be there, but presumably referenced by
207 * other
208 * vertices
209 */
210 // assert (listcount (v->parents) == 0);
211
212 if (v->children)
213 list_delete(v->children);
214 v->children = NULL;
215
216 if (v->parents)
217 list_delete(v->parents);
218 v->parents = NULL;
219
220 v->lsa = NULL;
221
222 XFREE(MTYPE_OSPF_VERTEX, v);
223 }
224
225 static void ospf_vertex_dump(const char *msg, struct vertex *v,
226 int print_parents, int print_children)
227 {
228 if (!IS_DEBUG_OSPF_EVENT)
229 return;
230
231 zlog_debug("%s %s vertex %s distance %u flags %u", msg,
232 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
233 inet_ntoa(v->lsa->id), v->distance, (unsigned int)v->flags);
234
235 if (print_parents) {
236 struct listnode *node;
237 struct vertex_parent *vp;
238
239 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
240 char buf1[BUFSIZ];
241
242 if (vp) {
243 zlog_debug(
244 "parent %s backlink %d nexthop %s interface %s",
245 inet_ntoa(vp->parent->lsa->id),
246 vp->backlink,
247 inet_ntop(AF_INET, &vp->nexthop->router,
248 buf1, BUFSIZ),
249 vp->nexthop->oi
250 ? IF_NAME(vp->nexthop->oi)
251 : "NULL");
252 }
253 }
254 }
255
256 if (print_children) {
257 struct listnode *cnode;
258 struct vertex *cv;
259
260 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, cv))
261 ospf_vertex_dump(" child:", cv, 0, 0);
262 }
263 }
264
265
266 /* Add a vertex to the list of children in each of its parents. */
267 static void ospf_vertex_add_parent(struct vertex *v)
268 {
269 struct vertex_parent *vp;
270 struct listnode *node;
271
272 assert(v && v->parents);
273
274 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
275 assert(vp->parent && vp->parent->children);
276
277 /* No need to add two links from the same parent. */
278 if (listnode_lookup(vp->parent->children, v) == NULL)
279 listnode_add(vp->parent->children, v);
280 }
281 }
282
283 static void ospf_spf_init(struct ospf_area *area)
284 {
285 struct vertex *v;
286
287 /* Create root node. */
288 v = ospf_vertex_new(area->router_lsa_self);
289
290 area->spf = v;
291
292 /* Reset ABR and ASBR router counts. */
293 area->abr_count = 0;
294 area->asbr_count = 0;
295 }
296
297 /* return index of link back to V from W, or -1 if no link found */
298 static int ospf_lsa_has_link(struct lsa_header *w, struct lsa_header *v)
299 {
300 unsigned int i, length;
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 if (v->type == OSPF_NETWORK_LSA)
307 return -1;
308
309 nl = (struct network_lsa *)w;
310 length = (ntohs(w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
311
312 for (i = 0; i < length; i++)
313 if (IPV4_ADDR_SAME(&nl->routers[i], &v->id))
314 return i;
315 return -1;
316 }
317
318 /* In case of W is Router LSA. */
319 if (w->type == OSPF_ROUTER_LSA) {
320 rl = (struct router_lsa *)w;
321
322 length = ntohs(w->length);
323
324 for (i = 0; i < ntohs(rl->links)
325 && length >= sizeof(struct router_lsa);
326 i++, length -= 12) {
327 switch (rl->link[i].type) {
328 case LSA_LINK_TYPE_POINTOPOINT:
329 case LSA_LINK_TYPE_VIRTUALLINK:
330 /* Router LSA ID. */
331 if (v->type == OSPF_ROUTER_LSA
332 && IPV4_ADDR_SAME(&rl->link[i].link_id,
333 &v->id)) {
334 return i;
335 }
336 break;
337 case LSA_LINK_TYPE_TRANSIT:
338 /* Network LSA ID. */
339 if (v->type == OSPF_NETWORK_LSA
340 && IPV4_ADDR_SAME(&rl->link[i].link_id,
341 &v->id)) {
342 return i;
343 }
344 break;
345 case LSA_LINK_TYPE_STUB:
346 /* Stub can't lead anywhere, carry on */
347 continue;
348 default:
349 break;
350 }
351 }
352 }
353 return -1;
354 }
355
356 /* Find the next link after prev_link from v to w. If prev_link is
357 * NULL, return the first link from v to w. Ignore stub and virtual links;
358 * these link types will never be returned.
359 */
360 static struct router_lsa_link *
361 ospf_get_next_link(struct vertex *v, struct vertex *w,
362 struct router_lsa_link *prev_link)
363 {
364 u_char *p;
365 u_char *lim;
366 u_char lsa_type = LSA_LINK_TYPE_TRANSIT;
367 struct router_lsa_link *l;
368
369 if (w->type == OSPF_VERTEX_ROUTER)
370 lsa_type = LSA_LINK_TYPE_POINTOPOINT;
371
372 if (prev_link == NULL)
373 p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
374 else {
375 p = (u_char *)prev_link;
376 p += (OSPF_ROUTER_LSA_LINK_SIZE
377 + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
378 }
379
380 lim = ((u_char *)v->lsa) + ntohs(v->lsa->length);
381
382 while (p < lim) {
383 l = (struct router_lsa_link *)p;
384
385 p += (OSPF_ROUTER_LSA_LINK_SIZE
386 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
387
388 if (l->m[0].type != lsa_type)
389 continue;
390
391 if (IPV4_ADDR_SAME(&l->link_id, &w->id))
392 return l;
393 }
394
395 return NULL;
396 }
397
398 static void ospf_spf_flush_parents(struct vertex *w)
399 {
400 struct vertex_parent *vp;
401 struct listnode *ln, *nn;
402
403 /* delete the existing nexthops */
404 for (ALL_LIST_ELEMENTS(w->parents, ln, nn, vp)) {
405 list_delete_node(w->parents, ln);
406 vertex_parent_free(vp);
407 }
408 }
409
410 /*
411 * Consider supplied next-hop for inclusion to the supplied list of
412 * equal-cost next-hops, adjust list as neccessary.
413 */
414 static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
415 struct vertex_nexthop *newhop,
416 unsigned int distance)
417 {
418 struct vertex_parent *vp, *wp;
419 struct listnode *node;
420
421 /* we must have a newhop, and a distance */
422 assert(v && w && newhop);
423 assert(distance);
424
425 /* IFF w has already been assigned a distance, then we shouldn't get
426 * here
427 * unless callers have determined V(l)->W is shortest / equal-shortest
428 * path (0 is a special case distance (no distance yet assigned)).
429 */
430 if (w->distance)
431 assert(distance <= w->distance);
432 else
433 w->distance = distance;
434
435 if (IS_DEBUG_OSPF_EVENT) {
436 char buf[2][INET_ADDRSTRLEN];
437 zlog_debug(
438 "%s: Adding %s as parent of %s", __func__,
439 inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])),
440 inet_ntop(AF_INET, &w->lsa->id, buf[1],
441 sizeof(buf[1])));
442 }
443
444 /* Adding parent for a new, better path: flush existing parents from W.
445 */
446 if (distance < w->distance) {
447 if (IS_DEBUG_OSPF_EVENT)
448 zlog_debug(
449 "%s: distance %d better than %d, flushing existing parents",
450 __func__, distance, w->distance);
451 ospf_spf_flush_parents(w);
452 w->distance = distance;
453 }
454
455 /* new parent is <= existing parents, add it to parent list (if nexthop
456 * not on parent list)
457 */
458 for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) {
459 if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) {
460 if (IS_DEBUG_OSPF_EVENT)
461 zlog_debug(
462 "%s: ... nexthop already on parent list, skipping add",
463 __func__);
464 return;
465 }
466 }
467
468 vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop);
469 listnode_add(w->parents, vp);
470
471 return;
472 }
473
474 /* 16.1.1. Calculate nexthop from root through V (parent) to
475 * vertex W (destination), with given distance from root->W.
476 *
477 * The link must be supplied if V is the root vertex. In all other cases
478 * it may be NULL.
479 *
480 * Note that this function may fail, hence the state of the destination
481 * vertex, W, should /not/ be modified in a dependent manner until
482 * this function returns. This function will update the W vertex with the
483 * provided distance as appropriate.
484 */
485 static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
486 struct vertex *v, struct vertex *w,
487 struct router_lsa_link *l,
488 unsigned int distance, int lsa_pos)
489 {
490 struct listnode *node, *nnode;
491 struct vertex_nexthop *nh;
492 struct vertex_parent *vp;
493 struct ospf_interface *oi = NULL;
494 unsigned int added = 0;
495 char buf1[BUFSIZ];
496 char buf2[BUFSIZ];
497
498 if (IS_DEBUG_OSPF_EVENT) {
499 zlog_debug("ospf_nexthop_calculation(): Start");
500 ospf_vertex_dump("V (parent):", v, 1, 1);
501 ospf_vertex_dump("W (dest) :", w, 1, 1);
502 zlog_debug("V->W distance: %d", distance);
503 }
504
505 if (v == area->spf) {
506 /* 16.1.1 para 4. In the first case, the parent vertex (V) is
507 the
508 root (the calculating router itself). This means that the
509 destination is either a directly connected network or
510 directly
511 connected router. The outgoing interface in this case is
512 simply
513 the OSPF interface connecting to the destination
514 network/router.
515 */
516
517 /* we *must* be supplied with the link data */
518 assert(l != NULL);
519 oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos);
520 if (!oi) {
521 zlog_debug(
522 "%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s",
523 __func__, lsa_pos,
524 inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
525 inet_ntop(AF_INET, &l->link_data, buf2,
526 BUFSIZ));
527 return 0;
528 }
529
530 if (IS_DEBUG_OSPF_EVENT) {
531 zlog_debug(
532 "%s: considering link:%s "
533 "type:%d link_id:%s link_data:%s",
534 __func__, oi->ifp->name, l->m[0].type,
535 inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
536 inet_ntop(AF_INET, &l->link_data, buf2,
537 BUFSIZ));
538 }
539
540 if (w->type == OSPF_VERTEX_ROUTER) {
541 /* l is a link from v to w
542 * l2 will be link from w to v
543 */
544 struct router_lsa_link *l2 = NULL;
545
546 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) {
547 struct in_addr nexthop = {.s_addr = 0};
548
549 /* If the destination is a router which connects
550 to
551 the calculating router via a
552 Point-to-MultiPoint
553 network, the destination's next hop IP
554 address(es)
555 can be determined by examining the
556 destination's
557 router-LSA: each link pointing back to the
558 calculating router and having a Link Data
559 field
560 belonging to the Point-to-MultiPoint network
561 provides an IP address of the next hop
562 router.
563
564 At this point l is a link from V to W, and V
565 is the
566 root ("us"). If it is a point-to-multipoint
567 interface,
568 then look through the links in the opposite
569 direction (W to V).
570 If any of them have an address that lands
571 within the
572 subnet declared by the PtMP link, then that
573 link
574 is a constituent of the PtMP link, and its
575 address is
576 a nexthop address for V.
577 */
578 if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
579 /* Having nexthop = 0 is tempting, but
580 NOT acceptable.
581 It breaks AS-External routes with a
582 forwarding address,
583 since
584 ospf_ase_complete_direct_routes()
585 will mistakenly
586 assume we've reached the last hop and
587 should place the
588 forwarding address as nexthop.
589 Also, users may configure
590 multi-access links in p2p mode,
591 so we need the IP to ARP the nexthop.
592 */
593 struct ospf_neighbor *nbr_w;
594
595 nbr_w = ospf_nbr_lookup_by_routerid(
596 oi->nbrs, &l->link_id);
597 if (nbr_w != NULL) {
598 added = 1;
599 nexthop = nbr_w->src;
600 }
601 } else if (oi->type
602 == OSPF_IFTYPE_POINTOMULTIPOINT) {
603 struct prefix_ipv4 la;
604
605 la.family = AF_INET;
606 la.prefixlen = oi->address->prefixlen;
607
608 /* V links to W on PtMP interface
609 - find the interface address on W */
610 while ((l2 = ospf_get_next_link(w, v,
611 l2))) {
612 la.prefix = l2->link_data;
613
614 if (prefix_cmp((struct prefix
615 *)&la,
616 oi->address)
617 != 0)
618 continue;
619 /* link_data is on our PtMP
620 * network */
621 added = 1;
622 nexthop = l2->link_data;
623 break;
624 }
625 }
626
627 if (added) {
628 /* found all necessary info to build
629 * nexthop */
630 nh = vertex_nexthop_new();
631 nh->oi = oi;
632 nh->router = nexthop;
633 ospf_spf_add_parent(v, w, nh, distance);
634 return 1;
635 } else
636 zlog_info(
637 "%s: could not determine nexthop for link %s",
638 __func__, oi->ifp->name);
639 } /* end point-to-point link from V to W */
640 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) {
641 struct ospf_vl_data *vl_data;
642
643 /* VLink implementation limitations:
644 * a) vl_data can only reference one nexthop, so
645 * no ECMP
646 * to backbone through VLinks. Though
647 * transit-area
648 * summaries may be considered, and those can
649 * be ECMP.
650 * b) We can only use /one/ VLink, even if
651 * multiple ones
652 * exist this router through multiple
653 * transit-areas.
654 */
655 vl_data = ospf_vl_lookup(area->ospf, NULL,
656 l->link_id);
657
658 if (vl_data
659 && CHECK_FLAG(vl_data->flags,
660 OSPF_VL_FLAG_APPROVED)) {
661 nh = vertex_nexthop_new();
662 nh->oi = vl_data->nexthop.oi;
663 nh->router = vl_data->nexthop.router;
664 ospf_spf_add_parent(v, w, nh, distance);
665 return 1;
666 } else
667 zlog_info(
668 "ospf_nexthop_calculation(): "
669 "vl_data for VL link not found");
670 } /* end virtual-link from V to W */
671 return 0;
672 } /* end W is a Router vertex */
673 else {
674 assert(w->type == OSPF_VERTEX_NETWORK);
675
676 nh = vertex_nexthop_new();
677 nh->oi = oi;
678 nh->router.s_addr = 0; /* Nexthop not required */
679 ospf_spf_add_parent(v, w, nh, distance);
680 return 1;
681 }
682 } /* end V is the root */
683 /* Check if W's parent is a network connected to root. */
684 else if (v->type == OSPF_VERTEX_NETWORK) {
685 /* See if any of V's parents are the root. */
686 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
687 if (vp->parent == area->spf) /* connects to root? */
688 {
689 /* 16.1.1 para 5. ...the parent vertex is a
690 * network that
691 * directly connects the calculating router to
692 * the destination
693 * router. The list of next hops is then
694 * determined by
695 * examining the destination's router-LSA...
696 */
697
698 assert(w->type == OSPF_VERTEX_ROUTER);
699 while ((l = ospf_get_next_link(w, v, l))) {
700 /* ...For each link in the router-LSA
701 * that points back to the
702 * parent network, the link's Link Data
703 * field provides the IP
704 * address of a next hop router. The
705 * outgoing interface to
706 * use can then be derived from the next
707 * hop IP address (or
708 * it can be inherited from the parent
709 * network).
710 */
711 nh = vertex_nexthop_new();
712 nh->oi = vp->nexthop->oi;
713 nh->router = l->link_data;
714 added = 1;
715 ospf_spf_add_parent(v, w, nh, distance);
716 }
717 /* Note lack of return is deliberate. See next
718 * comment. */
719 }
720 }
721 /* NB: This code is non-trivial.
722 *
723 * E.g. it is not enough to know that V connects to the root. It
724 * is
725 * also important that the while above, looping through all
726 * links from
727 * W->V found at least one link, so that we know there is
728 * bi-directional connectivity between V and W (which need not
729 * be the
730 * case, e.g. when OSPF has not yet converged fully).
731 * Otherwise, if
732 * we /always/ return here, without having checked that
733 * root->V->-W
734 * actually resulted in a valid nexthop being created, then we
735 * we will
736 * prevent SPF from finding/using higher cost paths.
737 *
738 * It is important, if root->V->W has not been added, that we
739 * continue
740 * through to the intervening-router nexthop code below. So as
741 * to
742 * ensure other paths to V may be used. This avoids unnecessary
743 * blackholes while OSPF is convergening.
744 *
745 * I.e. we may have arrived at this function, examining V -> W,
746 * via
747 * workable paths other than root -> V, and it's important to
748 * avoid
749 * getting "confused" by non-working root->V->W path - it's
750 * important
751 * to *not* lose the working non-root paths, just because of a
752 * non-viable root->V->W.
753 *
754 * See also bug #330 (required reading!), and:
755 *
756 * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes
757 */
758 if (added)
759 return added;
760 }
761
762 /* 16.1.1 para 4. If there is at least one intervening router in the
763 * current shortest path between the destination and the root, the
764 * destination simply inherits the set of next hops from the
765 * parent.
766 */
767 if (IS_DEBUG_OSPF_EVENT)
768 zlog_debug("%s: Intervening routers, adding parent(s)",
769 __func__);
770
771 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
772 added = 1;
773 ospf_spf_add_parent(v, w, vp->nexthop, distance);
774 }
775
776 return added;
777 }
778
779 /* RFC2328 Section 16.1 (2).
780 * v is on the SPF tree. Examine the links in v's LSA. Update the list
781 * of candidates with any vertices not already on the list. If a lower-cost
782 * path is found to a vertex already on the candidate list, store the new cost.
783 */
784 static void ospf_spf_next(struct vertex *v, struct ospf_area *area,
785 struct pqueue *candidate)
786 {
787 struct ospf_lsa *w_lsa = NULL;
788 u_char *p;
789 u_char *lim;
790 struct router_lsa_link *l = NULL;
791 struct in_addr *r;
792 int type = 0, lsa_pos = -1, lsa_pos_next = 0;
793
794 /* If this is a router-LSA, and bit V of the router-LSA (see Section
795 A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
796 if (v->type == OSPF_VERTEX_ROUTER) {
797 if (IS_ROUTER_LSA_VIRTUAL((struct router_lsa *)v->lsa))
798 area->transit = OSPF_TRANSIT_TRUE;
799 }
800
801 if (IS_DEBUG_OSPF_EVENT)
802 zlog_debug("%s: Next vertex of %s vertex %s", __func__,
803 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
804 inet_ntoa(v->lsa->id));
805
806 p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
807 lim = ((u_char *)v->lsa) + ntohs(v->lsa->length);
808
809 while (p < lim) {
810 struct vertex *w;
811 unsigned int distance;
812
813 /* In case of V is Router-LSA. */
814 if (v->lsa->type == OSPF_ROUTER_LSA) {
815 l = (struct router_lsa_link *)p;
816
817 lsa_pos = lsa_pos_next; /* LSA link position */
818 lsa_pos_next++;
819 p += (OSPF_ROUTER_LSA_LINK_SIZE
820 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
821
822 /* (a) If this is a link to a stub network, examine the
823 next
824 link in V's LSA. Links to stub networks will be
825 considered in the second stage of the shortest path
826 calculation. */
827 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
828 continue;
829
830 /* (b) Otherwise, W is a transit vertex (router or
831 transit
832 network). Look up the vertex W's LSA (router-LSA or
833 network-LSA) in Area A's link state database. */
834 switch (type) {
835 case LSA_LINK_TYPE_POINTOPOINT:
836 case LSA_LINK_TYPE_VIRTUALLINK:
837 if (type == LSA_LINK_TYPE_VIRTUALLINK) {
838 if (IS_DEBUG_OSPF_EVENT)
839 zlog_debug(
840 "looking up LSA through VL: %s",
841 inet_ntoa(l->link_id));
842 }
843
844 w_lsa = ospf_lsa_lookup(area, OSPF_ROUTER_LSA,
845 l->link_id, l->link_id);
846 if (w_lsa) {
847 if (IS_DEBUG_OSPF_EVENT)
848 zlog_debug(
849 "found Router LSA %s",
850 inet_ntoa(l->link_id));
851 }
852 break;
853 case LSA_LINK_TYPE_TRANSIT:
854 if (IS_DEBUG_OSPF_EVENT)
855 zlog_debug(
856 "Looking up Network LSA, ID: %s",
857 inet_ntoa(l->link_id));
858 w_lsa = ospf_lsa_lookup_by_id(
859 area, OSPF_NETWORK_LSA, l->link_id);
860 if (w_lsa)
861 if (IS_DEBUG_OSPF_EVENT)
862 zlog_debug("found the LSA");
863 break;
864 default:
865 zlog_warn("Invalid LSA link type %d", type);
866 continue;
867 }
868 } else {
869 /* In case of V is Network-LSA. */
870 r = (struct in_addr *)p;
871 p += sizeof(struct in_addr);
872
873 /* Lookup the vertex W's LSA. */
874 w_lsa = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
875 *r);
876 if (w_lsa) {
877 if (IS_DEBUG_OSPF_EVENT)
878 zlog_debug("found Router LSA %s",
879 inet_ntoa(w_lsa->data->id));
880 }
881 }
882
883 /* (b cont.) If the LSA does not exist, or its LS age is equal
884 to MaxAge, or it does not have a link back to vertex V,
885 examine the next link in V's LSA.[23] */
886 if (w_lsa == NULL) {
887 if (IS_DEBUG_OSPF_EVENT)
888 zlog_debug("No LSA found");
889 continue;
890 }
891
892 if (IS_LSA_MAXAGE(w_lsa)) {
893 if (IS_DEBUG_OSPF_EVENT)
894 zlog_debug("LSA is MaxAge");
895 continue;
896 }
897
898 if (ospf_lsa_has_link(w_lsa->data, v->lsa) < 0) {
899 if (IS_DEBUG_OSPF_EVENT)
900 zlog_debug("The LSA doesn't have a link back");
901 continue;
902 }
903
904 /* (c) If vertex W is already on the shortest-path tree, examine
905 the next link in the LSA. */
906 if (w_lsa->stat == LSA_SPF_IN_SPFTREE) {
907 if (IS_DEBUG_OSPF_EVENT)
908 zlog_debug("The LSA is already in SPF");
909 continue;
910 }
911
912 /* (d) Calculate the link state cost D of the resulting path
913 from the root to vertex W. D is equal to the sum of the link
914 state cost of the (already calculated) shortest path to
915 vertex V and the advertised cost of the link between vertices
916 V and W. If D is: */
917
918 /* calculate link cost D. */
919 if (v->lsa->type == OSPF_ROUTER_LSA)
920 distance = v->distance + ntohs(l->m[0].metric);
921 else /* v is not a Router-LSA */
922 distance = v->distance;
923
924 /* Is there already vertex W in candidate list? */
925 if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) {
926 /* prepare vertex W. */
927 w = ospf_vertex_new(w_lsa);
928
929 /* Calculate nexthop to W. */
930 if (ospf_nexthop_calculation(area, v, w, l, distance,
931 lsa_pos))
932 pqueue_enqueue(w, candidate);
933 else if (IS_DEBUG_OSPF_EVENT)
934 zlog_debug("Nexthop Calc failed");
935 } else if (w_lsa->stat >= 0) {
936 /* Get the vertex from candidates. */
937 w = candidate->array[w_lsa->stat];
938
939 /* if D is greater than. */
940 if (w->distance < distance) {
941 continue;
942 }
943 /* equal to. */
944 else if (w->distance == distance) {
945 /* Found an equal-cost path to W.
946 * Calculate nexthop of to W from V. */
947 ospf_nexthop_calculation(area, v, w, l,
948 distance, lsa_pos);
949 }
950 /* less than. */
951 else {
952 /* Found a lower-cost path to W.
953 * nexthop_calculation is conditional, if it
954 * finds
955 * valid nexthop it will call spf_add_parents,
956 * which
957 * will flush the old parents
958 */
959 if (ospf_nexthop_calculation(area, v, w, l,
960 distance, lsa_pos))
961 /* Decrease the key of the node in the
962 * heap.
963 * trickle-sort it up towards root, just
964 * in case this
965 * node should now be the new root due
966 * the cost change.
967 * (next pqueu_{de,en}queue will fully
968 * re-heap the queue).
969 */
970 trickle_up(w_lsa->stat, candidate);
971 }
972 } /* end W is already on the candidate list */
973 } /* end loop over the links in V's LSA */
974 }
975
976 static void ospf_spf_dump(struct vertex *v, int i)
977 {
978 struct listnode *cnode;
979 struct listnode *nnode;
980 struct vertex_parent *parent;
981
982 if (v->type == OSPF_VERTEX_ROUTER) {
983 if (IS_DEBUG_OSPF_EVENT)
984 zlog_debug("SPF Result: %d [R] %s", i,
985 inet_ntoa(v->lsa->id));
986 } else {
987 struct network_lsa *lsa = (struct network_lsa *)v->lsa;
988 if (IS_DEBUG_OSPF_EVENT)
989 zlog_debug("SPF Result: %d [N] %s/%d", i,
990 inet_ntoa(v->lsa->id),
991 ip_masklen(lsa->mask));
992 }
993
994 if (IS_DEBUG_OSPF_EVENT)
995 for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) {
996 zlog_debug(" nexthop %p %s %s", (void *)parent->nexthop,
997 inet_ntoa(parent->nexthop->router),
998 parent->nexthop->oi
999 ? IF_NAME(parent->nexthop->oi)
1000 : "NULL");
1001 }
1002
1003 i++;
1004
1005 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v))
1006 ospf_spf_dump(v, i);
1007 }
1008
1009 /* Second stage of SPF calculation. */
1010 static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
1011 struct route_table *rt, int parent_is_root)
1012 {
1013 struct listnode *cnode, *cnnode;
1014 struct vertex *child;
1015
1016 if (IS_DEBUG_OSPF_EVENT)
1017 zlog_debug("ospf_process_stub():processing stubs for area %s",
1018 inet_ntoa(area->area_id));
1019 if (v->type == OSPF_VERTEX_ROUTER) {
1020 u_char *p;
1021 u_char *lim;
1022 struct router_lsa_link *l;
1023 struct router_lsa *rlsa;
1024 int lsa_pos = 0;
1025
1026 if (IS_DEBUG_OSPF_EVENT)
1027 zlog_debug(
1028 "ospf_process_stubs():processing router LSA, id: %s",
1029 inet_ntoa(v->lsa->id));
1030 rlsa = (struct router_lsa *)v->lsa;
1031
1032
1033 if (IS_DEBUG_OSPF_EVENT)
1034 zlog_debug(
1035 "ospf_process_stubs(): we have %d links to process",
1036 ntohs(rlsa->links));
1037 p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
1038 lim = ((u_char *)v->lsa) + ntohs(v->lsa->length);
1039
1040 while (p < lim) {
1041 l = (struct router_lsa_link *)p;
1042
1043 p += (OSPF_ROUTER_LSA_LINK_SIZE
1044 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
1045
1046 if (l->m[0].type == LSA_LINK_TYPE_STUB)
1047 ospf_intra_add_stub(rt, l, v, area,
1048 parent_is_root, lsa_pos);
1049 lsa_pos++;
1050 }
1051 }
1052
1053 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1,
1054 1);
1055
1056 for (ALL_LIST_ELEMENTS(v->children, cnode, cnnode, child)) {
1057 if (CHECK_FLAG(child->flags, OSPF_VERTEX_PROCESSED))
1058 continue;
1059
1060 /* the first level of routers connected to the root
1061 * should have 'parent_is_root' set, including those
1062 * connected via a network vertex.
1063 */
1064 if (area->spf == v)
1065 parent_is_root = 1;
1066 else if (v->type == OSPF_VERTEX_ROUTER)
1067 parent_is_root = 0;
1068
1069 ospf_spf_process_stubs(area, child, rt, parent_is_root);
1070
1071 SET_FLAG(child->flags, OSPF_VERTEX_PROCESSED);
1072 }
1073 }
1074
1075 void ospf_rtrs_free(struct route_table *rtrs)
1076 {
1077 struct route_node *rn;
1078 struct list *or_list;
1079 struct ospf_route * or ;
1080 struct listnode *node, *nnode;
1081
1082 if (IS_DEBUG_OSPF_EVENT)
1083 zlog_debug("Route: Router Routing Table free");
1084
1085 for (rn = route_top(rtrs); rn; rn = route_next(rn))
1086 if ((or_list = rn->info) != NULL) {
1087 for (ALL_LIST_ELEMENTS(or_list, node, nnode, or))
1088 ospf_route_free(or);
1089
1090 list_delete(or_list);
1091
1092 /* Unlock the node. */
1093 rn->info = NULL;
1094 route_unlock_node(rn);
1095 }
1096 route_table_finish(rtrs);
1097 }
1098
1099 #if 0
1100 static void
1101 ospf_rtrs_print (struct route_table *rtrs)
1102 {
1103 struct route_node *rn;
1104 struct list *or_list;
1105 struct listnode *ln;
1106 struct listnode *pnode;
1107 struct ospf_route *or;
1108 struct ospf_path *path;
1109 char buf1[BUFSIZ];
1110 char buf2[BUFSIZ];
1111
1112 if (IS_DEBUG_OSPF_EVENT)
1113 zlog_debug ("ospf_rtrs_print() start");
1114
1115 for (rn = route_top (rtrs); rn; rn = route_next (rn))
1116 if ((or_list = rn->info) != NULL)
1117 for (ALL_LIST_ELEMENTS_RO (or_list, ln, or))
1118 {
1119 switch (or->path_type)
1120 {
1121 case OSPF_PATH_INTRA_AREA:
1122 if (IS_DEBUG_OSPF_EVENT)
1123 zlog_debug ("%s [%d] area: %s",
1124 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1125 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1126 buf2, BUFSIZ));
1127 break;
1128 case OSPF_PATH_INTER_AREA:
1129 if (IS_DEBUG_OSPF_EVENT)
1130 zlog_debug ("%s IA [%d] area: %s",
1131 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1132 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1133 buf2, BUFSIZ));
1134 break;
1135 default:
1136 break;
1137 }
1138
1139 for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
1140 {
1141 if (path->nexthop.s_addr == 0)
1142 {
1143 if (IS_DEBUG_OSPF_EVENT)
1144 zlog_debug (" directly attached to %s\r\n",
1145 ifindex2ifname (path->ifindex), VRF_DEFAULT);
1146 }
1147 else
1148 {
1149 if (IS_DEBUG_OSPF_EVENT)
1150 zlog_debug (" via %s, %s\r\n",
1151 inet_ntoa (path->nexthop),
1152 ifindex2ifname (path->ifindex), VRF_DEFAULT);
1153 }
1154 }
1155 }
1156
1157 zlog_debug ("ospf_rtrs_print() end");
1158 }
1159 #endif
1160
1161 /* Calculating the shortest-path tree for an area. */
1162 static void ospf_spf_calculate(struct ospf_area *area,
1163 struct route_table *new_table,
1164 struct route_table *new_rtrs)
1165 {
1166 struct pqueue *candidate;
1167 struct vertex *v;
1168
1169 if (IS_DEBUG_OSPF_EVENT) {
1170 zlog_debug("ospf_spf_calculate: Start");
1171 zlog_debug("ospf_spf_calculate: running Dijkstra for area %s",
1172 inet_ntoa(area->area_id));
1173 }
1174
1175 /* Check router-lsa-self. If self-router-lsa is not yet allocated,
1176 return this area's calculation. */
1177 if (!area->router_lsa_self) {
1178 if (IS_DEBUG_OSPF_EVENT)
1179 zlog_debug(
1180 "ospf_spf_calculate: "
1181 "Skip area %s's calculation due to empty router_lsa_self",
1182 inet_ntoa(area->area_id));
1183 return;
1184 }
1185
1186 /* RFC2328 16.1. (1). */
1187 /* Initialize the algorithm's data structures. */
1188
1189 /* This function scans all the LSA database and set the stat field to
1190 * LSA_SPF_NOT_EXPLORED. */
1191 ospf_lsdb_clean_stat(area->lsdb);
1192 /* Create a new heap for the candidates. */
1193 candidate = pqueue_create();
1194 candidate->cmp = cmp;
1195 candidate->update = update_stat;
1196
1197 /* Initialize the shortest-path tree to only the root (which is the
1198 router doing the calculation). */
1199 ospf_spf_init(area);
1200 v = area->spf;
1201 /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of
1202 * the
1203 * spanning tree. */
1204 *(v->stat) = LSA_SPF_IN_SPFTREE;
1205
1206 /* Set Area A's TransitCapability to FALSE. */
1207 area->transit = OSPF_TRANSIT_FALSE;
1208 area->shortcut_capability = 1;
1209
1210 for (;;) {
1211 /* RFC2328 16.1. (2). */
1212 ospf_spf_next(v, area, candidate);
1213
1214 /* RFC2328 16.1. (3). */
1215 /* If at this step the candidate list is empty, the shortest-
1216 path tree (of transit vertices) has been completely built and
1217 this stage of the procedure terminates. */
1218 if (candidate->size == 0)
1219 break;
1220
1221 /* Otherwise, choose the vertex belonging to the candidate list
1222 that is closest to the root, and add it to the shortest-path
1223 tree (removing it from the candidate list in the
1224 process). */
1225 /* Extract from the candidates the node with the lower key. */
1226 v = (struct vertex *)pqueue_dequeue(candidate);
1227 /* Update stat field in vertex. */
1228 *(v->stat) = LSA_SPF_IN_SPFTREE;
1229
1230 ospf_vertex_add_parent(v);
1231
1232 /* RFC2328 16.1. (4). */
1233 if (v->type == OSPF_VERTEX_ROUTER)
1234 ospf_intra_add_router(new_rtrs, v, area);
1235 else
1236 ospf_intra_add_transit(new_table, v, area);
1237
1238 /* RFC2328 16.1. (5). */
1239 /* Iterate the algorithm by returning to Step 2. */
1240
1241 } /* end loop until no more candidate vertices */
1242
1243 if (IS_DEBUG_OSPF_EVENT) {
1244 ospf_spf_dump(area->spf, 0);
1245 ospf_route_table_dump(new_table);
1246 }
1247
1248 /* Second stage of SPF calculation procedure's */
1249 ospf_spf_process_stubs(area, area->spf, new_table, 0);
1250
1251 /* Free candidate queue. */
1252 pqueue_delete(candidate);
1253
1254 ospf_vertex_dump(__func__, area->spf, 0, 1);
1255 /* Free nexthop information, canonical versions of which are attached
1256 * the first level of router vertices attached to the root vertex, see
1257 * ospf_nexthop_calculation.
1258 */
1259 ospf_canonical_nexthops_free(area->spf);
1260
1261 /* Increment SPF Calculation Counter. */
1262 area->spf_calculation++;
1263
1264 monotime(&area->ospf->ts_spf);
1265 area->ts_spf = area->ospf->ts_spf;
1266
1267 if (IS_DEBUG_OSPF_EVENT)
1268 zlog_debug("ospf_spf_calculate: Stop. %zd vertices",
1269 mtype_stats_alloc(MTYPE_OSPF_VERTEX));
1270
1271 /* Free SPF vertices, but not the list. List has ospf_vertex_free
1272 * as deconstructor.
1273 */
1274 list_delete_all_node(&vertex_list);
1275 }
1276
1277 /* Timer for SPF calculation. */
1278 static int ospf_spf_calculate_timer(struct thread *thread)
1279 {
1280 struct ospf *ospf = THREAD_ARG(thread);
1281 struct route_table *new_table, *new_rtrs;
1282 struct ospf_area *area;
1283 struct listnode *node, *nnode;
1284 struct timeval start_time, spf_start_time;
1285 int areas_processed = 0;
1286 unsigned long ia_time, prune_time, rt_time;
1287 unsigned long abr_time, total_spf_time, spf_time;
1288 char rbuf[32]; /* reason_buf */
1289
1290 if (IS_DEBUG_OSPF_EVENT)
1291 zlog_debug("SPF: Timer (SPF calculation expire)");
1292
1293 ospf->t_spf_calc = NULL;
1294
1295 monotime(&spf_start_time);
1296 /* Allocate new table tree. */
1297 new_table = route_table_init();
1298 new_rtrs = route_table_init();
1299
1300 ospf_vl_unapprove(ospf);
1301
1302 /* Calculate SPF for each area. */
1303 for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
1304 /* Do backbone last, so as to first discover intra-area paths
1305 * for any back-bone virtual-links
1306 */
1307 if (ospf->backbone && ospf->backbone == area)
1308 continue;
1309
1310 ospf_spf_calculate(area, new_table, new_rtrs);
1311 areas_processed++;
1312 }
1313
1314 /* SPF for backbone, if required */
1315 if (ospf->backbone) {
1316 ospf_spf_calculate(ospf->backbone, new_table, new_rtrs);
1317 areas_processed++;
1318 }
1319
1320 spf_time = monotime_since(&spf_start_time, NULL);
1321
1322 ospf_vl_shut_unapproved(ospf);
1323
1324 monotime(&start_time);
1325 ospf_ia_routing(ospf, new_table, new_rtrs);
1326 ia_time = monotime_since(&start_time, NULL);
1327
1328 monotime(&start_time);
1329 ospf_prune_unreachable_networks(new_table);
1330 ospf_prune_unreachable_routers(new_rtrs);
1331 prune_time = monotime_since(&start_time, NULL);
1332
1333 /* AS-external-LSA calculation should not be performed here. */
1334
1335 /* If new Router Route is installed,
1336 then schedule re-calculate External routes. */
1337 if (1)
1338 ospf_ase_calculate_schedule(ospf);
1339
1340 ospf_ase_calculate_timer_add(ospf);
1341
1342 /* Update routing table. */
1343 monotime(&start_time);
1344 ospf_route_install(ospf, new_table);
1345 rt_time = monotime_since(&start_time, NULL);
1346
1347 /* Update ABR/ASBR routing table */
1348 if (ospf->old_rtrs) {
1349 /* old_rtrs's node holds linked list of ospf_route. --kunihiro.
1350 */
1351 /* ospf_route_delete (ospf->old_rtrs); */
1352 ospf_rtrs_free(ospf->old_rtrs);
1353 }
1354
1355 ospf->old_rtrs = ospf->new_rtrs;
1356 ospf->new_rtrs = new_rtrs;
1357
1358 monotime(&start_time);
1359 if (IS_OSPF_ABR(ospf))
1360 ospf_abr_task(ospf);
1361 abr_time = monotime_since(&start_time, NULL);
1362
1363 total_spf_time =
1364 monotime_since(&spf_start_time, &ospf->ts_spf_duration);
1365
1366 rbuf[0] = '\0';
1367 if (spf_reason_flags) {
1368 if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL)
1369 strncat(rbuf, "R, ", sizeof(rbuf) - strlen(rbuf) - 1);
1370 if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL)
1371 strncat(rbuf, "N, ", sizeof(rbuf) - strlen(rbuf) - 1);
1372 if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL)
1373 strncat(rbuf, "S, ", sizeof(rbuf) - strlen(rbuf) - 1);
1374 if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL)
1375 strncat(rbuf, "AS, ", sizeof(rbuf) - strlen(rbuf) - 1);
1376 if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE)
1377 strncat(rbuf, "ABR, ", sizeof(rbuf) - strlen(rbuf) - 1);
1378 if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE)
1379 strncat(rbuf, "ASBR, ",
1380 sizeof(rbuf) - strlen(rbuf) - 1);
1381 if (spf_reason_flags & SPF_FLAG_MAXAGE)
1382 strncat(rbuf, "M, ", sizeof(rbuf) - strlen(rbuf) - 1);
1383
1384 size_t rbuflen = strlen(rbuf);
1385 if (rbuflen >= 2)
1386 rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
1387 else
1388 rbuf[0] = '\0';
1389 }
1390
1391 if (IS_DEBUG_OSPF_EVENT) {
1392 zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
1393 zlog_info("\t SPF Time: %ld", spf_time);
1394 zlog_info("\t InterArea: %ld", ia_time);
1395 zlog_info("\t Prune: %ld", prune_time);
1396 zlog_info("\tRouteInstall: %ld", rt_time);
1397 if (IS_OSPF_ABR(ospf))
1398 zlog_info("\t ABR: %ld (%d areas)", abr_time,
1399 areas_processed);
1400 zlog_info("Reason(s) for SPF: %s", rbuf);
1401 }
1402
1403 ospf_clear_spf_reason_flags();
1404
1405 return 0;
1406 }
1407
1408 /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
1409 set timer for SPF calc. */
1410 void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
1411 {
1412 unsigned long delay, elapsed, ht;
1413
1414 if (IS_DEBUG_OSPF_EVENT)
1415 zlog_debug("SPF: calculation timer scheduled");
1416
1417 /* OSPF instance does not exist. */
1418 if (ospf == NULL)
1419 return;
1420
1421 ospf_spf_set_reason(reason);
1422
1423 /* SPF calculation timer is already scheduled. */
1424 if (ospf->t_spf_calc) {
1425 if (IS_DEBUG_OSPF_EVENT)
1426 zlog_debug(
1427 "SPF: calculation timer is already scheduled: %p",
1428 (void *)ospf->t_spf_calc);
1429 return;
1430 }
1431
1432 elapsed = monotime_since(&ospf->ts_spf, NULL) / 1000;
1433
1434 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1435
1436 if (ht > ospf->spf_max_holdtime)
1437 ht = ospf->spf_max_holdtime;
1438
1439 /* Get SPF calculation delay time. */
1440 if (elapsed < ht) {
1441 /* Got an event within the hold time of last SPF. We need to
1442 * increase the hold_multiplier, if it's not already at/past
1443 * maximum value, and wasn't already increased..
1444 */
1445 if (ht < ospf->spf_max_holdtime)
1446 ospf->spf_hold_multiplier++;
1447
1448 /* always honour the SPF initial delay */
1449 if ((ht - elapsed) < ospf->spf_delay)
1450 delay = ospf->spf_delay;
1451 else
1452 delay = ht - elapsed;
1453 } else {
1454 /* Event is past required hold-time of last SPF */
1455 delay = ospf->spf_delay;
1456 ospf->spf_hold_multiplier = 1;
1457 }
1458
1459 if (IS_DEBUG_OSPF_EVENT)
1460 zlog_debug("SPF: calculation timer delay = %ld", delay);
1461
1462 zlog_info("SPF: Scheduled in %ld msec", delay);
1463
1464 ospf->t_spf_calc = NULL;
1465 thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay,
1466 &ospf->t_spf_calc);
1467 }