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