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