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