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