]>
Commit | Line | Data |
---|---|---|
049207c3 | 1 | /* |
2 | * Area Border Router function. | |
3 | * Copyright (C) 2004 Yasuhiro Ohara | |
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 | |
18 | * along with GNU Zebra; see the file COPYING. If not, write to the | |
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | * Boston, MA 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "log.h" | |
26 | #include "prefix.h" | |
27 | #include "table.h" | |
28 | #include "vty.h" | |
29 | #include "linklist.h" | |
30 | #include "command.h" | |
3b68735f | 31 | #include "thread.h" |
34956b31 | 32 | #include "plist.h" |
33 | #include "filter.h" | |
049207c3 | 34 | |
35 | #include "ospf6_proto.h" | |
36 | #include "ospf6_route.h" | |
37 | #include "ospf6_lsa.h" | |
38 | #include "ospf6_route.h" | |
39 | #include "ospf6_lsdb.h" | |
6452df09 | 40 | #include "ospf6_message.h" |
41 | ||
049207c3 | 42 | #include "ospf6_top.h" |
43 | #include "ospf6_area.h" | |
44 | #include "ospf6_interface.h" | |
6452df09 | 45 | #include "ospf6_neighbor.h" |
46 | ||
6452df09 | 47 | #include "ospf6_flood.h" |
3b68735f | 48 | #include "ospf6_intra.h" |
49 | #include "ospf6_abr.h" | |
049207c3 | 50 | #include "ospf6d.h" |
51 | ||
52 | unsigned char conf_debug_ospf6_abr; | |
53 | ||
6452df09 | 54 | int |
55 | ospf6_is_router_abr (struct ospf6 *o) | |
56 | { | |
52dc7ee6 | 57 | struct listnode *node; |
6452df09 | 58 | struct ospf6_area *oa; |
59 | int area_count = 0; | |
60 | ||
1eb8ef25 | 61 | for (ALL_LIST_ELEMENTS_RO (o->area_list, node, oa)) |
62 | if (IS_AREA_ENABLED (oa)) | |
63 | area_count++; | |
6452df09 | 64 | |
65 | if (area_count > 1) | |
66 | return 1; | |
67 | return 0; | |
68 | } | |
69 | ||
3b68735f | 70 | void |
71 | ospf6_abr_enable_area (struct ospf6_area *area) | |
72 | { | |
73 | struct ospf6_area *oa; | |
74 | struct ospf6_route *ro; | |
1eb8ef25 | 75 | struct listnode *node, *nnode; |
3b68735f | 76 | |
1eb8ef25 | 77 | for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) |
3b68735f | 78 | { |
3b68735f | 79 | /* update B bit for each area */ |
80 | OSPF6_ROUTER_LSA_SCHEDULE (oa); | |
81 | ||
82 | /* install other area's configured address range */ | |
83 | if (oa != area) | |
84 | { | |
85 | for (ro = ospf6_route_head (oa->range_table); ro; | |
86 | ro = ospf6_route_next (ro)) | |
4846ef64 | 87 | { |
88 | if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) | |
89 | ospf6_abr_originate_summary_to_area (ro, area); | |
90 | } | |
3b68735f | 91 | } |
92 | } | |
93 | ||
94 | /* install calculated routes to border routers */ | |
95 | for (ro = ospf6_route_head (area->ospf6->brouter_table); ro; | |
96 | ro = ospf6_route_next (ro)) | |
97 | ospf6_abr_originate_summary_to_area (ro, area); | |
98 | ||
99 | /* install calculated routes to network (may be rejected by ranges) */ | |
100 | for (ro = ospf6_route_head (area->ospf6->route_table); ro; | |
101 | ro = ospf6_route_next (ro)) | |
102 | ospf6_abr_originate_summary_to_area (ro, area); | |
103 | } | |
104 | ||
105 | void | |
106 | ospf6_abr_disable_area (struct ospf6_area *area) | |
107 | { | |
108 | struct ospf6_area *oa; | |
109 | struct ospf6_route *ro; | |
110 | struct ospf6_lsa *old; | |
1eb8ef25 | 111 | struct listnode *node, *nnode; |
3b68735f | 112 | |
113 | /* Withdraw all summary prefixes previously originated */ | |
114 | for (ro = ospf6_route_head (area->summary_prefix); ro; | |
115 | ro = ospf6_route_next (ro)) | |
116 | { | |
117 | old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, | |
118 | area->ospf6->router_id, area->lsdb); | |
119 | if (old) | |
120 | ospf6_lsa_purge (old); | |
121 | ospf6_route_remove (ro, area->summary_prefix); | |
122 | } | |
123 | ||
124 | /* Withdraw all summary router-routes previously originated */ | |
125 | for (ro = ospf6_route_head (area->summary_router); ro; | |
126 | ro = ospf6_route_next (ro)) | |
127 | { | |
128 | old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, | |
129 | area->ospf6->router_id, area->lsdb); | |
130 | if (old) | |
131 | ospf6_lsa_purge (old); | |
132 | ospf6_route_remove (ro, area->summary_router); | |
133 | } | |
134 | ||
135 | /* Schedule Router-LSA for each area (ABR status may change) */ | |
1eb8ef25 | 136 | for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) |
137 | /* update B bit for each area */ | |
138 | OSPF6_ROUTER_LSA_SCHEDULE (oa); | |
3b68735f | 139 | } |
140 | ||
049207c3 | 141 | /* RFC 2328 12.4.3. Summary-LSAs */ |
142 | void | |
6452df09 | 143 | ospf6_abr_originate_summary_to_area (struct ospf6_route *route, |
144 | struct ospf6_area *area) | |
049207c3 | 145 | { |
146 | struct ospf6_lsa *lsa, *old = NULL; | |
147 | struct ospf6_interface *oi; | |
148 | struct ospf6_route *summary, *range = NULL; | |
149 | struct ospf6_area *route_area; | |
150 | char buffer[OSPF6_MAX_LSASIZE]; | |
151 | struct ospf6_lsa_header *lsa_header; | |
152 | caddr_t p; | |
153 | struct ospf6_inter_prefix_lsa *prefix_lsa; | |
6452df09 | 154 | struct ospf6_inter_router_lsa *router_lsa; |
155 | struct ospf6_route_table *summary_table = NULL; | |
156 | u_int16_t type; | |
1e05838a | 157 | char buf[64]; |
158 | int is_debug = 0; | |
6452df09 | 159 | |
1e05838a | 160 | if (route->type == OSPF6_DEST_TYPE_ROUTER) |
6452df09 | 161 | { |
1e05838a | 162 | if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) |
6452df09 | 163 | { |
1e05838a | 164 | is_debug++; |
3b68735f | 165 | inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), |
6452df09 | 166 | buf, sizeof (buf)); |
c6487d61 | 167 | zlog_debug ("Originating summary in area %s for ASBR %s", |
168 | area->name, buf); | |
6452df09 | 169 | } |
1e05838a | 170 | summary_table = area->summary_router; |
171 | } | |
172 | else | |
173 | { | |
174 | if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX)) | |
6452df09 | 175 | { |
1e05838a | 176 | is_debug++; |
6452df09 | 177 | prefix2str (&route->prefix, buf, sizeof (buf)); |
c6487d61 | 178 | zlog_debug ("Originating summary in area %s for %s", |
179 | area->name, buf); | |
6452df09 | 180 | } |
1e05838a | 181 | summary_table = area->summary_prefix; |
6452df09 | 182 | } |
049207c3 | 183 | |
6452df09 | 184 | summary = ospf6_route_lookup (&route->prefix, summary_table); |
049207c3 | 185 | if (summary) |
6452df09 | 186 | old = ospf6_lsdb_lookup (summary->path.origin.type, |
049207c3 | 187 | summary->path.origin.id, |
188 | area->ospf6->router_id, area->lsdb); | |
189 | ||
190 | /* if this route has just removed, remove corresponding LSA */ | |
191 | if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) | |
192 | { | |
1e05838a | 193 | if (is_debug) |
c6487d61 | 194 | zlog_debug ("The route has just removed, purge previous LSA"); |
6452df09 | 195 | if (summary) |
196 | ospf6_route_remove (summary, summary_table); | |
049207c3 | 197 | if (old) |
6452df09 | 198 | ospf6_lsa_purge (old); |
049207c3 | 199 | return; |
200 | } | |
201 | ||
6452df09 | 202 | /* Only destination type network, range or ASBR are considered */ |
203 | if (route->type != OSPF6_DEST_TYPE_NETWORK && | |
204 | route->type != OSPF6_DEST_TYPE_RANGE && | |
205 | (route->type != OSPF6_DEST_TYPE_ROUTER || | |
206 | ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) | |
049207c3 | 207 | { |
1e05838a | 208 | if (is_debug) |
c6487d61 | 209 | zlog_debug ("Route type is none of network, range nor ASBR, withdraw"); |
6452df09 | 210 | if (summary) |
211 | ospf6_route_remove (summary, summary_table); | |
049207c3 | 212 | if (old) |
6452df09 | 213 | ospf6_lsa_purge (old); |
049207c3 | 214 | return; |
215 | } | |
216 | ||
217 | /* AS External routes are never considered */ | |
218 | if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || | |
219 | route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) | |
220 | { | |
1e05838a | 221 | if (is_debug) |
c6487d61 | 222 | zlog_debug ("Path type is external, withdraw"); |
6452df09 | 223 | if (summary) |
224 | ospf6_route_remove (summary, summary_table); | |
049207c3 | 225 | if (old) |
6452df09 | 226 | ospf6_lsa_purge (old); |
049207c3 | 227 | return; |
228 | } | |
229 | ||
6452df09 | 230 | /* do not generate if the path's area is the same as target area */ |
231 | if (route->path.area_id == area->area_id) | |
049207c3 | 232 | { |
1e05838a | 233 | if (is_debug) |
c6487d61 | 234 | zlog_debug ("The route is in the area itself, ignore"); |
6452df09 | 235 | if (summary) |
236 | ospf6_route_remove (summary, summary_table); | |
049207c3 | 237 | if (old) |
6452df09 | 238 | ospf6_lsa_purge (old); |
049207c3 | 239 | return; |
240 | } | |
241 | ||
6452df09 | 242 | /* do not generate if the nexthops belongs to the target area */ |
243 | oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); | |
244 | if (oi && oi->area && oi->area == area) | |
049207c3 | 245 | { |
1e05838a | 246 | if (is_debug) |
c6487d61 | 247 | zlog_debug ("The route's nexthop is in the same area, ignore"); |
6452df09 | 248 | if (summary) |
249 | ospf6_route_remove (summary, summary_table); | |
250 | if (old) | |
251 | ospf6_lsa_purge (old); | |
252 | return; | |
049207c3 | 253 | } |
254 | ||
6452df09 | 255 | /* do not generate if the route cost is greater or equal to LSInfinity */ |
8551e6da | 256 | if (route->path.cost >= OSPF_LS_INFINITY) |
049207c3 | 257 | { |
1e05838a | 258 | if (is_debug) |
c6487d61 | 259 | zlog_debug ("The cost exceeds LSInfinity, withdraw"); |
6452df09 | 260 | if (summary) |
261 | ospf6_route_remove (summary, summary_table); | |
049207c3 | 262 | if (old) |
6452df09 | 263 | ospf6_lsa_purge (old); |
049207c3 | 264 | return; |
265 | } | |
266 | ||
6452df09 | 267 | /* if this is a route to ASBR */ |
268 | if (route->type == OSPF6_DEST_TYPE_ROUTER) | |
049207c3 | 269 | { |
6452df09 | 270 | /* Only the prefered best path is considered */ |
271 | if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)) | |
272 | { | |
1e05838a | 273 | if (is_debug) |
c6487d61 | 274 | zlog_debug ("This is the secondary path to the ASBR, ignore"); |
6452df09 | 275 | if (summary) |
276 | ospf6_route_remove (summary, summary_table); | |
277 | if (old) | |
278 | ospf6_lsa_purge (old); | |
279 | return; | |
280 | } | |
281 | ||
282 | /* Do not generate if the area is stub */ | |
283 | /* XXX */ | |
049207c3 | 284 | } |
285 | ||
6452df09 | 286 | /* if this is an intra-area route, this may be suppressed by aggregation */ |
287 | if (route->type == OSPF6_DEST_TYPE_NETWORK && | |
288 | route->path.type == OSPF6_PATH_TYPE_INTRA) | |
049207c3 | 289 | { |
6452df09 | 290 | /* search for configured address range for the route's area */ |
291 | route_area = ospf6_area_lookup (route->path.area_id, area->ospf6); | |
292 | assert (route_area); | |
293 | range = ospf6_route_lookup_bestmatch (&route->prefix, | |
294 | route_area->range_table); | |
295 | ||
296 | /* ranges are ignored when originate backbone routes to transit area. | |
297 | Otherwise, if ranges are configured, the route is suppressed. */ | |
298 | if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && | |
8551e6da | 299 | (route->path.area_id != OSPF_AREA_BACKBONE || |
6452df09 | 300 | ! IS_AREA_TRANSIT (area))) |
301 | { | |
1e05838a | 302 | if (is_debug) |
6452df09 | 303 | { |
6452df09 | 304 | prefix2str (&range->prefix, buf, sizeof (buf)); |
c6487d61 | 305 | zlog_debug ("Suppressed by range %s of area %s", |
6452df09 | 306 | buf, route_area->name); |
307 | } | |
308 | ||
309 | if (summary) | |
310 | ospf6_route_remove (summary, summary_table); | |
311 | if (old) | |
312 | ospf6_lsa_purge (old); | |
313 | return; | |
314 | } | |
315 | } | |
316 | ||
317 | /* If this is a configured address range */ | |
318 | if (route->type == OSPF6_DEST_TYPE_RANGE) | |
319 | { | |
320 | /* If DoNotAdvertise is set */ | |
321 | if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) | |
322 | { | |
1e05838a | 323 | if (is_debug) |
c6487d61 | 324 | zlog_debug ("This is the range with DoNotAdvertise set. ignore"); |
6452df09 | 325 | if (summary) |
326 | ospf6_route_remove (summary, summary_table); | |
327 | if (old) | |
328 | ospf6_lsa_purge (old); | |
329 | return; | |
330 | } | |
331 | ||
332 | /* Whether the route have active longer prefix */ | |
333 | if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) | |
334 | { | |
1e05838a | 335 | if (is_debug) |
c6487d61 | 336 | zlog_debug ("The range is not active. withdraw"); |
6452df09 | 337 | if (summary) |
338 | ospf6_route_remove (summary, summary_table); | |
339 | if (old) | |
340 | ospf6_lsa_purge (old); | |
341 | return; | |
342 | } | |
049207c3 | 343 | } |
344 | ||
34956b31 | 345 | /* Check export list */ |
346 | if (EXPORT_NAME (area)) | |
347 | { | |
348 | if (EXPORT_LIST (area) == NULL) | |
349 | EXPORT_LIST (area) = | |
350 | access_list_lookup (AFI_IP6, EXPORT_NAME (area)); | |
351 | ||
352 | if (EXPORT_LIST (area)) | |
353 | if (access_list_apply (EXPORT_LIST (area), | |
354 | &route->prefix) == FILTER_DENY) | |
355 | { | |
356 | if (is_debug) | |
357 | { | |
358 | inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), | |
359 | buf, sizeof(buf)); | |
360 | zlog_debug ("prefix %s was denied by export list", buf); | |
361 | } | |
362 | return; | |
363 | } | |
364 | } | |
365 | ||
366 | /* Check filter-list */ | |
367 | if (PREFIX_NAME_OUT (area)) | |
368 | { | |
369 | if (PREFIX_LIST_OUT (area) == NULL) | |
370 | PREFIX_LIST_OUT (area) = | |
371 | prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area)); | |
372 | ||
373 | if (PREFIX_LIST_OUT (area)) | |
374 | if (prefix_list_apply (PREFIX_LIST_OUT (area), | |
375 | &route->prefix) != PREFIX_PERMIT) | |
376 | { | |
377 | if (is_debug) | |
378 | { | |
379 | inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), | |
380 | buf, sizeof (buf)); | |
381 | zlog_debug ("prefix %s was denied by filter-list out", buf); | |
382 | } | |
383 | return; | |
384 | } | |
385 | } | |
386 | ||
049207c3 | 387 | /* the route is going to be originated. store it in area's summary_table */ |
388 | if (summary == NULL) | |
389 | { | |
390 | summary = ospf6_route_copy (route); | |
6452df09 | 391 | if (route->type == OSPF6_DEST_TYPE_NETWORK || |
392 | route->type == OSPF6_DEST_TYPE_RANGE) | |
393 | summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); | |
394 | else | |
395 | summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); | |
049207c3 | 396 | summary->path.origin.adv_router = area->ospf6->router_id; |
397 | summary->path.origin.id = | |
398 | ospf6_new_ls_id (summary->path.origin.type, | |
399 | summary->path.origin.adv_router, area->lsdb); | |
9428f2dc | 400 | summary = ospf6_route_add (summary, summary_table); |
6452df09 | 401 | } |
402 | else | |
403 | { | |
404 | summary->type = route->type; | |
86f72dcb | 405 | quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed); |
049207c3 | 406 | } |
407 | ||
6452df09 | 408 | summary->path.router_bits = route->path.router_bits; |
409 | summary->path.options[0] = route->path.options[0]; | |
410 | summary->path.options[1] = route->path.options[1]; | |
411 | summary->path.options[2] = route->path.options[2]; | |
412 | summary->path.prefix_options = route->path.prefix_options; | |
413 | summary->path.area_id = area->area_id; | |
414 | summary->path.type = OSPF6_PATH_TYPE_INTER; | |
415 | summary->path.cost = route->path.cost; | |
416 | summary->nexthop[0] = route->nexthop[0]; | |
417 | ||
049207c3 | 418 | /* prepare buffer */ |
419 | memset (buffer, 0, sizeof (buffer)); | |
420 | lsa_header = (struct ospf6_lsa_header *) buffer; | |
049207c3 | 421 | |
6452df09 | 422 | if (route->type == OSPF6_DEST_TYPE_ROUTER) |
423 | { | |
424 | router_lsa = (struct ospf6_inter_router_lsa *) | |
425 | ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); | |
426 | p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa); | |
427 | ||
428 | /* Fill Inter-Area-Router-LSA */ | |
429 | router_lsa->options[0] = route->path.options[0]; | |
430 | router_lsa->options[1] = route->path.options[1]; | |
431 | router_lsa->options[2] = route->path.options[2]; | |
432 | OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost); | |
3b68735f | 433 | router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix); |
6452df09 | 434 | type = htons (OSPF6_LSTYPE_INTER_ROUTER); |
435 | } | |
436 | else | |
437 | { | |
438 | prefix_lsa = (struct ospf6_inter_prefix_lsa *) | |
439 | ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); | |
440 | p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa); | |
441 | ||
442 | /* Fill Inter-Area-Prefix-LSA */ | |
443 | OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost); | |
444 | prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; | |
445 | prefix_lsa->prefix.prefix_options = route->path.prefix_options; | |
446 | ||
447 | /* set Prefix */ | |
448 | memcpy (p, &route->prefix.u.prefix6, | |
449 | OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); | |
450 | ospf6_prefix_apply_mask (&prefix_lsa->prefix); | |
451 | p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); | |
452 | type = htons (OSPF6_LSTYPE_INTER_PREFIX); | |
453 | } | |
049207c3 | 454 | |
455 | /* Fill LSA Header */ | |
456 | lsa_header->age = 0; | |
6452df09 | 457 | lsa_header->type = type; |
049207c3 | 458 | lsa_header->id = summary->path.origin.id; |
459 | lsa_header->adv_router = area->ospf6->router_id; | |
460 | lsa_header->seqnum = | |
461 | ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, | |
462 | lsa_header->adv_router, area->lsdb); | |
463 | lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); | |
464 | ||
465 | /* LSA checksum */ | |
466 | ospf6_lsa_checksum (lsa_header); | |
467 | ||
468 | /* create LSA */ | |
469 | lsa = ospf6_lsa_create (lsa_header); | |
6452df09 | 470 | |
049207c3 | 471 | /* Originate */ |
6452df09 | 472 | ospf6_lsa_originate_area (lsa, area); |
473 | } | |
474 | ||
6ac29a51 | 475 | static void |
6452df09 | 476 | ospf6_abr_range_update (struct ospf6_route *range) |
477 | { | |
478 | u_int32_t cost = 0; | |
479 | struct ospf6_route *ro; | |
480 | ||
481 | assert (range->type == OSPF6_DEST_TYPE_RANGE); | |
482 | ||
483 | /* update range's cost and active flag */ | |
484 | for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table); | |
485 | ro; ro = ospf6_route_match_next (&range->prefix, ro)) | |
486 | { | |
487 | if (ro->path.area_id == range->path.area_id && | |
488 | ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) | |
489 | cost = MAX (cost, ro->path.cost); | |
490 | } | |
491 | ||
492 | if (range->path.cost != cost) | |
493 | { | |
494 | range->path.cost = cost; | |
495 | ||
496 | if (range->path.cost) | |
497 | SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); | |
498 | else | |
499 | UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); | |
500 | ||
501 | ospf6_abr_originate_summary (range); | |
502 | } | |
049207c3 | 503 | } |
504 | ||
505 | void | |
6452df09 | 506 | ospf6_abr_originate_summary (struct ospf6_route *route) |
049207c3 | 507 | { |
1eb8ef25 | 508 | struct listnode *node, *nnode; |
049207c3 | 509 | struct ospf6_area *oa; |
6452df09 | 510 | struct ospf6_route *range = NULL; |
049207c3 | 511 | |
6452df09 | 512 | if (route->type == OSPF6_DEST_TYPE_NETWORK) |
513 | { | |
514 | oa = ospf6_area_lookup (route->path.area_id, ospf6); | |
515 | range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table); | |
516 | if (range) | |
517 | ospf6_abr_range_update (range); | |
518 | } | |
519 | ||
1eb8ef25 | 520 | for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) |
521 | ospf6_abr_originate_summary_to_area (route, oa); | |
049207c3 | 522 | } |
523 | ||
524 | /* RFC 2328 16.2. Calculating the inter-area routes */ | |
525 | void | |
526 | ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) | |
527 | { | |
528 | struct prefix prefix, abr_prefix; | |
529 | struct ospf6_route_table *table = NULL; | |
530 | struct ospf6_route *range, *route, *old = NULL; | |
531 | struct ospf6_route *abr_entry; | |
6452df09 | 532 | u_char type = 0; |
049207c3 | 533 | char options[3] = {0, 0, 0}; |
534 | u_int8_t prefix_options = 0; | |
535 | u_int32_t cost = 0; | |
63069ad6 | 536 | u_char router_bits = 0; |
049207c3 | 537 | int i; |
ccb59b11 | 538 | char buf[64]; |
1e05838a | 539 | int is_debug = 0; |
3b68735f | 540 | |
cf1ce250 PJ |
541 | memset (&prefix, 0, sizeof (prefix)); |
542 | ||
049207c3 | 543 | if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) |
544 | { | |
545 | struct ospf6_inter_prefix_lsa *prefix_lsa; | |
1e05838a | 546 | |
547 | if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) | |
548 | { | |
549 | is_debug++; | |
c6487d61 | 550 | zlog_debug ("Examin %s in area %s", lsa->name, oa->name); |
1e05838a | 551 | } |
552 | ||
049207c3 | 553 | prefix_lsa = (struct ospf6_inter_prefix_lsa *) |
554 | OSPF6_LSA_HEADER_END (lsa->header); | |
555 | prefix.family = AF_INET6; | |
556 | prefix.prefixlen = prefix_lsa->prefix.prefix_length; | |
557 | ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix); | |
d91f35bc DO |
558 | if (is_debug) |
559 | prefix2str (&prefix, buf, sizeof (buf)); | |
049207c3 | 560 | table = oa->ospf6->route_table; |
561 | type = OSPF6_DEST_TYPE_NETWORK; | |
562 | prefix_options = prefix_lsa->prefix.prefix_options; | |
563 | cost = OSPF6_ABR_SUMMARY_METRIC (prefix_lsa); | |
564 | } | |
565 | else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) | |
566 | { | |
567 | struct ospf6_inter_router_lsa *router_lsa; | |
1e05838a | 568 | |
569 | if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) | |
570 | { | |
571 | is_debug++; | |
c6487d61 | 572 | zlog_debug ("Examin %s in area %s", lsa->name, oa->name); |
1e05838a | 573 | } |
574 | ||
049207c3 | 575 | router_lsa = (struct ospf6_inter_router_lsa *) |
576 | OSPF6_LSA_HEADER_END (lsa->header); | |
577 | ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); | |
d91f35bc DO |
578 | if (is_debug) |
579 | inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); | |
049207c3 | 580 | table = oa->ospf6->brouter_table; |
581 | type = OSPF6_DEST_TYPE_ROUTER; | |
582 | options[0] = router_lsa->options[0]; | |
583 | options[1] = router_lsa->options[1]; | |
584 | options[2] = router_lsa->options[2]; | |
585 | cost = OSPF6_ABR_SUMMARY_METRIC (router_lsa); | |
63069ad6 | 586 | SET_FLAG (router_bits, OSPF6_ROUTER_BIT_E); |
049207c3 | 587 | } |
588 | else | |
589 | assert (0); | |
590 | ||
ccb59b11 | 591 | /* Find existing route */ |
592 | route = ospf6_route_lookup (&prefix, table); | |
593 | if (route) | |
594 | ospf6_route_lock (route); | |
595 | while (route && ospf6_route_is_prefix (&prefix, route)) | |
049207c3 | 596 | { |
597 | if (route->path.area_id == oa->area_id && | |
598 | route->path.origin.type == lsa->header->type && | |
599 | route->path.origin.id == lsa->header->id && | |
cf1ce250 PJ |
600 | route->path.origin.adv_router == lsa->header->adv_router && |
601 | ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED)) | |
049207c3 | 602 | old = route; |
ccb59b11 | 603 | route = ospf6_route_next (route); |
049207c3 | 604 | } |
605 | ||
606 | /* (1) if cost == LSInfinity or if the LSA is MaxAge */ | |
8551e6da | 607 | if (cost == OSPF_LS_INFINITY) |
049207c3 | 608 | { |
1e05838a | 609 | if (is_debug) |
c6487d61 | 610 | zlog_debug ("cost is LS_INFINITY, ignore"); |
3b68735f | 611 | if (old) |
63069ad6 | 612 | ospf6_route_remove (old, table); |
3b68735f | 613 | return; |
614 | } | |
615 | if (OSPF6_LSA_IS_MAXAGE (lsa)) | |
616 | { | |
1e05838a | 617 | if (is_debug) |
c6487d61 | 618 | zlog_debug ("LSA is MaxAge, ignore"); |
049207c3 | 619 | if (old) |
63069ad6 | 620 | ospf6_route_remove (old, table); |
049207c3 | 621 | return; |
622 | } | |
623 | ||
624 | /* (2) if the LSA is self-originated, ignore */ | |
625 | if (lsa->header->adv_router == oa->ospf6->router_id) | |
626 | { | |
1e05838a | 627 | if (is_debug) |
c6487d61 | 628 | zlog_debug ("LSA is self-originated, ignore"); |
049207c3 | 629 | if (old) |
63069ad6 | 630 | ospf6_route_remove (old, table); |
049207c3 | 631 | return; |
632 | } | |
633 | ||
634 | /* (3) if the prefix is equal to an active configured address range */ | |
6452df09 | 635 | if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) |
049207c3 | 636 | { |
6452df09 | 637 | range = ospf6_route_lookup (&prefix, oa->range_table); |
638 | if (range) | |
639 | { | |
1e05838a | 640 | if (is_debug) |
c6487d61 | 641 | zlog_debug ("Prefix is equal to address range, ignore"); |
6452df09 | 642 | if (old) |
63069ad6 | 643 | ospf6_route_remove (old, table); |
6452df09 | 644 | return; |
645 | } | |
049207c3 | 646 | } |
647 | ||
648 | /* (4) if the routing table entry for the ABR does not exist */ | |
649 | ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix); | |
650 | abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table); | |
6452df09 | 651 | if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id || |
ccb59b11 | 652 | CHECK_FLAG (abr_entry->flag, OSPF6_ROUTE_REMOVE) || |
6452df09 | 653 | ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) |
049207c3 | 654 | { |
1e05838a | 655 | if (is_debug) |
c6487d61 | 656 | zlog_debug ("ABR router entry does not exist, ignore"); |
049207c3 | 657 | if (old) |
63069ad6 | 658 | ospf6_route_remove (old, table); |
049207c3 | 659 | return; |
660 | } | |
661 | ||
34956b31 | 662 | /* Check import list */ |
663 | if (IMPORT_NAME (oa)) | |
664 | { | |
665 | if (IMPORT_LIST (oa) == NULL) | |
666 | IMPORT_LIST (oa) = access_list_lookup (AFI_IP6, IMPORT_NAME (oa)); | |
667 | ||
668 | if (IMPORT_LIST (oa)) | |
669 | if (access_list_apply (IMPORT_LIST (oa), &prefix) == FILTER_DENY) | |
670 | { | |
671 | if (is_debug) | |
672 | zlog_debug ("Prefix was denied by import-list"); | |
673 | if (old) | |
674 | ospf6_route_remove (old, table); | |
675 | return; | |
676 | } | |
677 | } | |
678 | ||
679 | /* Check input prefix-list */ | |
680 | if (PREFIX_NAME_IN (oa)) | |
681 | { | |
682 | if (PREFIX_LIST_IN (oa) == NULL) | |
683 | PREFIX_LIST_IN (oa) = prefix_list_lookup (AFI_IP6, PREFIX_NAME_IN (oa)); | |
684 | ||
685 | if (PREFIX_LIST_IN (oa)) | |
686 | if (prefix_list_apply (PREFIX_LIST_IN (oa), &prefix) != PREFIX_PERMIT) | |
687 | { | |
688 | if (is_debug) | |
689 | zlog_debug ("Prefix was denied by prefix-list"); | |
690 | if (old) | |
691 | ospf6_route_remove (old, table); | |
692 | return; | |
693 | } | |
694 | } | |
695 | ||
049207c3 | 696 | /* (5),(6),(7) the path preference is handled by the sorting |
697 | in the routing table. Always install the path by substituting | |
698 | old route (if any). */ | |
699 | if (old) | |
ccb59b11 | 700 | route = ospf6_route_copy (old); |
049207c3 | 701 | else |
702 | route = ospf6_route_create (); | |
703 | ||
704 | route->type = type; | |
705 | route->prefix = prefix; | |
706 | route->path.origin.type = lsa->header->type; | |
707 | route->path.origin.id = lsa->header->id; | |
708 | route->path.origin.adv_router = lsa->header->adv_router; | |
63069ad6 | 709 | route->path.router_bits = router_bits; |
049207c3 | 710 | route->path.options[0] = options[0]; |
711 | route->path.options[1] = options[1]; | |
712 | route->path.options[2] = options[2]; | |
713 | route->path.prefix_options = prefix_options; | |
714 | route->path.area_id = oa->area_id; | |
715 | route->path.type = OSPF6_PATH_TYPE_INTER; | |
716 | route->path.cost = abr_entry->path.cost + cost; | |
717 | for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) | |
718 | route->nexthop[i] = abr_entry->nexthop[i]; | |
719 | ||
1e05838a | 720 | if (is_debug) |
c6487d61 | 721 | zlog_debug ("Install route: %s", buf); |
049207c3 | 722 | ospf6_route_add (route, table); |
723 | } | |
724 | ||
ccb59b11 | 725 | void |
726 | ospf6_abr_examin_brouter (u_int32_t router_id) | |
727 | { | |
728 | struct ospf6_lsa *lsa; | |
729 | struct ospf6_area *oa; | |
1eb8ef25 | 730 | struct listnode *node, *nnode; |
ccb59b11 | 731 | u_int16_t type; |
732 | ||
1eb8ef25 | 733 | for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) |
ccb59b11 | 734 | { |
1eb8ef25 | 735 | type = htons (OSPF6_LSTYPE_INTER_ROUTER); |
ccb59b11 | 736 | for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; |
737 | lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) | |
738 | ospf6_abr_examin_summary (lsa, oa); | |
ccb59b11 | 739 | |
1eb8ef25 | 740 | type = htons (OSPF6_LSTYPE_INTER_PREFIX); |
ccb59b11 | 741 | for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; |
742 | lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) | |
743 | ospf6_abr_examin_summary (lsa, oa); | |
744 | } | |
745 | } | |
746 | ||
34956b31 | 747 | void |
748 | ospf6_abr_reimport (struct ospf6_area *oa) | |
749 | { | |
750 | struct ospf6_lsa *lsa; | |
751 | u_int16_t type; | |
752 | ||
753 | type = htons (OSPF6_LSTYPE_INTER_ROUTER); | |
754 | for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; | |
755 | lsa = ospf6_lsdb_type_next (type, lsa)) | |
756 | ospf6_abr_examin_summary (lsa, oa); | |
757 | ||
758 | type = htons (OSPF6_LSTYPE_INTER_PREFIX); | |
759 | for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; | |
760 | lsa = ospf6_lsdb_type_next (type, lsa)) | |
761 | ospf6_abr_examin_summary (lsa, oa); | |
762 | } | |
763 | ||
764 | ||
049207c3 | 765 | \f |
766 | /* Display functions */ | |
e68a6767 DD |
767 | static char * |
768 | ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, | |
769 | int buflen, int pos) | |
770 | { | |
771 | struct ospf6_inter_prefix_lsa *prefix_lsa; | |
772 | struct in6_addr in6; | |
773 | ||
774 | if (lsa != NULL) | |
775 | { | |
776 | prefix_lsa = (struct ospf6_inter_prefix_lsa *) | |
777 | OSPF6_LSA_HEADER_END (lsa->header); | |
778 | ||
779 | ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); | |
780 | if (buf) | |
781 | { | |
782 | inet_ntop (AF_INET6, &in6, buf, buflen); | |
783 | sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length); | |
784 | } | |
785 | } | |
786 | ||
787 | return (buf); | |
788 | } | |
789 | ||
6ac29a51 | 790 | static int |
049207c3 | 791 | ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) |
792 | { | |
793 | struct ospf6_inter_prefix_lsa *prefix_lsa; | |
e68a6767 | 794 | char buf[INET6_ADDRSTRLEN]; |
049207c3 | 795 | |
796 | prefix_lsa = (struct ospf6_inter_prefix_lsa *) | |
797 | OSPF6_LSA_HEADER_END (lsa->header); | |
798 | ||
799 | vty_out (vty, " Metric: %lu%s", | |
800 | (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); | |
801 | ||
802 | ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, | |
803 | buf, sizeof (buf)); | |
804 | vty_out (vty, " Prefix Options: %s%s", buf, VNL); | |
805 | ||
e68a6767 DD |
806 | vty_out (vty, " Prefix: %s%s", |
807 | ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf), | |
808 | 0), VNL); | |
049207c3 | 809 | |
810 | return 0; | |
811 | } | |
812 | ||
e68a6767 DD |
813 | static char * |
814 | ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, | |
815 | int buflen, int pos) | |
816 | { | |
817 | struct ospf6_inter_router_lsa *router_lsa; | |
818 | ||
819 | if (lsa != NULL) | |
820 | { | |
821 | router_lsa = (struct ospf6_inter_router_lsa *) | |
822 | OSPF6_LSA_HEADER_END (lsa->header); | |
823 | ||
824 | ||
825 | if (buf) | |
826 | inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen); | |
827 | } | |
828 | ||
829 | return (buf); | |
830 | } | |
831 | ||
6ac29a51 | 832 | static int |
049207c3 | 833 | ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) |
834 | { | |
835 | struct ospf6_inter_router_lsa *router_lsa; | |
836 | char buf[64]; | |
837 | ||
838 | router_lsa = (struct ospf6_inter_router_lsa *) | |
839 | OSPF6_LSA_HEADER_END (lsa->header); | |
840 | ||
841 | ospf6_options_printbuf (router_lsa->options, buf, sizeof (buf)); | |
842 | vty_out (vty, " Options: %s%s", buf, VNL); | |
843 | vty_out (vty, " Metric: %lu%s", | |
844 | (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL); | |
e68a6767 | 845 | |
049207c3 | 846 | inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); |
847 | vty_out (vty, " Destination Router ID: %s%s", buf, VNL); | |
848 | ||
849 | return 0; | |
850 | } | |
851 | ||
852 | /* Debug commands */ | |
853 | DEFUN (debug_ospf6_abr, | |
854 | debug_ospf6_abr_cmd, | |
855 | "debug ospf6 abr", | |
856 | DEBUG_STR | |
857 | OSPF6_STR | |
858 | "Debug OSPFv3 ABR function\n" | |
859 | ) | |
860 | { | |
861 | OSPF6_DEBUG_ABR_ON (); | |
862 | return CMD_SUCCESS; | |
863 | } | |
864 | ||
865 | DEFUN (no_debug_ospf6_abr, | |
866 | no_debug_ospf6_abr_cmd, | |
867 | "no debug ospf6 abr", | |
868 | NO_STR | |
869 | DEBUG_STR | |
870 | OSPF6_STR | |
871 | "Debug OSPFv3 ABR function\n" | |
872 | ) | |
873 | { | |
874 | OSPF6_DEBUG_ABR_OFF (); | |
875 | return CMD_SUCCESS; | |
876 | } | |
877 | ||
878 | int | |
879 | config_write_ospf6_debug_abr (struct vty *vty) | |
880 | { | |
881 | if (IS_OSPF6_DEBUG_ABR) | |
882 | vty_out (vty, "debug ospf6 abr%s", VNL); | |
883 | return 0; | |
884 | } | |
885 | ||
886 | void | |
6ac29a51 | 887 | install_element_ospf6_debug_abr (void) |
049207c3 | 888 | { |
889 | install_element (ENABLE_NODE, &debug_ospf6_abr_cmd); | |
890 | install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd); | |
891 | install_element (CONFIG_NODE, &debug_ospf6_abr_cmd); | |
892 | install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd); | |
893 | } | |
894 | ||
6452df09 | 895 | struct ospf6_lsa_handler inter_prefix_handler = |
896 | { | |
897 | OSPF6_LSTYPE_INTER_PREFIX, | |
898 | "Inter-Prefix", | |
e68a6767 DD |
899 | "IAP", |
900 | ospf6_inter_area_prefix_lsa_show, | |
901 | ospf6_inter_area_prefix_lsa_get_prefix_str, | |
6452df09 | 902 | }; |
903 | ||
904 | struct ospf6_lsa_handler inter_router_handler = | |
905 | { | |
906 | OSPF6_LSTYPE_INTER_ROUTER, | |
907 | "Inter-Router", | |
e68a6767 DD |
908 | "IAR", |
909 | ospf6_inter_area_router_lsa_show, | |
910 | ospf6_inter_area_router_lsa_get_prefix_str, | |
6452df09 | 911 | }; |
912 | ||
049207c3 | 913 | void |
6ac29a51 | 914 | ospf6_abr_init (void) |
049207c3 | 915 | { |
6452df09 | 916 | ospf6_install_lsa_handler (&inter_prefix_handler); |
917 | ospf6_install_lsa_handler (&inter_router_handler); | |
049207c3 | 918 | } |
919 | ||
920 |