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