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