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