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