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