]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_asbr.c
*: Replace IPV6_MAX_PREFIXLEN to IPV6_MAX_BITLEN
[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(struct ospf6 *ospf6, int type);
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_BITLEN;
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 struct ospf6 *ospf6 = THREAD_ARG(thread);
1014 struct ospf6_redist *red;
1015 int type;
1016
1017 ospf6->t_distribute_update = NULL;
1018
1019 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1020 red = ospf6_redist_lookup(ospf6, type, 0);
1021
1022 if (!red)
1023 continue;
1024
1025 if (!CHECK_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED))
1026 continue;
1027
1028 if (ROUTEMAP_NAME(red))
1029 ROUTEMAP(red) =
1030 route_map_lookup_by_name(ROUTEMAP_NAME(red));
1031
1032 if (ROUTEMAP(red)) {
1033 if (IS_OSPF6_DEBUG_ASBR)
1034 zlog_debug(
1035 "%s: route-map %s update, reset redist %s",
1036 __func__, ROUTEMAP_NAME(red),
1037 ZROUTE_NAME(type));
1038
1039 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
1040 ospf6_zebra_redistribute(type, ospf6->vrf_id);
1041 }
1042
1043 UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
1044 }
1045
1046 return 0;
1047 }
1048
1049 void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
1050 struct ospf6_redist *red)
1051 {
1052 SET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
1053
1054 if (ospf6->t_distribute_update)
1055 return;
1056
1057 if (IS_OSPF6_DEBUG_ASBR)
1058 zlog_debug("%s: trigger redistribute reset thread", __func__);
1059
1060 ospf6->t_distribute_update = NULL;
1061 thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
1062 OSPF_MIN_LS_INTERVAL,
1063 &ospf6->t_distribute_update);
1064 }
1065
1066 void ospf6_asbr_routemap_update(const char *mapname)
1067 {
1068 int type;
1069 struct listnode *node, *nnode;
1070 struct ospf6 *ospf6 = NULL;
1071 struct ospf6_redist *red;
1072
1073 if (om6 == NULL)
1074 return;
1075
1076 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1077 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1078 red = ospf6_redist_lookup(ospf6, type, 0);
1079 if (!red || (ROUTEMAP_NAME(red) == NULL))
1080 continue;
1081 ROUTEMAP(red) =
1082 route_map_lookup_by_name(ROUTEMAP_NAME(red));
1083
1084 if (mapname == NULL
1085 || strcmp(ROUTEMAP_NAME(red), mapname))
1086 continue;
1087 if (ROUTEMAP(red)) {
1088 if (IS_OSPF6_DEBUG_ASBR)
1089 zlog_debug(
1090 "%s: route-map %s update, reset redist %s",
1091 __func__,
1092 mapname,
1093 ZROUTE_NAME(
1094 type));
1095
1096 route_map_counter_increment(ROUTEMAP(red));
1097 ospf6_asbr_distribute_list_update(ospf6, red);
1098 } else {
1099 /*
1100 * if the mapname matches a
1101 * route-map on ospf6 but the
1102 * map doesn't exist, it is
1103 * being deleted. flush and then
1104 * readvertise
1105 */
1106 if (IS_OSPF6_DEBUG_ASBR)
1107 zlog_debug(
1108 "%s: route-map %s deleted, reset redist %s",
1109 __func__,
1110 mapname,
1111 ZROUTE_NAME(
1112 type));
1113 ospf6_asbr_redistribute_unset(ospf6, red, type);
1114 ospf6_asbr_routemap_set(red, mapname);
1115 ospf6_asbr_redistribute_set(ospf6, type);
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(ospf6, red);
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 red->dmetric.type = -1;
1178 red->dmetric.value = -1;
1179 ROUTEMAP_NAME(red) = NULL;
1180 ROUTEMAP(red) = NULL;
1181
1182 listnode_add(ospf6->redist[type], red);
1183 ospf6->redistribute++;
1184
1185 return red;
1186 }
1187
1188 static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
1189 int type)
1190 {
1191 if (red) {
1192 listnode_delete(ospf6->redist[type], red);
1193 if (!ospf6->redist[type]->count) {
1194 list_delete(&ospf6->redist[type]);
1195 }
1196 XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
1197 ospf6->redistribute--;
1198 }
1199 }
1200
1201 /*Set the status of the ospf instance to ASBR based on the status parameter,
1202 * rechedule SPF calculation, originate router LSA*/
1203 void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
1204 {
1205 struct listnode *lnode, *lnnode;
1206 struct ospf6_area *oa;
1207
1208 zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
1209
1210 if (status) {
1211 if (IS_OSPF6_ASBR(ospf6)) {
1212 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1213 ospf6->name, status);
1214 return;
1215 }
1216 SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1217 } else {
1218 if (!IS_OSPF6_ASBR(ospf6)) {
1219 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1220 ospf6->name, status);
1221 return;
1222 }
1223 UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1224 }
1225
1226 /* Transition from/to status ASBR, schedule timer. */
1227 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
1228
1229 /* Reoriginate router LSA for all areas */
1230 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1231 OSPF6_ROUTER_LSA_SCHEDULE(oa);
1232 }
1233
1234 static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type)
1235 {
1236 ospf6_zebra_redistribute(type, ospf6->vrf_id);
1237
1238 ospf6_asbr_status_update(ospf6, ++ospf6->redist_count);
1239 }
1240
1241 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
1242 struct ospf6_redist *red, int type)
1243 {
1244 struct ospf6_route *route;
1245 struct ospf6_external_info *info;
1246
1247 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
1248
1249 for (route = ospf6_route_head(ospf6->external_table); route;
1250 route = ospf6_route_next(route)) {
1251 info = route->route_option;
1252 if (info->type != type)
1253 continue;
1254
1255 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix,
1256 ospf6);
1257 }
1258
1259 ospf6_asbr_routemap_unset(red);
1260 ospf6_asbr_status_update(ospf6, --ospf6->redist_count);
1261 }
1262
1263 /* When an area is unstubified, flood all the external LSAs in the area */
1264 void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
1265 {
1266 struct ospf6_lsa *lsa, *lsanext;
1267
1268 for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
1269 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
1270 if (IS_OSPF6_DEBUG_ASBR)
1271 zlog_debug("%s: Flooding AS-External LSA %s",
1272 __func__, lsa->name);
1273
1274 ospf6_flood_area(NULL, lsa, oa);
1275 }
1276 }
1277 }
1278
1279 /* When an area is stubified, remove all the external LSAs in the area */
1280 void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
1281 {
1282 struct ospf6_lsa *lsa, *lsanext;
1283 struct listnode *node, *nnode;
1284 struct ospf6_area *area;
1285 struct ospf6 *ospf6 = oa->ospf6;
1286 const struct route_node *iterend;
1287
1288 /* skip if router is in other non-stub areas */
1289 for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
1290 if (!IS_AREA_STUB(area))
1291 return;
1292
1293 /* if router is only in a stub area then purge AS-External LSAs */
1294 iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
1295 while (lsa != NULL) {
1296 assert(lsa->lock > 1);
1297 lsanext = ospf6_lsdb_next(iterend, lsa);
1298 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
1299 ospf6_lsdb_remove(lsa, ospf6->lsdb);
1300 lsa = lsanext;
1301 }
1302 }
1303
1304 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
1305 struct prefix *prefix,
1306 unsigned int nexthop_num,
1307 struct in6_addr *nexthop, route_tag_t tag,
1308 struct ospf6 *ospf6)
1309 {
1310 route_map_result_t ret;
1311 struct listnode *lnode;
1312 struct ospf6_area *oa;
1313 struct ospf6_route troute;
1314 struct ospf6_external_info tinfo;
1315 struct ospf6_route *route, *match;
1316 struct ospf6_external_info *info;
1317 struct prefix prefix_id;
1318 struct route_node *node;
1319 char ibuf[16];
1320 struct ospf6_redist *red;
1321
1322 red = ospf6_redist_lookup(ospf6, type, 0);
1323
1324 if (!red)
1325 return;
1326
1327 if ((type != DEFAULT_ROUTE)
1328 && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
1329 return;
1330
1331 memset(&troute, 0, sizeof(troute));
1332 memset(&tinfo, 0, sizeof(tinfo));
1333
1334 if (IS_OSPF6_DEBUG_ASBR)
1335 zlog_debug("Redistribute %pFX (%s)", prefix, ZROUTE_NAME(type));
1336
1337 /* if route-map was specified but not found, do not advertise */
1338 if (ROUTEMAP_NAME(red)) {
1339 if (ROUTEMAP(red) == NULL)
1340 ospf6_asbr_routemap_update(NULL);
1341 if (ROUTEMAP(red) == NULL) {
1342 zlog_warn(
1343 "route-map \"%s\" not found, suppress redistributing",
1344 ROUTEMAP_NAME(red));
1345 return;
1346 }
1347 }
1348
1349 /* apply route-map */
1350 if (ROUTEMAP(red)) {
1351 troute.route_option = &tinfo;
1352 tinfo.ifindex = ifindex;
1353 tinfo.tag = tag;
1354
1355 ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
1356 if (ret == RMAP_DENYMATCH) {
1357 if (IS_OSPF6_DEBUG_ASBR)
1358 zlog_debug("Denied by route-map \"%s\"",
1359 ROUTEMAP_NAME(red));
1360 ospf6_asbr_redistribute_remove(type, ifindex, prefix,
1361 ospf6);
1362 return;
1363 }
1364 }
1365
1366 match = ospf6_route_lookup(prefix, ospf6->external_table);
1367 if (match) {
1368 info = match->route_option;
1369 /* copy result of route-map */
1370 if (ROUTEMAP(red)) {
1371 if (troute.path.metric_type)
1372 match->path.metric_type =
1373 troute.path.metric_type;
1374 else
1375 match->path.metric_type =
1376 metric_type(ospf6, type, 0);
1377 if (troute.path.cost)
1378 match->path.cost = troute.path.cost;
1379 else
1380 match->path.cost = metric_value(ospf6, type, 0);
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 else
1442 route->path.metric_type = metric_type(ospf6, type, 0);
1443 if (troute.path.cost)
1444 route->path.cost = troute.path.cost;
1445 else
1446 route->path.cost = metric_value(ospf6, type, 0);
1447 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1448 memcpy(&info->forwarding, &tinfo.forwarding,
1449 sizeof(struct in6_addr));
1450 info->tag = tinfo.tag;
1451 } else {
1452 /* If there is no route-map, simply update the tag and metric
1453 * fields
1454 */
1455 route->path.metric_type = metric_type(ospf6, type, 0);
1456 route->path.cost = metric_value(ospf6, type, 0);
1457 info->tag = tag;
1458 }
1459
1460 info->type = type;
1461 if (nexthop_num && nexthop)
1462 ospf6_route_add_nexthop(route, ifindex, nexthop);
1463 else
1464 ospf6_route_add_nexthop(route, ifindex, NULL);
1465
1466 /* create/update binding in external_id_table */
1467 prefix_id.family = AF_INET;
1468 prefix_id.prefixlen = 32;
1469 prefix_id.u.prefix4.s_addr = htonl(info->id);
1470 node = route_node_get(ospf6->external_id_table, &prefix_id);
1471 node->info = route;
1472
1473 route = ospf6_route_add(route, ospf6->external_table);
1474 route->route_option = info;
1475
1476 if (IS_OSPF6_DEBUG_ASBR) {
1477 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
1478 zlog_debug(
1479 "Advertise as AS-External Id:%s prefix %pFX metric %u",
1480 ibuf, prefix, route->path.metric_type);
1481 }
1482
1483 route->path.origin.id = htonl(info->id);
1484 ospf6_as_external_lsa_originate(route, ospf6);
1485 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1486 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
1487 if (IS_AREA_NSSA(oa))
1488 ospf6_nssa_lsa_originate(route, oa);
1489 }
1490 }
1491
1492 void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
1493 struct prefix *prefix, struct ospf6 *ospf6)
1494 {
1495 struct ospf6_area *oa;
1496 struct ospf6_route *match;
1497 struct ospf6_external_info *info = NULL;
1498 struct listnode *lnode;
1499 struct route_node *node;
1500 struct ospf6_lsa *lsa;
1501 struct prefix prefix_id;
1502 char ibuf[16];
1503
1504 match = ospf6_route_lookup(prefix, ospf6->external_table);
1505 if (match == NULL) {
1506 if (IS_OSPF6_DEBUG_ASBR)
1507 zlog_debug("No such route %pFX to withdraw", prefix);
1508 return;
1509 }
1510
1511 info = match->route_option;
1512 assert(info);
1513
1514 if (info->type != type) {
1515 if (IS_OSPF6_DEBUG_ASBR)
1516 zlog_debug("Original protocol mismatch: %pFX", prefix);
1517 return;
1518 }
1519
1520 if (IS_OSPF6_DEBUG_ASBR) {
1521 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
1522 zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix, ibuf);
1523 }
1524
1525 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
1526 htonl(info->id), ospf6->router_id, ospf6->lsdb);
1527 if (lsa) {
1528 if (IS_OSPF6_DEBUG_ASBR) {
1529 zlog_debug("withdraw type 5 LSA for route %pFX",
1530 prefix);
1531 }
1532 ospf6_lsa_purge(lsa);
1533 }
1534
1535 /* Delete the NSSA LSA */
1536 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
1537 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7),
1538 htonl(info->id), ospf6->router_id,
1539 oa->lsdb);
1540 if (lsa) {
1541 if (IS_OSPF6_DEBUG_ASBR) {
1542 zlog_debug("withdraw type 7 LSA for route %pFX",
1543 prefix);
1544 }
1545 ospf6_lsa_purge(lsa);
1546 }
1547 }
1548
1549 /* remove binding in external_id_table */
1550 prefix_id.family = AF_INET;
1551 prefix_id.prefixlen = 32;
1552 prefix_id.u.prefix4.s_addr = htonl(info->id);
1553 node = route_node_lookup(ospf6->external_id_table, &prefix_id);
1554 assert(node);
1555 node->info = NULL;
1556 route_unlock_node(node); /* to free the lookup lock */
1557 route_unlock_node(node); /* to free the original lock */
1558
1559 ospf6_route_remove(match, ospf6->external_table);
1560 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
1561
1562 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1563 }
1564
1565 DEFUN (ospf6_redistribute,
1566 ospf6_redistribute_cmd,
1567 "redistribute " FRR_REDIST_STR_OSPF6D,
1568 "Redistribute\n"
1569 FRR_REDIST_HELP_STR_OSPF6D)
1570 {
1571 int type;
1572 struct ospf6_redist *red;
1573
1574 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1575
1576 char *proto = argv[argc - 1]->text;
1577 type = proto_redistnum(AFI_IP6, proto);
1578 if (type < 0)
1579 return CMD_WARNING_CONFIG_FAILED;
1580
1581 red = ospf6_redist_lookup(ospf6, type, 0);
1582 if (!red)
1583 ospf6_redist_add(ospf6, type, 0);
1584 else
1585 ospf6_asbr_redistribute_unset(ospf6, red, type);
1586
1587 ospf6_asbr_redistribute_set(ospf6, type);
1588
1589 return CMD_SUCCESS;
1590 }
1591
1592 DEFUN (ospf6_redistribute_routemap,
1593 ospf6_redistribute_routemap_cmd,
1594 "redistribute " FRR_REDIST_STR_OSPF6D " route-map WORD",
1595 "Redistribute\n"
1596 FRR_REDIST_HELP_STR_OSPF6D
1597 "Route map reference\n"
1598 "Route map name\n")
1599 {
1600 int idx_protocol = 1;
1601 int idx_word = 3;
1602 int type;
1603 struct ospf6_redist *red;
1604
1605 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1606
1607 char *proto = argv[idx_protocol]->text;
1608 type = proto_redistnum(AFI_IP6, proto);
1609 if (type < 0)
1610 return CMD_WARNING_CONFIG_FAILED;
1611
1612 red = ospf6_redist_lookup(ospf6, type, 0);
1613 if (!red)
1614 red = ospf6_redist_add(ospf6, type, 0);
1615 else
1616 ospf6_asbr_redistribute_unset(ospf6, red, type);
1617
1618 ospf6_asbr_routemap_set(red, argv[idx_word]->arg);
1619 ospf6_asbr_redistribute_set(ospf6, type);
1620
1621 return CMD_SUCCESS;
1622 }
1623
1624 DEFUN (no_ospf6_redistribute,
1625 no_ospf6_redistribute_cmd,
1626 "no redistribute " FRR_REDIST_STR_OSPF6D " [route-map WORD]",
1627 NO_STR
1628 "Redistribute\n"
1629 FRR_REDIST_HELP_STR_OSPF6D
1630 "Route map reference\n"
1631 "Route map name\n")
1632 {
1633 int idx_protocol = 2;
1634 int type;
1635 struct ospf6_redist *red;
1636
1637 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1638
1639 char *proto = argv[idx_protocol]->text;
1640 type = proto_redistnum(AFI_IP6, proto);
1641 if (type < 0)
1642 return CMD_WARNING_CONFIG_FAILED;
1643
1644 red = ospf6_redist_lookup(ospf6, type, 0);
1645 if (!red)
1646 return CMD_SUCCESS;
1647
1648 ospf6_asbr_redistribute_unset(ospf6, red, type);
1649 ospf6_redist_del(ospf6, red, type);
1650
1651 return CMD_SUCCESS;
1652 }
1653
1654 int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
1655 {
1656 int type;
1657 struct ospf6_redist *red;
1658
1659 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1660 red = ospf6_redist_lookup(ospf6, type, 0);
1661 if (!red)
1662 continue;
1663 if (type == ZEBRA_ROUTE_OSPF6)
1664 continue;
1665
1666 if (ROUTEMAP_NAME(red))
1667 vty_out(vty, " redistribute %s route-map %s\n",
1668 ZROUTE_NAME(type), ROUTEMAP_NAME(red));
1669 else
1670 vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type));
1671 }
1672
1673 return 0;
1674 }
1675
1676 static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
1677 json_object *json_array,
1678 json_object *json, bool use_json)
1679 {
1680 int type;
1681 int nroute[ZEBRA_ROUTE_MAX];
1682 int total;
1683 struct ospf6_route *route;
1684 struct ospf6_external_info *info;
1685 json_object *json_route;
1686 struct ospf6_redist *red;
1687
1688 total = 0;
1689 memset(nroute, 0, sizeof(nroute));
1690 for (route = ospf6_route_head(ospf6->external_table); route;
1691 route = ospf6_route_next(route)) {
1692 info = route->route_option;
1693 nroute[info->type]++;
1694 total++;
1695 }
1696
1697 if (!use_json)
1698 vty_out(vty, "Redistributing External Routes from:\n");
1699
1700 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1701
1702 red = ospf6_redist_lookup(ospf6, type, 0);
1703
1704 if (!red)
1705 continue;
1706 if (type == ZEBRA_ROUTE_OSPF6)
1707 continue;
1708
1709 if (use_json) {
1710 json_route = json_object_new_object();
1711 json_object_string_add(json_route, "routeType",
1712 ZROUTE_NAME(type));
1713 json_object_int_add(json_route, "numberOfRoutes",
1714 nroute[type]);
1715 json_object_boolean_add(json_route,
1716 "routeMapNamePresent",
1717 ROUTEMAP_NAME(red));
1718 }
1719
1720 if (ROUTEMAP_NAME(red)) {
1721 if (use_json) {
1722 json_object_string_add(json_route,
1723 "routeMapName",
1724 ROUTEMAP_NAME(red));
1725 json_object_boolean_add(json_route,
1726 "routeMapFound",
1727 ROUTEMAP(red));
1728 } else
1729 vty_out(vty,
1730 " %d: %s with route-map \"%s\"%s\n",
1731 nroute[type], ZROUTE_NAME(type),
1732 ROUTEMAP_NAME(red),
1733 (ROUTEMAP(red) ? ""
1734 : " (not found !)"));
1735 } else {
1736 if (!use_json)
1737 vty_out(vty, " %d: %s\n", nroute[type],
1738 ZROUTE_NAME(type));
1739 }
1740
1741 if (use_json)
1742 json_object_array_add(json_array, json_route);
1743 }
1744 if (use_json) {
1745 json_object_object_add(json, "redistributedRoutes", json_array);
1746 json_object_int_add(json, "totalRoutes", total);
1747 } else
1748 vty_out(vty, "Total %d routes\n", total);
1749 }
1750
1751 static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate)
1752 {
1753 struct prefix_ipv6 p = {};
1754 struct in6_addr nexthop = {};
1755 int cur_originate = ospf6->default_originate;
1756
1757 p.family = AF_INET6;
1758 p.prefixlen = 0;
1759
1760 ospf6->default_originate = originate;
1761
1762 switch (cur_originate) {
1763 case DEFAULT_ORIGINATE_NONE:
1764 break;
1765 case DEFAULT_ORIGINATE_ZEBRA:
1766 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
1767 zclient, AFI_IP6, ospf6->vrf_id);
1768 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1769 (struct prefix *)&p, ospf6);
1770
1771 break;
1772 case DEFAULT_ORIGINATE_ALWAYS:
1773 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1774 (struct prefix *)&p, ospf6);
1775 break;
1776 }
1777
1778 switch (originate) {
1779 case DEFAULT_ORIGINATE_NONE:
1780 break;
1781 case DEFAULT_ORIGINATE_ZEBRA:
1782 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
1783 zclient, AFI_IP6, ospf6->vrf_id);
1784
1785 break;
1786 case DEFAULT_ORIGINATE_ALWAYS:
1787 ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0,
1788 (struct prefix *)&p, 0, &nexthop, 0,
1789 ospf6);
1790 break;
1791 }
1792 }
1793
1794 /* Default Route originate. */
1795 DEFPY (ospf6_default_route_originate,
1796 ospf6_default_route_originate_cmd,
1797 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map WORD$rtmap}]",
1798 "Control distribution of default route\n"
1799 "Distribute a default route\n"
1800 "Always advertise default route\n"
1801 "OSPFv3 default metric\n"
1802 "OSPFv3 metric\n"
1803 "OSPFv3 metric type for default routes\n"
1804 "Set OSPFv3 External Type 1/2 metrics\n"
1805 "Route map reference\n"
1806 "Pointer to route-map entries\n")
1807 {
1808 int default_originate = DEFAULT_ORIGINATE_ZEBRA;
1809 struct ospf6_redist *red;
1810 bool sameRtmap = false;
1811
1812 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1813
1814 int cur_originate = ospf6->default_originate;
1815
1816 red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
1817
1818 if (always != NULL)
1819 default_originate = DEFAULT_ORIGINATE_ALWAYS;
1820
1821 if (mval_str == NULL)
1822 mval = -1;
1823
1824 if (mtype_str == NULL)
1825 mtype = -1;
1826
1827 /* To check ,if user is providing same route map */
1828 if ((rtmap == ROUTEMAP_NAME(red))
1829 || (rtmap && ROUTEMAP_NAME(red)
1830 && (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0)))
1831 sameRtmap = true;
1832
1833 /* Don't allow if the same lsa is aleardy originated. */
1834 if ((sameRtmap) && (red->dmetric.type == mtype)
1835 && (red->dmetric.value == mval)
1836 && (cur_originate == default_originate))
1837 return CMD_SUCCESS;
1838
1839 /* Updating Metric details */
1840 red->dmetric.type = mtype;
1841 red->dmetric.value = mval;
1842
1843 /* updating route map details */
1844 if (rtmap)
1845 ospf6_asbr_routemap_set(red, rtmap);
1846 else
1847 ospf6_asbr_routemap_unset(red);
1848
1849 ospf6_redistribute_default_set(ospf6, default_originate);
1850 return CMD_SUCCESS;
1851 }
1852
1853 DEFPY (no_ospf6_default_information_originate,
1854 no_ospf6_default_information_originate_cmd,
1855 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
1856 NO_STR
1857 "Control distribution of default information\n"
1858 "Distribute a default route\n"
1859 "Always advertise default route\n"
1860 "OSPFv3 default metric\n"
1861 "OSPFv3 metric\n"
1862 "OSPFv3 metric type for default routes\n"
1863 "Set OSPFv3 External Type 1/2 metrics\n"
1864 "Route map reference\n"
1865 "Pointer to route-map entries\n")
1866 {
1867 struct ospf6_redist *red;
1868
1869 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1870
1871 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
1872 if (!red)
1873 return CMD_SUCCESS;
1874
1875 ospf6_asbr_routemap_unset(red);
1876 ospf6_redist_del(ospf6, red, DEFAULT_ROUTE);
1877
1878 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
1879 return CMD_SUCCESS;
1880 }
1881
1882 /* Routemap Functions */
1883 static enum route_map_cmd_result_t
1884 ospf6_routemap_rule_match_address_prefixlist(void *rule,
1885 const struct prefix *prefix,
1886
1887 void *object)
1888 {
1889 struct prefix_list *plist;
1890
1891 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1892 if (plist == NULL)
1893 return RMAP_NOMATCH;
1894
1895 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1896 : RMAP_MATCH);
1897 }
1898
1899 static void *
1900 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
1901 {
1902 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1903 }
1904
1905 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
1906 {
1907 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1908 }
1909
1910 static const struct route_map_rule_cmd
1911 ospf6_routemap_rule_match_address_prefixlist_cmd = {
1912 "ipv6 address prefix-list",
1913 ospf6_routemap_rule_match_address_prefixlist,
1914 ospf6_routemap_rule_match_address_prefixlist_compile,
1915 ospf6_routemap_rule_match_address_prefixlist_free,
1916 };
1917
1918 /* `match interface IFNAME' */
1919 /* Match function should return 1 if match is success else return
1920 zero. */
1921 static enum route_map_cmd_result_t
1922 ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
1923 void *object)
1924 {
1925 struct interface *ifp;
1926 struct ospf6_external_info *ei;
1927
1928 ei = ((struct ospf6_route *)object)->route_option;
1929 ifp = if_lookup_by_name_all_vrf((char *)rule);
1930
1931 if (ifp != NULL && ei->ifindex == ifp->ifindex)
1932 return RMAP_MATCH;
1933
1934 return RMAP_NOMATCH;
1935 }
1936
1937 /* Route map `interface' match statement. `arg' should be
1938 interface name. */
1939 static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
1940 {
1941 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1942 }
1943
1944 /* Free route map's compiled `interface' value. */
1945 static void ospf6_routemap_rule_match_interface_free(void *rule)
1946 {
1947 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1948 }
1949
1950 /* Route map commands for interface matching. */
1951 static const struct route_map_rule_cmd
1952 ospf6_routemap_rule_match_interface_cmd = {
1953 "interface",
1954 ospf6_routemap_rule_match_interface,
1955 ospf6_routemap_rule_match_interface_compile,
1956 ospf6_routemap_rule_match_interface_free
1957 };
1958
1959 /* Match function for matching route tags */
1960 static enum route_map_cmd_result_t
1961 ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, void *object)
1962 {
1963 route_tag_t *tag = rule;
1964 struct ospf6_route *route = object;
1965 struct ospf6_external_info *info = route->route_option;
1966
1967 if (info->tag == *tag)
1968 return RMAP_MATCH;
1969
1970 return RMAP_NOMATCH;
1971 }
1972
1973 static const struct route_map_rule_cmd
1974 ospf6_routemap_rule_match_tag_cmd = {
1975 "tag",
1976 ospf6_routemap_rule_match_tag,
1977 route_map_rule_tag_compile,
1978 route_map_rule_tag_free,
1979 };
1980
1981 static enum route_map_cmd_result_t
1982 ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
1983 void *object)
1984 {
1985 char *metric_type = rule;
1986 struct ospf6_route *route = object;
1987
1988 if (strcmp(metric_type, "type-2") == 0)
1989 route->path.metric_type = 2;
1990 else
1991 route->path.metric_type = 1;
1992
1993 return RMAP_OKAY;
1994 }
1995
1996 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
1997 {
1998 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
1999 return NULL;
2000 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2001 }
2002
2003 static void ospf6_routemap_rule_set_metric_type_free(void *rule)
2004 {
2005 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2006 }
2007
2008 static const struct route_map_rule_cmd
2009 ospf6_routemap_rule_set_metric_type_cmd = {
2010 "metric-type",
2011 ospf6_routemap_rule_set_metric_type,
2012 ospf6_routemap_rule_set_metric_type_compile,
2013 ospf6_routemap_rule_set_metric_type_free,
2014 };
2015
2016 static enum route_map_cmd_result_t
2017 ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
2018 void *object)
2019 {
2020 char *metric = rule;
2021 struct ospf6_route *route = object;
2022
2023 route->path.cost = atoi(metric);
2024 return RMAP_OKAY;
2025 }
2026
2027 static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
2028 {
2029 uint32_t metric;
2030 char *endp;
2031 metric = strtoul(arg, &endp, 0);
2032 if (metric > OSPF_LS_INFINITY || *endp != '\0')
2033 return NULL;
2034 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2035 }
2036
2037 static void ospf6_routemap_rule_set_metric_free(void *rule)
2038 {
2039 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2040 }
2041
2042 static const struct route_map_rule_cmd
2043 ospf6_routemap_rule_set_metric_cmd = {
2044 "metric",
2045 ospf6_routemap_rule_set_metric,
2046 ospf6_routemap_rule_set_metric_compile,
2047 ospf6_routemap_rule_set_metric_free,
2048 };
2049
2050 static enum route_map_cmd_result_t
2051 ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
2052 void *object)
2053 {
2054 char *forwarding = rule;
2055 struct ospf6_route *route = object;
2056 struct ospf6_external_info *info = route->route_option;
2057
2058 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
2059 memset(&info->forwarding, 0, sizeof(struct in6_addr));
2060 return RMAP_ERROR;
2061 }
2062
2063 return RMAP_OKAY;
2064 }
2065
2066 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
2067 {
2068 struct in6_addr a;
2069 if (inet_pton(AF_INET6, arg, &a) != 1)
2070 return NULL;
2071 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2072 }
2073
2074 static void ospf6_routemap_rule_set_forwarding_free(void *rule)
2075 {
2076 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2077 }
2078
2079 static const struct route_map_rule_cmd
2080 ospf6_routemap_rule_set_forwarding_cmd = {
2081 "forwarding-address",
2082 ospf6_routemap_rule_set_forwarding,
2083 ospf6_routemap_rule_set_forwarding_compile,
2084 ospf6_routemap_rule_set_forwarding_free,
2085 };
2086
2087 static enum route_map_cmd_result_t
2088 ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object)
2089 {
2090 route_tag_t *tag = rule;
2091 struct ospf6_route *route = object;
2092 struct ospf6_external_info *info = route->route_option;
2093
2094 info->tag = *tag;
2095 return RMAP_OKAY;
2096 }
2097
2098 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
2099 "tag",
2100 ospf6_routemap_rule_set_tag,
2101 route_map_rule_tag_compile,
2102 route_map_rule_tag_free,
2103 };
2104
2105 /* add "set metric-type" */
2106 DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
2107 "set metric-type <type-1|type-2>",
2108 "Set value\n"
2109 "Type of metric\n"
2110 "OSPF6 external type 1 metric\n"
2111 "OSPF6 external type 2 metric\n")
2112 {
2113 char *ext = argv[2]->text;
2114
2115 const char *xpath =
2116 "./set-action[action='frr-ospf-route-map:metric-type']";
2117 char xpath_value[XPATH_MAXLEN];
2118
2119 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2120 snprintf(xpath_value, sizeof(xpath_value),
2121 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
2122 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
2123 return nb_cli_apply_changes(vty, NULL);
2124 }
2125
2126 /* delete "set metric-type" */
2127 DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
2128 "no set metric-type [<type-1|type-2>]",
2129 NO_STR
2130 "Set value\n"
2131 "Type of metric\n"
2132 "OSPF6 external type 1 metric\n"
2133 "OSPF6 external type 2 metric\n")
2134 {
2135 const char *xpath =
2136 "./set-action[action='frr-ospf-route-map:metric-type']";
2137
2138 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2139 return nb_cli_apply_changes(vty, NULL);
2140 }
2141
2142 /* add "set forwarding-address" */
2143 DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd,
2144 "set forwarding-address X:X::X:X",
2145 "Set value\n"
2146 "Forwarding Address\n"
2147 "IPv6 Address\n")
2148 {
2149 int idx_ipv6 = 2;
2150 const char *xpath =
2151 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2152 char xpath_value[XPATH_MAXLEN];
2153
2154 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2155 snprintf(xpath_value, sizeof(xpath_value),
2156 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath);
2157 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
2158 argv[idx_ipv6]->arg);
2159 return nb_cli_apply_changes(vty, NULL);
2160 }
2161
2162 /* delete "set forwarding-address" */
2163 DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd,
2164 "no set forwarding-address [X:X::X:X]",
2165 NO_STR
2166 "Set value\n"
2167 "Forwarding Address\n"
2168 "IPv6 Address\n")
2169 {
2170 const char *xpath =
2171 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2172
2173 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2174 return nb_cli_apply_changes(vty, NULL);
2175 }
2176
2177 static void ospf6_routemap_init(void)
2178 {
2179 route_map_init();
2180
2181 route_map_add_hook(ospf6_asbr_routemap_update);
2182 route_map_delete_hook(ospf6_asbr_routemap_update);
2183 route_map_event_hook(ospf6_asbr_routemap_event);
2184
2185 route_map_set_metric_hook(generic_set_add);
2186 route_map_no_set_metric_hook(generic_set_delete);
2187
2188 route_map_set_tag_hook(generic_set_add);
2189 route_map_no_set_tag_hook(generic_set_delete);
2190
2191 route_map_match_tag_hook(generic_match_add);
2192 route_map_no_match_tag_hook(generic_match_delete);
2193
2194 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
2195 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
2196
2197 route_map_match_interface_hook(generic_match_add);
2198 route_map_no_match_interface_hook(generic_match_delete);
2199
2200 route_map_install_match(
2201 &ospf6_routemap_rule_match_address_prefixlist_cmd);
2202 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
2203 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
2204
2205 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
2206 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
2207 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
2208 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
2209
2210 /* ASE Metric Type (e.g. Type-1/Type-2) */
2211 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
2212 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
2213
2214 /* ASE Metric */
2215 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
2216 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
2217 }
2218
2219
2220 /* Display functions */
2221 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
2222 char *buf, int buflen,
2223 int pos)
2224 {
2225 struct ospf6_as_external_lsa *external;
2226 struct in6_addr in6;
2227 int prefix_length = 0;
2228 char tbuf[16];
2229
2230 if (lsa) {
2231 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2232 lsa->header);
2233
2234 if (pos == 0) {
2235 ospf6_prefix_in6_addr(&in6, external,
2236 &external->prefix);
2237 prefix_length = external->prefix.prefix_length;
2238 } else {
2239 in6 = *((struct in6_addr
2240 *)((caddr_t)external
2241 + sizeof(struct
2242 ospf6_as_external_lsa)
2243 + OSPF6_PREFIX_SPACE(
2244 external->prefix
2245 .prefix_length)));
2246 }
2247 if (buf) {
2248 inet_ntop(AF_INET6, &in6, buf, buflen);
2249 if (prefix_length) {
2250 snprintf(tbuf, sizeof(tbuf), "/%d",
2251 prefix_length);
2252 strlcat(buf, tbuf, buflen);
2253 }
2254 }
2255 }
2256 return (buf);
2257 }
2258
2259 static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
2260 json_object *json_obj, bool use_json)
2261 {
2262 struct ospf6_as_external_lsa *external;
2263 char buf[64];
2264
2265 assert(lsa->header);
2266 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2267 lsa->header);
2268
2269 /* bits */
2270 snprintf(buf, sizeof(buf), "%c%c%c",
2271 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
2272 : '-'),
2273 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
2274 : '-'),
2275 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
2276 : '-'));
2277
2278 if (use_json) {
2279 json_object_string_add(json_obj, "bits", buf);
2280 json_object_int_add(json_obj, "metric",
2281 (unsigned long)OSPF6_ASBR_METRIC(external));
2282 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2283 buf, sizeof(buf));
2284 json_object_string_add(json_obj, "prefixOptions", buf);
2285 json_object_int_add(
2286 json_obj, "referenceLsType",
2287 ntohs(external->prefix.prefix_refer_lstype));
2288 json_object_string_add(json_obj, "prefix",
2289 ospf6_as_external_lsa_get_prefix_str(
2290 lsa, buf, sizeof(buf), 0));
2291
2292 /* Forwarding-Address */
2293 json_object_boolean_add(
2294 json_obj, "forwardingAddressPresent",
2295 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F));
2296 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
2297 json_object_string_add(
2298 json_obj, "forwardingAddress",
2299 ospf6_as_external_lsa_get_prefix_str(
2300 lsa, buf, sizeof(buf), 1));
2301
2302 /* Tag */
2303 json_object_boolean_add(
2304 json_obj, "tagPresent",
2305 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T));
2306 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
2307 json_object_int_add(json_obj, "tag",
2308 ospf6_as_external_lsa_get_tag(lsa));
2309 } else {
2310 vty_out(vty, " Bits: %s\n", buf);
2311 vty_out(vty, " Metric: %5lu\n",
2312 (unsigned long)OSPF6_ASBR_METRIC(external));
2313
2314 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2315 buf, sizeof(buf));
2316 vty_out(vty, " Prefix Options: %s\n", buf);
2317
2318 vty_out(vty, " Referenced LSType: %d\n",
2319 ntohs(external->prefix.prefix_refer_lstype));
2320
2321 vty_out(vty, " Prefix: %s\n",
2322 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
2323 sizeof(buf), 0));
2324
2325 /* Forwarding-Address */
2326 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
2327 vty_out(vty, " Forwarding-Address: %s\n",
2328 ospf6_as_external_lsa_get_prefix_str(
2329 lsa, buf, sizeof(buf), 1));
2330 }
2331
2332 /* Tag */
2333 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
2334 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
2335 ospf6_as_external_lsa_get_tag(lsa));
2336 }
2337 }
2338
2339 return 0;
2340 }
2341
2342 static void ospf6_asbr_external_route_show(struct vty *vty,
2343 struct ospf6_route *route,
2344 json_object *json_array,
2345 bool use_json)
2346 {
2347 struct ospf6_external_info *info = route->route_option;
2348 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
2349 uint32_t tmp_id;
2350 json_object *json_route;
2351 char route_type[2];
2352
2353 prefix2str(&route->prefix, prefix, sizeof(prefix));
2354 tmp_id = ntohl(info->id);
2355 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
2356 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
2357 inet_ntop(AF_INET6, &info->forwarding, forwarding,
2358 sizeof(forwarding));
2359 else
2360 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
2361 ospf6_route_get_first_nh_index(route));
2362
2363 if (use_json) {
2364 json_route = json_object_new_object();
2365 snprintf(route_type, sizeof(route_type), "%c",
2366 zebra_route_char(info->type));
2367 json_object_string_add(json_route, "routeType", route_type);
2368 json_object_string_add(json_route, "destination", prefix);
2369 json_object_string_add(json_route, "id", id);
2370 json_object_int_add(json_route, "metricType",
2371 route->path.metric_type);
2372 json_object_int_add(
2373 json_route, "routeCost",
2374 (unsigned long)(route->path.metric_type == 2
2375 ? route->path.u.cost_e2
2376 : route->path.cost));
2377 json_object_string_add(json_route, "forwarding", forwarding);
2378
2379 json_object_array_add(json_array, json_route);
2380 } else
2381
2382 vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
2383 zebra_route_char(info->type), &route->prefix, id,
2384 route->path.metric_type,
2385 (unsigned long)(route->path.metric_type == 2
2386 ? route->path.u.cost_e2
2387 : route->path.cost),
2388 forwarding);
2389 }
2390
2391 DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
2392 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2393 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2394 "All VRFs\n"
2395 "redistributing External information\n" JSON_STR)
2396 {
2397 struct ospf6_route *route;
2398 struct ospf6 *ospf6 = NULL;
2399 json_object *json = NULL;
2400 bool uj = use_json(argc, argv);
2401 struct listnode *node;
2402 const char *vrf_name = NULL;
2403 bool all_vrf = false;
2404 int idx_vrf = 0;
2405
2406 json_object *json_array_routes = NULL;
2407 json_object *json_array_redistribute = NULL;
2408
2409 OSPF6_CMD_CHECK_RUNNING();
2410 OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
2411
2412 if (uj) {
2413 json = json_object_new_object();
2414 json_array_routes = json_object_new_array();
2415 json_array_redistribute = json_object_new_array();
2416 }
2417
2418 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
2419 if (all_vrf
2420 || ((ospf6->name == NULL && vrf_name == NULL)
2421 || (ospf6->name && vrf_name
2422 && strcmp(ospf6->name, vrf_name) == 0))) {
2423 ospf6_redistribute_show_config(
2424 vty, ospf6, json_array_redistribute, json, uj);
2425
2426 for (route = ospf6_route_head(ospf6->external_table);
2427 route; route = ospf6_route_next(route)) {
2428 ospf6_asbr_external_route_show(
2429 vty, route, json_array_routes, uj);
2430 }
2431
2432 if (uj) {
2433 json_object_object_add(json, "routes",
2434 json_array_routes);
2435 vty_out(vty, "%s\n",
2436 json_object_to_json_string_ext(
2437 json, JSON_C_TO_STRING_PRETTY));
2438 json_object_free(json);
2439 }
2440
2441 if (!all_vrf)
2442 break;
2443 }
2444 }
2445
2446 return CMD_SUCCESS;
2447 }
2448
2449 static struct ospf6_lsa_handler as_external_handler = {
2450 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
2451 .lh_name = "AS-External",
2452 .lh_short_name = "ASE",
2453 .lh_show = ospf6_as_external_lsa_show,
2454 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2455 .lh_debug = 0};
2456
2457 static struct ospf6_lsa_handler nssa_external_handler = {
2458 .lh_type = OSPF6_LSTYPE_TYPE_7,
2459 .lh_name = "NSSA",
2460 .lh_short_name = "Type7",
2461 .lh_show = ospf6_as_external_lsa_show,
2462 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2463 .lh_debug = 0};
2464
2465 void ospf6_asbr_init(void)
2466 {
2467 ospf6_routemap_init();
2468
2469 ospf6_install_lsa_handler(&as_external_handler);
2470 ospf6_install_lsa_handler(&nssa_external_handler);
2471
2472 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
2473
2474 install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd);
2475 install_element(OSPF6_NODE,
2476 &no_ospf6_default_information_originate_cmd);
2477 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
2478 install_element(OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
2479 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
2480 }
2481
2482 void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6)
2483 {
2484 int type;
2485 struct ospf6_redist *red;
2486
2487 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
2488 red = ospf6_redist_lookup(ospf6, type, 0);
2489 if (!red)
2490 continue;
2491 if (type == ZEBRA_ROUTE_OSPF6)
2492 continue;
2493 ospf6_asbr_redistribute_unset(ospf6, red, type);
2494 ospf6_redist_del(ospf6, red, type);
2495 }
2496 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2497 if (red) {
2498 ospf6_asbr_routemap_unset(red);
2499 ospf6_redist_del(ospf6, red, type);
2500 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
2501 }
2502 }
2503
2504 void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
2505 {
2506 int type;
2507 struct ospf6_redist *red;
2508 char buf[RMAP_NAME_MAXLEN];
2509
2510 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
2511 buf[0] = '\0';
2512 if (type == ZEBRA_ROUTE_OSPF6)
2513 continue;
2514 red = ospf6_redist_lookup(ospf6, type, 0);
2515 if (!red)
2516 continue;
2517
2518 if (type == DEFAULT_ROUTE) {
2519 ospf6_redistribute_default_set(
2520 ospf6, ospf6->default_originate);
2521 continue;
2522 }
2523 if (ROUTEMAP_NAME(red))
2524 strlcpy(buf, ROUTEMAP_NAME(red), sizeof(buf));
2525
2526 ospf6_asbr_redistribute_unset(ospf6, red, type);
2527 if (buf[0])
2528 ospf6_asbr_routemap_set(red, buf);
2529 ospf6_asbr_redistribute_set(ospf6, type);
2530 }
2531 }
2532
2533 void ospf6_asbr_terminate(void)
2534 {
2535 /* Cleanup route maps */
2536 route_map_finish();
2537 }
2538
2539 DEFUN (debug_ospf6_asbr,
2540 debug_ospf6_asbr_cmd,
2541 "debug ospf6 asbr",
2542 DEBUG_STR
2543 OSPF6_STR
2544 "Debug OSPFv3 ASBR function\n"
2545 )
2546 {
2547 OSPF6_DEBUG_ASBR_ON();
2548 return CMD_SUCCESS;
2549 }
2550
2551 DEFUN (no_debug_ospf6_asbr,
2552 no_debug_ospf6_asbr_cmd,
2553 "no debug ospf6 asbr",
2554 NO_STR
2555 DEBUG_STR
2556 OSPF6_STR
2557 "Debug OSPFv3 ASBR function\n"
2558 )
2559 {
2560 OSPF6_DEBUG_ASBR_OFF();
2561 return CMD_SUCCESS;
2562 }
2563
2564 int config_write_ospf6_debug_asbr(struct vty *vty)
2565 {
2566 if (IS_OSPF6_DEBUG_ASBR)
2567 vty_out(vty, "debug ospf6 asbr\n");
2568 return 0;
2569 }
2570
2571 int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6)
2572 {
2573 struct ospf6_redist *red;
2574
2575 if (ospf6) {
2576 /* default-route print. */
2577 if (ospf6->default_originate != DEFAULT_ORIGINATE_NONE) {
2578 vty_out(vty, " default-information originate");
2579 if (ospf6->default_originate
2580 == DEFAULT_ORIGINATE_ALWAYS)
2581 vty_out(vty, " always");
2582
2583 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2584 if (red) {
2585 if (red->dmetric.value >= 0)
2586 vty_out(vty, " metric %d",
2587 red->dmetric.value);
2588
2589 if (red->dmetric.type >= 0)
2590 vty_out(vty, " metric-type %d",
2591 red->dmetric.type);
2592
2593 if (ROUTEMAP_NAME(red))
2594 vty_out(vty, " route-map %s",
2595 ROUTEMAP_NAME(red));
2596 }
2597
2598 vty_out(vty, "\n");
2599 }
2600 }
2601 return 0;
2602 }
2603
2604 void install_element_ospf6_debug_asbr(void)
2605 {
2606 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
2607 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
2608 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
2609 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
2610 }