]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * OSPF AS Boundary Router functions. | |
3 | * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada | |
4 | * | |
5 | * This file is part of GNU Zebra. | |
6 | * | |
7 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * GNU Zebra is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
896014f4 DL |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; see the file COPYING; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
718e3744 | 20 | */ |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | #include "thread.h" | |
25 | #include "memory.h" | |
26 | #include "linklist.h" | |
27 | #include "prefix.h" | |
28 | #include "if.h" | |
29 | #include "table.h" | |
30 | #include "vty.h" | |
31 | #include "filter.h" | |
32 | #include "log.h" | |
33 | ||
34 | #include "ospfd/ospfd.h" | |
35 | #include "ospfd/ospf_interface.h" | |
36 | #include "ospfd/ospf_asbr.h" | |
37 | #include "ospfd/ospf_lsa.h" | |
38 | #include "ospfd/ospf_lsdb.h" | |
39 | #include "ospfd/ospf_neighbor.h" | |
40 | #include "ospfd/ospf_spf.h" | |
41 | #include "ospfd/ospf_flood.h" | |
42 | #include "ospfd/ospf_route.h" | |
43 | #include "ospfd/ospf_zebra.h" | |
44 | #include "ospfd/ospf_dump.h" | |
63f0e941 | 45 | #include "ospfd/ospf_errors.h" |
6b0655a2 | 46 | |
718e3744 | 47 | /* Remove external route. */ |
d62a17ae | 48 | void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p) |
718e3744 | 49 | { |
d62a17ae | 50 | struct route_node *rn; |
51 | struct ospf_route * or ; | |
52 | ||
53 | rn = route_node_lookup(ospf->old_external_route, (struct prefix *)p); | |
54 | if (rn) | |
55 | if ((or = rn->info)) { | |
ae32e1c2 | 56 | zlog_info("Route[%pFX]: external path deleted", p); |
d62a17ae | 57 | |
58 | /* Remove route from zebra. */ | |
59 | if (or->type == OSPF_DESTINATION_NETWORK) | |
996c9314 LB |
60 | ospf_zebra_delete( |
61 | ospf, (struct prefix_ipv4 *)&rn->p, or); | |
d62a17ae | 62 | |
63 | ospf_route_free(or); | |
64 | rn->info = NULL; | |
65 | ||
66 | route_unlock_node(rn); | |
67 | route_unlock_node(rn); | |
68 | return; | |
69 | } | |
70 | ||
ae32e1c2 | 71 | zlog_info("Route[%pFX]: no such external path", p); |
718e3744 | 72 | } |
73 | ||
718e3744 | 74 | /* Add an External info for AS-external-LSA. */ |
d7c0a89a QY |
75 | struct external_info *ospf_external_info_new(uint8_t type, |
76 | unsigned short instance) | |
718e3744 | 77 | { |
d62a17ae | 78 | struct external_info *new; |
718e3744 | 79 | |
9f5dc319 | 80 | new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info)); |
d62a17ae | 81 | new->type = type; |
82 | new->instance = instance; | |
63f0e941 | 83 | new->to_be_processed = 0; |
718e3744 | 84 | |
d62a17ae | 85 | ospf_reset_route_map_set_values(&new->route_map_set); |
86 | return new; | |
718e3744 | 87 | } |
88 | ||
d62a17ae | 89 | static void ospf_external_info_free(struct external_info *ei) |
718e3744 | 90 | { |
d62a17ae | 91 | XFREE(MTYPE_OSPF_EXTERNAL_INFO, ei); |
718e3744 | 92 | } |
93 | ||
d62a17ae | 94 | void ospf_reset_route_map_set_values(struct route_map_set_values *values) |
718e3744 | 95 | { |
d62a17ae | 96 | values->metric = -1; |
97 | values->metric_type = -1; | |
718e3744 | 98 | } |
99 | ||
d62a17ae | 100 | int ospf_route_map_set_compare(struct route_map_set_values *values1, |
101 | struct route_map_set_values *values2) | |
718e3744 | 102 | { |
d62a17ae | 103 | return values1->metric == values2->metric |
104 | && values1->metric_type == values2->metric_type; | |
718e3744 | 105 | } |
106 | ||
107 | /* Add an External info for AS-external-LSA. */ | |
996c9314 | 108 | struct external_info * |
d7c0a89a | 109 | ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance, |
996c9314 LB |
110 | struct prefix_ipv4 p, ifindex_t ifindex, |
111 | struct in_addr nexthop, route_tag_t tag) | |
718e3744 | 112 | { |
d62a17ae | 113 | struct external_info *new; |
114 | struct route_node *rn; | |
115 | struct ospf_external *ext; | |
d62a17ae | 116 | |
de1ac5fd | 117 | ext = ospf_external_lookup(ospf, type, instance); |
d62a17ae | 118 | if (!ext) |
de1ac5fd | 119 | ext = ospf_external_add(ospf, type, instance); |
d62a17ae | 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? */ | |
5e5181bb DS |
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 */ | |
d62a17ae | 130 | } |
131 | ||
5e5181bb DS |
132 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) |
133 | zlog_debug( | |
674c29dd | 134 | "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.", |
5e5181bb | 135 | ospf_redist_string(type), instance, |
674c29dd | 136 | ospf->vrf_id, &p, &nexthop.s_addr); |
5e5181bb DS |
137 | XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info); |
138 | } | |
139 | ||
d62a17ae | 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; | |
04e94d39 | 146 | new->orig_tag = tag; |
63f0e941 | 147 | new->aggr_route = NULL; |
d62a17ae | 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)) { | |
d62a17ae | 154 | zlog_debug( |
674c29dd DS |
155 | "Redistribute[%s][%u]: %pFX external info created, with NH %pI4", |
156 | ospf_redist_string(type), ospf->vrf_id, &p, | |
157 | &nexthop.s_addr); | |
d62a17ae | 158 | } |
159 | return new; | |
718e3744 | 160 | } |
161 | ||
d7c0a89a QY |
162 | void ospf_external_info_delete(struct ospf *ospf, uint8_t type, |
163 | unsigned short instance, struct prefix_ipv4 p) | |
718e3744 | 164 | { |
d62a17ae | 165 | struct route_node *rn; |
166 | struct ospf_external *ext; | |
167 | ||
de1ac5fd | 168 | ext = ospf_external_lookup(ospf, type, instance); |
d62a17ae | 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 | } | |
718e3744 | 179 | } |
180 | ||
d7c0a89a QY |
181 | struct external_info *ospf_external_info_lookup(struct ospf *ospf, uint8_t type, |
182 | unsigned short instance, | |
d62a17ae | 183 | struct prefix_ipv4 *p) |
718e3744 | 184 | { |
d62a17ae | 185 | struct route_node *rn; |
186 | struct ospf_external *ext; | |
187 | ||
de1ac5fd | 188 | ext = ospf_external_lookup(ospf, type, instance); |
d62a17ae | 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; | |
718e3744 | 200 | } |
201 | ||
d62a17ae | 202 | struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, |
203 | struct prefix_ipv4 *p) | |
718e3744 | 204 | { |
d62a17ae | 205 | struct ospf_lsa *lsa; |
206 | struct as_external_lsa *al; | |
207 | struct in_addr mask, id; | |
718e3744 | 208 | |
64f46c22 | 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 | */ | |
718e3744 | 220 | |
d62a17ae | 221 | masklen2ip(p->prefixlen, &mask); |
64f46c22 | 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; | |
718e3744 | 227 | |
64f46c22 | 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; | |
d62a17ae | 235 | } |
718e3744 | 236 | |
64f46c22 | 237 | return NULL; |
718e3744 | 238 | } |
239 | ||
6b0655a2 | 240 | |
718e3744 | 241 | /* Update ASBR status. */ |
d7c0a89a | 242 | void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) |
718e3744 | 243 | { |
868a0861 DS |
244 | zlog_info("ASBR[%s:Status:%d]: Update", |
245 | ospf_get_name(ospf), status); | |
d62a17ae | 246 | |
247 | /* ASBR on. */ | |
248 | if (status) { | |
249 | /* Already ASBR. */ | |
250 | if (IS_OSPF_ASBR(ospf)) { | |
868a0861 DS |
251 | zlog_info("ASBR[%s:Status:%d]: Already ASBR", |
252 | ospf_get_name(ospf), status); | |
d62a17ae | 253 | return; |
254 | } | |
255 | SET_FLAG(ospf->flags, OSPF_FLAG_ASBR); | |
256 | } else { | |
257 | /* Already non ASBR. */ | |
258 | if (!IS_OSPF_ASBR(ospf)) { | |
868a0861 DS |
259 | zlog_info("ASBR[%s:Status:%d]: Already non ASBR", |
260 | ospf_get_name(ospf), status); | |
d62a17ae | 261 | return; |
262 | } | |
263 | UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR); | |
718e3744 | 264 | } |
718e3744 | 265 | |
d62a17ae | 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); | |
718e3744 | 269 | } |
270 | ||
0f321812 AC |
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 | */ | |
1c1c342d | 274 | static int ospf_asbr_nssa_redist_update_timer(struct thread *thread) |
0f321812 | 275 | { |
1c1c342d | 276 | struct ospf *ospf = THREAD_ARG(thread); |
0f321812 AC |
277 | int type; |
278 | ||
1c1c342d AC |
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 | ||
0f321812 AC |
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)) | |
945eec2b | 294 | ospf_external_lsa_refresh_type(ospf, type, |
295 | red->instance, | |
1c1c342d | 296 | LSA_REFRESH_FORCE); |
0f321812 AC |
297 | } |
298 | ||
299 | ospf_external_lsa_refresh_default(ospf); | |
1c1c342d AC |
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); | |
0f321812 AC |
312 | } |
313 | ||
d7c0a89a QY |
314 | void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type, |
315 | unsigned short instance) | |
718e3744 | 316 | { |
d62a17ae | 317 | struct route_node *rn; |
318 | struct external_info *ei; | |
319 | struct ospf_external *ext; | |
320 | ||
de1ac5fd | 321 | ext = ospf_external_lookup(ospf, type, instance); |
d62a17ae | 322 | if (!ext) |
323 | return; | |
324 | ||
325 | /* Delete external info for specified type. */ | |
5e5181bb DS |
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 | ||
1fe59b44 | 337 | if (is_default_prefix4(&ei->p) |
5e5181bb DS |
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, | |
d62a17ae | 347 | ei->ifindex /*, ei->nexthop */); |
348 | ||
5e5181bb DS |
349 | ospf_external_info_free(ei); |
350 | route_unlock_node(rn); | |
351 | rn->info = NULL; | |
352 | } | |
718e3744 | 353 | } |
ad7222b7 | 354 | |
5e5181bb | 355 | |
ad7222b7 | 356 | /* External Route Aggregator Handlers */ |
423e71c4 | 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*/ | |
936fbaef | 364 | if (p->prefixlen == IPV4_MAX_BITLEN) |
423e71c4 | 365 | return false; |
366 | ||
367 | return true; | |
368 | } | |
ad7222b7 | 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 | ||
63f0e941 | 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) { | |
fddbafcc | 442 | (void)ospf_originate_summary_lsa(ospf, aggr, ei); |
63f0e941 | 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 | |
fddbafcc | 450 | (void)ospf_external_lsa_originate(ospf, ei); |
63f0e941 | 451 | } |
452 | ||
ad7222b7 | 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)) | |
63f0e941 | 469 | zlog_debug("%s: Release the aggregator Address(%pI4/%d)", |
470 | __func__, &aggr->p.prefix, aggr->p.prefixlen); | |
ad7222b7 | 471 | hash_free(aggr->match_extnl_hash); |
472 | aggr->match_extnl_hash = NULL; | |
473 | ||
474 | XFREE(MTYPE_OSPF_EXTERNAL_RT_AGGR, aggr); | |
475 | } | |
63f0e941 | 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); | |
63f0e941 | 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( | |
1d5453d6 | 542 | "%s: Matching aggregator found.prefix:%pI4/%d Aggregator %pI4/%d", |
63f0e941 | 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)", | |
a4544597 | 694 | __func__, &aggr->p.prefix, aggr->p.prefixlen); |
63f0e941 | 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)", | |
a4544597 | 712 | __func__, &aggr->p.prefix, aggr->p.prefixlen); |
63f0e941 | 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; | |
1fe59b44 | 865 | if (is_default_prefix4(&ei->p)) |
63f0e941 | 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)) | |
1d5453d6 | 979 | zlog_debug("%s: Process modified aggregators.", __func__); |
63f0e941 | 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)) | |
1d5453d6 | 1070 | zlog_debug("%s: operation:%d", __func__, operation); |
63f0e941 | 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 | } | |
423e71c4 | 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; | |
08df5b3b | 1162 | route_unlock_node(rn); |
423e71c4 | 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; | |
08df5b3b | 1220 | route_unlock_node(rn); |
423e71c4 | 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 | } |