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