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