]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_asbr.c
ospf6d: Fix External routes ECMP
[mirror_frr.git] / ospf6d / ospf6_asbr.c
1 /*
2 * Copyright (C) 2003 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "log.h"
24 #include "memory.h"
25 #include "prefix.h"
26 #include "command.h"
27 #include "vty.h"
28 #include "routemap.h"
29 #include "table.h"
30 #include "plist.h"
31 #include "thread.h"
32 #include "linklist.h"
33
34 #include "ospf6_proto.h"
35 #include "ospf6_lsa.h"
36 #include "ospf6_lsdb.h"
37 #include "ospf6_route.h"
38 #include "ospf6_zebra.h"
39 #include "ospf6_message.h"
40
41 #include "ospf6_top.h"
42 #include "ospf6_area.h"
43 #include "ospf6_interface.h"
44 #include "ospf6_neighbor.h"
45 #include "ospf6_asbr.h"
46 #include "ospf6_intra.h"
47 #include "ospf6_flood.h"
48 #include "ospf6d.h"
49
50 unsigned char conf_debug_ospf6_asbr = 0;
51
52 #define ZROUTE_NAME(x) zebra_route_string(x)
53
54 /* AS External LSA origination */
55 static void ospf6_as_external_lsa_originate(struct ospf6_route *route)
56 {
57 char buffer[OSPF6_MAX_LSASIZE];
58 struct ospf6_lsa_header *lsa_header;
59 struct ospf6_lsa *lsa;
60 struct ospf6_external_info *info = route->route_option;
61
62 struct ospf6_as_external_lsa *as_external_lsa;
63 char buf[PREFIX2STR_BUFFER];
64 caddr_t p;
65
66 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) {
67 prefix2str(&route->prefix, buf, sizeof(buf));
68 zlog_debug("Originate AS-External-LSA for %s", buf);
69 }
70
71 /* prepare buffer */
72 memset(buffer, 0, sizeof(buffer));
73 lsa_header = (struct ospf6_lsa_header *)buffer;
74 as_external_lsa = (struct ospf6_as_external_lsa
75 *)((caddr_t)lsa_header
76 + sizeof(struct ospf6_lsa_header));
77 p = (caddr_t)((caddr_t)as_external_lsa
78 + sizeof(struct ospf6_as_external_lsa));
79
80 /* Fill AS-External-LSA */
81 /* Metric type */
82 if (route->path.metric_type == 2)
83 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
84 else
85 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
86
87 /* forwarding address */
88 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
89 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
90 else
91 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
92
93 /* external route tag */
94 if (info->tag)
95 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
96 else
97 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
98
99 /* Set metric */
100 OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
101
102 /* prefixlen */
103 as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
104
105 /* PrefixOptions */
106 as_external_lsa->prefix.prefix_options = route->path.prefix_options;
107
108 /* don't use refer LS-type */
109 as_external_lsa->prefix.prefix_refer_lstype = htons(0);
110
111 /* set Prefix */
112 memcpy(p, &route->prefix.u.prefix6,
113 OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
114 ospf6_prefix_apply_mask(&as_external_lsa->prefix);
115 p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
116
117 /* Forwarding address */
118 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
119 memcpy(p, &info->forwarding, sizeof(struct in6_addr));
120 p += sizeof(struct in6_addr);
121 }
122
123 /* External Route Tag */
124 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
125 route_tag_t network_order = htonl(info->tag);
126
127 memcpy(p, &network_order, sizeof(network_order));
128 p += sizeof(network_order);
129 }
130
131 /* Fill LSA Header */
132 lsa_header->age = 0;
133 lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
134 lsa_header->id = route->path.origin.id;
135 lsa_header->adv_router = ospf6->router_id;
136 lsa_header->seqnum =
137 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
138 lsa_header->adv_router, ospf6->lsdb);
139 lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
140
141 /* LSA checksum */
142 ospf6_lsa_checksum(lsa_header);
143
144 /* create LSA */
145 lsa = ospf6_lsa_create(lsa_header);
146
147 /* Originate */
148 ospf6_lsa_originate_process(lsa, ospf6);
149 }
150
151 static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
152 {
153 struct ospf6_as_external_lsa *external;
154 ptrdiff_t tag_offset;
155 route_tag_t network_order;
156
157 if (!lsa)
158 return 0;
159
160 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
161 lsa->header);
162
163 if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
164 return 0;
165
166 tag_offset = sizeof(*external)
167 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
168 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
169 tag_offset += sizeof(struct in6_addr);
170
171 memcpy(&network_order, (caddr_t)external + tag_offset,
172 sizeof(network_order));
173 return ntohl(network_order);
174 }
175
176 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
177 struct ospf6_route *route)
178 {
179 struct ospf6_route *old_route;
180 struct ospf6_path *ecmp_path, *o_path = NULL;
181 struct listnode *anode;
182 struct listnode *nnode, *rnode, *rnext;
183 struct ospf6_nexthop *nh, *rnh;
184 char buf[PREFIX2STR_BUFFER];
185 bool route_found = false;
186
187 for (old_route = old; old_route; old_route = old_route->next) {
188 if (ospf6_route_is_same(old_route, route) &&
189 (old_route->path.type == route->path.type) &&
190 (old_route->path.cost == route->path.cost) &&
191 (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
192
193 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
194 prefix2str(&old_route->prefix, buf,
195 sizeof(buf));
196 zlog_debug("%s: old route %s path cost %u [%u]",
197 __PRETTY_FUNCTION__, buf,
198 old_route->path.cost,
199 ospf6_route_is_same(old_route,
200 route));
201 }
202 route_found = true;
203 /* check if this path exists already in
204 * route->paths list, if so, replace nh_list
205 * from asbr_entry.
206 */
207 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
208 o_path)) {
209 if ((o_path->origin.id == route->path.origin.id)
210 && (o_path->origin.adv_router ==
211 route->path.origin.adv_router))
212 break;
213 }
214 /* If path is not found in old_route paths's list,
215 * add a new path to route paths list and merge
216 * nexthops in route->path->nh_list.
217 * Otherwise replace existing path's nh_list.
218 */
219 if (o_path == NULL) {
220 ecmp_path = ospf6_path_dup(&route->path);
221
222 /* Add a nh_list to new ecmp path */
223 ospf6_copy_nexthops(ecmp_path->nh_list,
224 route->nh_list);
225 /* Merge nexthop to existing route's nh_list */
226 ospf6_route_merge_nexthops(old_route, route);
227
228 /* Update RIB/FIB */
229 if (ospf6->route_table->hook_add)
230 (*ospf6->route_table->hook_add)
231 (old_route);
232
233 /* Add the new path to route's path list */
234 listnode_add_sort(old_route->paths, ecmp_path);
235
236 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
237 prefix2str(&route->prefix, buf,
238 sizeof(buf));
239 zlog_debug("%s: route %s another path added with nh %u, Paths %u",
240 __PRETTY_FUNCTION__, buf,
241 listcount(ecmp_path->nh_list),
242 old_route->paths ?
243 listcount(old_route->paths)
244 : 0);
245 }
246 } else {
247 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
248 nnode, nh)) {
249 for (ALL_LIST_ELEMENTS(
250 old_route->nh_list,
251 rnode, rnext, rnh)) {
252 if (!ospf6_nexthop_is_same(rnh,
253 nh))
254 continue;
255
256 listnode_delete(
257 old_route->nh_list,
258 rnh);
259 ospf6_nexthop_delete(rnh);
260 }
261 }
262 list_delete_all_node(o_path->nh_list);
263 ospf6_copy_nexthops(o_path->nh_list,
264 route->nh_list);
265
266 /* Merge nexthop to existing route's nh_list */
267 ospf6_route_merge_nexthops(old_route,
268 route);
269
270 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
271 prefix2str(&route->prefix,
272 buf, sizeof(buf));
273 zlog_debug("%s: existing route %s with effective nh count %u",
274 __PRETTY_FUNCTION__, buf,
275 old_route->nh_list ?
276 listcount(old_route->nh_list)
277 : 0);
278 }
279
280 /* Update RIB/FIB */
281 if (ospf6->route_table->hook_add)
282 (*ospf6->route_table->hook_add)
283 (old_route);
284
285 }
286 /* Delete the new route its info added to existing
287 * route.
288 */
289 ospf6_route_delete(route);
290 break;
291 }
292 }
293
294 if (!route_found) {
295 /* Add new route to existing node in ospf6 route table. */
296 ospf6_route_add(route, ospf6->route_table);
297 }
298 }
299
300 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
301 {
302 struct ospf6_as_external_lsa *external;
303 struct prefix asbr_id;
304 struct ospf6_route *asbr_entry, *route, *old;
305 struct ospf6_path *path;
306 char buf[PREFIX2STR_BUFFER];
307
308 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
309 lsa->header);
310
311 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
312 zlog_debug("Calculate AS-External route for %s", lsa->name);
313
314 if (lsa->header->adv_router == ospf6->router_id) {
315 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
316 zlog_debug("Ignore self-originated AS-External-LSA");
317 return;
318 }
319
320 if (OSPF6_ASBR_METRIC(external) == OSPF_LS_INFINITY) {
321 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
322 zlog_debug("Ignore LSA with LSInfinity Metric");
323 return;
324 }
325
326 if (CHECK_FLAG(external->prefix.prefix_options,
327 OSPF6_PREFIX_OPTION_NU)) {
328 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
329 zlog_debug("Ignore LSA with NU bit set Metric");
330 return;
331 }
332
333 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
334 asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
335 if (asbr_entry == NULL
336 || !CHECK_FLAG(asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) {
337 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
338 prefix2str(&asbr_id, buf, sizeof(buf));
339 zlog_debug("ASBR entry not found: %s", buf);
340 }
341 return;
342 }
343
344 route = ospf6_route_create();
345 route->type = OSPF6_DEST_TYPE_NETWORK;
346 route->prefix.family = AF_INET6;
347 route->prefix.prefixlen = external->prefix.prefix_length;
348 ospf6_prefix_in6_addr(&route->prefix.u.prefix6, &external->prefix);
349
350 route->path.area_id = asbr_entry->path.area_id;
351 route->path.origin.type = lsa->header->type;
352 route->path.origin.id = lsa->header->id;
353 route->path.origin.adv_router = lsa->header->adv_router;
354
355 route->path.prefix_options = external->prefix.prefix_options;
356 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
357 route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
358 route->path.metric_type = 2;
359 route->path.cost = asbr_entry->path.cost;
360 route->path.u.cost_e2 = OSPF6_ASBR_METRIC(external);
361 } else {
362 route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
363 route->path.metric_type = 1;
364 route->path.cost =
365 asbr_entry->path.cost + OSPF6_ASBR_METRIC(external);
366 route->path.u.cost_e2 = 0;
367 }
368
369 route->path.tag = ospf6_as_external_lsa_get_tag(lsa);
370
371 ospf6_route_copy_nexthops(route, asbr_entry);
372
373 path = ospf6_path_dup(&route->path);
374 ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
375 listnode_add_sort(route->paths, path);
376
377
378 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
379 prefix2str(&route->prefix, buf, sizeof(buf));
380 zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
381 __PRETTY_FUNCTION__,
382 (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1)
383 ? 1 : 2, buf, route->path.cost,
384 route->path.u.cost_e2,
385 listcount(route->nh_list));
386 }
387
388 old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
389 if (!old) {
390 /* Add the new route to ospf6 instance route table. */
391 ospf6_route_add(route, ospf6->route_table);
392 } else {
393 /* RFC 2328 16.4 (6)
394 * ECMP: Keep new equal preference path in current
395 * route's path list, update zebra with new effective
396 * list along with addition of ECMP path.
397 */
398 ospf6_asbr_update_route_ecmp_path(old, route);
399 }
400
401 }
402
403 void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
404 {
405 struct ospf6_as_external_lsa *external;
406 struct prefix prefix;
407 struct ospf6_route *route, *nroute;
408 char buf[PREFIX2STR_BUFFER];
409
410 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
411 lsa->header);
412
413 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
414 zlog_debug("Withdraw AS-External route for %s", lsa->name);
415
416 if (lsa->header->adv_router == ospf6->router_id) {
417 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
418 zlog_debug("Ignore self-originated AS-External-LSA");
419 return;
420 }
421
422 memset(&prefix, 0, sizeof(struct prefix));
423 prefix.family = AF_INET6;
424 prefix.prefixlen = external->prefix.prefix_length;
425 ospf6_prefix_in6_addr(&prefix.u.prefix6, &external->prefix);
426
427 route = ospf6_route_lookup(&prefix, ospf6->route_table);
428 if (route == NULL) {
429 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
430 prefix2str(&prefix, buf, sizeof(buf));
431 zlog_debug("AS-External route %s not found", buf);
432 }
433 return;
434 }
435
436 for (ospf6_route_lock(route);
437 route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
438 nroute = ospf6_route_next(route);
439 if (route->type != OSPF6_DEST_TYPE_NETWORK)
440 continue;
441
442 /* Route has multiple ECMP paths remove,
443 * matching path and update effective route's nh list.
444 */
445 if (listcount(route->paths) > 1) {
446 struct listnode *anode, *anext;
447 struct listnode *nnode, *rnode, *rnext;
448 struct ospf6_nexthop *nh, *rnh;
449 struct ospf6_path *o_path;
450 bool nh_updated = false;
451
452 /* Iterate all paths of route to find maching with LSA
453 * remove from route path list. If route->path is same,
454 * replace from paths list.
455 */
456 for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
457 o_path)) {
458 if (o_path->origin.type != lsa->header->type)
459 continue;
460 if (o_path->origin.id != lsa->header->id)
461 continue;
462 if (o_path->origin.adv_router !=
463 lsa->header->adv_router)
464 continue;
465
466 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
467 prefix2str(&prefix, buf, sizeof(buf));
468 zlog_debug(
469 "%s: route %s path found with nh %u",
470 __PRETTY_FUNCTION__, buf,
471 listcount(o_path->nh_list));
472 }
473
474 /* Remove found path's nh_list from
475 * the route's nh_list.
476 */
477 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
478 nnode, nh)) {
479 for (ALL_LIST_ELEMENTS(route->nh_list,
480 rnode, rnext, rnh)) {
481 if (!ospf6_nexthop_is_same(rnh,
482 nh))
483 continue;
484 listnode_delete(route->nh_list,
485 rnh);
486 ospf6_nexthop_delete(rnh);
487 }
488 }
489 /* Delete the path from route's path list */
490 listnode_delete(route->paths, o_path);
491 ospf6_path_free(o_path);
492 nh_updated = true;
493 }
494
495 if (nh_updated) {
496 /* Iterate all paths and merge nexthop,
497 * unlesss any of the nexthop similar to
498 * ones deleted as part of path deletion.
499 */
500
501 for (ALL_LIST_ELEMENTS(route->paths, anode,
502 anext, o_path)) {
503 ospf6_merge_nexthops(route->nh_list,
504 o_path->nh_list);
505 }
506
507 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
508 prefix2str(&route->prefix, buf,
509 sizeof(buf));
510 zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
511 , __PRETTY_FUNCTION__,
512 (route->path.type ==
513 OSPF6_PATH_TYPE_EXTERNAL1)
514 ? 1 : 2, buf,
515 listcount(route->paths),
516 listcount(route->nh_list));
517 }
518
519 /* Update RIB/FIB w/ effective nh_list */
520 if (ospf6->route_table->hook_add)
521 (*ospf6->route_table->hook_add)(route);
522
523 /* route's path is similar to lsa header,
524 * replace route's path with route's
525 * paths list head.
526 */
527 if (route->path.origin.id == lsa->header->id &&
528 route->path.origin.adv_router ==
529 lsa->header->adv_router) {
530 struct ospf6_path *h_path;
531
532 h_path = (struct ospf6_path *)
533 listgetdata(listhead(route->paths));
534 route->path.origin.type =
535 h_path->origin.type;
536 route->path.origin.id =
537 h_path->origin.id;
538 route->path.origin.adv_router =
539 h_path->origin.adv_router;
540 }
541 }
542 continue;
543
544 } else {
545 if (route->path.origin.type != lsa->header->type)
546 continue;
547 if (route->path.origin.id != lsa->header->id)
548 continue;
549 if (route->path.origin.adv_router !=
550 lsa->header->adv_router)
551 continue;
552 }
553 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
554 prefix2str(&route->prefix, buf, sizeof(buf));
555 zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
556 __PRETTY_FUNCTION__,
557 route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
558 ? 1 : 2, buf, route->path.cost,
559 route->path.u.cost_e2,
560 listcount(route->nh_list));
561 }
562 ospf6_route_remove(route, ospf6->route_table);
563 }
564 if (route != NULL)
565 ospf6_route_unlock(route);
566 }
567
568 void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry)
569 {
570 struct ospf6_lsa *lsa;
571 u_int16_t type;
572 u_int32_t router;
573
574 if (!CHECK_FLAG(asbr_entry->flag, OSPF6_ROUTE_BEST)) {
575 char buf[16];
576 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&asbr_entry->prefix),
577 buf, sizeof(buf));
578 zlog_info("ignore non-best path: lsentry %s add", buf);
579 return;
580 }
581
582 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
583 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
584 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
585 if (!OSPF6_LSA_IS_MAXAGE(lsa))
586 ospf6_asbr_lsa_add(lsa);
587 }
588 }
589
590 void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry)
591 {
592 struct ospf6_lsa *lsa;
593 u_int16_t type;
594 u_int32_t router;
595
596 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
597 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
598 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
599 ospf6_asbr_lsa_remove(lsa);
600 }
601
602
603 /* redistribute function */
604
605 static void ospf6_asbr_routemap_set(int type, const char *mapname)
606 {
607 if (ospf6->rmap[type].name)
608 free(ospf6->rmap[type].name);
609 ospf6->rmap[type].name = strdup(mapname);
610 ospf6->rmap[type].map = route_map_lookup_by_name(mapname);
611 }
612
613 static void ospf6_asbr_routemap_unset(int type)
614 {
615 if (ospf6->rmap[type].name)
616 free(ospf6->rmap[type].name);
617 ospf6->rmap[type].name = NULL;
618 ospf6->rmap[type].map = NULL;
619 }
620
621 static void ospf6_asbr_routemap_update(const char *mapname)
622 {
623 int type;
624
625 if (ospf6 == NULL)
626 return;
627
628 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
629 if (ospf6->rmap[type].name) {
630 ospf6->rmap[type].map = route_map_lookup_by_name(
631 ospf6->rmap[type].name);
632
633 if (mapname && ospf6->rmap[type].map &&
634 (strcmp(ospf6->rmap[type].name, mapname) == 0)) {
635 if (IS_OSPF6_DEBUG_ASBR)
636 zlog_debug("%s: route-map %s update, reset redist %s",
637 __PRETTY_FUNCTION__, mapname,
638 ZROUTE_NAME(type));
639
640 ospf6_zebra_no_redistribute(type);
641 ospf6_zebra_redistribute(type);
642 }
643 } else
644 ospf6->rmap[type].map = NULL;
645 }
646 }
647
648 int ospf6_asbr_is_asbr(struct ospf6 *o)
649 {
650 return o->external_table->count;
651 }
652
653 static void ospf6_asbr_redistribute_set(int type)
654 {
655 ospf6_zebra_redistribute(type);
656 }
657
658 static void ospf6_asbr_redistribute_unset(int type)
659 {
660 struct ospf6_route *route;
661 struct ospf6_external_info *info;
662
663 ospf6_zebra_no_redistribute(type);
664
665 for (route = ospf6_route_head(ospf6->external_table); route;
666 route = ospf6_route_next(route)) {
667 info = route->route_option;
668 if (info->type != type)
669 continue;
670
671 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix);
672 }
673
674 ospf6_asbr_routemap_unset(type);
675 }
676
677 /* When an area is unstubified, flood all the external LSAs in the area */
678 void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
679 {
680 struct ospf6_lsa *lsa;
681
682 for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
683 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
684 zlog_debug("%s: Flooding AS-External LSA %s\n",
685 __func__, lsa->name);
686 ospf6_flood_area(NULL, lsa, oa);
687 }
688 }
689 }
690
691 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
692 struct prefix *prefix, u_int nexthop_num,
693 struct in6_addr *nexthop, route_tag_t tag)
694 {
695 int ret;
696 struct ospf6_route troute;
697 struct ospf6_external_info tinfo;
698 struct ospf6_route *route, *match;
699 struct ospf6_external_info *info;
700 struct prefix prefix_id;
701 struct route_node *node;
702 char pbuf[PREFIX2STR_BUFFER], ibuf[16];
703 struct listnode *lnode, *lnnode;
704 struct ospf6_area *oa;
705
706 if (!ospf6_zebra_is_redistribute(type))
707 return;
708
709 memset(&troute, 0, sizeof(troute));
710 memset(&tinfo, 0, sizeof(tinfo));
711
712 if (IS_OSPF6_DEBUG_ASBR) {
713 prefix2str(prefix, pbuf, sizeof(pbuf));
714 zlog_debug("Redistribute %s (%s)", pbuf, ZROUTE_NAME(type));
715 }
716
717 /* if route-map was specified but not found, do not advertise */
718 if (ospf6->rmap[type].name) {
719 if (ospf6->rmap[type].map == NULL)
720 ospf6_asbr_routemap_update(NULL);
721 if (ospf6->rmap[type].map == NULL) {
722 zlog_warn(
723 "route-map \"%s\" not found, suppress redistributing",
724 ospf6->rmap[type].name);
725 return;
726 }
727 }
728
729 /* apply route-map */
730 if (ospf6->rmap[type].map) {
731 troute.route_option = &tinfo;
732 tinfo.ifindex = ifindex;
733 tinfo.tag = tag;
734
735 ret = route_map_apply(ospf6->rmap[type].map, prefix, RMAP_OSPF6,
736 &troute);
737 if (ret == RMAP_DENYMATCH) {
738 if (IS_OSPF6_DEBUG_ASBR)
739 zlog_debug("Denied by route-map \"%s\"",
740 ospf6->rmap[type].name);
741 return;
742 }
743 }
744
745 match = ospf6_route_lookup(prefix, ospf6->external_table);
746 if (match) {
747 info = match->route_option;
748
749 /* copy result of route-map */
750 if (ospf6->rmap[type].map) {
751 if (troute.path.metric_type)
752 match->path.metric_type =
753 troute.path.metric_type;
754 if (troute.path.cost)
755 match->path.cost = troute.path.cost;
756 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
757 memcpy(&info->forwarding, &tinfo.forwarding,
758 sizeof(struct in6_addr));
759 info->tag = tinfo.tag;
760 } else {
761 /* If there is no route-map, simply update the tag */
762 info->tag = tag;
763 }
764
765 info->type = type;
766
767 if (nexthop_num && nexthop)
768 ospf6_route_add_nexthop(match, ifindex, nexthop);
769 else
770 ospf6_route_add_nexthop(match, ifindex, NULL);
771
772 /* create/update binding in external_id_table */
773 prefix_id.family = AF_INET;
774 prefix_id.prefixlen = 32;
775 prefix_id.u.prefix4.s_addr = htonl(info->id);
776 node = route_node_get(ospf6->external_id_table, &prefix_id);
777 node->info = match;
778
779 if (IS_OSPF6_DEBUG_ASBR) {
780 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf,
781 sizeof(ibuf));
782 zlog_debug("Advertise as AS-External Id:%s", ibuf);
783 }
784
785 match->path.origin.id = htonl(info->id);
786 ospf6_as_external_lsa_originate(match);
787 return;
788 }
789
790 /* create new entry */
791 route = ospf6_route_create();
792 route->type = OSPF6_DEST_TYPE_NETWORK;
793 memcpy(&route->prefix, prefix, sizeof(struct prefix));
794
795 info = (struct ospf6_external_info *)XCALLOC(
796 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
797 route->route_option = info;
798 info->id = ospf6->external_id++;
799
800 /* copy result of route-map */
801 if (ospf6->rmap[type].map) {
802 if (troute.path.metric_type)
803 route->path.metric_type = troute.path.metric_type;
804 if (troute.path.cost)
805 route->path.cost = troute.path.cost;
806 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
807 memcpy(&info->forwarding, &tinfo.forwarding,
808 sizeof(struct in6_addr));
809 info->tag = tinfo.tag;
810 } else {
811 /* If there is no route-map, simply set the tag */
812 info->tag = tag;
813 }
814
815 info->type = type;
816 if (nexthop_num && nexthop)
817 ospf6_route_add_nexthop(route, ifindex, nexthop);
818 else
819 ospf6_route_add_nexthop(route, ifindex, NULL);
820
821 /* create/update binding in external_id_table */
822 prefix_id.family = AF_INET;
823 prefix_id.prefixlen = 32;
824 prefix_id.u.prefix4.s_addr = htonl(info->id);
825 node = route_node_get(ospf6->external_id_table, &prefix_id);
826 node->info = route;
827
828 route = ospf6_route_add(route, ospf6->external_table);
829 route->route_option = info;
830
831 if (IS_OSPF6_DEBUG_ASBR) {
832 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
833 zlog_debug("Advertise as AS-External Id:%s", ibuf);
834 }
835
836 route->path.origin.id = htonl(info->id);
837 ospf6_as_external_lsa_originate(route);
838
839 /* Router-Bit (ASBR Flag) may have to be updated */
840 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
841 OSPF6_ROUTER_LSA_SCHEDULE(oa);
842 }
843
844 void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
845 struct prefix *prefix)
846 {
847 struct ospf6_route *match;
848 struct ospf6_external_info *info = NULL;
849 struct route_node *node;
850 struct ospf6_lsa *lsa;
851 struct prefix prefix_id;
852 char pbuf[PREFIX2STR_BUFFER], ibuf[16];
853 struct listnode *lnode, *lnnode;
854 struct ospf6_area *oa;
855
856 match = ospf6_route_lookup(prefix, ospf6->external_table);
857 if (match == NULL) {
858 if (IS_OSPF6_DEBUG_ASBR) {
859 prefix2str(prefix, pbuf, sizeof(pbuf));
860 zlog_debug("No such route %s to withdraw", pbuf);
861 }
862 return;
863 }
864
865 info = match->route_option;
866 assert(info);
867
868 if (info->type != type) {
869 if (IS_OSPF6_DEBUG_ASBR) {
870 prefix2str(prefix, pbuf, sizeof(pbuf));
871 zlog_debug("Original protocol mismatch: %s", pbuf);
872 }
873 return;
874 }
875
876 if (IS_OSPF6_DEBUG_ASBR) {
877 prefix2str(prefix, pbuf, sizeof(pbuf));
878 inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
879 zlog_debug("Withdraw %s (AS-External Id:%s)", pbuf, ibuf);
880 }
881
882 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
883 htonl(info->id), ospf6->router_id, ospf6->lsdb);
884 if (lsa)
885 ospf6_lsa_purge(lsa);
886
887 /* remove binding in external_id_table */
888 prefix_id.family = AF_INET;
889 prefix_id.prefixlen = 32;
890 prefix_id.u.prefix4.s_addr = htonl(info->id);
891 node = route_node_lookup(ospf6->external_id_table, &prefix_id);
892 assert(node);
893 node->info = NULL;
894 route_unlock_node(node); /* to free the lookup lock */
895 route_unlock_node(node); /* to free the original lock */
896
897 ospf6_route_remove(match, ospf6->external_table);
898 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
899
900 /* Router-Bit (ASBR Flag) may have to be updated */
901 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
902 OSPF6_ROUTER_LSA_SCHEDULE(oa);
903 }
904
905 DEFUN (ospf6_redistribute,
906 ospf6_redistribute_cmd,
907 "redistribute " FRR_REDIST_STR_OSPF6D,
908 "Redistribute\n"
909 FRR_REDIST_HELP_STR_OSPF6D)
910 {
911 int type;
912
913 char *proto = argv[argc - 1]->text;
914 type = proto_redistnum(AFI_IP6, proto);
915 if (type < 0)
916 return CMD_WARNING_CONFIG_FAILED;
917
918 ospf6_asbr_redistribute_unset(type);
919 ospf6_asbr_redistribute_set(type);
920 return CMD_SUCCESS;
921 }
922
923 DEFUN (ospf6_redistribute_routemap,
924 ospf6_redistribute_routemap_cmd,
925 "redistribute " FRR_REDIST_STR_OSPF6D " route-map WORD",
926 "Redistribute\n"
927 FRR_REDIST_HELP_STR_OSPF6D
928 "Route map reference\n"
929 "Route map name\n")
930 {
931 int idx_protocol = 1;
932 int idx_word = 3;
933 int type;
934
935 char *proto = argv[idx_protocol]->text;
936 type = proto_redistnum(AFI_IP6, proto);
937 if (type < 0)
938 return CMD_WARNING_CONFIG_FAILED;
939
940 ospf6_asbr_redistribute_unset(type);
941 ospf6_asbr_routemap_set(type, argv[idx_word]->arg);
942 ospf6_asbr_redistribute_set(type);
943 return CMD_SUCCESS;
944 }
945
946 DEFUN (no_ospf6_redistribute,
947 no_ospf6_redistribute_cmd,
948 "no redistribute " FRR_REDIST_STR_OSPF6D " [route-map WORD]",
949 NO_STR
950 "Redistribute\n"
951 FRR_REDIST_HELP_STR_OSPF6D
952 "Route map reference\n"
953 "Route map name\n")
954 {
955 int idx_protocol = 2;
956 int type;
957
958 char *proto = argv[idx_protocol]->text;
959 type = proto_redistnum(AFI_IP6, proto);
960 if (type < 0)
961 return CMD_WARNING_CONFIG_FAILED;
962
963 ospf6_asbr_redistribute_unset(type);
964
965 return CMD_SUCCESS;
966 }
967
968 int ospf6_redistribute_config_write(struct vty *vty)
969 {
970 int type;
971
972 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
973 if (type == ZEBRA_ROUTE_OSPF6)
974 continue;
975 if (!ospf6_zebra_is_redistribute(type))
976 continue;
977
978 if (ospf6->rmap[type].name)
979 vty_out(vty, " redistribute %s route-map %s\n",
980 ZROUTE_NAME(type), ospf6->rmap[type].name);
981 else
982 vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type));
983 }
984
985 return 0;
986 }
987
988 static void ospf6_redistribute_show_config(struct vty *vty)
989 {
990 int type;
991 int nroute[ZEBRA_ROUTE_MAX];
992 int total;
993 struct ospf6_route *route;
994 struct ospf6_external_info *info;
995
996 total = 0;
997 for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
998 nroute[type] = 0;
999 for (route = ospf6_route_head(ospf6->external_table); route;
1000 route = ospf6_route_next(route)) {
1001 info = route->route_option;
1002 nroute[info->type]++;
1003 total++;
1004 }
1005
1006 vty_out(vty, "Redistributing External Routes from:\n");
1007 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1008 if (type == ZEBRA_ROUTE_OSPF6)
1009 continue;
1010 if (!ospf6_zebra_is_redistribute(type))
1011 continue;
1012
1013 if (ospf6->rmap[type].name)
1014 vty_out(vty, " %d: %s with route-map \"%s\"%s\n",
1015 nroute[type], ZROUTE_NAME(type),
1016 ospf6->rmap[type].name,
1017 (ospf6->rmap[type].map ? ""
1018 : " (not found !)"));
1019 else
1020 vty_out(vty, " %d: %s\n", nroute[type],
1021 ZROUTE_NAME(type));
1022 }
1023 vty_out(vty, "Total %d routes\n", total);
1024 }
1025
1026
1027 /* Routemap Functions */
1028 static route_map_result_t
1029 ospf6_routemap_rule_match_address_prefixlist(void *rule, struct prefix *prefix,
1030 route_map_object_t type,
1031 void *object)
1032 {
1033 struct prefix_list *plist;
1034
1035 if (type != RMAP_OSPF6)
1036 return RMAP_NOMATCH;
1037
1038 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1039 if (plist == NULL)
1040 return RMAP_NOMATCH;
1041
1042 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1043 : RMAP_MATCH);
1044 }
1045
1046 static void *
1047 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
1048 {
1049 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1050 }
1051
1052 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
1053 {
1054 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1055 }
1056
1057 struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = {
1058 "ipv6 address prefix-list",
1059 ospf6_routemap_rule_match_address_prefixlist,
1060 ospf6_routemap_rule_match_address_prefixlist_compile,
1061 ospf6_routemap_rule_match_address_prefixlist_free,
1062 };
1063
1064 /* `match interface IFNAME' */
1065 /* Match function should return 1 if match is success else return
1066 zero. */
1067 static route_map_result_t
1068 ospf6_routemap_rule_match_interface(void *rule, struct prefix *prefix,
1069 route_map_object_t type, void *object)
1070 {
1071 struct interface *ifp;
1072 struct ospf6_external_info *ei;
1073
1074 if (type == RMAP_OSPF6) {
1075 ei = ((struct ospf6_route *)object)->route_option;
1076 ifp = if_lookup_by_name((char *)rule, VRF_DEFAULT);
1077
1078 if (ifp != NULL && ei->ifindex == ifp->ifindex)
1079 return RMAP_MATCH;
1080 }
1081
1082 return RMAP_NOMATCH;
1083 }
1084
1085 /* Route map `interface' match statement. `arg' should be
1086 interface name. */
1087 static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
1088 {
1089 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1090 }
1091
1092 /* Free route map's compiled `interface' value. */
1093 static void ospf6_routemap_rule_match_interface_free(void *rule)
1094 {
1095 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1096 }
1097
1098 /* Route map commands for interface matching. */
1099 struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = {
1100 "interface", ospf6_routemap_rule_match_interface,
1101 ospf6_routemap_rule_match_interface_compile,
1102 ospf6_routemap_rule_match_interface_free};
1103
1104 /* Match function for matching route tags */
1105 static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
1106 struct prefix *prefix,
1107 route_map_object_t type,
1108 void *object)
1109 {
1110 route_tag_t *tag = rule;
1111 struct ospf6_route *route = object;
1112 struct ospf6_external_info *info = route->route_option;
1113
1114 if (type == RMAP_OSPF6 && info->tag == *tag)
1115 return RMAP_MATCH;
1116
1117 return RMAP_NOMATCH;
1118 }
1119
1120 static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = {
1121 "tag", ospf6_routemap_rule_match_tag, route_map_rule_tag_compile,
1122 route_map_rule_tag_free,
1123 };
1124
1125 static route_map_result_t
1126 ospf6_routemap_rule_set_metric_type(void *rule, struct prefix *prefix,
1127 route_map_object_t type, void *object)
1128 {
1129 char *metric_type = rule;
1130 struct ospf6_route *route = object;
1131
1132 if (type != RMAP_OSPF6)
1133 return RMAP_OKAY;
1134
1135 if (strcmp(metric_type, "type-2") == 0)
1136 route->path.metric_type = 2;
1137 else
1138 route->path.metric_type = 1;
1139
1140 return RMAP_OKAY;
1141 }
1142
1143 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
1144 {
1145 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
1146 return NULL;
1147 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1148 }
1149
1150 static void ospf6_routemap_rule_set_metric_type_free(void *rule)
1151 {
1152 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1153 }
1154
1155 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = {
1156 "metric-type", ospf6_routemap_rule_set_metric_type,
1157 ospf6_routemap_rule_set_metric_type_compile,
1158 ospf6_routemap_rule_set_metric_type_free,
1159 };
1160
1161 static route_map_result_t
1162 ospf6_routemap_rule_set_metric(void *rule, struct prefix *prefix,
1163 route_map_object_t type, void *object)
1164 {
1165 char *metric = rule;
1166 struct ospf6_route *route = object;
1167
1168 if (type != RMAP_OSPF6)
1169 return RMAP_OKAY;
1170
1171 route->path.cost = atoi(metric);
1172 return RMAP_OKAY;
1173 }
1174
1175 static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
1176 {
1177 u_int32_t metric;
1178 char *endp;
1179 metric = strtoul(arg, &endp, 0);
1180 if (metric > OSPF_LS_INFINITY || *endp != '\0')
1181 return NULL;
1182 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1183 }
1184
1185 static void ospf6_routemap_rule_set_metric_free(void *rule)
1186 {
1187 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1188 }
1189
1190 struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = {
1191 "metric", ospf6_routemap_rule_set_metric,
1192 ospf6_routemap_rule_set_metric_compile,
1193 ospf6_routemap_rule_set_metric_free,
1194 };
1195
1196 static route_map_result_t
1197 ospf6_routemap_rule_set_forwarding(void *rule, struct prefix *prefix,
1198 route_map_object_t type, void *object)
1199 {
1200 char *forwarding = rule;
1201 struct ospf6_route *route = object;
1202 struct ospf6_external_info *info = route->route_option;
1203
1204 if (type != RMAP_OSPF6)
1205 return RMAP_OKAY;
1206
1207 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
1208 memset(&info->forwarding, 0, sizeof(struct in6_addr));
1209 return RMAP_ERROR;
1210 }
1211
1212 return RMAP_OKAY;
1213 }
1214
1215 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
1216 {
1217 struct in6_addr a;
1218 if (inet_pton(AF_INET6, arg, &a) != 1)
1219 return NULL;
1220 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
1221 }
1222
1223 static void ospf6_routemap_rule_set_forwarding_free(void *rule)
1224 {
1225 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
1226 }
1227
1228 struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = {
1229 "forwarding-address", ospf6_routemap_rule_set_forwarding,
1230 ospf6_routemap_rule_set_forwarding_compile,
1231 ospf6_routemap_rule_set_forwarding_free,
1232 };
1233
1234 static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
1235 struct prefix *prefix,
1236 route_map_object_t type,
1237 void *object)
1238 {
1239 route_tag_t *tag = rule;
1240 struct ospf6_route *route = object;
1241 struct ospf6_external_info *info = route->route_option;
1242
1243 if (type != RMAP_OSPF6)
1244 return RMAP_OKAY;
1245
1246 info->tag = *tag;
1247 return RMAP_OKAY;
1248 }
1249
1250 static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
1251 "tag", ospf6_routemap_rule_set_tag, route_map_rule_tag_compile,
1252 route_map_rule_tag_free,
1253 };
1254
1255 static int route_map_command_status(struct vty *vty, int ret)
1256 {
1257 switch (ret) {
1258 case RMAP_RULE_MISSING:
1259 vty_out(vty, "OSPF6 Can't find rule.\n");
1260 return CMD_WARNING_CONFIG_FAILED;
1261 break;
1262 case RMAP_COMPILE_ERROR:
1263 vty_out(vty, "OSPF6 Argument is malformed.\n");
1264 return CMD_WARNING_CONFIG_FAILED;
1265 break;
1266 case RMAP_COMPILE_SUCCESS:
1267 break;
1268 }
1269
1270 return CMD_SUCCESS;
1271 }
1272
1273 /* add "set metric-type" */
1274 DEFUN (ospf6_routemap_set_metric_type,
1275 ospf6_routemap_set_metric_type_cmd,
1276 "set metric-type <type-1|type-2>",
1277 "Set value\n"
1278 "Type of metric\n"
1279 "OSPF6 external type 1 metric\n"
1280 "OSPF6 external type 2 metric\n")
1281 {
1282 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1283 int idx_external = 2;
1284 int ret = route_map_add_set(route_map_index, "metric-type",
1285 argv[idx_external]->arg);
1286 return route_map_command_status(vty, ret);
1287 }
1288
1289 /* delete "set metric-type" */
1290 DEFUN (ospf6_routemap_no_set_metric_type,
1291 ospf6_routemap_no_set_metric_type_cmd,
1292 "no set metric-type [<type-1|type-2>]",
1293 NO_STR
1294 "Set value\n"
1295 "Type of metric\n"
1296 "OSPF6 external type 1 metric\n"
1297 "OSPF6 external type 2 metric\n")
1298 {
1299 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1300 char *ext = (argc == 4) ? argv[3]->text : NULL;
1301 int ret = route_map_delete_set(route_map_index, "metric-type", ext);
1302 return route_map_command_status(vty, ret);
1303 }
1304
1305 /* add "set forwarding-address" */
1306 DEFUN (ospf6_routemap_set_forwarding,
1307 ospf6_routemap_set_forwarding_cmd,
1308 "set forwarding-address X:X::X:X",
1309 "Set value\n"
1310 "Forwarding Address\n"
1311 "IPv6 Address\n")
1312 {
1313 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1314 int idx_ipv6 = 2;
1315 int ret = route_map_add_set(route_map_index, "forwarding-address",
1316 argv[idx_ipv6]->arg);
1317 return route_map_command_status(vty, ret);
1318 }
1319
1320 /* delete "set forwarding-address" */
1321 DEFUN (ospf6_routemap_no_set_forwarding,
1322 ospf6_routemap_no_set_forwarding_cmd,
1323 "no set forwarding-address X:X::X:X",
1324 NO_STR
1325 "Set value\n"
1326 "Forwarding Address\n"
1327 "IPv6 Address\n")
1328 {
1329 VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
1330 int idx_ipv6 = 3;
1331 int ret = route_map_delete_set(route_map_index, "forwarding-address",
1332 argv[idx_ipv6]->arg);
1333 return route_map_command_status(vty, ret);
1334 }
1335
1336 static void ospf6_routemap_init(void)
1337 {
1338 route_map_init();
1339
1340 route_map_add_hook(ospf6_asbr_routemap_update);
1341 route_map_delete_hook(ospf6_asbr_routemap_update);
1342
1343 route_map_set_metric_hook(generic_set_add);
1344 route_map_no_set_metric_hook(generic_set_delete);
1345
1346 route_map_match_tag_hook(generic_match_add);
1347 route_map_no_match_tag_hook(generic_match_delete);
1348
1349 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
1350 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
1351
1352 route_map_match_interface_hook(generic_match_add);
1353 route_map_no_match_interface_hook(generic_match_delete);
1354
1355 route_map_install_match(
1356 &ospf6_routemap_rule_match_address_prefixlist_cmd);
1357 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
1358 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
1359
1360 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
1361 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
1362 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
1363 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
1364
1365 /* ASE Metric Type (e.g. Type-1/Type-2) */
1366 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
1367 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
1368
1369 /* ASE Metric */
1370 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
1371 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
1372 }
1373
1374
1375 /* Display functions */
1376 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
1377 char *buf, int buflen,
1378 int pos)
1379 {
1380 struct ospf6_as_external_lsa *external;
1381 struct in6_addr in6;
1382 int prefix_length = 0;
1383
1384 if (lsa) {
1385 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
1386 lsa->header);
1387
1388 if (pos == 0) {
1389 ospf6_prefix_in6_addr(&in6, &external->prefix);
1390 prefix_length = external->prefix.prefix_length;
1391 } else {
1392 in6 = *((struct in6_addr
1393 *)((caddr_t)external
1394 + sizeof(struct
1395 ospf6_as_external_lsa)
1396 + OSPF6_PREFIX_SPACE(
1397 external->prefix
1398 .prefix_length)));
1399 }
1400 if (buf) {
1401 inet_ntop(AF_INET6, &in6, buf, buflen);
1402 if (prefix_length)
1403 sprintf(&buf[strlen(buf)], "/%d",
1404 prefix_length);
1405 }
1406 }
1407 return (buf);
1408 }
1409
1410 static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)
1411 {
1412 struct ospf6_as_external_lsa *external;
1413 char buf[64];
1414
1415 assert(lsa->header);
1416 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
1417 lsa->header);
1418
1419 /* bits */
1420 snprintf(buf, sizeof(buf), "%c%c%c",
1421 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
1422 : '-'),
1423 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
1424 : '-'),
1425 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
1426 : '-'));
1427
1428 vty_out(vty, " Bits: %s\n", buf);
1429 vty_out(vty, " Metric: %5lu\n",
1430 (u_long)OSPF6_ASBR_METRIC(external));
1431
1432 ospf6_prefix_options_printbuf(external->prefix.prefix_options, buf,
1433 sizeof(buf));
1434 vty_out(vty, " Prefix Options: %s\n", buf);
1435
1436 vty_out(vty, " Referenced LSType: %d\n",
1437 ntohs(external->prefix.prefix_refer_lstype));
1438
1439 vty_out(vty, " Prefix: %s\n",
1440 ospf6_as_external_lsa_get_prefix_str(lsa, buf, sizeof(buf), 0));
1441
1442 /* Forwarding-Address */
1443 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
1444 vty_out(vty, " Forwarding-Address: %s\n",
1445 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
1446 sizeof(buf), 1));
1447 }
1448
1449 /* Tag */
1450 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
1451 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
1452 ospf6_as_external_lsa_get_tag(lsa));
1453 }
1454
1455 return 0;
1456 }
1457
1458 static void ospf6_asbr_external_route_show(struct vty *vty,
1459 struct ospf6_route *route)
1460 {
1461 struct ospf6_external_info *info = route->route_option;
1462 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
1463 u_int32_t tmp_id;
1464
1465 prefix2str(&route->prefix, prefix, sizeof(prefix));
1466 tmp_id = ntohl(info->id);
1467 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
1468 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
1469 inet_ntop(AF_INET6, &info->forwarding, forwarding,
1470 sizeof(forwarding));
1471 else
1472 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
1473 ospf6_route_get_first_nh_index(route));
1474
1475 vty_out(vty, "%c %-32s %-15s type-%d %5lu %s\n",
1476 zebra_route_char(info->type), prefix, id,
1477 route->path.metric_type,
1478 (u_long)(route->path.metric_type == 2 ? route->path.u.cost_e2
1479 : route->path.cost),
1480 forwarding);
1481 }
1482
1483 DEFUN (show_ipv6_ospf6_redistribute,
1484 show_ipv6_ospf6_redistribute_cmd,
1485 "show ipv6 ospf6 redistribute",
1486 SHOW_STR
1487 IP6_STR
1488 OSPF6_STR
1489 "redistributing External information\n"
1490 )
1491 {
1492 struct ospf6_route *route;
1493
1494 OSPF6_CMD_CHECK_RUNNING();
1495
1496 ospf6_redistribute_show_config(vty);
1497
1498 for (route = ospf6_route_head(ospf6->external_table); route;
1499 route = ospf6_route_next(route))
1500 ospf6_asbr_external_route_show(vty, route);
1501
1502 return CMD_SUCCESS;
1503 }
1504
1505 struct ospf6_lsa_handler as_external_handler = {
1506 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
1507 .lh_name = "AS-External",
1508 .lh_short_name = "ASE",
1509 .lh_show = ospf6_as_external_lsa_show,
1510 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
1511 .lh_debug = 0
1512 };
1513
1514 void ospf6_asbr_init(void)
1515 {
1516 ospf6_routemap_init();
1517
1518 ospf6_install_lsa_handler(&as_external_handler);
1519
1520 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
1521
1522 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
1523 install_element(OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
1524 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
1525 }
1526
1527 void ospf6_asbr_redistribute_reset(void)
1528 {
1529 int type;
1530
1531 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1532 if (type == ZEBRA_ROUTE_OSPF6)
1533 continue;
1534 if (ospf6_zebra_is_redistribute(type))
1535 ospf6_asbr_redistribute_unset(type);
1536 }
1537 }
1538
1539 void ospf6_asbr_terminate(void)
1540 {
1541 route_map_finish();
1542 }
1543
1544 DEFUN (debug_ospf6_asbr,
1545 debug_ospf6_asbr_cmd,
1546 "debug ospf6 asbr",
1547 DEBUG_STR
1548 OSPF6_STR
1549 "Debug OSPFv3 ASBR function\n"
1550 )
1551 {
1552 OSPF6_DEBUG_ASBR_ON();
1553 return CMD_SUCCESS;
1554 }
1555
1556 DEFUN (no_debug_ospf6_asbr,
1557 no_debug_ospf6_asbr_cmd,
1558 "no debug ospf6 asbr",
1559 NO_STR
1560 DEBUG_STR
1561 OSPF6_STR
1562 "Debug OSPFv3 ASBR function\n"
1563 )
1564 {
1565 OSPF6_DEBUG_ASBR_OFF();
1566 return CMD_SUCCESS;
1567 }
1568
1569 int config_write_ospf6_debug_asbr(struct vty *vty)
1570 {
1571 if (IS_OSPF6_DEBUG_ASBR)
1572 vty_out(vty, "debug ospf6 asbr\n");
1573 return 0;
1574 }
1575
1576 void install_element_ospf6_debug_asbr()
1577 {
1578 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
1579 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
1580 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
1581 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
1582 }