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