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