]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_asbr.c
Merge pull request #2357 from opensourcerouting/pbrd-ubuntu-fix
[mirror_frr.git] / ospf6d / ospf6_asbr.c
CommitLineData
718e3744 1/*
508e53e2 2 * Copyright (C) 2003 Yasuhiro Ohara
718e3744 3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 19 */
20
21#include <zebra.h>
22
23#include "log.h"
24#include "memory.h"
25#include "prefix.h"
26#include "command.h"
27#include "vty.h"
28#include "routemap.h"
29#include "table.h"
30#include "plist.h"
31#include "thread.h"
508e53e2 32#include "linklist.h"
718e3744 33
508e53e2 34#include "ospf6_proto.h"
35#include "ospf6_lsa.h"
36#include "ospf6_lsdb.h"
37#include "ospf6_route.h"
718e3744 38#include "ospf6_zebra.h"
6452df09 39#include "ospf6_message.h"
40
718e3744 41#include "ospf6_top.h"
508e53e2 42#include "ospf6_area.h"
6452df09 43#include "ospf6_interface.h"
44#include "ospf6_neighbor.h"
508e53e2 45#include "ospf6_asbr.h"
46#include "ospf6_intra.h"
6452df09 47#include "ospf6_flood.h"
049207c3 48#include "ospf6d.h"
718e3744 49
508e53e2 50unsigned char conf_debug_ospf6_asbr = 0;
718e3744 51
f52d13cb 52#define ZROUTE_NAME(x) zebra_route_string(x)
508e53e2 53
54/* AS External LSA origination */
d62a17ae 55static void ospf6_as_external_lsa_originate(struct ospf6_route *route)
718e3744 56{
d62a17ae 57 char buffer[OSPF6_MAX_LSASIZE];
58 struct ospf6_lsa_header *lsa_header;
59 struct ospf6_lsa *lsa;
60 struct ospf6_external_info *info = route->route_option;
61
62 struct ospf6_as_external_lsa *as_external_lsa;
63 char buf[PREFIX2STR_BUFFER];
64 caddr_t p;
65
66 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) {
67 prefix2str(&route->prefix, buf, sizeof(buf));
68 zlog_debug("Originate AS-External-LSA for %s", buf);
69 }
70
71 /* prepare buffer */
72 memset(buffer, 0, sizeof(buffer));
73 lsa_header = (struct ospf6_lsa_header *)buffer;
74 as_external_lsa = (struct ospf6_as_external_lsa
75 *)((caddr_t)lsa_header
76 + sizeof(struct ospf6_lsa_header));
77 p = (caddr_t)((caddr_t)as_external_lsa
78 + sizeof(struct ospf6_as_external_lsa));
79
80 /* Fill AS-External-LSA */
81 /* Metric type */
82 if (route->path.metric_type == 2)
83 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
84 else
85 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
86
87 /* forwarding address */
88 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
89 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
90 else
91 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
92
93 /* external route tag */
94 if (info->tag)
95 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
96 else
97 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
98
99 /* Set metric */
100 OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
101
102 /* prefixlen */
103 as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
104
105 /* PrefixOptions */
106 as_external_lsa->prefix.prefix_options = route->path.prefix_options;
107
108 /* don't use refer LS-type */
109 as_external_lsa->prefix.prefix_refer_lstype = htons(0);
110
111 /* set Prefix */
112 memcpy(p, &route->prefix.u.prefix6,
113 OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
114 ospf6_prefix_apply_mask(&as_external_lsa->prefix);
115 p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
116
117 /* Forwarding address */
118 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
119 memcpy(p, &info->forwarding, sizeof(struct in6_addr));
120 p += sizeof(struct in6_addr);
121 }
122
123 /* External Route Tag */
124 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
125 route_tag_t network_order = htonl(info->tag);
126
127 memcpy(p, &network_order, sizeof(network_order));
128 p += sizeof(network_order);
129 }
130
131 /* Fill LSA Header */
132 lsa_header->age = 0;
133 lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
134 lsa_header->id = route->path.origin.id;
135 lsa_header->adv_router = ospf6->router_id;
136 lsa_header->seqnum =
137 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
138 lsa_header->adv_router, ospf6->lsdb);
139 lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
140
141 /* LSA checksum */
142 ospf6_lsa_checksum(lsa_header);
143
144 /* create LSA */
145 lsa = ospf6_lsa_create(lsa_header);
146
147 /* Originate */
148 ospf6_lsa_originate_process(lsa, ospf6);
718e3744 149}
150
76249532
CS
151int ospf6_orig_as_external_lsa(struct thread *thread)
152{
153 struct ospf6_interface *oi;
154 struct ospf6_lsa *lsa;
155 uint32_t type, adv_router;
156
157 oi = (struct ospf6_interface *)THREAD_ARG(thread);
158 oi->thread_as_extern_lsa = NULL;
159
160 if (oi->state == OSPF6_INTERFACE_DOWN)
161 return 0;
162
163 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
164 adv_router = oi->area->ospf6->router_id;
165 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
166 if (IS_OSPF6_DEBUG_ASBR)
996c9314
LB
167 zlog_debug(
168 "%s: Send update of AS-External LSA %s seq 0x%x",
169 __PRETTY_FUNCTION__, lsa->name,
170 ntohl(lsa->header->seqnum));
76249532
CS
171
172 ospf6_flood_interface(NULL, lsa, oi);
173 }
174
175 return 0;
176}
177
d62a17ae 178static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
464015fa 179{
d62a17ae 180 struct ospf6_as_external_lsa *external;
181 ptrdiff_t tag_offset;
182 route_tag_t network_order;
464015fa 183
d62a17ae 184 if (!lsa)
185 return 0;
464015fa 186
d62a17ae 187 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
188 lsa->header);
464015fa 189
d62a17ae 190 if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
191 return 0;
464015fa 192
d62a17ae 193 tag_offset = sizeof(*external)
194 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
195 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
196 tag_offset += sizeof(struct in6_addr);
464015fa 197
d62a17ae 198 memcpy(&network_order, (caddr_t)external + tag_offset,
199 sizeof(network_order));
200 return ntohl(network_order);
464015fa 201}
6b0655a2 202
064d4355
CS
203void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
204 struct ospf6_route *route)
205{
206 struct ospf6_route *old_route;
207 struct ospf6_path *ecmp_path, *o_path = NULL;
07b37f93 208 struct listnode *anode, *anext;
064d4355
CS
209 struct listnode *nnode, *rnode, *rnext;
210 struct ospf6_nexthop *nh, *rnh;
211 char buf[PREFIX2STR_BUFFER];
212 bool route_found = false;
213
07b37f93
CS
214 /* check for old entry match with new route origin,
215 * delete old entry.
216 */
064d4355 217 for (old_route = old; old_route; old_route = old_route->next) {
07b37f93
CS
218 bool route_updated = false;
219
996c9314
LB
220 if (!ospf6_route_is_same(old_route, route)
221 || (old_route->path.type != route->path.type))
07b37f93
CS
222 continue;
223
224 /* Current and New route has same origin,
225 * delete old entry.
226 */
227 for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
996c9314 228 o_path)) {
07b37f93
CS
229 /* Check old route path and route has same
230 * origin.
231 */
996c9314
LB
232 if (o_path->area_id != route->path.area_id
233 || (memcmp(&(o_path)->origin, &(route)->path.origin,
234 sizeof(struct ospf6_ls_origin))
235 != 0))
07b37f93
CS
236 continue;
237
238 /* Cost is not same then delete current path */
996c9314
LB
239 if ((o_path->cost == route->path.cost)
240 && (o_path->u.cost_e2 == route->path.u.cost_e2))
07b37f93 241 continue;
064d4355
CS
242
243 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
244 prefix2str(&old_route->prefix, buf,
245 sizeof(buf));
996c9314
LB
246 zlog_debug(
247 "%s: route %s cost old %u new %u is not same, replace route",
248 __PRETTY_FUNCTION__, buf, o_path->cost,
249 route->path.cost);
07b37f93
CS
250 }
251
252 /* Remove selected current rout path's nh from
253 * effective nh list.
254 */
255 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
256 for (ALL_LIST_ELEMENTS(old_route->nh_list,
996c9314 257 rnode, rnext, rnh)) {
07b37f93
CS
258 if (!ospf6_nexthop_is_same(rnh, nh))
259 continue;
260 listnode_delete(old_route->nh_list,
996c9314 261 rnh);
07b37f93
CS
262 ospf6_nexthop_delete(rnh);
263 route_updated = true;
264 }
265 }
266
267 listnode_delete(old_route->paths, o_path);
268 ospf6_path_free(o_path);
269
270 /* Current route's path (adv_router info) is similar
271 * to route being added.
272 * Replace current route's path with paths list head.
273 * Update FIB with effective NHs.
274 */
275 if (listcount(old_route->paths)) {
996c9314
LB
276 if (old_route->path.origin.id
277 == route->path.origin.id
278 && old_route->path.origin.adv_router
279 == route->path.origin
280 .adv_router) {
07b37f93
CS
281 struct ospf6_path *h_path;
282
283 h_path = (struct ospf6_path *)
996c9314
LB
284 listgetdata(listhead(
285 old_route->paths));
07b37f93
CS
286 old_route->path.origin.type =
287 h_path->origin.type;
288 old_route->path.origin.id =
289 h_path->origin.id;
290 old_route->path.origin.adv_router =
291 h_path->origin.adv_router;
292 }
293
294 if (route_updated) {
295 for (ALL_LIST_ELEMENTS(old_route->paths,
996c9314
LB
296 anode, anext,
297 o_path)) {
07b37f93
CS
298 ospf6_merge_nexthops(
299 old_route->nh_list,
300 o_path->nh_list);
301 }
302 /* Update RIB/FIB with effective
303 * nh_list
304 */
305 if (ospf6->route_table->hook_add)
996c9314
LB
306 (*ospf6->route_table->hook_add)(
307 old_route);
07b37f93
CS
308 break;
309 }
310 } else {
311 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
312 prefix2str(&old_route->prefix, buf,
313 sizeof(buf));
996c9314
LB
314 zlog_debug(
315 "%s: route %s old cost %u new cost %u, delete old entry.",
316 __PRETTY_FUNCTION__, buf,
317 old_route->path.cost,
318 route->path.cost);
07b37f93
CS
319 }
320 ospf6_route_remove(old_route,
321 ospf6->route_table);
322 break;
323 }
324 }
325 if (route_updated)
326 break;
327 }
328
329 /* Add new route */
330 for (old_route = old; old_route; old_route = old_route->next) {
331
332 /* Current and New Route prefix or route type
333 * is not same skip this current node.
334 */
996c9314
LB
335 if (!ospf6_route_is_same(old_route, route)
336 || (old_route->path.type != route->path.type))
07b37f93
CS
337 continue;
338
339 /* Old Route and New Route have Equal Cost, Merge NHs */
996c9314
LB
340 if ((old_route->path.cost == route->path.cost)
341 && (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
07b37f93
CS
342
343 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
344 prefix2str(&old_route->prefix, buf,
345 sizeof(buf));
996c9314
LB
346 zlog_debug(
347 "%s: old route %s path cost %u e2 %u",
348 __PRETTY_FUNCTION__, buf,
349 old_route->path.cost,
350 old_route->path.u.cost_e2);
064d4355
CS
351 }
352 route_found = true;
353 /* check if this path exists already in
354 * route->paths list, if so, replace nh_list
355 * from asbr_entry.
356 */
357 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
358 o_path)) {
996c9314
LB
359 if (o_path->area_id == route->path.area_id
360 && (memcmp(&(o_path)->origin,
361 &(route)->path.origin,
362 sizeof(struct ospf6_ls_origin))
363 == 0))
064d4355
CS
364 break;
365 }
366 /* If path is not found in old_route paths's list,
367 * add a new path to route paths list and merge
368 * nexthops in route->path->nh_list.
369 * Otherwise replace existing path's nh_list.
370 */
371 if (o_path == NULL) {
372 ecmp_path = ospf6_path_dup(&route->path);
373
374 /* Add a nh_list to new ecmp path */
375 ospf6_copy_nexthops(ecmp_path->nh_list,
376 route->nh_list);
377 /* Merge nexthop to existing route's nh_list */
378 ospf6_route_merge_nexthops(old_route, route);
379
380 /* Update RIB/FIB */
381 if (ospf6->route_table->hook_add)
996c9314
LB
382 (*ospf6->route_table->hook_add)(
383 old_route);
064d4355
CS
384
385 /* Add the new path to route's path list */
386 listnode_add_sort(old_route->paths, ecmp_path);
387
388 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
389 prefix2str(&route->prefix, buf,
390 sizeof(buf));
996c9314
LB
391 zlog_debug(
392 "%s: route %s another path added with nh %u, effective paths %u nh %u",
064d4355
CS
393 __PRETTY_FUNCTION__, buf,
394 listcount(ecmp_path->nh_list),
996c9314
LB
395 old_route->paths
396 ? listcount(
397 old_route
398 ->paths)
399 : 0,
07b37f93 400 listcount(old_route->nh_list));
064d4355
CS
401 }
402 } else {
403 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
404 nnode, nh)) {
405 for (ALL_LIST_ELEMENTS(
996c9314
LB
406 old_route->nh_list, rnode,
407 rnext, rnh)) {
064d4355
CS
408 if (!ospf6_nexthop_is_same(rnh,
409 nh))
410 continue;
411
412 listnode_delete(
413 old_route->nh_list,
414 rnh);
415 ospf6_nexthop_delete(rnh);
416 }
417 }
418 list_delete_all_node(o_path->nh_list);
419 ospf6_copy_nexthops(o_path->nh_list,
996c9314 420 route->nh_list);
064d4355
CS
421
422 /* Merge nexthop to existing route's nh_list */
996c9314 423 ospf6_route_merge_nexthops(old_route, route);
064d4355
CS
424
425 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
996c9314
LB
426 prefix2str(&route->prefix, buf,
427 sizeof(buf));
428 zlog_debug(
429 "%s: existing route %s with effective nh count %u",
430 __PRETTY_FUNCTION__, buf,
431 old_route->nh_list
432 ? listcount(
433 old_route
434 ->nh_list)
435 : 0);
064d4355
CS
436 }
437
438 /* Update RIB/FIB */
439 if (ospf6->route_table->hook_add)
996c9314
LB
440 (*ospf6->route_table->hook_add)(
441 old_route);
064d4355
CS
442 }
443 /* Delete the new route its info added to existing
444 * route.
445 */
446 ospf6_route_delete(route);
07b37f93 447
064d4355
CS
448 break;
449 }
450 }
451
452 if (!route_found) {
453 /* Add new route to existing node in ospf6 route table. */
454 ospf6_route_add(route, ospf6->route_table);
455 }
456}
457
d62a17ae 458void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
718e3744 459{
d62a17ae 460 struct ospf6_as_external_lsa *external;
461 struct prefix asbr_id;
064d4355
CS
462 struct ospf6_route *asbr_entry, *route, *old;
463 struct ospf6_path *path;
d62a17ae 464 char buf[PREFIX2STR_BUFFER];
465
466 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
467 lsa->header);
468
469 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
470 zlog_debug("Calculate AS-External route for %s", lsa->name);
471
472 if (lsa->header->adv_router == ospf6->router_id) {
473 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
474 zlog_debug("Ignore self-originated AS-External-LSA");
475 return;
476 }
477
478 if (OSPF6_ASBR_METRIC(external) == OSPF_LS_INFINITY) {
479 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
480 zlog_debug("Ignore LSA with LSInfinity Metric");
481 return;
482 }
483
484 if (CHECK_FLAG(external->prefix.prefix_options,
485 OSPF6_PREFIX_OPTION_NU)) {
486 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
487 zlog_debug("Ignore LSA with NU bit set Metric");
488 return;
489 }
490
491 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
492 asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
493 if (asbr_entry == NULL
494 || !CHECK_FLAG(asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) {
495 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
496 prefix2str(&asbr_id, buf, sizeof(buf));
497 zlog_debug("ASBR entry not found: %s", buf);
498 }
499 return;
500 }
501
502 route = ospf6_route_create();
503 route->type = OSPF6_DEST_TYPE_NETWORK;
504 route->prefix.family = AF_INET6;
505 route->prefix.prefixlen = external->prefix.prefix_length;
506 ospf6_prefix_in6_addr(&route->prefix.u.prefix6, &external->prefix);
507
508 route->path.area_id = asbr_entry->path.area_id;
509 route->path.origin.type = lsa->header->type;
510 route->path.origin.id = lsa->header->id;
511 route->path.origin.adv_router = lsa->header->adv_router;
512
513 route->path.prefix_options = external->prefix.prefix_options;
514 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
515 route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
516 route->path.metric_type = 2;
517 route->path.cost = asbr_entry->path.cost;
518 route->path.u.cost_e2 = OSPF6_ASBR_METRIC(external);
519 } else {
520 route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
521 route->path.metric_type = 1;
522 route->path.cost =
523 asbr_entry->path.cost + OSPF6_ASBR_METRIC(external);
524 route->path.u.cost_e2 = 0;
525 }
526
527 route->path.tag = ospf6_as_external_lsa_get_tag(lsa);
528
529 ospf6_route_copy_nexthops(route, asbr_entry);
530
064d4355
CS
531 path = ospf6_path_dup(&route->path);
532 ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
533 listnode_add_sort(route->paths, path);
534
535
d62a17ae 536 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
537 prefix2str(&route->prefix, buf, sizeof(buf));
064d4355
CS
538 zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
539 __PRETTY_FUNCTION__,
996c9314
LB
540 (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1
541 : 2,
542 buf, route->path.cost, route->path.u.cost_e2,
064d4355
CS
543 listcount(route->nh_list));
544 }
545
546 old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
547 if (!old) {
548 /* Add the new route to ospf6 instance route table. */
549 ospf6_route_add(route, ospf6->route_table);
550 } else {
551 /* RFC 2328 16.4 (6)
552 * ECMP: Keep new equal preference path in current
553 * route's path list, update zebra with new effective
554 * list along with addition of ECMP path.
555 */
556 ospf6_asbr_update_route_ecmp_path(old, route);
d62a17ae 557 }
718e3744 558}
559
07b37f93
CS
560void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
561 struct ospf6_route *asbr_entry)
718e3744 562{
d62a17ae 563 struct ospf6_as_external_lsa *external;
564 struct prefix prefix;
07b37f93 565 struct ospf6_route *route, *nroute, *route_to_del;
d62a17ae 566 char buf[PREFIX2STR_BUFFER];
567
568 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
569 lsa->header);
570
571 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
572 zlog_debug("Withdraw AS-External route for %s", lsa->name);
573
574 if (lsa->header->adv_router == ospf6->router_id) {
575 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
576 zlog_debug("Ignore self-originated AS-External-LSA");
577 return;
578 }
579
07b37f93
CS
580 route_to_del = ospf6_route_create();
581 route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
582 route_to_del->prefix.family = AF_INET6;
583 route_to_del->prefix.prefixlen = external->prefix.prefix_length;
584 ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6,
585 &external->prefix);
586
587 route_to_del->path.origin.type = lsa->header->type;
588 route_to_del->path.origin.id = lsa->header->id;
589 route_to_del->path.origin.adv_router = lsa->header->adv_router;
590
591 if (asbr_entry) {
592 route_to_del->path.area_id = asbr_entry->path.area_id;
593 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
594 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
595 route_to_del->path.metric_type = 2;
596 route_to_del->path.cost = asbr_entry->path.cost;
597 route_to_del->path.u.cost_e2 =
598 OSPF6_ASBR_METRIC(external);
599 } else {
600 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
601 route_to_del->path.metric_type = 1;
996c9314
LB
602 route_to_del->path.cost = asbr_entry->path.cost
603 + OSPF6_ASBR_METRIC(external);
07b37f93
CS
604 route_to_del->path.u.cost_e2 = 0;
605 }
606 }
607
d62a17ae 608 memset(&prefix, 0, sizeof(struct prefix));
609 prefix.family = AF_INET6;
610 prefix.prefixlen = external->prefix.prefix_length;
611 ospf6_prefix_in6_addr(&prefix.u.prefix6, &external->prefix);
612
613 route = ospf6_route_lookup(&prefix, ospf6->route_table);
614 if (route == NULL) {
615 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
616 prefix2str(&prefix, buf, sizeof(buf));
617 zlog_debug("AS-External route %s not found", buf);
618 }
267bf505
DS
619
620 ospf6_route_delete(route_to_del);
d62a17ae 621 return;
622 }
623
07b37f93
CS
624 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
625 prefix2str(&prefix, buf, sizeof(buf));
996c9314
LB
626 zlog_debug(
627 "%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u",
628 __PRETTY_FUNCTION__, buf, route->path.cost,
629 route->path.u.cost_e2, route_to_del->path.cost,
630 route_to_del->path.u.cost_e2);
07b37f93
CS
631 }
632
996c9314
LB
633 for (ospf6_route_lock(route);
634 route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
d62a17ae 635 nroute = ospf6_route_next(route);
07b37f93 636
d62a17ae 637 if (route->type != OSPF6_DEST_TYPE_NETWORK)
638 continue;
064d4355 639
07b37f93
CS
640 /* Route has multiple ECMP paths, remove matching
641 * path. Update current route's effective nh list
642 * after removal of one of the path.
064d4355
CS
643 */
644 if (listcount(route->paths) > 1) {
645 struct listnode *anode, *anext;
646 struct listnode *nnode, *rnode, *rnext;
647 struct ospf6_nexthop *nh, *rnh;
648 struct ospf6_path *o_path;
649 bool nh_updated = false;
650
651 /* Iterate all paths of route to find maching with LSA
652 * remove from route path list. If route->path is same,
653 * replace from paths list.
654 */
655 for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
996c9314 656 o_path)) {
07b37f93 657 if ((o_path->origin.type != lsa->header->type)
996c9314
LB
658 || (o_path->origin.adv_router
659 != lsa->header->adv_router)
660 || (o_path->origin.id != lsa->header->id))
064d4355 661 continue;
07b37f93
CS
662
663 /* Compare LSA cost with current
664 * route info.
665 */
996c9314
LB
666 if (!asbr_entry
667 && (o_path->cost != route_to_del->path.cost
668 || o_path->u.cost_e2
669 != route_to_del->path.u
670 .cost_e2)) {
07b37f93 671 if (IS_OSPF6_DEBUG_EXAMIN(
996c9314 672 AS_EXTERNAL)) {
07b37f93
CS
673 prefix2str(&prefix, buf,
674 sizeof(buf));
675 zlog_debug(
996c9314
LB
676 "%s: route %s to delete is not same, cost %u del cost %u. skip",
677 __PRETTY_FUNCTION__,
678 buf, route->path.cost,
679 route_to_del->path
680 .cost);
07b37f93 681 }
064d4355 682 continue;
07b37f93 683 }
064d4355 684
996c9314 685 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
064d4355
CS
686 prefix2str(&prefix, buf, sizeof(buf));
687 zlog_debug(
8873ebd3 688 "%s: route %s path found with cost %u nh %u to remove.",
064d4355 689 __PRETTY_FUNCTION__, buf,
8873ebd3 690 route->path.cost,
064d4355
CS
691 listcount(o_path->nh_list));
692 }
693
694 /* Remove found path's nh_list from
695 * the route's nh_list.
696 */
697 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
698 nnode, nh)) {
699 for (ALL_LIST_ELEMENTS(route->nh_list,
996c9314
LB
700 rnode, rnext,
701 rnh)) {
064d4355 702 if (!ospf6_nexthop_is_same(rnh,
996c9314 703 nh))
064d4355
CS
704 continue;
705 listnode_delete(route->nh_list,
706 rnh);
707 ospf6_nexthop_delete(rnh);
708 }
709 }
710 /* Delete the path from route's path list */
711 listnode_delete(route->paths, o_path);
712 ospf6_path_free(o_path);
713 nh_updated = true;
714 }
715
716 if (nh_updated) {
717 /* Iterate all paths and merge nexthop,
718 * unlesss any of the nexthop similar to
719 * ones deleted as part of path deletion.
720 */
721
722 for (ALL_LIST_ELEMENTS(route->paths, anode,
723 anext, o_path)) {
724 ospf6_merge_nexthops(route->nh_list,
725 o_path->nh_list);
726 }
727
728 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
729 prefix2str(&route->prefix, buf,
730 sizeof(buf));
996c9314
LB
731 zlog_debug(
732 "%s: AS-External %u route %s update paths %u nh %u",
733 __PRETTY_FUNCTION__,
734 (route->path.type
735 == OSPF6_PATH_TYPE_EXTERNAL1)
736 ? 1
737 : 2,
738 buf, listcount(route->paths),
739 listcount(route->nh_list));
064d4355
CS
740 }
741
8873ebd3
CS
742 if (listcount(route->paths)) {
743 /* Update RIB/FIB with effective
744 * nh_list
745 */
746 if (ospf6->route_table->hook_add)
747 (*ospf6->route_table->hook_add)
748 (route);
064d4355 749
8873ebd3
CS
750 /* route's primary path is similar
751 * to LSA, replace route's primary
752 * path with route's paths list head.
753 */
754 if ((route->path.origin.id ==
755 lsa->header->id) &&
756 (route->path.origin.adv_router
757 == lsa->header->adv_router)) {
758 struct ospf6_path *h_path;
064d4355 759
8873ebd3 760 h_path = (struct ospf6_path *)
996c9314
LB
761 listgetdata(
762 listhead(route->paths));
8873ebd3
CS
763 route->path.origin.type =
764 h_path->origin.type;
765 route->path.origin.id =
766 h_path->origin.id;
767 route->path.origin.adv_router =
064d4355 768 h_path->origin.adv_router;
8873ebd3
CS
769 }
770 } else {
771 ospf6_route_remove(route,
772 ospf6->route_table);
064d4355
CS
773 }
774 }
d62a17ae 775 continue;
776
064d4355 777 } else {
07b37f93
CS
778 /* Compare LSA origin and cost with current route info.
779 * if any check fails skip del this route node.
780 */
996c9314
LB
781 if (asbr_entry
782 && (!ospf6_route_is_same_origin(route, route_to_del)
783 || (route->path.type != route_to_del->path.type)
784 || (route->path.cost != route_to_del->path.cost)
785 || (route->path.u.cost_e2
786 != route_to_del->path.u.cost_e2))) {
07b37f93
CS
787 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
788 prefix2str(&prefix, buf, sizeof(buf));
996c9314
LB
789 zlog_debug(
790 "%s: route %s to delete is not same, cost %u del cost %u. skip",
791 __PRETTY_FUNCTION__, buf,
792 route->path.cost,
793 route_to_del->path.cost);
07b37f93 794 }
064d4355 795 continue;
07b37f93
CS
796 }
797
996c9314
LB
798 if ((route->path.origin.type != lsa->header->type)
799 || (route->path.origin.adv_router
800 != lsa->header->adv_router)
801 || (route->path.origin.id != lsa->header->id))
064d4355
CS
802 continue;
803 }
d62a17ae 804 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
805 prefix2str(&route->prefix, buf, sizeof(buf));
996c9314
LB
806 zlog_debug(
807 "%s: AS-External %u route remove %s cost %u(%u) nh %u",
808 __PRETTY_FUNCTION__,
809 route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
810 ? 1
811 : 2,
812 buf, route->path.cost, route->path.u.cost_e2,
813 listcount(route->nh_list));
d62a17ae 814 }
815 ospf6_route_remove(route, ospf6->route_table);
816 }
817 if (route != NULL)
818 ospf6_route_unlock(route);
07b37f93
CS
819
820 ospf6_route_delete(route_to_del);
718e3744 821}
822
d62a17ae 823void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry)
508e53e2 824{
d62a17ae 825 struct ospf6_lsa *lsa;
d7c0a89a
QY
826 uint16_t type;
827 uint32_t router;
d62a17ae 828
829 if (!CHECK_FLAG(asbr_entry->flag, OSPF6_ROUTE_BEST)) {
830 char buf[16];
831 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&asbr_entry->prefix),
832 buf, sizeof(buf));
833 zlog_info("ignore non-best path: lsentry %s add", buf);
834 return;
835 }
836
837 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
838 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
839 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
840 if (!OSPF6_LSA_IS_MAXAGE(lsa))
841 ospf6_asbr_lsa_add(lsa);
842 }
508e53e2 843}
844
d62a17ae 845void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry)
718e3744 846{
d62a17ae 847 struct ospf6_lsa *lsa;
d7c0a89a
QY
848 uint16_t type;
849 uint32_t router;
d62a17ae 850
851 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
852 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
853 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
07b37f93 854 ospf6_asbr_lsa_remove(lsa, asbr_entry);
508e53e2 855}
718e3744 856
508e53e2 857
508e53e2 858/* redistribute function */
859
d62a17ae 860static void ospf6_asbr_routemap_set(int type, const char *mapname)
508e53e2 861{
d62a17ae 862 if (ospf6->rmap[type].name)
863 free(ospf6->rmap[type].name);
864 ospf6->rmap[type].name = strdup(mapname);
865 ospf6->rmap[type].map = route_map_lookup_by_name(mapname);
718e3744 866}
867
d62a17ae 868static void ospf6_asbr_routemap_unset(int type)
718e3744 869{
d62a17ae 870 if (ospf6->rmap[type].name)
871 free(ospf6->rmap[type].name);
872 ospf6->rmap[type].name = NULL;
873 ospf6->rmap[type].map = NULL;
508e53e2 874}
875
856ae1eb
CS
876static int ospf6_asbr_routemap_update_timer(struct thread *thread)
877{
878 void **arg;
879 int arg_type;
880
881 arg = THREAD_ARG(thread);
882 arg_type = (int)(intptr_t)arg[1];
883
884 ospf6->t_distribute_update = NULL;
885
886 if (ospf6->rmap[arg_type].name)
996c9314
LB
887 ospf6->rmap[arg_type].map =
888 route_map_lookup_by_name(ospf6->rmap[arg_type].name);
856ae1eb
CS
889 if (ospf6->rmap[arg_type].map) {
890 if (IS_OSPF6_DEBUG_ASBR)
891 zlog_debug("%s: route-map %s update, reset redist %s",
892 __PRETTY_FUNCTION__,
893 ospf6->rmap[arg_type].name,
894 ZROUTE_NAME(arg_type));
895
896 ospf6_zebra_no_redistribute(arg_type);
897 ospf6_zebra_redistribute(arg_type);
898 }
899
900 XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
901 return 0;
902}
903
904void ospf6_asbr_distribute_list_update(int type)
905{
906 void **args = NULL;
907
908 if (ospf6->t_distribute_update)
909 return;
910
996c9314 911 args = XCALLOC(MTYPE_OSPF6_DIST_ARGS, sizeof(void *) * 2);
856ae1eb
CS
912
913 args[0] = ospf6;
914 args[1] = (void *)((ptrdiff_t)type);
915
916 if (IS_OSPF6_DEBUG_ASBR)
917 zlog_debug("%s: trigger redistribute %s reset thread",
918 __PRETTY_FUNCTION__, ZROUTE_NAME(type));
919
920 ospf6->t_distribute_update = NULL;
921 thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer,
922 (void **)args, OSPF_MIN_LS_INTERVAL,
923 &ospf6->t_distribute_update);
924}
925
d62a17ae 926static void ospf6_asbr_routemap_update(const char *mapname)
508e53e2 927{
d62a17ae 928 int type;
929
930 if (ospf6 == NULL)
931 return;
932
933 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
c600ce45 934 if (ospf6->rmap[type].name) {
d62a17ae 935 ospf6->rmap[type].map = route_map_lookup_by_name(
936 ospf6->rmap[type].name);
c600ce45 937
996c9314
LB
938 if (mapname && ospf6->rmap[type].map
939 && (strcmp(ospf6->rmap[type].name, mapname) == 0)) {
c600ce45 940 if (IS_OSPF6_DEBUG_ASBR)
996c9314
LB
941 zlog_debug(
942 "%s: route-map %s update, reset redist %s",
943 __PRETTY_FUNCTION__, mapname,
944 ZROUTE_NAME(type));
856ae1eb 945 ospf6_asbr_distribute_list_update(type);
c600ce45
CS
946 }
947 } else
d62a17ae 948 ospf6->rmap[type].map = NULL;
949 }
718e3744 950}
951
856ae1eb
CS
952static void ospf6_asbr_routemap_event(route_map_event_t event, const char *name)
953{
954 int type;
955
956 if (ospf6 == NULL)
957 return;
958 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
996c9314
LB
959 if ((ospf6->rmap[type].name)
960 && (strcmp(ospf6->rmap[type].name, name) == 0)) {
856ae1eb
CS
961 ospf6_asbr_distribute_list_update(type);
962 }
963 }
964}
965
d62a17ae 966int ospf6_asbr_is_asbr(struct ospf6 *o)
508e53e2 967{
d62a17ae 968 return o->external_table->count;
508e53e2 969}
970
d62a17ae 971static void ospf6_asbr_redistribute_set(int type)
718e3744 972{
d62a17ae 973 ospf6_zebra_redistribute(type);
508e53e2 974}
975
d62a17ae 976static void ospf6_asbr_redistribute_unset(int type)
508e53e2 977{
d62a17ae 978 struct ospf6_route *route;
979 struct ospf6_external_info *info;
718e3744 980
d62a17ae 981 ospf6_zebra_no_redistribute(type);
508e53e2 982
d62a17ae 983 for (route = ospf6_route_head(ospf6->external_table); route;
984 route = ospf6_route_next(route)) {
985 info = route->route_option;
986 if (info->type != type)
987 continue;
718e3744 988
d62a17ae 989 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix);
990 }
d9628728 991
d62a17ae 992 ospf6_asbr_routemap_unset(type);
508e53e2 993}
718e3744 994
ca1f4309 995/* When an area is unstubified, flood all the external LSAs in the area */
d62a17ae 996void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
ca1f4309 997{
d62a17ae 998 struct ospf6_lsa *lsa;
999
1000 for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
1001 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
1002 zlog_debug("%s: Flooding AS-External LSA %s\n",
1003 __func__, lsa->name);
1004 ospf6_flood_area(NULL, lsa, oa);
1005 }
ca1f4309 1006 }
ca1f4309
DS
1007}
1008
d62a17ae 1009void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
d7c0a89a
QY
1010 struct prefix *prefix,
1011 unsigned int nexthop_num,
d62a17ae 1012 struct in6_addr *nexthop, route_tag_t tag)
508e53e2 1013{
d62a17ae 1014 int ret;
1015 struct ospf6_route troute;
1016 struct ospf6_external_info tinfo;
1017 struct ospf6_route *route, *match;
1018 struct ospf6_external_info *info;
1019 struct prefix prefix_id;
1020 struct route_node *node;
1021 char pbuf[PREFIX2STR_BUFFER], ibuf[16];
1022 struct listnode *lnode, *lnnode;
1023 struct ospf6_area *oa;
1024
1025 if (!ospf6_zebra_is_redistribute(type))
1026 return;
1027
6e38a9ec
VJ
1028 memset(&troute, 0, sizeof(troute));
1029 memset(&tinfo, 0, sizeof(tinfo));
1030
d62a17ae 1031 if (IS_OSPF6_DEBUG_ASBR) {
1032 prefix2str(prefix, pbuf, sizeof(pbuf));
1033 zlog_debug("Redistribute %s (%s)", pbuf, ZROUTE_NAME(type));
1034 }
1035
1036 /* if route-map was specified but not found, do not advertise */
1037 if (ospf6->rmap[type].name) {
1038 if (ospf6->rmap[type].map == NULL)
1039 ospf6_asbr_routemap_update(NULL);
1040 if (ospf6->rmap[type].map == NULL) {
1041 zlog_warn(
1042 "route-map \"%s\" not found, suppress redistributing",
1043 ospf6->rmap[type].name);
1044 return;
1045 }
1046 }
1047
1048 /* apply route-map */
1049 if (ospf6->rmap[type].map) {
d62a17ae 1050 troute.route_option = &tinfo;
1051 tinfo.ifindex = ifindex;
1052 tinfo.tag = tag;
1053
1054 ret = route_map_apply(ospf6->rmap[type].map, prefix, RMAP_OSPF6,
1055 &troute);
1056 if (ret == RMAP_DENYMATCH) {
1057 if (IS_OSPF6_DEBUG_ASBR)
1058 zlog_debug("Denied by route-map \"%s\"",
1059 ospf6->rmap[type].name);
1060 return;
1061 }
1062 }
1063
1064 match = ospf6_route_lookup(prefix, ospf6->external_table);
1065 if (match) {
1066 info = match->route_option;
d62a17ae 1067 /* copy result of route-map */
1068 if (ospf6->rmap[type].map) {
1069 if (troute.path.metric_type)
1070 match->path.metric_type =
1071 troute.path.metric_type;
1072 if (troute.path.cost)
1073 match->path.cost = troute.path.cost;
1074 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1075 memcpy(&info->forwarding, &tinfo.forwarding,
1076 sizeof(struct in6_addr));
1077 info->tag = tinfo.tag;
1078 } else {
1079 /* If there is no route-map, simply update the tag */
1080 info->tag = tag;
1081 }
1082
1083 info->type = type;
1084
1085 if (nexthop_num && nexthop)
1086 ospf6_route_add_nexthop(match, ifindex, nexthop);
1087 else
1088 ospf6_route_add_nexthop(match, ifindex, NULL);
1089
1090 /* create/update binding in external_id_table */
1091 prefix_id.family = AF_INET;
1092 prefix_id.prefixlen = 32;
1093 prefix_id.u.prefix4.s_addr = htonl(info->id);
1094 node = route_node_get(ospf6->external_id_table, &prefix_id);
1095 node->info = match;
1096
1097 if (IS_OSPF6_DEBUG_ASBR) {
1098 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf,
1099 sizeof(ibuf));
856ae1eb 1100 prefix2str(prefix, pbuf, sizeof(pbuf));
996c9314
LB
1101 zlog_debug(
1102 "Advertise as AS-External Id:%s prefix %s metric %u",
1103 ibuf, pbuf, match->path.metric_type);
d62a17ae 1104 }
1105
1106 match->path.origin.id = htonl(info->id);
1107 ospf6_as_external_lsa_originate(match);
1108 return;
1109 }
1110
1111 /* create new entry */
1112 route = ospf6_route_create();
1113 route->type = OSPF6_DEST_TYPE_NETWORK;
1114 memcpy(&route->prefix, prefix, sizeof(struct prefix));
1115
1116 info = (struct ospf6_external_info *)XCALLOC(
1117 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
1118 route->route_option = info;
1119 info->id = ospf6->external_id++;
1120
1121 /* copy result of route-map */
1122 if (ospf6->rmap[type].map) {
1123 if (troute.path.metric_type)
1124 route->path.metric_type = troute.path.metric_type;
1125 if (troute.path.cost)
1126 route->path.cost = troute.path.cost;
1127 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1128 memcpy(&info->forwarding, &tinfo.forwarding,
1129 sizeof(struct in6_addr));
1130 info->tag = tinfo.tag;
1131 } else {
1132 /* If there is no route-map, simply set the tag */
1133 info->tag = tag;
1134 }
1135
1136 info->type = type;
1137 if (nexthop_num && nexthop)
1138 ospf6_route_add_nexthop(route, ifindex, nexthop);
1139 else
1140 ospf6_route_add_nexthop(route, ifindex, NULL);
1141
1142 /* create/update binding in external_id_table */
1143 prefix_id.family = AF_INET;
1144 prefix_id.prefixlen = 32;
1145 prefix_id.u.prefix4.s_addr = htonl(info->id);
1146 node = route_node_get(ospf6->external_id_table, &prefix_id);
1147 node->info = route;
1148
1149 route = ospf6_route_add(route, ospf6->external_table);
1150 route->route_option = info;
1151
1152 if (IS_OSPF6_DEBUG_ASBR) {
1153 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
856ae1eb
CS
1154 prefix2str(prefix, pbuf, sizeof(pbuf));
1155 zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
1156 ibuf, pbuf, route->path.metric_type);
d62a17ae 1157 }
1158
1159 route->path.origin.id = htonl(info->id);
1160 ospf6_as_external_lsa_originate(route);
1161
1162 /* Router-Bit (ASBR Flag) may have to be updated */
1163 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1164 OSPF6_ROUTER_LSA_SCHEDULE(oa);
718e3744 1165}
1166
d62a17ae 1167void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
1168 struct prefix *prefix)
718e3744 1169{
d62a17ae 1170 struct ospf6_route *match;
1171 struct ospf6_external_info *info = NULL;
1172 struct route_node *node;
1173 struct ospf6_lsa *lsa;
1174 struct prefix prefix_id;
1175 char pbuf[PREFIX2STR_BUFFER], ibuf[16];
1176 struct listnode *lnode, *lnnode;
1177 struct ospf6_area *oa;
1178
1179 match = ospf6_route_lookup(prefix, ospf6->external_table);
1180 if (match == NULL) {
1181 if (IS_OSPF6_DEBUG_ASBR) {
1182 prefix2str(prefix, pbuf, sizeof(pbuf));
1183 zlog_debug("No such route %s to withdraw", pbuf);
1184 }
1185 return;
1186 }
1187
1188 info = match->route_option;
1189 assert(info);
1190
1191 if (info->type != type) {
1192 if (IS_OSPF6_DEBUG_ASBR) {
1193 prefix2str(prefix, pbuf, sizeof(pbuf));
1194 zlog_debug("Original protocol mismatch: %s", pbuf);
1195 }
1196 return;
1197 }
1198
1199 if (IS_OSPF6_DEBUG_ASBR) {
1200 prefix2str(prefix, pbuf, sizeof(pbuf));
1201 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
1202 zlog_debug("Withdraw %s (AS-External Id:%s)", pbuf, ibuf);
1203 }
1204
1205 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
1206 htonl(info->id), ospf6->router_id, ospf6->lsdb);
1207 if (lsa)
1208 ospf6_lsa_purge(lsa);
1209
1210 /* remove binding in external_id_table */
1211 prefix_id.family = AF_INET;
1212 prefix_id.prefixlen = 32;
1213 prefix_id.u.prefix4.s_addr = htonl(info->id);
1214 node = route_node_lookup(ospf6->external_id_table, &prefix_id);
1215 assert(node);
1216 node->info = NULL;
d107621d
CS
1217 route_unlock_node(node); /* to free the lookup lock */
1218 route_unlock_node(node); /* to free the original lock */
d62a17ae 1219
1220 ospf6_route_remove(match, ospf6->external_table);
1221 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
1222
1223 /* Router-Bit (ASBR Flag) may have to be updated */
1224 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1225 OSPF6_ROUTER_LSA_SCHEDULE(oa);
718e3744 1226}
1227
508e53e2 1228DEFUN (ospf6_redistribute,
1229 ospf6_redistribute_cmd,
40d1cbfb 1230 "redistribute " FRR_REDIST_STR_OSPF6D,
508e53e2 1231 "Redistribute\n"
3b14d86e 1232 FRR_REDIST_HELP_STR_OSPF6D)
718e3744 1233{
d62a17ae 1234 int type;
e0ca5fde 1235
d62a17ae 1236 char *proto = argv[argc - 1]->text;
1237 type = proto_redistnum(AFI_IP6, proto);
1238 if (type < 0)
1239 return CMD_WARNING_CONFIG_FAILED;
718e3744 1240
d62a17ae 1241 ospf6_asbr_redistribute_unset(type);
1242 ospf6_asbr_redistribute_set(type);
1243 return CMD_SUCCESS;
508e53e2 1244}
718e3744 1245
508e53e2 1246DEFUN (ospf6_redistribute_routemap,
1247 ospf6_redistribute_routemap_cmd,
40d1cbfb 1248 "redistribute " FRR_REDIST_STR_OSPF6D " route-map WORD",
508e53e2 1249 "Redistribute\n"
ab0181ee 1250 FRR_REDIST_HELP_STR_OSPF6D
508e53e2 1251 "Route map reference\n"
e52702f2 1252 "Route map name\n")
508e53e2 1253{
d62a17ae 1254 int idx_protocol = 1;
1255 int idx_word = 3;
1256 int type;
1257
1258 char *proto = argv[idx_protocol]->text;
1259 type = proto_redistnum(AFI_IP6, proto);
1260 if (type < 0)
1261 return CMD_WARNING_CONFIG_FAILED;
1262
1263 ospf6_asbr_redistribute_unset(type);
1264 ospf6_asbr_routemap_set(type, argv[idx_word]->arg);
1265 ospf6_asbr_redistribute_set(type);
1266 return CMD_SUCCESS;
508e53e2 1267}
1268
1269DEFUN (no_ospf6_redistribute,
1270 no_ospf6_redistribute_cmd,
40d1cbfb 1271 "no redistribute " FRR_REDIST_STR_OSPF6D " [route-map WORD]",
508e53e2 1272 NO_STR
1273 "Redistribute\n"
ab0181ee 1274 FRR_REDIST_HELP_STR_OSPF6D
1d68dbfe
DW
1275 "Route map reference\n"
1276 "Route map name\n")
508e53e2 1277{
d62a17ae 1278 int idx_protocol = 2;
1279 int type;
e0ca5fde 1280
d62a17ae 1281 char *proto = argv[idx_protocol]->text;
1282 type = proto_redistnum(AFI_IP6, proto);
1283 if (type < 0)
1284 return CMD_WARNING_CONFIG_FAILED;
e26bbeba 1285
d62a17ae 1286 ospf6_asbr_redistribute_unset(type);
e26bbeba 1287
d62a17ae 1288 return CMD_SUCCESS;
508e53e2 1289}
718e3744 1290
d62a17ae 1291int ospf6_redistribute_config_write(struct vty *vty)
508e53e2 1292{
d62a17ae 1293 int type;
1294
1295 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1296 if (type == ZEBRA_ROUTE_OSPF6)
1297 continue;
1298 if (!ospf6_zebra_is_redistribute(type))
1299 continue;
1300
1301 if (ospf6->rmap[type].name)
1302 vty_out(vty, " redistribute %s route-map %s\n",
1303 ZROUTE_NAME(type), ospf6->rmap[type].name);
1304 else
1305 vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type));
1306 }
1307
1308 return 0;
718e3744 1309}
1310
d62a17ae 1311static void ospf6_redistribute_show_config(struct vty *vty)
718e3744 1312{
d62a17ae 1313 int type;
1314 int nroute[ZEBRA_ROUTE_MAX];
1315 int total;
1316 struct ospf6_route *route;
1317 struct ospf6_external_info *info;
1318
1319 total = 0;
1320 for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
1321 nroute[type] = 0;
1322 for (route = ospf6_route_head(ospf6->external_table); route;
1323 route = ospf6_route_next(route)) {
1324 info = route->route_option;
1325 nroute[info->type]++;
1326 total++;
1327 }
718e3744 1328
d62a17ae 1329 vty_out(vty, "Redistributing External Routes from:\n");
1330 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1331 if (type == ZEBRA_ROUTE_OSPF6)
1332 continue;
1333 if (!ospf6_zebra_is_redistribute(type))
1334 continue;
1335
1336 if (ospf6->rmap[type].name)
1337 vty_out(vty, " %d: %s with route-map \"%s\"%s\n",
1338 nroute[type], ZROUTE_NAME(type),
1339 ospf6->rmap[type].name,
1340 (ospf6->rmap[type].map ? ""
1341 : " (not found !)"));
1342 else
1343 vty_out(vty, " %d: %s\n", nroute[type],
1344 ZROUTE_NAME(type));
1345 }
1346 vty_out(vty, "Total %d routes\n", total);
1347}
718e3744 1348
6b0655a2 1349
508e53e2 1350/* Routemap Functions */
6ac29a51 1351static route_map_result_t
d62a17ae 1352ospf6_routemap_rule_match_address_prefixlist(void *rule, struct prefix *prefix,
1353 route_map_object_t type,
1354 void *object)
508e53e2 1355{
d62a17ae 1356 struct prefix_list *plist;
718e3744 1357
d62a17ae 1358 if (type != RMAP_OSPF6)
1359 return RMAP_NOMATCH;
718e3744 1360
d62a17ae 1361 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1362 if (plist == NULL)
1363 return RMAP_NOMATCH;
718e3744 1364
d62a17ae 1365 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1366 : RMAP_MATCH);
508e53e2 1367}
718e3744 1368
6ac29a51 1369static void *
d62a17ae 1370ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
508e53e2 1371{
d62a17ae 1372 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 1373}
1374
d62a17ae 1375static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
718e3744 1376{
d62a17ae 1377 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 1378}
718e3744 1379
d62a17ae 1380struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = {
1381 "ipv6 address prefix-list",
1382 ospf6_routemap_rule_match_address_prefixlist,
1383 ospf6_routemap_rule_match_address_prefixlist_compile,
1384 ospf6_routemap_rule_match_address_prefixlist_free,
508e53e2 1385};
718e3744 1386
42a7debf
VT
1387/* `match interface IFNAME' */
1388/* Match function should return 1 if match is success else return
1389 zero. */
1390static route_map_result_t
d62a17ae 1391ospf6_routemap_rule_match_interface(void *rule, struct prefix *prefix,
1392 route_map_object_t type, void *object)
42a7debf 1393{
d62a17ae 1394 struct interface *ifp;
1395 struct ospf6_external_info *ei;
42a7debf 1396
d62a17ae 1397 if (type == RMAP_OSPF6) {
1398 ei = ((struct ospf6_route *)object)->route_option;
1399 ifp = if_lookup_by_name((char *)rule, VRF_DEFAULT);
42a7debf 1400
d62a17ae 1401 if (ifp != NULL && ei->ifindex == ifp->ifindex)
1402 return RMAP_MATCH;
1403 }
42a7debf 1404
d62a17ae 1405 return RMAP_NOMATCH;
42a7debf
VT
1406}
1407
1408/* Route map `interface' match statement. `arg' should be
1409 interface name. */
d62a17ae 1410static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
42a7debf 1411{
d62a17ae 1412 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
42a7debf
VT
1413}
1414
1415/* Free route map's compiled `interface' value. */
d62a17ae 1416static void ospf6_routemap_rule_match_interface_free(void *rule)
42a7debf 1417{
d62a17ae 1418 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
42a7debf
VT
1419}
1420
1421/* Route map commands for interface matching. */
d62a17ae 1422struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = {
1423 "interface", ospf6_routemap_rule_match_interface,
1424 ospf6_routemap_rule_match_interface_compile,
1425 ospf6_routemap_rule_match_interface_free};
42a7debf 1426
464015fa 1427/* Match function for matching route tags */
d62a17ae 1428static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
1429 struct prefix *prefix,
1430 route_map_object_t type,
1431 void *object)
464015fa 1432{
d62a17ae 1433 route_tag_t *tag = rule;
1434 struct ospf6_route *route = object;
1435 struct ospf6_external_info *info = route->route_option;
464015fa 1436
d62a17ae 1437 if (type == RMAP_OSPF6 && info->tag == *tag)
1438 return RMAP_MATCH;
464015fa 1439
d62a17ae 1440 return RMAP_NOMATCH;
464015fa
CF
1441}
1442
d62a17ae 1443static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = {
9d303b37 1444 "tag", ospf6_routemap_rule_match_tag, route_map_rule_tag_compile,
d62a17ae 1445 route_map_rule_tag_free,
464015fa
CF
1446};
1447
6ac29a51 1448static route_map_result_t
d62a17ae 1449ospf6_routemap_rule_set_metric_type(void *rule, struct prefix *prefix,
1450 route_map_object_t type, void *object)
508e53e2 1451{
d62a17ae 1452 char *metric_type = rule;
1453 struct ospf6_route *route = object;
718e3744 1454
d62a17ae 1455 if (type != RMAP_OSPF6)
1456 return RMAP_OKAY;
718e3744 1457
d62a17ae 1458 if (strcmp(metric_type, "type-2") == 0)
1459 route->path.metric_type = 2;
1460 else
1461 route->path.metric_type = 1;
718e3744 1462
d62a17ae 1463 return RMAP_OKAY;
508e53e2 1464}
718e3744 1465
d62a17ae 1466static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
508e53e2 1467{
d62a17ae 1468 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
1469 return NULL;
1470 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 1471}
1472
d62a17ae 1473static void ospf6_routemap_rule_set_metric_type_free(void *rule)
718e3744 1474{
d62a17ae 1475 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 1476}
718e3744 1477
d62a17ae 1478struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = {
9d303b37 1479 "metric-type", ospf6_routemap_rule_set_metric_type,
d62a17ae 1480 ospf6_routemap_rule_set_metric_type_compile,
1481 ospf6_routemap_rule_set_metric_type_free,
508e53e2 1482};
718e3744 1483
6ac29a51 1484static route_map_result_t
d62a17ae 1485ospf6_routemap_rule_set_metric(void *rule, struct prefix *prefix,
1486 route_map_object_t type, void *object)
508e53e2 1487{
d62a17ae 1488 char *metric = rule;
1489 struct ospf6_route *route = object;
718e3744 1490
d62a17ae 1491 if (type != RMAP_OSPF6)
1492 return RMAP_OKAY;
718e3744 1493
d62a17ae 1494 route->path.cost = atoi(metric);
1495 return RMAP_OKAY;
508e53e2 1496}
718e3744 1497
d62a17ae 1498static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
508e53e2 1499{
d7c0a89a 1500 uint32_t metric;
d62a17ae 1501 char *endp;
1502 metric = strtoul(arg, &endp, 0);
1503 if (metric > OSPF_LS_INFINITY || *endp != '\0')
1504 return NULL;
1505 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 1506}
1507
d62a17ae 1508static void ospf6_routemap_rule_set_metric_free(void *rule)
718e3744 1509{
d62a17ae 1510 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 1511}
718e3744 1512
d62a17ae 1513struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = {
9d303b37 1514 "metric", ospf6_routemap_rule_set_metric,
d62a17ae 1515 ospf6_routemap_rule_set_metric_compile,
1516 ospf6_routemap_rule_set_metric_free,
508e53e2 1517};
718e3744 1518
6ac29a51 1519static route_map_result_t
d62a17ae 1520ospf6_routemap_rule_set_forwarding(void *rule, struct prefix *prefix,
1521 route_map_object_t type, void *object)
508e53e2 1522{
d62a17ae 1523 char *forwarding = rule;
1524 struct ospf6_route *route = object;
1525 struct ospf6_external_info *info = route->route_option;
718e3744 1526
d62a17ae 1527 if (type != RMAP_OSPF6)
1528 return RMAP_OKAY;
718e3744 1529
d62a17ae 1530 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
1531 memset(&info->forwarding, 0, sizeof(struct in6_addr));
1532 return RMAP_ERROR;
1533 }
718e3744 1534
d62a17ae 1535 return RMAP_OKAY;
718e3744 1536}
1537
d62a17ae 1538static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
718e3744 1539{
d62a17ae 1540 struct in6_addr a;
1541 if (inet_pton(AF_INET6, arg, &a) != 1)
1542 return NULL;
1543 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 1544}
1545
d62a17ae 1546static void ospf6_routemap_rule_set_forwarding_free(void *rule)
718e3744 1547{
d62a17ae 1548 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 1549}
718e3744 1550
d62a17ae 1551struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = {
9d303b37 1552 "forwarding-address", ospf6_routemap_rule_set_forwarding,
d62a17ae 1553 ospf6_routemap_rule_set_forwarding_compile,
1554 ospf6_routemap_rule_set_forwarding_free,
508e53e2 1555};
718e3744 1556
d62a17ae 1557static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
1558 struct prefix *prefix,
1559 route_map_object_t type,
1560 void *object)
464015fa 1561{
d62a17ae 1562 route_tag_t *tag = rule;
1563 struct ospf6_route *route = object;
1564 struct ospf6_external_info *info = route->route_option;
464015fa 1565
d62a17ae 1566 if (type != RMAP_OSPF6)
1567 return RMAP_OKAY;
464015fa 1568
d62a17ae 1569 info->tag = *tag;
1570 return RMAP_OKAY;
464015fa
CF
1571}
1572
d62a17ae 1573static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
9d303b37 1574 "tag", ospf6_routemap_rule_set_tag, route_map_rule_tag_compile,
d62a17ae 1575 route_map_rule_tag_free,
464015fa
CF
1576};
1577
d62a17ae 1578static int route_map_command_status(struct vty *vty, int ret)
508e53e2 1579{
d62a17ae 1580 switch (ret) {
1581 case RMAP_RULE_MISSING:
1582 vty_out(vty, "OSPF6 Can't find rule.\n");
9ca25fed 1583 return CMD_WARNING_CONFIG_FAILED;
d62a17ae 1584 break;
1585 case RMAP_COMPILE_ERROR:
1586 vty_out(vty, "OSPF6 Argument is malformed.\n");
9ca25fed 1587 return CMD_WARNING_CONFIG_FAILED;
d62a17ae 1588 break;
9ca25fed 1589 case RMAP_COMPILE_SUCCESS:
d62a17ae 1590 break;
1591 }
9ca25fed
DS
1592
1593 return CMD_SUCCESS;
508e53e2 1594}
718e3744 1595
508e53e2 1596/* add "set metric-type" */
1597DEFUN (ospf6_routemap_set_metric_type,
1598 ospf6_routemap_set_metric_type_cmd,
6147e2c6 1599 "set metric-type <type-1|type-2>",
508e53e2 1600 "Set value\n"
1601 "Type of metric\n"
1602 "OSPF6 external type 1 metric\n"
1603 "OSPF6 external type 2 metric\n")
1604{
d62a17ae 1605 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1606 int idx_external = 2;
1607 int ret = route_map_add_set(route_map_index, "metric-type",
1608 argv[idx_external]->arg);
1609 return route_map_command_status(vty, ret);
718e3744 1610}
1611
508e53e2 1612/* delete "set metric-type" */
1613DEFUN (ospf6_routemap_no_set_metric_type,
1614 ospf6_routemap_no_set_metric_type_cmd,
dab8cd00 1615 "no set metric-type [<type-1|type-2>]",
508e53e2 1616 NO_STR
1617 "Set value\n"
1618 "Type of metric\n"
1619 "OSPF6 external type 1 metric\n"
1620 "OSPF6 external type 2 metric\n")
718e3744 1621{
d62a17ae 1622 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1623 char *ext = (argc == 4) ? argv[3]->text : NULL;
1624 int ret = route_map_delete_set(route_map_index, "metric-type", ext);
1625 return route_map_command_status(vty, ret);
508e53e2 1626}
718e3744 1627
508e53e2 1628/* add "set forwarding-address" */
1629DEFUN (ospf6_routemap_set_forwarding,
1630 ospf6_routemap_set_forwarding_cmd,
1631 "set forwarding-address X:X::X:X",
1632 "Set value\n"
1633 "Forwarding Address\n"
1634 "IPv6 Address\n")
1635{
d62a17ae 1636 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1637 int idx_ipv6 = 2;
1638 int ret = route_map_add_set(route_map_index, "forwarding-address",
1639 argv[idx_ipv6]->arg);
1640 return route_map_command_status(vty, ret);
508e53e2 1641}
718e3744 1642
508e53e2 1643/* delete "set forwarding-address" */
1644DEFUN (ospf6_routemap_no_set_forwarding,
1645 ospf6_routemap_no_set_forwarding_cmd,
1646 "no set forwarding-address X:X::X:X",
1647 NO_STR
1648 "Set value\n"
1649 "Forwarding Address\n"
1650 "IPv6 Address\n")
1651{
d62a17ae 1652 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1653 int idx_ipv6 = 3;
1654 int ret = route_map_delete_set(route_map_index, "forwarding-address",
1655 argv[idx_ipv6]->arg);
1656 return route_map_command_status(vty, ret);
508e53e2 1657}
718e3744 1658
d62a17ae 1659static void ospf6_routemap_init(void)
508e53e2 1660{
d62a17ae 1661 route_map_init();
b2575bc0 1662
d62a17ae 1663 route_map_add_hook(ospf6_asbr_routemap_update);
1664 route_map_delete_hook(ospf6_asbr_routemap_update);
856ae1eb 1665 route_map_event_hook(ospf6_asbr_routemap_event);
508e53e2 1666
d62a17ae 1667 route_map_set_metric_hook(generic_set_add);
1668 route_map_no_set_metric_hook(generic_set_delete);
82f97584 1669
d62a17ae 1670 route_map_match_tag_hook(generic_match_add);
1671 route_map_no_match_tag_hook(generic_match_delete);
e1a1b2ed 1672
d62a17ae 1673 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
1674 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
e1a1b2ed 1675
d62a17ae 1676 route_map_match_interface_hook(generic_match_add);
1677 route_map_no_match_interface_hook(generic_match_delete);
e1a1b2ed 1678
d62a17ae 1679 route_map_install_match(
1680 &ospf6_routemap_rule_match_address_prefixlist_cmd);
1681 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
1682 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
42a7debf 1683
d62a17ae 1684 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
1685 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
1686 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
1687 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
508e53e2 1688
d62a17ae 1689 /* ASE Metric Type (e.g. Type-1/Type-2) */
1690 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
1691 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
508e53e2 1692
d62a17ae 1693 /* ASE Metric */
1694 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
1695 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
718e3744 1696}
1697
6b0655a2 1698
508e53e2 1699/* Display functions */
d62a17ae 1700static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
1701 char *buf, int buflen,
1702 int pos)
e68a6767 1703{
d62a17ae 1704 struct ospf6_as_external_lsa *external;
1705 struct in6_addr in6;
1706 int prefix_length = 0;
1707
1708 if (lsa) {
1709 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
1710 lsa->header);
1711
1712 if (pos == 0) {
1713 ospf6_prefix_in6_addr(&in6, &external->prefix);
1714 prefix_length = external->prefix.prefix_length;
1715 } else {
1716 in6 = *((struct in6_addr
1717 *)((caddr_t)external
1718 + sizeof(struct
1719 ospf6_as_external_lsa)
1720 + OSPF6_PREFIX_SPACE(
1721 external->prefix
1722 .prefix_length)));
1723 }
1724 if (buf) {
1725 inet_ntop(AF_INET6, &in6, buf, buflen);
1726 if (prefix_length)
1727 sprintf(&buf[strlen(buf)], "/%d",
1728 prefix_length);
1729 }
e68a6767 1730 }
d62a17ae 1731 return (buf);
e68a6767
DD
1732}
1733
d62a17ae 1734static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
718e3744 1735{
d62a17ae 1736 struct ospf6_as_external_lsa *external;
1737 char buf[64];
1738
1739 assert(lsa->header);
1740 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
1741 lsa->header);
1742
1743 /* bits */
1744 snprintf(buf, sizeof(buf), "%c%c%c",
1745 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
1746 : '-'),
1747 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
1748 : '-'),
1749 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
1750 : '-'));
1751
1752 vty_out(vty, " Bits: %s\n", buf);
1753 vty_out(vty, " Metric: %5lu\n",
d7c0a89a 1754 (unsigned long)OSPF6_ASBR_METRIC(external));
d62a17ae 1755
1756 ospf6_prefix_options_printbuf(external->prefix.prefix_options, buf,
1757 sizeof(buf));
1758 vty_out(vty, " Prefix Options: %s\n", buf);
1759
1760 vty_out(vty, " Referenced LSType: %d\n",
1761 ntohs(external->prefix.prefix_refer_lstype));
1762
1763 vty_out(vty, " Prefix: %s\n",
1764 ospf6_as_external_lsa_get_prefix_str(lsa, buf, sizeof(buf), 0));
1765
1766 /* Forwarding-Address */
1767 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
1768 vty_out(vty, " Forwarding-Address: %s\n",
1769 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
1770 sizeof(buf), 1));
1771 }
1772
1773 /* Tag */
1774 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
1775 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
1776 ospf6_as_external_lsa_get_tag(lsa));
1777 }
1778
1779 return 0;
718e3744 1780}
1781
d62a17ae 1782static void ospf6_asbr_external_route_show(struct vty *vty,
1783 struct ospf6_route *route)
718e3744 1784{
d62a17ae 1785 struct ospf6_external_info *info = route->route_option;
1786 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
d7c0a89a 1787 uint32_t tmp_id;
d62a17ae 1788
1789 prefix2str(&route->prefix, prefix, sizeof(prefix));
1790 tmp_id = ntohl(info->id);
1791 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
1792 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
1793 inet_ntop(AF_INET6, &info->forwarding, forwarding,
1794 sizeof(forwarding));
1795 else
1796 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
1797 ospf6_route_get_first_nh_index(route));
1798
1799 vty_out(vty, "%c %-32s %-15s type-%d %5lu %s\n",
1800 zebra_route_char(info->type), prefix, id,
1801 route->path.metric_type,
d7c0a89a
QY
1802 (unsigned long)(route->path.metric_type == 2
1803 ? route->path.u.cost_e2
1804 : route->path.cost),
d62a17ae 1805 forwarding);
718e3744 1806}
1807
508e53e2 1808DEFUN (show_ipv6_ospf6_redistribute,
1809 show_ipv6_ospf6_redistribute_cmd,
1810 "show ipv6 ospf6 redistribute",
1811 SHOW_STR
1812 IP6_STR
1813 OSPF6_STR
1814 "redistributing External information\n"
1815 )
718e3744 1816{
d62a17ae 1817 struct ospf6_route *route;
718e3744 1818
d62a17ae 1819 OSPF6_CMD_CHECK_RUNNING();
b52a8a52 1820
d62a17ae 1821 ospf6_redistribute_show_config(vty);
718e3744 1822
d62a17ae 1823 for (route = ospf6_route_head(ospf6->external_table); route;
1824 route = ospf6_route_next(route))
1825 ospf6_asbr_external_route_show(vty, route);
508e53e2 1826
d62a17ae 1827 return CMD_SUCCESS;
718e3744 1828}
1829
d62a17ae 1830struct ospf6_lsa_handler as_external_handler = {
3981b5c7
VJ
1831 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
1832 .lh_name = "AS-External",
1833 .lh_short_name = "ASE",
1834 .lh_show = ospf6_as_external_lsa_show,
1835 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
996c9314 1836 .lh_debug = 0};
508e53e2 1837
d62a17ae 1838void ospf6_asbr_init(void)
718e3744 1839{
d62a17ae 1840 ospf6_routemap_init();
508e53e2 1841
d62a17ae 1842 ospf6_install_lsa_handler(&as_external_handler);
718e3744 1843
d62a17ae 1844 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
508e53e2 1845
d62a17ae 1846 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
1847 install_element(OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
1848 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
718e3744 1849}
1850
d62a17ae 1851void ospf6_asbr_redistribute_reset(void)
d9628728 1852{
d62a17ae 1853 int type;
1854
1855 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1856 if (type == ZEBRA_ROUTE_OSPF6)
1857 continue;
1858 if (ospf6_zebra_is_redistribute(type))
1859 ospf6_asbr_redistribute_unset(type);
1860 }
d9628728
CF
1861}
1862
d62a17ae 1863void ospf6_asbr_terminate(void)
ae2254aa 1864{
856ae1eb
CS
1865 /* Cleanup route maps */
1866 route_map_add_hook(NULL);
1867 route_map_delete_hook(NULL);
1868 route_map_event_hook(NULL);
d62a17ae 1869 route_map_finish();
ae2254aa 1870}
718e3744 1871
508e53e2 1872DEFUN (debug_ospf6_asbr,
1873 debug_ospf6_asbr_cmd,
1874 "debug ospf6 asbr",
1875 DEBUG_STR
1876 OSPF6_STR
1877 "Debug OSPFv3 ASBR function\n"
1878 )
1879{
d62a17ae 1880 OSPF6_DEBUG_ASBR_ON();
1881 return CMD_SUCCESS;
508e53e2 1882}
1883
1884DEFUN (no_debug_ospf6_asbr,
1885 no_debug_ospf6_asbr_cmd,
1886 "no debug ospf6 asbr",
1887 NO_STR
1888 DEBUG_STR
1889 OSPF6_STR
1890 "Debug OSPFv3 ASBR function\n"
1891 )
1892{
d62a17ae 1893 OSPF6_DEBUG_ASBR_OFF();
1894 return CMD_SUCCESS;
508e53e2 1895}
1896
d62a17ae 1897int config_write_ospf6_debug_asbr(struct vty *vty)
508e53e2 1898{
d62a17ae 1899 if (IS_OSPF6_DEBUG_ASBR)
1900 vty_out(vty, "debug ospf6 asbr\n");
1901 return 0;
508e53e2 1902}
1903
d62a17ae 1904void install_element_ospf6_debug_asbr()
92300491 1905{
d62a17ae 1906 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
1907 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
1908 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
1909 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
92300491 1910}