]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_asbr.c
Merge pull request #8814 from kuldeepkash/topojson_framework
[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 #include "lib/northbound_cli.h"
34
35 #include "ospf6_proto.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_lsdb.h"
38 #include "ospf6_route.h"
39 #include "ospf6_zebra.h"
40 #include "ospf6_message.h"
41 #include "ospf6_spf.h"
42
43 #include "ospf6_top.h"
44 #include "ospf6d.h"
45 #include "ospf6_area.h"
46 #include "ospf6_interface.h"
47 #include "ospf6_neighbor.h"
48 #include "ospf6_asbr.h"
49 #include "ospf6_abr.h"
50 #include "ospf6_intra.h"
51 #include "ospf6_flood.h"
52 #include "ospf6d.h"
53 #include "ospf6_spf.h"
54 #include "ospf6_nssa.h"
55 #include "lib/json.h"
56
57 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
58 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments");
59 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
60
61 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
62 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
63 struct ospf6_redist *red, int type);
64
65 #ifndef VTYSH_EXTRACT_PL
66 #include "ospf6d/ospf6_asbr_clippy.c"
67 #endif
68
69 unsigned char conf_debug_ospf6_asbr = 0;
70
71 #define ZROUTE_NAME(x) zebra_route_string(x)
72
73 /* AS External LSA origination */
74 void ospf6_as_external_lsa_originate(struct ospf6_route *route,
75 struct ospf6 *ospf6)
76 {
77 char buffer[OSPF6_MAX_LSASIZE];
78 struct ospf6_lsa_header *lsa_header;
79 struct ospf6_lsa *lsa;
80 struct ospf6_external_info *info = route->route_option;
81
82 struct ospf6_as_external_lsa *as_external_lsa;
83 caddr_t p;
84
85 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
86 zlog_debug("Originate AS-External-LSA for %pFX",
87 &route->prefix);
88
89 /* prepare buffer */
90 memset(buffer, 0, sizeof(buffer));
91 lsa_header = (struct ospf6_lsa_header *)buffer;
92 as_external_lsa = (struct ospf6_as_external_lsa
93 *)((caddr_t)lsa_header
94 + sizeof(struct ospf6_lsa_header));
95 p = (caddr_t)((caddr_t)as_external_lsa
96 + sizeof(struct ospf6_as_external_lsa));
97
98 /* Fill AS-External-LSA */
99 /* Metric type */
100 if (route->path.metric_type == 2)
101 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
102 else
103 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
104
105 /* forwarding address */
106 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
107 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
108 else
109 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
110
111 /* external route tag */
112 if (info->tag)
113 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
114 else
115 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
116
117 /* Set metric */
118 OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
119
120 /* prefixlen */
121 as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
122
123 /* PrefixOptions */
124 as_external_lsa->prefix.prefix_options = route->path.prefix_options;
125
126 /* don't use refer LS-type */
127 as_external_lsa->prefix.prefix_refer_lstype = htons(0);
128
129 /* set Prefix */
130 memcpy(p, &route->prefix.u.prefix6,
131 OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
132 ospf6_prefix_apply_mask(&as_external_lsa->prefix);
133 p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
134
135 /* Forwarding address */
136 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
137 memcpy(p, &info->forwarding, sizeof(struct in6_addr));
138 p += sizeof(struct in6_addr);
139 }
140
141 /* External Route Tag */
142 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
143 route_tag_t network_order = htonl(info->tag);
144
145 memcpy(p, &network_order, sizeof(network_order));
146 p += sizeof(network_order);
147 }
148
149 /* Fill LSA Header */
150 lsa_header->age = 0;
151 lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
152 lsa_header->id = route->path.origin.id;
153 lsa_header->adv_router = ospf6->router_id;
154 lsa_header->seqnum =
155 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
156 lsa_header->adv_router, ospf6->lsdb);
157 lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
158
159 /* LSA checksum */
160 ospf6_lsa_checksum(lsa_header);
161
162 /* create LSA */
163 lsa = ospf6_lsa_create(lsa_header);
164
165 /* Originate */
166 ospf6_lsa_originate_process(lsa, ospf6);
167 }
168
169 int ospf6_orig_as_external_lsa(struct thread *thread)
170 {
171 struct ospf6_interface *oi;
172 struct ospf6_lsa *lsa;
173 uint32_t type, adv_router;
174
175 oi = (struct ospf6_interface *)THREAD_ARG(thread);
176 oi->thread_as_extern_lsa = NULL;
177
178 if (oi->state == OSPF6_INTERFACE_DOWN)
179 return 0;
180 if (IS_AREA_NSSA(oi->area))
181 return 0;
182
183 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
184 adv_router = oi->area->ospf6->router_id;
185 for (ALL_LSDB_TYPED_ADVRTR(oi->area->ospf6->lsdb, type, adv_router,
186 lsa)) {
187 if (IS_OSPF6_DEBUG_ASBR)
188 zlog_debug(
189 "%s: Send update of AS-External LSA %s seq 0x%x",
190 __func__, lsa->name,
191 ntohl(lsa->header->seqnum));
192
193 ospf6_flood_interface(NULL, lsa, oi);
194 }
195
196 return 0;
197 }
198
199 static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
200 {
201 struct ospf6_as_external_lsa *external;
202 ptrdiff_t tag_offset;
203 route_tag_t network_order;
204
205 if (!lsa)
206 return 0;
207
208 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
209 lsa->header);
210
211 if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
212 return 0;
213
214 tag_offset = sizeof(*external)
215 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
216 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
217 tag_offset += sizeof(struct in6_addr);
218
219 memcpy(&network_order, (caddr_t)external + tag_offset,
220 sizeof(network_order));
221 return ntohl(network_order);
222 }
223
224 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
225 struct ospf6_route *route,
226 struct ospf6 *ospf6)
227 {
228 struct ospf6_route *old_route, *next_route;
229 struct ospf6_path *ecmp_path, *o_path = NULL;
230 struct listnode *anode, *anext;
231 struct listnode *nnode, *rnode, *rnext;
232 struct ospf6_nexthop *nh, *rnh;
233 bool route_found = false;
234
235 /* check for old entry match with new route origin,
236 * delete old entry.
237 */
238 for (old_route = old; old_route; old_route = next_route) {
239 bool route_updated = false;
240
241 next_route = old_route->next;
242
243 if (!ospf6_route_is_same(old_route, route)
244 || (old_route->path.type != route->path.type))
245 continue;
246
247 /* Current and New route has same origin,
248 * delete old entry.
249 */
250 for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
251 o_path)) {
252 /* Check old route path and route has same
253 * origin.
254 */
255 if (o_path->area_id != route->path.area_id
256 || (memcmp(&(o_path)->origin, &(route)->path.origin,
257 sizeof(struct ospf6_ls_origin))
258 != 0))
259 continue;
260
261 /* Cost is not same then delete current path */
262 if ((o_path->cost == route->path.cost)
263 && (o_path->u.cost_e2 == route->path.u.cost_e2))
264 continue;
265
266 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
267 zlog_debug(
268 "%s: route %pFX cost old %u new %u is not same, replace route",
269 __func__, &old_route->prefix, o_path->cost,
270 route->path.cost);
271 }
272
273 /* Remove selected current rout path's nh from
274 * effective nh list.
275 */
276 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
277 for (ALL_LIST_ELEMENTS(old_route->nh_list,
278 rnode, rnext, rnh)) {
279 if (!ospf6_nexthop_is_same(rnh, nh))
280 continue;
281 listnode_delete(old_route->nh_list,
282 rnh);
283 ospf6_nexthop_delete(rnh);
284 }
285 }
286
287 listnode_delete(old_route->paths, o_path);
288 ospf6_path_free(o_path);
289 route_updated = true;
290
291 /* Current route's path (adv_router info) is similar
292 * to route being added.
293 * Replace current route's path with paths list head.
294 * Update FIB with effective NHs.
295 */
296 if (listcount(old_route->paths)) {
297 for (ALL_LIST_ELEMENTS(old_route->paths,
298 anode, anext, o_path)) {
299 ospf6_merge_nexthops(
300 old_route->nh_list,
301 o_path->nh_list);
302 }
303 /* Update RIB/FIB with effective
304 * nh_list
305 */
306 if (ospf6->route_table->hook_add)
307 (*ospf6->route_table->hook_add)(
308 old_route);
309
310 if (old_route->path.origin.id
311 == route->path.origin.id
312 && old_route->path.origin.adv_router
313 == route->path.origin
314 .adv_router) {
315 struct ospf6_path *h_path;
316
317 h_path = (struct ospf6_path *)
318 listgetdata(listhead(
319 old_route->paths));
320 old_route->path.origin.type =
321 h_path->origin.type;
322 old_route->path.origin.id =
323 h_path->origin.id;
324 old_route->path.origin.adv_router =
325 h_path->origin.adv_router;
326 }
327 } else {
328 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
329 zlog_debug(
330 "%s: route %pFX old cost %u new cost %u, delete old entry.",
331 __func__, &old_route->prefix,
332 old_route->path.cost,
333 route->path.cost);
334 }
335 if (old == old_route)
336 old = next_route;
337 ospf6_route_remove(old_route,
338 ospf6->route_table);
339 }
340 }
341 if (route_updated)
342 break;
343 }
344
345 /* Add new route */
346 for (old_route = old; old_route; old_route = old_route->next) {
347
348 /* Current and New Route prefix or route type
349 * is not same skip this current node.
350 */
351 if (!ospf6_route_is_same(old_route, route)
352 || (old_route->path.type != route->path.type))
353 continue;
354
355 /* Old Route and New Route have Equal Cost, Merge NHs */
356 if ((old_route->path.cost == route->path.cost)
357 && (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
358
359 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
360 zlog_debug(
361 "%s: old route %pFX path cost %u e2 %u",
362 __func__, &old_route->prefix,
363 old_route->path.cost,
364 old_route->path.u.cost_e2);
365 }
366 route_found = true;
367 /* check if this path exists already in
368 * route->paths list, if so, replace nh_list
369 * from asbr_entry.
370 */
371 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
372 o_path)) {
373 if (o_path->area_id == route->path.area_id
374 && (memcmp(&(o_path)->origin,
375 &(route)->path.origin,
376 sizeof(struct ospf6_ls_origin))
377 == 0))
378 break;
379 }
380 /* If path is not found in old_route paths's list,
381 * add a new path to route paths list and merge
382 * nexthops in route->path->nh_list.
383 * Otherwise replace existing path's nh_list.
384 */
385 if (o_path == NULL) {
386 ecmp_path = ospf6_path_dup(&route->path);
387
388 /* Add a nh_list to new ecmp path */
389 ospf6_copy_nexthops(ecmp_path->nh_list,
390 route->nh_list);
391
392 /* Add the new path to route's path list */
393 listnode_add_sort(old_route->paths, ecmp_path);
394
395 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
396 zlog_debug(
397 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
398 __func__, &route->prefix,
399 listcount(ecmp_path->nh_list),
400 old_route->paths ? listcount(
401 old_route->paths)
402 : 0,
403 listcount(old_route->nh_list));
404 }
405 } else {
406 list_delete_all_node(o_path->nh_list);
407 ospf6_copy_nexthops(o_path->nh_list,
408 route->nh_list);
409 }
410
411 /* Reset nexthop lists, rebuild from brouter table
412 * for each adv. router.
413 */
414 list_delete_all_node(old_route->nh_list);
415
416 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
417 o_path)) {
418 struct ospf6_route *asbr_entry;
419
420 asbr_entry = ospf6_route_lookup(
421 &o_path->ls_prefix,
422 ospf6->brouter_table);
423 if (asbr_entry == NULL) {
424 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
425 zlog_debug(
426 "%s: ls_prfix %pFX asbr_entry not found.",
427 __func__,
428 &old_route->prefix);
429 continue;
430 }
431 ospf6_route_merge_nexthops(old_route,
432 asbr_entry);
433 }
434
435 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
436 zlog_debug(
437 "%s: route %pFX with effective paths %u nh %u",
438 __func__, &route->prefix,
439 old_route->paths
440 ? listcount(old_route->paths)
441 : 0,
442 old_route->nh_list
443 ? listcount(old_route->nh_list)
444 : 0);
445
446 /* Update RIB/FIB */
447 if (ospf6->route_table->hook_add)
448 (*ospf6->route_table->hook_add)(old_route);
449
450 /* Delete the new route its info added to existing
451 * route.
452 */
453 ospf6_route_delete(route);
454
455 break;
456 }
457 }
458
459 if (!route_found) {
460 /* Add new route to existing node in ospf6 route table. */
461 ospf6_route_add(route, ospf6->route_table);
462 }
463 }
464
465 /* Check if the forwarding address is local address */
466 static int ospf6_ase_forward_address_check(struct ospf6 *ospf6,
467 struct in6_addr *fwd_addr)
468 {
469 struct listnode *anode, *node, *cnode;
470 struct ospf6_interface *oi;
471 struct ospf6_area *oa;
472 struct interface *ifp;
473 struct connected *c;
474
475 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, oa)) {
476 for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
477 if (!if_is_operative(oi->interface)
478 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
479 continue;
480
481 ifp = oi->interface;
482 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
483 if (IPV6_ADDR_SAME(&c->address->u.prefix6,
484 fwd_addr))
485 return 0;
486 }
487 }
488 }
489
490 return 1;
491 }
492
493 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
494 {
495 struct ospf6_as_external_lsa *external;
496 struct prefix asbr_id;
497 struct ospf6_route *asbr_entry, *route, *old = NULL;
498 struct ospf6_path *path;
499 struct ospf6 *ospf6;
500 int type;
501 struct ospf6_area *oa = NULL;
502 struct prefix fwd_addr;
503 ptrdiff_t offset;
504
505 type = ntohs(lsa->header->type);
506 oa = lsa->lsdb->data;
507
508 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
509 lsa->header);
510
511 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
512 zlog_debug("Calculate AS-External route for %s", lsa->name);
513
514 ospf6 = ospf6_get_by_lsdb(lsa);
515
516 if (lsa->header->adv_router == ospf6->router_id) {
517 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
518 zlog_debug("Ignore self-originated AS-External-LSA");
519 return;
520 }
521
522 if (OSPF6_ASBR_METRIC(external) == OSPF_LS_INFINITY) {
523 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
524 zlog_debug("Ignore LSA with LSInfinity Metric");
525 return;
526 }
527
528 if (CHECK_FLAG(external->prefix.prefix_options,
529 OSPF6_PREFIX_OPTION_NU)) {
530 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
531 zlog_debug("Ignore LSA with NU bit set Metric");
532 return;
533 }
534
535 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
536 asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
537 if (asbr_entry == NULL) {
538 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
539 zlog_debug("ASBR entry not found: %pFX", &asbr_id);
540 return;
541 } else {
542 /* The router advertising external LSA can be ASBR or ABR */
543 if (!CHECK_FLAG(asbr_entry->path.router_bits,
544 OSPF6_ROUTER_BIT_E)) {
545 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
546 zlog_debug(
547 "External bit reset ASBR route entry : %pFX",
548 &asbr_id);
549 return;
550 }
551 }
552
553 /* Check the forwarding address */
554 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
555 offset = sizeof(*external)
556 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
557 memset(&fwd_addr, 0, sizeof(struct prefix));
558 fwd_addr.family = AF_INET6;
559 fwd_addr.prefixlen = IPV6_MAX_PREFIXLEN;
560 memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
561 sizeof(struct in6_addr));
562
563 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr.u.prefix6)) {
564 if (!ospf6_ase_forward_address_check(
565 ospf6, &fwd_addr.u.prefix6)) {
566 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
567 zlog_debug(
568 "Fwd address %pFX is local address",
569 &fwd_addr);
570 return;
571 }
572
573 /* Find the forwarding entry */
574 asbr_entry = ospf6_route_lookup_bestmatch(
575 &fwd_addr, ospf6->route_table);
576 if (asbr_entry == NULL) {
577 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
578 zlog_debug(
579 "Fwd address not found: %pFX",
580 &fwd_addr);
581 return;
582 }
583 }
584 }
585
586 route = ospf6_route_create();
587 route->type = OSPF6_DEST_TYPE_NETWORK;
588 route->prefix.family = AF_INET6;
589 route->prefix.prefixlen = external->prefix.prefix_length;
590 ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
591 &external->prefix);
592
593 route->path.area_id = asbr_entry->path.area_id;
594 route->path.origin.type = lsa->header->type;
595 route->path.origin.id = lsa->header->id;
596 route->path.origin.adv_router = lsa->header->adv_router;
597 route->path.prefix_options = external->prefix.prefix_options;
598 memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix));
599
600 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
601 route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
602 route->path.metric_type = 2;
603 route->path.cost = asbr_entry->path.cost;
604 route->path.u.cost_e2 = OSPF6_ASBR_METRIC(external);
605 } else {
606 route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
607 route->path.metric_type = 1;
608 route->path.cost =
609 asbr_entry->path.cost + OSPF6_ASBR_METRIC(external);
610 route->path.u.cost_e2 = 0;
611 }
612
613 route->path.tag = ospf6_as_external_lsa_get_tag(lsa);
614
615 ospf6_route_copy_nexthops(route, asbr_entry);
616
617 path = ospf6_path_dup(&route->path);
618 ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
619 listnode_add_sort(route->paths, path);
620
621
622 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
623 zlog_debug(
624 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__,
625 (type == OSPF6_LSTYPE_AS_EXTERNAL) ? "AS-External"
626 : "NSSA",
627 (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1 : 2,
628 &route->prefix, route->path.cost, route->path.u.cost_e2,
629 listcount(route->nh_list));
630
631 if (type == OSPF6_LSTYPE_AS_EXTERNAL)
632 old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
633 else if (type == OSPF6_LSTYPE_TYPE_7)
634 old = ospf6_route_lookup(&route->prefix, oa->route_table);
635 if (!old) {
636 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
637 zlog_debug("%s: Adding new route", __func__);
638 /* Add the new route to ospf6 instance route table. */
639 if (type == OSPF6_LSTYPE_AS_EXTERNAL)
640 ospf6_route_add(route, ospf6->route_table);
641 /* Add the route to the area route table */
642 else if (type == OSPF6_LSTYPE_TYPE_7) {
643 ospf6_route_add(route, oa->route_table);
644 }
645 } else {
646 /* RFC 2328 16.4 (6)
647 * ECMP: Keep new equal preference path in current
648 * route's path list, update zebra with new effective
649 * list along with addition of ECMP path.
650 */
651 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
652 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
653 __func__, &route->prefix, route->path.cost,
654 route->path.u.cost_e2,
655 listcount(route->nh_list));
656 ospf6_asbr_update_route_ecmp_path(old, route, ospf6);
657 }
658 }
659
660 void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
661 struct ospf6_route *asbr_entry)
662 {
663 struct ospf6_as_external_lsa *external;
664 struct prefix prefix;
665 struct ospf6_route *route, *nroute, *route_to_del;
666 struct ospf6_area *oa = NULL;
667 struct ospf6 *ospf6;
668 int type;
669 bool debug = false;
670
671 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
672 lsa->header);
673
674 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA))
675 debug = true;
676
677 ospf6 = ospf6_get_by_lsdb(lsa);
678 type = ntohs(lsa->header->type);
679
680 if (type == OSPF6_LSTYPE_TYPE_7) {
681 if (debug)
682 zlog_debug("%s: Withdraw Type 7 route for %s",
683 __func__, lsa->name);
684 oa = lsa->lsdb->data;
685 } else {
686 if (debug)
687 zlog_debug("%s: Withdraw AS-External route for %s",
688 __func__, lsa->name);
689
690 if (ospf6_check_and_set_router_abr(ospf6))
691 oa = ospf6->backbone;
692 else
693 oa = listgetdata(listhead(ospf6->area_list));
694 }
695
696 if (oa == NULL) {
697 if (debug)
698 zlog_debug("%s: Invalid area", __func__);
699 return;
700 }
701
702 if (lsa->header->adv_router == oa->ospf6->router_id) {
703 if (debug)
704 zlog_debug("Ignore self-originated AS-External-LSA");
705 return;
706 }
707
708 route_to_del = ospf6_route_create();
709 route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
710 route_to_del->prefix.family = AF_INET6;
711 route_to_del->prefix.prefixlen = external->prefix.prefix_length;
712 ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external,
713 &external->prefix);
714
715 route_to_del->path.origin.type = lsa->header->type;
716 route_to_del->path.origin.id = lsa->header->id;
717 route_to_del->path.origin.adv_router = lsa->header->adv_router;
718
719 if (asbr_entry) {
720 route_to_del->path.area_id = asbr_entry->path.area_id;
721 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
722 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
723 route_to_del->path.metric_type = 2;
724 route_to_del->path.cost = asbr_entry->path.cost;
725 route_to_del->path.u.cost_e2 =
726 OSPF6_ASBR_METRIC(external);
727 } else {
728 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
729 route_to_del->path.metric_type = 1;
730 route_to_del->path.cost = asbr_entry->path.cost
731 + OSPF6_ASBR_METRIC(external);
732 route_to_del->path.u.cost_e2 = 0;
733 }
734 }
735
736 memset(&prefix, 0, sizeof(struct prefix));
737 prefix.family = AF_INET6;
738 prefix.prefixlen = external->prefix.prefix_length;
739 ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
740
741 if (type == OSPF6_LSTYPE_TYPE_7)
742 route = ospf6_route_lookup(&prefix, oa->route_table);
743 else
744 route = ospf6_route_lookup(&prefix, oa->ospf6->route_table);
745
746 if (route == NULL) {
747 if (debug)
748 zlog_debug("AS-External route %pFX not found", &prefix);
749 ospf6_route_delete(route_to_del);
750 return;
751 }
752
753 if (debug)
754 zlog_debug(
755 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
756 __func__, &prefix, route->path.cost, route->path.u.cost_e2,
757 route_to_del->path.cost, route_to_del->path.u.cost_e2);
758
759 for (ospf6_route_lock(route);
760 route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
761 nroute = ospf6_route_next(route);
762
763 if (route->type != OSPF6_DEST_TYPE_NETWORK)
764 continue;
765
766 /* Route has multiple ECMP paths, remove matching
767 * path. Update current route's effective nh list
768 * after removal of one of the path.
769 */
770 if (listcount(route->paths) > 1) {
771 struct listnode *anode, *anext;
772 struct listnode *nnode, *rnode, *rnext;
773 struct ospf6_nexthop *nh, *rnh;
774 struct ospf6_path *o_path;
775 bool nh_updated = false;
776
777 /* Iterate all paths of route to find maching with LSA
778 * remove from route path list. If route->path is same,
779 * replace from paths list.
780 */
781 for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
782 o_path)) {
783 if ((o_path->origin.type != lsa->header->type)
784 || (o_path->origin.adv_router
785 != lsa->header->adv_router)
786 || (o_path->origin.id != lsa->header->id))
787 continue;
788
789 /* Compare LSA cost with current
790 * route info.
791 */
792 if (!asbr_entry
793 && (o_path->cost != route_to_del->path.cost
794 || o_path->u.cost_e2
795 != route_to_del->path.u
796 .cost_e2)) {
797 if (IS_OSPF6_DEBUG_EXAMIN(
798 AS_EXTERNAL)) {
799 zlog_debug(
800 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
801 __func__, &prefix,
802 route->path.cost,
803 route_to_del->path
804 .cost);
805 }
806 continue;
807 }
808
809 if (debug) {
810 zlog_debug(
811 "%s: route %pFX path found with cost %u nh %u to remove.",
812 __func__, &prefix, route->path.cost,
813 listcount(o_path->nh_list));
814 }
815
816 /* Remove found path's nh_list from
817 * the route's nh_list.
818 */
819 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
820 nnode, nh)) {
821 for (ALL_LIST_ELEMENTS(route->nh_list,
822 rnode, rnext,
823 rnh)) {
824 if (!ospf6_nexthop_is_same(rnh,
825 nh))
826 continue;
827 listnode_delete(route->nh_list,
828 rnh);
829 ospf6_nexthop_delete(rnh);
830 }
831 }
832 /* Delete the path from route's path list */
833 listnode_delete(route->paths, o_path);
834 ospf6_path_free(o_path);
835 nh_updated = true;
836 }
837
838 if (nh_updated) {
839 /* Iterate all paths and merge nexthop,
840 * unlesss any of the nexthop similar to
841 * ones deleted as part of path deletion.
842 */
843
844 for (ALL_LIST_ELEMENTS(route->paths, anode,
845 anext, o_path)) {
846 ospf6_merge_nexthops(route->nh_list,
847 o_path->nh_list);
848 }
849
850 if (debug) {
851 zlog_debug(
852 "%s: AS-External %u route %pFX update paths %u nh %u",
853 __func__,
854 (route->path.type
855 == OSPF6_PATH_TYPE_EXTERNAL1)
856 ? 1
857 : 2,
858 &route->prefix, listcount(route->paths),
859 route->nh_list ? listcount(
860 route->nh_list)
861 : 0);
862 }
863
864 if (listcount(route->paths)) {
865 /* Update RIB/FIB with effective
866 * nh_list
867 */
868 if (oa->ospf6->route_table->hook_add)
869 (*oa->ospf6->route_table
870 ->hook_add)(route);
871
872 /* route's primary path is similar
873 * to LSA, replace route's primary
874 * path with route's paths list head.
875 */
876 if ((route->path.origin.id ==
877 lsa->header->id) &&
878 (route->path.origin.adv_router
879 == lsa->header->adv_router)) {
880 struct ospf6_path *h_path;
881
882 h_path = (struct ospf6_path *)
883 listgetdata(
884 listhead(route->paths));
885 route->path.origin.type =
886 h_path->origin.type;
887 route->path.origin.id =
888 h_path->origin.id;
889 route->path.origin.adv_router =
890 h_path->origin.adv_router;
891 }
892 } else {
893 if (type == OSPF6_LSTYPE_TYPE_7)
894 ospf6_route_remove(
895 route, oa->route_table);
896 else
897 ospf6_route_remove(
898 route,
899 oa->ospf6->route_table);
900 }
901 }
902 continue;
903
904 } else {
905 /* Compare LSA origin and cost with current route info.
906 * if any check fails skip del this route node.
907 */
908 if (asbr_entry
909 && (!ospf6_route_is_same_origin(route, route_to_del)
910 || (route->path.type != route_to_del->path.type)
911 || (route->path.cost != route_to_del->path.cost)
912 || (route->path.u.cost_e2
913 != route_to_del->path.u.cost_e2))) {
914 if (debug) {
915 zlog_debug(
916 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
917 __func__, &prefix, route->path.cost,
918 route_to_del->path.cost);
919 }
920 continue;
921 }
922
923 if ((route->path.origin.type != lsa->header->type)
924 || (route->path.origin.adv_router
925 != lsa->header->adv_router)
926 || (route->path.origin.id != lsa->header->id))
927 continue;
928 }
929 if (debug) {
930 zlog_debug(
931 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
932 __func__,
933 route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
934 ? 1
935 : 2,
936 &route->prefix, route->path.cost, route->path.u.cost_e2,
937 listcount(route->nh_list));
938 }
939 if (type == OSPF6_LSTYPE_TYPE_7)
940 ospf6_route_remove(route, oa->route_table);
941 else
942 ospf6_route_remove(route, oa->ospf6->route_table);
943 }
944 if (route != NULL)
945 ospf6_route_unlock(route);
946
947 ospf6_route_delete(route_to_del);
948 }
949
950 void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry, struct ospf6 *ospf6)
951 {
952 struct ospf6_lsa *lsa;
953 uint16_t type;
954 uint32_t router;
955
956 if (!CHECK_FLAG(asbr_entry->flag, OSPF6_ROUTE_BEST)) {
957 char buf[16];
958 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&asbr_entry->prefix),
959 buf, sizeof(buf));
960 zlog_info("ignore non-best path: lsentry %s add", buf);
961 return;
962 }
963
964 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
965 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
966 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
967 if (!OSPF6_LSA_IS_MAXAGE(lsa))
968 ospf6_asbr_lsa_add(lsa);
969 }
970 }
971
972 void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry,
973 struct ospf6 *ospf6)
974 {
975 struct ospf6_lsa *lsa;
976 uint16_t type;
977 uint32_t router;
978
979 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
980 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
981 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
982 ospf6_asbr_lsa_remove(lsa, asbr_entry);
983 }
984
985
986 /* redistribute function */
987 static void ospf6_asbr_routemap_set(struct ospf6_redist *red,
988 const char *mapname)
989 {
990 if (ROUTEMAP_NAME(red)) {
991 route_map_counter_decrement(ROUTEMAP(red));
992 free(ROUTEMAP_NAME(red));
993 }
994
995 ROUTEMAP_NAME(red) = strdup(mapname);
996 ROUTEMAP(red) = route_map_lookup_by_name(mapname);
997 route_map_counter_increment(ROUTEMAP(red));
998 }
999
1000 static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
1001 {
1002 if (ROUTEMAP_NAME(red))
1003 free(ROUTEMAP_NAME(red));
1004
1005 route_map_counter_decrement(ROUTEMAP(red));
1006
1007 ROUTEMAP_NAME(red) = NULL;
1008 ROUTEMAP(red) = NULL;
1009 }
1010
1011 static int ospf6_asbr_routemap_update_timer(struct thread *thread)
1012 {
1013 void **arg;
1014 int arg_type;
1015 struct ospf6 *ospf6;
1016 struct ospf6_redist *red;
1017
1018 arg = THREAD_ARG(thread);
1019 ospf6 = (struct ospf6 *)arg[0];
1020 arg_type = (int)(intptr_t)arg[1];
1021
1022 ospf6->t_distribute_update = NULL;
1023
1024 red = ospf6_redist_lookup(ospf6, arg_type, 0);
1025
1026 if (red && ROUTEMAP_NAME(red))
1027 ROUTEMAP(red) = route_map_lookup_by_name(ROUTEMAP_NAME(red));
1028 if (red && ROUTEMAP(red)) {
1029 if (IS_OSPF6_DEBUG_ASBR)
1030 zlog_debug("%s: route-map %s update, reset redist %s",
1031 __func__, ROUTEMAP_NAME(red),
1032 ZROUTE_NAME(arg_type));
1033
1034 ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id);
1035 ospf6_zebra_redistribute(arg_type, ospf6->vrf_id);
1036 }
1037
1038 XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
1039 return 0;
1040 }
1041
1042 void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6)
1043 {
1044 void **args = NULL;
1045
1046 if (ospf6->t_distribute_update)
1047 return;
1048
1049 args = XCALLOC(MTYPE_OSPF6_DIST_ARGS, sizeof(void *) * 2);
1050
1051 args[0] = ospf6;
1052 args[1] = (void *)((ptrdiff_t)type);
1053
1054 if (IS_OSPF6_DEBUG_ASBR)
1055 zlog_debug("%s: trigger redistribute %s reset thread", __func__,
1056 ZROUTE_NAME(type));
1057
1058 ospf6->t_distribute_update = NULL;
1059 thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, args,
1060 OSPF_MIN_LS_INTERVAL,
1061 &ospf6->t_distribute_update);
1062 }
1063
1064 void ospf6_asbr_routemap_update(const char *mapname)
1065 {
1066 int type;
1067 struct listnode *node, *nnode;
1068 struct ospf6 *ospf6 = NULL;
1069 struct ospf6_redist *red;
1070
1071 if (om6 == NULL)
1072 return;
1073
1074 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1075 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1076 red = ospf6_redist_lookup(ospf6, type, 0);
1077 if (!red || (ROUTEMAP_NAME(red) == NULL))
1078 continue;
1079 ROUTEMAP(red) =
1080 route_map_lookup_by_name(ROUTEMAP_NAME(red));
1081
1082 if (mapname == NULL
1083 || strcmp(ROUTEMAP_NAME(red), mapname))
1084 continue;
1085 if (ROUTEMAP(red)) {
1086 if (IS_OSPF6_DEBUG_ASBR)
1087 zlog_debug(
1088 "%s: route-map %s update, reset redist %s",
1089 __func__,
1090 mapname,
1091 ZROUTE_NAME(
1092 type));
1093
1094 route_map_counter_increment(ROUTEMAP(red));
1095
1096 ospf6_asbr_distribute_list_update(type, ospf6);
1097 } else {
1098 /*
1099 * if the mapname matches a
1100 * route-map on ospf6 but the
1101 * map doesn't exist, it is
1102 * being deleted. flush and then
1103 * readvertise
1104 */
1105 if (IS_OSPF6_DEBUG_ASBR)
1106 zlog_debug(
1107 "%s: route-map %s deleted, reset redist %s",
1108 __func__,
1109 mapname,
1110 ZROUTE_NAME(
1111 type));
1112 ospf6_asbr_redistribute_unset(ospf6, red, type);
1113 ospf6_asbr_routemap_set(red, mapname);
1114 ospf6_asbr_redistribute_set(
1115 type, ospf6->vrf_id);
1116 }
1117 }
1118 }
1119 }
1120
1121 static void ospf6_asbr_routemap_event(const char *name)
1122 {
1123 int type;
1124 struct listnode *node, *nnode;
1125 struct ospf6 *ospf6;
1126 struct ospf6_redist *red;
1127
1128 if (om6 == NULL)
1129 return;
1130 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1131 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1132 red = ospf6_redist_lookup(ospf6, type, 0);
1133 if (red && ROUTEMAP_NAME(red)
1134 && (strcmp(ROUTEMAP_NAME(red), name) == 0))
1135 ospf6_asbr_distribute_list_update(type, ospf6);
1136 }
1137 }
1138 }
1139
1140 int ospf6_asbr_is_asbr(struct ospf6 *o)
1141 {
1142 return (o->external_table->count || IS_OSPF6_ASBR(o));
1143 }
1144
1145 struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
1146 unsigned short instance)
1147 {
1148 struct list *red_list;
1149 struct listnode *node;
1150 struct ospf6_redist *red;
1151
1152 red_list = ospf6->redist[type];
1153 if (!red_list)
1154 return (NULL);
1155
1156 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
1157 if (red->instance == instance)
1158 return red;
1159
1160 return NULL;
1161 }
1162
1163 static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
1164 uint8_t instance)
1165 {
1166 struct ospf6_redist *red;
1167
1168 red = ospf6_redist_lookup(ospf6, type, instance);
1169 if (red)
1170 return red;
1171
1172 if (!ospf6->redist[type])
1173 ospf6->redist[type] = list_new();
1174
1175 red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
1176 red->instance = instance;
1177 ROUTEMAP_NAME(red) = NULL;
1178 ROUTEMAP(red) = NULL;
1179
1180 listnode_add(ospf6->redist[type], red);
1181 ospf6->redistribute++;
1182
1183 return red;
1184 }
1185
1186 static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
1187 int type)
1188 {
1189 if (red) {
1190 listnode_delete(ospf6->redist[type], red);
1191 if (!ospf6->redist[type]->count) {
1192 list_delete(&ospf6->redist[type]);
1193 }
1194 XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
1195 ospf6->redistribute--;
1196 }
1197 }
1198
1199 /*Set the status of the ospf instance to ASBR based on the status parameter,
1200 * rechedule SPF calculation, originate router LSA*/
1201 void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
1202 {
1203 struct listnode *lnode, *lnnode;
1204 struct ospf6_area *oa;
1205
1206 zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
1207
1208 if (status) {
1209 if (IS_OSPF6_ASBR(ospf6)) {
1210 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1211 ospf6->name, status);
1212 return;
1213 }
1214 SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1215 } else {
1216 if (!IS_OSPF6_ASBR(ospf6)) {
1217 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1218 ospf6->name, status);
1219 return;
1220 }
1221 UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1222 }
1223
1224 /* Transition from/to status ASBR, schedule timer. */
1225 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
1226
1227 /* Reoriginate router LSA for all areas */
1228 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1229 OSPF6_ROUTER_LSA_SCHEDULE(oa);
1230 }
1231
1232 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)
1233 {
1234 struct ospf6 *ospf6 = NULL;
1235 ospf6_zebra_redistribute(type, vrf_id);
1236
1237 ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
1238
1239 if (!ospf6)
1240 return;
1241
1242 ospf6_asbr_status_update(ospf6, ++ospf6->redist_count);
1243 }
1244
1245 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
1246 struct ospf6_redist *red, int type)
1247 {
1248 struct ospf6_route *route;
1249 struct ospf6_external_info *info;
1250
1251 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
1252
1253 for (route = ospf6_route_head(ospf6->external_table); route;
1254 route = ospf6_route_next(route)) {
1255 info = route->route_option;
1256 if (info->type != type)
1257 continue;
1258
1259 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix,
1260 ospf6);
1261 }
1262
1263 ospf6_asbr_routemap_unset(red);
1264 zlog_debug("%s: redist_count %d", __func__, ospf6->redist_count);
1265 ospf6_asbr_status_update(ospf6, --ospf6->redist_count);
1266 }
1267
1268 /* When an area is unstubified, flood all the external LSAs in the area */
1269 void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
1270 {
1271 struct ospf6_lsa *lsa, *lsanext;
1272
1273 for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
1274 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
1275 if (IS_OSPF6_DEBUG_ASBR)
1276 zlog_debug("%s: Flooding AS-External LSA %s",
1277 __func__, lsa->name);
1278
1279 ospf6_flood_area(NULL, lsa, oa);
1280 }
1281 }
1282 }
1283
1284 /* When an area is stubified, remove all the external LSAs in the area */
1285 void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
1286 {
1287 struct ospf6_lsa *lsa, *lsanext;
1288 struct listnode *node, *nnode;
1289 struct ospf6_area *area;
1290 struct ospf6 *ospf6 = oa->ospf6;
1291 const struct route_node *iterend;
1292
1293 /* skip if router is in other non-stub areas */
1294 for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
1295 if (!IS_AREA_STUB(area))
1296 return;
1297
1298 /* if router is only in a stub area then purge AS-External LSAs */
1299 iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
1300 while (lsa != NULL) {
1301 assert(lsa->lock > 1);
1302 lsanext = ospf6_lsdb_next(iterend, lsa);
1303 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
1304 ospf6_lsdb_remove(lsa, ospf6->lsdb);
1305 lsa = lsanext;
1306 }
1307 }
1308
1309 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
1310 struct prefix *prefix,
1311 unsigned int nexthop_num,
1312 struct in6_addr *nexthop, route_tag_t tag,
1313 struct ospf6 *ospf6)
1314 {
1315 route_map_result_t ret;
1316 struct listnode *lnode;
1317 struct ospf6_area *oa;
1318 struct ospf6_route troute;
1319 struct ospf6_external_info tinfo;
1320 struct ospf6_route *route, *match;
1321 struct ospf6_external_info *info;
1322 struct prefix prefix_id;
1323 struct route_node *node;
1324 char ibuf[16];
1325 struct ospf6_redist *red;
1326
1327 red = ospf6_redist_lookup(ospf6, type, 0);
1328
1329 if (!red)
1330 return;
1331
1332 if ((type != DEFAULT_ROUTE)
1333 && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
1334 return;
1335
1336 memset(&troute, 0, sizeof(troute));
1337 memset(&tinfo, 0, sizeof(tinfo));
1338
1339 if (IS_OSPF6_DEBUG_ASBR)
1340 zlog_debug("Redistribute %pFX (%s)", prefix, ZROUTE_NAME(type));
1341
1342 /* if route-map was specified but not found, do not advertise */
1343 if (ROUTEMAP_NAME(red)) {
1344 if (ROUTEMAP(red) == NULL)
1345 ospf6_asbr_routemap_update(NULL);
1346 if (ROUTEMAP(red) == NULL) {
1347 zlog_warn(
1348 "route-map \"%s\" not found, suppress redistributing",
1349 ROUTEMAP_NAME(red));
1350 return;
1351 }
1352 }
1353
1354 /* apply route-map */
1355 if (ROUTEMAP(red)) {
1356 troute.route_option = &tinfo;
1357 tinfo.ifindex = ifindex;
1358 tinfo.tag = tag;
1359
1360 ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
1361 if (ret == RMAP_DENYMATCH) {
1362 if (IS_OSPF6_DEBUG_ASBR)
1363 zlog_debug("Denied by route-map \"%s\"",
1364 ROUTEMAP_NAME(red));
1365 ospf6_asbr_redistribute_remove(type, ifindex, prefix,
1366 ospf6);
1367 return;
1368 }
1369 }
1370
1371 match = ospf6_route_lookup(prefix, ospf6->external_table);
1372 if (match) {
1373 info = match->route_option;
1374 /* copy result of route-map */
1375 if (ROUTEMAP(red)) {
1376 if (troute.path.metric_type)
1377 match->path.metric_type =
1378 troute.path.metric_type;
1379 if (troute.path.cost)
1380 match->path.cost = troute.path.cost;
1381 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1382 memcpy(&info->forwarding, &tinfo.forwarding,
1383 sizeof(struct in6_addr));
1384 info->tag = tinfo.tag;
1385 } else {
1386 /* If there is no route-map, simply update the tag and
1387 * metric fields
1388 */
1389 match->path.metric_type = metric_type(ospf6, type, 0);
1390 match->path.cost = metric_value(ospf6, type, 0);
1391 info->tag = tag;
1392 }
1393
1394 info->type = type;
1395
1396 if (nexthop_num && nexthop)
1397 ospf6_route_add_nexthop(match, ifindex, nexthop);
1398 else
1399 ospf6_route_add_nexthop(match, ifindex, NULL);
1400
1401 /* create/update binding in external_id_table */
1402 prefix_id.family = AF_INET;
1403 prefix_id.prefixlen = 32;
1404 prefix_id.u.prefix4.s_addr = htonl(info->id);
1405 node = route_node_get(ospf6->external_id_table, &prefix_id);
1406 node->info = match;
1407
1408 if (IS_OSPF6_DEBUG_ASBR) {
1409 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf,
1410 sizeof(ibuf));
1411 zlog_debug(
1412 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1413 ibuf, prefix, match->path.metric_type);
1414 }
1415
1416 match->path.origin.id = htonl(info->id);
1417 ospf6_as_external_lsa_originate(match, ospf6);
1418 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1419 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
1420 if (IS_AREA_NSSA(oa))
1421 ospf6_nssa_lsa_originate(match, oa);
1422 }
1423
1424 return;
1425 }
1426
1427 /* create new entry */
1428 route = ospf6_route_create();
1429 route->type = OSPF6_DEST_TYPE_NETWORK;
1430 prefix_copy(&route->prefix, prefix);
1431
1432 info = (struct ospf6_external_info *)XCALLOC(
1433 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
1434 route->route_option = info;
1435 info->id = ospf6->external_id++;
1436
1437 /* copy result of route-map */
1438 if (ROUTEMAP(red)) {
1439 if (troute.path.metric_type)
1440 route->path.metric_type = troute.path.metric_type;
1441 if (troute.path.cost)
1442 route->path.cost = troute.path.cost;
1443 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1444 memcpy(&info->forwarding, &tinfo.forwarding,
1445 sizeof(struct in6_addr));
1446 info->tag = tinfo.tag;
1447 } else {
1448 /* If there is no route-map, simply update the tag and metric
1449 * fields
1450 */
1451 route->path.metric_type = metric_type(ospf6, type, 0);
1452 route->path.cost = metric_value(ospf6, type, 0);
1453 info->tag = tag;
1454 }
1455
1456 info->type = type;
1457 if (nexthop_num && nexthop)
1458 ospf6_route_add_nexthop(route, ifindex, nexthop);
1459 else
1460 ospf6_route_add_nexthop(route, ifindex, NULL);
1461
1462 /* create/update binding in external_id_table */
1463 prefix_id.family = AF_INET;
1464 prefix_id.prefixlen = 32;
1465 prefix_id.u.prefix4.s_addr = htonl(info->id);
1466 node = route_node_get(ospf6->external_id_table, &prefix_id);
1467 node->info = route;
1468
1469 route = ospf6_route_add(route, ospf6->external_table);
1470 route->route_option = info;
1471
1472 if (IS_OSPF6_DEBUG_ASBR) {
1473 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
1474 zlog_debug(
1475 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1476 ibuf, prefix, route->path.metric_type);
1477 }
1478
1479 route->path.origin.id = htonl(info->id);
1480 ospf6_as_external_lsa_originate(route, ospf6);
1481 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1482 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
1483 if (IS_AREA_NSSA(oa))
1484 ospf6_nssa_lsa_originate(route, oa);
1485 }
1486 }
1487
1488 void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
1489 struct prefix *prefix, struct ospf6 *ospf6)
1490 {
1491 struct ospf6_area *oa;
1492 struct ospf6_route *match;
1493 struct ospf6_external_info *info = NULL;
1494 struct listnode *lnode;
1495 struct route_node *node;
1496 struct ospf6_lsa *lsa;
1497 struct prefix prefix_id;
1498 char ibuf[16];
1499
1500 match = ospf6_route_lookup(prefix, ospf6->external_table);
1501 if (match == NULL) {
1502 if (IS_OSPF6_DEBUG_ASBR)
1503 zlog_debug("No such route %pFX to withdraw", prefix);
1504 return;
1505 }
1506
1507 info = match->route_option;
1508 assert(info);
1509
1510 if (info->type != type) {
1511 if (IS_OSPF6_DEBUG_ASBR)
1512 zlog_debug("Original protocol mismatch: %pFX", prefix);
1513 return;
1514 }
1515
1516 if (IS_OSPF6_DEBUG_ASBR) {
1517 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
1518 zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix, ibuf);
1519 }
1520
1521 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
1522 htonl(info->id), ospf6->router_id, ospf6->lsdb);
1523 if (lsa) {
1524 if (IS_OSPF6_DEBUG_ASBR) {
1525 zlog_debug("withdraw type 5 LSA for route %pFX",
1526 prefix);
1527 }
1528 ospf6_lsa_purge(lsa);
1529 }
1530
1531 /* Delete the NSSA LSA */
1532 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
1533 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7),
1534 htonl(info->id), ospf6->router_id,
1535 oa->lsdb);
1536 if (lsa) {
1537 if (IS_OSPF6_DEBUG_ASBR) {
1538 zlog_debug("withdraw type 7 LSA for route %pFX",
1539 prefix);
1540 }
1541 ospf6_lsa_purge(lsa);
1542 }
1543 }
1544
1545 /* remove binding in external_id_table */
1546 prefix_id.family = AF_INET;
1547 prefix_id.prefixlen = 32;
1548 prefix_id.u.prefix4.s_addr = htonl(info->id);
1549 node = route_node_lookup(ospf6->external_id_table, &prefix_id);
1550 assert(node);
1551 node->info = NULL;
1552 route_unlock_node(node); /* to free the lookup lock */
1553 route_unlock_node(node); /* to free the original lock */
1554
1555 ospf6_route_remove(match, ospf6->external_table);
1556 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
1557
1558 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1559 }
1560
1561 DEFUN (ospf6_redistribute,
1562 ospf6_redistribute_cmd,
1563 "redistribute " FRR_REDIST_STR_OSPF6D,
1564 "Redistribute\n"
1565 FRR_REDIST_HELP_STR_OSPF6D)
1566 {
1567 int type;
1568 struct ospf6_redist *red;
1569
1570 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1571
1572 char *proto = argv[argc - 1]->text;
1573 type = proto_redistnum(AFI_IP6, proto);
1574 if (type < 0)
1575 return CMD_WARNING_CONFIG_FAILED;
1576
1577 red = ospf6_redist_add(ospf6, type, 0);
1578 if (!red)
1579 return CMD_SUCCESS;
1580
1581 ospf6_asbr_redistribute_unset(ospf6, red, type);
1582 ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
1583
1584 return CMD_SUCCESS;
1585 }
1586
1587 DEFUN (ospf6_redistribute_routemap,
1588 ospf6_redistribute_routemap_cmd,
1589 "redistribute " FRR_REDIST_STR_OSPF6D " route-map WORD",
1590 "Redistribute\n"
1591 FRR_REDIST_HELP_STR_OSPF6D
1592 "Route map reference\n"
1593 "Route map name\n")
1594 {
1595 int idx_protocol = 1;
1596 int idx_word = 3;
1597 int type;
1598 struct ospf6_redist *red;
1599
1600 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1601
1602 char *proto = argv[idx_protocol]->text;
1603 type = proto_redistnum(AFI_IP6, proto);
1604 if (type < 0)
1605 return CMD_WARNING_CONFIG_FAILED;
1606
1607 red = ospf6_redist_add(ospf6, type, 0);
1608 if (!red)
1609 return CMD_SUCCESS;
1610
1611 ospf6_asbr_redistribute_unset(ospf6, red, type);
1612 ospf6_asbr_routemap_set(red, argv[idx_word]->arg);
1613 ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
1614
1615 return CMD_SUCCESS;
1616 }
1617
1618 DEFUN (no_ospf6_redistribute,
1619 no_ospf6_redistribute_cmd,
1620 "no redistribute " FRR_REDIST_STR_OSPF6D " [route-map WORD]",
1621 NO_STR
1622 "Redistribute\n"
1623 FRR_REDIST_HELP_STR_OSPF6D
1624 "Route map reference\n"
1625 "Route map name\n")
1626 {
1627 int idx_protocol = 2;
1628 int type;
1629 struct ospf6_redist *red;
1630
1631 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1632
1633 char *proto = argv[idx_protocol]->text;
1634 type = proto_redistnum(AFI_IP6, proto);
1635 if (type < 0)
1636 return CMD_WARNING_CONFIG_FAILED;
1637
1638 red = ospf6_redist_lookup(ospf6, type, 0);
1639 if (!red)
1640 return CMD_SUCCESS;
1641
1642 ospf6_asbr_redistribute_unset(ospf6, red, type);
1643 ospf6_redist_del(ospf6, red, type);
1644
1645 return CMD_SUCCESS;
1646 }
1647
1648 int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
1649 {
1650 int type;
1651 struct ospf6_redist *red;
1652
1653 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1654 red = ospf6_redist_lookup(ospf6, type, 0);
1655 if (!red)
1656 continue;
1657 if (type == ZEBRA_ROUTE_OSPF6)
1658 continue;
1659
1660 if (ROUTEMAP_NAME(red))
1661 vty_out(vty, " redistribute %s route-map %s\n",
1662 ZROUTE_NAME(type), ROUTEMAP_NAME(red));
1663 else
1664 vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type));
1665 }
1666
1667 return 0;
1668 }
1669
1670 static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
1671 json_object *json_array,
1672 json_object *json, bool use_json)
1673 {
1674 int type;
1675 int nroute[ZEBRA_ROUTE_MAX];
1676 int total;
1677 struct ospf6_route *route;
1678 struct ospf6_external_info *info;
1679 json_object *json_route;
1680 struct ospf6_redist *red;
1681
1682 total = 0;
1683 memset(nroute, 0, sizeof(nroute));
1684 for (route = ospf6_route_head(ospf6->external_table); route;
1685 route = ospf6_route_next(route)) {
1686 info = route->route_option;
1687 nroute[info->type]++;
1688 total++;
1689 }
1690
1691 if (!use_json)
1692 vty_out(vty, "Redistributing External Routes from:\n");
1693
1694 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1695
1696 red = ospf6_redist_lookup(ospf6, type, 0);
1697
1698 if (!red)
1699 continue;
1700 if (type == ZEBRA_ROUTE_OSPF6)
1701 continue;
1702
1703 if (use_json) {
1704 json_route = json_object_new_object();
1705 json_object_string_add(json_route, "routeType",
1706 ZROUTE_NAME(type));
1707 json_object_int_add(json_route, "numberOfRoutes",
1708 nroute[type]);
1709 json_object_boolean_add(json_route,
1710 "routeMapNamePresent",
1711 ROUTEMAP_NAME(red));
1712 }
1713
1714 if (ROUTEMAP_NAME(red)) {
1715 if (use_json) {
1716 json_object_string_add(json_route,
1717 "routeMapName",
1718 ROUTEMAP_NAME(red));
1719 json_object_boolean_add(json_route,
1720 "routeMapFound",
1721 ROUTEMAP(red));
1722 } else
1723 vty_out(vty,
1724 " %d: %s with route-map \"%s\"%s\n",
1725 nroute[type], ZROUTE_NAME(type),
1726 ROUTEMAP_NAME(red),
1727 (ROUTEMAP(red) ? ""
1728 : " (not found !)"));
1729 } else {
1730 if (!use_json)
1731 vty_out(vty, " %d: %s\n", nroute[type],
1732 ZROUTE_NAME(type));
1733 }
1734
1735 if (use_json)
1736 json_object_array_add(json_array, json_route);
1737 }
1738 if (use_json) {
1739 json_object_object_add(json, "redistributedRoutes", json_array);
1740 json_object_int_add(json, "totalRoutes", total);
1741 } else
1742 vty_out(vty, "Total %d routes\n", total);
1743 }
1744
1745 static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate)
1746 {
1747 struct prefix_ipv6 p = {};
1748 struct in6_addr nexthop = {};
1749 int cur_originate = ospf6->default_originate;
1750
1751 p.family = AF_INET6;
1752 p.prefixlen = 0;
1753
1754 ospf6->default_originate = originate;
1755
1756 switch (cur_originate) {
1757 case DEFAULT_ORIGINATE_NONE:
1758 break;
1759 case DEFAULT_ORIGINATE_ZEBRA:
1760 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
1761 zclient, AFI_IP6, ospf6->vrf_id);
1762 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1763 (struct prefix *)&p, ospf6);
1764
1765 break;
1766 case DEFAULT_ORIGINATE_ALWAYS:
1767 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1768 (struct prefix *)&p, ospf6);
1769 break;
1770 }
1771
1772 switch (originate) {
1773 case DEFAULT_ORIGINATE_NONE:
1774 break;
1775 case DEFAULT_ORIGINATE_ZEBRA:
1776 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
1777 zclient, AFI_IP6, ospf6->vrf_id);
1778
1779 break;
1780 case DEFAULT_ORIGINATE_ALWAYS:
1781 ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0,
1782 (struct prefix *)&p, 0, &nexthop, 0,
1783 ospf6);
1784 break;
1785 }
1786 }
1787
1788 /* Default Route originate. */
1789 DEFPY (ospf6_default_route_originate,
1790 ospf6_default_route_originate_cmd,
1791 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map WORD$rtmap}]",
1792 "Control distribution of default route\n"
1793 "Distribute a default route\n"
1794 "Always advertise default route\n"
1795 "OSPFv3 default metric\n"
1796 "OSPFv3 metric\n"
1797 "OSPFv3 metric type for default routes\n"
1798 "Set OSPFv3 External Type 1/2 metrics\n"
1799 "Route map reference\n"
1800 "Pointer to route-map entries\n")
1801 {
1802 int default_originate = DEFAULT_ORIGINATE_ZEBRA;
1803 struct ospf6_redist *red;
1804 bool sameRtmap = false;
1805
1806 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1807
1808 int cur_originate = ospf6->default_originate;
1809
1810 red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
1811
1812 if (always != NULL)
1813 default_originate = DEFAULT_ORIGINATE_ALWAYS;
1814
1815 if (mval_str == NULL)
1816 mval = -1;
1817
1818 if (mtype_str == NULL)
1819 mtype = -1;
1820
1821 /* To check ,if user is providing same route map */
1822 if ((rtmap == ROUTEMAP_NAME(red))
1823 || (rtmap && ROUTEMAP_NAME(red)
1824 && (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0)))
1825 sameRtmap = true;
1826
1827 /* Don't allow if the same lsa is aleardy originated. */
1828 if ((sameRtmap) && (red->dmetric.type == mtype)
1829 && (red->dmetric.value == mval)
1830 && (cur_originate == default_originate))
1831 return CMD_SUCCESS;
1832
1833 /* Updating Metric details */
1834 red->dmetric.type = mtype;
1835 red->dmetric.value = mval;
1836
1837 /* updating route map details */
1838 if (rtmap)
1839 ospf6_asbr_routemap_set(red, rtmap);
1840 else
1841 ospf6_asbr_routemap_unset(red);
1842
1843 ospf6_redistribute_default_set(ospf6, default_originate);
1844 return CMD_SUCCESS;
1845 }
1846
1847 DEFPY (no_ospf6_default_information_originate,
1848 no_ospf6_default_information_originate_cmd,
1849 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
1850 NO_STR
1851 "Control distribution of default information\n"
1852 "Distribute a default route\n"
1853 "Always advertise default route\n"
1854 "OSPFv3 default metric\n"
1855 "OSPFv3 metric\n"
1856 "OSPFv3 metric type for default routes\n"
1857 "Set OSPFv3 External Type 1/2 metrics\n"
1858 "Route map reference\n"
1859 "Pointer to route-map entries\n")
1860 {
1861 struct ospf6_redist *red;
1862
1863 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1864
1865 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
1866 if (!red)
1867 return CMD_SUCCESS;
1868
1869 ospf6_asbr_routemap_unset(red);
1870 ospf6_redist_del(ospf6, red, DEFAULT_ROUTE);
1871
1872 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
1873 return CMD_SUCCESS;
1874 }
1875
1876 /* Routemap Functions */
1877 static enum route_map_cmd_result_t
1878 ospf6_routemap_rule_match_address_prefixlist(void *rule,
1879 const struct prefix *prefix,
1880
1881 void *object)
1882 {
1883 struct prefix_list *plist;
1884
1885 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1886 if (plist == NULL)
1887 return RMAP_NOMATCH;
1888
1889 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1890 : RMAP_MATCH);
1891 }
1892
1893 static void *
1894 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
1895 {
1896 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1897 }
1898
1899 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
1900 {
1901 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1902 }
1903
1904 static const struct route_map_rule_cmd
1905 ospf6_routemap_rule_match_address_prefixlist_cmd = {
1906 "ipv6 address prefix-list",
1907 ospf6_routemap_rule_match_address_prefixlist,
1908 ospf6_routemap_rule_match_address_prefixlist_compile,
1909 ospf6_routemap_rule_match_address_prefixlist_free,
1910 };
1911
1912 /* `match interface IFNAME' */
1913 /* Match function should return 1 if match is success else return
1914 zero. */
1915 static enum route_map_cmd_result_t
1916 ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
1917 void *object)
1918 {
1919 struct interface *ifp;
1920 struct ospf6_external_info *ei;
1921
1922 ei = ((struct ospf6_route *)object)->route_option;
1923 ifp = if_lookup_by_name_all_vrf((char *)rule);
1924
1925 if (ifp != NULL && ei->ifindex == ifp->ifindex)
1926 return RMAP_MATCH;
1927
1928 return RMAP_NOMATCH;
1929 }
1930
1931 /* Route map `interface' match statement. `arg' should be
1932 interface name. */
1933 static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
1934 {
1935 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1936 }
1937
1938 /* Free route map's compiled `interface' value. */
1939 static void ospf6_routemap_rule_match_interface_free(void *rule)
1940 {
1941 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1942 }
1943
1944 /* Route map commands for interface matching. */
1945 static const struct route_map_rule_cmd
1946 ospf6_routemap_rule_match_interface_cmd = {
1947 "interface",
1948 ospf6_routemap_rule_match_interface,
1949 ospf6_routemap_rule_match_interface_compile,
1950 ospf6_routemap_rule_match_interface_free
1951 };
1952
1953 /* Match function for matching route tags */
1954 static enum route_map_cmd_result_t
1955 ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, void *object)
1956 {
1957 route_tag_t *tag = rule;
1958 struct ospf6_route *route = object;
1959 struct ospf6_external_info *info = route->route_option;
1960
1961 if (info->tag == *tag)
1962 return RMAP_MATCH;
1963
1964 return RMAP_NOMATCH;
1965 }
1966
1967 static const struct route_map_rule_cmd
1968 ospf6_routemap_rule_match_tag_cmd = {
1969 "tag",
1970 ospf6_routemap_rule_match_tag,
1971 route_map_rule_tag_compile,
1972 route_map_rule_tag_free,
1973 };
1974
1975 static enum route_map_cmd_result_t
1976 ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
1977 void *object)
1978 {
1979 char *metric_type = rule;
1980 struct ospf6_route *route = object;
1981
1982 if (strcmp(metric_type, "type-2") == 0)
1983 route->path.metric_type = 2;
1984 else
1985 route->path.metric_type = 1;
1986
1987 return RMAP_OKAY;
1988 }
1989
1990 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
1991 {
1992 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
1993 return NULL;
1994 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1995 }
1996
1997 static void ospf6_routemap_rule_set_metric_type_free(void *rule)
1998 {
1999 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2000 }
2001
2002 static const struct route_map_rule_cmd
2003 ospf6_routemap_rule_set_metric_type_cmd = {
2004 "metric-type",
2005 ospf6_routemap_rule_set_metric_type,
2006 ospf6_routemap_rule_set_metric_type_compile,
2007 ospf6_routemap_rule_set_metric_type_free,
2008 };
2009
2010 static enum route_map_cmd_result_t
2011 ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
2012 void *object)
2013 {
2014 char *metric = rule;
2015 struct ospf6_route *route = object;
2016
2017 route->path.cost = atoi(metric);
2018 return RMAP_OKAY;
2019 }
2020
2021 static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
2022 {
2023 uint32_t metric;
2024 char *endp;
2025 metric = strtoul(arg, &endp, 0);
2026 if (metric > OSPF_LS_INFINITY || *endp != '\0')
2027 return NULL;
2028 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2029 }
2030
2031 static void ospf6_routemap_rule_set_metric_free(void *rule)
2032 {
2033 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2034 }
2035
2036 static const struct route_map_rule_cmd
2037 ospf6_routemap_rule_set_metric_cmd = {
2038 "metric",
2039 ospf6_routemap_rule_set_metric,
2040 ospf6_routemap_rule_set_metric_compile,
2041 ospf6_routemap_rule_set_metric_free,
2042 };
2043
2044 static enum route_map_cmd_result_t
2045 ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
2046 void *object)
2047 {
2048 char *forwarding = rule;
2049 struct ospf6_route *route = object;
2050 struct ospf6_external_info *info = route->route_option;
2051
2052 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
2053 memset(&info->forwarding, 0, sizeof(struct in6_addr));
2054 return RMAP_ERROR;
2055 }
2056
2057 return RMAP_OKAY;
2058 }
2059
2060 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
2061 {
2062 struct in6_addr a;
2063 if (inet_pton(AF_INET6, arg, &a) != 1)
2064 return NULL;
2065 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2066 }
2067
2068 static void ospf6_routemap_rule_set_forwarding_free(void *rule)
2069 {
2070 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2071 }
2072
2073 static const struct route_map_rule_cmd
2074 ospf6_routemap_rule_set_forwarding_cmd = {
2075 "forwarding-address",
2076 ospf6_routemap_rule_set_forwarding,
2077 ospf6_routemap_rule_set_forwarding_compile,
2078 ospf6_routemap_rule_set_forwarding_free,
2079 };
2080
2081 static enum route_map_cmd_result_t
2082 ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object)
2083 {
2084 route_tag_t *tag = rule;
2085 struct ospf6_route *route = object;
2086 struct ospf6_external_info *info = route->route_option;
2087
2088 info->tag = *tag;
2089 return RMAP_OKAY;
2090 }
2091
2092 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
2093 "tag",
2094 ospf6_routemap_rule_set_tag,
2095 route_map_rule_tag_compile,
2096 route_map_rule_tag_free,
2097 };
2098
2099 /* add "set metric-type" */
2100 DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
2101 "set metric-type <type-1|type-2>",
2102 "Set value\n"
2103 "Type of metric\n"
2104 "OSPF6 external type 1 metric\n"
2105 "OSPF6 external type 2 metric\n")
2106 {
2107 char *ext = argv[2]->text;
2108
2109 const char *xpath =
2110 "./set-action[action='frr-ospf-route-map:metric-type']";
2111 char xpath_value[XPATH_MAXLEN];
2112
2113 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2114 snprintf(xpath_value, sizeof(xpath_value),
2115 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
2116 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
2117 return nb_cli_apply_changes(vty, NULL);
2118 }
2119
2120 /* delete "set metric-type" */
2121 DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
2122 "no set metric-type [<type-1|type-2>]",
2123 NO_STR
2124 "Set value\n"
2125 "Type of metric\n"
2126 "OSPF6 external type 1 metric\n"
2127 "OSPF6 external type 2 metric\n")
2128 {
2129 const char *xpath =
2130 "./set-action[action='frr-ospf-route-map:metric-type']";
2131
2132 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2133 return nb_cli_apply_changes(vty, NULL);
2134 }
2135
2136 /* add "set forwarding-address" */
2137 DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd,
2138 "set forwarding-address X:X::X:X",
2139 "Set value\n"
2140 "Forwarding Address\n"
2141 "IPv6 Address\n")
2142 {
2143 int idx_ipv6 = 2;
2144 const char *xpath =
2145 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2146 char xpath_value[XPATH_MAXLEN];
2147
2148 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2149 snprintf(xpath_value, sizeof(xpath_value),
2150 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath);
2151 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
2152 argv[idx_ipv6]->arg);
2153 return nb_cli_apply_changes(vty, NULL);
2154 }
2155
2156 /* delete "set forwarding-address" */
2157 DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd,
2158 "no set forwarding-address [X:X::X:X]",
2159 NO_STR
2160 "Set value\n"
2161 "Forwarding Address\n"
2162 "IPv6 Address\n")
2163 {
2164 const char *xpath =
2165 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2166
2167 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2168 return nb_cli_apply_changes(vty, NULL);
2169 }
2170
2171 static void ospf6_routemap_init(void)
2172 {
2173 route_map_init();
2174
2175 route_map_add_hook(ospf6_asbr_routemap_update);
2176 route_map_delete_hook(ospf6_asbr_routemap_update);
2177 route_map_event_hook(ospf6_asbr_routemap_event);
2178
2179 route_map_set_metric_hook(generic_set_add);
2180 route_map_no_set_metric_hook(generic_set_delete);
2181
2182 route_map_set_tag_hook(generic_set_add);
2183 route_map_no_set_tag_hook(generic_set_delete);
2184
2185 route_map_match_tag_hook(generic_match_add);
2186 route_map_no_match_tag_hook(generic_match_delete);
2187
2188 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
2189 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
2190
2191 route_map_match_interface_hook(generic_match_add);
2192 route_map_no_match_interface_hook(generic_match_delete);
2193
2194 route_map_install_match(
2195 &ospf6_routemap_rule_match_address_prefixlist_cmd);
2196 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
2197 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
2198
2199 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
2200 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
2201 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
2202 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
2203
2204 /* ASE Metric Type (e.g. Type-1/Type-2) */
2205 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
2206 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
2207
2208 /* ASE Metric */
2209 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
2210 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
2211 }
2212
2213
2214 /* Display functions */
2215 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
2216 char *buf, int buflen,
2217 int pos)
2218 {
2219 struct ospf6_as_external_lsa *external;
2220 struct in6_addr in6;
2221 int prefix_length = 0;
2222 char tbuf[16];
2223
2224 if (lsa) {
2225 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2226 lsa->header);
2227
2228 if (pos == 0) {
2229 ospf6_prefix_in6_addr(&in6, external,
2230 &external->prefix);
2231 prefix_length = external->prefix.prefix_length;
2232 } else {
2233 in6 = *((struct in6_addr
2234 *)((caddr_t)external
2235 + sizeof(struct
2236 ospf6_as_external_lsa)
2237 + OSPF6_PREFIX_SPACE(
2238 external->prefix
2239 .prefix_length)));
2240 }
2241 if (buf) {
2242 inet_ntop(AF_INET6, &in6, buf, buflen);
2243 if (prefix_length) {
2244 snprintf(tbuf, sizeof(tbuf), "/%d",
2245 prefix_length);
2246 strlcat(buf, tbuf, buflen);
2247 }
2248 }
2249 }
2250 return (buf);
2251 }
2252
2253 static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
2254 json_object *json_obj, bool use_json)
2255 {
2256 struct ospf6_as_external_lsa *external;
2257 char buf[64];
2258
2259 assert(lsa->header);
2260 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2261 lsa->header);
2262
2263 /* bits */
2264 snprintf(buf, sizeof(buf), "%c%c%c",
2265 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
2266 : '-'),
2267 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
2268 : '-'),
2269 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
2270 : '-'));
2271
2272 if (use_json) {
2273 json_object_string_add(json_obj, "bits", buf);
2274 json_object_int_add(json_obj, "metric",
2275 (unsigned long)OSPF6_ASBR_METRIC(external));
2276 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2277 buf, sizeof(buf));
2278 json_object_string_add(json_obj, "prefixOptions", buf);
2279 json_object_int_add(
2280 json_obj, "referenceLsType",
2281 ntohs(external->prefix.prefix_refer_lstype));
2282 json_object_string_add(json_obj, "prefix",
2283 ospf6_as_external_lsa_get_prefix_str(
2284 lsa, buf, sizeof(buf), 0));
2285
2286 /* Forwarding-Address */
2287 json_object_boolean_add(
2288 json_obj, "forwardingAddressPresent",
2289 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F));
2290 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
2291 json_object_string_add(
2292 json_obj, "forwardingAddress",
2293 ospf6_as_external_lsa_get_prefix_str(
2294 lsa, buf, sizeof(buf), 1));
2295
2296 /* Tag */
2297 json_object_boolean_add(
2298 json_obj, "tagPresent",
2299 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T));
2300 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
2301 json_object_int_add(json_obj, "tag",
2302 ospf6_as_external_lsa_get_tag(lsa));
2303 } else {
2304 vty_out(vty, " Bits: %s\n", buf);
2305 vty_out(vty, " Metric: %5lu\n",
2306 (unsigned long)OSPF6_ASBR_METRIC(external));
2307
2308 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2309 buf, sizeof(buf));
2310 vty_out(vty, " Prefix Options: %s\n", buf);
2311
2312 vty_out(vty, " Referenced LSType: %d\n",
2313 ntohs(external->prefix.prefix_refer_lstype));
2314
2315 vty_out(vty, " Prefix: %s\n",
2316 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
2317 sizeof(buf), 0));
2318
2319 /* Forwarding-Address */
2320 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
2321 vty_out(vty, " Forwarding-Address: %s\n",
2322 ospf6_as_external_lsa_get_prefix_str(
2323 lsa, buf, sizeof(buf), 1));
2324 }
2325
2326 /* Tag */
2327 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
2328 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
2329 ospf6_as_external_lsa_get_tag(lsa));
2330 }
2331 }
2332
2333 return 0;
2334 }
2335
2336 static void ospf6_asbr_external_route_show(struct vty *vty,
2337 struct ospf6_route *route,
2338 json_object *json_array,
2339 bool use_json)
2340 {
2341 struct ospf6_external_info *info = route->route_option;
2342 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
2343 uint32_t tmp_id;
2344 json_object *json_route;
2345 char route_type[2];
2346
2347 prefix2str(&route->prefix, prefix, sizeof(prefix));
2348 tmp_id = ntohl(info->id);
2349 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
2350 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
2351 inet_ntop(AF_INET6, &info->forwarding, forwarding,
2352 sizeof(forwarding));
2353 else
2354 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
2355 ospf6_route_get_first_nh_index(route));
2356
2357 if (use_json) {
2358 json_route = json_object_new_object();
2359 snprintf(route_type, sizeof(route_type), "%c",
2360 zebra_route_char(info->type));
2361 json_object_string_add(json_route, "routeType", route_type);
2362 json_object_string_add(json_route, "destination", prefix);
2363 json_object_string_add(json_route, "id", id);
2364 json_object_int_add(json_route, "metricType",
2365 route->path.metric_type);
2366 json_object_int_add(
2367 json_route, "routeCost",
2368 (unsigned long)(route->path.metric_type == 2
2369 ? route->path.u.cost_e2
2370 : route->path.cost));
2371 json_object_string_add(json_route, "forwarding", forwarding);
2372
2373 json_object_array_add(json_array, json_route);
2374 } else
2375
2376 vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
2377 zebra_route_char(info->type), &route->prefix, id,
2378 route->path.metric_type,
2379 (unsigned long)(route->path.metric_type == 2
2380 ? route->path.u.cost_e2
2381 : route->path.cost),
2382 forwarding);
2383 }
2384
2385 DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
2386 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2387 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2388 "All VRFs\n"
2389 "redistributing External information\n" JSON_STR)
2390 {
2391 struct ospf6_route *route;
2392 struct ospf6 *ospf6 = NULL;
2393 json_object *json = NULL;
2394 bool uj = use_json(argc, argv);
2395 struct listnode *node;
2396 const char *vrf_name = NULL;
2397 bool all_vrf = false;
2398 int idx_vrf = 0;
2399
2400 json_object *json_array_routes = NULL;
2401 json_object *json_array_redistribute = NULL;
2402
2403 OSPF6_CMD_CHECK_RUNNING();
2404 OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
2405
2406 if (uj) {
2407 json = json_object_new_object();
2408 json_array_routes = json_object_new_array();
2409 json_array_redistribute = json_object_new_array();
2410 }
2411
2412 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
2413 if (all_vrf
2414 || ((ospf6->name == NULL && vrf_name == NULL)
2415 || (ospf6->name && vrf_name
2416 && strcmp(ospf6->name, vrf_name) == 0))) {
2417 ospf6_redistribute_show_config(
2418 vty, ospf6, json_array_redistribute, json, uj);
2419
2420 for (route = ospf6_route_head(ospf6->external_table);
2421 route; route = ospf6_route_next(route)) {
2422 ospf6_asbr_external_route_show(
2423 vty, route, json_array_routes, uj);
2424 }
2425
2426 if (uj) {
2427 json_object_object_add(json, "routes",
2428 json_array_routes);
2429 vty_out(vty, "%s\n",
2430 json_object_to_json_string_ext(
2431 json, JSON_C_TO_STRING_PRETTY));
2432 json_object_free(json);
2433 }
2434
2435 if (!all_vrf)
2436 break;
2437 }
2438 }
2439
2440 return CMD_SUCCESS;
2441 }
2442
2443 static struct ospf6_lsa_handler as_external_handler = {
2444 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
2445 .lh_name = "AS-External",
2446 .lh_short_name = "ASE",
2447 .lh_show = ospf6_as_external_lsa_show,
2448 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2449 .lh_debug = 0};
2450
2451 static struct ospf6_lsa_handler nssa_external_handler = {
2452 .lh_type = OSPF6_LSTYPE_TYPE_7,
2453 .lh_name = "NSSA",
2454 .lh_short_name = "Type7",
2455 .lh_show = ospf6_as_external_lsa_show,
2456 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2457 .lh_debug = 0};
2458
2459 void ospf6_asbr_init(void)
2460 {
2461 ospf6_routemap_init();
2462
2463 ospf6_install_lsa_handler(&as_external_handler);
2464 ospf6_install_lsa_handler(&nssa_external_handler);
2465
2466 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
2467
2468 install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd);
2469 install_element(OSPF6_NODE,
2470 &no_ospf6_default_information_originate_cmd);
2471 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
2472 install_element(OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
2473 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
2474 }
2475
2476 void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
2477 {
2478 int type;
2479 struct ospf6_redist *red;
2480
2481 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
2482 red = ospf6_redist_lookup(ospf6, type, 0);
2483 if (!red)
2484 continue;
2485 if (type == ZEBRA_ROUTE_OSPF6)
2486 continue;
2487 ospf6_asbr_redistribute_unset(ospf6, red, type);
2488 ospf6_redist_del(ospf6, red, type);
2489 }
2490 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2491 if (red) {
2492 ospf6_asbr_routemap_unset(red);
2493 ospf6_redist_del(ospf6, red, type);
2494 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
2495 }
2496 }
2497
2498 void ospf6_asbr_terminate(void)
2499 {
2500 /* Cleanup route maps */
2501 route_map_finish();
2502 }
2503
2504 DEFUN (debug_ospf6_asbr,
2505 debug_ospf6_asbr_cmd,
2506 "debug ospf6 asbr",
2507 DEBUG_STR
2508 OSPF6_STR
2509 "Debug OSPFv3 ASBR function\n"
2510 )
2511 {
2512 OSPF6_DEBUG_ASBR_ON();
2513 return CMD_SUCCESS;
2514 }
2515
2516 DEFUN (no_debug_ospf6_asbr,
2517 no_debug_ospf6_asbr_cmd,
2518 "no debug ospf6 asbr",
2519 NO_STR
2520 DEBUG_STR
2521 OSPF6_STR
2522 "Debug OSPFv3 ASBR function\n"
2523 )
2524 {
2525 OSPF6_DEBUG_ASBR_OFF();
2526 return CMD_SUCCESS;
2527 }
2528
2529 int config_write_ospf6_debug_asbr(struct vty *vty)
2530 {
2531 if (IS_OSPF6_DEBUG_ASBR)
2532 vty_out(vty, "debug ospf6 asbr\n");
2533 return 0;
2534 }
2535
2536 int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6)
2537 {
2538 struct ospf6_redist *red;
2539
2540 if (ospf6) {
2541 /* default-route print. */
2542 if (ospf6->default_originate != DEFAULT_ORIGINATE_NONE) {
2543 vty_out(vty, " default-information originate");
2544 if (ospf6->default_originate
2545 == DEFAULT_ORIGINATE_ALWAYS)
2546 vty_out(vty, " always");
2547
2548 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2549 if (red) {
2550 if (red->dmetric.value >= 0)
2551 vty_out(vty, " metric %d",
2552 red->dmetric.value);
2553
2554 if (red->dmetric.type >= 0)
2555 vty_out(vty, " metric-type %d",
2556 red->dmetric.type);
2557
2558 if (ROUTEMAP_NAME(red))
2559 vty_out(vty, " route-map %s",
2560 ROUTEMAP_NAME(red));
2561 }
2562
2563 vty_out(vty, "\n");
2564 }
2565 }
2566 return 0;
2567 }
2568
2569 void install_element_ospf6_debug_asbr(void)
2570 {
2571 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
2572 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
2573 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
2574 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
2575 }