Coverage Report

Created: 2025-07-14 06:48

/src/frr/ospfd/ospf_asbr.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * OSPF AS Boundary Router functions.
4
 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
5
 */
6
7
#include <zebra.h>
8
9
#include "frrevent.h"
10
#include "memory.h"
11
#include "linklist.h"
12
#include "prefix.h"
13
#include "if.h"
14
#include "table.h"
15
#include "vty.h"
16
#include "filter.h"
17
#include "log.h"
18
19
#include "ospfd/ospfd.h"
20
#include "ospfd/ospf_interface.h"
21
#include "ospfd/ospf_asbr.h"
22
#include "ospfd/ospf_lsa.h"
23
#include "ospfd/ospf_lsdb.h"
24
#include "ospfd/ospf_neighbor.h"
25
#include "ospfd/ospf_spf.h"
26
#include "ospfd/ospf_flood.h"
27
#include "ospfd/ospf_route.h"
28
#include "ospfd/ospf_zebra.h"
29
#include "ospfd/ospf_dump.h"
30
#include "ospfd/ospf_errors.h"
31
32
/* Remove external route. */
33
void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p)
34
0
{
35
0
  struct route_node *rn;
36
0
  struct ospf_route * or ;
37
38
0
  rn = route_node_lookup(ospf->old_external_route, (struct prefix *)p);
39
0
  if (rn)
40
0
    if ((or = rn->info)) {
41
0
      zlog_info("Route[%pFX]: external path deleted", p);
42
43
      /* Remove route from zebra. */
44
0
      if (or->type == OSPF_DESTINATION_NETWORK)
45
0
        ospf_zebra_delete(
46
0
          ospf, (struct prefix_ipv4 *)&rn->p, or);
47
48
0
      ospf_route_free(or);
49
0
      rn->info = NULL;
50
51
0
      route_unlock_node(rn);
52
0
      route_unlock_node(rn);
53
0
      return;
54
0
    }
55
56
0
  zlog_info("Route[%pFX]: no such external path", p);
57
0
}
58
59
/* Add an External info for AS-external-LSA. */
60
struct external_info *ospf_external_info_new(struct ospf *ospf, uint8_t type,
61
               unsigned short instance)
62
0
{
63
0
  struct external_info *new;
64
65
0
  new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info));
66
0
  new->ospf = ospf;
67
0
  new->type = type;
68
0
  new->instance = instance;
69
0
  new->to_be_processed = 0;
70
71
0
  ospf_reset_route_map_set_values(&new->route_map_set);
72
0
  return new;
73
0
}
74
75
static void ospf_external_info_free(struct external_info *ei)
76
0
{
77
0
  XFREE(MTYPE_OSPF_EXTERNAL_INFO, ei);
78
0
}
79
80
void ospf_reset_route_map_set_values(struct route_map_set_values *values)
81
0
{
82
0
  values->metric = -1;
83
0
  values->metric_type = -1;
84
0
}
85
86
int ospf_route_map_set_compare(struct route_map_set_values *values1,
87
             struct route_map_set_values *values2)
88
0
{
89
0
  return values1->metric == values2->metric
90
0
         && values1->metric_type == values2->metric_type;
91
0
}
92
93
/* Add an External info for AS-external-LSA. */
94
struct external_info *
95
ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance,
96
           struct prefix_ipv4 p, ifindex_t ifindex,
97
           struct in_addr nexthop, route_tag_t tag, uint32_t metric)
98
0
{
99
0
  struct external_info *new;
100
0
  struct route_node *rn;
101
0
  struct ospf_external *ext;
102
103
0
  ext = ospf_external_lookup(ospf, type, instance);
104
0
  if (!ext)
105
0
    ext = ospf_external_add(ospf, type, instance);
106
107
0
  rn = route_node_get(EXTERNAL_INFO(ext), (struct prefix *)&p);
108
  /* If old info exists, -- discard new one or overwrite with new one? */
109
0
  if (rn && rn->info) {
110
0
    new = rn->info;
111
0
    if ((new->ifindex == ifindex)
112
0
        && (new->nexthop.s_addr == nexthop.s_addr)
113
0
        && (new->tag == tag)) {
114
0
      route_unlock_node(rn);
115
0
      return NULL; /* NULL => no LSA to refresh */
116
0
    }
117
118
0
    if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
119
0
      zlog_debug(
120
0
        "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
121
0
        ospf_redist_string(type), instance,
122
0
        ospf->vrf_id, &p, &nexthop.s_addr);
123
0
    XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
124
0
  }
125
126
  /* Create new External info instance. */
127
0
  new = ospf_external_info_new(ospf, type, instance);
128
0
  new->p = p;
129
0
  new->ifindex = ifindex;
130
0
  new->nexthop = nexthop;
131
0
  new->tag = tag;
132
0
  new->orig_tag = tag;
133
0
  new->aggr_route = NULL;
134
0
  new->metric = metric;
135
0
  new->min_metric = 0;
136
0
  new->max_metric = OSPF_LS_INFINITY;
137
138
  /* we don't unlock rn from the get() because we're attaching the info */
139
0
  if (rn)
140
0
    rn->info = new;
141
142
0
  if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
143
0
    zlog_debug(
144
0
      "Redistribute[%s][%u]: %pFX external info created, with NH %pI4, metric:%u",
145
0
      ospf_redist_string(type), ospf->vrf_id, &p,
146
0
      &nexthop.s_addr, metric);
147
0
  }
148
0
  return new;
149
0
}
150
151
void ospf_external_info_delete(struct ospf *ospf, uint8_t type,
152
             unsigned short instance, struct prefix_ipv4 p)
153
0
{
154
0
  struct route_node *rn;
155
0
  struct ospf_external *ext;
156
157
0
  ext = ospf_external_lookup(ospf, type, instance);
158
0
  if (!ext)
159
0
    return;
160
161
0
  rn = route_node_lookup(EXTERNAL_INFO(ext), (struct prefix *)&p);
162
0
  if (rn) {
163
0
    ospf_external_info_free(rn->info);
164
0
    rn->info = NULL;
165
0
    route_unlock_node(rn);
166
0
    route_unlock_node(rn);
167
0
  }
168
0
}
169
170
struct external_info *ospf_external_info_lookup(struct ospf *ospf, uint8_t type,
171
            unsigned short instance,
172
            struct prefix_ipv4 *p)
173
0
{
174
0
  struct route_node *rn;
175
0
  struct ospf_external *ext;
176
177
0
  ext = ospf_external_lookup(ospf, type, instance);
178
0
  if (!ext)
179
0
    return NULL;
180
181
0
  rn = route_node_lookup(EXTERNAL_INFO(ext), (struct prefix *)p);
182
0
  if (rn) {
183
0
    route_unlock_node(rn);
184
0
    if (rn->info)
185
0
      return rn->info;
186
0
  }
187
188
0
  return NULL;
189
0
}
190
191
struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf,
192
               struct prefix_ipv4 *p)
193
0
{
194
0
  struct ospf_lsa *lsa;
195
0
  struct as_external_lsa *al;
196
0
  struct in_addr mask, id;
197
198
  /* First search the lsdb with address specific LSID
199
   * where all the host bits are set, if there a matched
200
   * LSA, return.
201
   * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255
202
   * If no lsa with above LSID, use received address as
203
   * LSID and check if any LSA in LSDB.
204
   * If LSA found, check if the mask is same b/w the matched
205
   * LSA and received prefix, if same then it is the LSA for
206
   * this prefix.
207
   * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0
208
   */
209
210
0
  masklen2ip(p->prefixlen, &mask);
211
0
  id.s_addr = p->prefix.s_addr | (~mask.s_addr);
212
0
  lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id,
213
0
             ospf->router_id);
214
0
  if (lsa) {
215
0
    if (p->prefixlen == IPV4_MAX_BITLEN) {
216
0
      al = (struct as_external_lsa *)lsa->data;
217
218
0
      if (mask.s_addr != al->mask.s_addr)
219
0
        return NULL;
220
0
    }
221
0
    return lsa;
222
0
  }
223
224
0
  lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
225
0
             p->prefix, ospf->router_id);
226
227
0
  if (lsa) {
228
0
    al = (struct as_external_lsa *)lsa->data;
229
0
    if (mask.s_addr == al->mask.s_addr)
230
0
      return lsa;
231
0
  }
232
233
0
  return NULL;
234
0
}
235
236
237
/* Update ASBR status. */
238
void ospf_asbr_status_update(struct ospf *ospf, uint8_t status)
239
0
{
240
0
  zlog_info("ASBR[%s:Status:%d]: Update",
241
0
      ospf_get_name(ospf), status);
242
243
  /* ASBR on. */
244
0
  if (status) {
245
    /* Already ASBR. */
246
0
    if (IS_OSPF_ASBR(ospf)) {
247
0
      zlog_info("ASBR[%s:Status:%d]: Already ASBR",
248
0
          ospf_get_name(ospf), status);
249
0
      return;
250
0
    }
251
0
    SET_FLAG(ospf->flags, OSPF_FLAG_ASBR);
252
0
  } else {
253
    /* Already non ASBR. */
254
0
    if (!IS_OSPF_ASBR(ospf)) {
255
0
      zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
256
0
          ospf_get_name(ospf), status);
257
0
      return;
258
0
    }
259
0
    UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR);
260
0
  }
261
262
  /* Transition from/to status ASBR, schedule timer. */
263
0
  ospf_spf_calculate_schedule(ospf, SPF_FLAG_ASBR_STATUS_CHANGE);
264
0
  ospf_router_lsa_update(ospf);
265
0
}
266
267
/* If there's redistribution configured, we need to refresh external
268
 * LSAs in order to install Type-7 and flood to all NSSA Areas
269
 */
270
static void ospf_asbr_nssa_redist_update_timer(struct event *thread)
271
0
{
272
0
  struct ospf *ospf = EVENT_ARG(thread);
273
0
  int type;
274
0
275
0
  ospf->t_asbr_nssa_redist_update = NULL;
276
0
277
0
  if (IS_DEBUG_OSPF_EVENT)
278
0
    zlog_debug("Running ASBR NSSA redistribution update on timer");
279
0
280
0
  for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
281
0
    struct list *red_list;
282
0
    struct listnode *node;
283
0
    struct ospf_redist *red;
284
0
285
0
    red_list = ospf->redist[type];
286
0
    if (!red_list)
287
0
      continue;
288
0
289
0
    for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
290
0
      ospf_external_lsa_refresh_type(ospf, type,
291
0
                   red->instance,
292
0
                   LSA_REFRESH_FORCE);
293
0
  }
294
0
295
0
  ospf_external_lsa_refresh_default(ospf);
296
0
}
297
298
void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf)
299
0
{
300
0
  if (IS_DEBUG_OSPF_EVENT)
301
0
    zlog_debug("Scheduling ASBR NSSA redistribution update");
302
303
0
  event_add_timer(master, ospf_asbr_nssa_redist_update_timer, ospf,
304
0
      OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY,
305
0
      &ospf->t_asbr_nssa_redist_update);
306
0
}
307
308
void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,
309
        unsigned short instance)
310
0
{
311
0
  struct route_node *rn;
312
0
  struct external_info *ei;
313
0
  struct ospf_external *ext;
314
315
0
  ext = ospf_external_lookup(ospf, type, instance);
316
0
  if (!ext)
317
0
    return;
318
319
  /* Delete external info for specified type. */
320
0
  if (!EXTERNAL_INFO(ext))
321
0
    return;
322
323
0
  for (rn = route_top(EXTERNAL_INFO(ext)); rn; rn = route_next(rn)) {
324
0
    ei = rn->info;
325
326
0
    if (!ei)
327
0
      continue;
328
329
0
    struct ospf_external_aggr_rt *aggr;
330
331
0
    if (is_default_prefix4(&ei->p)
332
0
        && ospf->default_originate != DEFAULT_ORIGINATE_NONE)
333
0
      continue;
334
335
0
    aggr = ei->aggr_route;
336
337
0
    if (aggr)
338
0
      ospf_unlink_ei_from_aggr(ospf, aggr, ei);
339
0
    else if (ospf_external_info_find_lsa(ospf, &ei->p))
340
0
      ospf_external_lsa_flush(ospf, type, &ei->p,
341
0
            ei->ifindex /*, ei->nexthop */);
342
343
0
    ospf_external_info_free(ei);
344
0
    route_unlock_node(rn);
345
0
    rn->info = NULL;
346
0
  }
347
0
}
348
349
350
/* External Route Aggregator Handlers */
351
bool is_valid_summary_addr(struct prefix_ipv4 *p)
352
0
{
353
  /* Default prefix validation*/
354
0
  if (p->prefix.s_addr == INADDR_ANY)
355
0
    return false;
356
357
  /*Host route shouldn't be configured as summary addres*/
358
0
  if (p->prefixlen == IPV4_MAX_BITLEN)
359
0
    return false;
360
361
0
  return true;
362
0
}
363
void ospf_asbr_external_aggregator_init(struct ospf *instance)
364
1
{
365
1
  instance->rt_aggr_tbl = route_table_init();
366
367
1
  instance->t_external_aggr = NULL;
368
369
1
  instance->aggr_action = 0;
370
371
1
  instance->aggr_delay_interval = OSPF_EXTL_AGGR_DEFAULT_DELAY;
372
1
}
373
374
static unsigned int ospf_external_rt_hash_key(const void *data)
375
0
{
376
0
  const struct external_info *ei = data;
377
0
  unsigned int key = 0;
378
379
0
  key = prefix_hash_key(&ei->p);
380
0
  return key;
381
0
}
382
383
static bool ospf_external_rt_hash_cmp(const void *d1, const void *d2)
384
0
{
385
0
  const struct external_info *ei1 = d1;
386
0
  const struct external_info *ei2 = d2;
387
388
0
  return prefix_same((struct prefix *)&ei1->p, (struct prefix *)&ei2->p);
389
0
}
390
391
static struct ospf_external_aggr_rt *
392
ospf_external_aggregator_new(struct prefix_ipv4 *p)
393
0
{
394
0
  struct ospf_external_aggr_rt *aggr;
395
396
0
  aggr = (struct ospf_external_aggr_rt *)XCALLOC(
397
0
    MTYPE_OSPF_EXTERNAL_RT_AGGR,
398
0
    sizeof(struct ospf_external_aggr_rt));
399
400
0
  if (!aggr)
401
0
    return NULL;
402
403
0
  aggr->p.family = p->family;
404
0
  aggr->p.prefix = p->prefix;
405
0
  aggr->p.prefixlen = p->prefixlen;
406
0
  aggr->match_extnl_hash = hash_create(ospf_external_rt_hash_key,
407
0
               ospf_external_rt_hash_cmp,
408
0
               "Ospf external route hash");
409
0
  return aggr;
410
0
}
411
412
static void ospf_aggr_handle_external_info(void *data)
413
0
{
414
0
  struct external_info *ei = (struct external_info *)data;
415
0
  struct ospf_external_aggr_rt *aggr = NULL;
416
0
  struct ospf *ospf = ei->ospf;
417
0
  struct ospf_lsa *lsa = NULL;
418
0
419
0
  ei->aggr_route = NULL;
420
0
421
0
  ei->to_be_processed = true;
422
0
423
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
424
0
    zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__,
425
0
         &ei->p.prefix, ei->p.prefixlen);
426
0
427
0
  assert(ospf);
428
0
429
0
  if (!ospf_redistribute_check(ospf, ei, NULL))
430
0
    return;
431
0
432
0
  aggr = ospf_external_aggr_match(ospf, &ei->p);
433
0
  if (aggr) {
434
0
    (void)ospf_originate_summary_lsa(ospf, aggr, ei);
435
0
    return;
436
0
  }
437
0
438
0
  lsa = ospf_external_info_find_lsa(ospf, &ei->p);
439
0
  if (lsa)
440
0
    ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 1);
441
0
  else
442
0
    (void)ospf_external_lsa_originate(ospf, ei);
443
0
}
444
445
static void ospf_aggr_unlink_external_info(void *data)
446
0
{
447
0
  struct external_info *ei = (struct external_info *)data;
448
449
0
  ei->aggr_route = NULL;
450
451
0
  ei->to_be_processed = true;
452
0
}
453
454
void ospf_external_aggregator_free(struct ospf_external_aggr_rt *aggr)
455
0
{
456
0
  hash_clean_and_free(&aggr->match_extnl_hash,
457
0
          (void *)ospf_aggr_unlink_external_info);
458
459
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
460
0
    zlog_debug("%s: Release the aggregator Address(%pI4/%d)",
461
0
         __func__, &aggr->p.prefix, aggr->p.prefixlen);
462
463
0
  XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr);
464
0
}
465
466
static void ospf_external_aggr_add(struct ospf *ospf,
467
           struct ospf_external_aggr_rt *aggr)
468
0
{
469
0
  struct route_node *rn;
470
471
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
472
0
    zlog_debug("%s: Adding Aggregate route to Aggr table (%pI4/%d)",
473
0
         __func__, &aggr->p.prefix, aggr->p.prefixlen);
474
0
  rn = route_node_get(ospf->rt_aggr_tbl, (struct prefix *)&aggr->p);
475
0
  if (rn->info)
476
0
    route_unlock_node(rn);
477
0
  else
478
0
    rn->info = aggr;
479
0
}
480
481
static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn)
482
0
{
483
0
  struct ospf_external_aggr_rt *aggr = rn->info;
484
485
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
486
0
    zlog_debug("%s: Deleting Aggregate route (%pI4/%d)", __func__,
487
0
         &aggr->p.prefix, aggr->p.prefixlen);
488
489
  /* Sent a Max age LSA if it is already originated. */
490
0
  if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
491
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
492
0
      zlog_debug("%s: Flushing Aggregate route (%pI4/%d)",
493
0
           __func__, &aggr->p.prefix,
494
0
           aggr->p.prefixlen);
495
0
    ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
496
0
  }
497
498
0
  rn->info = NULL;
499
0
  route_unlock_node(rn);
500
0
}
501
502
struct ospf_external_aggr_rt *
503
ospf_extrenal_aggregator_lookup(struct ospf *ospf, struct prefix_ipv4 *p)
504
103
{
505
103
  struct route_node *rn;
506
103
  struct ospf_external_aggr_rt *summary_rt = NULL;
507
508
103
  rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
509
103
  if (rn) {
510
0
    summary_rt = rn->info;
511
0
    route_unlock_node(rn);
512
0
    return summary_rt;
513
0
  }
514
103
  return NULL;
515
103
}
516
517
struct ospf_external_aggr_rt *ospf_external_aggr_match(struct ospf *ospf,
518
                   struct prefix_ipv4 *p)
519
0
{
520
0
  struct route_node *node;
521
0
  struct ospf_external_aggr_rt *summary_rt = NULL;
522
523
0
  node = route_node_match(ospf->rt_aggr_tbl, (struct prefix *)p);
524
0
  if (node) {
525
526
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
527
0
      if (node->info) {
528
0
        struct ospf_external_aggr_rt *ag = node->info;
529
530
0
        zlog_debug(
531
0
          "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d",
532
0
          __func__, &p->prefix, p->prefixlen,
533
0
          &ag->p.prefix, ag->p.prefixlen);
534
0
      }
535
536
0
    summary_rt = node->info;
537
0
    route_unlock_node(node);
538
0
    return summary_rt;
539
0
  }
540
0
  return NULL;
541
0
}
542
543
void ospf_unlink_ei_from_aggr(struct ospf *ospf,
544
            struct ospf_external_aggr_rt *aggr,
545
            struct external_info *ei)
546
0
{
547
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
548
0
    zlog_debug(
549
0
      "%s: Unlinking extrenal route(%pI4/%d) from aggregator(%pI4/%d), external route count:%ld",
550
0
      __func__, &ei->p.prefix, ei->p.prefixlen,
551
0
      &aggr->p.prefix, aggr->p.prefixlen,
552
0
      OSPF_EXTERNAL_RT_COUNT(aggr));
553
0
  hash_release(aggr->match_extnl_hash, ei);
554
0
  ei->aggr_route = NULL;
555
556
  /* Flush the aggreagte route if matching
557
   * external route count becomes zero.
558
   */
559
0
  if (!OSPF_EXTERNAL_RT_COUNT(aggr)
560
0
      && CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
561
562
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
563
0
      zlog_debug("%s: Flushing the aggreagte route (%pI4/%d)",
564
0
           __func__, &aggr->p.prefix,
565
0
           aggr->p.prefixlen);
566
567
    /* Flush the aggregate LSA */
568
0
    ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
569
570
    /* Unset the Origination flag */
571
0
    UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
572
0
  }
573
0
}
574
575
static void ospf_link_ei_to_aggr(struct ospf_external_aggr_rt *aggr,
576
         struct external_info *ei)
577
0
{
578
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
579
0
    zlog_debug(
580
0
      "%s: Linking extrenal route(%pI4/%d) to aggregator(%pI4/%d)",
581
0
      __func__, &ei->p.prefix, ei->p.prefixlen,
582
0
      &aggr->p.prefix, aggr->p.prefixlen);
583
0
  (void)hash_get(aggr->match_extnl_hash, ei, hash_alloc_intern);
584
0
  ei->aggr_route = aggr;
585
0
}
586
587
struct ospf_lsa *ospf_originate_summary_lsa(struct ospf *ospf,
588
              struct ospf_external_aggr_rt *aggr,
589
              struct external_info *ei)
590
0
{
591
0
  struct ospf_lsa *lsa;
592
0
  struct external_info ei_aggr;
593
0
  struct as_external_lsa *asel;
594
0
  struct ospf_external_aggr_rt *old_aggr;
595
0
  route_tag_t tag = 0;
596
597
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
598
0
    zlog_debug("%s: Prepare to originate Summary route(%pI4/%d)",
599
0
         __func__, &aggr->p.prefix, aggr->p.prefixlen);
600
601
  /* This case to handle when the overlapping aggregator address
602
   * is availbe.Best match will be considered.So need to delink
603
   * from old aggregator and link to the new aggr.
604
   */
605
0
  if (ei->aggr_route) {
606
0
    if (ei->aggr_route != aggr) {
607
0
      old_aggr = ei->aggr_route;
608
0
      ospf_unlink_ei_from_aggr(ospf, old_aggr, ei);
609
0
    }
610
0
  }
611
612
  /* Add the external route to hash table */
613
0
  ospf_link_ei_to_aggr(aggr, ei);
614
615
0
  lsa = ospf_external_info_find_lsa(ospf, &aggr->p);
616
  /* Don't originate external LSA,
617
   * If it is configured not to advertise.
618
   */
619
0
  if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
620
    /* If it is already originated as external LSA,
621
     * But, it is configured not to advertise then
622
     * flush the originated external lsa.
623
     */
624
0
    if (lsa)
625
0
      ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
626
0
    UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
627
628
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
629
0
      zlog_debug(
630
0
        "%s: Don't originate the summary address,It is configured to not-advertise.",
631
0
        __func__);
632
0
    return NULL;
633
0
  }
634
635
  /* Prepare the extrenal_info for aggregator */
636
0
  memset(&ei_aggr, 0, sizeof(ei_aggr));
637
0
  ei_aggr.p = aggr->p;
638
0
  ei_aggr.tag = aggr->tag;
639
0
  ei_aggr.type = 0;
640
0
  ei_aggr.instance = ospf->instance;
641
0
  ei_aggr.route_map_set.metric = -1;
642
0
  ei_aggr.route_map_set.metric_type = -1;
643
644
  /* Summary route already originated,
645
   * So, Do nothing.
646
   */
647
0
  if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
648
0
    if (!lsa) {
649
0
      flog_warn(EC_OSPF_LSA_MISSING,
650
0
          "%s: Could not refresh/originate %pI4/%d",
651
0
          __func__, &aggr->p.prefix, aggr->p.prefixlen);
652
0
      return NULL;
653
0
    }
654
655
0
    asel = (struct as_external_lsa *)lsa->data;
656
0
    tag = (unsigned long)ntohl(asel->e[0].route_tag);
657
658
    /* If tag modified , then re-originate the route
659
     * with modified tag details.
660
     */
661
0
    if (tag != ei_aggr.tag) {
662
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
663
0
        zlog_debug(
664
0
          "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
665
0
          __func__, tag, ei_aggr.tag,
666
0
          &aggr->p.prefix, aggr->p.prefixlen);
667
668
0
      ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
669
0
              LSA_REFRESH_FORCE, 1);
670
0
    }
671
0
    return lsa;
672
0
  }
673
674
0
  if (lsa && IS_LSA_MAXAGE(lsa)) {
675
    /* This is special case.
676
     * If a summary route need to be originated but where
677
     * summary route already exist in lsdb with maxage, then
678
     * it need to be refreshed.
679
     */
680
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
681
0
      zlog_debug(
682
0
        "%s: LSA is in MAX-AGE so refreshing LSA(%pI4/%d)",
683
0
        __func__, &aggr->p.prefix, aggr->p.prefixlen);
684
685
0
    ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
686
0
            LSA_REFRESH_FORCE, 1);
687
0
    SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
688
0
    return lsa;
689
0
  }
690
691
  /* If the external route prefix same as aggregate route
692
   * and if external route is already originated as TYPE-5
693
   * then it need to be refreshed and originate bit should
694
   * be set.
695
   */
696
0
  if (lsa && prefix_same((struct prefix *)&ei_aggr.p,
697
0
             (struct prefix *)&ei->p)) {
698
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
699
0
      zlog_debug(
700
0
        "%s: External route prefix is same as aggr so refreshing LSA(%pI4/%d)",
701
0
        __func__, &aggr->p.prefix, aggr->p.prefixlen);
702
0
    ospf_external_lsa_refresh(ospf, lsa, &ei_aggr,
703
0
            LSA_REFRESH_FORCE, 1);
704
0
    SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
705
0
    return lsa;
706
0
  }
707
708
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
709
0
    zlog_debug("%s: Originate Summary route(%pI4/%d)", __func__,
710
0
         &aggr->p.prefix, aggr->p.prefixlen);
711
712
  /* Originate summary LSA */
713
0
  lsa = ospf_external_lsa_originate(ospf, &ei_aggr);
714
0
  if (lsa) {
715
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
716
0
      zlog_debug("%s: Set the origination bit for aggregator",
717
0
           __func__);
718
0
    SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
719
0
  }
720
721
0
  return lsa;
722
0
}
723
void ospf_unset_all_aggr_flag(struct ospf *ospf)
724
0
{
725
0
  struct route_node *rn = NULL;
726
727
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
728
0
    zlog_debug("Unset the origination bit for all aggregator");
729
730
0
  for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
731
0
    if (!rn->info)
732
0
      continue;
733
734
0
    struct ospf_external_aggr_rt *aggr = rn->info;
735
736
0
    UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
737
0
  }
738
0
}
739
740
static void ospf_delete_all_marked_aggregators(struct ospf *ospf)
741
0
{
742
0
  struct route_node *rn = NULL;
743
0
744
0
  /* Loop through all the aggregators, Delete all aggregators
745
0
   * which are marked as DELETE. Set action to NONE for remaining
746
0
   * aggregators
747
0
   */
748
0
  for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
749
0
    if (!rn->info)
750
0
      continue;
751
0
752
0
    struct ospf_external_aggr_rt *aggr = rn->info;
753
0
754
0
    if (aggr->action != OSPF_ROUTE_AGGR_DEL) {
755
0
      aggr->action = OSPF_ROUTE_AGGR_NONE;
756
0
      continue;
757
0
    }
758
0
    ospf_external_aggr_delete(ospf, rn);
759
0
    ospf_external_aggregator_free(aggr);
760
0
  }
761
0
}
762
763
static void ospf_handle_aggregated_exnl_rt(struct ospf *ospf,
764
             struct ospf_external_aggr_rt *aggr,
765
             struct external_info *ei)
766
0
{
767
0
  struct ospf_lsa *lsa;
768
0
  struct as_external_lsa *al;
769
0
  struct in_addr mask;
770
0
771
0
  /* Handling the case where the external route prefix
772
0
   * and aggregate prefix is same
773
0
   * If same don't flush the originated external LSA.
774
0
   */
775
0
  if (prefix_same((struct prefix *)&aggr->p, (struct prefix *)&ei->p)) {
776
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
777
0
      zlog_debug(
778
0
        "%s: External Route prefix same as Aggregator(%pI4/%d), so don't flush.",
779
0
        __func__, &ei->p.prefix, ei->p.prefixlen);
780
0
    return;
781
0
  }
782
0
783
0
  lsa = ospf_external_info_find_lsa(ospf, &ei->p);
784
0
  if (lsa) {
785
0
    al = (struct as_external_lsa *)lsa->data;
786
0
    masklen2ip(ei->p.prefixlen, &mask);
787
0
788
0
    if (mask.s_addr != al->mask.s_addr)
789
0
      return;
790
0
791
0
    ospf_external_lsa_flush(ospf, ei->type, &ei->p, 0);
792
0
  }
793
0
}
794
795
static void ospf_handle_exnl_rt_after_aggr_del(struct ospf *ospf,
796
                 struct external_info *ei)
797
0
{
798
0
  struct ospf_lsa *lsa;
799
0
800
0
  /* Process only marked external routes.
801
0
   * These routes were part of a deleted
802
0
   * aggregator.So, originate now.
803
0
   */
804
0
  if (!ei->to_be_processed)
805
0
    return;
806
0
807
0
  ei->to_be_processed = false;
808
0
809
0
  lsa = ospf_external_info_find_lsa(ospf, &ei->p);
810
0
811
0
  if (lsa)
812
0
    ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0);
813
0
  else {
814
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
815
0
      zlog_debug("%s: Originate external route(%pI4/%d)",
816
0
           __func__, &ei->p.prefix, ei->p.prefixlen);
817
0
818
0
    ospf_external_lsa_originate(ospf, ei);
819
0
  }
820
0
}
821
822
static void ospf_handle_external_aggr_add(struct ospf *ospf)
823
0
{
824
0
  struct external_info *ei;
825
0
  struct route_node *rn = NULL;
826
0
  struct route_table *rt = NULL;
827
0
  int type = 0;
828
0
829
0
  /* Delete all the aggregators which are marked as
830
0
   * OSPF_ROUTE_AGGR_DEL.
831
0
   */
832
0
  ospf_delete_all_marked_aggregators(ospf);
833
0
834
0
  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
835
0
    struct list *ext_list;
836
0
    struct listnode *node;
837
0
    struct ospf_external *ext;
838
0
    struct ospf_external_aggr_rt *aggr;
839
0
840
0
    ext_list = ospf->external[type];
841
0
    if (!ext_list)
842
0
      continue;
843
0
844
0
    for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
845
0
      rt = ext->external_info;
846
0
      if (!rt)
847
0
        continue;
848
0
849
0
      for (rn = route_top(rt); rn; rn = route_next(rn)) {
850
0
        if (!rn->info)
851
0
          continue;
852
0
853
0
        ei = rn->info;
854
0
        if (is_default_prefix4(&ei->p))
855
0
          continue;
856
0
857
0
        /* Check the AS-external-LSA
858
0
         * should be originated.
859
0
         */
860
0
        if (!ospf_redistribute_check(ospf, ei, NULL))
861
0
          continue;
862
0
863
0
        aggr = ospf_external_aggr_match(ospf, &ei->p);
864
0
865
0
        /* If matching aggregator found, Add
866
0
         * the external route reference to the
867
0
         * aggregator and originate the aggr
868
0
         * route if it is advertisable.
869
0
         * flush the external LSA if it is
870
0
         * already originated for this external
871
0
         * prefix.
872
0
         */
873
0
        if (aggr) {
874
0
          ospf_originate_summary_lsa(ospf, aggr,
875
0
                   ei);
876
0
877
0
          /* All aggregated external rts
878
0
           * are handled here.
879
0
           */
880
0
          ospf_handle_aggregated_exnl_rt(
881
0
            ospf, aggr, ei);
882
0
          continue;
883
0
        }
884
0
885
0
        /* External routes which are only out
886
0
         * of aggregation will be handled here.
887
0
         */
888
0
        ospf_handle_exnl_rt_after_aggr_del(ospf, ei);
889
0
      }
890
0
    }
891
0
  }
892
0
}
893
894
static void
895
ospf_aggr_handle_advertise_change(struct ospf *ospf,
896
          struct ospf_external_aggr_rt *aggr,
897
          struct external_info *ei_aggr)
898
0
{
899
0
  struct ospf_lsa *lsa;
900
0
901
0
  /* Check if advertise option modified. */
902
0
  if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE)) {
903
0
904
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
905
0
      zlog_debug(
906
0
        "%s: Don't originate the summary address,It is configured to not-advertise.",
907
0
        __func__);
908
0
909
0
    if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
910
0
911
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
912
0
        zlog_debug(
913
0
          "%s: No-advertise,So Flush the Aggregate route(%pI4/%d)",
914
0
          __func__, &aggr->p.prefix,
915
0
          aggr->p.prefixlen);
916
0
917
0
      ospf_external_lsa_flush(ospf, 0, &aggr->p, 0);
918
0
919
0
      UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
920
0
    }
921
0
    return;
922
0
  }
923
0
924
0
  if (!CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
925
0
    if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
926
0
      zlog_debug("%s: Now it is advatisable", __func__);
927
0
928
0
    lsa = ospf_external_info_find_lsa(ospf, &ei_aggr->p);
929
0
    if (lsa && IS_LSA_MAXAGE(lsa)) {
930
0
      /* This is special case.
931
0
       * If a summary route need to be originated but where
932
0
       * summary route already exist in lsdb with maxage, then
933
0
       * it need to be refreshed.
934
0
       */
935
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
936
0
        zlog_debug(
937
0
          "%s: It is already with Maxage, So refresh it (%pI4/%d)",
938
0
          __func__, &aggr->p.prefix,
939
0
          aggr->p.prefixlen);
940
0
941
0
      ospf_external_lsa_refresh(ospf, lsa, ei_aggr,
942
0
              LSA_REFRESH_FORCE, 1);
943
0
944
0
      SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_ORIGINATED);
945
0
946
0
    } else {
947
0
948
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
949
0
        zlog_debug(
950
0
          "%s: Originate Aggregate LSA (%pI4/%d)",
951
0
          __func__, &aggr->p.prefix,
952
0
          aggr->p.prefixlen);
953
0
954
0
      /* Originate summary LSA */
955
0
      lsa = ospf_external_lsa_originate(ospf, ei_aggr);
956
0
      if (lsa)
957
0
        SET_FLAG(aggr->flags,
958
0
           OSPF_EXTERNAL_AGGRT_ORIGINATED);
959
0
    }
960
0
  }
961
0
}
962
963
static void ospf_handle_external_aggr_update(struct ospf *ospf)
964
0
{
965
0
  struct route_node *rn = NULL;
966
0
967
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
968
0
    zlog_debug("%s: Process modified aggregators.", __func__);
969
0
970
0
  for (rn = route_top(ospf->rt_aggr_tbl); rn; rn = route_next(rn)) {
971
0
    struct ospf_external_aggr_rt *aggr;
972
0
    struct ospf_lsa *lsa = NULL;
973
0
    struct as_external_lsa *asel = NULL;
974
0
    struct external_info ei_aggr;
975
0
    route_tag_t tag = 0;
976
0
977
0
    if (!rn->info)
978
0
      continue;
979
0
980
0
    aggr = rn->info;
981
0
982
0
    if (aggr->action == OSPF_ROUTE_AGGR_DEL) {
983
0
      aggr->action = OSPF_ROUTE_AGGR_NONE;
984
0
      ospf_external_aggr_delete(ospf, rn);
985
0
986
0
      hash_clean_and_free(
987
0
        &aggr->match_extnl_hash,
988
0
        (void *)ospf_aggr_handle_external_info);
989
0
990
0
    } else if (aggr->action == OSPF_ROUTE_AGGR_MODIFY) {
991
0
992
0
      aggr->action = OSPF_ROUTE_AGGR_NONE;
993
0
994
0
      /* Prepare the extrenal_info for aggregator */
995
0
      memset(&ei_aggr, 0, sizeof(ei_aggr));
996
0
      ei_aggr.p = aggr->p;
997
0
      ei_aggr.tag = aggr->tag;
998
0
      ei_aggr.type = 0;
999
0
      ei_aggr.instance = ospf->instance;
1000
0
      ei_aggr.route_map_set.metric = -1;
1001
0
      ei_aggr.route_map_set.metric_type = -1;
1002
0
1003
0
      /* Check if tag modified */
1004
0
      if (CHECK_FLAG(aggr->flags,
1005
0
               OSPF_EXTERNAL_AGGRT_ORIGINATED)) {
1006
0
        lsa = ospf_external_info_find_lsa(ospf,
1007
0
                  &ei_aggr.p);
1008
0
        if (!lsa) {
1009
0
          flog_warn(EC_OSPF_LSA_MISSING,
1010
0
              "%s: Could not refresh/originate %pI4/%d",
1011
0
              __func__, &aggr->p.prefix,
1012
0
              aggr->p.prefixlen);
1013
0
          continue;
1014
0
        }
1015
0
1016
0
        asel = (struct as_external_lsa *)lsa->data;
1017
0
        tag = (unsigned long)ntohl(
1018
0
          asel->e[0].route_tag);
1019
0
1020
0
        /* If tag modified , then re-originate the
1021
0
         * route with modified tag details.
1022
0
         */
1023
0
        if (tag != ei_aggr.tag) {
1024
0
          if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1025
0
            zlog_debug(
1026
0
              "%s: Route tag changed(old:%d new:%d,So refresh the summary route.(%pI4/%d)",
1027
0
              __func__, tag,
1028
0
              ei_aggr.tag,
1029
0
              &aggr->p.prefix,
1030
0
              aggr->p.prefixlen);
1031
0
1032
0
          ospf_external_lsa_refresh(
1033
0
            ospf, lsa, &ei_aggr,
1034
0
            LSA_REFRESH_FORCE, 1);
1035
0
        }
1036
0
      }
1037
0
1038
0
      /* Advertise option modified ?
1039
0
       * If so, handled it here.
1040
0
       */
1041
0
      ospf_aggr_handle_advertise_change(ospf, aggr, &ei_aggr);
1042
0
    }
1043
0
  }
1044
0
}
1045
1046
static void ospf_asbr_external_aggr_process(struct event *thread)
1047
0
{
1048
0
  struct ospf *ospf = EVENT_ARG(thread);
1049
0
  int operation = 0;
1050
0
1051
0
  ospf->t_external_aggr = NULL;
1052
0
  operation = ospf->aggr_action;
1053
0
1054
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1055
0
    zlog_debug("%s: operation:%d", __func__, operation);
1056
0
1057
0
  switch (operation) {
1058
0
  case OSPF_ROUTE_AGGR_ADD:
1059
0
    ospf_handle_external_aggr_add(ospf);
1060
0
    break;
1061
0
  case OSPF_ROUTE_AGGR_DEL:
1062
0
  case OSPF_ROUTE_AGGR_MODIFY:
1063
0
    ospf_handle_external_aggr_update(ospf);
1064
0
    break;
1065
0
  default:
1066
0
    break;
1067
0
  }
1068
0
}
1069
static void ospf_external_aggr_timer(struct ospf *ospf,
1070
             struct ospf_external_aggr_rt *aggr,
1071
             enum ospf_aggr_action_t operation)
1072
0
{
1073
0
  aggr->action = operation;
1074
1075
0
  if (ospf->t_external_aggr) {
1076
0
    if (ospf->aggr_action == OSPF_ROUTE_AGGR_ADD) {
1077
1078
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1079
0
        zlog_debug(
1080
0
          "%s: Not required to retsart timer,set is already added.",
1081
0
          __func__);
1082
0
      return;
1083
0
    }
1084
1085
0
    if (operation == OSPF_ROUTE_AGGR_ADD) {
1086
0
      if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1087
0
        zlog_debug(
1088
0
          "%s, Restarting Aggregator delay timer.",
1089
0
          __func__);
1090
0
      EVENT_OFF(ospf->t_external_aggr);
1091
0
    }
1092
0
  }
1093
1094
0
  if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
1095
0
    zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
1096
0
         __func__, ospf->aggr_delay_interval);
1097
1098
0
  ospf->aggr_action = operation;
1099
0
  event_add_timer(master, ospf_asbr_external_aggr_process, ospf,
1100
0
      ospf->aggr_delay_interval, &ospf->t_external_aggr);
1101
0
}
1102
1103
int ospf_asbr_external_aggregator_set(struct ospf *ospf, struct prefix_ipv4 *p,
1104
              route_tag_t tag)
1105
0
{
1106
0
  struct ospf_external_aggr_rt *aggregator;
1107
1108
0
  aggregator = ospf_extrenal_aggregator_lookup(ospf, p);
1109
1110
0
  if (aggregator) {
1111
0
    if (CHECK_FLAG(aggregator->flags,
1112
0
             OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1113
0
      UNSET_FLAG(aggregator->flags,
1114
0
           OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1115
0
    else if (aggregator->tag == tag)
1116
0
      return OSPF_SUCCESS;
1117
1118
0
    aggregator->tag = tag;
1119
1120
0
    ospf_external_aggr_timer(ospf, aggregator,
1121
0
           OSPF_ROUTE_AGGR_MODIFY);
1122
0
  } else {
1123
0
    aggregator = ospf_external_aggregator_new(p);
1124
0
    if (!aggregator)
1125
0
      return OSPF_FAILURE;
1126
1127
0
    aggregator->tag = tag;
1128
1129
0
    ospf_external_aggr_add(ospf, aggregator);
1130
0
    ospf_external_aggr_timer(ospf, aggregator, OSPF_ROUTE_AGGR_ADD);
1131
0
  }
1132
1133
0
  return OSPF_SUCCESS;
1134
0
}
1135
1136
int ospf_asbr_external_aggregator_unset(struct ospf *ospf,
1137
          struct prefix_ipv4 *p, route_tag_t tag)
1138
0
{
1139
0
  struct route_node *rn;
1140
0
  struct ospf_external_aggr_rt *aggr;
1141
1142
0
  rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
1143
0
  if (!rn)
1144
0
    return OSPF_INVALID;
1145
0
  route_unlock_node(rn);
1146
1147
0
  aggr = rn->info;
1148
1149
0
  if (tag && (tag != aggr->tag))
1150
0
    return OSPF_INVALID;
1151
1152
0
  if (!OSPF_EXTERNAL_RT_COUNT(aggr)) {
1153
0
    ospf_external_aggr_delete(ospf, rn);
1154
0
    ospf_external_aggregator_free(aggr);
1155
0
    return OSPF_SUCCESS;
1156
0
  }
1157
1158
0
  ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_DEL);
1159
1160
0
  return OSPF_SUCCESS;
1161
0
}
1162
1163
int ospf_asbr_external_rt_no_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
1164
0
{
1165
0
  struct ospf_external_aggr_rt *aggr;
1166
0
  route_tag_t tag = 0;
1167
1168
0
  aggr = ospf_extrenal_aggregator_lookup(ospf, p);
1169
0
  if (aggr) {
1170
0
    if (CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1171
0
      return OSPF_SUCCESS;
1172
1173
0
    SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1174
1175
0
    aggr->tag = tag;
1176
1177
0
    if (!OSPF_EXTERNAL_RT_COUNT(aggr))
1178
0
      return OSPF_SUCCESS;
1179
1180
0
    ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_MODIFY);
1181
0
  } else {
1182
0
    aggr = ospf_external_aggregator_new(p);
1183
1184
0
    if (!aggr)
1185
0
      return OSPF_FAILURE;
1186
1187
0
    SET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1188
0
    ospf_external_aggr_add(ospf, aggr);
1189
0
    ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_ADD);
1190
0
  }
1191
1192
0
  return OSPF_SUCCESS;
1193
0
}
1194
1195
int ospf_asbr_external_rt_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
1196
0
{
1197
0
  struct route_node *rn;
1198
0
  struct ospf_external_aggr_rt *aggr;
1199
1200
0
  rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
1201
0
  if (!rn)
1202
0
    return OSPF_INVALID;
1203
0
  route_unlock_node(rn);
1204
1205
0
  aggr = rn->info;
1206
1207
0
  if (!CHECK_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE))
1208
0
    return OSPF_INVALID;
1209
1210
0
  UNSET_FLAG(aggr->flags, OSPF_EXTERNAL_AGGRT_NO_ADVERTISE);
1211
1212
0
  if (!OSPF_EXTERNAL_RT_COUNT(aggr))
1213
0
    return OSPF_SUCCESS;
1214
1215
0
  ospf_external_aggr_timer(ospf, aggr, OSPF_ROUTE_AGGR_MODIFY);
1216
0
  return OSPF_SUCCESS;
1217
0
}
1218
1219
int ospf_external_aggregator_timer_set(struct ospf *ospf, uint16_t interval)
1220
0
{
1221
0
  ospf->aggr_delay_interval = interval;
1222
0
  return OSPF_SUCCESS;
1223
0
}