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