]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_spf.c
Merge pull request #8351 from volta-networks/fix_ospf6_abr_examin_summary_check_cost_...
[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 () */
718e3744 33
34#include "ospfd/ospfd.h"
35#include "ospfd/ospf_interface.h"
36#include "ospfd/ospf_ism.h"
37#include "ospfd/ospf_asbr.h"
38#include "ospfd/ospf_lsa.h"
39#include "ospfd/ospf_lsdb.h"
40#include "ospfd/ospf_neighbor.h"
41#include "ospfd/ospf_nsm.h"
42#include "ospfd/ospf_spf.h"
43#include "ospfd/ospf_route.h"
44#include "ospfd/ospf_ia.h"
45#include "ospfd/ospf_ase.h"
46#include "ospfd/ospf_abr.h"
47#include "ospfd/ospf_dump.h"
cf9b9f77 48#include "ospfd/ospf_sr.h"
7fd0729f 49#include "ospfd/ospf_ti_lfa.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
c971918a
DL
56/* dummy vertex to flag "in spftree" */
57static const struct vertex vertex_in_spftree = {};
58#define LSA_SPF_IN_SPFTREE (struct vertex *)&vertex_in_spftree
59#define LSA_SPF_NOT_EXPLORED NULL
60
d62a17ae 61static void ospf_clear_spf_reason_flags(void)
cf744958 62{
d62a17ae 63 spf_reason_flags = 0;
cf744958
DS
64}
65
d62a17ae 66static void ospf_spf_set_reason(ospf_spf_reason_t reason)
cf744958 67{
d62a17ae 68 spf_reason_flags |= 1 << reason;
cf744958
DS
69}
70
d62a17ae 71static void ospf_vertex_free(void *);
6b0655a2 72
5ec5929c
G
73/*
74 * Heap related functions, for the managment of the candidates, to
75 * be used with pqueue.
76 */
c971918a 77static int vertex_cmp(const struct vertex *v1, const struct vertex *v2)
462f20d5 78{
c971918a
DL
79 if (v1->distance != v2->distance)
80 return v1->distance - v2->distance;
81
82 if (v1->type != v2->type) {
83 switch (v1->type) {
84 case OSPF_VERTEX_NETWORK:
85 return -1;
86 case OSPF_VERTEX_ROUTER:
87 return 1;
88 }
d62a17ae 89 }
90 return 0;
462f20d5 91}
960b9a53 92DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp);
462f20d5 93
c971918a 94static void lsdb_clean_stat(struct ospf_lsdb *lsdb)
462f20d5 95{
c971918a
DL
96 struct route_table *table;
97 struct route_node *rn;
98 struct ospf_lsa *lsa;
99 int i;
100
101 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
102 table = lsdb->type[i].db;
103 for (rn = route_top(table); rn; rn = route_next(rn))
104 if ((lsa = (rn->info)) != NULL)
105 lsa->stat = LSA_SPF_NOT_EXPLORED;
106 }
462f20d5 107}
6b0655a2 108
d62a17ae 109static struct vertex_nexthop *vertex_nexthop_new(void)
718e3744 110{
d62a17ae 111 return XCALLOC(MTYPE_OSPF_NEXTHOP, sizeof(struct vertex_nexthop));
718e3744 112}
113
d62a17ae 114static void vertex_nexthop_free(struct vertex_nexthop *nh)
718e3744 115{
d62a17ae 116 XFREE(MTYPE_OSPF_NEXTHOP, nh);
718e3744 117}
118
5ec5929c
G
119/*
120 * Free the canonical nexthop objects for an area, ie the nexthop objects
9c27ef9b
PJ
121 * attached to the first-hop router vertices, and any intervening network
122 * vertices.
eb3da6df 123 */
d62a17ae 124static void ospf_canonical_nexthops_free(struct vertex *root)
718e3744 125{
d62a17ae 126 struct listnode *node, *nnode;
127 struct vertex *child;
128
129 for (ALL_LIST_ELEMENTS(root->children, node, nnode, child)) {
130 struct listnode *n2, *nn2;
131 struct vertex_parent *vp;
132
5ec5929c
G
133 /*
134 * router vertices through an attached network each
d62a17ae 135 * have a distinct (canonical / not inherited) nexthop
136 * which must be freed.
137 *
138 * A network vertex can only have router vertices as its
139 * children, so only one level of recursion is possible.
140 */
141 if (child->type == OSPF_VERTEX_NETWORK)
142 ospf_canonical_nexthops_free(child);
143
144 /* Free child nexthops pointing back to this root vertex */
385a1e07 145 for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp)) {
cd4af525 146 if (vp->parent == root && vp->nexthop) {
d62a17ae 147 vertex_nexthop_free(vp->nexthop);
cd4af525 148 vp->nexthop = NULL;
7fd0729f
G
149 if (vp->local_nexthop) {
150 vertex_nexthop_free(vp->local_nexthop);
151 vp->local_nexthop = NULL;
152 }
cd4af525 153 }
385a1e07 154 }
d62a17ae 155 }
156}
6b0655a2 157
5ec5929c
G
158/*
159 * TODO: Parent list should be excised, in favour of maintaining only
9c27ef9b
PJ
160 * vertex_nexthop, with refcounts.
161 */
d62a17ae 162static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
7fd0729f
G
163 struct vertex_nexthop *hop,
164 struct vertex_nexthop *lhop)
eb3da6df 165{
d62a17ae 166 struct vertex_parent *new;
167
168 new = XMALLOC(MTYPE_OSPF_VERTEX_PARENT, sizeof(struct vertex_parent));
169
d62a17ae 170 new->parent = v;
171 new->backlink = backlink;
172 new->nexthop = hop;
7fd0729f 173 new->local_nexthop = lhop;
5ec5929c 174
d62a17ae 175 return new;
718e3744 176}
0c0f9cd5 177
d62a17ae 178static void vertex_parent_free(void *p)
eb3da6df 179{
d62a17ae 180 XFREE(MTYPE_OSPF_VERTEX_PARENT, p);
eb3da6df 181}
6b0655a2 182
7fd0729f 183int vertex_parent_cmp(void *aa, void *bb)
f32b6b9c
DL
184{
185 struct vertex_parent *a = aa, *b = bb;
186 return IPV4_ADDR_CMP(&a->nexthop->router, &b->nexthop->router);
187}
188
81443a28
G
189static struct vertex *ospf_vertex_new(struct ospf_area *area,
190 struct ospf_lsa *lsa)
718e3744 191{
d62a17ae 192 struct vertex *new;
193
194 new = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex));
195
196 new->flags = 0;
d62a17ae 197 new->type = lsa->data->type;
198 new->id = lsa->data->id;
199 new->lsa = lsa->data;
200 new->children = list_new();
201 new->parents = list_new();
202 new->parents->del = vertex_parent_free;
f32b6b9c 203 new->parents->cmp = vertex_parent_cmp;
c971918a
DL
204 new->lsa_p = lsa;
205
206 lsa->stat = new;
d62a17ae 207
81443a28 208 listnode_add(area->spf_vertex_list, new);
d62a17ae 209
210 if (IS_DEBUG_OSPF_EVENT)
96b663a3 211 zlog_debug("%s: Created %s vertex %pI4", __func__,
d62a17ae 212 new->type == OSPF_VERTEX_ROUTER ? "Router"
213 : "Network",
96b663a3 214 &new->lsa->id);
5ec5929c 215
d62a17ae 216 return new;
718e3744 217}
218
d62a17ae 219static void ospf_vertex_free(void *data)
718e3744 220{
d62a17ae 221 struct vertex *v = data;
222
223 if (IS_DEBUG_OSPF_EVENT)
96b663a3 224 zlog_debug("%s: Free %s vertex %pI4", __func__,
d62a17ae 225 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
96b663a3 226 &v->lsa->id);
d62a17ae 227
d62a17ae 228 if (v->children)
6a154c88 229 list_delete(&v->children);
d62a17ae 230
231 if (v->parents)
6a154c88 232 list_delete(&v->parents);
d62a17ae 233
234 v->lsa = NULL;
235
236 XFREE(MTYPE_OSPF_VERTEX, v);
718e3744 237}
238
d62a17ae 239static void ospf_vertex_dump(const char *msg, struct vertex *v,
240 int print_parents, int print_children)
630e4807 241{
d62a17ae 242 if (!IS_DEBUG_OSPF_EVENT)
243 return;
244
96b663a3 245 zlog_debug("%s %s vertex %pI4 distance %u flags %u", msg,
d62a17ae 246 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
96b663a3 247 &v->lsa->id, v->distance, (unsigned int)v->flags);
d62a17ae 248
249 if (print_parents) {
250 struct listnode *node;
251 struct vertex_parent *vp;
252
253 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
d62a17ae 254 if (vp) {
255 zlog_debug(
c067e23e
DS
256 "parent %pI4 backlink %d nexthop %pI4 lsa pos %d",
257 &vp->parent->lsa->id, vp->backlink,
258 &vp->nexthop->router,
1d376ff5 259 vp->nexthop->lsa_pos);
d62a17ae 260 }
261 }
262 }
263
264 if (print_children) {
265 struct listnode *cnode;
266 struct vertex *cv;
267
268 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, cv))
269 ospf_vertex_dump(" child:", cv, 0, 0);
630e4807 270 }
630e4807 271}
272
273
274/* Add a vertex to the list of children in each of its parents. */
d62a17ae 275static void ospf_vertex_add_parent(struct vertex *v)
718e3744 276{
d62a17ae 277 struct vertex_parent *vp;
278 struct listnode *node;
279
280 assert(v && v->parents);
281
282 for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) {
283 assert(vp->parent && vp->parent->children);
284
285 /* No need to add two links from the same parent. */
286 if (listnode_lookup(vp->parent->children, v) == NULL)
287 listnode_add(vp->parent->children, v);
288 }
718e3744 289}
6b0655a2 290
7fd0729f
G
291/* Find a vertex according to its router id */
292struct vertex *ospf_spf_vertex_find(struct in_addr id, struct list *vertex_list)
293{
294 struct listnode *node;
295 struct vertex *found;
296
297 for (ALL_LIST_ELEMENTS_RO(vertex_list, node, found)) {
298 if (found->id.s_addr == id.s_addr)
299 return found;
300 }
301
302 return NULL;
303}
304
cc1725bd
G
305/* Find a vertex parent according to its router id */
306struct vertex_parent *ospf_spf_vertex_parent_find(struct in_addr id,
307 struct vertex *vertex)
308{
309 struct listnode *node;
310 struct vertex_parent *found;
311
312 for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, found)) {
313 if (found->parent->id.s_addr == id.s_addr)
314 return found;
315 }
316
317 return NULL;
318}
319
385a1e07
G
320struct vertex *ospf_spf_vertex_by_nexthop(struct vertex *root,
321 struct in_addr *nexthop)
322{
323 struct listnode *node;
324 struct vertex *child;
325 struct vertex_parent *vertex_parent;
326
327 for (ALL_LIST_ELEMENTS_RO(root->children, node, child)) {
328 vertex_parent = ospf_spf_vertex_parent_find(root->id, child);
329 if (vertex_parent->nexthop->router.s_addr == nexthop->s_addr)
330 return child;
331 }
332
333 return NULL;
334}
335
7fd0729f
G
336/* Create a deep copy of a SPF vertex without children and parents */
337static struct vertex *ospf_spf_vertex_copy(struct vertex *vertex)
338{
339 struct vertex *copy;
340
341 copy = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex));
342
343 memcpy(copy, vertex, sizeof(struct vertex));
344 copy->parents = list_new();
345 copy->parents->del = vertex_parent_free;
346 copy->parents->cmp = vertex_parent_cmp;
347 copy->children = list_new();
348
349 return copy;
350}
351
352/* Create a deep copy of a SPF vertex_parent */
353static struct vertex_parent *
354ospf_spf_vertex_parent_copy(struct vertex_parent *vertex_parent)
355{
356 struct vertex_parent *vertex_parent_copy;
357 struct vertex_nexthop *nexthop_copy, *local_nexthop_copy;
358
359 vertex_parent_copy =
360 XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex_parent));
385a1e07
G
361
362 nexthop_copy = vertex_nexthop_new();
363 local_nexthop_copy = vertex_nexthop_new();
7fd0729f
G
364
365 memcpy(vertex_parent_copy, vertex_parent, sizeof(struct vertex_parent));
366 memcpy(nexthop_copy, vertex_parent->nexthop,
367 sizeof(struct vertex_nexthop));
368 memcpy(local_nexthop_copy, vertex_parent->local_nexthop,
369 sizeof(struct vertex_nexthop));
370
371 vertex_parent_copy->nexthop = nexthop_copy;
372 vertex_parent_copy->local_nexthop = local_nexthop_copy;
373
374 return vertex_parent_copy;
375}
376
377/* Create a deep copy of a SPF tree */
378void ospf_spf_copy(struct vertex *vertex, struct list *vertex_list)
379{
380 struct listnode *node;
381 struct vertex *vertex_copy, *child, *child_copy, *parent_copy;
382 struct vertex_parent *vertex_parent, *vertex_parent_copy;
383
384 /* First check if the node is already in the vertex list */
385 vertex_copy = ospf_spf_vertex_find(vertex->id, vertex_list);
386 if (!vertex_copy) {
387 vertex_copy = ospf_spf_vertex_copy(vertex);
388 listnode_add(vertex_list, vertex_copy);
389 }
390
391 /* Copy all parents, create parent nodes if necessary */
392 for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, vertex_parent)) {
393 parent_copy = ospf_spf_vertex_find(vertex_parent->parent->id,
394 vertex_list);
395 if (!parent_copy) {
396 parent_copy =
397 ospf_spf_vertex_copy(vertex_parent->parent);
398 listnode_add(vertex_list, parent_copy);
399 }
400 vertex_parent_copy = ospf_spf_vertex_parent_copy(vertex_parent);
401 vertex_parent_copy->parent = parent_copy;
402 listnode_add(vertex_copy->parents, vertex_parent_copy);
403 }
404
405 /* Copy all children, create child nodes if necessary */
406 for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) {
407 child_copy = ospf_spf_vertex_find(child->id, vertex_list);
408 if (!child_copy) {
409 child_copy = ospf_spf_vertex_copy(child);
410 listnode_add(vertex_list, child_copy);
411 }
412 listnode_add(vertex_copy->children, child_copy);
413 }
414
415 /* Finally continue copying with child nodes */
416 for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child))
417 ospf_spf_copy(child, vertex_list);
418}
419
420static void ospf_spf_remove_branch(struct vertex_parent *vertex_parent,
421 struct vertex *child,
422 struct list *vertex_list)
423{
424 struct listnode *node, *nnode, *inner_node, *inner_nnode;
425 struct vertex *grandchild;
426 struct vertex_parent *vertex_parent_found;
427 bool has_more_links = false;
428
429 /*
430 * First check if there are more nexthops for that parent to that child
431 */
432 for (ALL_LIST_ELEMENTS_RO(child->parents, node, vertex_parent_found)) {
433 if (vertex_parent_found->parent->id.s_addr
434 == vertex_parent->parent->id.s_addr
435 && vertex_parent_found->nexthop->router.s_addr
436 != vertex_parent->nexthop->router.s_addr)
437 has_more_links = true;
438 }
439
440 /*
441 * No more links from that parent? Then delete the child from its
442 * children list.
443 */
444 if (!has_more_links)
445 listnode_delete(vertex_parent->parent->children, child);
446
447 /*
448 * Delete the vertex_parent from the child parents list, this needs to
449 * be done anyway.
450 */
451 listnode_delete(child->parents, vertex_parent);
452
453 /*
454 * Are there actually more parents left? If not, then delete the child!
455 * This is done by recursively removing the links to the grandchildren,
456 * such that finally the child can be removed without leaving unused
457 * partial branches.
458 */
459 if (child->parents->count == 0) {
460 for (ALL_LIST_ELEMENTS(child->children, node, nnode,
461 grandchild)) {
462 for (ALL_LIST_ELEMENTS(grandchild->parents, inner_node,
463 inner_nnode,
464 vertex_parent_found)) {
465 ospf_spf_remove_branch(vertex_parent_found,
466 grandchild, vertex_list);
467 }
468 }
469 listnode_delete(vertex_list, child);
470 ospf_vertex_free(child);
471 }
472}
473
385a1e07
G
474static int ospf_spf_remove_link(struct vertex *vertex, struct list *vertex_list,
475 struct router_lsa_link *link)
7fd0729f
G
476{
477 struct listnode *node, *inner_node;
478 struct vertex *child;
479 struct vertex_parent *vertex_parent;
480
481 /*
482 * Identify the node who shares a subnet (given by the link) with a
483 * child and remove the branch of this particular child.
484 */
485 for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) {
486 for (ALL_LIST_ELEMENTS_RO(child->parents, inner_node,
487 vertex_parent)) {
488 if ((vertex_parent->local_nexthop->router.s_addr
489 & link->link_data.s_addr)
490 == (link->link_id.s_addr
491 & link->link_data.s_addr)) {
492 ospf_spf_remove_branch(vertex_parent, child,
493 vertex_list);
494 return 0;
495 }
496 }
497 }
498
499 /* No link found yet, move on recursively */
500 for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) {
501 if (ospf_spf_remove_link(child, vertex_list, link) == 0)
502 return 0;
503 }
504
505 /* link was not removed yet */
506 return 1;
507}
508
385a1e07
G
509void ospf_spf_remove_resource(struct vertex *vertex, struct list *vertex_list,
510 struct protected_resource *resource)
511{
512 struct listnode *node, *nnode;
513 struct vertex *found;
514 struct vertex_parent *vertex_parent;
515
516 switch (resource->type) {
517 case OSPF_TI_LFA_LINK_PROTECTION:
518 ospf_spf_remove_link(vertex, vertex_list, resource->link);
519 break;
520 case OSPF_TI_LFA_NODE_PROTECTION:
521 found = ospf_spf_vertex_find(resource->router_id, vertex_list);
522 if (!found)
523 break;
524
525 /*
526 * Remove the node by removing all links from its parents. Note
527 * that the child is automatically removed here with the last
528 * link from a parent, hence no explicit removal of the node.
529 */
530 for (ALL_LIST_ELEMENTS(found->parents, node, nnode,
531 vertex_parent))
532 ospf_spf_remove_branch(vertex_parent, found,
533 vertex_list);
534
535 break;
536 default:
537 /* do nothing */
538 break;
539 }
540}
541
1d376ff5 542static void ospf_spf_init(struct ospf_area *area, struct ospf_lsa *root_lsa,
6fc9528e 543 bool is_dry_run, bool is_root_node)
718e3744 544{
81443a28 545 struct list *vertex_list;
d62a17ae 546 struct vertex *v;
547
81443a28
G
548 /* Create vertex list */
549 vertex_list = list_new();
550 vertex_list->del = ospf_vertex_free;
551 area->spf_vertex_list = vertex_list;
d62a17ae 552
81443a28
G
553 /* Create root node. */
554 v = ospf_vertex_new(area, root_lsa);
d62a17ae 555 area->spf = v;
81443a28 556
1d376ff5 557 area->spf_dry_run = is_dry_run;
6fc9528e 558 area->spf_root_node = is_root_node;
d62a17ae 559
560 /* Reset ABR and ASBR router counts. */
561 area->abr_count = 0;
562 area->asbr_count = 0;
718e3744 563}
564
d355bfa7 565/* return index of link back to V from W, or -1 if no link found */
d62a17ae 566static int ospf_lsa_has_link(struct lsa_header *w, struct lsa_header *v)
718e3744 567{
d62a17ae 568 unsigned int i, length;
569 struct router_lsa *rl;
570 struct network_lsa *nl;
571
572 /* In case of W is Network LSA. */
573 if (w->type == OSPF_NETWORK_LSA) {
574 if (v->type == OSPF_NETWORK_LSA)
575 return -1;
576
577 nl = (struct network_lsa *)w;
578 length = (ntohs(w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4;
579
580 for (i = 0; i < length; i++)
581 if (IPV4_ADDR_SAME(&nl->routers[i], &v->id))
582 return i;
583 return -1;
584 }
585
586 /* In case of W is Router LSA. */
587 if (w->type == OSPF_ROUTER_LSA) {
588 rl = (struct router_lsa *)w;
589
590 length = ntohs(w->length);
591
592 for (i = 0; i < ntohs(rl->links)
593 && length >= sizeof(struct router_lsa);
594 i++, length -= 12) {
595 switch (rl->link[i].type) {
596 case LSA_LINK_TYPE_POINTOPOINT:
597 case LSA_LINK_TYPE_VIRTUALLINK:
598 /* Router LSA ID. */
599 if (v->type == OSPF_ROUTER_LSA
600 && IPV4_ADDR_SAME(&rl->link[i].link_id,
601 &v->id)) {
602 return i;
603 }
604 break;
605 case LSA_LINK_TYPE_TRANSIT:
606 /* Network LSA ID. */
607 if (v->type == OSPF_NETWORK_LSA
608 && IPV4_ADDR_SAME(&rl->link[i].link_id,
609 &v->id)) {
610 return i;
611 }
612 break;
613 case LSA_LINK_TYPE_STUB:
614 /* Stub can't lead anywhere, carry on */
615 continue;
616 default:
617 break;
618 }
619 }
620 }
621 return -1;
718e3744 622}
623
5ec5929c
G
624/*
625 * Find the next link after prev_link from v to w. If prev_link is
630e4807 626 * NULL, return the first link from v to w. Ignore stub and virtual links;
627 * these link types will never be returned.
628 */
4dadc291 629static struct router_lsa_link *
d62a17ae 630ospf_get_next_link(struct vertex *v, struct vertex *w,
631 struct router_lsa_link *prev_link)
718e3744 632{
d7c0a89a
QY
633 uint8_t *p;
634 uint8_t *lim;
635 uint8_t lsa_type = LSA_LINK_TYPE_TRANSIT;
d62a17ae 636 struct router_lsa_link *l;
637
638 if (w->type == OSPF_VERTEX_ROUTER)
639 lsa_type = LSA_LINK_TYPE_POINTOPOINT;
640
641 if (prev_link == NULL)
d7c0a89a 642 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
d62a17ae 643 else {
d7c0a89a 644 p = (uint8_t *)prev_link;
d62a17ae 645 p += (OSPF_ROUTER_LSA_LINK_SIZE
646 + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
647 }
0c0f9cd5 648
d7c0a89a 649 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
718e3744 650
d62a17ae 651 while (p < lim) {
652 l = (struct router_lsa_link *)p;
718e3744 653
d62a17ae 654 p += (OSPF_ROUTER_LSA_LINK_SIZE
655 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
718e3744 656
d62a17ae 657 if (l->m[0].type != lsa_type)
658 continue;
718e3744 659
d62a17ae 660 if (IPV4_ADDR_SAME(&l->link_id, &w->id))
661 return l;
662 }
718e3744 663
d62a17ae 664 return NULL;
718e3744 665}
666
d62a17ae 667static void ospf_spf_flush_parents(struct vertex *w)
bc20c1a4 668{
d62a17ae 669 struct vertex_parent *vp;
670 struct listnode *ln, *nn;
671
672 /* delete the existing nexthops */
673 for (ALL_LIST_ELEMENTS(w->parents, ln, nn, vp)) {
674 list_delete_node(w->parents, ln);
675 vertex_parent_free(vp);
676 }
bc20c1a4
PJ
677}
678
d62a17ae 679/*
75ee0b8e 680 * Consider supplied next-hop for inclusion to the supplied list of
d62a17ae 681 * equal-cost next-hops, adjust list as neccessary.
bf9392c6 682 */
d62a17ae 683static void ospf_spf_add_parent(struct vertex *v, struct vertex *w,
684 struct vertex_nexthop *newhop,
7fd0729f 685 struct vertex_nexthop *newlhop,
d62a17ae 686 unsigned int distance)
bf9392c6 687{
d62a17ae 688 struct vertex_parent *vp, *wp;
689 struct listnode *node;
690
691 /* we must have a newhop, and a distance */
692 assert(v && w && newhop);
693 assert(distance);
694
5ec5929c
G
695 /*
696 * IFF w has already been assigned a distance, then we shouldn't get
697 * here unless callers have determined V(l)->W is shortest /
698 * equal-shortest path (0 is a special case distance (no distance yet
699 * assigned)).
d62a17ae 700 */
701 if (w->distance)
702 assert(distance <= w->distance);
703 else
704 w->distance = distance;
705
c067e23e
DS
706 if (IS_DEBUG_OSPF_EVENT)
707 zlog_debug("%s: Adding %pI4 as parent of %pI4", __func__,
708 &v->lsa->id, &w->lsa->id);
d62a17ae 709
5ec5929c
G
710 /*
711 * Adding parent for a new, better path: flush existing parents from W.
d62a17ae 712 */
713 if (distance < w->distance) {
714 if (IS_DEBUG_OSPF_EVENT)
715 zlog_debug(
716 "%s: distance %d better than %d, flushing existing parents",
717 __func__, distance, w->distance);
718 ospf_spf_flush_parents(w);
719 w->distance = distance;
720 }
721
5ec5929c
G
722 /*
723 * new parent is <= existing parents, add it to parent list (if nexthop
d62a17ae 724 * not on parent list)
725 */
726 for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) {
727 if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) {
728 if (IS_DEBUG_OSPF_EVENT)
729 zlog_debug(
730 "%s: ... nexthop already on parent list, skipping add",
731 __func__);
732 return;
733 }
734 }
7b92589c 735
7fd0729f
G
736 vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop,
737 newlhop);
f32b6b9c 738 listnode_add_sort(w->parents, vp);
0c0f9cd5 739
d62a17ae 740 return;
eb3da6df 741}
742
1d376ff5
G
743static int match_stub_prefix(struct lsa_header *lsa, struct in_addr v_link_addr,
744 struct in_addr w_link_addr)
745{
746 uint8_t *p, *lim;
747 struct router_lsa_link *l = NULL;
748 struct in_addr masked_lsa_addr;
749
750 if (lsa->type != OSPF_ROUTER_LSA)
751 return 0;
752
753 p = ((uint8_t *)lsa) + OSPF_LSA_HEADER_SIZE + 4;
754 lim = ((uint8_t *)lsa) + ntohs(lsa->length);
755
756 while (p < lim) {
757 l = (struct router_lsa_link *)p;
758 p += (OSPF_ROUTER_LSA_LINK_SIZE
759 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
760
761 if (l->m[0].type != LSA_LINK_TYPE_STUB)
762 continue;
763
764 masked_lsa_addr.s_addr =
765 (l->link_id.s_addr & l->link_data.s_addr);
766
767 /* check that both links belong to the same stub subnet */
768 if ((masked_lsa_addr.s_addr
769 == (v_link_addr.s_addr & l->link_data.s_addr))
770 && (masked_lsa_addr.s_addr
771 == (w_link_addr.s_addr & l->link_data.s_addr)))
772 return 1;
773 }
774
775 return 0;
776}
777
5ec5929c
G
778/*
779 * 16.1.1. Calculate nexthop from root through V (parent) to
bd34fb34 780 * vertex W (destination), with given distance from root->W.
eb3da6df 781 *
782 * The link must be supplied if V is the root vertex. In all other cases
783 * it may be NULL.
bd34fb34
PJ
784 *
785 * Note that this function may fail, hence the state of the destination
786 * vertex, W, should /not/ be modified in a dependent manner until
787 * this function returns. This function will update the W vertex with the
788 * provided distance as appropriate.
630e4807 789 */
d62a17ae 790static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
791 struct vertex *v, struct vertex *w,
792 struct router_lsa_link *l,
793 unsigned int distance, int lsa_pos)
718e3744 794{
d62a17ae 795 struct listnode *node, *nnode;
7fd0729f 796 struct vertex_nexthop *nh, *lnh;
d62a17ae 797 struct vertex_parent *vp;
d62a17ae 798 unsigned int added = 0;
d62a17ae 799
800 if (IS_DEBUG_OSPF_EVENT) {
801 zlog_debug("ospf_nexthop_calculation(): Start");
802 ospf_vertex_dump("V (parent):", v, 1, 1);
803 ospf_vertex_dump("W (dest) :", w, 1, 1);
804 zlog_debug("V->W distance: %d", distance);
c81ee5c9
JT
805 }
806
d62a17ae 807 if (v == area->spf) {
5ec5929c
G
808 /*
809 * 16.1.1 para 4. In the first case, the parent vertex (V) is
810 * the root (the calculating router itself). This means that
811 * the destination is either a directly connected network or
812 * directly connected router. The outgoing interface in this
813 * case is simply the OSPF interface connecting to the
814 * destination network/router.
815 */
d62a17ae 816
817 /* we *must* be supplied with the link data */
818 assert(l != NULL);
c81ee5c9 819
c067e23e 820 if (IS_DEBUG_OSPF_EVENT)
d62a17ae 821 zlog_debug(
c067e23e
DS
822 "%s: considering link type:%d link_id:%pI4 link_data:%pI4",
823 __func__, l->m[0].type, &l->link_id,
824 &l->link_data);
c81ee5c9 825
d62a17ae 826 if (w->type == OSPF_VERTEX_ROUTER) {
5ec5929c
G
827 /*
828 * l is a link from v to w l2 will be link from w to v
d62a17ae 829 */
830 struct router_lsa_link *l2 = NULL;
831
832 if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) {
d615c345
DS
833 struct ospf_interface *oi = NULL;
834 struct in_addr nexthop = {.s_addr = 0};
835
94dd5670
G
836 if (area->spf_root_node) {
837 oi = ospf_if_lookup_by_lsa_pos(area,
838 lsa_pos);
839 if (!oi) {
840 zlog_debug(
c067e23e 841 "%s: OI not found in LSA: lsa_pos: %d link_id:%pI4 link_data:%pI4",
94dd5670 842 __func__, lsa_pos,
c067e23e
DS
843 &l->link_id,
844 &l->link_data);
94dd5670
G
845 return 0;
846 }
d615c345 847 }
6fc9528e 848
5ec5929c
G
849 /*
850 * If the destination is a router which connects
851 * to the calculating router via a
852 * Point-to-MultiPoint network, the
853 * destination's next hop IP address(es) can be
854 * determined by examining the destination's
855 * router-LSA: each link pointing back to the
856 * calculating router and having a Link Data
857 * field belonging to the Point-to-MultiPoint
858 * network provides an IP address of the next
859 * hop router.
860 *
861 * At this point l is a link from V to W, and V
862 * is the root ("us"). If it is a point-to-
863 * multipoint interface, then look through the
864 * links in the opposite direction (W to V).
865 * If any of them have an address that lands
866 * within the subnet declared by the PtMP link,
867 * then that link is a constituent of the PtMP
868 * link, and its address is a nexthop address
869 * for V.
1d376ff5
G
870 *
871 * Note for point-to-point interfaces:
872 *
873 * Having nexthop = 0 (as proposed in the RFC)
874 * is tempting, but NOT acceptable. It breaks
875 * AS-External routes with a forwarding address,
876 * since ospf_ase_complete_direct_routes() will
877 * mistakenly assume we've reached the last hop
878 * and should place the forwarding address as
879 * nexthop. Also, users may configure multi-
880 * access links in p2p mode, so we need the IP
881 * to ARP the nexthop.
882 *
6fc9528e
G
883 * If the calculating router is the SPF root
884 * node and the link is P2P then access the
885 * interface information directly. This can be
886 * crucial when e.g. IP unnumbered is used
887 * where 'correct' nexthop information are not
888 * available via Router LSAs.
889 *
890 * Otherwise handle P2P and P2MP the same way
891 * as described above using a reverse lookup to
892 * figure out the nexthop.
5ec5929c 893 */
94dd5670
G
894
895 /*
896 * HACK: we don't know (yet) how to distinguish
897 * between P2P and P2MP interfaces by just
898 * looking at LSAs, which is important for
899 * TI-LFA since you want to do SPF calculations
900 * from the perspective of other nodes. Since
901 * TI-LFA is currently not implemented for P2MP
902 * we just check here if it is enabled and then
903 * blindly assume that P2P is used. Ultimately
904 * the interface code needs to be removed
905 * somehow.
906 */
907 if (area->ospf->ti_lfa_enabled
908 || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT)) {
d615c345 909 struct ospf_neighbor *nbr_w = NULL;
d62a17ae 910
d615c345
DS
911 /* Calculating node is root node, link
912 * is P2P */
913 if (area->spf_root_node) {
6fc9528e
G
914 nbr_w = ospf_nbr_lookup_by_routerid(
915 oi->nbrs, &l->link_id);
916 if (nbr_w) {
917 added = 1;
918 nexthop = nbr_w->src;
919 }
920 }
d62a17ae 921
d615c345
DS
922 /* Reverse lookup */
923 if (!added) {
924 while ((l2 = ospf_get_next_link(
925 w, v, l2))) {
926 if (match_stub_prefix(
927 v->lsa,
928 l->link_data,
929 l2->link_data)) {
930 added = 1;
931 nexthop =
932 l2->link_data;
933 break;
934 }
935 }
936 }
94dd5670 937 } else if (oi && oi->type
d615c345
DS
938 == OSPF_IFTYPE_POINTOMULTIPOINT) {
939 struct prefix_ipv4 la;
940
941 la.family = AF_INET;
942 la.prefixlen = oi->address->prefixlen;
943
944 /*
945 * V links to W on PtMP interface;
946 * find the interface address on W
947 */
6fc9528e
G
948 while ((l2 = ospf_get_next_link(w, v,
949 l2))) {
d615c345
DS
950 la.prefix = l2->link_data;
951
952 if (prefix_cmp((struct prefix
953 *)&la,
954 oi->address)
955 != 0)
956 continue;
957 added = 1;
958 nexthop = l2->link_data;
959 break;
d62a17ae 960 }
961 }
962
963 if (added) {
d62a17ae 964 nh = vertex_nexthop_new();
d62a17ae 965 nh->router = nexthop;
1d376ff5 966 nh->lsa_pos = lsa_pos;
7fd0729f
G
967
968 /*
969 * Since v is the root the nexthop and
970 * local nexthop are the same.
971 */
972 lnh = vertex_nexthop_new();
973 memcpy(lnh, nh,
974 sizeof(struct vertex_nexthop));
975
976 ospf_spf_add_parent(v, w, nh, lnh,
977 distance);
d62a17ae 978 return 1;
979 } else
980 zlog_info(
d615c345 981 "%s: could not determine nexthop for link %s",
94dd5670 982 __func__, oi ? oi->ifp->name : "");
d62a17ae 983 } /* end point-to-point link from V to W */
984 else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) {
5ec5929c
G
985 /*
986 * VLink implementation limitations:
987 * a) vl_data can only reference one nexthop,
988 * so no ECMP to backbone through VLinks.
989 * Though transit-area summaries may be
990 * considered, and those can be ECMP.
d62a17ae 991 * b) We can only use /one/ VLink, even if
5ec5929c
G
992 * multiple ones exist this router through
993 * multiple transit-areas.
d62a17ae 994 */
1d376ff5
G
995
996 struct ospf_vl_data *vl_data;
997
d62a17ae 998 vl_data = ospf_vl_lookup(area->ospf, NULL,
999 l->link_id);
1000
1001 if (vl_data
1002 && CHECK_FLAG(vl_data->flags,
1003 OSPF_VL_FLAG_APPROVED)) {
1004 nh = vertex_nexthop_new();
d62a17ae 1005 nh->router = vl_data->nexthop.router;
1d376ff5 1006 nh->lsa_pos = vl_data->nexthop.lsa_pos;
7fd0729f
G
1007
1008 /*
1009 * Since v is the root the nexthop and
1010 * local nexthop are the same.
1011 */
1012 lnh = vertex_nexthop_new();
1013 memcpy(lnh, nh,
1014 sizeof(struct vertex_nexthop));
1015
1016 ospf_spf_add_parent(v, w, nh, lnh,
1017 distance);
d62a17ae 1018 return 1;
1019 } else
1020 zlog_info(
3efd0893 1021 "ospf_nexthop_calculation(): vl_data for VL link not found");
d62a17ae 1022 } /* end virtual-link from V to W */
1023 return 0;
1024 } /* end W is a Router vertex */
1025 else {
1026 assert(w->type == OSPF_VERTEX_NETWORK);
1027
1028 nh = vertex_nexthop_new();
d62a17ae 1029 nh->router.s_addr = 0; /* Nexthop not required */
1d376ff5 1030 nh->lsa_pos = lsa_pos;
7fd0729f
G
1031
1032 /*
1033 * Since v is the root the nexthop and
1034 * local nexthop are the same.
1035 */
1036 lnh = vertex_nexthop_new();
1037 memcpy(lnh, nh, sizeof(struct vertex_nexthop));
1038
1039 ospf_spf_add_parent(v, w, nh, lnh, distance);
d62a17ae 1040 return 1;
1041 }
1042 } /* end V is the root */
1043 /* Check if W's parent is a network connected to root. */
1044 else if (v->type == OSPF_VERTEX_NETWORK) {
1045 /* See if any of V's parents are the root. */
1046 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
5ec5929c
G
1047 if (vp->parent == area->spf) {
1048 /*
1049 * 16.1.1 para 5. ...the parent vertex is a
1050 * network that directly connects the
1051 * calculating router to the destination
1052 * router. The list of next hops is then
1053 * determined by examining the destination's
1054 * router-LSA ...
d62a17ae 1055 */
1056
1057 assert(w->type == OSPF_VERTEX_ROUTER);
1058 while ((l = ospf_get_next_link(w, v, l))) {
5ec5929c
G
1059 /*
1060 * ... For each link in the router-LSA
1061 * that points back to the parent
1062 * network, the link's Link Data field
1063 * provides the IP address of a next hop
1064 * router. The outgoing interface to use
1065 * can then be derived from the next
1066 * hop IP address (or it can be
1067 * inherited from the parent network).
d62a17ae 1068 */
1069 nh = vertex_nexthop_new();
d62a17ae 1070 nh->router = l->link_data;
1d376ff5 1071 nh->lsa_pos = vp->nexthop->lsa_pos;
7fd0729f
G
1072
1073 /*
1074 * Since v is the root the nexthop and
1075 * local nexthop are the same.
1076 */
1077 lnh = vertex_nexthop_new();
1078 memcpy(lnh, nh,
1079 sizeof(struct vertex_nexthop));
1080
d62a17ae 1081 added = 1;
7fd0729f
G
1082 ospf_spf_add_parent(v, w, nh, lnh,
1083 distance);
d62a17ae 1084 }
5ec5929c
G
1085 /*
1086 * Note lack of return is deliberate. See next
1087 * comment.
1088 */
d62a17ae 1089 }
c81ee5c9 1090 }
5ec5929c
G
1091 /*
1092 * NB: This code is non-trivial.
d62a17ae 1093 *
1094 * E.g. it is not enough to know that V connects to the root. It
5ec5929c
G
1095 * is also important that the while above, looping through all
1096 * links from W->V found at least one link, so that we know
1097 * there is bi-directional connectivity between V and W (which
1098 * need not be the case, e.g. when OSPF has not yet converged
1099 * fully). Otherwise, if we /always/ return here, without having
1100 * checked that root->V->-W actually resulted in a valid nexthop
1101 * being created, then we we will prevent SPF from finding/using
1102 * higher cost paths.
d62a17ae 1103 *
1104 * It is important, if root->V->W has not been added, that we
5ec5929c
G
1105 * continue through to the intervening-router nexthop code
1106 * below. So as to ensure other paths to V may be used. This
1107 * avoids unnecessary blackholes while OSPF is converging.
d62a17ae 1108 *
1109 * I.e. we may have arrived at this function, examining V -> W,
5ec5929c
G
1110 * via workable paths other than root -> V, and it's important
1111 * to avoid getting "confused" by non-working root->V->W path
1112 * - it's important to *not* lose the working non-root paths,
1113 * just because of a non-viable root->V->W.
d62a17ae 1114 */
1115 if (added)
1116 return added;
1117 }
c81ee5c9 1118
5ec5929c
G
1119 /*
1120 * 16.1.1 para 4. If there is at least one intervening router in the
d62a17ae 1121 * current shortest path between the destination and the root, the
1122 * destination simply inherits the set of next hops from the
1123 * parent.
1124 */
1125 if (IS_DEBUG_OSPF_EVENT)
1126 zlog_debug("%s: Intervening routers, adding parent(s)",
1127 __func__);
1128
1129 for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) {
1130 added = 1;
7fd0729f
G
1131
1132 /*
1133 * The nexthop is inherited, but the local nexthop still needs
1134 * to be created.
1135 */
1136 if (l) {
1137 lnh = vertex_nexthop_new();
1138 lnh->router = l->link_data;
1139 lnh->lsa_pos = lsa_pos;
1140 } else {
1141 lnh = NULL;
1142 }
1143
1144 ospf_spf_add_parent(v, w, vp->nexthop, lnh, distance);
d62a17ae 1145 }
c81ee5c9 1146
d62a17ae 1147 return added;
718e3744 1148}
1149
385a1e07
G
1150static int ospf_spf_is_protected_resource(struct ospf_area *area,
1151 struct router_lsa_link *link,
1152 struct lsa_header *lsa)
7fd0729f 1153{
385a1e07 1154 uint8_t *p, *lim;
7fd0729f 1155 struct router_lsa_link *p_link;
385a1e07
G
1156 struct router_lsa_link *l = NULL;
1157 struct in_addr router_id;
1158 int link_type;
7fd0729f 1159
385a1e07 1160 if (!area->spf_protected_resource)
7fd0729f
G
1161 return 0;
1162
385a1e07
G
1163 link_type = link->m[0].type;
1164
1165 switch (area->spf_protected_resource->type) {
1166 case OSPF_TI_LFA_LINK_PROTECTION:
1167 p_link = area->spf_protected_resource->link;
1168 if (!p_link)
1169 return 0;
1170
1171 /* For P2P: check if the link belongs to the same subnet */
1172 if (link_type == LSA_LINK_TYPE_POINTOPOINT
1173 && (p_link->link_id.s_addr & p_link->link_data.s_addr)
1174 == (link->link_data.s_addr
1175 & p_link->link_data.s_addr))
1176 return 1;
1177
1178 /* For stub: check if this the same subnet */
1179 if (link_type == LSA_LINK_TYPE_STUB
1180 && (p_link->link_id.s_addr == link->link_id.s_addr)
1181 && (p_link->link_data.s_addr == link->link_data.s_addr))
1182 return 1;
1183
1184 break;
1185 case OSPF_TI_LFA_NODE_PROTECTION:
1186 router_id = area->spf_protected_resource->router_id;
1187 if (router_id.s_addr == INADDR_ANY)
1188 return 0;
1189
1190 /* For P2P: check if the link leads to the protected node */
1191 if (link_type == LSA_LINK_TYPE_POINTOPOINT
1192 && link->link_id.s_addr == router_id.s_addr)
1193 return 1;
1194
1195 /* The rest is about stub links! */
1196 if (link_type != LSA_LINK_TYPE_STUB)
1197 return 0;
1198
1199 /*
1200 * Check if there's a P2P link in the router LSA with the
1201 * corresponding link data in the same subnet.
1202 */
1203
1204 p = ((uint8_t *)lsa) + OSPF_LSA_HEADER_SIZE + 4;
1205 lim = ((uint8_t *)lsa) + ntohs(lsa->length);
1206
1207 while (p < lim) {
1208 l = (struct router_lsa_link *)p;
1209 p += (OSPF_ROUTER_LSA_LINK_SIZE
1210 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
1211
1212 /* We only care about P2P with the proper link id */
1213 if ((l->m[0].type != LSA_LINK_TYPE_POINTOPOINT)
1214 || (l->link_id.s_addr != router_id.s_addr))
1215 continue;
1216
1217 /* Link data in the subnet given by the link? */
1218 if ((link->link_id.s_addr & link->link_data.s_addr)
1219 == (l->link_data.s_addr & link->link_data.s_addr))
1220 return 1;
1221 }
1222
1223 break;
1224 case OSPF_TI_LFA_UNDEFINED_PROTECTION:
1225 break;
1226 }
7fd0729f
G
1227
1228 return 0;
1229}
1230
133e59cf
G
1231/*
1232 * For TI-LFA we need the reverse SPF for Q spaces. The reverse SPF is created
1233 * by honoring the weight of the reverse 'edge', e.g. the edge from W to V, and
1234 * NOT the weight of the 'edge' from V to W as usual. Hence we need to find the
1235 * corresponding link in the LSA of W and extract the particular weight.
1236 *
1237 * TODO: Only P2P supported by now!
1238 */
1239static uint16_t get_reverse_distance(struct vertex *v,
1240 struct router_lsa_link *l,
1241 struct ospf_lsa *w_lsa)
1242{
1243 uint8_t *p, *lim;
1244 struct router_lsa_link *w_link;
1245 uint16_t distance = 0;
1246
7815c834
G
1247 assert(w_lsa && w_lsa->data);
1248
133e59cf
G
1249 p = ((uint8_t *)w_lsa->data) + OSPF_LSA_HEADER_SIZE + 4;
1250 lim = ((uint8_t *)w_lsa->data) + ntohs(w_lsa->data->length);
1251
1252 while (p < lim) {
1253 w_link = (struct router_lsa_link *)p;
1254 p += (OSPF_ROUTER_LSA_LINK_SIZE
1255 + (w_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
1256
1257 /* Only care about P2P with link ID equal to V's router id */
1258 if (w_link->m[0].type == LSA_LINK_TYPE_POINTOPOINT
1259 && w_link->link_id.s_addr == v->id.s_addr) {
1260 distance = ntohs(w_link->m[0].metric);
1261 break;
1262 }
1263 }
1264
1265 /*
1266 * This might happen if the LSA for W is not complete yet. In this
1267 * case we take the weight of the 'forward' link from V. When the LSA
1268 * for W is completed the reverse SPF is run again anyway.
1269 */
1270 if (distance == 0)
1271 distance = ntohs(l->m[0].metric);
1272
7815c834
G
1273 if (IS_DEBUG_OSPF_EVENT)
1274 zlog_debug("%s: reversed distance is %u", __func__, distance);
133e59cf
G
1275
1276 return distance;
1277}
1278
5ec5929c
G
1279/*
1280 * RFC2328 16.1 (2).
1281 * v is on the SPF tree. Examine the links in v's LSA. Update the list of
1282 * candidates with any vertices not already on the list. If a lower-cost path
1283 * is found to a vertex already on the candidate list, store the new cost.
630e4807 1284 */
5ec5929c 1285static void ospf_spf_next(struct vertex *v, struct ospf_area *area,
c971918a 1286 struct vertex_pqueue_head *candidate)
718e3744 1287{
d62a17ae 1288 struct ospf_lsa *w_lsa = NULL;
d7c0a89a
QY
1289 uint8_t *p;
1290 uint8_t *lim;
d62a17ae 1291 struct router_lsa_link *l = NULL;
1292 struct in_addr *r;
1293 int type = 0, lsa_pos = -1, lsa_pos_next = 0;
133e59cf 1294 uint16_t link_distance;
d62a17ae 1295
5ec5929c
G
1296 /*
1297 * If this is a router-LSA, and bit V of the router-LSA (see Section
1298 * A.4.2:RFC2328) is set, set Area A's TransitCapability to true.
1299 */
d62a17ae 1300 if (v->type == OSPF_VERTEX_ROUTER) {
1301 if (IS_ROUTER_LSA_VIRTUAL((struct router_lsa *)v->lsa))
1302 area->transit = OSPF_TRANSIT_TRUE;
1303 }
718e3744 1304
d62a17ae 1305 if (IS_DEBUG_OSPF_EVENT)
96b663a3 1306 zlog_debug("%s: Next vertex of %s vertex %pI4", __func__,
d62a17ae 1307 v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network",
96b663a3 1308 &v->lsa->id);
d62a17ae 1309
d7c0a89a
QY
1310 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
1311 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
d62a17ae 1312
1313 while (p < lim) {
1314 struct vertex *w;
1315 unsigned int distance;
1316
1317 /* In case of V is Router-LSA. */
1318 if (v->lsa->type == OSPF_ROUTER_LSA) {
1319 l = (struct router_lsa_link *)p;
1320
1321 lsa_pos = lsa_pos_next; /* LSA link position */
1322 lsa_pos_next++;
1d376ff5 1323
d62a17ae 1324 p += (OSPF_ROUTER_LSA_LINK_SIZE
1325 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
1326
5ec5929c
G
1327 /*
1328 * (a) If this is a link to a stub network, examine the
1329 * next link in V's LSA. Links to stub networks will
1330 * be considered in the second stage of the shortest
1331 * path calculation.
1332 */
d62a17ae 1333 if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB)
1334 continue;
1335
7fd0729f 1336 /*
385a1e07 1337 * Don't process TI-LFA protected resources.
7fd0729f
G
1338 *
1339 * TODO: Replace this by a proper solution, e.g. remove
1340 * corresponding links from the LSDB and run the SPF
1341 * algo with the stripped-down LSDB.
1342 */
385a1e07 1343 if (ospf_spf_is_protected_resource(area, l, v->lsa))
7fd0729f
G
1344 continue;
1345
5ec5929c
G
1346 /*
1347 * (b) Otherwise, W is a transit vertex (router or
1348 * transit network). Look up the vertex W's LSA
1349 * (router-LSA or network-LSA) in Area A's link state
1350 * database.
1351 */
d62a17ae 1352 switch (type) {
1353 case LSA_LINK_TYPE_POINTOPOINT:
1354 case LSA_LINK_TYPE_VIRTUALLINK:
5ec5929c
G
1355 if (type == LSA_LINK_TYPE_VIRTUALLINK
1356 && IS_DEBUG_OSPF_EVENT)
1357 zlog_debug(
96b663a3
MS
1358 "looking up LSA through VL: %pI4",
1359 &l->link_id);
5ec5929c 1360 w_lsa = ospf_lsa_lookup(area->ospf, area,
b5a8894d 1361 OSPF_ROUTER_LSA,
d62a17ae 1362 l->link_id, l->link_id);
5ec5929c 1363 if (w_lsa && IS_DEBUG_OSPF_EVENT)
96b663a3
MS
1364 zlog_debug("found Router LSA %pI4",
1365 &l->link_id);
d62a17ae 1366 break;
1367 case LSA_LINK_TYPE_TRANSIT:
1368 if (IS_DEBUG_OSPF_EVENT)
1369 zlog_debug(
96b663a3
MS
1370 "Looking up Network LSA, ID: %pI4",
1371 &l->link_id);
d62a17ae 1372 w_lsa = ospf_lsa_lookup_by_id(
1373 area, OSPF_NETWORK_LSA, l->link_id);
5ec5929c
G
1374 if (w_lsa && IS_DEBUG_OSPF_EVENT)
1375 zlog_debug("found the LSA");
d62a17ae 1376 break;
1377 default:
cf444bcf 1378 flog_warn(EC_OSPF_LSA,
668e8a11 1379 "Invalid LSA link type %d", type);
d62a17ae 1380 continue;
1381 }
3239e3ca 1382
133e59cf
G
1383 /*
1384 * For TI-LFA we might need the reverse SPF.
1385 * Currently only works with P2P!
1386 */
1387 if (type == LSA_LINK_TYPE_POINTOPOINT
1388 && area->spf_reversed)
1389 link_distance =
1390 get_reverse_distance(v, l, w_lsa);
1391 else
1392 link_distance = ntohs(l->m[0].metric);
1393
3239e3ca 1394 /* step (d) below */
133e59cf 1395 distance = v->distance + link_distance;
d62a17ae 1396 } else {
1397 /* In case of V is Network-LSA. */
1398 r = (struct in_addr *)p;
1399 p += sizeof(struct in_addr);
1400
1401 /* Lookup the vertex W's LSA. */
1402 w_lsa = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA,
1403 *r);
5ec5929c 1404 if (w_lsa && IS_DEBUG_OSPF_EVENT)
96b663a3
MS
1405 zlog_debug("found Router LSA %pI4",
1406 &w_lsa->data->id);
3239e3ca
DL
1407
1408 /* step (d) below */
1409 distance = v->distance;
d62a17ae 1410 }
718e3744 1411
5ec5929c
G
1412 /*
1413 * (b cont.) If the LSA does not exist, or its LS age is equal
1414 * to MaxAge, or it does not have a link back to vertex V,
1415 * examine the next link in V's LSA.[23]
1416 */
d62a17ae 1417 if (w_lsa == NULL) {
1418 if (IS_DEBUG_OSPF_EVENT)
1419 zlog_debug("No LSA found");
1420 continue;
1421 }
718e3744 1422
d62a17ae 1423 if (IS_LSA_MAXAGE(w_lsa)) {
1424 if (IS_DEBUG_OSPF_EVENT)
1425 zlog_debug("LSA is MaxAge");
1426 continue;
1427 }
718e3744 1428
d62a17ae 1429 if (ospf_lsa_has_link(w_lsa->data, v->lsa) < 0) {
1430 if (IS_DEBUG_OSPF_EVENT)
1431 zlog_debug("The LSA doesn't have a link back");
1432 continue;
1433 }
718e3744 1434
5ec5929c
G
1435 /*
1436 * (c) If vertex W is already on the shortest-path tree, examine
1437 * the next link in the LSA.
1438 */
d62a17ae 1439 if (w_lsa->stat == LSA_SPF_IN_SPFTREE) {
1440 if (IS_DEBUG_OSPF_EVENT)
1441 zlog_debug("The LSA is already in SPF");
1442 continue;
1443 }
718e3744 1444
5ec5929c
G
1445 /*
1446 * (d) Calculate the link state cost D of the resulting path
1447 * from the root to vertex W. D is equal to the sum of the link
1448 * state cost of the (already calculated) shortest path to
1449 * vertex V and the advertised cost of the link between vertices
1450 * V and W. If D is:
1451 */
d62a17ae 1452
3239e3ca 1453 /* calculate link cost D -- moved above */
d62a17ae 1454
1455 /* Is there already vertex W in candidate list? */
1456 if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) {
1457 /* prepare vertex W. */
81443a28 1458 w = ospf_vertex_new(area, w_lsa);
d62a17ae 1459
1460 /* Calculate nexthop to W. */
1461 if (ospf_nexthop_calculation(area, v, w, l, distance,
1462 lsa_pos))
c971918a 1463 vertex_pqueue_add(candidate, w);
d62a17ae 1464 else if (IS_DEBUG_OSPF_EVENT)
1465 zlog_debug("Nexthop Calc failed");
c971918a
DL
1466 } else if (w_lsa->stat != LSA_SPF_IN_SPFTREE) {
1467 w = w_lsa->stat;
d62a17ae 1468 if (w->distance < distance) {
1469 continue;
1470 }
d62a17ae 1471 else if (w->distance == distance) {
5ec5929c
G
1472 /*
1473 * Found an equal-cost path to W.
1474 * Calculate nexthop of to W from V.
1475 */
d62a17ae 1476 ospf_nexthop_calculation(area, v, w, l,
1477 distance, lsa_pos);
1478 }
d62a17ae 1479 else {
5ec5929c
G
1480 /*
1481 * Found a lower-cost path to W.
d62a17ae 1482 * nexthop_calculation is conditional, if it
5ec5929c
G
1483 * finds valid nexthop it will call
1484 * spf_add_parents, which will flush the old
1485 * parents.
d62a17ae 1486 */
c971918a
DL
1487 vertex_pqueue_del(candidate, w);
1488 ospf_nexthop_calculation(area, v, w, l,
1d376ff5 1489 distance, lsa_pos);
c971918a 1490 vertex_pqueue_add(candidate, w);
d62a17ae 1491 }
1492 } /* end W is already on the candidate list */
1493 } /* end loop over the links in V's LSA */
1494}
718e3744 1495
d62a17ae 1496static void ospf_spf_dump(struct vertex *v, int i)
1497{
1498 struct listnode *cnode;
1499 struct listnode *nnode;
1500 struct vertex_parent *parent;
1501
1502 if (v->type == OSPF_VERTEX_ROUTER) {
1503 if (IS_DEBUG_OSPF_EVENT)
96b663a3
MS
1504 zlog_debug("SPF Result: %d [R] %pI4", i,
1505 &v->lsa->id);
d62a17ae 1506 } else {
1507 struct network_lsa *lsa = (struct network_lsa *)v->lsa;
1508 if (IS_DEBUG_OSPF_EVENT)
96b663a3
MS
1509 zlog_debug("SPF Result: %d [N] %pI4/%d", i,
1510 &v->lsa->id,
d62a17ae 1511 ip_masklen(lsa->mask));
462f20d5 1512 }
718e3744 1513
d62a17ae 1514 if (IS_DEBUG_OSPF_EVENT)
1515 for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) {
96b663a3
MS
1516 zlog_debug(" nexthop %p %pI4 %d",
1517 (void *)parent->nexthop,
1518 &parent->nexthop->router,
1d376ff5 1519 parent->nexthop->lsa_pos);
d62a17ae 1520 }
718e3744 1521
d62a17ae 1522 i++;
718e3744 1523
d62a17ae 1524 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v))
1525 ospf_spf_dump(v, i);
718e3744 1526}
1527
3a76b1be
G
1528void ospf_spf_print(struct vty *vty, struct vertex *v, int i)
1529{
1530 struct listnode *cnode;
1531 struct listnode *nnode;
1532 struct vertex_parent *parent;
1533
1534 if (v->type == OSPF_VERTEX_ROUTER) {
7fd0729f 1535 vty_out(vty, "SPF Result: depth %d [R] %pI4\n", i, &v->lsa->id);
3a76b1be
G
1536 } else {
1537 struct network_lsa *lsa = (struct network_lsa *)v->lsa;
96b663a3
MS
1538 vty_out(vty, "SPF Result: depth %d [N] %pI4/%d\n", i,
1539 &v->lsa->id, ip_masklen(lsa->mask));
3a76b1be
G
1540 }
1541
1542 for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) {
7fd0729f
G
1543 vty_out(vty,
1544 " nexthop %pI4 lsa pos %d -- local nexthop %pI4 lsa pos %d\n",
1545 &parent->nexthop->router, parent->nexthop->lsa_pos,
1546 &parent->local_nexthop->router,
1547 parent->local_nexthop->lsa_pos);
3a76b1be
G
1548 }
1549
1550 i++;
1551
1552 for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v))
1553 ospf_spf_print(vty, v, i);
1554}
1555
718e3744 1556/* Second stage of SPF calculation. */
d62a17ae 1557static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v,
1558 struct route_table *rt, int parent_is_root)
718e3744 1559{
d62a17ae 1560 struct listnode *cnode, *cnnode;
1561 struct vertex *child;
1562
1563 if (IS_DEBUG_OSPF_EVENT)
96b663a3
MS
1564 zlog_debug("ospf_process_stub():processing stubs for area %pI4",
1565 &area->area_id);
5ec5929c 1566
d62a17ae 1567 if (v->type == OSPF_VERTEX_ROUTER) {
d7c0a89a
QY
1568 uint8_t *p;
1569 uint8_t *lim;
d62a17ae 1570 struct router_lsa_link *l;
5ec5929c 1571 struct router_lsa *router_lsa;
d62a17ae 1572 int lsa_pos = 0;
1573
1574 if (IS_DEBUG_OSPF_EVENT)
1575 zlog_debug(
96b663a3
MS
1576 "ospf_process_stubs():processing router LSA, id: %pI4",
1577 &v->lsa->id);
d62a17ae 1578
5ec5929c 1579 router_lsa = (struct router_lsa *)v->lsa;
d62a17ae 1580
1581 if (IS_DEBUG_OSPF_EVENT)
1582 zlog_debug(
1583 "ospf_process_stubs(): we have %d links to process",
5ec5929c
G
1584 ntohs(router_lsa->links));
1585
d7c0a89a
QY
1586 p = ((uint8_t *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4;
1587 lim = ((uint8_t *)v->lsa) + ntohs(v->lsa->length);
d62a17ae 1588
1589 while (p < lim) {
1590 l = (struct router_lsa_link *)p;
1591
1592 p += (OSPF_ROUTER_LSA_LINK_SIZE
1593 + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
1594
385a1e07 1595 /* Don't process TI-LFA protected resources */
7fd0729f 1596 if (l->m[0].type == LSA_LINK_TYPE_STUB
385a1e07 1597 && !ospf_spf_is_protected_resource(area, l, v->lsa))
d62a17ae 1598 ospf_intra_add_stub(rt, l, v, area,
1599 parent_is_root, lsa_pos);
1600 lsa_pos++;
1601 }
1602 }
718e3744 1603
d62a17ae 1604 ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1,
1605 1);
718e3744 1606
d62a17ae 1607 for (ALL_LIST_ELEMENTS(v->children, cnode, cnnode, child)) {
1608 if (CHECK_FLAG(child->flags, OSPF_VERTEX_PROCESSED))
1609 continue;
718e3744 1610
5ec5929c
G
1611 /*
1612 * The first level of routers connected to the root
d62a17ae 1613 * should have 'parent_is_root' set, including those
1614 * connected via a network vertex.
1615 */
1616 if (area->spf == v)
1617 parent_is_root = 1;
1618 else if (v->type == OSPF_VERTEX_ROUTER)
1619 parent_is_root = 0;
1620
1621 ospf_spf_process_stubs(area, child, rt, parent_is_root);
1622
1623 SET_FLAG(child->flags, OSPF_VERTEX_PROCESSED);
1624 }
718e3744 1625}
1626
d62a17ae 1627void ospf_rtrs_free(struct route_table *rtrs)
718e3744 1628{
d62a17ae 1629 struct route_node *rn;
1630 struct list *or_list;
1631 struct ospf_route * or ;
1632 struct listnode *node, *nnode;
718e3744 1633
d62a17ae 1634 if (IS_DEBUG_OSPF_EVENT)
1635 zlog_debug("Route: Router Routing Table free");
718e3744 1636
d62a17ae 1637 for (rn = route_top(rtrs); rn; rn = route_next(rn))
1638 if ((or_list = rn->info) != NULL) {
1639 for (ALL_LIST_ELEMENTS(or_list, node, nnode, or))
1640 ospf_route_free(or);
718e3744 1641
6a154c88 1642 list_delete(&or_list);
718e3744 1643
d62a17ae 1644 /* Unlock the node. */
1645 rn->info = NULL;
1646 route_unlock_node(rn);
1647 }
5ec5929c 1648
d62a17ae 1649 route_table_finish(rtrs);
718e3744 1650}
1651
81443a28
G
1652void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list)
1653{
1654 /*
1655 * Free nexthop information, canonical versions of which are
1656 * attached the first level of router vertices attached to the
1657 * root vertex, see ospf_nexthop_calculation.
1658 */
7fd0729f
G
1659 if (spf)
1660 ospf_canonical_nexthops_free(spf);
81443a28
G
1661
1662 /* Free SPF vertices list with deconstructor ospf_vertex_free. */
7fd0729f
G
1663 if (vertex_list)
1664 list_delete(&vertex_list);
81443a28
G
1665}
1666
5ec5929c 1667/* Calculating the shortest-path tree for an area, see RFC2328 16.1. */
1d376ff5
G
1668void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
1669 struct route_table *new_table,
6fc9528e
G
1670 struct route_table *new_rtrs, bool is_dry_run,
1671 bool is_root_node)
718e3744 1672{
c971918a 1673 struct vertex_pqueue_head candidate;
d62a17ae 1674 struct vertex *v;
718e3744 1675
d62a17ae 1676 if (IS_DEBUG_OSPF_EVENT) {
1677 zlog_debug("ospf_spf_calculate: Start");
96b663a3
MS
1678 zlog_debug("ospf_spf_calculate: running Dijkstra for area %pI4",
1679 &area->area_id);
d62a17ae 1680 }
718e3744 1681
5ec5929c
G
1682 /*
1683 * If the router LSA of the root is not yet allocated, return this
1684 * area's calculation. In the 'usual' case the root_lsa is the
1685 * self-originated router LSA of the node itself.
1686 */
1687 if (!root_lsa) {
d62a17ae 1688 if (IS_DEBUG_OSPF_EVENT)
1689 zlog_debug(
96b663a3
MS
1690 "ospf_spf_calculate: Skip area %pI4's calculation due to empty root LSA",
1691 &area->area_id);
d62a17ae 1692 return;
1693 }
718e3744 1694
5ec5929c 1695 /* Initialize the algorithm's data structures, see RFC2328 16.1. (1). */
d62a17ae 1696
5ec5929c
G
1697 /*
1698 * This function scans all the LSA database and set the stat field to
1699 * LSA_SPF_NOT_EXPLORED.
1700 */
c971918a 1701 lsdb_clean_stat(area->lsdb);
5ec5929c 1702
d62a17ae 1703 /* Create a new heap for the candidates. */
c971918a 1704 vertex_pqueue_init(&candidate);
d62a17ae 1705
5ec5929c
G
1706 /*
1707 * Initialize the shortest-path tree to only the root (which is usually
1708 * the router doing the calculation).
1709 */
6fc9528e 1710 ospf_spf_init(area, root_lsa, is_dry_run, is_root_node);
d62a17ae 1711
2951a7a4 1712 /* Set Area A's TransitCapability to false. */
d62a17ae 1713 area->transit = OSPF_TRANSIT_FALSE;
1714 area->shortcut_capability = 1;
1715
5ec5929c
G
1716 /*
1717 * Use the root vertex for the start of the SPF algorithm and make it
1718 * part of the tree.
1719 */
1720 v = area->spf;
1721 v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
1722
d62a17ae 1723 for (;;) {
1724 /* RFC2328 16.1. (2). */
5ec5929c 1725 ospf_spf_next(v, area, &candidate);
d62a17ae 1726
1727 /* RFC2328 16.1. (3). */
c971918a
DL
1728 v = vertex_pqueue_pop(&candidate);
1729 if (!v)
5ec5929c 1730 /* No more vertices left. */
c971918a 1731 break;
5ec5929c 1732
c971918a 1733 v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
d62a17ae 1734
1735 ospf_vertex_add_parent(v);
1736
1737 /* RFC2328 16.1. (4). */
1738 if (v->type == OSPF_VERTEX_ROUTER)
1739 ospf_intra_add_router(new_rtrs, v, area);
1740 else
1741 ospf_intra_add_transit(new_table, v, area);
1742
5ec5929c
G
1743 /* Iterate back to (2), see RFC2328 16.1. (5). */
1744 }
d62a17ae 1745
1746 if (IS_DEBUG_OSPF_EVENT) {
1747 ospf_spf_dump(area->spf, 0);
1748 ospf_route_table_dump(new_table);
1749 }
cf744958 1750
5ec5929c
G
1751 /*
1752 * Second stage of SPF calculation procedure's, add leaves to the tree
1753 * for stub networks.
1754 */
d62a17ae 1755 ospf_spf_process_stubs(area, area->spf, new_table, 0);
cf744958 1756
d62a17ae 1757 ospf_vertex_dump(__func__, area->spf, 0, 1);
718e3744 1758
d62a17ae 1759 /* Increment SPF Calculation Counter. */
1760 area->spf_calculation++;
1761
1762 monotime(&area->ospf->ts_spf);
1763 area->ts_spf = area->ospf->ts_spf;
cf744958 1764
d62a17ae 1765 if (IS_DEBUG_OSPF_EVENT)
1766 zlog_debug("ospf_spf_calculate: Stop. %zd vertices",
1767 mtype_stats_alloc(MTYPE_OSPF_VERTEX));
7fd0729f
G
1768}
1769
1770void ospf_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
1771 struct route_table *new_table,
1772 struct route_table *new_rtrs)
1773{
1774 ospf_spf_calculate(area, area->router_lsa_self, new_table, new_rtrs,
1775 false, true);
d62a17ae 1776
7fd0729f 1777 if (ospf->ti_lfa_enabled)
385a1e07
G
1778 ospf_ti_lfa_compute(area, new_table,
1779 ospf->ti_lfa_protection_type);
7fd0729f
G
1780
1781 ospf_spf_cleanup(area->spf, area->spf_vertex_list);
718e3744 1782}
6b0655a2 1783
7fd0729f
G
1784void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
1785 struct route_table *new_rtrs)
718e3744 1786{
d62a17ae 1787 struct ospf_area *area;
1788 struct listnode *node, *nnode;
d62a17ae 1789
1790 /* Calculate SPF for each area. */
1791 for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
1792 /* Do backbone last, so as to first discover intra-area paths
5ec5929c 1793 * for any back-bone virtual-links */
d62a17ae 1794 if (ospf->backbone && ospf->backbone == area)
1795 continue;
cf744958 1796
7fd0729f 1797 ospf_spf_calculate_area(ospf, area, new_table, new_rtrs);
d62a17ae 1798 }
1799
1800 /* SPF for backbone, if required */
7fd0729f
G
1801 if (ospf->backbone)
1802 ospf_spf_calculate_area(ospf, ospf->backbone, new_table,
1803 new_rtrs);
5ec5929c
G
1804}
1805
1806/* Worker for SPF calculation scheduler. */
1807static int ospf_spf_calculate_schedule_worker(struct thread *thread)
1808{
1809 struct ospf *ospf = THREAD_ARG(thread);
1810 struct route_table *new_table, *new_rtrs;
1811 struct timeval start_time, spf_start_time;
5ec5929c
G
1812 unsigned long ia_time, prune_time, rt_time;
1813 unsigned long abr_time, total_spf_time, spf_time;
1814 char rbuf[32]; /* reason_buf */
1815
1816 if (IS_DEBUG_OSPF_EVENT)
1817 zlog_debug("SPF: Timer (SPF calculation expire)");
1818
1819 ospf->t_spf_calc = NULL;
1820
1821 ospf_vl_unapprove(ospf);
1822
1823 /* Execute SPF for each area including backbone, see RFC 2328 16.1. */
1824 monotime(&spf_start_time);
1825 new_table = route_table_init(); /* routing table */
1826 new_rtrs = route_table_init(); /* ABR/ASBR routing table */
7fd0729f 1827 ospf_spf_calculate_areas(ospf, new_table, new_rtrs);
d62a17ae 1828 spf_time = monotime_since(&spf_start_time, NULL);
1829
1830 ospf_vl_shut_unapproved(ospf);
1831
5ec5929c 1832 /* Calculate inter-area routes, see RFC 2328 16.2. */
d62a17ae 1833 monotime(&start_time);
1834 ospf_ia_routing(ospf, new_table, new_rtrs);
1835 ia_time = monotime_since(&start_time, NULL);
1836
5ec5929c 1837 /* Get rid of transit networks and routers we cannot reach anyway. */
d62a17ae 1838 monotime(&start_time);
1839 ospf_prune_unreachable_networks(new_table);
1840 ospf_prune_unreachable_routers(new_rtrs);
1841 prune_time = monotime_since(&start_time, NULL);
1842
5ec5929c 1843 /* Note: RFC 2328 16.3. is apparently missing. */
d62a17ae 1844
5ec5929c
G
1845 /*
1846 * Calculate AS external routes, see RFC 2328 16.4.
1847 * There is a dedicated routing table for external routes which is not
1848 * handled here directly
1849 */
1850 ospf_ase_calculate_schedule(ospf);
d62a17ae 1851 ospf_ase_calculate_timer_add(ospf);
1852
b5a8894d 1853 if (IS_DEBUG_OSPF_EVENT)
996c9314
LB
1854 zlog_debug(
1855 "%s: ospf install new route, vrf %s id %u new_table count %lu",
5e81f5dd 1856 __func__, ospf_vrf_id_to_name(ospf->vrf_id),
996c9314 1857 ospf->vrf_id, new_table->count);
5ec5929c 1858
d62a17ae 1859 /* Update routing table. */
1860 monotime(&start_time);
1861 ospf_route_install(ospf, new_table);
1862 rt_time = monotime_since(&start_time, NULL);
1863
5ec5929c
G
1864 /* Free old ABR/ASBR routing table */
1865 if (ospf->old_rtrs)
d62a17ae 1866 /* ospf_route_delete (ospf->old_rtrs); */
1867 ospf_rtrs_free(ospf->old_rtrs);
d62a17ae 1868
5ec5929c 1869 /* Update ABR/ASBR routing table */
d62a17ae 1870 ospf->old_rtrs = ospf->new_rtrs;
1871 ospf->new_rtrs = new_rtrs;
1872
5ec5929c 1873 /* ABRs may require additional changes, see RFC 2328 16.7. */
d62a17ae 1874 monotime(&start_time);
0124b46b 1875 if (IS_OSPF_ABR(ospf)) {
1876 if (ospf->anyNSSA)
1877 ospf_abr_nssa_check_status(ospf);
d62a17ae 1878 ospf_abr_task(ospf);
0124b46b 1879 }
d62a17ae 1880 abr_time = monotime_since(&start_time, NULL);
1881
cf9b9f77 1882 /* Schedule Segment Routing update */
b37eb79c 1883 ospf_sr_update_task(ospf);
cf9b9f77 1884
d62a17ae 1885 total_spf_time =
1886 monotime_since(&spf_start_time, &ospf->ts_spf_duration);
1887
1888 rbuf[0] = '\0';
1889 if (spf_reason_flags) {
1890 if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL)
96b663a3 1891 strlcat(rbuf, "R, ", sizeof(rbuf));
d62a17ae 1892 if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL)
96b663a3 1893 strlcat(rbuf, "N, ", sizeof(rbuf));
d62a17ae 1894 if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL)
96b663a3 1895 strlcat(rbuf, "S, ", sizeof(rbuf));
d62a17ae 1896 if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL)
96b663a3 1897 strlcat(rbuf, "AS, ", sizeof(rbuf));
d62a17ae 1898 if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE)
96b663a3 1899 strlcat(rbuf, "ABR, ", sizeof(rbuf));
d62a17ae 1900 if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE)
96b663a3 1901 strlcat(rbuf, "ASBR, ", sizeof(rbuf));
d62a17ae 1902 if (spf_reason_flags & SPF_FLAG_MAXAGE)
96b663a3 1903 strlcat(rbuf, "M, ", sizeof(rbuf));
d62a17ae 1904
1905 size_t rbuflen = strlen(rbuf);
1906 if (rbuflen >= 2)
1907 rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
1908 else
1909 rbuf[0] = '\0';
1910 }
1911
1912 if (IS_DEBUG_OSPF_EVENT) {
1913 zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
d6951e5e
DL
1914 zlog_info(" SPF Time: %ld", spf_time);
1915 zlog_info(" InterArea: %ld", ia_time);
1916 zlog_info(" Prune: %ld", prune_time);
1917 zlog_info(" RouteInstall: %ld", rt_time);
d62a17ae 1918 if (IS_OSPF_ABR(ospf))
d6951e5e 1919 zlog_info(" ABR: %ld (%d areas)",
7fd0729f 1920 abr_time, ospf->areas->count);
d62a17ae 1921 zlog_info("Reason(s) for SPF: %s", rbuf);
1922 }
1923
1924 ospf_clear_spf_reason_flags();
1925
1926 return 0;
718e3744 1927}
1928
5ec5929c
G
1929/*
1930 * Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
1931 * for SPF calc.
1932 */
d62a17ae 1933void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
718e3744 1934{
d62a17ae 1935 unsigned long delay, elapsed, ht;
718e3744 1936
d62a17ae 1937 if (IS_DEBUG_OSPF_EVENT)
1938 zlog_debug("SPF: calculation timer scheduled");
1939
1940 /* OSPF instance does not exist. */
1941 if (ospf == NULL)
1942 return;
1943
1944 ospf_spf_set_reason(reason);
1945
1946 /* SPF calculation timer is already scheduled. */
1947 if (ospf->t_spf_calc) {
1948 if (IS_DEBUG_OSPF_EVENT)
1949 zlog_debug(
1950 "SPF: calculation timer is already scheduled: %p",
1951 (void *)ospf->t_spf_calc);
1952 return;
1953 }
1954
1955 elapsed = monotime_since(&ospf->ts_spf, NULL) / 1000;
1956
1957 ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
1958
1959 if (ht > ospf->spf_max_holdtime)
1960 ht = ospf->spf_max_holdtime;
1961
1962 /* Get SPF calculation delay time. */
1963 if (elapsed < ht) {
5ec5929c
G
1964 /*
1965 * Got an event within the hold time of last SPF. We need to
d62a17ae 1966 * increase the hold_multiplier, if it's not already at/past
5ec5929c 1967 * maximum value, and wasn't already increased.
d62a17ae 1968 */
1969 if (ht < ospf->spf_max_holdtime)
1970 ospf->spf_hold_multiplier++;
1971
1972 /* always honour the SPF initial delay */
1973 if ((ht - elapsed) < ospf->spf_delay)
1974 delay = ospf->spf_delay;
1975 else
1976 delay = ht - elapsed;
1977 } else {
1978 /* Event is past required hold-time of last SPF */
1979 delay = ospf->spf_delay;
1980 ospf->spf_hold_multiplier = 1;
1981 }
1982
1983 if (IS_DEBUG_OSPF_EVENT)
05ba78e4 1984 zlog_debug("SPF: calculation timer delay = %ld msec", delay);
cf744958 1985
d62a17ae 1986 ospf->t_spf_calc = NULL;
5ec5929c
G
1987 thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
1988 delay, &ospf->t_spf_calc);
718e3744 1989}