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