Line data Source code
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 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 "log.h"
25 : #include "prefix.h"
26 : #include "table.h"
27 : #include "vty.h"
28 : #include "linklist.h"
29 : #include "command.h"
30 : #include "thread.h"
31 : #include "plist.h"
32 : #include "filter.h"
33 :
34 : #include "ospf6_proto.h"
35 : #include "ospf6_route.h"
36 : #include "ospf6_lsa.h"
37 : #include "ospf6_route.h"
38 : #include "ospf6_lsdb.h"
39 : #include "ospf6_message.h"
40 : #include "ospf6_zebra.h"
41 :
42 : #include "ospf6_top.h"
43 : #include "ospf6_area.h"
44 : #include "ospf6_interface.h"
45 : #include "ospf6_neighbor.h"
46 :
47 : #include "ospf6_flood.h"
48 : #include "ospf6_intra.h"
49 : #include "ospf6_asbr.h"
50 : #include "ospf6_abr.h"
51 : #include "ospf6d.h"
52 : #include "ospf6_nssa.h"
53 :
54 : unsigned char conf_debug_ospf6_abr;
55 :
56 92 : int ospf6_ls_origin_same(struct ospf6_path *o_path, struct ospf6_path *r_path)
57 : {
58 92 : if (((o_path->origin.type == r_path->origin.type)
59 90 : && (o_path->origin.id == r_path->origin.id)
60 68 : && (o_path->origin.adv_router == r_path->origin.adv_router)))
61 : return 1;
62 : else
63 24 : return 0;
64 : }
65 :
66 229 : bool ospf6_check_and_set_router_abr(struct ospf6 *o)
67 : {
68 229 : struct listnode *node;
69 229 : struct ospf6_area *oa;
70 229 : int area_count = 0;
71 229 : bool is_backbone = false;
72 :
73 761 : for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
74 303 : if (IS_OSPF6_DEBUG_ABR)
75 0 : zlog_debug("%s, area_id %pI4", __func__, &oa->area_id);
76 303 : if (IS_AREA_ENABLED(oa))
77 283 : area_count++;
78 :
79 303 : if (o->backbone == oa)
80 57 : is_backbone = true;
81 : }
82 :
83 229 : if ((area_count > 1) && (is_backbone)) {
84 36 : if (IS_OSPF6_DEBUG_ABR)
85 0 : zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__);
86 36 : SET_FLAG(o->flag, OSPF6_FLAG_ABR);
87 36 : return true;
88 : } else {
89 193 : if (IS_OSPF6_DEBUG_ABR)
90 0 : zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
91 193 : UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
92 193 : return false;
93 : }
94 : }
95 :
96 37 : static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
97 : struct ospf6_area *area)
98 : {
99 37 : struct ospf6_interface *oi;
100 :
101 37 : oi = ospf6_interface_lookup_by_ifindex(
102 37 : ospf6_route_get_first_nh_index(route), area->ospf6->vrf_id);
103 37 : if (oi && oi->area && oi->area == area)
104 : return 1;
105 : else
106 37 : return 0;
107 : }
108 :
109 0 : static void ospf6_abr_delete_route(struct ospf6_route *summary,
110 : struct ospf6_route_table *summary_table,
111 : struct ospf6_lsa *old)
112 : {
113 0 : if (summary) {
114 0 : ospf6_route_remove(summary, summary_table);
115 : }
116 :
117 0 : if (old && !OSPF6_LSA_IS_MAXAGE(old))
118 0 : ospf6_lsa_purge(old);
119 0 : }
120 :
121 2 : void ospf6_abr_enable_area(struct ospf6_area *area)
122 : {
123 2 : struct ospf6_area *oa;
124 2 : struct listnode *node, *nnode;
125 :
126 8 : for (ALL_LIST_ELEMENTS(area->ospf6->area_list, node, nnode, oa))
127 : /* update B bit for each area */
128 4 : OSPF6_ROUTER_LSA_SCHEDULE(oa);
129 2 : }
130 :
131 10 : void ospf6_abr_disable_area(struct ospf6_area *area)
132 : {
133 10 : struct ospf6_area *oa;
134 10 : struct ospf6_route *ro, *nro;
135 10 : struct ospf6_lsa *old;
136 10 : struct listnode *node, *nnode;
137 :
138 : /* Withdraw all summary prefixes previously originated */
139 11 : for (ro = ospf6_route_head(area->summary_prefix); ro; ro = nro) {
140 1 : nro = ospf6_route_next(ro);
141 2 : old = ospf6_lsdb_lookup(ro->path.origin.type,
142 : ro->path.origin.id,
143 1 : area->ospf6->router_id, area->lsdb);
144 1 : if (old)
145 1 : ospf6_lsa_purge(old);
146 1 : ospf6_route_remove(ro, area->summary_prefix);
147 : }
148 :
149 : /* Withdraw all summary router-routes previously originated */
150 11 : for (ro = ospf6_route_head(area->summary_router); ro; ro = nro) {
151 1 : nro = ospf6_route_next(ro);
152 2 : old = ospf6_lsdb_lookup(ro->path.origin.type,
153 : ro->path.origin.id,
154 1 : area->ospf6->router_id, area->lsdb);
155 1 : if (old)
156 1 : ospf6_lsa_purge(old);
157 1 : ospf6_route_remove(ro, area->summary_router);
158 : }
159 :
160 : /* Schedule Router-LSA for each area (ABR status may change) */
161 34 : for (ALL_LIST_ELEMENTS(area->ospf6->area_list, node, nnode, oa))
162 : /* update B bit for each area */
163 14 : OSPF6_ROUTER_LSA_SCHEDULE(oa);
164 10 : }
165 :
166 : /* RFC 2328 12.4.3. Summary-LSAs */
167 : /* Returns 1 if a summary LSA has been generated for the area */
168 : /* This is used by the area/range logic to add/remove blackhole routes */
169 228 : int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
170 : struct ospf6_area *area)
171 : {
172 228 : struct ospf6_lsa *lsa, *old = NULL;
173 228 : struct ospf6_route *summary, *range = NULL;
174 228 : struct ospf6_area *route_area;
175 228 : char buffer[OSPF6_MAX_LSASIZE];
176 228 : struct ospf6_lsa_header *lsa_header;
177 228 : caddr_t p;
178 228 : struct ospf6_inter_prefix_lsa *prefix_lsa;
179 228 : struct ospf6_inter_router_lsa *router_lsa;
180 228 : struct ospf6_route_table *summary_table = NULL;
181 228 : uint16_t type;
182 228 : int is_debug = 0;
183 :
184 228 : if (IS_OSPF6_DEBUG_ABR) {
185 0 : char buf[BUFSIZ];
186 :
187 0 : if (route->type == OSPF6_DEST_TYPE_ROUTER)
188 0 : inet_ntop(AF_INET,
189 0 : &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
190 : sizeof(buf));
191 : else
192 0 : prefix2str(&route->prefix, buf, sizeof(buf));
193 :
194 0 : zlog_debug("%s : start area %s, route %s", __func__, area->name,
195 : buf);
196 : }
197 :
198 228 : if (route->type == OSPF6_DEST_TYPE_ROUTER)
199 149 : summary_table = area->summary_router;
200 : else
201 79 : summary_table = area->summary_prefix;
202 :
203 228 : summary = ospf6_route_lookup(&route->prefix, summary_table);
204 228 : if (summary) {
205 24 : old = ospf6_lsdb_lookup(summary->path.origin.type,
206 : summary->path.origin.id,
207 12 : area->ospf6->router_id, area->lsdb);
208 : /* Reset the OSPF6_LSA_UNAPPROVED flag */
209 12 : if (old)
210 12 : UNSET_FLAG(old->flag, OSPF6_LSA_UNAPPROVED);
211 : }
212 :
213 : /* Only destination type network, range or ASBR are considered */
214 228 : if (route->type != OSPF6_DEST_TYPE_NETWORK
215 228 : && route->type != OSPF6_DEST_TYPE_RANGE
216 149 : && ((route->type != OSPF6_DEST_TYPE_ROUTER)
217 149 : || !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
218 77 : if (IS_OSPF6_DEBUG_ABR)
219 0 : zlog_debug(
220 : "%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
221 : __func__, route->type, route->path.router_bits);
222 77 : return 0;
223 : }
224 :
225 : /* AS External routes are never considered */
226 151 : if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
227 151 : || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
228 42 : if (IS_OSPF6_DEBUG_ABR)
229 0 : zlog_debug("%s : Path type is external, skip",
230 : __func__);
231 42 : return 0;
232 : }
233 :
234 : /* do not generate if the path's area is the same as target area */
235 109 : if (route->path.area_id == area->area_id) {
236 72 : if (IS_OSPF6_DEBUG_ABR)
237 0 : zlog_debug(
238 : "%s: The route is in the area itself, ignore",
239 : __func__);
240 72 : return 0;
241 : }
242 :
243 37 : if (route->type == OSPF6_DEST_TYPE_NETWORK) {
244 11 : bool filter = false;
245 :
246 11 : route_area =
247 11 : ospf6_area_lookup(route->path.area_id, area->ospf6);
248 11 : assert(route_area);
249 :
250 : /* Check export-list */
251 11 : if (EXPORT_LIST(route_area)
252 0 : && access_list_apply(EXPORT_LIST(route_area),
253 : &route->prefix)
254 : == FILTER_DENY) {
255 0 : if (IS_OSPF6_DEBUG_ABR)
256 0 : zlog_debug(
257 : "%s: prefix %pFX was denied by export-list",
258 : __func__, &route->prefix);
259 : filter = true;
260 : }
261 :
262 : /* Check output prefix-list */
263 11 : if (PREFIX_LIST_OUT(route_area)
264 0 : && prefix_list_apply(PREFIX_LIST_OUT(route_area),
265 : &route->prefix)
266 : != PREFIX_PERMIT) {
267 0 : if (IS_OSPF6_DEBUG_ABR)
268 0 : zlog_debug(
269 : "%s: prefix %pFX was denied by prefix-list out",
270 : __func__, &route->prefix);
271 : filter = true;
272 : }
273 :
274 : /* Check import-list */
275 11 : if (IMPORT_LIST(area)
276 0 : && access_list_apply(IMPORT_LIST(area), &route->prefix)
277 : == FILTER_DENY) {
278 0 : if (IS_OSPF6_DEBUG_ABR)
279 0 : zlog_debug(
280 : "%s: prefix %pFX was denied by import-list",
281 : __func__, &route->prefix);
282 : filter = true;
283 : }
284 :
285 : /* Check input prefix-list */
286 11 : if (PREFIX_LIST_IN(area)
287 0 : && prefix_list_apply(PREFIX_LIST_IN(area), &route->prefix)
288 : != PREFIX_PERMIT) {
289 0 : if (IS_OSPF6_DEBUG_ABR)
290 0 : zlog_debug(
291 : "%s: prefix %pFX was denied by prefix-list in",
292 : __func__, &route->prefix);
293 : filter = true;
294 : }
295 :
296 11 : if (filter) {
297 0 : if (summary) {
298 0 : ospf6_route_remove(summary, summary_table);
299 0 : if (old)
300 0 : ospf6_lsa_purge(old);
301 : }
302 0 : return 0;
303 : }
304 : }
305 :
306 : /* do not generate if the nexthops belongs to the target area */
307 37 : if (ospf6_abr_nexthops_belong_to_area(route, area)) {
308 0 : if (IS_OSPF6_DEBUG_ABR)
309 0 : zlog_debug(
310 : "%s: The route's nexthop is in the same area, ignore",
311 : __func__);
312 0 : return 0;
313 : }
314 :
315 37 : if (route->type == OSPF6_DEST_TYPE_ROUTER) {
316 26 : if (ADV_ROUTER_IN_PREFIX(&route->prefix)
317 26 : == area->ospf6->router_id) {
318 22 : if (IS_OSPF6_DEBUG_ABR)
319 0 : zlog_debug(
320 : "%s: Skipping ASBR announcement for ABR (%pI4)",
321 : __func__,
322 : &ADV_ROUTER_IN_PREFIX(&route->prefix));
323 22 : return 0;
324 : }
325 : }
326 :
327 15 : if (route->type == OSPF6_DEST_TYPE_ROUTER) {
328 4 : if (IS_OSPF6_DEBUG_ABR
329 4 : || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
330 0 : is_debug++;
331 0 : if (IS_OSPF6_DEBUG_ABR)
332 0 : zlog_debug(
333 : "Originating summary in area %s for ASBR %pI4",
334 : area->name,
335 : &ADV_ROUTER_IN_PREFIX(&route->prefix));
336 : }
337 : } else {
338 11 : if (IS_OSPF6_DEBUG_ABR
339 11 : || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
340 : is_debug++;
341 :
342 11 : if (route->type == OSPF6_DEST_TYPE_NETWORK &&
343 11 : route->path.origin.type ==
344 11 : htons(OSPF6_LSTYPE_INTER_PREFIX)) {
345 0 : if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
346 0 : if (is_debug)
347 0 : zlog_debug(
348 : "%s: route %pFX with cost %u is not best, ignore.",
349 : __func__, &route->prefix,
350 : route->path.cost);
351 0 : return 0;
352 : }
353 : }
354 :
355 11 : if (route->path.origin.type ==
356 11 : htons(OSPF6_LSTYPE_INTRA_PREFIX)) {
357 11 : if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
358 0 : if (is_debug)
359 0 : zlog_debug(
360 : "%s: intra-prefix route %pFX with cost %u is not best, ignore.",
361 : __func__, &route->prefix,
362 : route->path.cost);
363 0 : return 0;
364 : }
365 : }
366 :
367 11 : if (is_debug)
368 0 : zlog_debug(
369 : "Originating summary in area %s for %pFX cost %u",
370 : area->name, &route->prefix, route->path.cost);
371 : }
372 :
373 : /* if this route has just removed, remove corresponding LSA */
374 15 : if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
375 3 : if (is_debug)
376 0 : zlog_debug(
377 : "The route has just removed, purge previous LSA");
378 :
379 3 : if (route->type == OSPF6_DEST_TYPE_RANGE) {
380 : /* Whether the route have active longer prefix */
381 0 : if (!CHECK_FLAG(route->flag,
382 : OSPF6_ROUTE_ACTIVE_SUMMARY)) {
383 0 : if (is_debug)
384 0 : zlog_debug(
385 : "The range is not active. withdraw");
386 :
387 0 : ospf6_abr_delete_route(summary, summary_table,
388 : old);
389 : }
390 3 : } else if (old) {
391 1 : ospf6_route_remove(summary, summary_table);
392 1 : ospf6_lsa_purge(old);
393 : }
394 3 : return 0;
395 : }
396 :
397 12 : if ((route->type == OSPF6_DEST_TYPE_ROUTER)
398 3 : && (IS_AREA_STUB(area) || IS_AREA_NSSA(area))) {
399 0 : if (is_debug)
400 0 : zlog_debug(
401 : "Area has been stubbed, purge Inter-Router LSA");
402 :
403 0 : ospf6_abr_delete_route(summary, summary_table, old);
404 0 : return 0;
405 : }
406 :
407 12 : if (area->no_summary
408 0 : && (route->path.subtype != OSPF6_PATH_SUBTYPE_DEFAULT_RT)) {
409 0 : if (is_debug)
410 0 : zlog_debug("Area has been stubbed, purge prefix LSA");
411 :
412 0 : ospf6_abr_delete_route(summary, summary_table, old);
413 0 : return 0;
414 : }
415 :
416 : /* do not generate if the route cost is greater or equal to LSInfinity
417 : */
418 12 : if (route->path.cost >= OSPF_LS_INFINITY) {
419 : /* When we're clearing the range route because all active
420 : * prefixes
421 : * under the range are gone, we set the range's cost to
422 : * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
423 : * don't want to trigger the code here for that. This code is
424 : * for
425 : * handling routes that have gone to infinity. The range removal
426 : * happens
427 : * elsewhere.
428 : */
429 0 : if ((route->type != OSPF6_DEST_TYPE_RANGE)
430 0 : && (route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC)) {
431 0 : if (is_debug)
432 0 : zlog_debug(
433 : "The cost exceeds LSInfinity, withdraw");
434 0 : if (old)
435 0 : ospf6_lsa_purge(old);
436 0 : return 0;
437 : }
438 : }
439 :
440 : /* if this is a route to ASBR */
441 12 : if (route->type == OSPF6_DEST_TYPE_ROUTER) {
442 : /* Only the preferred best path is considered */
443 3 : if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
444 0 : if (is_debug)
445 0 : zlog_debug(
446 : "This is the secondary path to the ASBR, ignore");
447 0 : ospf6_abr_delete_route(summary, summary_table, old);
448 0 : return 0;
449 : }
450 :
451 : /* Do not generate if area is NSSA */
452 3 : route_area =
453 3 : ospf6_area_lookup(route->path.area_id, area->ospf6);
454 3 : assert(route_area);
455 :
456 3 : if (IS_AREA_NSSA(route_area)) {
457 0 : if (is_debug)
458 0 : zlog_debug(
459 : "%s: The route comes from NSSA area, skip",
460 : __func__);
461 0 : ospf6_abr_delete_route(summary, summary_table, old);
462 0 : return 0;
463 : }
464 :
465 : /* Do not generate if the area is stub */
466 : /* XXX */
467 : }
468 :
469 : /* if this is an intra-area route, this may be suppressed by aggregation
470 : */
471 12 : if (route->type == OSPF6_DEST_TYPE_NETWORK
472 9 : && route->path.type == OSPF6_PATH_TYPE_INTRA) {
473 : /* search for configured address range for the route's area */
474 9 : route_area =
475 9 : ospf6_area_lookup(route->path.area_id, area->ospf6);
476 9 : assert(route_area);
477 9 : range = ospf6_route_lookup_bestmatch(&route->prefix,
478 : route_area->range_table);
479 :
480 : /* ranges are ignored when originate backbone routes to transit
481 : area.
482 : Otherwise, if ranges are configured, the route is suppressed.
483 : */
484 9 : if (range && !CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)
485 0 : && (route->path.area_id != OSPF_AREA_BACKBONE
486 0 : || !IS_AREA_TRANSIT(area))) {
487 0 : if (is_debug)
488 0 : zlog_debug(
489 : "Suppressed by range %pFX of area %s",
490 : &range->prefix, route_area->name);
491 : /* The existing summary route could be a range, don't
492 : * remove it in this case
493 : */
494 0 : if (summary && summary->type != OSPF6_DEST_TYPE_RANGE)
495 0 : ospf6_abr_delete_route(summary, summary_table,
496 : old);
497 0 : return 0;
498 : }
499 : }
500 :
501 : /* If this is a configured address range */
502 12 : if (route->type == OSPF6_DEST_TYPE_RANGE) {
503 : /* If DoNotAdvertise is set */
504 0 : if (CHECK_FLAG(route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
505 0 : if (is_debug)
506 0 : zlog_debug(
507 : "This is the range with DoNotAdvertise set. ignore");
508 0 : ospf6_abr_delete_route(summary, summary_table, old);
509 0 : return 0;
510 : }
511 :
512 : /* If there are no active prefixes in this range, remove */
513 0 : if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) {
514 0 : if (is_debug)
515 0 : zlog_debug("The range is not active. withdraw");
516 0 : ospf6_abr_delete_route(summary, summary_table, old);
517 0 : return 0;
518 : }
519 : }
520 :
521 : /* the route is going to be originated. store it in area's summary_table
522 : */
523 12 : if (summary == NULL) {
524 3 : summary = ospf6_route_copy(route);
525 3 : summary->path.origin.adv_router = area->ospf6->router_id;
526 :
527 3 : if (route->type == OSPF6_DEST_TYPE_ROUTER) {
528 1 : summary->path.origin.type =
529 1 : htons(OSPF6_LSTYPE_INTER_ROUTER);
530 1 : summary->path.origin.id =
531 1 : ADV_ROUTER_IN_PREFIX(&route->prefix);
532 : } else {
533 2 : summary->path.origin.type =
534 2 : htons(OSPF6_LSTYPE_INTER_PREFIX);
535 2 : summary->path.origin.id = ospf6_new_ls_id(
536 : summary->path.origin.type,
537 : summary->path.origin.adv_router, area->lsdb);
538 : }
539 3 : summary = ospf6_route_add(summary, summary_table);
540 : } else {
541 9 : summary->type = route->type;
542 9 : monotime(&summary->changed);
543 : }
544 :
545 12 : summary->prefix_options = route->prefix_options;
546 12 : summary->path.router_bits = route->path.router_bits;
547 12 : summary->path.options[0] = route->path.options[0];
548 12 : summary->path.options[1] = route->path.options[1];
549 12 : summary->path.options[2] = route->path.options[2];
550 12 : summary->path.area_id = area->area_id;
551 12 : summary->path.type = OSPF6_PATH_TYPE_INTER;
552 12 : summary->path.subtype = route->path.subtype;
553 12 : summary->path.cost = route->path.cost;
554 : /* summary->nexthop[0] = route->nexthop[0]; */
555 :
556 : /* prepare buffer */
557 12 : memset(buffer, 0, sizeof(buffer));
558 12 : lsa_header = (struct ospf6_lsa_header *)buffer;
559 :
560 12 : if (route->type == OSPF6_DEST_TYPE_ROUTER) {
561 3 : router_lsa = (struct ospf6_inter_router_lsa
562 : *)((caddr_t)lsa_header
563 : + sizeof(struct ospf6_lsa_header));
564 3 : p = (caddr_t)router_lsa + sizeof(struct ospf6_inter_router_lsa);
565 :
566 : /* Fill Inter-Area-Router-LSA */
567 3 : router_lsa->options[0] = route->path.options[0];
568 3 : router_lsa->options[1] = route->path.options[1];
569 3 : router_lsa->options[2] = route->path.options[2];
570 3 : OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa, route->path.cost);
571 3 : router_lsa->router_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
572 3 : type = htons(OSPF6_LSTYPE_INTER_ROUTER);
573 : } else {
574 9 : prefix_lsa = (struct ospf6_inter_prefix_lsa
575 : *)((caddr_t)lsa_header
576 : + sizeof(struct ospf6_lsa_header));
577 9 : p = (caddr_t)prefix_lsa + sizeof(struct ospf6_inter_prefix_lsa);
578 :
579 : /* Fill Inter-Area-Prefix-LSA */
580 9 : OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa, route->path.cost);
581 9 : prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
582 9 : prefix_lsa->prefix.prefix_options = route->prefix_options;
583 :
584 : /* set Prefix */
585 9 : memcpy(p, &route->prefix.u.prefix6,
586 9 : OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
587 9 : ospf6_prefix_apply_mask(&prefix_lsa->prefix);
588 9 : p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
589 9 : type = htons(OSPF6_LSTYPE_INTER_PREFIX);
590 : }
591 :
592 : /* Fill LSA Header */
593 12 : lsa_header->age = 0;
594 12 : lsa_header->type = type;
595 12 : lsa_header->id = summary->path.origin.id;
596 12 : lsa_header->adv_router = area->ospf6->router_id;
597 24 : lsa_header->seqnum =
598 12 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
599 : lsa_header->adv_router, area->lsdb);
600 12 : lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
601 :
602 : /* LSA checksum */
603 12 : ospf6_lsa_checksum(lsa_header);
604 :
605 : /* create LSA */
606 12 : lsa = ospf6_lsa_create(lsa_header);
607 :
608 : /* Reset the unapproved flag */
609 12 : UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
610 :
611 : /* Originate */
612 12 : ospf6_lsa_originate_area(lsa, area);
613 :
614 12 : if (IS_OSPF6_DEBUG_ABR)
615 0 : zlog_debug("%s : finish area %s", __func__, area->name);
616 :
617 : return 1;
618 : }
619 :
620 12 : void ospf6_abr_range_reset_cost(struct ospf6 *ospf6)
621 : {
622 12 : struct listnode *node, *nnode;
623 12 : struct ospf6_area *oa;
624 12 : struct ospf6_route *range;
625 :
626 48 : for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
627 24 : for (range = ospf6_route_head(oa->range_table); range;
628 0 : range = ospf6_route_next(range))
629 0 : OSPF6_ABR_RANGE_CLEAR_COST(range);
630 24 : for (range = ospf6_route_head(oa->nssa_range_table); range;
631 0 : range = ospf6_route_next(range))
632 0 : OSPF6_ABR_RANGE_CLEAR_COST(range);
633 : }
634 12 : }
635 :
636 0 : static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route *range,
637 : struct ospf6 *o)
638 : {
639 0 : struct ospf6_route *ro;
640 0 : uint32_t cost = 0;
641 :
642 0 : for (ro = ospf6_route_match_head(&range->prefix, o->route_table); ro;
643 0 : ro = ospf6_route_match_next(&range->prefix, ro)) {
644 0 : if (CHECK_FLAG(ro->flag, OSPF6_ROUTE_REMOVE))
645 0 : continue;
646 0 : if (ro->path.area_id != range->path.area_id)
647 0 : continue;
648 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)
649 0 : && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL1
650 0 : && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL2)
651 0 : continue;
652 0 : if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)
653 0 : && ro->path.type != OSPF6_PATH_TYPE_INTRA)
654 0 : continue;
655 :
656 0 : cost = MAX(cost, ro->path.cost);
657 : }
658 :
659 0 : return cost;
660 : }
661 :
662 : static inline int
663 0 : ospf6_abr_range_summary_needs_update(struct ospf6_route *range, uint32_t cost)
664 : {
665 0 : int redo_summary = 0;
666 :
667 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) {
668 0 : UNSET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
669 0 : redo_summary = 1;
670 0 : } else if (CHECK_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
671 0 : if (range->path.cost != 0) {
672 0 : range->path.cost = 0;
673 0 : redo_summary = 1;
674 : }
675 0 : } else if (cost) {
676 0 : if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path)
677 0 : && range->path.cost != range->path.u.cost_config)) {
678 0 : range->path.cost = range->path.u.cost_config;
679 0 : SET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
680 0 : redo_summary = 1;
681 0 : } else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path)
682 0 : && range->path.cost != cost) {
683 0 : range->path.cost = cost;
684 0 : SET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
685 0 : redo_summary = 1;
686 : }
687 0 : } else if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) {
688 : /* Cost is zero, meaning no active range */
689 0 : UNSET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
690 0 : range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
691 0 : redo_summary = 1;
692 : }
693 :
694 0 : return (redo_summary);
695 : }
696 :
697 0 : void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6)
698 : {
699 0 : uint32_t cost = 0;
700 0 : struct listnode *node, *nnode;
701 0 : struct ospf6_area *oa;
702 0 : int summary_orig = 0;
703 :
704 0 : assert(range->type == OSPF6_DEST_TYPE_RANGE);
705 0 : oa = ospf6_area_lookup(range->path.area_id, ospf6);
706 0 : assert(oa);
707 :
708 : /* update range's cost and active flag */
709 0 : cost = ospf6_abr_range_compute_cost(range, ospf6);
710 :
711 0 : if (IS_OSPF6_DEBUG_ABR)
712 0 : zlog_debug("%s: range %pFX, cost %d", __func__, &range->prefix,
713 : cost);
714 :
715 : /* Non-zero cost is a proxy for active longer prefixes in this range.
716 : * If there are active routes covered by this range AND either the
717 : * configured
718 : * cost has changed or the summarized cost has changed then redo
719 : * summaries.
720 : * Alternately, if there are no longer active prefixes and there are
721 : * summary announcements, withdraw those announcements.
722 : *
723 : * The don't advertise code relies on the path.cost being set to UNSPEC
724 : * to
725 : * work the first time. Subsequent times the path.cost is not 0 anyway
726 : * if there
727 : * were active ranges.
728 : */
729 0 : if (!ospf6_abr_range_summary_needs_update(range, cost))
730 : return;
731 :
732 0 : if (IS_OSPF6_DEBUG_ABR)
733 0 : zlog_debug("%s: range %pFX update", __func__, &range->prefix);
734 :
735 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)) {
736 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)
737 : && !CHECK_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
738 0 : ospf6_nssa_lsa_originate(range, oa, true);
739 0 : summary_orig = 1;
740 : } else {
741 0 : struct ospf6_lsa *lsa;
742 :
743 0 : lsa = ospf6_lsdb_lookup(range->path.origin.type,
744 : range->path.origin.id,
745 : ospf6->router_id, oa->lsdb);
746 0 : if (lsa)
747 0 : ospf6_lsa_premature_aging(lsa);
748 : }
749 : } else {
750 0 : for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
751 0 : summary_orig +=
752 0 : ospf6_abr_originate_summary_to_area(range, oa);
753 : }
754 : }
755 :
756 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)
757 0 : && summary_orig) {
758 0 : if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
759 0 : if (IS_OSPF6_DEBUG_ABR)
760 0 : zlog_debug("Add discard route");
761 :
762 0 : ospf6_zebra_add_discard(range, ospf6);
763 : }
764 : } else {
765 : /* Summary removed or no summary generated as no
766 : * specifics exist */
767 0 : if (CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
768 0 : if (IS_OSPF6_DEBUG_ABR)
769 0 : zlog_debug("Delete discard route");
770 :
771 0 : ospf6_zebra_delete_discard(range, ospf6);
772 : }
773 : }
774 : }
775 :
776 151 : void ospf6_abr_originate_summary(struct ospf6_route *route, struct ospf6 *ospf6)
777 : {
778 151 : struct listnode *node, *nnode;
779 151 : struct ospf6_area *oa;
780 151 : struct ospf6_route *range = NULL;
781 :
782 151 : if (IS_OSPF6_DEBUG_ABR) {
783 0 : char buf[BUFSIZ];
784 :
785 0 : if (route->type == OSPF6_DEST_TYPE_ROUTER)
786 0 : inet_ntop(AF_INET,
787 0 : &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
788 : sizeof(buf));
789 : else
790 0 : prefix2str(&route->prefix, buf, sizeof(buf));
791 :
792 0 : zlog_debug("%s: route %s", __func__, buf);
793 : }
794 :
795 151 : if (route->type == OSPF6_DEST_TYPE_NETWORK) {
796 61 : oa = ospf6_area_lookup(route->path.area_id, ospf6);
797 61 : if (!oa) {
798 0 : zlog_err("OSPFv6 area lookup failed");
799 0 : return;
800 : }
801 :
802 61 : range = ospf6_route_lookup_bestmatch(&route->prefix,
803 : oa->range_table);
804 61 : if (range) {
805 0 : ospf6_abr_range_update(range, ospf6);
806 : }
807 : }
808 :
809 526 : for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
810 224 : ospf6_abr_originate_summary_to_area(route, oa);
811 : }
812 :
813 12 : void ospf6_abr_defaults_to_stub(struct ospf6 *o)
814 : {
815 12 : struct listnode *node, *nnode;
816 12 : struct ospf6_area *oa;
817 12 : struct ospf6_route *def, *route;
818 12 : int type = DEFAULT_ROUTE;
819 :
820 12 : if (!o->backbone)
821 : return;
822 :
823 12 : def = ospf6_route_create(o);
824 12 : def->type = OSPF6_DEST_TYPE_NETWORK;
825 12 : def->prefix.family = AF_INET6;
826 12 : def->prefix.prefixlen = 0;
827 12 : memset(&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
828 12 : def->type = OSPF6_DEST_TYPE_NETWORK;
829 12 : def->path.type = OSPF6_PATH_TYPE_INTER;
830 12 : def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
831 12 : def->path.area_id = o->backbone->area_id;
832 12 : def->path.metric_type = metric_type(o, type, 0);
833 12 : def->path.cost = metric_value(o, type, 0);
834 :
835 48 : for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) {
836 24 : if (IS_AREA_STUB(oa) || (IS_AREA_NSSA(oa) && oa->no_summary)) {
837 : /* announce defaults to stubby areas */
838 0 : if (IS_OSPF6_DEBUG_ABR)
839 0 : zlog_debug(
840 : "Announcing default route into stubby area %s",
841 : oa->name);
842 0 : UNSET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
843 0 : ospf6_abr_originate_summary_to_area(def, oa);
844 : } else {
845 : /* withdraw defaults when an area switches from stub to
846 : * non-stub */
847 24 : route = ospf6_route_lookup(&def->prefix,
848 : oa->summary_prefix);
849 24 : if (route
850 0 : && (route->path.subtype == def->path.subtype)) {
851 0 : if (IS_OSPF6_DEBUG_ABR)
852 0 : zlog_debug(
853 : "Withdrawing default route from non-stubby area %s",
854 : oa->name);
855 0 : SET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
856 0 : ospf6_abr_originate_summary_to_area(def, oa);
857 : }
858 : }
859 : }
860 12 : ospf6_route_delete(def);
861 : }
862 :
863 0 : void ospf6_abr_old_path_update(struct ospf6_route *old_route,
864 : struct ospf6_route *route,
865 : struct ospf6_route_table *table)
866 : {
867 0 : struct ospf6_path *o_path = NULL;
868 0 : struct listnode *anode, *anext;
869 0 : struct listnode *nnode, *rnode, *rnext;
870 0 : struct ospf6_nexthop *nh, *rnh;
871 :
872 0 : for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, o_path)) {
873 0 : if (o_path->area_id != route->path.area_id
874 0 : || !ospf6_ls_origin_same(o_path, &route->path))
875 0 : continue;
876 :
877 0 : if ((o_path->cost == route->path.cost) &&
878 0 : (o_path->u.cost_e2 == route->path.u.cost_e2))
879 0 : continue;
880 :
881 0 : for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
882 0 : for (ALL_LIST_ELEMENTS(old_route->nh_list, rnode,
883 : rnext, rnh)) {
884 0 : if (!ospf6_nexthop_is_same(rnh, nh))
885 0 : continue;
886 0 : listnode_delete(old_route->nh_list, rnh);
887 0 : ospf6_nexthop_delete(rnh);
888 : }
889 :
890 : }
891 :
892 0 : listnode_delete(old_route->paths, o_path);
893 0 : ospf6_path_free(o_path);
894 :
895 0 : for (ALL_LIST_ELEMENTS(old_route->paths, anode,
896 : anext, o_path)) {
897 0 : ospf6_merge_nexthops(old_route->nh_list,
898 : o_path->nh_list);
899 : }
900 :
901 0 : if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
902 0 : zlog_debug("%s: paths %u nh %u", __func__,
903 : old_route->paths
904 : ? listcount(old_route->paths)
905 : : 0,
906 : old_route->nh_list
907 : ? listcount(old_route->nh_list)
908 : : 0);
909 :
910 0 : if (table->hook_add)
911 0 : (*table->hook_add)(old_route);
912 :
913 0 : if (old_route->path.origin.id == route->path.origin.id &&
914 0 : old_route->path.origin.adv_router ==
915 0 : route->path.origin.adv_router) {
916 0 : struct ospf6_path *h_path;
917 :
918 0 : h_path = (struct ospf6_path *)
919 0 : listgetdata(listhead(old_route->paths));
920 0 : old_route->path.origin.type = h_path->origin.type;
921 0 : old_route->path.origin.id = h_path->origin.id;
922 0 : old_route->path.origin.adv_router =
923 0 : h_path->origin.adv_router;
924 : }
925 : }
926 0 : }
927 :
928 2 : void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa, struct ospf6_route *old,
929 : struct ospf6_route_table *table)
930 : {
931 2 : if (IS_OSPF6_DEBUG_ABR)
932 0 : zlog_debug("%s: route %pFX, paths %d", __func__, &old->prefix,
933 : listcount(old->paths));
934 :
935 2 : if (listcount(old->paths) > 1) {
936 0 : struct listnode *anode, *anext, *nnode, *rnode, *rnext;
937 0 : struct ospf6_path *o_path;
938 0 : struct ospf6_nexthop *nh, *rnh;
939 0 : bool nh_updated = false;
940 :
941 0 : for (ALL_LIST_ELEMENTS(old->paths, anode, anext, o_path)) {
942 0 : if (o_path->origin.adv_router != lsa->header->adv_router
943 0 : || o_path->origin.id != lsa->header->id)
944 0 : continue;
945 0 : for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
946 0 : for (ALL_LIST_ELEMENTS(old->nh_list,
947 : rnode, rnext, rnh)) {
948 0 : if (!ospf6_nexthop_is_same(rnh, nh))
949 0 : continue;
950 0 : if (IS_OSPF6_DEBUG_ABR)
951 0 : zlog_debug("deleted nexthop");
952 0 : listnode_delete(old->nh_list, rnh);
953 0 : ospf6_nexthop_delete(rnh);
954 : }
955 : }
956 0 : listnode_delete(old->paths, o_path);
957 0 : ospf6_path_free(o_path);
958 0 : nh_updated = true;
959 : }
960 :
961 0 : if (nh_updated) {
962 0 : if (listcount(old->paths)) {
963 0 : if (IS_OSPF6_DEBUG_ABR
964 0 : || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
965 0 : zlog_debug("%s: old %pFX updated nh %u",
966 : __func__, &old->prefix,
967 : old->nh_list ? listcount(
968 : old->nh_list)
969 : : 0);
970 :
971 0 : if (table->hook_add)
972 0 : (*table->hook_add)(old);
973 :
974 0 : if ((old->path.origin.id == lsa->header->id) &&
975 0 : (old->path.origin.adv_router
976 0 : == lsa->header->adv_router)) {
977 0 : struct ospf6_path *h_path;
978 :
979 0 : h_path = (struct ospf6_path *)
980 0 : listgetdata(
981 : listhead(old->paths));
982 0 : old->path.origin.type =
983 0 : h_path->origin.type;
984 0 : old->path.origin.id = h_path->origin.id;
985 0 : old->path.origin.adv_router =
986 0 : h_path->origin.adv_router;
987 : }
988 : } else
989 0 : ospf6_route_remove(old, table);
990 : }
991 : } else
992 2 : ospf6_route_remove(old, table);
993 2 : }
994 :
995 : /* RFC 2328 16.2. Calculating the inter-area routes */
996 29 : void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
997 : {
998 29 : struct prefix prefix, abr_prefix;
999 29 : struct ospf6_route_table *table = NULL;
1000 29 : struct ospf6_route *range, *route, *old = NULL, *old_route;
1001 29 : struct ospf6_route *abr_entry;
1002 29 : uint8_t type = 0;
1003 29 : char options[3] = {0, 0, 0};
1004 29 : uint8_t prefix_options = 0;
1005 29 : uint32_t cost = 0;
1006 29 : uint8_t router_bits = 0;
1007 29 : char buf[PREFIX2STR_BUFFER];
1008 29 : int is_debug = 0;
1009 29 : struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
1010 29 : struct ospf6_inter_router_lsa *router_lsa = NULL;
1011 29 : bool old_entry_updated = false;
1012 29 : struct ospf6_path *path, *o_path, *ecmp_path;
1013 29 : struct listnode *anode;
1014 29 : bool add_route = false;
1015 :
1016 29 : memset(&prefix, 0, sizeof(prefix));
1017 :
1018 29 : if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) {
1019 21 : if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX)) {
1020 0 : is_debug++;
1021 0 : zlog_debug("%s: LSA %s age %d in area %s", __func__,
1022 : lsa->name, ospf6_lsa_age_current(lsa),
1023 : oa->name);
1024 : }
1025 :
1026 21 : prefix_lsa =
1027 21 : (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
1028 : lsa->header);
1029 21 : prefix.family = AF_INET6;
1030 21 : prefix.prefixlen = prefix_lsa->prefix.prefix_length;
1031 21 : ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
1032 21 : &prefix_lsa->prefix);
1033 21 : if (is_debug)
1034 0 : prefix2str(&prefix, buf, sizeof(buf));
1035 21 : table = oa->ospf6->route_table;
1036 21 : type = OSPF6_DEST_TYPE_NETWORK;
1037 21 : prefix_options = prefix_lsa->prefix.prefix_options;
1038 21 : cost = OSPF6_ABR_SUMMARY_METRIC(prefix_lsa);
1039 8 : } else if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_ROUTER)) {
1040 8 : if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER)) {
1041 0 : is_debug++;
1042 0 : zlog_debug("%s: LSA %s age %d in area %s", __func__,
1043 : lsa->name, ospf6_lsa_age_current(lsa),
1044 : oa->name);
1045 : }
1046 :
1047 8 : router_lsa =
1048 8 : (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
1049 : lsa->header);
1050 8 : ospf6_linkstate_prefix(router_lsa->router_id, htonl(0),
1051 : &prefix);
1052 8 : if (is_debug)
1053 0 : inet_ntop(AF_INET, &router_lsa->router_id, buf,
1054 : sizeof(buf));
1055 :
1056 8 : table = oa->ospf6->brouter_table;
1057 8 : type = OSPF6_DEST_TYPE_ROUTER;
1058 8 : options[0] = router_lsa->options[0];
1059 8 : options[1] = router_lsa->options[1];
1060 8 : options[2] = router_lsa->options[2];
1061 8 : cost = OSPF6_ABR_SUMMARY_METRIC(router_lsa);
1062 8 : SET_FLAG(router_bits, OSPF6_ROUTER_BIT_E);
1063 : } else
1064 0 : assert(0);
1065 :
1066 : /* Find existing route */
1067 29 : route = ospf6_route_lookup(&prefix, table);
1068 29 : if (route) {
1069 10 : ospf6_route_lock(route);
1070 10 : if (is_debug)
1071 0 : zlog_debug("%s: route %pFX, paths %d", __func__,
1072 : &prefix, listcount(route->paths));
1073 : }
1074 42 : while (route && ospf6_route_is_prefix(&prefix, route)) {
1075 13 : if (route->path.area_id == oa->area_id
1076 7 : && route->path.origin.type == lsa->header->type
1077 4 : && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED)) {
1078 : /* LSA adv. router could be part of route's
1079 : * paths list. Find the existing path and set
1080 : * old as the route.
1081 : */
1082 4 : if (listcount(route->paths) > 1) {
1083 0 : for (ALL_LIST_ELEMENTS_RO(route->paths, anode,
1084 : o_path)) {
1085 0 : if (o_path->origin.id == lsa->header->id
1086 0 : && o_path->origin.adv_router ==
1087 0 : lsa->header->adv_router) {
1088 0 : old = route;
1089 :
1090 0 : if (is_debug)
1091 0 : zlog_debug(
1092 : "%s: old entry found in paths, adv_router %pI4",
1093 : __func__,
1094 : &o_path->origin.adv_router);
1095 :
1096 : break;
1097 : }
1098 : }
1099 4 : } else if (route->path.origin.id == lsa->header->id &&
1100 4 : route->path.origin.adv_router ==
1101 4 : lsa->header->adv_router)
1102 4 : old = route;
1103 : }
1104 13 : route = ospf6_route_next(route);
1105 : }
1106 29 : if (route)
1107 4 : ospf6_route_unlock(route);
1108 :
1109 : /* (1) if cost == LSInfinity or if the LSA is MaxAge */
1110 29 : if (cost == OSPF_LS_INFINITY) {
1111 0 : if (is_debug)
1112 0 : zlog_debug("cost is LS_INFINITY, ignore");
1113 0 : if (old)
1114 0 : ospf6_abr_old_route_remove(lsa, old, table);
1115 25 : return;
1116 : }
1117 29 : if (OSPF6_LSA_IS_MAXAGE(lsa)) {
1118 14 : if (is_debug)
1119 0 : zlog_debug("%s: LSA %s is MaxAge, ignore", __func__,
1120 : lsa->name);
1121 14 : if (old)
1122 2 : ospf6_abr_old_route_remove(lsa, old, table);
1123 14 : return;
1124 : }
1125 :
1126 :
1127 : /* (2) if the LSA is self-originated, ignore */
1128 15 : if (lsa->header->adv_router == oa->ospf6->router_id) {
1129 3 : if (is_debug)
1130 0 : zlog_debug("LSA %s is self-originated, ignore",
1131 : lsa->name);
1132 3 : if (old)
1133 0 : ospf6_route_remove(old, table);
1134 3 : return;
1135 : }
1136 :
1137 : /* (3) if the prefix is equal to an active configured address range */
1138 : /* or if the NU bit is set in the prefix */
1139 12 : if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) {
1140 : /* must have been set in previous block */
1141 9 : assert(prefix_lsa);
1142 :
1143 9 : range = ospf6_route_lookup(&prefix, oa->range_table);
1144 9 : if (range) {
1145 0 : if (is_debug)
1146 0 : zlog_debug(
1147 : "Prefix is equal to address range, ignore");
1148 0 : if (old)
1149 0 : ospf6_route_remove(old, table);
1150 0 : return;
1151 : }
1152 :
1153 9 : if (CHECK_FLAG(prefix_lsa->prefix.prefix_options,
1154 : OSPF6_PREFIX_OPTION_NU)
1155 : || CHECK_FLAG(prefix_lsa->prefix.prefix_options,
1156 : OSPF6_PREFIX_OPTION_LA)) {
1157 0 : if (is_debug)
1158 0 : zlog_debug("Prefix has NU/LA bit set, ignore");
1159 0 : if (old)
1160 0 : ospf6_route_remove(old, table);
1161 0 : return;
1162 : }
1163 : }
1164 :
1165 12 : if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_ROUTER)) {
1166 : /* To pass test suites */
1167 3 : assert(router_lsa);
1168 3 : if (!OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_R)
1169 : || !OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_V6)) {
1170 0 : if (is_debug)
1171 0 : zlog_debug("Prefix has NU/LA bit set, ignore");
1172 0 : if (old)
1173 0 : ospf6_route_remove(old, table);
1174 :
1175 0 : return;
1176 : }
1177 : /* Avoid infinite recursion if someone has maliciously announced
1178 : an
1179 : Inter-Router LSA for an ABR
1180 : */
1181 3 : if (lsa->header->adv_router == router_lsa->router_id) {
1182 0 : if (is_debug)
1183 0 : zlog_debug(
1184 : "Ignoring Inter-Router LSA for an ABR (%s)",
1185 : buf);
1186 0 : if (old)
1187 0 : ospf6_route_remove(old, table);
1188 :
1189 0 : return;
1190 : }
1191 : }
1192 :
1193 : /* (4) if the routing table entry for the ABR does not exist */
1194 12 : ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &abr_prefix);
1195 12 : abr_entry = ospf6_route_lookup(&abr_prefix, oa->ospf6->brouter_table);
1196 12 : if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id
1197 8 : || CHECK_FLAG(abr_entry->flag, OSPF6_ROUTE_REMOVE)
1198 8 : || !CHECK_FLAG(abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) {
1199 8 : if (is_debug)
1200 0 : zlog_debug(
1201 : "%s: ABR router entry %pFX does not exist, ignore",
1202 : __func__, &abr_prefix);
1203 8 : if (old) {
1204 0 : if (old->type == OSPF6_DEST_TYPE_ROUTER &&
1205 0 : oa->intra_brouter_calc) {
1206 0 : if (is_debug)
1207 0 : zlog_debug(
1208 : "%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
1209 : __func__, buf, (void *)old);
1210 : } else {
1211 0 : if (is_debug)
1212 0 : zlog_debug(
1213 : "%s: remove old entry: %s %p ",
1214 : __func__, buf, (void *)old);
1215 0 : ospf6_abr_old_route_remove(lsa, old, table);
1216 : }
1217 : }
1218 8 : return;
1219 : }
1220 :
1221 : /* (5),(6): the path preference is handled by the sorting
1222 : in the routing table. Always install the path by substituting
1223 : old route (if any). */
1224 4 : route = ospf6_route_create(oa->ospf6);
1225 :
1226 4 : route->type = type;
1227 4 : route->prefix = prefix;
1228 4 : route->prefix_options = prefix_options;
1229 4 : route->path.origin.type = lsa->header->type;
1230 4 : route->path.origin.id = lsa->header->id;
1231 4 : route->path.origin.adv_router = lsa->header->adv_router;
1232 4 : route->path.router_bits = router_bits;
1233 4 : route->path.options[0] = options[0];
1234 4 : route->path.options[1] = options[1];
1235 4 : route->path.options[2] = options[2];
1236 4 : route->path.area_id = oa->area_id;
1237 4 : route->path.type = OSPF6_PATH_TYPE_INTER;
1238 4 : route->path.cost = abr_entry->path.cost + cost;
1239 :
1240 : /* copy brouter rechable nexthops into the route. */
1241 4 : ospf6_route_copy_nexthops(route, abr_entry);
1242 :
1243 : /* (7) If the routes are identical, copy the next hops over to existing
1244 : route. ospf6's route table implementation will otherwise string both
1245 : routes, but keep the older one as the best route since the routes
1246 : are identical.
1247 : */
1248 4 : old = ospf6_route_lookup(&prefix, table);
1249 4 : if (old) {
1250 3 : if (is_debug)
1251 0 : zlog_debug("%s: found old route %pFX, paths %d",
1252 : __func__, &prefix, listcount(old->paths));
1253 : }
1254 8 : for (old_route = old; old_route; old_route = old_route->next) {
1255 :
1256 : /* The route linked-list is grouped in batches of prefix.
1257 : * If the new prefix is not the same as the one of interest
1258 : * then we have walked over the end of the batch and so we
1259 : * should break rather than continuing unnecessarily.
1260 : */
1261 5 : if (!ospf6_route_is_same(old_route, route))
1262 : break;
1263 4 : if ((old_route->type != route->type)
1264 4 : || (old_route->path.type != route->path.type))
1265 2 : continue;
1266 :
1267 2 : if ((ospf6_route_cmp(route, old_route) != 0)) {
1268 0 : if (is_debug)
1269 0 : zlog_debug(
1270 : "%s: old %p %pFX cost %u new route cost %u are not same",
1271 : __func__, (void *)old_route, &prefix,
1272 : old_route->path.cost, route->path.cost);
1273 :
1274 : /* Check new route's adv. router is same in one of
1275 : * the paths with differed cost, if so remove the
1276 : * old path as later new route will be added.
1277 : */
1278 0 : if (listcount(old_route->paths) > 1)
1279 0 : ospf6_abr_old_path_update(old_route, route,
1280 : table);
1281 0 : continue;
1282 : }
1283 :
1284 2 : list_delete_all_node(old_route->nh_list);
1285 2 : ospf6_route_copy_nexthops(old_route, route);
1286 2 : old_entry_updated = true;
1287 :
1288 4 : for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
1289 : o_path)) {
1290 2 : if (o_path->area_id == route->path.area_id
1291 2 : && ospf6_ls_origin_same(o_path, &route->path))
1292 : break;
1293 : }
1294 :
1295 : /* New adv. router for a existing path add to paths list */
1296 2 : if (o_path == NULL) {
1297 0 : ecmp_path = ospf6_path_dup(&route->path);
1298 :
1299 : /* Add a nh_list to new ecmp path */
1300 0 : ospf6_copy_nexthops(ecmp_path->nh_list, route->nh_list);
1301 :
1302 : /* Add the new path to route's path list */
1303 0 : listnode_add_sort(old_route->paths, ecmp_path);
1304 :
1305 0 : if (is_debug) {
1306 0 : zlog_debug(
1307 : "%s: route %pFX cost %u another path %pI4 added with nh %u, effective paths %u nh %u",
1308 : __func__, &route->prefix,
1309 : old_route->path.cost,
1310 : &ecmp_path->origin.adv_router,
1311 : listcount(ecmp_path->nh_list),
1312 : old_route->paths
1313 : ? listcount(old_route->paths)
1314 : : 0,
1315 : listcount(old_route->nh_list));
1316 : }
1317 : } else {
1318 2 : struct ospf6_route *tmp_route;
1319 :
1320 2 : tmp_route = ospf6_route_create(oa->ospf6);
1321 :
1322 2 : ospf6_copy_nexthops(tmp_route->nh_list,
1323 : o_path->nh_list);
1324 :
1325 2 : if (!ospf6_route_cmp_nexthops(tmp_route, route)) {
1326 : /* adv. router exists in the list, update nhs */
1327 0 : list_delete_all_node(o_path->nh_list);
1328 0 : ospf6_copy_nexthops(o_path->nh_list,
1329 : route->nh_list);
1330 0 : ospf6_route_delete(tmp_route);
1331 : } else {
1332 : /* adv. router has no change in nhs */
1333 2 : old_entry_updated = false;
1334 2 : ospf6_route_delete(tmp_route);
1335 2 : continue;
1336 : }
1337 : }
1338 :
1339 0 : if (is_debug)
1340 0 : zlog_debug(
1341 : "%s: Update route: %s %p old cost %u new cost %u nh %u",
1342 : __func__, buf, (void *)old_route,
1343 : old_route->path.cost, route->path.cost,
1344 : listcount(old_route->nh_list));
1345 :
1346 : /* For Inter-Prefix route: Update RIB/FIB,
1347 : * For Inter-Router trigger summary update
1348 : */
1349 0 : if (table->hook_add)
1350 0 : (*table->hook_add)(old_route);
1351 :
1352 : break;
1353 : }
1354 :
1355 : /* If the old entry is not updated and old entry not found or old entry
1356 : * does not match with the new entry then add the new route
1357 : */
1358 0 : if (old_entry_updated == false) {
1359 4 : if ((old == NULL) || (old->type != route->type)
1360 3 : || (old->path.type != route->path.type)
1361 2 : || (old->path.cost != route->path.cost))
1362 2 : add_route = true;
1363 : }
1364 :
1365 2 : if (add_route) {
1366 2 : if (is_debug) {
1367 0 : zlog_debug(
1368 : "%s: Install new route: %s cost %u nh %u adv_router %pI4",
1369 : __func__, buf, route->path.cost,
1370 : listcount(route->nh_list),
1371 : &route->path.origin.adv_router);
1372 : }
1373 :
1374 2 : path = ospf6_path_dup(&route->path);
1375 2 : ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list);
1376 2 : listnode_add_sort(route->paths, path);
1377 : /* ospf6_ia_add_nw_route (table, &prefix, route); */
1378 2 : ospf6_route_add(route, table);
1379 : } else
1380 : /* if we did not add the route remove it */
1381 2 : ospf6_route_delete(route);
1382 : }
1383 :
1384 36 : void ospf6_abr_examin_brouter(uint32_t router_id, struct ospf6_route *route,
1385 : struct ospf6 *ospf6)
1386 : {
1387 36 : struct ospf6_lsa *lsa;
1388 36 : struct ospf6_area *oa;
1389 36 : uint16_t type;
1390 :
1391 36 : oa = ospf6_area_lookup(route->path.area_id, ospf6);
1392 : /*
1393 : * It is possible to designate a non backbone
1394 : * area first. If that is the case safely
1395 : * fall out of this function.
1396 : */
1397 36 : if (oa == NULL)
1398 0 : return;
1399 :
1400 36 : type = htons(OSPF6_LSTYPE_INTER_ROUTER);
1401 38 : for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router_id, lsa))
1402 2 : ospf6_abr_examin_summary(lsa, oa);
1403 :
1404 36 : type = htons(OSPF6_LSTYPE_INTER_PREFIX);
1405 41 : for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router_id, lsa))
1406 5 : ospf6_abr_examin_summary(lsa, oa);
1407 : }
1408 :
1409 1 : void ospf6_abr_prefix_resummarize(struct ospf6 *o)
1410 : {
1411 1 : struct ospf6_route *route;
1412 :
1413 1 : if (IS_OSPF6_DEBUG_ABR)
1414 0 : zlog_debug("Re-examining Inter-Prefix Summaries");
1415 :
1416 1 : for (route = ospf6_route_head(o->route_table); route;
1417 0 : route = ospf6_route_next(route))
1418 0 : ospf6_abr_originate_summary(route, o);
1419 :
1420 1 : if (IS_OSPF6_DEBUG_ABR)
1421 0 : zlog_debug("Finished re-examining Inter-Prefix Summaries");
1422 1 : }
1423 :
1424 :
1425 : /* Display functions */
1426 30 : static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
1427 : char *buf, int buflen,
1428 : int pos)
1429 : {
1430 30 : struct ospf6_inter_prefix_lsa *prefix_lsa;
1431 30 : struct in6_addr in6;
1432 30 : char tbuf[16];
1433 :
1434 30 : if (lsa != NULL) {
1435 30 : prefix_lsa =
1436 30 : (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
1437 : lsa->header);
1438 :
1439 30 : ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix);
1440 30 : if (buf) {
1441 30 : inet_ntop(AF_INET6, &in6, buf, buflen);
1442 30 : snprintf(tbuf, sizeof(tbuf), "/%d",
1443 30 : prefix_lsa->prefix.prefix_length);
1444 30 : strlcat(buf, tbuf, buflen);
1445 : }
1446 : }
1447 :
1448 30 : return (buf);
1449 : }
1450 :
1451 0 : static int ospf6_inter_area_prefix_lsa_show(struct vty *vty,
1452 : struct ospf6_lsa *lsa,
1453 : json_object *json_obj,
1454 : bool use_json)
1455 : {
1456 0 : struct ospf6_inter_prefix_lsa *prefix_lsa;
1457 0 : char buf[INET6_ADDRSTRLEN];
1458 :
1459 0 : prefix_lsa = (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
1460 : lsa->header);
1461 :
1462 0 : if (use_json) {
1463 0 : json_object_int_add(
1464 : json_obj, "metric",
1465 0 : (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa));
1466 0 : ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options,
1467 : buf, sizeof(buf));
1468 0 : json_object_string_add(json_obj, "prefixOptions", buf);
1469 0 : json_object_string_add(
1470 : json_obj, "prefix",
1471 0 : ospf6_inter_area_prefix_lsa_get_prefix_str(
1472 : lsa, buf, sizeof(buf), 0));
1473 : } else {
1474 0 : vty_out(vty, " Metric: %lu\n",
1475 0 : (unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa));
1476 :
1477 0 : ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options,
1478 : buf, sizeof(buf));
1479 0 : vty_out(vty, " Prefix Options: %s\n", buf);
1480 :
1481 0 : vty_out(vty, " Prefix: %s\n",
1482 : ospf6_inter_area_prefix_lsa_get_prefix_str(
1483 : lsa, buf, sizeof(buf), 0));
1484 : }
1485 :
1486 0 : return 0;
1487 : }
1488 :
1489 30 : static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa,
1490 : char *buf, int buflen,
1491 : int pos)
1492 : {
1493 30 : struct ospf6_inter_router_lsa *router_lsa;
1494 :
1495 30 : if (lsa != NULL) {
1496 30 : router_lsa =
1497 30 : (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
1498 : lsa->header);
1499 :
1500 :
1501 30 : if (buf)
1502 30 : inet_ntop(AF_INET, &router_lsa->router_id, buf, buflen);
1503 : }
1504 :
1505 30 : return (buf);
1506 : }
1507 :
1508 0 : static int ospf6_inter_area_router_lsa_show(struct vty *vty,
1509 : struct ospf6_lsa *lsa,
1510 : json_object *json_obj,
1511 : bool use_json)
1512 : {
1513 0 : struct ospf6_inter_router_lsa *router_lsa;
1514 0 : char buf[64];
1515 :
1516 0 : router_lsa = (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
1517 : lsa->header);
1518 :
1519 0 : ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf));
1520 0 : if (use_json) {
1521 0 : json_object_string_add(json_obj, "options", buf);
1522 0 : json_object_int_add(
1523 : json_obj, "metric",
1524 0 : (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa));
1525 : } else {
1526 0 : vty_out(vty, " Options: %s\n", buf);
1527 0 : vty_out(vty, " Metric: %lu\n",
1528 0 : (unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa));
1529 : }
1530 :
1531 0 : inet_ntop(AF_INET, &router_lsa->router_id, buf, sizeof(buf));
1532 0 : if (use_json)
1533 0 : json_object_string_add(json_obj, "destinationRouterId", buf);
1534 : else
1535 0 : vty_out(vty, " Destination Router ID: %s\n", buf);
1536 :
1537 0 : return 0;
1538 : }
1539 :
1540 : /* Debug commands */
1541 0 : DEFUN (debug_ospf6_abr,
1542 : debug_ospf6_abr_cmd,
1543 : "debug ospf6 abr",
1544 : DEBUG_STR
1545 : OSPF6_STR
1546 : "Debug OSPFv3 ABR function\n"
1547 : )
1548 : {
1549 0 : OSPF6_DEBUG_ABR_ON();
1550 0 : return CMD_SUCCESS;
1551 : }
1552 :
1553 0 : DEFUN (no_debug_ospf6_abr,
1554 : no_debug_ospf6_abr_cmd,
1555 : "no debug ospf6 abr",
1556 : NO_STR
1557 : DEBUG_STR
1558 : OSPF6_STR
1559 : "Debug OSPFv3 ABR function\n"
1560 : )
1561 : {
1562 0 : OSPF6_DEBUG_ABR_OFF();
1563 0 : return CMD_SUCCESS;
1564 : }
1565 :
1566 0 : int config_write_ospf6_debug_abr(struct vty *vty)
1567 : {
1568 0 : if (IS_OSPF6_DEBUG_ABR)
1569 0 : vty_out(vty, "debug ospf6 abr\n");
1570 0 : return 0;
1571 : }
1572 :
1573 8 : void install_element_ospf6_debug_abr(void)
1574 : {
1575 8 : install_element(ENABLE_NODE, &debug_ospf6_abr_cmd);
1576 8 : install_element(ENABLE_NODE, &no_debug_ospf6_abr_cmd);
1577 8 : install_element(CONFIG_NODE, &debug_ospf6_abr_cmd);
1578 8 : install_element(CONFIG_NODE, &no_debug_ospf6_abr_cmd);
1579 8 : }
1580 :
1581 : static struct ospf6_lsa_handler inter_prefix_handler = {
1582 : .lh_type = OSPF6_LSTYPE_INTER_PREFIX,
1583 : .lh_name = "Inter-Prefix",
1584 : .lh_short_name = "IAP",
1585 : .lh_show = ospf6_inter_area_prefix_lsa_show,
1586 : .lh_get_prefix_str = ospf6_inter_area_prefix_lsa_get_prefix_str,
1587 : .lh_debug = 0};
1588 :
1589 : static struct ospf6_lsa_handler inter_router_handler = {
1590 : .lh_type = OSPF6_LSTYPE_INTER_ROUTER,
1591 : .lh_name = "Inter-Router",
1592 : .lh_short_name = "IAR",
1593 : .lh_show = ospf6_inter_area_router_lsa_show,
1594 : .lh_get_prefix_str = ospf6_inter_area_router_lsa_get_prefix_str,
1595 : .lh_debug = 0};
1596 :
1597 8 : void ospf6_abr_init(void)
1598 : {
1599 8 : ospf6_install_lsa_handler(&inter_prefix_handler);
1600 8 : ospf6_install_lsa_handler(&inter_router_handler);
1601 8 : }
|