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