]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_asbr.c
Fix by Vadim Suraev - [zebra 14710] #6.
[mirror_frr.git] / ospf6d / ospf6_asbr.c
CommitLineData
718e3744 1/*
2 * Copyright (C) 2001-2002 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
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "log.h"
25#include "memory.h"
26#include "prefix.h"
27#include "command.h"
28#include "vty.h"
29#include "routemap.h"
30#include "table.h"
31#include "plist.h"
32#include "thread.h"
33
34#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */
35#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */
36#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */
37#include "ospf6_zebra.h"
38#include "ospf6_asbr.h"
39#include "ospf6_damp.h"
40#include "ospf6_top.h"
41#include "ospf6_lsdb.h"
42#include "ospf6_proto.h"
43
44extern struct thread_master *master;
45
46struct route_table *external_table;
47struct
48{
49 char *name;
50 struct route_map *map;
51} rmap [ZEBRA_ROUTE_MAX];
52
53static u_int32_t link_state_id = 0;
54
55char *
56zroute_name[] =
57{
58 "system", "kernel", "connected", "static",
59 "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
60};
61char *
62zroute_abname[] =
63{
64 "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
65};
66
67#define ZROUTE_NAME(x) \
68 (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
69 zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
70
71#define ZROUTE_ABNAME(x) \
72 (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
73 zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
74
75/* redistribute function */
76void
77ospf6_asbr_routemap_set (int type, char *mapname)
78{
79 if (rmap[type].name)
80 free (rmap[type].name);
81
82 rmap[type].name = strdup (mapname);
83 rmap[type].map = route_map_lookup_by_name (mapname);
84}
85
86void
87ospf6_asbr_routemap_unset (int type)
88{
89 if (rmap[type].name)
90 free (rmap[type].name);
91 rmap[type].name = NULL;
92 rmap[type].map = NULL;
93}
94
95void
96ospf6_asbr_routemap_update ()
97{
98 int i;
99 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
100 {
101 if (rmap[i].name)
102 rmap[i].map = route_map_lookup_by_name (rmap[i].name);
103 else
104 rmap[i].map = NULL;
105 }
106}
107
108DEFUN (ospf6_redistribute,
109 ospf6_redistribute_cmd,
110 "redistribute (static|kernel|connected|ripng|bgp)",
111 "Redistribute\n"
112 "Static route\n"
113 "Kernel route\n"
114 "Connected route\n"
115 "RIPng route\n"
116 "BGP route\n"
117 )
118{
119 int type = 0;
120
121 if (strncmp (argv[0], "sta", 3) == 0)
122 type = ZEBRA_ROUTE_STATIC;
123 else if (strncmp (argv[0], "ker", 3) == 0)
124 type = ZEBRA_ROUTE_KERNEL;
125 else if (strncmp (argv[0], "con", 3) == 0)
126 type = ZEBRA_ROUTE_CONNECT;
127 else if (strncmp (argv[0], "rip", 3) == 0)
128 type = ZEBRA_ROUTE_RIPNG;
129 else if (strncmp (argv[0], "bgp", 3) == 0)
130 type = ZEBRA_ROUTE_BGP;
131
132 ospf6_zebra_no_redistribute (type);
133 ospf6_asbr_routemap_unset (type);
134 ospf6_zebra_redistribute (type);
135 return CMD_SUCCESS;
136}
137
138DEFUN (ospf6_redistribute_routemap,
139 ospf6_redistribute_routemap_cmd,
140 "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
141 "Redistribute\n"
142 "Static routes\n"
143 "Kernel route\n"
144 "Connected route\n"
145 "RIPng route\n"
146 "BGP route\n"
147 "Route map reference\n"
148 "Route map name\n"
149 )
150{
151 int type = 0;
152
153 if (strncmp (argv[0], "sta", 3) == 0)
154 type = ZEBRA_ROUTE_STATIC;
155 else if (strncmp (argv[0], "ker", 3) == 0)
156 type = ZEBRA_ROUTE_KERNEL;
157 else if (strncmp (argv[0], "con", 3) == 0)
158 type = ZEBRA_ROUTE_CONNECT;
159 else if (strncmp (argv[0], "rip", 3) == 0)
160 type = ZEBRA_ROUTE_RIPNG;
161 else if (strncmp (argv[0], "bgp", 3) == 0)
162 type = ZEBRA_ROUTE_BGP;
163
164 ospf6_zebra_no_redistribute (type);
165 ospf6_asbr_routemap_set (type, argv[1]);
166 ospf6_zebra_redistribute (type);
167 return CMD_SUCCESS;
168}
169
170DEFUN (no_ospf6_redistribute,
171 no_ospf6_redistribute_cmd,
172 "no redistribute (static|kernel|connected|ripng|bgp)",
173 NO_STR
174 "Redistribute\n"
175 "Static route\n"
176 "Kernel route\n"
177 "Connected route\n"
178 "RIPng route\n"
179 "BGP route\n"
180 )
181{
182 int type = 0;
183 struct route_node *node;
184 struct ospf6_external_route *route;
185 struct ospf6_external_info *info, *info_next = NULL;
186
187 if (strncmp (argv[0], "sta", 3) == 0)
188 type = ZEBRA_ROUTE_STATIC;
189 else if (strncmp (argv[0], "ker", 3) == 0)
190 type = ZEBRA_ROUTE_KERNEL;
191 else if (strncmp (argv[0], "con", 3) == 0)
192 type = ZEBRA_ROUTE_CONNECT;
193 else if (strncmp (argv[0], "rip", 3) == 0)
194 type = ZEBRA_ROUTE_RIPNG;
195 else if (strncmp (argv[0], "bgp", 3) == 0)
196 type = ZEBRA_ROUTE_BGP;
197
198 ospf6_zebra_no_redistribute (type);
199 ospf6_asbr_routemap_unset (type);
200
201 /* remove redistributed route */
202 for (node = route_top (external_table); node; node = route_next (node))
203 {
204 route = node->info;
205 if (! route)
206 continue;
207 for (info = route->info_head; info; info = info_next)
208 {
209 info_next = info->next;
210 if (info->type != type)
211 continue;
212 ospf6_asbr_route_remove (info->type, info->ifindex,
213 &route->prefix);
214 }
215 }
216
217 return CMD_SUCCESS;
218}
219
220
221int
222ospf6_redistribute_config_write (struct vty *vty)
223{
224 int i;
225
226 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
227 {
228 if (i == ZEBRA_ROUTE_OSPF6)
229 continue;
230
231 if (! ospf6_zebra_is_redistribute (i))
232 continue;
233
234 if (rmap[i].map)
235 vty_out (vty, " redistribute %s route-map %s%s",
236 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
237 else
238 vty_out (vty, " redistribute %s%s",
239 ZROUTE_NAME(i), VTY_NEWLINE);
240 }
241
242 return 0;
243}
244
245void
246ospf6_redistribute_show_config (struct vty *vty)
247{
248 int i;
249
250 if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
251 ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
252 ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
253 ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
254 ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
255 return;
256
257 vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
258 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
259 {
260 if (i == ZEBRA_ROUTE_OSPF6)
261 continue;
262 if (! ospf6_zebra_is_redistribute (i))
263 continue;
264
265 if (rmap[i].map)
266 vty_out (vty, " %s with route-map %s%s",
267 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
268 else
269 vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
270 }
271}
272
273/* AS External LSA origination */
274int
275ospf6_asbr_external_lsa_originate (struct thread *thread)
276{
277 struct ospf6_external_info *info;
278 char buffer [MAXLSASIZE];
279 struct ospf6_lsa_as_external *e;
280 char *p;
281
282 info = THREAD_ARG (thread);
283
284 /* clear thread */
285 info->thread_originate = NULL;
286
287 if (info->is_removed)
288 {
289 if (IS_OSPF6_DUMP_ASBR)
290 {
291 char pbuf[64];
292 prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
293 zlog_info ("ASBR: quit redistribution %s: state is down",
294 pbuf);
295 }
296 return 0;
297 }
298
299 /* prepare buffer */
300 memset (buffer, 0, sizeof (buffer));
301 e = (struct ospf6_lsa_as_external *) buffer;
302 p = (char *) (e + 1);
303
304 if (info->metric_type == 2)
305 SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
306 else
307 UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
308
309 /* forwarding address */
310 if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
311 SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
312 else
313 UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
314
315 /* external route tag */
316 UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
317
318 /* set metric. note: related to E bit */
319 OSPF6_ASBR_METRIC_SET (e, info->metric);
320
321 /* prefixlen */
322 e->prefix.prefix_length = info->route->prefix.prefixlen;
323
324 /* PrefixOptions */
325 e->prefix.prefix_options = info->prefix_options;
326
327 /* don't use refer LS-type */
328 e->prefix.prefix_refer_lstype = htons (0);
329
330 /* set Prefix */
331 memcpy (p, &info->route->prefix.u.prefix6,
332 OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
333 ospf6_prefix_apply_mask (&e->prefix);
334 p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
335
336 /* Forwarding address */
337 if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
338 {
339 memcpy (p, &info->forwarding, sizeof (struct in6_addr));
340 p += sizeof (struct in6_addr);
341 }
342
343 /* External Route Tag */
344 if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
345 {
346 /* xxx */
347 }
348
349 ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
350 htonl (info->id), ospf6->router_id,
351 (char *) buffer, p - buffer, ospf6);
352 return 0;
353}
354
355int
356ospf6_asbr_schedule_external (void *data)
357{
358 struct ospf6_external_info *info = data;
359 u_long elasped_time, time = 0;
360
361 if (info->thread_originate)
362 {
363 if (IS_OSPF6_DUMP_ASBR)
364 {
365 char pbuf[64];
366 prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
367 zlog_info ("ASBR: schedule redistribution %s: another thread",
368 pbuf);
369 }
370 return 0;
371 }
372
373 elasped_time =
374 ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
375 htonl (info->id), ospf6->router_id, ospf6);
376 if (elasped_time < OSPF6_MIN_LS_INTERVAL)
377 time = OSPF6_MIN_LS_INTERVAL - elasped_time;
378 else
379 time = 0;
380
381 //if (IS_OSPF6_DUMP_ASBR)
382 {
383 char pbuf[64];
384 prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
385 zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
386 pbuf, (u_long) info->id, time);
387 }
388
389 if (time)
390 info->thread_originate =
391 thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
392 else
393 info->thread_originate =
394 thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
395
396 return 0;
397}
398
399int
400ospf6_asbr_external_lsa_flush (void *data)
401{
402 struct ospf6_lsa *lsa = data;
403 if (lsa)
404 ospf6_lsa_premature_aging (lsa);
405 return 0;
406}
407
408int
409ospf6_asbr_external_lsa_refresh (void *data)
410{
411 struct ospf6_lsa *lsa = data;
412 struct ospf6_lsa_as_external *e;
413 struct prefix prefix;
414 struct route_node *node;
e26bbeba 415 struct ospf6_external_route *route = NULL;
416 struct ospf6_external_info *info = NULL;
417 struct ospf6_external_info *match = NULL;
718e3744 418
419 if (IS_OSPF6_DUMP_ASBR)
420 zlog_info ("ASBR: refresh %s", lsa->str);
421
422 e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
423 ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
424 prefix.prefixlen = e->prefix.prefix_length;
425 prefix.family = AF_INET6;
426 apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
427
e26bbeba 428 for (node = route_top (external_table); node; node = route_next (node))
429 {
430 route = node->info;
431 if (route == NULL)
432 continue;
433
434 for (info = route->info_head; info; info = info->next)
435 {
436 if (lsa->header->id == htonl (info->id))
437 match = info;
438 }
439 }
440
441 if (match == NULL)
442 {
443 ospf6_lsa_premature_aging (lsa);
444 return 0;
445 }
446
447 ospf6_asbr_schedule_external (match);
448 return 0;
449
450#if 0
718e3744 451 node = route_node_lookup (external_table, &prefix);
452 if (! node || ! node->info)
453 {
454 char pname[64];
455
456 prefix2str (&prefix, pname, sizeof (pname));
457 if (IS_OSPF6_DUMP_ASBR)
458 zlog_info ("ASBR: could not find %s: premature age", pname);
459 ospf6_lsa_premature_aging (lsa);
460 return 0;
461 }
462
463 /* find external_info */
464 route = node->info;
465 for (info = route->info_head; info; info = info->next)
466 {
467 if (lsa->header->id == htonl (info->id))
468 break;
469 }
470
471 if (info)
472 ospf6_asbr_schedule_external (info);
473 else
474 ospf6_lsa_premature_aging (lsa);
475
476 return 0;
e26bbeba 477#endif
718e3744 478}
479
480void
481ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
482 u_int nexthop_num, struct in6_addr *nexthop)
483{
484 int ret;
485 struct route_node *node;
486 struct ospf6_external_route *route;
487 struct ospf6_external_info *info, tinfo;
488
e26bbeba 489#if defined (MUSICA) || defined (LINUX)
490 /* XXX As long as the OSPFv3 redistribution is applied to all the connected
491 * routes, one needs to filter the ::/96 prefixes.
492 * However it could be a wanted case, it will be removed soon.
493 */
494 struct prefix_ipv6 *p = (prefix_ipv6 *)prefix;
495
496 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
497 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
498 return;
499#endif /* MUSICA or LINUX */
500
718e3744 501 if (! ospf6_zebra_is_redistribute (type))
502 return;
503
504 /* apply route-map */
505 memset (&tinfo, 0, sizeof (struct ospf6_external_info));
506 if (rmap[type].map)
507 {
508 ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
509 if (ret == RMAP_DENYMATCH)
510 {
511 if (IS_OSPF6_DUMP_ASBR)
512 zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
513 return;
514 }
515 }
516
517 node = route_node_get (external_table, prefix);
518 route = node->info;
519
520 if (! route)
521 {
522 route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
523 sizeof (struct ospf6_external_route));
524 memset (route, 0, sizeof (struct ospf6_external_route));
525
526 memcpy (&route->prefix, prefix, sizeof (struct prefix));
527
528 node->info = route;
529 route->node = node;
530 }
531
532 for (info = route->info_head; info; info = info->next)
533 {
534 if (info->type == type && info->ifindex == ifindex)
535 break;
536 }
537
538 if (! info)
539 {
540 info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
541 sizeof (struct ospf6_external_info));
542 memset (info, 0, sizeof (struct ospf6_external_info));
543
544 info->route = route;
545 /* add tail */
546 info->prev = route->info_tail;
547 if (route->info_tail)
548 route->info_tail->next = info;
549 else
550 route->info_head = info;
551 route->info_tail = info;
552
553 info->id = link_state_id++;
554 }
555
556 /* copy result of route-map */
557 info->metric_type = tinfo.metric_type;
558 info->metric = tinfo.metric;
559 memcpy (&info->forwarding, &tinfo.forwarding,
560 sizeof (struct in6_addr));
561
562 info->type = type;
563 info->ifindex = ifindex;
564
565 if (nexthop_num && nexthop)
566 {
567 info->nexthop_num = nexthop_num;
568
569 if (info->nexthop)
570 XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
571
572 info->nexthop = (struct in6_addr *)
573 XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
574 nexthop_num * sizeof (struct in6_addr));
575 memcpy (info->nexthop, nexthop,
576 nexthop_num * sizeof (struct in6_addr));
577 }
578
579 info->is_removed = 0;
580
581 //if (IS_OSPF6_DUMP_ASBR)
582 {
583 char pbuf[64];
584 struct timeval now;
585 prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
586 gettimeofday (&now, NULL);
587 zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
588 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
589 }
590
591#ifdef HAVE_OSPF6_DAMP
592 ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
593 ospf6_asbr_schedule_external, info);
594#else /*HAVE_OSPF6_DAMP*/
595 ospf6_asbr_schedule_external (info);
596#endif /*HAVE_OSPF6_DAMP*/
597}
598
599void
600ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
601{
602 struct route_node *node;
603 struct ospf6_external_route *route;
604 struct ospf6_external_info *info;
605 struct ospf6_lsa *lsa;
606
e26bbeba 607#if defined (MUSICA) || defined (LINUX)
608 /* XXX As long as the OSPFv3 redistribution is applied to all the connected
609 * routes, one needs to filter the ::/96 prefixes.
610 * However it could be a wanted case, it will be removed soon.
611 */
612 struct prefix_ipv6 *p = (prefix_ipv6 *)prefix;
613
614 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
615 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
616 return;
617#endif /* MUSICA or LINUX */
618
718e3744 619 node = route_node_get (external_table, prefix);
620 route = node->info;
621
622 if (! route)
623 return;
624
625 for (info = route->info_head; info; info = info->next)
626 {
627 if (info->type == type && info->ifindex == ifindex)
628 break;
629 }
630
631 if (! info)
632 return;
633
634 //if (IS_OSPF6_DUMP_ASBR)
635 {
636 char pbuf[64];
637 struct timeval now;
638 prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
639 gettimeofday (&now, NULL);
640 zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
641 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
642 }
643
644 if (info->thread_originate)
645 thread_cancel (info->thread_originate);
646 info->thread_originate = NULL;
647
648 lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
649 htonl (info->id), ospf6->router_id, ospf6);
650#ifdef HAVE_OSPF6_DAMP
651 ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
652 ospf6_asbr_external_lsa_flush, lsa);
653#else /*HAVE_OSPF6_DAMP*/
654 ospf6_asbr_external_lsa_flush (lsa);
655#endif /*HAVE_OSPF6_DAMP*/
656
657#if 1
658 info->is_removed = 1;
659#else
660 /* remove from route */
661 if (info->prev)
662 info->prev->next = info->next;
663 else
664 info->route->info_head = info->next;
665 if (info->next)
666 info->next->prev = info->prev;
667 else
668 info->route->info_tail = info->prev;
669
670 /* if no info, free route */
671 if (! info->route->info_head && ! info->route->info_tail)
672 {
673 info->route->node->info = NULL;
674 free (info->route);
675 }
676
677 if (info->nexthop)
678 free (info->nexthop);
679 free (info);
680#endif /*0*/
681}
682
683void
684ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
685{
686 struct ospf6_lsa_as_external *external;
687 struct prefix_ls asbr_id;
688 struct ospf6_route_req asbr_entry;
689 struct ospf6_route_req request;
690
691 external = OSPF6_LSA_HEADER_END (lsa->header);
692
693 if (IS_LSA_MAXAGE (lsa))
694 {
695 if (IS_OSPF6_DUMP_ASBR)
696 zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
697 lsa->str, (u_long)ntohl (lsa->header->seqnum));
698 ospf6_asbr_external_lsa_remove (lsa);
699 return;
700 }
701
702 if (IS_OSPF6_DUMP_ASBR)
703 zlog_info ("ASBR: new external lsa: %s seq: %lx",
704 lsa->str, (u_long)ntohl (lsa->header->seqnum));
705
706 if (lsa->header->adv_router == ospf6->router_id)
707 {
708 if (IS_OSPF6_DUMP_ASBR)
709 zlog_info ("ASBR: my external LSA, ignore");
710 return;
711 }
712
713 if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
714 {
715 if (IS_OSPF6_DUMP_ASBR)
716 zlog_info ("ASBR: metric is infinity, ignore");
717 return;
718 }
719
720 memset (&asbr_id, 0, sizeof (asbr_id));
721 asbr_id.family = AF_UNSPEC;
722 asbr_id.prefixlen = 64; /* xxx */
723 asbr_id.adv_router.s_addr = lsa->header->adv_router;
724
725 ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
726 ospf6->topology_table);
727
728 if (ospf6_route_end (&asbr_entry))
729 {
730 if (IS_OSPF6_DUMP_ASBR)
731 {
732 char buf[64];
733 inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
734 zlog_info ("ASBR: router %s not found, ignore", buf);
735 }
736 return;
737 }
738
739 memset (&request, 0, sizeof (request));
740 request.route.type = OSPF6_DEST_TYPE_NETWORK;
741 request.route.prefix.family = AF_INET6;
742 request.route.prefix.prefixlen = external->prefix.prefix_length;
743 memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
744 OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
745
746 request.path.area_id = asbr_entry.path.area_id;
747 request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
748 request.path.origin.id = lsa->header->id;
749 request.path.origin.adv_router = lsa->header->adv_router;
750 if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
751 {
752 request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
753 request.path.metric_type = 2;
754 request.path.cost = asbr_entry.path.cost;
755 request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
756 }
757 else
758 {
759 request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
760 request.path.metric_type = 1;
761 request.path.cost = asbr_entry.path.cost
762 + OSPF6_ASBR_METRIC (external);
763 request.path.cost_e2 = 0;
764 }
765 request.path.prefix_options = external->prefix.prefix_options;
766
767 while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
768 asbr_id.adv_router.s_addr &&
769 asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
770 {
771 memcpy (&request.nexthop, &asbr_entry.nexthop,
772 sizeof (struct ospf6_nexthop));
773 if (IS_OSPF6_DUMP_ASBR)
774 {
775 char buf[64], nhop[64], ifname[IFNAMSIZ];
776 prefix2str (&request.route.prefix, buf, sizeof (buf));
777 inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
778 if_indextoname (request.nexthop.ifindex, ifname);
779 zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
780 }
781 ospf6_route_add (&request, ospf6->route_table);
782 ospf6_route_next (&asbr_entry);
783 }
784}
785
786void
787ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
788{
789 struct ospf6_lsa_as_external *external;
790 struct prefix dest;
791 char buf[64];
792 struct ospf6_route_req request;
793
794 if (IS_OSPF6_DUMP_ASBR)
795 zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
796 lsa->str, (u_long)ntohl (lsa->header->seqnum));
797
798 if (lsa->header->adv_router == ospf6->router_id)
799 {
800 if (IS_OSPF6_DUMP_ASBR)
801 zlog_info ("ASBR: my external LSA, ignore");
802 return;
803 }
804
805 external = OSPF6_LSA_HEADER_END (lsa->header);
806 memset (&dest, 0, sizeof (dest));
807 dest.family = AF_INET6;
808 dest.prefixlen = external->prefix.prefix_length;
809 memcpy (&dest.u.prefix6, (char *)(external + 1),
810 OSPF6_PREFIX_SPACE (dest.prefixlen));
811
812 ospf6_route_lookup (&request, &dest, ospf6->route_table);
813 if (ospf6_route_end (&request))
814 {
815 if (IS_OSPF6_DUMP_ASBR)
816 {
817 prefix2str (&dest, buf, sizeof (buf));
818 zlog_info ("ASBR: %s not found", buf);
819 }
820 return;
821 }
822
823 while (request.path.origin.id != lsa->header->id ||
824 request.path.origin.adv_router != lsa->header->adv_router)
825 {
826 if (prefix_same (&request.route.prefix, &dest) != 1)
827 {
828 if (IS_OSPF6_DUMP_ASBR)
829 zlog_info ("ASBR: Can't find the entry matches the origin");
830 return;
831 }
832 ospf6_route_next (&request);
833 }
834 assert (request.path.origin.id == lsa->header->id);
835 assert (request.path.origin.adv_router == request.path.origin.adv_router);
836
837 while (request.path.origin.id == lsa->header->id &&
838 request.path.origin.adv_router == lsa->header->adv_router &&
839 prefix_same (&request.route.prefix, &dest) == 1)
840 {
841 if (IS_OSPF6_DUMP_ASBR)
842 {
843 char nhop[64], ifname[IFNAMSIZ];
844 prefix2str (&dest, buf, sizeof (buf));
845 inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
846 if_indextoname (request.nexthop.ifindex, ifname);
847 zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
848 }
849
850 ospf6_route_remove (&request, ospf6->route_table);
851 ospf6_route_next (&request);
852 }
853}
854
855void
856ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
857{
858 assert (old || new);
859
860 if (old == NULL)
861 ospf6_asbr_external_lsa_add (new);
862 else if (new == NULL)
863 ospf6_asbr_external_lsa_remove (old);
864 else
865 {
866 ospf6_route_table_freeze (ospf6->route_table);
867 ospf6_asbr_external_lsa_remove (old);
868 ospf6_asbr_external_lsa_add (new);
869 ospf6_route_table_thaw (ospf6->route_table);
870 }
871}
872
873void
874ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
875{
876 struct ospf6_lsdb_node node;
877
878 struct prefix_ls *inter_router;
879 u_int32_t id, adv_router;
880
881 inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
882 id = inter_router->id.s_addr;
883 adv_router = inter_router->adv_router.s_addr;
884
885 if (IS_OSPF6_DUMP_ASBR)
886 {
887 char buf[64];
888 inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
889 zlog_info ("ASBR: new router found: %s", buf);
890 }
891
892 if (ntohl (id) != 0 ||
893 ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
894 {
895 zlog_warn ("ASBR: Inter topology table malformed");
896 return;
897 }
898
899 for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
900 adv_router, ospf6->lsdb);
901 ! ospf6_lsdb_is_end (&node);
902 ospf6_lsdb_next (&node))
903 ospf6_asbr_external_lsa_add (node.lsa);
904}
905
906void
907ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
908{
909 struct prefix_ls *inter_router;
910 u_int32_t id, adv_router;
911 struct ospf6_route_req request;
912
913 inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
914 id = inter_router->id.s_addr;
915 adv_router = inter_router->adv_router.s_addr;
916
917 if (IS_OSPF6_DUMP_ASBR)
918 {
919 char buf[64];
920 inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
921 zlog_info ("ASBR: router disappearing: %s", buf);
922 }
923
924 if (ntohl (id) != 0 ||
925 ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
926 {
927 zlog_warn ("ASBR: Inter topology table malformed");
928 }
929
930 for (ospf6_route_head (&request, ospf6->route_table);
931 ! ospf6_route_end (&request);
932 ospf6_route_next (&request))
933 {
934 if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
935 request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
936 continue;
937 if (request.path.area_id != topo_entry->path.area_id)
938 continue;
939 if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
940 continue;
941 if (memcmp (&topo_entry->nexthop, &request.nexthop,
942 sizeof (struct ospf6_nexthop)))
943 continue;
944
945 ospf6_route_remove (&request, ospf6->route_table);
946 }
947}
948
949int
950ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
951{
952 struct ospf6_lsa_as_external *external;
953 char buf[128], *ptr;
954 struct in6_addr in6;
955
956 assert (lsa->header);
957 external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
958
959 /* bits */
960 snprintf (buf, sizeof (buf), "%s%s%s",
961 (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
962 "E" : "-"),
963 (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
964 "F" : "-"),
965 (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
966 "T" : "-"));
967
968 vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE);
969 vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
970 VTY_NEWLINE);
971
972 ospf6_prefix_options_str (external->prefix.prefix_options,
973 buf, sizeof (buf));
974 vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
975
976 vty_out (vty, " Referenced LSType: %d%s",
977 ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
978
979 ospf6_prefix_in6_addr (&external->prefix, &in6);
980 inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
981 vty_out (vty, " Prefix: %s/%d%s",
982 buf, external->prefix.prefix_length, VTY_NEWLINE);
983
984 /* Forwarding-Address */
985 if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
986 {
987 ptr = ((char *)(external + 1))
988 + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
989 inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
990 vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE);
991 }
992
993 return 0;
994}
995
996void
997ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
998{
999 if (old)
1000 ospf6_asbr_external_lsa_remove (old);
1001 if (new && ! IS_LSA_MAXAGE (new))
1002 ospf6_asbr_external_lsa_add (new);
1003}
1004
1005void
1006ospf6_asbr_register_as_external ()
1007{
1008 struct ospf6_lsa_slot slot;
1009
1010 memset (&slot, 0, sizeof (slot));
1011 slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
1012 slot.name = "AS-External";
1013 slot.func_show = ospf6_asbr_external_show;
1014 slot.func_refresh = ospf6_asbr_external_lsa_refresh;
1015 ospf6_lsa_slot_register (&slot);
1016
1017 ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook =
1018 ospf6_asbr_database_hook;
1019}
1020
1021void
1022ospf6_asbr_external_info_show (struct vty *vty,
1023 struct ospf6_external_info *info)
1024{
1025 char prefix_buf[64], id_buf[16];
1026 struct in_addr id;
1027
1028 if (info->is_removed)
1029 return;
1030
1031 id.s_addr = ntohl (info->id);
1032 inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
1033 prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
1034 vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
1035 ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
1036 info->nexthop_num, (u_long) info->metric, info->metric_type,
1037 VTY_NEWLINE);
1038}
1039
1040void
1041ospf6_asbr_external_route_show (struct vty *vty,
1042 struct ospf6_external_route *route)
1043{
1044 struct ospf6_external_info *info;
1045 for (info = route->info_head; info; info = info->next)
1046 ospf6_asbr_external_info_show (vty, info);
1047}
1048
1049DEFUN (show_ipv6_route_ospf6_external,
1050 show_ipv6_route_ospf6_external_cmd,
1051 "show ipv6 ospf6 route redistribute",
1052 SHOW_STR
1053 IP6_STR
1054 ROUTE_STR
1055 OSPF6_STR
1056 "redistributing External information\n"
1057 )
1058{
1059 struct route_node *node;
1060 struct ospf6_external_route *route;
1061
1062 vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
1063 " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
1064 VTY_NEWLINE);
1065 for (node = route_top (external_table); node; node = route_next (node))
1066 {
1067 route = node->info;
1068 if (route)
1069 ospf6_asbr_external_route_show (vty, route);
1070 }
1071 return CMD_SUCCESS;
1072}
1073
1074void
1075ospf6_asbr_init ()
1076{
1077 external_table = route_table_init ();
1078 link_state_id = 0;
1079
1080 ospf6_asbr_register_as_external ();
1081
1082 install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
1083 install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
1084 install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
1085 install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
1086 install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
1087}
1088
1089