summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_asbr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_asbr.c')
-rw-r--r--ospf6d/ospf6_asbr.c1040
1 files changed, 1040 insertions, 0 deletions
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
new file mode 100644
index 00000000..00a2b66c
--- /dev/null
+++ b/ospf6d/ospf6_asbr.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (C) 2001-2002 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+ char *name;
+ struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{
+ "system", "kernel", "connected", "static",
+ "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+ "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+ (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+ zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+
+ rmap[type].name = strdup (mapname);
+ rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+ if (rmap[type].name)
+ free (rmap[type].name);
+ rmap[type].name = NULL;
+ rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+ int i;
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (rmap[i].name)
+ rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+ else
+ rmap[i].map = NULL;
+ }
+}
+
+DEFUN (ospf6_redistribute,
+ ospf6_redistribute_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp)",
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+ ospf6_redistribute_routemap_cmd,
+ "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+ "Redistribute\n"
+ "Static routes\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ "Route map reference\n"
+ "Route map name\n"
+ )
+{
+ int type = 0;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_set (type, argv[1]);
+ ospf6_zebra_redistribute (type);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+ no_ospf6_redistribute_cmd,
+ "no redistribute (static|kernel|connected|ripng|bgp)",
+ NO_STR
+ "Redistribute\n"
+ "Static route\n"
+ "Kernel route\n"
+ "Connected route\n"
+ "RIPng route\n"
+ "BGP route\n"
+ )
+{
+ int type = 0;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, *info_next = NULL;
+
+ if (strncmp (argv[0], "sta", 3) == 0)
+ type = ZEBRA_ROUTE_STATIC;
+ else if (strncmp (argv[0], "ker", 3) == 0)
+ type = ZEBRA_ROUTE_KERNEL;
+ else if (strncmp (argv[0], "con", 3) == 0)
+ type = ZEBRA_ROUTE_CONNECT;
+ else if (strncmp (argv[0], "rip", 3) == 0)
+ type = ZEBRA_ROUTE_RIPNG;
+ else if (strncmp (argv[0], "bgp", 3) == 0)
+ type = ZEBRA_ROUTE_BGP;
+
+ ospf6_zebra_no_redistribute (type);
+ ospf6_asbr_routemap_unset (type);
+
+ /* remove redistributed route */
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (! route)
+ continue;
+ for (info = route->info_head; info; info = info_next)
+ {
+ info_next = info->next;
+ if (info->type != type)
+ continue;
+ ospf6_asbr_route_remove (info->type, info->ifindex,
+ &route->prefix);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+ int i;
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " redistribute %s route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " redistribute %s%s",
+ ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_redistribute_show_config (struct vty *vty)
+{
+ int i;
+
+ if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+ ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+ return;
+
+ vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (i == ZEBRA_ROUTE_OSPF6)
+ continue;
+ if (! ospf6_zebra_is_redistribute (i))
+ continue;
+
+ if (rmap[i].map)
+ vty_out (vty, " %s with route-map %s%s",
+ ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+ else
+ vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+ }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+ struct ospf6_external_info *info;
+ char buffer [MAXLSASIZE];
+ struct ospf6_lsa_as_external *e;
+ char *p;
+
+ info = THREAD_ARG (thread);
+
+ /* clear thread */
+ info->thread_originate = NULL;
+
+ if (info->is_removed)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: quit redistribution %s: state is down",
+ pbuf);
+ }
+ return 0;
+ }
+
+ /* prepare buffer */
+ memset (buffer, 0, sizeof (buffer));
+ e = (struct ospf6_lsa_as_external *) buffer;
+ p = (char *) (e + 1);
+
+ if (info->metric_type == 2)
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
+
+ /* forwarding address */
+ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+ SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+ else
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
+
+ /* external route tag */
+ UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
+
+ /* set metric. note: related to E bit */
+ OSPF6_ASBR_METRIC_SET (e, info->metric);
+
+ /* prefixlen */
+ e->prefix.prefix_length = info->route->prefix.prefixlen;
+
+ /* PrefixOptions */
+ e->prefix.prefix_options = info->prefix_options;
+
+ /* don't use refer LS-type */
+ e->prefix.prefix_refer_lstype = htons (0);
+
+ /* set Prefix */
+ memcpy (p, &info->route->prefix.u.prefix6,
+ OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
+ ospf6_prefix_apply_mask (&e->prefix);
+ p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
+
+ /* Forwarding address */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+ p += sizeof (struct in6_addr);
+ }
+
+ /* External Route Tag */
+ if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
+ {
+ /* xxx */
+ }
+
+ ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id,
+ (char *) buffer, p - buffer, ospf6);
+ return 0;
+}
+
+int
+ospf6_asbr_schedule_external (void *data)
+{
+ struct ospf6_external_info *info = data;
+ u_long elasped_time, time = 0;
+
+ if (info->thread_originate)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s: another thread",
+ pbuf);
+ }
+ return 0;
+ }
+
+ elasped_time =
+ ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+ if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+ time = OSPF6_MIN_LS_INTERVAL - elasped_time;
+ else
+ time = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
+ pbuf, (u_long) info->id, time);
+ }
+
+ if (time)
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
+ else
+ info->thread_originate =
+ thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
+
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_flush (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ if (lsa)
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+}
+
+int
+ospf6_asbr_external_lsa_refresh (void *data)
+{
+ struct ospf6_lsa *lsa = data;
+ struct ospf6_lsa_as_external *e;
+ struct prefix prefix;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: refresh %s", lsa->str);
+
+ e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
+ ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
+ prefix.prefixlen = e->prefix.prefix_length;
+ prefix.family = AF_INET6;
+ apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
+
+ node = route_node_lookup (external_table, &prefix);
+ if (! node || ! node->info)
+ {
+ char pname[64];
+
+ prefix2str (&prefix, pname, sizeof (pname));
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: could not find %s: premature age", pname);
+ ospf6_lsa_premature_aging (lsa);
+ return 0;
+ }
+
+ /* find external_info */
+ route = node->info;
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (lsa->header->id == htonl (info->id))
+ break;
+ }
+
+ if (info)
+ ospf6_asbr_schedule_external (info);
+ else
+ ospf6_lsa_premature_aging (lsa);
+
+ return 0;
+}
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+ u_int nexthop_num, struct in6_addr *nexthop)
+{
+ int ret;
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info, tinfo;
+
+ if (! ospf6_zebra_is_redistribute (type))
+ return;
+
+ /* apply route-map */
+ memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+ if (rmap[type].map)
+ {
+ ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+ if (ret == RMAP_DENYMATCH)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+ return;
+ }
+ }
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ {
+ route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_route));
+ memset (route, 0, sizeof (struct ospf6_external_route));
+
+ memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+ node->info = route;
+ route->node = node;
+ }
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ {
+ info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ sizeof (struct ospf6_external_info));
+ memset (info, 0, sizeof (struct ospf6_external_info));
+
+ info->route = route;
+ /* add tail */
+ info->prev = route->info_tail;
+ if (route->info_tail)
+ route->info_tail->next = info;
+ else
+ route->info_head = info;
+ route->info_tail = info;
+
+ info->id = link_state_id++;
+ }
+
+ /* copy result of route-map */
+ info->metric_type = tinfo.metric_type;
+ info->metric = tinfo.metric;
+ memcpy (&info->forwarding, &tinfo.forwarding,
+ sizeof (struct in6_addr));
+
+ info->type = type;
+ info->ifindex = ifindex;
+
+ if (nexthop_num && nexthop)
+ {
+ info->nexthop_num = nexthop_num;
+
+ if (info->nexthop)
+ XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+ info->nexthop = (struct in6_addr *)
+ XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+ nexthop_num * sizeof (struct in6_addr));
+ memcpy (info->nexthop, nexthop,
+ nexthop_num * sizeof (struct in6_addr));
+ }
+
+ info->is_removed = 0;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+ ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
+}
+
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+ struct ospf6_external_info *info;
+ struct ospf6_lsa *lsa;
+
+ node = route_node_get (external_table, prefix);
+ route = node->info;
+
+ if (! route)
+ return;
+
+ for (info = route->info_head; info; info = info->next)
+ {
+ if (info->type == type && info->ifindex == ifindex)
+ break;
+ }
+
+ if (! info)
+ return;
+
+ //if (IS_OSPF6_DUMP_ASBR)
+ {
+ char pbuf[64];
+ struct timeval now;
+ prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+ gettimeofday (&now, NULL);
+ zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+ pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+ }
+
+ if (info->thread_originate)
+ thread_cancel (info->thread_originate);
+ info->thread_originate = NULL;
+
+ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+ ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+ ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+ ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+ info->is_removed = 1;
+#else
+ /* remove from route */
+ if (info->prev)
+ info->prev->next = info->next;
+ else
+ info->route->info_head = info->next;
+ if (info->next)
+ info->next->prev = info->prev;
+ else
+ info->route->info_tail = info->prev;
+
+ /* if no info, free route */
+ if (! info->route->info_head && ! info->route->info_tail)
+ {
+ info->route->node->info = NULL;
+ free (info->route);
+ }
+
+ if (info->nexthop)
+ free (info->nexthop);
+ free (info);
+#endif /*0*/
+}
+
+void
+ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix_ls asbr_id;
+ struct ospf6_route_req asbr_entry;
+ struct ospf6_route_req request;
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+
+ if (IS_LSA_MAXAGE (lsa))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+ ospf6_asbr_external_lsa_remove (lsa);
+ return;
+ }
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: new external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: metric is infinity, ignore");
+ return;
+ }
+
+ memset (&asbr_id, 0, sizeof (asbr_id));
+ asbr_id.family = AF_UNSPEC;
+ asbr_id.prefixlen = 64; /* xxx */
+ asbr_id.adv_router.s_addr = lsa->header->adv_router;
+
+ ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
+ ospf6->topology_table);
+
+ if (ospf6_route_end (&asbr_entry))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router %s not found, ignore", buf);
+ }
+ return;
+ }
+
+ memset (&request, 0, sizeof (request));
+ request.route.type = OSPF6_DEST_TYPE_NETWORK;
+ request.route.prefix.family = AF_INET6;
+ request.route.prefix.prefixlen = external->prefix.prefix_length;
+ memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
+
+ request.path.area_id = asbr_entry.path.area_id;
+ request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ request.path.origin.id = lsa->header->id;
+ request.path.origin.adv_router = lsa->header->adv_router;
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+ request.path.metric_type = 2;
+ request.path.cost = asbr_entry.path.cost;
+ request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
+ }
+ else
+ {
+ request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+ request.path.metric_type = 1;
+ request.path.cost = asbr_entry.path.cost
+ + OSPF6_ASBR_METRIC (external);
+ request.path.cost_e2 = 0;
+ }
+ request.path.prefix_options = external->prefix.prefix_options;
+
+ while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
+ asbr_id.adv_router.s_addr &&
+ asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
+ {
+ memcpy (&request.nexthop, &asbr_entry.nexthop,
+ sizeof (struct ospf6_nexthop));
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64], nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&request.route.prefix, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
+ }
+ ospf6_route_add (&request, ospf6->route_table);
+ ospf6_route_next (&asbr_entry);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ struct prefix dest;
+ char buf[64];
+ struct ospf6_route_req request;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
+ lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+ if (lsa->header->adv_router == ospf6->router_id)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: my external LSA, ignore");
+ return;
+ }
+
+ external = OSPF6_LSA_HEADER_END (lsa->header);
+ memset (&dest, 0, sizeof (dest));
+ dest.family = AF_INET6;
+ dest.prefixlen = external->prefix.prefix_length;
+ memcpy (&dest.u.prefix6, (char *)(external + 1),
+ OSPF6_PREFIX_SPACE (dest.prefixlen));
+
+ ospf6_route_lookup (&request, &dest, ospf6->route_table);
+ if (ospf6_route_end (&request))
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ prefix2str (&dest, buf, sizeof (buf));
+ zlog_info ("ASBR: %s not found", buf);
+ }
+ return;
+ }
+
+ while (request.path.origin.id != lsa->header->id ||
+ request.path.origin.adv_router != lsa->header->adv_router)
+ {
+ if (prefix_same (&request.route.prefix, &dest) != 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ zlog_info ("ASBR: Can't find the entry matches the origin");
+ return;
+ }
+ ospf6_route_next (&request);
+ }
+ assert (request.path.origin.id == lsa->header->id);
+ assert (request.path.origin.adv_router == request.path.origin.adv_router);
+
+ while (request.path.origin.id == lsa->header->id &&
+ request.path.origin.adv_router == lsa->header->adv_router &&
+ prefix_same (&request.route.prefix, &dest) == 1)
+ {
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char nhop[64], ifname[IFNAMSIZ];
+ prefix2str (&dest, buf, sizeof (buf));
+ inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+ if_indextoname (request.nexthop.ifindex, ifname);
+ zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
+ }
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ ospf6_route_next (&request);
+ }
+}
+
+void
+ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ assert (old || new);
+
+ if (old == NULL)
+ ospf6_asbr_external_lsa_add (new);
+ else if (new == NULL)
+ ospf6_asbr_external_lsa_remove (old);
+ else
+ {
+ ospf6_route_table_freeze (ospf6->route_table);
+ ospf6_asbr_external_lsa_remove (old);
+ ospf6_asbr_external_lsa_add (new);
+ ospf6_route_table_thaw (ospf6->route_table);
+ }
+}
+
+void
+ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
+{
+ struct ospf6_lsdb_node node;
+
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: new router found: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ return;
+ }
+
+ for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+ adv_router, ospf6->lsdb);
+ ! ospf6_lsdb_is_end (&node);
+ ospf6_lsdb_next (&node))
+ ospf6_asbr_external_lsa_add (node.lsa);
+}
+
+void
+ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
+{
+ struct prefix_ls *inter_router;
+ u_int32_t id, adv_router;
+ struct ospf6_route_req request;
+
+ inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
+ id = inter_router->id.s_addr;
+ adv_router = inter_router->adv_router.s_addr;
+
+ if (IS_OSPF6_DUMP_ASBR)
+ {
+ char buf[64];
+ inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
+ zlog_info ("ASBR: router disappearing: %s", buf);
+ }
+
+ if (ntohl (id) != 0 ||
+ ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
+ {
+ zlog_warn ("ASBR: Inter topology table malformed");
+ }
+
+ for (ospf6_route_head (&request, ospf6->route_table);
+ ! ospf6_route_end (&request);
+ ospf6_route_next (&request))
+ {
+ if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
+ request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
+ continue;
+ if (request.path.area_id != topo_entry->path.area_id)
+ continue;
+ if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
+ continue;
+ if (memcmp (&topo_entry->nexthop, &request.nexthop,
+ sizeof (struct ospf6_nexthop)))
+ continue;
+
+ ospf6_route_remove (&request, ospf6->route_table);
+ }
+}
+
+int
+ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+ struct ospf6_lsa_as_external *external;
+ char buf[128], *ptr;
+ struct in6_addr in6;
+
+ assert (lsa->header);
+ external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+
+ /* bits */
+ snprintf (buf, sizeof (buf), "%s%s%s",
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
+ "E" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
+ "F" : "-"),
+ (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
+ "T" : "-"));
+
+ vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE);
+ vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
+ VTY_NEWLINE);
+
+ ospf6_prefix_options_str (external->prefix.prefix_options,
+ buf, sizeof (buf));
+ vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE);
+
+ vty_out (vty, " Referenced LSType: %d%s",
+ ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+
+ ospf6_prefix_in6_addr (&external->prefix, &in6);
+ inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+ vty_out (vty, " Prefix: %s/%d%s",
+ buf, external->prefix.prefix_length, VTY_NEWLINE);
+
+ /* Forwarding-Address */
+ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
+ {
+ ptr = ((char *)(external + 1))
+ + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
+ inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
+ vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+void
+ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+ if (old)
+ ospf6_asbr_external_lsa_remove (old);
+ if (new && ! IS_LSA_MAXAGE (new))
+ ospf6_asbr_external_lsa_add (new);
+}
+
+void
+ospf6_asbr_register_as_external ()
+{
+ struct ospf6_lsa_slot slot;
+
+ memset (&slot, 0, sizeof (slot));
+ slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
+ slot.name = "AS-External";
+ slot.func_show = ospf6_asbr_external_show;
+ slot.func_refresh = ospf6_asbr_external_lsa_refresh;
+ ospf6_lsa_slot_register (&slot);
+
+ ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook =
+ ospf6_asbr_database_hook;
+}
+
+void
+ospf6_asbr_external_info_show (struct vty *vty,
+ struct ospf6_external_info *info)
+{
+ char prefix_buf[64], id_buf[16];
+ struct in_addr id;
+
+ if (info->is_removed)
+ return;
+
+ id.s_addr = ntohl (info->id);
+ inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
+ prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
+ vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
+ ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
+ info->nexthop_num, (u_long) info->metric, info->metric_type,
+ VTY_NEWLINE);
+}
+
+void
+ospf6_asbr_external_route_show (struct vty *vty,
+ struct ospf6_external_route *route)
+{
+ struct ospf6_external_info *info;
+ for (info = route->info_head; info; info = info->next)
+ ospf6_asbr_external_info_show (vty, info);
+}
+
+DEFUN (show_ipv6_route_ospf6_external,
+ show_ipv6_route_ospf6_external_cmd,
+ "show ipv6 ospf6 route redistribute",
+ SHOW_STR
+ IP6_STR
+ ROUTE_STR
+ OSPF6_STR
+ "redistributing External information\n"
+ )
+{
+ struct route_node *node;
+ struct ospf6_external_route *route;
+
+ vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+ " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+ VTY_NEWLINE);
+ for (node = route_top (external_table); node; node = route_next (node))
+ {
+ route = node->info;
+ if (route)
+ ospf6_asbr_external_route_show (vty, route);
+ }
+ return CMD_SUCCESS;
+}
+
+void
+ospf6_asbr_init ()
+{
+ external_table = route_table_init ();
+ link_state_id = 0;
+
+ ospf6_asbr_register_as_external ();
+
+ install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+ install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+ install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+}
+
+