diff options
author | paul <paul> | 2002-12-13 20:15:29 +0000 |
---|---|---|
committer | paul <paul> | 2002-12-13 20:15:29 +0000 |
commit | 718e3744195351130f4ce7dbe0613f4b3e23df93 (patch) | |
tree | bac2ad39971cd43f31241ef123bd4e470f695ac9 /ospf6d/ospf6_asbr.c |
Initial revision
Diffstat (limited to 'ospf6d/ospf6_asbr.c')
-rw-r--r-- | ospf6d/ospf6_asbr.c | 1040 |
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); +} + + |