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