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