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