Coverage Report

Created: 2025-10-23 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/ospfd/ospf_ase.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * OSPF AS external route calculation.
4
 * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada
5
 */
6
7
#include <zebra.h>
8
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 "vty.h"
17
#include "log.h"
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_ase.h"
30
#include "ospfd/ospf_zebra.h"
31
#include "ospfd/ospf_dump.h"
32
33
struct ospf_route *ospf_find_asbr_route(struct ospf *ospf,
34
          struct route_table *rtrs,
35
          struct prefix_ipv4 *asbr)
36
0
{
37
0
  struct route_node *rn;
38
0
  struct ospf_route * or, *best = NULL;
39
0
  struct listnode *node;
40
0
  struct list *chosen;
41
42
  /* Sanity check. */
43
0
  if (rtrs == NULL)
44
0
    return NULL;
45
46
0
  rn = route_node_lookup(rtrs, (struct prefix *)asbr);
47
0
  if (!rn)
48
0
    return NULL;
49
50
0
  route_unlock_node(rn);
51
52
0
  chosen = list_new();
53
54
  /* First try to find intra-area non-bb paths. */
55
0
  if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE))
56
0
    for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
57
0
      if (or->cost < OSPF_LS_INFINITY)
58
0
        if (!OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)
59
0
              &&
60
0
            or->path_type == OSPF_PATH_INTRA_AREA)
61
0
          listnode_add(chosen, or);
62
63
  /* If none is found -- look through all. */
64
0
  if (listcount(chosen) == 0) {
65
0
    list_delete(&chosen);
66
0
    chosen = rn->info;
67
0
  }
68
69
  /* Now find the route with least cost. */
70
0
  for (ALL_LIST_ELEMENTS_RO(chosen, node, or))
71
0
    if (or->cost < OSPF_LS_INFINITY) {
72
0
      if (best == NULL)
73
0
        best = or ;
74
0
      else if (best->cost > or->cost)
75
0
        best = or ;
76
0
      else if (best->cost ==
77
0
         or->cost
78
0
             && IPV4_ADDR_CMP(
79
0
                  &best->u.std.area_id,
80
0
                  & or->u.std.area_id)
81
0
                  < 0)
82
0
        best = or ;
83
0
    }
84
85
0
  if (chosen != rn->info)
86
0
    list_delete(&chosen);
87
88
0
  return best;
89
0
}
90
91
struct ospf_route *ospf_find_asbr_route_through_area(struct route_table *rtrs,
92
                 struct prefix_ipv4 *asbr,
93
                 struct ospf_area *area)
94
0
{
95
0
  struct route_node *rn;
96
97
  /* Sanity check. */
98
0
  if (rtrs == NULL)
99
0
    return NULL;
100
101
0
  rn = route_node_lookup(rtrs, (struct prefix *)asbr);
102
103
0
  if (rn) {
104
0
    struct listnode *node;
105
0
    struct ospf_route * or ;
106
107
0
    route_unlock_node(rn);
108
109
0
    for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or))
110
0
      if (IPV4_ADDR_SAME(& or->u.std.area_id, &area->area_id))
111
0
        return or ;
112
0
  }
113
114
0
  return NULL;
115
0
}
116
117
static void ospf_ase_complete_direct_routes(struct ospf_route *ro,
118
              struct in_addr nexthop)
119
0
{
120
0
  struct listnode *node;
121
0
  struct ospf_path *op;
122
123
0
  for (ALL_LIST_ELEMENTS_RO(ro->paths, node, op))
124
0
    if (op->nexthop.s_addr == INADDR_ANY)
125
0
      op->nexthop.s_addr = nexthop.s_addr;
126
0
}
127
128
static int ospf_ase_forward_address_check(struct ospf *ospf,
129
            struct in_addr fwd_addr)
130
0
{
131
0
  struct listnode *ifn;
132
0
  struct ospf_interface *oi;
133
134
0
  for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ifn, oi))
135
0
    if (if_is_operative(oi->ifp))
136
0
      if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
137
0
        if (IPV4_ADDR_SAME(&oi->address->u.prefix4,
138
0
               &fwd_addr))
139
0
          return 0;
140
141
0
  return 1;
142
0
}
143
144
static struct ospf_route *
145
ospf_ase_calculate_new_route(struct ospf_lsa *lsa,
146
           struct ospf_route *asbr_route, uint32_t metric)
147
0
{
148
0
  struct as_external_lsa *al;
149
0
  struct ospf_route *new;
150
151
0
  al = (struct as_external_lsa *)lsa->data;
152
153
0
  new = ospf_route_new();
154
155
  /* Set redistributed type -- does make sense? */
156
  /* new->type = type; */
157
0
  new->id = al->header.id;
158
0
  new->mask = al->mask;
159
160
0
  if (!IS_EXTERNAL_METRIC(al->e[0].tos)) {
161
0
    if (IS_DEBUG_OSPF(lsa, LSA))
162
0
      zlog_debug(
163
0
        "Route[External]: type-1 created, asbr cost:%d  metric:%d.",
164
0
        asbr_route->cost, metric);
165
0
    new->path_type = OSPF_PATH_TYPE1_EXTERNAL;
166
0
    new->cost = asbr_route->cost + metric; /* X + Y */
167
0
  } else {
168
0
    if (IS_DEBUG_OSPF(lsa, LSA))
169
0
      zlog_debug("Route[External]: type-2 created.");
170
0
    new->path_type = OSPF_PATH_TYPE2_EXTERNAL;
171
0
    new->cost = asbr_route->cost;   /* X */
172
0
    new->u.ext.type2_cost = metric; /* Y */
173
0
  }
174
175
0
  new->type = OSPF_DESTINATION_NETWORK;
176
0
  new->u.ext.origin = lsa;
177
0
  new->u.ext.tag = ntohl(al->e[0].route_tag);
178
0
  new->u.ext.asbr = asbr_route;
179
180
0
  assert(new != asbr_route);
181
182
0
  return new;
183
0
}
184
185
#define OSPF_ASE_CALC_INTERVAL 1
186
187
int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
188
0
{
189
0
  uint32_t metric;
190
0
  struct as_external_lsa *al;
191
0
  struct ospf_route *asbr_route;
192
0
  struct prefix_ipv4 asbr, p;
193
0
  struct route_node *rn;
194
0
  struct ospf_route *new, * or ;
195
0
  int ret;
196
197
0
  assert(lsa);
198
0
  al = (struct as_external_lsa *)lsa->data;
199
200
0
  if (lsa->data->type == OSPF_AS_NSSA_LSA)
201
0
    if (IS_DEBUG_OSPF_NSSA)
202
0
      zlog_debug("%s: Processing Type-7", __func__);
203
204
  /* Stay away from any Local Translated Type-7 LSAs */
205
0
  if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
206
0
    if (IS_DEBUG_OSPF_NSSA)
207
0
      zlog_debug("%s: Rejecting Local Xlt'd", __func__);
208
0
    return 0;
209
0
  }
210
211
0
  if (IS_DEBUG_OSPF(lsa, LSA)) {
212
0
    zlog_debug(
213
0
      "Route[External]: Calculate AS-external-LSA to %pI4/%d adv_router %pI4",
214
0
      &al->header.id, ip_masklen(al->mask),
215
0
      &al->header.adv_router);
216
0
  }
217
218
  /* (1) If the cost specified by the LSA is LSInfinity, or if the
219
         LSA's LS age is equal to MaxAge, then examine the next LSA. */
220
0
  if ((metric = GET_METRIC(al->e[0].metric)) >= OSPF_LS_INFINITY) {
221
0
    if (IS_DEBUG_OSPF(lsa, LSA))
222
0
      zlog_debug(
223
0
        "Route[External]: Metric is OSPF_LS_INFINITY");
224
0
    return 0;
225
0
  }
226
0
  if (IS_LSA_MAXAGE(lsa)) {
227
0
    if (IS_DEBUG_OSPF(lsa, LSA))
228
0
      zlog_debug(
229
0
        "Route[External]: AS-external-LSA is MAXAGE");
230
0
    return 0;
231
0
  }
232
233
  /* (2) If the LSA was originated by the calculating router itself,
234
     examine the next LSA. */
235
0
  if (IS_LSA_SELF(lsa)) {
236
0
    if (IS_DEBUG_OSPF(lsa, LSA))
237
0
      zlog_debug(
238
0
        "Route[External]: AS-external-LSA is self originated");
239
0
    return 0;
240
0
  }
241
242
  /* (3) Call the destination described by the LSA N.  N's address is
243
         obtained by masking the LSA's Link State ID with the
244
         network/subnet mask contained in the body of the LSA.  Look
245
         up the routing table entries (potentially one per attached
246
         area) for the AS boundary router (ASBR) that originated the
247
         LSA. If no entries exist for router ASBR (i.e., ASBR is
248
         unreachable), do nothing with this LSA and consider the next
249
         in the list. */
250
251
0
  asbr.family = AF_INET;
252
0
  asbr.prefix = al->header.adv_router;
253
0
  asbr.prefixlen = IPV4_MAX_BITLEN;
254
0
  apply_mask_ipv4(&asbr);
255
256
0
  asbr_route = ospf_find_asbr_route(ospf, ospf->new_rtrs, &asbr);
257
0
  if (asbr_route == NULL) {
258
0
    if (IS_DEBUG_OSPF(lsa, LSA))
259
0
      zlog_debug(
260
0
        "Route[External]: Can't find originating ASBR route");
261
0
    return 0;
262
0
  }
263
0
  if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) {
264
0
    if (IS_DEBUG_OSPF(lsa, LSA))
265
0
      zlog_debug(
266
0
        "Route[External]: Originating router is not an ASBR");
267
0
    return 0;
268
0
  }
269
270
  /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR.
271
   * As per RFC 3101, expectation is to receive type-7 lsas from
272
   * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and
273
   * originated ASBR's area is NSSA.
274
   */
275
0
  if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA)
276
0
      && (asbr_route->u.std.external_routing != OSPF_AREA_DEFAULT)) {
277
0
    if (IS_DEBUG_OSPF(lsa, LSA))
278
0
      zlog_debug(
279
0
        "Route[External]: Ignore, If type-5 LSA from NSSA area.");
280
0
    return 0;
281
0
  }
282
283
  /*     Else, this LSA describes an AS external path to destination
284
         N.  Examine the forwarding address specified in the AS-
285
         external-LSA.  This indicates the IP address to which
286
         packets for the destination should be forwarded. */
287
288
0
  if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
289
    /* If the forwarding address is set to 0.0.0.0, packets should
290
       be sent to the ASBR itself. Among the multiple routing table
291
       entries for the ASBR, select the preferred entry as follows.
292
       If RFC1583Compatibility is set to "disabled", prune the set
293
       of routing table entries for the ASBR as described in
294
       Section 16.4.1. In any case, among the remaining routing
295
       table entries, select the routing table entry with the least
296
       cost; when there are multiple least cost routing table
297
       entries the entry whose associated area has the largest OSPF
298
       Area ID (when considered as an unsigned 32-bit integer) is
299
       chosen. */
300
301
    /* asbr_route already contains the requested route */
302
0
  } else {
303
    /* If the forwarding address is non-zero, look up the
304
       forwarding address in the routing table.[24] The matching
305
       routing table entry must specify an intra-area or inter-area
306
       path; if no such path exists, do nothing with the LSA and
307
       consider the next in the list. */
308
0
    if (!ospf_ase_forward_address_check(ospf, al->e[0].fwd_addr)) {
309
0
      if (IS_DEBUG_OSPF(lsa, LSA))
310
0
        zlog_debug(
311
0
          "Route[External]: Forwarding address is our router address");
312
0
      return 0;
313
0
    }
314
315
0
    asbr.family = AF_INET;
316
0
    asbr.prefix = al->e[0].fwd_addr;
317
0
    asbr.prefixlen = IPV4_MAX_BITLEN;
318
319
0
    rn = route_node_match(ospf->new_table, (struct prefix *)&asbr);
320
321
0
    if (rn == NULL || (asbr_route = rn->info) == NULL) {
322
0
      if (IS_DEBUG_OSPF(lsa, LSA))
323
0
        zlog_debug(
324
0
          "Route[External]: Can't find route to forwarding address");
325
0
      if (rn)
326
0
        route_unlock_node(rn);
327
0
      return 0;
328
0
    }
329
330
0
    route_unlock_node(rn);
331
0
  }
332
333
  /* (4) Let X be the cost specified by the preferred routing table
334
         entry for the ASBR/forwarding address, and Y the cost
335
         specified in the LSA.  X is in terms of the link state
336
         metric, and Y is a type 1 or 2 external metric. */
337
338
339
  /* (5) Look up the routing table entry for the destination N.  If
340
         no entry exists for N, install the AS external path to N,
341
         with next hop equal to the list of next hops to the
342
         forwarding address, and advertising router equal to ASBR.
343
         If the external metric type is 1, then the path-type is set
344
         to type 1 external and the cost is equal to X+Y.  If the
345
         external metric type is 2, the path-type is set to type 2
346
         external, the link state component of the route's cost is X,
347
         and the type 2 cost is Y. */
348
0
  new = ospf_ase_calculate_new_route(lsa, asbr_route, metric);
349
350
  /* (6) Compare the AS external path described by the LSA with the
351
         existing paths in N's routing table entry, as follows. If
352
         the new path is preferred, it replaces the present paths in
353
         N's routing table entry.  If the new path is of equal
354
         preference, it is added to N's routing table entry's list of
355
         paths. */
356
357
  /* Set prefix. */
358
0
  p.family = AF_INET;
359
0
  p.prefix = al->header.id;
360
0
  p.prefixlen = ip_masklen(al->mask);
361
362
  /* if there is a Intra/Inter area route to the N
363
     do not install external route */
364
0
  if ((rn = route_node_lookup(ospf->new_table, (struct prefix *)&p))) {
365
0
    route_unlock_node(rn);
366
0
    if (rn->info == NULL)
367
0
      zlog_info("Route[External]: rn->info NULL");
368
0
    if (new)
369
0
      ospf_route_free(new);
370
0
    return 0;
371
0
  }
372
  /* Find a route to the same dest */
373
  /* If there is no route, create new one. */
374
0
  if ((rn = route_node_lookup(ospf->new_external_route,
375
0
            (struct prefix *)&p)))
376
0
    route_unlock_node(rn);
377
378
0
  if (!rn || (or = rn->info) == NULL) {
379
0
    if (IS_DEBUG_OSPF(lsa, LSA))
380
0
      zlog_debug("Route[External]: Adding a new route %pFX with paths %u",
381
0
           &p, listcount(asbr_route->paths));
382
383
0
    ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
384
385
0
    if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
386
0
      ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
387
0
    return 0;
388
0
  } else {
389
    /* (a) Intra-area and inter-area paths are always preferred
390
           over AS external paths.
391
392
       (b) Type 1 external paths are always preferred over type 2
393
           external paths. When all paths are type 2 external
394
           paths, the paths with the smallest advertised type 2
395
           metric are always preferred. */
396
0
    ret = ospf_route_cmp(ospf, new, or);
397
398
    /*     (c) If the new AS external path is still
399
       indistinguishable
400
         from the current paths in the N's routing table
401
       entry,
402
         and RFC1583Compatibility is set to "disabled", select
403
         the preferred paths based on the intra-AS paths to
404
       the
405
         ASBR/forwarding addresses, as specified in Section
406
         16.4.1.
407
408
           (d) If the new AS external path is still
409
       indistinguishable
410
         from the current paths in the N's routing table
411
       entry,
412
         select the preferred path based on a least cost
413
         comparison.  Type 1 external paths are compared by
414
         looking at the sum of the distance to the forwarding
415
         address and the advertised type 1 metric (X+Y).  Type
416
       2
417
         external paths advertising equal type 2 metrics are
418
         compared by looking at the distance to the forwarding
419
         addresses.
420
    */
421
    /* New route is better */
422
0
    if (ret < 0) {
423
0
      if (IS_DEBUG_OSPF(lsa, LSA))
424
0
        zlog_debug(
425
0
          "Route[External]: New route is better");
426
0
      ospf_route_subst(rn, new, asbr_route);
427
0
      if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
428
0
        ospf_ase_complete_direct_routes(
429
0
          new, al->e[0].fwd_addr);
430
0
      or = new;
431
0
      new = NULL;
432
0
    }
433
    /* Old route is better */
434
0
    else if (ret > 0) {
435
0
      if (IS_DEBUG_OSPF(lsa, LSA))
436
0
        zlog_debug(
437
0
          "Route[External]: Old route is better");
438
      /* do nothing */
439
0
    }
440
    /* Routes are equal */
441
0
    else {
442
0
      if (IS_DEBUG_OSPF(lsa, LSA))
443
0
        zlog_debug("Route[External]: Routes are equal");
444
0
      ospf_route_copy_nexthops(or, asbr_route->paths);
445
0
      if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
446
0
        ospf_ase_complete_direct_routes(
447
0
          or, al->e[0].fwd_addr);
448
0
    }
449
0
  }
450
  /* Make sure setting newly calculated ASBR route.*/
451
0
  or->u.ext.asbr = asbr_route;
452
0
  if (new)
453
0
    ospf_route_free(new);
454
455
0
  lsa->route = or ;
456
0
  return 0;
457
0
}
458
459
static int ospf_ase_route_match_same(struct route_table *rt,
460
             struct prefix *prefix,
461
             struct ospf_route *newor)
462
0
{
463
0
  struct route_node *rn;
464
0
  struct ospf_route *or;
465
0
  struct ospf_path *op;
466
0
  struct ospf_path *newop;
467
0
  struct listnode *n1;
468
0
  struct listnode *n2;
469
470
0
  if (!rt || !prefix)
471
0
    return 0;
472
473
0
  rn = route_node_lookup(rt, prefix);
474
0
  if (!rn)
475
0
    return 0;
476
477
0
  route_unlock_node(rn);
478
479
0
  or = rn->info;
480
481
0
  assert(or);
482
483
0
  if (or->path_type != newor->path_type)
484
0
    return 0;
485
486
0
  switch (or->path_type) {
487
0
  case OSPF_PATH_TYPE1_EXTERNAL:
488
0
    if (or->cost != newor->cost)
489
0
      return 0;
490
0
    break;
491
0
  case OSPF_PATH_TYPE2_EXTERNAL:
492
0
    if ((or->cost != newor->cost)
493
0
        || (or->u.ext.type2_cost != newor->u.ext.type2_cost))
494
0
      return 0;
495
0
    break;
496
0
  default:
497
0
    assert(0);
498
0
    return 0;
499
0
  }
500
501
0
  assert(or->paths);
502
503
0
  if (or->paths->count != newor->paths->count)
504
0
    return 0;
505
506
  /* Check each path. */
507
0
  for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2;
508
0
       n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) {
509
0
    op = listgetdata(n1);
510
0
    newop = listgetdata(n2);
511
512
0
    if (!IPV4_ADDR_SAME(&op->nexthop, &newop->nexthop))
513
0
      return 0;
514
0
    if (op->ifindex != newop->ifindex)
515
0
      return 0;
516
0
  }
517
518
0
  if (or->u.ext.tag != newor->u.ext.tag)
519
0
    return 0;
520
521
0
  return 1;
522
0
}
523
524
static int ospf_ase_compare_tables(struct ospf *ospf,
525
           struct route_table *new_external_route,
526
           struct route_table *old_external_route)
527
0
{
528
0
  struct route_node *rn, *new_rn;
529
0
  struct ospf_route * or ;
530
531
  /* Remove deleted routes */
532
0
  for (rn = route_top(old_external_route); rn; rn = route_next(rn))
533
0
    if ((or = rn->info)) {
534
0
      if (!(new_rn = route_node_lookup(new_external_route,
535
0
               &rn->p)))
536
0
        ospf_zebra_delete(
537
0
          ospf, (struct prefix_ipv4 *)&rn->p, or);
538
0
      else
539
0
        route_unlock_node(new_rn);
540
0
    }
541
542
543
  /* Install new routes */
544
0
  for (rn = route_top(new_external_route); rn; rn = route_next(rn))
545
0
    if ((or = rn->info) != NULL)
546
0
      if (!ospf_ase_route_match_same(old_external_route,
547
0
                   &rn->p, or))
548
0
        ospf_zebra_add(
549
0
          ospf, (struct prefix_ipv4 *)&rn->p, or);
550
551
0
  return 0;
552
0
}
553
554
static void ospf_ase_calculate_timer(struct event *t)
555
0
{
556
0
  struct ospf *ospf;
557
0
  struct ospf_lsa *lsa;
558
0
  struct route_node *rn;
559
0
  struct listnode *node;
560
0
  struct ospf_area *area;
561
0
  struct timeval start_time, stop_time;
562
0
563
0
  ospf = EVENT_ARG(t);
564
0
  ospf->t_ase_calc = NULL;
565
0
566
0
  if (ospf->ase_calc) {
567
0
    ospf->ase_calc = 0;
568
0
569
0
    monotime(&start_time);
570
0
571
0
    /* Calculate external route for each AS-external-LSA */
572
0
    LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
573
0
      ospf_ase_calculate_route(ospf, lsa);
574
0
575
0
    /*  This version simple adds to the table all NSSA areas  */
576
0
    if (ospf->anyNSSA)
577
0
      for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
578
0
        if (IS_DEBUG_OSPF_NSSA)
579
0
          zlog_debug("%s: looking at area %pI4",
580
0
               __func__, &area->area_id);
581
0
582
0
        if (area->external_routing == OSPF_AREA_NSSA)
583
0
          LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
584
0
            ospf_ase_calculate_route(ospf,
585
0
                   lsa);
586
0
      }
587
0
    /* kevinm: And add the NSSA routes in ospf_top */
588
0
    LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
589
0
      ospf_ase_calculate_route(ospf, lsa);
590
0
591
0
    /* Compare old and new external routing table and install the
592
0
       difference info zebra/kernel */
593
0
    ospf_ase_compare_tables(ospf, ospf->new_external_route,
594
0
          ospf->old_external_route);
595
0
596
0
    /* Delete old external routing table */
597
0
    ospf_route_table_free(ospf->old_external_route);
598
0
    ospf->old_external_route = ospf->new_external_route;
599
0
    ospf->new_external_route = route_table_init();
600
0
601
0
    monotime(&stop_time);
602
0
603
0
    if (IS_DEBUG_OSPF_EVENT)
604
0
      zlog_info(
605
0
        "SPF Processing Time(usecs): External Routes: %lld",
606
0
        (stop_time.tv_sec - start_time.tv_sec)
607
0
            * 1000000LL
608
0
          + (stop_time.tv_usec
609
0
             - start_time.tv_usec));
610
0
  }
611
0
612
0
  /*
613
0
   * Uninstall remnant routes that were installed before the restart, but
614
0
   * that are no longer valid.
615
0
   */
616
0
  if (ospf->gr_info.finishing_restart) {
617
0
    ospf_zebra_gr_disable(ospf);
618
0
    ospf_zebra_gr_enable(ospf, ospf->gr_info.grace_period);
619
0
    ospf->gr_info.finishing_restart = false;
620
0
  }
621
0
}
622
623
void ospf_ase_calculate_schedule(struct ospf *ospf)
624
0
{
625
0
  if (ospf == NULL)
626
0
    return;
627
628
0
  ospf->ase_calc = 1;
629
0
}
630
631
void ospf_ase_calculate_timer_add(struct ospf *ospf)
632
0
{
633
0
  if (ospf == NULL)
634
0
    return;
635
636
0
  event_add_timer(master, ospf_ase_calculate_timer, ospf,
637
0
      OSPF_ASE_CALC_INTERVAL, &ospf->t_ase_calc);
638
0
}
639
640
void ospf_ase_register_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
641
164
{
642
164
  struct route_node *rn;
643
164
  struct prefix_ipv4 p;
644
164
  struct list *lst;
645
164
  struct as_external_lsa *al;
646
647
164
  al = (struct as_external_lsa *)lsa->data;
648
164
  p.family = AF_INET;
649
164
  p.prefix = lsa->data->id;
650
164
  p.prefixlen = ip_masklen(al->mask);
651
164
  apply_mask_ipv4(&p);
652
653
164
  rn = route_node_get(top->external_lsas, (struct prefix *)&p);
654
164
  if ((lst = rn->info) == NULL)
655
37
    rn->info = lst = list_new();
656
127
  else
657
127
    route_unlock_node(rn);
658
659
  /* We assume that if LSA is deleted from DB
660
     is is also deleted from this RT */
661
164
  listnode_add(lst, ospf_lsa_lock(lsa)); /* external_lsas lst */
662
164
}
663
664
void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
665
0
{
666
0
  struct route_node *rn;
667
0
  struct prefix_ipv4 p;
668
0
  struct list *lst;
669
0
  struct as_external_lsa *al;
670
671
0
  al = (struct as_external_lsa *)lsa->data;
672
0
  p.family = AF_INET;
673
0
  p.prefix = lsa->data->id;
674
0
  p.prefixlen = ip_masklen(al->mask);
675
0
  apply_mask_ipv4(&p);
676
677
0
  rn = route_node_lookup(top->external_lsas, (struct prefix *)&p);
678
679
0
  if (rn) {
680
0
    lst = rn->info;
681
0
    struct listnode *node = listnode_lookup(lst, lsa);
682
    /* Unlock lsa only if node is present in the list */
683
0
    if (node) {
684
0
      listnode_delete(lst, lsa);
685
0
      ospf_lsa_unlock(&lsa); /* external_lsas list */
686
0
    }
687
688
0
    route_unlock_node(rn);
689
0
  }
690
0
}
691
692
void ospf_ase_external_lsas_finish(struct route_table *rt)
693
0
{
694
0
  struct route_node *rn;
695
0
  struct ospf_lsa *lsa;
696
0
  struct list *lst;
697
0
  struct listnode *node, *nnode;
698
699
0
  for (rn = route_top(rt); rn; rn = route_next(rn))
700
0
    if ((lst = rn->info) != NULL) {
701
0
      for (ALL_LIST_ELEMENTS(lst, node, nnode, lsa))
702
0
        ospf_lsa_unlock(&lsa); /* external_lsas lst */
703
0
      list_delete(&lst);
704
0
    }
705
706
0
  route_table_finish(rt);
707
0
}
708
709
void ospf_ase_incremental_update(struct ospf *ospf, struct ospf_lsa *lsa)
710
61
{
711
61
  struct list *lsas;
712
61
  struct listnode *node;
713
61
  struct route_node *rn, *rn2;
714
61
  struct prefix_ipv4 p;
715
61
  struct route_table *tmp_old;
716
61
  struct as_external_lsa *al;
717
718
61
  al = (struct as_external_lsa *)lsa->data;
719
61
  p.family = AF_INET;
720
61
  p.prefix = lsa->data->id;
721
61
  p.prefixlen = ip_masklen(al->mask);
722
61
  apply_mask_ipv4(&p);
723
724
  /* if new_table is NULL, there was no spf calculation, thus
725
     incremental update is unneeded */
726
61
  if (!ospf->new_table)
727
61
    return;
728
729
  /* If there is already an intra-area or inter-area route
730
     to the destination, no recalculation is necessary
731
     (internal routes take precedence). */
732
733
0
  rn = route_node_lookup(ospf->new_table, (struct prefix *)&p);
734
0
  if (rn) {
735
0
    route_unlock_node(rn);
736
0
    if (rn->info)
737
0
      return;
738
0
  }
739
740
0
  rn = route_node_lookup(ospf->external_lsas, (struct prefix *)&p);
741
0
  assert(rn);
742
0
  assert(rn->info);
743
0
  lsas = rn->info;
744
0
  route_unlock_node(rn);
745
746
0
  for (ALL_LIST_ELEMENTS_RO(lsas, node, lsa))
747
0
    ospf_ase_calculate_route(ospf, lsa);
748
749
  /* prepare temporary old routing table for compare */
750
0
  tmp_old = route_table_init();
751
0
  rn = route_node_lookup(ospf->old_external_route, (struct prefix *)&p);
752
0
  if (rn && rn->info) {
753
0
    rn2 = route_node_get(tmp_old, (struct prefix *)&p);
754
0
    rn2->info = rn->info;
755
0
    route_unlock_node(rn);
756
0
  }
757
758
  /* install changes to zebra */
759
0
  ospf_ase_compare_tables(ospf, ospf->new_external_route, tmp_old);
760
761
  /* update ospf->old_external_route table */
762
0
  if (rn && rn->info)
763
0
    ospf_route_free((struct ospf_route *)rn->info);
764
765
0
  rn2 = route_node_lookup(ospf->new_external_route, (struct prefix *)&p);
766
  /* if new route exists, install it to ospf->old_external_route */
767
0
  if (rn2 && rn2->info) {
768
0
    if (!rn)
769
0
      rn = route_node_get(ospf->old_external_route,
770
0
              (struct prefix *)&p);
771
0
    rn->info = rn2->info;
772
0
  } else {
773
    /* remove route node from ospf->old_external_route */
774
0
    if (rn) {
775
0
      rn->info = NULL;
776
0
      route_unlock_node(rn);
777
0
    }
778
0
  }
779
780
0
  if (rn2) {
781
    /* rn2->info is stored in route node of ospf->old_external_route
782
     */
783
0
    rn2->info = NULL;
784
0
    route_unlock_node(rn2);
785
0
    route_unlock_node(rn2);
786
0
  }
787
788
0
  route_table_finish(tmp_old);
789
0
}