]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_spf.c
Merge pull request #2602 from pacovn/PVS-Studio_element_overflow
[mirror_frr.git] / ospfd / ospf_spf.c
CommitLineData
718e3744 1/* OSPF SPF calculation.
896014f4
DL
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 */
718e3744 20
21#include <zebra.h>
22
cbf3e3eb 23#include "monotime.h"
718e3744 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"
d62a17ae 32#include "sockunion.h" /* for inet_ntop () */
462f20d5 33#include "pqueue.h"
718e3744 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"
cf9b9f77 49#include "ospfd/ospf_sr.h"
718e3744 50
cf744958
DS
51/* Variables to ensure a SPF scheduled log message is printed only once */
52
53static unsigned int spf_reason_flags = 0;
54
d62a17ae 55static void ospf_clear_spf_reason_flags(void)
cf744958 56{
d62a17ae 57 spf_reason_flags = 0;
cf744958
DS
58}
59
d62a17ae 60static void ospf_spf_set_reason(ospf_spf_reason_t reason)
cf744958 61{
d62a17ae 62 spf_reason_flags |= 1 << reason;
cf744958
DS
63}
64
d62a17ae 65static void ospf_vertex_free(void *);
9c27ef9b
PJ
66/* List of allocated vertices, to simplify cleanup of SPF.
67 * Not thread-safe obviously. If it ever needs to be, it'd have to be
68 * dynamically allocated at begin of ospf_spf_calculate
69 */
d62a17ae 70static struct list vertex_list = {.del = ospf_vertex_free};
6b0655a2 71
462f20d5 72/* Heap related functions, for the managment of the candidates, to
73 * be used with pqueue. */
d62a17ae 74static int cmp(void *node1, void *node2)
462f20d5 75{
d62a17ae 76 struct vertex *v1 = (struct vertex *)node1;
77 struct vertex *v2 = (struct vertex *)node2;
78 if (v1 != NULL && v2 != NULL) {
79 /* network vertices must be chosen before router vertices of
80 * same
81 * cost in order to find all shortest paths
82 */
83 if (((v1->distance - v2->distance) == 0)
84 && (v1->type != v2->type)) {
85 switch (v1->type) {
86 case OSPF_VERTEX_NETWORK:
87 return -1;
88 case OSPF_VERTEX_ROUTER:
89 return 1;
90 }
91 } else
92 return (v1->distance - v2->distance);
93 }
94 return 0;
462f20d5 95}
96
d62a17ae 97static void update_stat(void *node, int position)
462f20d5 98{
d62a17ae 99 struct vertex *v = node;
eb3da6df 100
d62a17ae 101 /* Set the status of the vertex, when its position changes. */
102 *(v->stat) = position;
462f20d5 103}
6b0655a2 104
d62a17ae 105static struct vertex_nexthop *vertex_nexthop_new(void)
718e3744 106{
d62a17ae 107 return XCALLOC(MTYPE_OSPF_NEXTHOP, sizeof(struct vertex_nexthop));
718e3744 108}
109
d62a17ae 110static void vertex_nexthop_free(struct vertex_nexthop *nh)
718e3744 111{
d62a17ae 112 XFREE(MTYPE_OSPF_NEXTHOP, nh);
718e3744 113}
114
eb3da6df 115/* Free the canonical nexthop objects for an area, ie the nexthop objects
9c27ef9b
PJ
116 * attached to the first-hop router vertices, and any intervening network
117 * vertices.
eb3da6df 118 */
d62a17ae 119static void ospf_canonical_nexthops_free(struct vertex *root)
718e3744 120{
d62a17ae 121 struct listnode *node, *nnode;
122 struct vertex *child;
123
124 for (ALL_LIST_ELEMENTS(root->children, node, nnode, child)) {
125 struct listnode *n2, *nn2;
126 struct vertex_parent *vp;
127
128 /* router vertices through an attached network each
129 * have a distinct (canonical / not inherited) nexthop
130 * which must be freed.
131 *
132 * A network vertex can only have router vertices as its
133 * children, so only one level of recursion is possible.
134 */
135 if (child->type == OSPF_VERTEX_NETWORK)
136 ospf_canonical_nexthops_free(child);
137
138 /* Free child nexthops pointing back to this root vertex */
139 for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp))
cd4af525 140 if (vp->parent == root && vp->nexthop) {
d62a17ae 141 vertex_nexthop_free(vp->nexthop);
cd4af525
CS
142 vp->nexthop = NULL;
143 }
d62a17ae 144 }
145}
6b0655a2 146
9c27ef9b
PJ
147/* TODO: Parent list should be excised, in favour of maintaining only
148 * vertex_nexthop, with refcounts.
149 */
d62a17ae 150static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
151 struct vertex_nexthop *hop)
eb3da6df 152{
d62a17ae 153 struct vertex_parent *new;
154
155 new = XMALLOC(MTYPE_OSPF_VERTEX_PARENT, sizeof(struct vertex_parent));
156
157 if (new == NULL)
158 return NULL;
159
160 new->parent = v;
161 new->backlink = backlink;
162 new->nexthop = hop;
163 return new;
718e3744 164}
0c0f9cd5 165
d62a17ae 166static void vertex_parent_free(void *p)
eb3da6df 167{
d62a17ae 168 XFREE(MTYPE_OSPF_VERTEX_PARENT, p);
eb3da6df 169}
6b0655a2 170
d62a17ae 171static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
718e3744 172{
d62a17ae 173 struct vertex *new;
174
175 new = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex));
176
177 new->flags = 0;
178 new->stat = &(lsa->stat);
179 new->type = lsa->data->type;
180 new->id = lsa->data->id;
181 new->lsa = lsa->data;
182 new->children = list_new();
183 new->parents = list_new();
184 new->parents->del = vertex_parent_free;
185
186 listnode_add(&vertex_list, new);
187
188 if (IS_DEBUG_OSPF_EVENT)
189 zlog_debug("%s: Created %s vertex %s", __func__,
190 new->type == OSPF_VERTEX_ROUTER ? "Router"
191 : "Network",
192 inet_ntoa(new->lsa->id));
193 return new;
718e3744 194}
195
d62a17ae 196static void ospf_vertex_free(void *data)
718e3744 197{
d62a17ae 198 struct vertex *v = data;
199
200 if (IS_DEBUG_OSPF_EVENT)
201 zlog_debug("%s: Free %s vertex %s", __func__,
202 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
203 inet_ntoa(v->lsa->id));
204
205 /* There should be no parents potentially holding references to this
206 * vertex
207 * Children however may still be there, but presumably referenced by
208 * other
209 * vertices
210 */
211 // assert (listcount (v->parents) == 0);
212
213 if (v->children)
affe9e99 214 list_delete_and_null(&v->children);
d62a17ae 215
216 if (v->parents)
affe9e99 217 list_delete_and_null(&v->parents);
d62a17ae 218
219 v->lsa = NULL;
220
221 XFREE(MTYPE_OSPF_VERTEX, v);
718e3744 222}
223
d62a17ae 224static void ospf_vertex_dump(const char *msg, struct vertex *v,
225 int print_parents, int print_children)
630e4807 226{
d62a17ae 227 if (!IS_DEBUG_OSPF_EVENT)
228 return;
229
230 zlog_debug("%s %s vertex %s distance %u flags %u", msg,
231 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
232 inet_ntoa(v->lsa->id), v->distance, (unsigned int)v->flags);
233
234 if (print_parents) {
235 struct listnode *node;
236 struct vertex_parent *vp;
237
238 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
239 char buf1[BUFSIZ];
240
241 if (vp) {
242 zlog_debug(
243 "parent %s backlink %d nexthop %s interface %s",
244 inet_ntoa(vp->parent->lsa->id),
245 vp->backlink,
246 inet_ntop(AF_INET, &vp->nexthop->router,
247 buf1, BUFSIZ),
248 vp->nexthop->oi
249 ? IF_NAME(vp->nexthop->oi)
250 : "NULL");
251 }
252 }
253 }
254
255 if (print_children) {
256 struct listnode *cnode;
257 struct vertex *cv;
258
259 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, cv))
260 ospf_vertex_dump(" child:", cv, 0, 0);
630e4807 261 }
630e4807 262}
263
264
265/* Add a vertex to the list of children in each of its parents. */
d62a17ae 266static void ospf_vertex_add_parent(struct vertex *v)
718e3744 267{
d62a17ae 268 struct vertex_parent *vp;
269 struct listnode *node;
270
271 assert(v && v->parents);
272
273 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
274 assert(vp->parent && vp->parent->children);
275
276 /* No need to add two links from the same parent. */
277 if (listnode_lookup(vp->parent->children, v) == NULL)
278 listnode_add(vp->parent->children, v);
279 }
718e3744 280}
6b0655a2 281
d62a17ae 282static void ospf_spf_init(struct ospf_area *area)
718e3744 283{
d62a17ae 284 struct vertex *v;
285
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;
718e3744 294}
295
d355bfa7 296/* return index of link back to V from W, or -1 if no link found */
d62a17ae 297static int ospf_lsa_has_link(struct lsa_header *w, struct lsa_header *v)
718e3744 298{
d62a17ae 299 unsigned int i, length;
300 struct router_lsa *rl;
301 struct network_lsa *nl;
302
303 /* In case of W is Network LSA. */
304 if (w->type == OSPF_NETWORK_LSA) {
305 if (v->type == OSPF_NETWORK_LSA)
306 return -1;
307
308 nl = (struct network_lsa *)w;
309 length = (ntohs(w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
310
311 for (i = 0; i < length; i++)
312 if (IPV4_ADDR_SAME(&nl->routers[i], &v->id))
313 return i;
314 return -1;
315 }
316
317 /* In case of W is Router LSA. */
318 if (w->type == OSPF_ROUTER_LSA) {
319 rl = (struct router_lsa *)w;
320
321 length = ntohs(w->length);
322
323 for (i = 0; i < ntohs(rl->links)
324 && length >= sizeof(struct router_lsa);
325 i++, length -= 12) {
326 switch (rl->link[i].type) {
327 case LSA_LINK_TYPE_POINTOPOINT:
328 case LSA_LINK_TYPE_VIRTUALLINK:
329 /* Router LSA ID. */
330 if (v->type == OSPF_ROUTER_LSA
331 && IPV4_ADDR_SAME(&rl->link[i].link_id,
332 &v->id)) {
333 return i;
334 }
335 break;
336 case LSA_LINK_TYPE_TRANSIT:
337 /* Network LSA ID. */
338 if (v->type == OSPF_NETWORK_LSA
339 && IPV4_ADDR_SAME(&rl->link[i].link_id,
340 &v->id)) {
341 return i;
342 }
343 break;
344 case LSA_LINK_TYPE_STUB:
345 /* Stub can't lead anywhere, carry on */
346 continue;
347 default:
348 break;
349 }
350 }
351 }
352 return -1;
718e3744 353}
354
630e4807 355/* Find the next link after prev_link from v to w. If prev_link is
356 * NULL, return the first link from v to w. Ignore stub and virtual links;
357 * these link types will never be returned.
358 */
4dadc291 359static struct router_lsa_link *
d62a17ae 360ospf_get_next_link(struct vertex *v, struct vertex *w,
361 struct router_lsa_link *prev_link)
718e3744 362{
d7c0a89a
QY
363 uint8_t *p;
364 uint8_t *lim;
365 uint8_t lsa_type = LSA_LINK_TYPE_TRANSIT;
d62a17ae 366 struct router_lsa_link *l;
367
368 if (w->type == OSPF_VERTEX_ROUTER)
369 lsa_type = LSA_LINK_TYPE_POINTOPOINT;
370
371 if (prev_link == NULL)
d7c0a89a 372 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
d62a17ae 373 else {
d7c0a89a 374 p = (uint8_t *)prev_link;
d62a17ae 375 p += (OSPF_ROUTER_LSA_LINK_SIZE
376 + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
377 }
0c0f9cd5 378
d7c0a89a 379 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
718e3744 380
d62a17ae 381 while (p < lim) {
382 l = (struct router_lsa_link *)p;
718e3744 383
d62a17ae 384 p += (OSPF_ROUTER_LSA_LINK_SIZE
385 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
718e3744 386
d62a17ae 387 if (l->m[0].type != lsa_type)
388 continue;
718e3744 389
d62a17ae 390 if (IPV4_ADDR_SAME(&l->link_id, &w->id))
391 return l;
392 }
718e3744 393
d62a17ae 394 return NULL;
718e3744 395}
396
d62a17ae 397static void ospf_spf_flush_parents(struct vertex *w)
bc20c1a4 398{
d62a17ae 399 struct vertex_parent *vp;
400 struct listnode *ln, *nn;
401
402 /* delete the existing nexthops */
403 for (ALL_LIST_ELEMENTS(w->parents, ln, nn, vp)) {
404 list_delete_node(w->parents, ln);
405 vertex_parent_free(vp);
406 }
bc20c1a4
PJ
407}
408
d62a17ae 409/*
75ee0b8e 410 * Consider supplied next-hop for inclusion to the supplied list of
d62a17ae 411 * equal-cost next-hops, adjust list as neccessary.
bf9392c6 412 */
d62a17ae 413static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
414 struct vertex_nexthop *newhop,
415 unsigned int distance)
bf9392c6 416{
d62a17ae 417 struct vertex_parent *vp, *wp;
418 struct listnode *node;
419
420 /* we must have a newhop, and a distance */
421 assert(v && w && newhop);
422 assert(distance);
423
424 /* IFF w has already been assigned a distance, then we shouldn't get
425 * here
426 * unless callers have determined V(l)->W is shortest / equal-shortest
427 * path (0 is a special case distance (no distance yet assigned)).
428 */
429 if (w->distance)
430 assert(distance <= w->distance);
431 else
432 w->distance = distance;
433
434 if (IS_DEBUG_OSPF_EVENT) {
435 char buf[2][INET_ADDRSTRLEN];
436 zlog_debug(
437 "%s: Adding %s as parent of %s", __func__,
438 inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])),
439 inet_ntop(AF_INET, &w->lsa->id, buf[1],
440 sizeof(buf[1])));
441 }
442
443 /* Adding parent for a new, better path: flush existing parents from W.
444 */
445 if (distance < w->distance) {
446 if (IS_DEBUG_OSPF_EVENT)
447 zlog_debug(
448 "%s: distance %d better than %d, flushing existing parents",
449 __func__, distance, w->distance);
450 ospf_spf_flush_parents(w);
451 w->distance = distance;
452 }
453
454 /* new parent is <= existing parents, add it to parent list (if nexthop
455 * not on parent list)
456 */
457 for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) {
458 if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) {
459 if (IS_DEBUG_OSPF_EVENT)
460 zlog_debug(
461 "%s: ... nexthop already on parent list, skipping add",
462 __func__);
463 return;
464 }
465 }
7b92589c 466
d62a17ae 467 vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop);
468 listnode_add(w->parents, vp);
0c0f9cd5 469
d62a17ae 470 return;
eb3da6df 471}
472
630e4807 473/* 16.1.1. Calculate nexthop from root through V (parent) to
bd34fb34 474 * vertex W (destination), with given distance from root->W.
eb3da6df 475 *
476 * The link must be supplied if V is the root vertex. In all other cases
477 * it may be NULL.
bd34fb34
PJ
478 *
479 * Note that this function may fail, hence the state of the destination
480 * vertex, W, should /not/ be modified in a dependent manner until
481 * this function returns. This function will update the W vertex with the
482 * provided distance as appropriate.
630e4807 483 */
d62a17ae 484static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
485 struct vertex *v, struct vertex *w,
486 struct router_lsa_link *l,
487 unsigned int distance, int lsa_pos)
718e3744 488{
d62a17ae 489 struct listnode *node, *nnode;
490 struct vertex_nexthop *nh;
491 struct vertex_parent *vp;
492 struct ospf_interface *oi = NULL;
493 unsigned int added = 0;
494 char buf1[BUFSIZ];
495 char buf2[BUFSIZ];
496
497 if (IS_DEBUG_OSPF_EVENT) {
498 zlog_debug("ospf_nexthop_calculation(): Start");
499 ospf_vertex_dump("V (parent):", v, 1, 1);
500 ospf_vertex_dump("W (dest) :", w, 1, 1);
501 zlog_debug("V->W distance: %d", distance);
c81ee5c9
JT
502 }
503
d62a17ae 504 if (v == area->spf) {
505 /* 16.1.1 para 4. In the first case, the parent vertex (V) is
506 the
507 root (the calculating router itself). This means that the
508 destination is either a directly connected network or
509 directly
510 connected router. The outgoing interface in this case is
511 simply
512 the OSPF interface connecting to the destination
513 network/router.
514 */
515
516 /* we *must* be supplied with the link data */
517 assert(l != NULL);
518 oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos);
519 if (!oi) {
520 zlog_debug(
521 "%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s",
522 __func__, lsa_pos,
523 inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
524 inet_ntop(AF_INET, &l->link_data, buf2,
525 BUFSIZ));
526 return 0;
c81ee5c9 527 }
c81ee5c9 528
d62a17ae 529 if (IS_DEBUG_OSPF_EVENT) {
530 zlog_debug(
531 "%s: considering link:%s "
532 "type:%d link_id:%s link_data:%s",
533 __func__, oi->ifp->name, l->m[0].type,
534 inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ),
535 inet_ntop(AF_INET, &l->link_data, buf2,
536 BUFSIZ));
537 }
c81ee5c9 538
d62a17ae 539 if (w->type == OSPF_VERTEX_ROUTER) {
540 /* l is a link from v to w
541 * l2 will be link from w to v
542 */
543 struct router_lsa_link *l2 = NULL;
544
545 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) {
546 struct in_addr nexthop = {.s_addr = 0};
547
548 /* If the destination is a router which connects
549 to
550 the calculating router via a
551 Point-to-MultiPoint
552 network, the destination's next hop IP
553 address(es)
554 can be determined by examining the
555 destination's
556 router-LSA: each link pointing back to the
557 calculating router and having a Link Data
558 field
559 belonging to the Point-to-MultiPoint network
560 provides an IP address of the next hop
561 router.
562
563 At this point l is a link from V to W, and V
564 is the
565 root ("us"). If it is a point-to-multipoint
566 interface,
567 then look through the links in the opposite
568 direction (W to V).
569 If any of them have an address that lands
570 within the
571 subnet declared by the PtMP link, then that
572 link
573 is a constituent of the PtMP link, and its
574 address is
575 a nexthop address for V.
576 */
577 if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
578 /* Having nexthop = 0 is tempting, but
579 NOT acceptable.
580 It breaks AS-External routes with a
581 forwarding address,
582 since
583 ospf_ase_complete_direct_routes()
584 will mistakenly
585 assume we've reached the last hop and
586 should place the
587 forwarding address as nexthop.
588 Also, users may configure
589 multi-access links in p2p mode,
590 so we need the IP to ARP the nexthop.
591 */
592 struct ospf_neighbor *nbr_w;
593
594 nbr_w = ospf_nbr_lookup_by_routerid(
595 oi->nbrs, &l->link_id);
596 if (nbr_w != NULL) {
597 added = 1;
598 nexthop = nbr_w->src;
599 }
600 } else if (oi->type
601 == OSPF_IFTYPE_POINTOMULTIPOINT) {
602 struct prefix_ipv4 la;
603
604 la.family = AF_INET;
605 la.prefixlen = oi->address->prefixlen;
606
607 /* V links to W on PtMP interface
608 - find the interface address on W */
609 while ((l2 = ospf_get_next_link(w, v,
610 l2))) {
611 la.prefix = l2->link_data;
612
613 if (prefix_cmp((struct prefix
614 *)&la,
615 oi->address)
616 != 0)
617 continue;
618 /* link_data is on our PtMP
619 * network */
620 added = 1;
621 nexthop = l2->link_data;
622 break;
623 }
624 }
625
626 if (added) {
627 /* found all necessary info to build
628 * nexthop */
629 nh = vertex_nexthop_new();
630 nh->oi = oi;
631 nh->router = nexthop;
632 ospf_spf_add_parent(v, w, nh, distance);
633 return 1;
634 } else
635 zlog_info(
636 "%s: could not determine nexthop for link %s",
637 __func__, oi->ifp->name);
638 } /* end point-to-point link from V to W */
639 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) {
640 struct ospf_vl_data *vl_data;
641
642 /* VLink implementation limitations:
643 * a) vl_data can only reference one nexthop, so
644 * no ECMP
645 * to backbone through VLinks. Though
646 * transit-area
647 * summaries may be considered, and those can
648 * be ECMP.
649 * b) We can only use /one/ VLink, even if
650 * multiple ones
651 * exist this router through multiple
652 * transit-areas.
653 */
654 vl_data = ospf_vl_lookup(area->ospf, NULL,
655 l->link_id);
656
657 if (vl_data
658 && CHECK_FLAG(vl_data->flags,
659 OSPF_VL_FLAG_APPROVED)) {
660 nh = vertex_nexthop_new();
661 nh->oi = vl_data->nexthop.oi;
662 nh->router = vl_data->nexthop.router;
663 ospf_spf_add_parent(v, w, nh, distance);
664 return 1;
665 } else
666 zlog_info(
667 "ospf_nexthop_calculation(): "
668 "vl_data for VL link not found");
669 } /* end virtual-link from V to W */
670 return 0;
671 } /* end W is a Router vertex */
672 else {
673 assert(w->type == OSPF_VERTEX_NETWORK);
674
675 nh = vertex_nexthop_new();
676 nh->oi = oi;
677 nh->router.s_addr = 0; /* Nexthop not required */
678 ospf_spf_add_parent(v, w, nh, distance);
679 return 1;
680 }
681 } /* end V is the root */
682 /* Check if W's parent is a network connected to root. */
683 else if (v->type == OSPF_VERTEX_NETWORK) {
684 /* See if any of V's parents are the root. */
685 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
686 if (vp->parent == area->spf) /* connects to root? */
687 {
688 /* 16.1.1 para 5. ...the parent vertex is a
689 * network that
690 * directly connects the calculating router to
691 * the destination
692 * router. The list of next hops is then
693 * determined by
694 * examining the destination's router-LSA...
695 */
696
697 assert(w->type == OSPF_VERTEX_ROUTER);
698 while ((l = ospf_get_next_link(w, v, l))) {
699 /* ...For each link in the router-LSA
700 * that points back to the
701 * parent network, the link's Link Data
702 * field provides the IP
703 * address of a next hop router. The
704 * outgoing interface to
705 * use can then be derived from the next
706 * hop IP address (or
707 * it can be inherited from the parent
708 * network).
709 */
710 nh = vertex_nexthop_new();
711 nh->oi = vp->nexthop->oi;
712 nh->router = l->link_data;
713 added = 1;
714 ospf_spf_add_parent(v, w, nh, distance);
715 }
716 /* Note lack of return is deliberate. See next
717 * comment. */
718 }
c81ee5c9 719 }
d62a17ae 720 /* NB: This code is non-trivial.
721 *
722 * E.g. it is not enough to know that V connects to the root. It
723 * is
724 * also important that the while above, looping through all
725 * links from
726 * W->V found at least one link, so that we know there is
727 * bi-directional connectivity between V and W (which need not
728 * be the
729 * case, e.g. when OSPF has not yet converged fully).
730 * Otherwise, if
731 * we /always/ return here, without having checked that
732 * root->V->-W
733 * actually resulted in a valid nexthop being created, then we
734 * we will
735 * prevent SPF from finding/using higher cost paths.
736 *
737 * It is important, if root->V->W has not been added, that we
738 * continue
739 * through to the intervening-router nexthop code below. So as
740 * to
741 * ensure other paths to V may be used. This avoids unnecessary
742 * blackholes while OSPF is convergening.
743 *
744 * I.e. we may have arrived at this function, examining V -> W,
745 * via
746 * workable paths other than root -> V, and it's important to
747 * avoid
748 * getting "confused" by non-working root->V->W path - it's
749 * important
750 * to *not* lose the working non-root paths, just because of a
751 * non-viable root->V->W.
752 *
753 * See also bug #330 (required reading!), and:
754 *
755 * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes
756 */
757 if (added)
758 return added;
759 }
c81ee5c9 760
d62a17ae 761 /* 16.1.1 para 4. If there is at least one intervening router in the
762 * current shortest path between the destination and the root, the
763 * destination simply inherits the set of next hops from the
764 * parent.
765 */
766 if (IS_DEBUG_OSPF_EVENT)
767 zlog_debug("%s: Intervening routers, adding parent(s)",
768 __func__);
769
770 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
771 added = 1;
772 ospf_spf_add_parent(v, w, vp->nexthop, distance);
773 }
c81ee5c9 774
d62a17ae 775 return added;
718e3744 776}
777
630e4807 778/* RFC2328 Section 16.1 (2).
779 * v is on the SPF tree. Examine the links in v's LSA. Update the list
780 * of candidates with any vertices not already on the list. If a lower-cost
781 * path is found to a vertex already on the candidate list, store the new cost.
782 */
b5a8894d 783static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
996c9314 784 struct ospf_area *area, struct pqueue *candidate)
718e3744 785{
d62a17ae 786 struct ospf_lsa *w_lsa = NULL;
d7c0a89a
QY
787 uint8_t *p;
788 uint8_t *lim;
d62a17ae 789 struct router_lsa_link *l = NULL;
790 struct in_addr *r;
791 int type = 0, lsa_pos = -1, lsa_pos_next = 0;
792
793 /* If this is a router-LSA, and bit V of the router-LSA (see Section
794 A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
795 if (v->type == OSPF_VERTEX_ROUTER) {
796 if (IS_ROUTER_LSA_VIRTUAL((struct router_lsa *)v->lsa))
797 area->transit = OSPF_TRANSIT_TRUE;
798 }
718e3744 799
d62a17ae 800 if (IS_DEBUG_OSPF_EVENT)
801 zlog_debug("%s: Next vertex of %s vertex %s", __func__,
802 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
803 inet_ntoa(v->lsa->id));
804
d7c0a89a
QY
805 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
806 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
d62a17ae 807
808 while (p < lim) {
809 struct vertex *w;
810 unsigned int distance;
811
812 /* In case of V is Router-LSA. */
813 if (v->lsa->type == OSPF_ROUTER_LSA) {
814 l = (struct router_lsa_link *)p;
815
816 lsa_pos = lsa_pos_next; /* LSA link position */
817 lsa_pos_next++;
818 p += (OSPF_ROUTER_LSA_LINK_SIZE
819 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
820
821 /* (a) If this is a link to a stub network, examine the
822 next
823 link in V's LSA. Links to stub networks will be
824 considered in the second stage of the shortest path
825 calculation. */
826 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
827 continue;
828
829 /* (b) Otherwise, W is a transit vertex (router or
830 transit
831 network). Look up the vertex W's LSA (router-LSA or
832 network-LSA) in Area A's link state database. */
833 switch (type) {
834 case LSA_LINK_TYPE_POINTOPOINT:
835 case LSA_LINK_TYPE_VIRTUALLINK:
836 if (type == LSA_LINK_TYPE_VIRTUALLINK) {
837 if (IS_DEBUG_OSPF_EVENT)
838 zlog_debug(
839 "looking up LSA through VL: %s",
840 inet_ntoa(l->link_id));
841 }
842
b5a8894d
CS
843 w_lsa = ospf_lsa_lookup(ospf, area,
844 OSPF_ROUTER_LSA,
d62a17ae 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 }
718e3744 882
d62a17ae 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 }
718e3744 891
d62a17ae 892 if (IS_LSA_MAXAGE(w_lsa)) {
893 if (IS_DEBUG_OSPF_EVENT)
894 zlog_debug("LSA is MaxAge");
895 continue;
896 }
718e3744 897
d62a17ae 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 }
718e3744 903
d62a17ae 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 }
718e3744 911
d62a17ae 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}
718e3744 975
d62a17ae 976static 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));
462f20d5 992 }
718e3744 993
d62a17ae 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 }
718e3744 1002
d62a17ae 1003 i++;
718e3744 1004
d62a17ae 1005 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v))
1006 ospf_spf_dump(v, i);
718e3744 1007}
1008
1009/* Second stage of SPF calculation. */
d62a17ae 1010static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
1011 struct route_table *rt, int parent_is_root)
718e3744 1012{
d62a17ae 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) {
d7c0a89a
QY
1020 uint8_t *p;
1021 uint8_t *lim;
d62a17ae 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));
d7c0a89a
QY
1037 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
1038 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
d62a17ae 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 }
718e3744 1052
d62a17ae 1053 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1,
1054 1);
718e3744 1055
d62a17ae 1056 for (ALL_LIST_ELEMENTS(v->children, cnode, cnnode, child)) {
1057 if (CHECK_FLAG(child->flags, OSPF_VERTEX_PROCESSED))
1058 continue;
718e3744 1059
d62a17ae 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 }
718e3744 1073}
1074
d62a17ae 1075void ospf_rtrs_free(struct route_table *rtrs)
718e3744 1076{
d62a17ae 1077 struct route_node *rn;
1078 struct list *or_list;
1079 struct ospf_route * or ;
1080 struct listnode *node, *nnode;
718e3744 1081
d62a17ae 1082 if (IS_DEBUG_OSPF_EVENT)
1083 zlog_debug("Route: Router Routing Table free");
718e3744 1084
d62a17ae 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);
718e3744 1089
affe9e99 1090 list_delete_and_null(&or_list);
718e3744 1091
d62a17ae 1092 /* Unlock the node. */
1093 rn->info = NULL;
1094 route_unlock_node(rn);
1095 }
1096 route_table_finish(rtrs);
718e3744 1097}
1098
075e12f5 1099#if 0
4dadc291 1100static void
718e3744 1101ospf_rtrs_print (struct route_table *rtrs)
1102{
1103 struct route_node *rn;
52dc7ee6 1104 struct list *or_list;
1105 struct listnode *ln;
1106 struct listnode *pnode;
718e3744 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)
2a42e285 1113 zlog_debug ("ospf_rtrs_print() start");
718e3744 1114
1115 for (rn = route_top (rtrs); rn; rn = route_next (rn))
1116 if ((or_list = rn->info) != NULL)
1eb8ef25 1117 for (ALL_LIST_ELEMENTS_RO (or_list, ln, or))
718e3744 1118 {
718e3744 1119 switch (or->path_type)
1120 {
1121 case OSPF_PATH_INTRA_AREA:
0c0f9cd5 1122 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1123 zlog_debug ("%s [%d] area: %s",
0c0f9cd5 1124 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1125 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1126 buf2, BUFSIZ));
718e3744 1127 break;
1128 case OSPF_PATH_INTER_AREA:
0c0f9cd5 1129 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1130 zlog_debug ("%s IA [%d] area: %s",
0c0f9cd5 1131 inet_ntop (AF_INET, &or->id, buf1, BUFSIZ),
1132 or->cost, inet_ntop (AF_INET, &or->u.std.area_id,
1133 buf2, BUFSIZ));
718e3744 1134 break;
1135 default:
1136 break;
1137 }
1138
1eb8ef25 1139 for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path))
718e3744 1140 {
718e3744 1141 if (path->nexthop.s_addr == 0)
0c0f9cd5 1142 {
1143 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1144 zlog_debug (" directly attached to %s\r\n",
baaea325 1145 ifindex2ifname (path->ifindex), VRF_DEFAULT);
0c0f9cd5 1146 }
1147 else
1148 {
1149 if (IS_DEBUG_OSPF_EVENT)
2a42e285 1150 zlog_debug (" via %s, %s\r\n",
a8ba847f 1151 inet_ntoa (path->nexthop),
baaea325 1152 ifindex2ifname (path->ifindex), VRF_DEFAULT);
0c0f9cd5 1153 }
718e3744 1154 }
1155 }
1156
2a42e285 1157 zlog_debug ("ospf_rtrs_print() end");
718e3744 1158}
075e12f5 1159#endif
718e3744 1160
1161/* Calculating the shortest-path tree for an area. */
b5a8894d 1162static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
d62a17ae 1163 struct route_table *new_table,
1164 struct route_table *new_rtrs)
718e3744 1165{
d62a17ae 1166 struct pqueue *candidate;
1167 struct vertex *v;
718e3744 1168
d62a17ae 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 }
718e3744 1174
d62a17ae 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 }
718e3744 1185
d62a17ae 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). */
b5a8894d 1212 ospf_spf_next(v, ospf, area, candidate);
d62a17ae 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 }
cf744958 1247
d62a17ae 1248 /* Second stage of SPF calculation procedure's */
1249 ospf_spf_process_stubs(area, area->spf, new_table, 0);
cf744958 1250
d62a17ae 1251 /* Free candidate queue. */
1252 pqueue_delete(candidate);
718e3744 1253
d62a17ae 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);
718e3744 1260
d62a17ae 1261 /* Increment SPF Calculation Counter. */
1262 area->spf_calculation++;
1263
1264 monotime(&area->ospf->ts_spf);
1265 area->ts_spf = area->ospf->ts_spf;
cf744958 1266
d62a17ae 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);
718e3744 1275}
6b0655a2 1276
718e3744 1277/* Timer for SPF calculation. */
d62a17ae 1278static int ospf_spf_calculate_timer(struct thread *thread)
718e3744 1279{
d62a17ae 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;
cf744958 1309
b5a8894d 1310 ospf_spf_calculate(ospf, area, new_table, new_rtrs);
d62a17ae 1311 areas_processed++;
1312 }
1313
1314 /* SPF for backbone, if required */
1315 if (ospf->backbone) {
b5a8894d 1316 ospf_spf_calculate(ospf, ospf->backbone, new_table, new_rtrs);
d62a17ae 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
b5a8894d 1342 if (IS_DEBUG_OSPF_EVENT)
996c9314
LB
1343 zlog_debug(
1344 "%s: ospf install new route, vrf %s id %u new_table count %lu",
1345 __PRETTY_FUNCTION__, ospf_vrf_id_to_name(ospf->vrf_id),
1346 ospf->vrf_id, new_table->count);
d62a17ae 1347 /* Update routing table. */
1348 monotime(&start_time);
1349 ospf_route_install(ospf, new_table);
1350 rt_time = monotime_since(&start_time, NULL);
1351
1352 /* Update ABR/ASBR routing table */
1353 if (ospf->old_rtrs) {
1354 /* old_rtrs's node holds linked list of ospf_route. --kunihiro.
1355 */
1356 /* ospf_route_delete (ospf->old_rtrs); */
1357 ospf_rtrs_free(ospf->old_rtrs);
1358 }
1359
1360 ospf->old_rtrs = ospf->new_rtrs;
1361 ospf->new_rtrs = new_rtrs;
1362
1363 monotime(&start_time);
1364 if (IS_OSPF_ABR(ospf))
1365 ospf_abr_task(ospf);
1366 abr_time = monotime_since(&start_time, NULL);
1367
cf9b9f77
OD
1368 /* Schedule Segment Routing update */
1369 ospf_sr_update_timer_add(ospf);
1370
d62a17ae 1371 total_spf_time =
1372 monotime_since(&spf_start_time, &ospf->ts_spf_duration);
1373
1374 rbuf[0] = '\0';
1375 if (spf_reason_flags) {
1376 if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL)
1377 strncat(rbuf, "R, ", sizeof(rbuf) - strlen(rbuf) - 1);
1378 if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL)
1379 strncat(rbuf, "N, ", sizeof(rbuf) - strlen(rbuf) - 1);
1380 if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL)
1381 strncat(rbuf, "S, ", sizeof(rbuf) - strlen(rbuf) - 1);
1382 if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL)
1383 strncat(rbuf, "AS, ", sizeof(rbuf) - strlen(rbuf) - 1);
1384 if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE)
1385 strncat(rbuf, "ABR, ", sizeof(rbuf) - strlen(rbuf) - 1);
1386 if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE)
1387 strncat(rbuf, "ASBR, ",
1388 sizeof(rbuf) - strlen(rbuf) - 1);
1389 if (spf_reason_flags & SPF_FLAG_MAXAGE)
1390 strncat(rbuf, "M, ", sizeof(rbuf) - strlen(rbuf) - 1);
1391
1392 size_t rbuflen = strlen(rbuf);
1393 if (rbuflen >= 2)
1394 rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
1395 else
1396 rbuf[0] = '\0';
1397 }
1398
1399 if (IS_DEBUG_OSPF_EVENT) {
1400 zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
1401 zlog_info("\t SPF Time: %ld", spf_time);
1402 zlog_info("\t InterArea: %ld", ia_time);
1403 zlog_info("\t Prune: %ld", prune_time);
1404 zlog_info("\tRouteInstall: %ld", rt_time);
1405 if (IS_OSPF_ABR(ospf))
1406 zlog_info("\t ABR: %ld (%d areas)", abr_time,
1407 areas_processed);
1408 zlog_info("Reason(s) for SPF: %s", rbuf);
1409 }
1410
1411 ospf_clear_spf_reason_flags();
1412
1413 return 0;
718e3744 1414}
1415
1416/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we
1417 set timer for SPF calc. */
d62a17ae 1418void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
718e3744 1419{
d62a17ae 1420 unsigned long delay, elapsed, ht;
718e3744 1421
d62a17ae 1422 if (IS_DEBUG_OSPF_EVENT)
1423 zlog_debug("SPF: calculation timer scheduled");
1424
1425 /* OSPF instance does not exist. */
1426 if (ospf == NULL)
1427 return;
1428
1429 ospf_spf_set_reason(reason);
1430
1431 /* SPF calculation timer is already scheduled. */
1432 if (ospf->t_spf_calc) {
1433 if (IS_DEBUG_OSPF_EVENT)
1434 zlog_debug(
1435 "SPF: calculation timer is already scheduled: %p",
1436 (void *)ospf->t_spf_calc);
1437 return;
1438 }
1439
1440 elapsed = monotime_since(&ospf->ts_spf, NULL) / 1000;
1441
1442 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1443
1444 if (ht > ospf->spf_max_holdtime)
1445 ht = ospf->spf_max_holdtime;
1446
1447 /* Get SPF calculation delay time. */
1448 if (elapsed < ht) {
1449 /* Got an event within the hold time of last SPF. We need to
1450 * increase the hold_multiplier, if it's not already at/past
1451 * maximum value, and wasn't already increased..
1452 */
1453 if (ht < ospf->spf_max_holdtime)
1454 ospf->spf_hold_multiplier++;
1455
1456 /* always honour the SPF initial delay */
1457 if ((ht - elapsed) < ospf->spf_delay)
1458 delay = ospf->spf_delay;
1459 else
1460 delay = ht - elapsed;
1461 } else {
1462 /* Event is past required hold-time of last SPF */
1463 delay = ospf->spf_delay;
1464 ospf->spf_hold_multiplier = 1;
1465 }
1466
1467 if (IS_DEBUG_OSPF_EVENT)
05ba78e4 1468 zlog_debug("SPF: calculation timer delay = %ld msec", delay);
cf744958 1469
d62a17ae 1470 ospf->t_spf_calc = NULL;
1471 thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay,
1472 &ospf->t_spf_calc);
718e3744 1473}