Coverage Report

Created: 2025-12-12 06:43

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